home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / eaclib.zip / EA.cpp next >
C/C++ Source or Header  |  1996-05-22  |  14KB  |  453 lines

  1. /* --------------------------------------------------------------------------
  2.  * $RCSfile: EA.cpp,v $
  3.  * $Revision: 1.1 $
  4.  * $Date: 1996/05/22 20:59:55 $
  5.  * $Author: Bablok $
  6.  * --------------------------------------------------------------------------
  7.  * Synopsis:
  8.  *
  9.  * Implementation of class EA. This class wraps the extended attributes API of
  10.  * OS/2.
  11.  *
  12.  * This file is part of the EA classlib package.
  13.  * Copyright Bernhard Bablok, 1996
  14.  *
  15.  * The EA classlib package is distributed in the hope that it will be
  16.  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
  17.  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  18.  *
  19.  * You may use the classes in the package to any extend you wish. You are
  20.  * allowed to change and copy the source of the classes, as long as you keep
  21.  * the copyright notice intact and as long as you document the changes you made.
  22.  *
  23.  * You are not allowed to sell the EA classlib package or a modified version
  24.  * thereof, but you may charge for costs of distribution media.
  25.  *
  26.  * --------------------------------------------------------------------------
  27.  * Change-Log:
  28.  *
  29.  * $Log: EA.cpp,v $
  30.  * Revision 1.1  1996/05/22 20:59:55  Bablok
  31.  * Initial revision
  32.  *
  33.  * -------------------------------------------------------------------------- */
  34.  
  35. #ifndef _IEXCEPT_
  36.    #include <iexcept.hpp>
  37. #endif
  38. #ifndef _IMSGTEXT_
  39.    #include <imsgtext.hpp>
  40. #endif
  41.  
  42. #ifndef EA_H
  43.    #include "EA.hpp"
  44. #endif
  45. #ifndef EALIST_H
  46.    #include "EAList.hpp"
  47. #endif
  48.  
  49. ///////////////////////////////////////////////////////////////////////////////
  50. //  Construct a multivalued EA from an EAList
  51. //
  52. EA::EA(const IString& name, const EAList& eaList, BYTE flag) : mName(name),
  53.                                                                    mFlag(flag) {
  54.  
  55.    if (!eaList.numberOfElements()) {
  56.       IInvalidRequest exc(IMessageText(ERR_EALIST_EMPTY,MSG_FILE),
  57.                                                      0,IException::recoverable);
  58.       ITHROW(exc);
  59.    }
  60.    mName.upperCase();
  61.  
  62.    // Calculate size of required buffer for mValue and check type   ------------
  63.  
  64.    EAList::Cursor current(eaList);
  65.    Boolean isSingleTyped = true;
  66.  
  67.    current.setToFirst();
  68.    USHORT  type   = current.element().mType,
  69.            length = 0;
  70.  
  71.    forCursor(current) {
  72.       const EA& ea = current.element();
  73.       isSingleTyped = type == ea.mType;
  74.       if (ea.isLengthPreceded())
  75.          length += sizeof(USHORT);
  76.       length += ea.mValue.length();
  77.    }
  78.  
  79.    // Query code page information   --------------------------------------------
  80.  
  81.    ULONG codePage, codePageLength;
  82.    APIRET rc = DosQueryCp(sizeof(codePage),&codePage,&codePageLength);
  83.  
  84.    if (rc == ERROR_CP_NOT_MOVED) {
  85.       IException exc(ISystemErrorInfo(rc,"DosQueryCp"),
  86.                                                     rc,IException::recoverable);
  87.       ITHROW(exc);
  88.    }
  89.  
  90.    // Allocate and fill buffer for mValue   ------------------------------------
  91.  
  92.    char *buffer, *p;
  93.    if (isSingleTyped)
  94.       length += 3*sizeof(USHORT);
  95.    else
  96.       length += 2*sizeof(USHORT) + eaList.numberOfElements()*sizeof(USHORT);
  97.    buffer = new char[length];
  98.    if (!buffer) {
  99.       IOutOfMemory exc(IMessageText(ERR_MEM_ALLOC_FAILED,MSG_FILE),0);
  100.       ITHROW(exc);
  101.    }
  102.    p = buffer;
  103.    *(USHORT*) p = (USHORT) codePage;
  104.    p += sizeof(USHORT);
  105.    *(USHORT*) p = (USHORT) eaList.numberOfElements();
  106.    p += sizeof(USHORT);
  107.    if (isSingleTyped) {
  108.       *(USHORT*) p = eaList.anyElement().mType;
  109.       p += sizeof(USHORT);
  110.    }
  111.  
  112.    forCursor(current) {
  113.       const EA& ea = current.element();
  114.       if (!isSingleTyped) {
  115.          *(USHORT*) p = ea.mType;
  116.          p += sizeof(USHORT);
  117.       }
  118.       if (ea.isLengthPreceded()) {
  119.          *(USHORT*) p = ea.mValue.length();
  120.          p += sizeof(USHORT);
  121.       }
  122.       memcpy(p,(char*) ea.mValue,ea.mValue.length());
  123.       p += ea.mValue.length();
  124.    }
  125.  
  126.    // set mValue and clean up resources   --------------------------------------
  127.  
  128.    mValue = IString(buffer,length);
  129.    if (isSingleTyped)
  130.       mType  = EAT_MVST;
  131.    else
  132.       mType  = EAT_MVMT;
  133.    delete buffer;
  134. }
  135.  
  136.  
  137. ///////////////////////////////////////////////////////////////////////////////
  138. //  Construct an EA from a FEA2-structure
  139. //
  140. EA::EA(FEA2* fea2) {
  141.    mName = fea2->szName;
  142.    mFlag = fea2->fEA;
  143.    if (fea2->cbValue) {
  144.       char* val = (char*) fea2 + sizeof(FEA2) + fea2->cbName;
  145.       mType  = *(USHORT*) val;                        // first word is type
  146.       if (isLengthPreceded())                         // second word is length
  147.          mValue = IString(val+2*sizeof(USHORT),fea2->cbValue-2*sizeof(USHORT));
  148.       else
  149.          mValue = IString(val+sizeof(USHORT),fea2->cbValue - sizeof(USHORT));
  150.    } else {
  151.       mValue = "";
  152.       mType  = EAT_ASCII;
  153.    }
  154. }
  155.  
  156.  
  157. ///////////////////////////////////////////////////////////////////////////////
  158. //  Read an EA from a given file. If the given EA does not exist, the value
  159. //  is set to "".
  160. //
  161. EA& EA::read(PVOID fileRef, Boolean isPathName) {
  162.  
  163.    if (mName == "") {
  164.       IInvalidRequest exc(IMessageText(ERR_NO_EA_NAME,MSG_FILE),
  165.                                                      0,IException::recoverable);
  166.       ITHROW(exc);
  167.    }
  168.  
  169.    // set up EA list and query EA   --------------------------------------------
  170.  
  171.    EAOP2 eaBuffer;
  172.    eaBuffer.fpGEA2List = createGEA2LIST();
  173.    eaBuffer.fpFEA2List = createFEA2LISTBuffer(fileRef,isPathName);
  174.    eaBuffer.oError     = 0;
  175.    APIRET rc;
  176.    if (isPathName)
  177.       rc = DosQueryPathInfo((PSZ)fileRef,FIL_QUERYEASFROMLIST,&eaBuffer,
  178.                                                                  sizeof(EAOP2));
  179.    else
  180.       rc = DosQueryFileInfo(*(HFILE*)fileRef,FIL_QUERYEASFROMLIST,&eaBuffer,
  181.                                                                  sizeof(EAOP2));
  182.    if (rc) {
  183.       delete eaBuffer.fpGEA2List;
  184.       delete eaBuffer.fpFEA2List;
  185.       IString api;
  186.       if (isPathName)
  187.          api = "DosQueryPathInfo";
  188.       else
  189.          api = "DosQueryFileInfo";
  190.       IException exc(ISystemErrorInfo(rc,api),rc,IException::recoverable);
  191.       ITHROW(exc);
  192.    }
  193.  
  194.    // convert result to EA   ---------------------------------------------------
  195.  
  196.    *this = EA(&eaBuffer.fpFEA2List->list[0]);
  197.    delete eaBuffer.fpGEA2List;
  198.    delete eaBuffer.fpFEA2List;
  199.    return *this;
  200. }
  201.  
  202.  
  203. ///////////////////////////////////////////////////////////////////////////////
  204. //  Write an EA to the given file.
  205. //
  206. EA& EA::write(PVOID fileRef, Boolean isPathName) {
  207.  
  208.    if (mName == "") {
  209.       IInvalidRequest exc(IMessageText(ERR_NO_EA_NAME,MSG_FILE),
  210.                                                      0,IException::recoverable);
  211.       ITHROW(exc);
  212.    }
  213.  
  214.    EAOP2 eaBuffer;
  215.    eaBuffer.fpGEA2List = 0;
  216.    eaBuffer.fpFEA2List = createFEA2LIST();
  217.    eaBuffer.oError     = 0;
  218.    APIRET rc;
  219.    if (isPathName)
  220.       rc = DosSetPathInfo((PSZ)fileRef,FIL_QUERYEASIZE,&eaBuffer,sizeof(EAOP2),
  221.                                                                   DSPI_WRTTHRU);
  222.    else
  223.       rc = DosSetFileInfo(*(HFILE*)fileRef,FIL_QUERYEASIZE,
  224.                                                        &eaBuffer,sizeof(EAOP2));
  225.    delete eaBuffer.fpFEA2List;
  226.    if (rc) {
  227.       IString api;
  228.       if (isPathName)
  229.          api = "DosSetPathInfo";
  230.       else
  231.          api = "DosSetFileInfo";
  232.       IException exc(ISystemErrorInfo(rc,api),rc,IException::recoverable);
  233.       ITHROW(exc);
  234.    }
  235.    return *this;
  236. }
  237.  
  238.  
  239. ///////////////////////////////////////////////////////////////////////////////
  240. //  Remove an EA from the given file.
  241. //
  242. EA& EA::remove(PVOID fileRef, Boolean isPathName) {
  243.    EA rem(*this);
  244.    rem.mValue = "";
  245.    rem.write(fileRef,isPathName);
  246.    return *this;
  247. }
  248.  
  249.  
  250. ///////////////////////////////////////////////////////////////////////////////
  251. //  Determine if data-area of EA is preceded by length (static version)
  252. //
  253. Boolean EA::isLengthPreceded(USHORT type) {
  254.    switch (type) {
  255.       case EAT_BINARY:
  256.       case EAT_ASCII:
  257.       case EAT_BITMAP:
  258.       case EAT_METAFILE:
  259.       case EAT_ICON:
  260.       case EAT_EA:
  261.          return true;
  262.       default:
  263.          return false;
  264.    }
  265. }
  266.  
  267.  
  268. ///////////////////////////////////////////////////////////////////////////////
  269. //  Convert mName to GEA2LIST-structure
  270. //
  271. GEA2LIST* EA::createGEA2LIST() const {
  272.    size_t length = sizeof(GEA2LIST) + mName.length();
  273.    char *buffer = new char[length];
  274.    if (!buffer) {
  275.       IOutOfMemory exc(IMessageText(ERR_MEM_ALLOC_FAILED,MSG_FILE),0);
  276.       ITHROW(exc);
  277.    }
  278.    char *p = buffer;
  279.  
  280.    memset(p,0,length);
  281.    *(ULONG*) p = length;                             // cbList
  282.    p += 2*sizeof(ULONG);
  283.    *(BYTE*) p = mName.length();                      // cbName
  284.    p += sizeof(BYTE);
  285.    memcpy(p,(char*) mName,mName.length());           // mName
  286.    return (GEA2LIST*) buffer;
  287. }
  288.  
  289.  
  290. ///////////////////////////////////////////////////////////////////////////////
  291. //  Convert mName,mValue,mType to FEA2LIST-structure
  292. //
  293. FEA2LIST* EA::createFEA2LIST() const {
  294.  
  295.    FEA2LIST *buffer = createFEA2LISTBuffer();
  296.    char *p = (char*) buffer;
  297.    p += sizeof(ULONG);                               // skip cbList
  298.    createFEA2(p);
  299.    return buffer;
  300. }
  301.  
  302.  
  303. ///////////////////////////////////////////////////////////////////////////////
  304. //  Convert mName,mValue,mType to FEA2-structure
  305. //
  306. ULONG EA::createFEA2(char *buffer) const {
  307.  
  308.    char *p = buffer + sizeof(ULONG);            // skip oNextEntryOffset
  309.  
  310.    *(BYTE*) p = mFlag;                          // fEA
  311.    p += sizeof(BYTE);
  312.    *(BYTE*) p = mName.length();                 // cbName
  313.    p += sizeof(BYTE);
  314.    *(USHORT*) p = mValue.length();              // cbValue
  315.    USHORT *cbValuePtr = (USHORT*) p;
  316.    p += sizeof(USHORT);
  317.    memcpy(p,(char*)mName,mName.length());       // szName
  318.    p += mName.length() + sizeof(char);
  319.    if (mValue.length()) {
  320.       *(USHORT*) p = mType;                     // EA data type
  321.       *cbValuePtr += sizeof(USHORT);            // increase cbValue
  322.       p += sizeof(USHORT);
  323.       if (isLengthPreceded()) {
  324.          *(USHORT*) p = mValue.length();        // length of data
  325.          *cbValuePtr += sizeof(USHORT);         // increase cbValue
  326.          p += sizeof(USHORT);
  327.       }
  328.       memcpy(p,(char*) mValue,mValue.length());
  329.       p += mValue.length();
  330.    }
  331.  
  332.    return p - buffer;
  333. }
  334.  
  335.  
  336. ///////////////////////////////////////////////////////////////////////////////
  337. //  Allocate FEA2LIST data area for get operation
  338. //
  339. FEA2LIST* EA::createFEA2LISTBuffer(PVOID fileRef, Boolean isPathName) const {
  340.  
  341.    // query EA size   ----------------------------------------------------------
  342.  
  343.    FILESTATUS4 status;
  344.    APIRET rc;
  345.    if (isPathName)
  346.       rc = DosQueryPathInfo((PSZ)fileRef,FIL_QUERYEASIZE,&status,
  347.                                                            sizeof(FILESTATUS4));
  348.    else
  349.       rc = DosQueryFileInfo(*(HFILE*)fileRef,FIL_QUERYEASIZE,&status,
  350.                                                            sizeof(FILESTATUS4));
  351.    if (rc) {
  352.       IString api;
  353.       if (isPathName)
  354.          api = "DosQueryPathInfo";
  355.       else
  356.          api = "DosQueryFileInfo";
  357.       IException exc(ISystemErrorInfo(rc,api),rc,IException::recoverable);
  358.       ITHROW(exc);
  359.    }
  360.  
  361.    unsigned long bufferSize = sizeof(ULONG)+2*status.cbList+mName.length()+1;
  362.    char *buffer = new char[bufferSize];                      // crude, but quick
  363.    if (!buffer) {
  364.       IOutOfMemory exc(IMessageText(ERR_MEM_ALLOC_FAILED,MSG_FILE),0);
  365.       ITHROW(exc);
  366.    }
  367.    memset(buffer,0,bufferSize);
  368.    *(ULONG*) buffer = bufferSize;
  369.    return (FEA2LIST*) buffer;
  370. }
  371.  
  372.  
  373. ///////////////////////////////////////////////////////////////////////////////
  374. //  Allocate FEA2LIST data area for put operation
  375. //
  376. FEA2LIST* EA::createFEA2LISTBuffer() const {
  377.  
  378.    size_t length = sizeof(FEA2LIST) +
  379.                    mName.length()   +                // length of szName
  380.                    mValue.length();                  // length of value
  381.    if (mValue.length()) {
  382.       length += sizeof(USHORT);                      // first word is type
  383.       if (isLengthPreceded())                        // second word is length
  384.          length += sizeof(USHORT);
  385.    }
  386.    char* buffer = new char[length];
  387.    if (!buffer) {
  388.       IOutOfMemory exc(IMessageText(ERR_MEM_ALLOC_FAILED,MSG_FILE),0);
  389.       ITHROW(exc);
  390.    }
  391.  
  392.    memset(buffer,0,length);
  393.    *(ULONG*) buffer = length;
  394.    return (FEA2LIST*) buffer;
  395. }
  396.  
  397.  
  398. ///////////////////////////////////////////////////////////////////////////////
  399. //  Return type of EA as string
  400. //
  401. IString EA::typeAsString(USHORT type) {
  402.    switch (type) {
  403.       case EAT_BINARY:
  404.          return "Binary";
  405.       case EAT_ASCII:
  406.          return "ASCII";
  407.       case EAT_BITMAP:
  408.          return "Bitmap";
  409.       case EAT_METAFILE:
  410.          return "Metafile";
  411.       case EAT_ICON:
  412.          return "Icon";
  413.       case EAT_EA:
  414.          return "EA";
  415.       case EAT_MVMT:
  416.          return "MVMT";
  417.       case EAT_MVST:
  418.          return "MVST";
  419.       case EAT_ASN1:
  420.          return "ASN.1";
  421.       default:
  422.          return IString("Unknown(") + IString::c2x(type) + IString(')');
  423.    }
  424. }
  425.  
  426.  
  427. ///////////////////////////////////////////////////////////////////////////////
  428. //  Return number of values in a multi-valued EA
  429. //
  430. USHORT EA::numValues() const {
  431.  
  432.    if (mType != EAT_MVMT && mType != EAT_MVST) {
  433.       IInvalidRequest exc(IMessageText(ERR_NOT_MULTI_VALUED,MSG_FILE),
  434.                                                      0,IException::recoverable);
  435.       ITHROW(exc);
  436.    }
  437.    return *(USHORT*) ((char*) mValue+sizeof(USHORT));
  438. }
  439.  
  440.  
  441. ///////////////////////////////////////////////////////////////////////////////
  442. //  Return code page from a multi-valued EA
  443. //
  444. USHORT EA::codePage() const {
  445.  
  446.    if (mType != EAT_MVMT && mType != EAT_MVST) {
  447.       IInvalidRequest exc(IMessageText(ERR_NOT_MULTI_VALUED,MSG_FILE),
  448.                                                      0,IException::recoverable);
  449.       ITHROW(exc);
  450.    }
  451.    return *(USHORT*) ((char*) mValue);
  452. }
  453.