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

  1. /* --------------------------------------------------------------------------
  2.  * $RCSfile: EAList.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 EAList. This class wraps the extended attributes API
  10.  * of OS/2 and handles complete sets of file-EAs.
  11.  *
  12.  * An EAList is implemented as a key sorted set. This allows the conversion
  13.  * of an EAList to a multivalued EA and back again.
  14.  *
  15.  * This file is part of the EA classlib package.
  16.  * Copyright Bernhard Bablok, 1996
  17.  *
  18.  * The EA classlib package is distributed in the hope that it will be
  19.  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
  20.  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  21.  *
  22.  * You may use the classes in the package to any extend you wish. You are
  23.  * allowed to change and copy the source of the classes, as long as you keep
  24.  * the copyright notice intact and as long as you document the changes you made.
  25.  *
  26.  * You are not allowed to sell the EA classlib package or a modified version
  27.  * thereof, but you may charge for costs of distribution media.
  28.  *
  29.  * --------------------------------------------------------------------------
  30.  * Change-Log:
  31.  *
  32.  * $Log: EAList.cpp,v $
  33.  * Revision 1.1  1996/05/22 20:59:55  Bablok
  34.  * Initial revision
  35.  *
  36.  * -------------------------------------------------------------------------- */
  37.  
  38. #ifndef _IEXCEPT_
  39.    #include <iexcept.hpp>
  40. #endif
  41. #ifndef _IMSGTEXT_
  42.    #include <imsgtext.hpp>
  43. #endif
  44. #ifndef __iostream_h
  45.    #include <iostream.h>
  46. #endif
  47. #ifndef __math_h
  48.    #include <math.h>
  49. #endif
  50.  
  51. #ifndef EA_H
  52.    #include "EA.hpp"
  53. #endif
  54. #ifndef EALIST_H
  55.    #include "EAList.hpp"
  56. #endif
  57.  
  58. ///////////////////////////////////////////////////////////////////////////////
  59. // Copy constructor
  60. //
  61. EAList::EAList(const EAList& eaList) : EASet(EALIST_DEFAULT_SIZE),
  62.                                                                mFEA2List(NULL) {
  63.    if (eaList.mFEA2List) {
  64.       ULONG length = *(ULONG*) eaList.mFEA2List;
  65.       char *buffer = new char[length];
  66.       if (!buffer) {
  67.          IOutOfMemory exc(IMessageText(ERR_MEM_ALLOC_FAILED,MSG_FILE),0);
  68.          ITHROW(exc);
  69.       }
  70.       memcpy(buffer,(char*) eaList.mFEA2List,length);
  71.       mFEA2List = (FEA2LIST*) buffer;
  72.    }
  73.    addAllFrom(eaList);
  74. }
  75.  
  76.  
  77. ///////////////////////////////////////////////////////////////////////////////
  78. // Construct EAList from multi-valued EA
  79. //
  80. EAList::EAList(const IString& basename, const EA& ea) :
  81.                                    EASet(EALIST_DEFAULT_SIZE), mFEA2List(NULL) {
  82.  
  83.    USHORT type,
  84.           n      = ea.numValues(),     // this will throw an exception if not mv
  85.           digits = log10(n) + 1;
  86.    BYTE   flag   = ea.flag();
  87.    char   *p     = (char*) ea.value() + 2*sizeof(USHORT);   // skip header
  88.  
  89.    // extract type if single-typed   -------------------------------------------
  90.  
  91.    if (ea.type() == EAT_MVST) {
  92.       type = *(USHORT*) p;
  93.       p += sizeof(USHORT);
  94.       if (!EA::isLengthPreceded(type)) {
  95.          IString excText(IMessageText(ERR_INVALID_TYPE,MSG_FILE));
  96.          excText += " (" + EA::typeAsString(type) + ")";
  97.          IInvalidRequest exc(excText,0,IException::recoverable);
  98.          ITHROW(exc);
  99.       }
  100.    }
  101.  
  102.    // iterate through all entries   --------------------------------------------
  103.  
  104.    for (int i=1; i<=n; ++i) {
  105.       if (ea.type() == EAT_MVMT) {
  106.          type = *(USHORT*) p;
  107.          p += sizeof(USHORT);
  108.          if (!EA::isLengthPreceded(type)) {
  109.             IString excText(IMessageText(ERR_INVALID_TYPE,MSG_FILE));
  110.             excText += " (" + EA::typeAsString(type) + ")";
  111.             IInvalidRequest exc(excText,0,IException::recoverable);
  112.             ITHROW(exc);
  113.          }
  114.       }
  115.       USHORT length = *(USHORT*) p;
  116.       p += sizeof(USHORT);
  117.       IString name = basename + IString('.') + IString(i).rightJustify(digits,0);
  118.       add(EA(name,p,length,type,flag));
  119.       p += length;
  120.    }
  121. }
  122.  
  123.  
  124. ///////////////////////////////////////////////////////////////////////////////
  125. // Assignment
  126. //
  127. EAList& EAList::operator=(const EAList& eaList) {
  128.    if (&eaList == this)
  129.       return *this;
  130.  
  131.    if (mFEA2List)
  132.       delete mFEA2List;
  133.    if (eaList.mFEA2List) {
  134.       ULONG length = *(ULONG*) eaList.mFEA2List;
  135.       char *buffer = new char[length];
  136.       if (!buffer) {
  137.          IOutOfMemory exc(IMessageText(ERR_MEM_ALLOC_FAILED,MSG_FILE),0);
  138.          ITHROW(exc);
  139.       }
  140.       memcpy(buffer,(char*) eaList.mFEA2List,length);
  141.       mFEA2List = (FEA2LIST*) buffer;
  142.    }  else
  143.       mFEA2List = NULL;
  144.  
  145.    removeAll();
  146.    addAllFrom(eaList);
  147.    return *this;
  148. }
  149.  
  150.  
  151. ///////////////////////////////////////////////////////////////////////////////
  152. //  Read EAs from a given file. This function either reads all EAs of the
  153. //  file, or only the EAs given in the list.
  154. //
  155. EAList& EAList::read(PVOID fileRef,Boolean isPathName,Boolean onlyEAsFromList) {
  156.  
  157.    EAOP2 eaBuffer;
  158.    eaBuffer.oError = 0;
  159.  
  160.    if (onlyEAsFromList) {
  161.       if (!numberOfElements())                                 // nothing to do!
  162.          return *this;
  163.       eaBuffer.fpGEA2List = createGEA2LIST();
  164.       eaBuffer.fpFEA2List = createFEA2LISTBuffer(fileRef,isPathName);
  165.    } else {
  166.       DENA2 *eaEnumBuffer = queryDENA2(fileRef,isPathName);
  167.       if (!eaEnumBuffer) {
  168.          removeAll();
  169.          return *this;
  170.       }
  171.       eaBuffer.fpGEA2List = createGEA2LIST(eaEnumBuffer);
  172.       eaBuffer.fpFEA2List = createFEA2LISTBuffer(eaEnumBuffer);
  173.       delete eaEnumBuffer;
  174.    }
  175.  
  176.    APIRET rc;
  177.    if (isPathName)
  178.       rc = DosQueryPathInfo((PSZ)fileRef,FIL_QUERYEASFROMLIST,
  179.                                                        &eaBuffer,sizeof(EAOP2));
  180.    else
  181.       rc = DosQueryFileInfo(*(HFILE*)fileRef,FIL_QUERYEASFROMLIST,
  182.                                                        &eaBuffer,sizeof(EAOP2));
  183.    delete eaBuffer.fpGEA2List;
  184.    if (rc) {
  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.    if (!onlyEAsFromList)
  194.       removeAll();                         // this is save now
  195.    return convert();                       // converts FEA2LIST to EAList
  196. }
  197.  
  198.  
  199. ///////////////////////////////////////////////////////////////////////////////
  200. //  Write EAs to a given file.
  201. //
  202. EAList& EAList::write(PVOID fileRef,Boolean isPathName,Boolean useFEA2List) {
  203.  
  204.    if (!numberOfElements())        // nothing to do!
  205.       return *this;
  206.  
  207.    EAOP2 eaBuffer;
  208.    eaBuffer.oError     = 0;
  209.    eaBuffer.fpGEA2List = 0;
  210.  
  211.    if (useFEA2List)
  212.       eaBuffer.fpFEA2List = mFEA2List;
  213.    else
  214.       eaBuffer.fpFEA2List = createFEA2LIST();
  215.  
  216.    APIRET rc;
  217.    if (isPathName)
  218.       rc = DosSetPathInfo((PSZ)fileRef,FIL_QUERYEASIZE,&eaBuffer,sizeof(EAOP2),
  219.                                                                   DSPI_WRTTHRU);
  220.    else
  221.       rc = DosSetFileInfo(*(HFILE*)fileRef,FIL_QUERYEASIZE,
  222.                                                        &eaBuffer,sizeof(EAOP2));
  223.    if (rc) {
  224.       IString api;
  225.       if (isPathName)
  226.          api = "DosSetPathInfo";
  227.       else
  228.          api = "DosSetFileInfo";
  229.       IException exc(ISystemErrorInfo(rc,api),rc,IException::recoverable);
  230.       ITHROW(exc);
  231.    }
  232.    return *this;
  233. }
  234.  
  235.  
  236. ///////////////////////////////////////////////////////////////////////////////
  237. //  Remove EAs from a given file. This function either removes all EAs of the
  238. //  file, or only the EAs given in the list.
  239. //
  240. EAList& EAList::remove(PVOID fileRef,Boolean isPathName,Boolean onlyEAsFromList) {
  241.  
  242.    EAList removeList;
  243.  
  244.    if (onlyEAsFromList)
  245.       removeList = *this;
  246.    else
  247.       removeList.read(fileRef,isPathName,false);
  248.  
  249.    EAList::Cursor current(removeList);
  250.    forCursor(current)
  251.       removeList.elementAt(current).setValue("");
  252.  
  253.    removeList.write(fileRef,isPathName,false);
  254.    return *this;
  255. }
  256.  
  257.  
  258. ///////////////////////////////////////////////////////////////////////////////
  259. //  Enumerate EAs. This function returns a pointer to a DENA2-structure.
  260. //
  261. DENA2* EAList::queryDENA2(PVOID fileRef, Boolean isPathName) const {
  262.  
  263.    // query EA size   ----------------------------------------------------------
  264.  
  265.    FILESTATUS4 filestatus4;
  266.    APIRET rc;
  267.    if (isPathName)
  268.       rc = DosQueryPathInfo((PSZ)fileRef,FIL_QUERYEASIZE,&filestatus4,
  269.                                                            sizeof(FILESTATUS4));
  270.    else
  271.       rc = DosQueryFileInfo(*(HFILE*)fileRef,FIL_QUERYEASIZE,&filestatus4,
  272.                                                            sizeof(FILESTATUS4));
  273.    if (rc) {
  274.       IString api;
  275.       if (isPathName)
  276.          api = "DosQueryPathInfo";
  277.       else
  278.          api = "DosQueryFileInfo";
  279.       IException exc(ISystemErrorInfo(rc,api),rc,IException::recoverable);
  280.       ITHROW(exc);
  281.    }
  282.  
  283.    // Allocate necessary buffer   ----------------------------------------------
  284.  
  285.    char *buffer = new char[2*filestatus4.cbList];
  286.    if (!buffer) {
  287.       IOutOfMemory exc(IMessageText(ERR_MEM_ALLOC_FAILED,MSG_FILE),0);
  288.       ITHROW(exc);
  289.    }
  290.  
  291.    // Query DENA2-structure   --------------------------------------------------
  292.  
  293.    ULONG count = -1;                                            // query all EAs
  294.    if (isPathName)
  295.       rc = DosEnumAttribute(ENUMEA_REFTYPE_PATH,fileRef,1,buffer,
  296.                              2*filestatus4.cbList,&count,ENUMEA_LEVEL_NO_VALUE);
  297.    else
  298.       rc = DosEnumAttribute(ENUMEA_REFTYPE_FHANDLE,fileRef,1,buffer,
  299.                              2*filestatus4.cbList,&count,ENUMEA_LEVEL_NO_VALUE);
  300.    if (rc) {
  301.       IException exc(ISystemErrorInfo(rc,"DosEnumAttribute"),
  302.                                                     rc,IException::recoverable);
  303.       ITHROW(exc);
  304.    }
  305.  
  306.    if (!count) {
  307.       delete buffer;
  308.       return NULL;
  309.    } else
  310.       return (DENA2*) buffer;
  311. }
  312.  
  313.  
  314. ///////////////////////////////////////////////////////////////////////////////
  315. //  Create GEA2LIST-structure from DENA2. This structure contains all
  316. //  necessary information to query EAs.
  317. //
  318. GEA2LIST* EAList::createGEA2LIST(DENA2* pDENA2) const {
  319.  
  320.    IASSERT(pDENA2 != 0);
  321.  
  322.    // Calculate size of buffer   -----------------------------------------------
  323.  
  324.    ULONG length = sizeof(ULONG);                    // cbList
  325.    DENA2* p = pDENA2;
  326.    while (1) {
  327.       length += sizeof(GEA2) + p->cbName;
  328.       length += 4-(length&3) & 3;                   // align on double word
  329.       if (p->oNextEntryOffset)
  330.          p = (DENA2*) ((char*) p + p->oNextEntryOffset);
  331.       else
  332.          break;
  333.    }
  334.  
  335.    // Allocate buffer   --------------------------------------------------------
  336.  
  337.    char *buffer = new char[length];
  338.    if (!buffer) {
  339.       IOutOfMemory exc(IMessageText(ERR_MEM_ALLOC_FAILED,MSG_FILE),0);
  340.       ITHROW(exc);
  341.    }
  342.  
  343.    // fill buffer   ------------------------------------------------------------
  344.  
  345.    memset(buffer,0,length);
  346.    *(ULONG*) buffer = length;                 // cbList
  347.    GEA2* pGEA2 = (GEA2*) (buffer+sizeof(ULONG));
  348.    p = pDENA2;
  349.    while (1) {
  350.       pGEA2->cbName = p->cbName;
  351.       memcpy(pGEA2->szName,p->szName,p->cbName);
  352.       if (p->oNextEntryOffset) {
  353.          length = sizeof(GEA2) + p->cbName;
  354.          pGEA2->oNextEntryOffset = length + (4-(length&3) & 3);
  355.          pGEA2 = (GEA2*) ((char*) pGEA2 + pGEA2->oNextEntryOffset);
  356.          p     = (DENA2*) ((char*) p + p->oNextEntryOffset);
  357.       } else
  358.          break;
  359.    }
  360.    return (GEA2LIST*) buffer;
  361. }
  362.  
  363.  
  364. ///////////////////////////////////////////////////////////////////////////////
  365. //  Create FEA2LIST-buffer from DENA2-structure.
  366. //
  367. FEA2LIST* EAList::createFEA2LISTBuffer(DENA2* pDENA2) {
  368.  
  369.    IASSERT(pDENA2 != 0);
  370.  
  371.    // Calculate size of buffer   -----------------------------------------------
  372.  
  373.    ULONG length = sizeof(ULONG);                    // cbList
  374.    while (1) {
  375.       length += sizeof(FEA2) + pDENA2->cbName + pDENA2->cbValue;
  376.       length += 4-(length&3) & 3;                   // align on double word
  377.       if (pDENA2->oNextEntryOffset)
  378.          pDENA2 = (DENA2*) ((char*) pDENA2 + pDENA2->oNextEntryOffset);
  379.       else
  380.          break;
  381.    }
  382.  
  383.    // Allocate buffer   --------------------------------------------------------
  384.  
  385.    char *buffer = new char[length];
  386.    if (!buffer) {
  387.       IOutOfMemory exc(IMessageText(ERR_MEM_ALLOC_FAILED,MSG_FILE),0);
  388.       ITHROW(exc);
  389.    }
  390.    memset(buffer,0,length);
  391.    *(ULONG*) buffer = length;
  392.    if (mFEA2List)
  393.       delete mFEA2List;
  394.    mFEA2List = (FEA2LIST*) buffer;
  395.    return (FEA2LIST*) buffer;
  396. }
  397.  
  398.  
  399. ///////////////////////////////////////////////////////////////////////////////
  400. //  Create GEA2LIST-structure from EAList. This structure contains all
  401. //  necessary information to query EAs.
  402. //
  403. GEA2LIST* EAList::createGEA2LIST() const {
  404.  
  405.    IASSERT(numberOfElements());
  406.  
  407.    // Calculate size of buffer   -----------------------------------------------
  408.  
  409.    ULONG length = sizeof(ULONG);                    // cbList
  410.    EAList::Cursor current(*this);
  411.    forCursor(current) {
  412.       if (current.element().name() == "") {
  413.          IInvalidRequest exc(IMessageText(ERR_NO_EA_NAME,MSG_FILE),
  414.                                                      0,IException::recoverable);
  415.          ITHROW(exc);
  416.       }
  417.       length += sizeof(GEA2) + current.element().name().length();
  418.       length += 4-(length&3) & 3;                   // align on double word
  419.    }
  420.  
  421.    // Allocate buffer   --------------------------------------------------------
  422.  
  423.    char *buffer = new char[length];
  424.    if (!buffer) {
  425.       IOutOfMemory exc(IMessageText(ERR_MEM_ALLOC_FAILED,MSG_FILE),0);
  426.       ITHROW(exc);
  427.    }
  428.  
  429.    // fill buffer   ------------------------------------------------------------
  430.  
  431.    memset(buffer,0,length);
  432.    *(ULONG*) buffer = length;                 // cbList
  433.    GEA2* pGEA2 = (GEA2*) (buffer+sizeof(ULONG));
  434.    current.setToFirst();
  435.    while (1) {
  436.       pGEA2->cbName = current.element().name().length();
  437.       memcpy(pGEA2->szName,(const char*)current.element().name(),pGEA2->cbName);
  438.       current.setToNext();
  439.       if (current.isValid()) {
  440.          length = sizeof(GEA2) + pGEA2->cbName;
  441.          pGEA2->oNextEntryOffset = length + (4-(length&3) & 3);
  442.          pGEA2 = (GEA2*) ((char*) pGEA2 + pGEA2->oNextEntryOffset);
  443.       } else
  444.          break;
  445.    }
  446.    return (GEA2LIST*) buffer;
  447. }
  448.  
  449.  
  450. ///////////////////////////////////////////////////////////////////////////////
  451. //  Create FEA2LIST-buffer large enough for all EAs.
  452. //
  453. FEA2LIST* EAList::createFEA2LISTBuffer(PVOID fileRef,Boolean isPathName) {
  454.  
  455.    if (mFEA2List)
  456.       delete mFEA2List;
  457.    mFEA2List = anyElement().createFEA2LISTBuffer(fileRef,isPathName);
  458.    return mFEA2List;
  459. }
  460.  
  461.  
  462. ///////////////////////////////////////////////////////////////////////////////
  463. //  Create FEA2LIST-buffer from given EAList.
  464. //
  465. FEA2LIST* EAList::createFEA2LISTBuffer() {
  466.  
  467.    IASSERT(numberOfElements());
  468.  
  469.    // Calculate size of buffer   -----------------------------------------------
  470.  
  471.    ULONG length = sizeof(ULONG);                     // cbList
  472.    EAList::Cursor current(*this);
  473.    forCursor(current) {
  474.       const EA& ea = current.element();
  475.       if (ea.name() == "") {
  476.          IInvalidRequest exc(IMessageText(ERR_NO_EA_NAME,MSG_FILE),
  477.                                                      0,IException::recoverable);
  478.          ITHROW(exc);
  479.       }
  480.       length += sizeof(FEA2) + ea.name().length() + ea.value().length();
  481.       if (ea.value().length()) {
  482.          length += sizeof(USHORT);                   // first word is type
  483.          if (ea.isLengthPreceded())                  // second word is length
  484.             length += sizeof(USHORT);
  485.       }
  486.       length += 4-(length&3) & 3;                   // align on double word
  487.    }
  488.  
  489.    // Allocate buffer   --------------------------------------------------------
  490.  
  491.    char *buffer = new char[length];
  492.    if (!buffer) {
  493.       IOutOfMemory exc(IMessageText(ERR_MEM_ALLOC_FAILED,MSG_FILE),0);
  494.       ITHROW(exc);
  495.    }
  496.    memset(buffer,0,length);
  497.    *(ULONG*) buffer = length;
  498.    if (mFEA2List)
  499.       delete mFEA2List;
  500.    mFEA2List = (FEA2LIST*) buffer;
  501.    return mFEA2List;
  502. }
  503.  
  504.  
  505. ///////////////////////////////////////////////////////////////////////////////
  506. //  Convert FEA2LIST-structure to EAList
  507. //
  508. EAList& EAList::convert() {
  509.  
  510.     FEA2 *p = &(mFEA2List->list[0]);
  511.     while (1) {
  512.        EA ea(p);
  513.        if (ea.value() != "")
  514.           addOrReplaceElementWithKey(ea);
  515.        else
  516.           removeElementWithKey(ea.name());
  517.        if (p->oNextEntryOffset)
  518.           p = (FEA2*) ((char*) p + p->oNextEntryOffset);
  519.        else
  520.           break;
  521.     }
  522.     return *this;
  523. }
  524.  
  525.  
  526. ///////////////////////////////////////////////////////////////////////////////
  527. //  Create FEA2LIST from given EAList.
  528. //
  529. FEA2LIST* EAList::createFEA2LIST() {
  530.  
  531.    createFEA2LISTBuffer();
  532.    FEA2* p = (FEA2*) ((char*)mFEA2List + sizeof(ULONG));
  533.  
  534.    EAList::Cursor current(*this);
  535.    current.setToFirst();
  536.    while (1) {
  537.       size_t length = current.element().createFEA2((char*)p);
  538.       current.setToNext();
  539.       if (current.isValid()) {
  540.          p->oNextEntryOffset = length + (4-(length&3) & 3);
  541.          p = (FEA2*) ((char*) p + p->oNextEntryOffset);
  542.       } else
  543.          break;
  544.    }
  545.    return mFEA2List;
  546. }
  547.  
  548.  
  549. ///////////////////////////////////////////////////////////////////////////////
  550. // Set values of an EAList from a multi-valued EA
  551. //
  552. EAList& EAList::setValues(const EA& ea) {
  553.  
  554.    USHORT n;
  555.    if ((n = ea.numValues()) != numberOfElements()) {
  556.       IInvalidRequest exc(IMessageText(ERR_ELEMENT_COUNT,MSG_FILE),
  557.                                                      0,IException::recoverable);
  558.       ITHROW(exc);
  559.    }
  560.  
  561.    USHORT type, digits = log10(n) + 1;
  562.    BYTE   flag   = ea.flag();
  563.    char   *p     = (char*) ea.value() + 2*sizeof(USHORT);   // skip header
  564.  
  565.    // extract type if single-typed   -------------------------------------------
  566.  
  567.    if (ea.type() == EAT_MVST) {
  568.       type = *(USHORT*) p;
  569.       p += sizeof(USHORT);
  570.       if (!EA::isLengthPreceded(type)) {
  571.          IString excText(IMessageText(ERR_INVALID_TYPE,MSG_FILE));
  572.          excText += " (" + EA::typeAsString(type) + ")";
  573.          IInvalidRequest exc(excText,0,IException::recoverable);
  574.          ITHROW(exc);
  575.       }
  576.    }
  577.  
  578.    // iterate through all entries   --------------------------------------------
  579.  
  580.    EAList::Cursor current(*this);
  581.    forCursor(current) {
  582.       if (ea.type() == EAT_MVMT) {
  583.          type = *(USHORT*) p;
  584.          p += sizeof(USHORT);
  585.          if (!EA::isLengthPreceded(type)) {
  586.             IString excText(IMessageText(ERR_INVALID_TYPE,MSG_FILE));
  587.             excText += " (" + EA::typeAsString(type) + ")";
  588.             IInvalidRequest exc(excText,0,IException::recoverable);
  589.             ITHROW(exc);
  590.          }
  591.       }
  592.       USHORT length = *(USHORT*) p;
  593.       p += sizeof(USHORT);
  594.       elementAt(current).setValue(IString(p,length));
  595.       elementAt(current).setType(type);
  596.       elementAt(current).setFlag(flag);
  597.       p += length;
  598.    }
  599.    return *this;
  600. }
  601.  
  602.  
  603. ///////////////////////////////////////////////////////////////////////////////
  604. // Write mFEA2List to ostream (ostream must be open in binary mode)
  605. //
  606. ostream& operator<<(ostream& out, EAList& eaList) {
  607.    if (eaList.mFEA2List == NULL)
  608.       eaList.createFEA2LIST();
  609.    out.write((char*) eaList.mFEA2List,*(ULONG*) eaList.mFEA2List);
  610.    return out;
  611. }
  612.  
  613.  
  614. ///////////////////////////////////////////////////////////////////////////////
  615. // Read mFEA2List from istream (istream must be open in binary mode) and
  616. // convert to EAList
  617. //
  618. istream& operator>>(istream& in, EAList& eaList) {
  619.    ULONG length;
  620.    in.read((char*) &length,sizeof(ULONG));
  621.    char *buffer = new char[length];
  622.    if (!buffer) {
  623.       IOutOfMemory exc(IMessageText(ERR_MEM_ALLOC_FAILED,MSG_FILE),0);
  624.       ITHROW(exc);
  625.    }
  626.    *(ULONG*) buffer = length;
  627.    in.read(buffer+sizeof(ULONG),length-sizeof(ULONG));
  628.  
  629.    eaList.removeAll();
  630.    if (eaList.mFEA2List)
  631.       delete eaList.mFEA2List;
  632.    eaList.mFEA2List = (FEA2LIST*) buffer;
  633.    eaList.convert();
  634.  
  635.    return in;
  636. }
  637.