home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / yeah09.zip / source / lib / ea.cpp next >
C/C++ Source or Header  |  1996-05-25  |  11KB  |  463 lines

  1. //------------------------------------------------------------
  2. //
  3. // Name:     ea.cpp
  4. // Version:  0.9
  5. // Author:   Björn Fahller.
  6. //
  7. // Copyright (C) Björn Fahller, 1996.
  8. //
  9. // Purpose:  Base class for extended attributes. The "engine" in
  10. //           YEAH.
  11. //
  12. // History:
  13. //          Ver.  Date         What
  14. //          0.9   1996-05-26   First official release.
  15. //
  16. //------------------------------------------------------------
  17.  
  18. #include <IString.hpp>
  19. #include <string.h>
  20. #include "YEA.H"
  21.  
  22.  
  23. #define INCL_DOSFILEMGR
  24. #include <os2.h>
  25.  
  26. #include <strstrea.h>
  27. #include <fstream.h>
  28. #include <IExcBase.hpp>
  29.  
  30. //////////////
  31. //
  32. // Prototypes of static functions.
  33. //
  34. //////////////
  35.  
  36. IEXCLASSIMPLEMENT(EAError, IException);
  37. IEXCLASSIMPLEMENT(EAReadError, EAError);
  38. IEXCLASSIMPLEMENT(EAWriteError, EAError);
  39. IEXCLASSIMPLEMENT(EATypeMismatchError, EAError);
  40.  
  41. static EA::CreatorMap defaultEAInit(void);
  42. void setupGEA(EAOP2* peaop2, const IString& name);
  43. EA* createFrom(EAOP2* peaop2, const EA::CreatorMap& cm);
  44. static char* prepareFEA(EAOP2* peaop2, const IString& name);
  45. static EA::NameSet nameset(ULONG type, PVOID p);
  46. static void defaultErrorHandler(EA::Error, ULONG);
  47.  
  48. //////////////
  49. //
  50. // Definition of class static variables
  51. //
  52. /////////////
  53.  
  54. inline EA::CreatorMap defaultEAInit(void)
  55. {
  56.   return EA::CreatorMap();
  57. }
  58.  
  59. EA::CreatorMap EA::defaultCreatorMap = defaultEAInit();
  60. void (*EA::errorHandler)(EA::Error, ULONG) = defaultErrorHandler;
  61.  
  62. /////////////
  63. //
  64. // Public methods
  65. //
  66. /////////////
  67.  
  68. EA::~EA(void)
  69. {
  70. }
  71.  
  72. void EA::getFrom(const IString& file, const IString& name)
  73. {
  74.   peaop2 = new EAOP2;
  75.   peaop2->fpGEA2List = (GEA2LIST*)new char[500];
  76.   peaop2->fpFEA2List = (FEA2LIST*)new char[65536];
  77.   ::setupGEA(peaop2, name);
  78.   APIRET rc = DosQueryPathInfo(file, FIL_QUERYEASFROMLIST, peaop2, sizeof(*peaop2));
  79.   if (rc)
  80.   {
  81.     delete peaop2->fpGEA2List;
  82.     delete peaop2->fpFEA2List;
  83.     delete peaop2;
  84.     peaop2 = 0;
  85.     errorHandler(ReadError, rc);
  86.     return;
  87.   }
  88.   feaproc();
  89.   delete peaop2->fpGEA2List;
  90.   delete peaop2->fpFEA2List;
  91.   delete peaop2;
  92.   peaop2 = 0;
  93. }
  94.  
  95. void EA::getFrom(fstreambase& file, const IString& name)
  96. {
  97.   peaop2 = new EAOP2;
  98.   peaop2->fpGEA2List = (GEA2LIST*)new char[500];
  99.   peaop2->fpFEA2List = (FEA2LIST*)new char[65536];
  100.   ::setupGEA(peaop2, name);
  101.   APIRET rc = DosQueryFileInfo(file.rdbuf()->fd(), FIL_QUERYEASFROMLIST, peaop2, sizeof(*peaop2));
  102.   if (rc)
  103.   {
  104.     delete peaop2->fpGEA2List;
  105.     delete peaop2->fpFEA2List;
  106.     delete peaop2;
  107.     peaop2 = 0;
  108.     errorHandler(ReadError, rc);
  109.     return;
  110.   }
  111.   feaproc();
  112.   delete peaop2->fpGEA2List;
  113.   delete peaop2->fpFEA2List;
  114.   delete peaop2;
  115.   peaop2 = 0;
  116. }
  117.  
  118. void EA::storeTo(const IString& file, const IString& name)
  119. {
  120.   peaop2 = new EAOP2;
  121.   peaop2->fpGEA2List = (GEA2LIST*)new char[500];
  122.   peaop2->fpFEA2List = (FEA2LIST*)new char[65536];
  123.  
  124.   setupFEA(name);
  125.   APIRET rc = DosSetPathInfo(file, FIL_QUERYEASIZE, peaop2, sizeof(*peaop2), 0);
  126.  
  127.   delete peaop2->fpGEA2List;
  128.   delete peaop2->fpFEA2List;
  129.   delete peaop2;
  130.   peaop2 = 0;
  131.  
  132.   if (rc)
  133.   {
  134.     errorHandler(WriteError, rc);
  135.   }
  136. }
  137.  
  138. void EA::storeTo(fstreambase& file, const IString& name)
  139. {
  140.   peaop2 = new EAOP2;
  141.   peaop2->fpGEA2List = (GEA2LIST*)new char[500];
  142.   peaop2->fpFEA2List = (FEA2LIST*)new char[65536];
  143.  
  144.   setupFEA(name);
  145.   APIRET rc = DosSetFileInfo(file.rdbuf()->fd(), FIL_QUERYEASIZE, peaop2, sizeof(*peaop2));
  146.  
  147.   delete peaop2->fpGEA2List;
  148.   delete peaop2->fpFEA2List;
  149.   delete peaop2;
  150.   peaop2 = 0;
  151.  
  152.   if (rc)
  153.   {
  154.     errorHandler(WriteError, rc);
  155.   }
  156. }
  157.  
  158.  
  159. /////////////
  160. //
  161. // Protected methods
  162. //
  163. /////////////
  164.  
  165. EA::EA(EA::Identifier anId)
  166.  : id(anId),
  167.    flags(0),
  168.    peaop2(0)
  169. {
  170. }
  171.  
  172. EA::EA(const EA& e)
  173.   : id(e.id),
  174.     flags(e.flags),
  175.     peaop2(0)
  176. {
  177. }
  178.  
  179. const EA& EA::operator=(const EA& e)
  180. {
  181.   id = e.id;
  182.   flags = e.flags;
  183.   return *this;
  184. }
  185.  
  186. /////////////
  187. //
  188. // Private methods
  189. //
  190. /////////////
  191.  
  192. void EA::setupFEA(const IString& name)
  193. {
  194.   char* p = ::prepareFEA(peaop2, name);
  195.   EAOP2& eaop2 = *peaop2;
  196.   ostrstream os(p, 65536-((char*)eaop2.fpFEA2List-p));
  197.   os.write((char*)&id, sizeof(id));
  198.   writeTo(os);
  199.   os.seekp(0, ios::end);
  200.   unsigned long length = os.tellp();
  201.   eaop2.fpFEA2List->list[0].cbValue = (USHORT)length;
  202.   eaop2.fpFEA2List->list[0].fEA = flags;
  203.   eaop2.fpFEA2List->cbList = length + p-(char*)eaop2.fpFEA2List;
  204.   if (eaop2.fpFEA2List->cbList % 4)
  205.   {
  206.     eaop2.fpFEA2List->cbList+= 4-(eaop2.fpFEA2List->cbList % 4);
  207.   }
  208. }
  209.  
  210.  
  211. void EA::feaproc(void)
  212. {
  213.   EAOP2& eaop2 = *peaop2;
  214.  
  215.   if (eaop2.fpFEA2List->list[0].cbValue == 0)
  216.   {
  217.     errorHandler(NoSuchEAError, 0);
  218.     return;
  219.   }
  220.   istrstream is(eaop2.fpFEA2List->list[0].szName+eaop2.fpFEA2List->list[0].cbName+1,
  221.                 eaop2.fpFEA2List->list[0].cbValue);
  222.  
  223.   Identifier type;
  224.   is.read((char*)(&type), sizeof(type));
  225.   if (type != id)
  226.   {
  227.     errorHandler(TypeMismatchError, type);
  228.     return;
  229.   }
  230.   flags = eaop2.fpFEA2List->list[0].fEA;
  231.   readFrom(is);
  232. }
  233.  
  234.  
  235. /////////////
  236. //
  237. // Static methods
  238. //
  239. /////////////
  240.  
  241. void EA::remove(const IString& file, const IString& name)
  242. {
  243.   EAOP2 eaop2;
  244.   eaop2.fpFEA2List = (FEA2LIST*)new char[1024];
  245.   eaop2.fpGEA2List = 0;
  246.   eaop2.oError = 0;
  247.   char* p = ::prepareFEA(&eaop2, name);
  248.   eaop2.fpFEA2List->list[0].cbValue = 0;
  249.   eaop2.fpFEA2List->list[0].fEA = 0;
  250.   eaop2.fpFEA2List->cbList = p-(char*)eaop2.fpFEA2List;
  251.   if (eaop2.fpFEA2List->cbList % 4)
  252.   {
  253.     eaop2.fpFEA2List->cbList+= 4-(eaop2.fpFEA2List->cbList % 4);
  254.   }
  255.   APIRET rc = DosSetPathInfo(file, FIL_QUERYEASIZE, &eaop2, sizeof(eaop2), 0);
  256.   delete eaop2.fpFEA2List;
  257.   if (rc)
  258.   {
  259.     errorHandler(WriteError, rc);
  260.   }
  261. }
  262.  
  263. void EA::remove(fstreambase& file, const IString& name)
  264. {
  265.   EAOP2 eaop2;
  266.   eaop2.fpFEA2List = (FEA2LIST*)new char[1024];
  267.   eaop2.fpGEA2List = 0;
  268.   eaop2.oError = 0;
  269.   char* p = ::prepareFEA(&eaop2, name);
  270.   eaop2.fpFEA2List->list[0].cbValue = 0;
  271.   eaop2.fpFEA2List->list[0].fEA = 0;
  272.   eaop2.fpFEA2List->cbList = p-(char*)eaop2.fpFEA2List;
  273.   if (eaop2.fpFEA2List->cbList % 4)
  274.   {
  275.     eaop2.fpFEA2List->cbList+= 4-(eaop2.fpFEA2List->cbList % 4);
  276.   }
  277.   APIRET rc = DosSetFileInfo(file.rdbuf()->fd(), FIL_QUERYEASIZE, &eaop2, sizeof(eaop2));
  278.   delete eaop2.fpFEA2List;
  279.   if (rc)
  280.   {
  281.     errorHandler(WriteError, rc);
  282.   }
  283. }
  284.  
  285.  
  286. EA* EA::newFrom(const IString& file, const IString& name, const CreatorMap& cm)
  287. {
  288.   EAOP2 eaop2;
  289.   eaop2.oError = 0;
  290.   eaop2.fpFEA2List = (FEA2LIST*)new char[500];
  291.   eaop2.fpGEA2List = (GEA2LIST*)new char[65536];
  292.   ::setupGEA(&eaop2, name);
  293.   APIRET rc = DosQueryPathInfo(file, FIL_QUERYEASFROMLIST, &eaop2, sizeof(eaop2));
  294.   if (rc)
  295.   {
  296.     delete eaop2.fpFEA2List;
  297.     delete eaop2.fpGEA2List;
  298.     errorHandler(ReadError, rc);
  299.     return 0;
  300.   }
  301.   EA* pea = createFrom(&eaop2, cm);
  302.   delete eaop2.fpFEA2List;
  303.   delete eaop2.fpGEA2List;
  304.   return pea;
  305. }
  306.  
  307. EA* EA::newFrom(fstreambase& file, const IString& name, const CreatorMap& cm)
  308. {
  309.   EAOP2 eaop2;
  310.   eaop2.oError = 0;
  311.   eaop2.fpFEA2List = (FEA2LIST*)new char[500];
  312.   eaop2.fpGEA2List = (GEA2LIST*)new char[65536];
  313.   ::setupGEA(&eaop2, name);
  314.   APIRET rc = DosQueryFileInfo(file.rdbuf()->fd(), FIL_QUERYEASFROMLIST, &eaop2, sizeof(eaop2));
  315.   if (rc)
  316.   {
  317.     delete eaop2.fpFEA2List;
  318.     delete eaop2.fpGEA2List;
  319.     errorHandler(ReadError, rc);
  320.     return 0;
  321.   }
  322.   EA* pea = createFrom(&eaop2, cm);
  323.   delete eaop2.fpFEA2List;
  324.   delete eaop2.fpGEA2List;
  325.   return pea;
  326. }
  327.  
  328. EA::NameSet EA::namesIn(const IString& name)
  329. {
  330.   return nameset(ENUMEA_REFTYPE_PATH, (PVOID)(char*)name);
  331. }
  332.  
  333. EA::NameSet EA::namesIn(fstreambase& file)
  334. {
  335.   return nameset(ENUMEA_REFTYPE_FHANDLE, (PVOID)(file.rdbuf()->fd()));
  336. }
  337.  
  338. ////////////
  339. //
  340. // Static functions
  341. //
  342. ////////////
  343.  
  344. static EA::NameSet nameset(ULONG type, PVOID p)
  345. {
  346.   DENA2* pdena = (DENA2*)new char[65364];
  347.   pdena->oNextEntryOffset = 0;
  348.   pdena->cbValue = 0;
  349.   pdena->cbName = 0;
  350.   pdena->fEA = 0;
  351.   LONG count = -1;
  352.   APIRET rc = DosEnumAttribute(type, p, 1, (PVOID)pdena, 65364, (PULONG)(&count), ENUMEA_LEVEL_NO_VALUE);
  353.   if (rc)
  354.   {
  355.     delete pdena;
  356.     EA::errorHandler(EA::ReadError, rc);
  357.     return EA::NameSet();
  358.   }
  359.   EA::NameSet nameSet;
  360.   DENA2* pWalker = pdena;
  361.   while (count--)
  362.   {
  363.     nameSet.add(EA::Name(IString(pWalker->szName, unsigned(pWalker->cbName)), (EA::Flagset)(pWalker->fEA)));
  364.     pWalker = (DENA2*)((char*)pWalker + pWalker->oNextEntryOffset);
  365.   }
  366.   delete pdena;
  367.   return nameSet;
  368. }
  369.  
  370.  
  371. void setupGEA(EAOP2* peaop2, const IString& name)
  372. {
  373.   EAOP2& eaop2 = *peaop2;
  374.   eaop2.oError = 0;
  375.   eaop2.fpGEA2List->list[0].oNextEntryOffset = 0;
  376.   eaop2.fpGEA2List->list[0].cbName = (BYTE)name.length();
  377.   strcpy(eaop2.fpGEA2List->list[0].szName, name);
  378.   eaop2.fpGEA2List->cbList = name.length()
  379.     + sizeof(eaop2.fpGEA2List->list[0].oNextEntryOffset)
  380.     + sizeof(eaop2.fpGEA2List->list[0].cbName)
  381.     + sizeof(eaop2.fpGEA2List->cbList);
  382.   if (eaop2.fpGEA2List->cbList % 4)
  383.   {
  384.     eaop2.fpGEA2List->cbList+= 4-(eaop2.fpGEA2List->cbList % 4);
  385.   }
  386.   eaop2.fpFEA2List->cbList = 65536;
  387. }
  388.  
  389.  
  390. EA* createFrom(EAOP2* peaop2, const EA::CreatorMap& cm)
  391. {
  392.   EAOP2& eaop2 = *peaop2;
  393.  
  394.   if (eaop2.fpFEA2List->list[0].cbValue == 0)
  395.   {
  396.     EA::errorHandler(EA::NoSuchEAError, 0);
  397.     return 0;
  398.   }
  399.   istrstream is(eaop2.fpFEA2List->list[0].szName+eaop2.fpFEA2List->list[0].cbName+1,
  400.                 eaop2.fpFEA2List->list[0].cbValue);
  401.   EA::Identifier type;
  402.   is.read((char*)(&type), sizeof(type));
  403.   streampos beginning = is.tellg();
  404.   EA::CreatorMap::Cursor cur(cm);
  405.   EA* pea = cm.locateElementWithKey(type, cur) ? cur.element().c(is,cur.element().pSubMap) : 0;
  406.   if (pea)
  407.   {
  408.     is.seekg(beginning);
  409.     pea->setCreatorMap(&cm);
  410.     pea->readFrom(is);
  411.   }
  412.   return pea;
  413. }
  414.  
  415.  
  416. static char* prepareFEA(EAOP2* peaop2, const IString& name)
  417. {
  418.   EAOP2& eaop2 = *peaop2;
  419.   eaop2.oError = 0;
  420.   eaop2.fpFEA2List->list[0].oNextEntryOffset = 0;
  421.   eaop2.fpFEA2List->list[0].cbName = (BYTE)name.length();
  422.   strcpy(eaop2.fpFEA2List->list[0].szName, name);
  423.   char* p = eaop2.fpFEA2List->list[0].szName+
  424.             eaop2.fpFEA2List->list[0].cbName+1;
  425.   return p;
  426. }
  427.  
  428.  
  429. static void defaultErrorHandler(EA::Error e, ULONG u)
  430. {
  431.   switch (e) {
  432.   case EA::ReadError:
  433.     {
  434.       EAReadError err("Failed to read EA", u, IException::recoverable);
  435.       throw err;
  436.     }
  437.     break;
  438.   case EA::WriteError:
  439.     {
  440.       EAWriteError err("Failed to write EA", u, IException::recoverable);
  441.       throw err;
  442.     }
  443.     break;
  444.   case EA::NoSuchEAError:
  445.   case EA::TypeMismatchError:
  446.     {
  447.       EATypeMismatchError err(e == EA::NoSuchEAError
  448.                               ? "Unknown EA type" : "Unexpected EA type",
  449.                               u, IException::recoverable);
  450.        // error code 0 means that there was no EA to read
  451.       throw err;
  452.     }
  453.     break;
  454.   default:
  455.     {
  456.       EAError err("Unknown error!!!", u);
  457.       throw err;
  458.     }
  459.   }
  460. }
  461.  
  462.  
  463.