home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / BC_502 / OWLSRC.PAK / STGDOC.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  28.5 KB  |  1,206 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // Copyright (c) 1993, 1997 by Borland International, All Rights Reserved
  4. //
  5. //$Revision:   10.6  $
  6. //
  7. // Implementation of classes TStorageDocument, TDocFile, and associated streams
  8. //----------------------------------------------------------------------------
  9. #define INC_OLE2
  10. #include <owl/pch.h>
  11. #if !defined(OWL_DOCVIEW_H)
  12. # include <owl/docview.h>      // force Windows headers in before OLE
  13. #endif
  14. #if !defined(WINSYS_STRING_H)
  15. # include <winsys/string.h>
  16. #endif
  17. #if !defined(OWL_STGDOC_H)
  18. # include <owl/stgdoc.h>
  19. #endif
  20. #include <stdio.h>
  21.  
  22. OWL_DIAGINFO;
  23.  
  24. #if defined(BI_NAMESPACE)
  25. namespace OWL {
  26. #endif
  27.  
  28. //
  29. // Simple refcount debug assistant
  30. //
  31. #if defined(CHECK_REFCOUNT)
  32. static void RefCountCheck(IStorage far* si) {
  33.   uint32 count = si->AddRef();
  34.   count = si->Release();
  35. }
  36. #else
  37. # define RefCountCheck(si)
  38. #endif
  39.  
  40. const int B_size    = 516;                // default buffer size
  41. const char DefaultStreamName[] = "Contents";
  42.  
  43. //
  44. // class TStorageBuf
  45. // ~~~~~ ~~~~~~~~~~~
  46. class  _OWLCLASS_RTL TStorageBuf : public streambuf {
  47.   public:
  48.     // Constructors, destructor
  49.     //
  50.     TStorageBuf _FAR * open(IStorage& stg, LPCSTR name, int omode);
  51.     TStorageBuf();                       // make a closed TStorageBuf
  52.     virtual ~TStorageBuf();
  53.  
  54.     int is_open() { return opened; }     // is the file open
  55.     IStream* fd() { return strm; }
  56.  
  57.     TStorageBuf _FAR * close();          // flush and close file
  58. //  TStorageBuf _FAR * attach(IStream*); // attach this TStorageBuf to opened IStream
  59.     virtual int overflow(int = EOF);
  60.     virtual int underflow();
  61.     virtual int sync();
  62.     virtual streampos  seekoff(streamoff, ios::seek_dir, int);
  63.     virtual streambuf _FAR * setbuf(char _FAR *, int);
  64.  
  65.   protected:
  66. //  IStorage* stg;       // parent storage
  67.     IStream*  strm;
  68.     int       mode;      // the opened mode
  69.     short     opened;    // non-zero if stream is open
  70.     uint64    last_seek;
  71.     char      lahead[2]; // current input char if unbuffered
  72. };
  73.  
  74. //
  75. // class TStorageStreamBase
  76. // ~~~~~ ~~~~~~~~~~~~~~~~~~
  77. class _OWLCLASS_RTL TStorageStreamBase : virtual public ios {
  78.   public:
  79.     TStorageStreamBase(IStorage& stg, const char far* name, int mode);
  80.    ~TStorageStreamBase() {}
  81.     void    setbuf(char _FAR *, int);
  82.     void    close();
  83.  
  84.     TStorageBuf buf;
  85. };
  86.  
  87. //
  88. // class TStorageInStream
  89. // ~~~~~ ~~~~~~~~~~~~~~~~
  90. class _OWLCLASS_RTL TStorageInStream : public TStorageStreamBase,
  91.                                        public TInStream {
  92.   public:
  93.     TStorageInStream(TStorageDocument& doc,  const char far* name, int mode)
  94.                            : TInStream(doc,         name,     mode),
  95.                    TStorageStreamBase(*doc.StorageI,name,     mode) {}
  96.    ~TStorageInStream() {}
  97. };
  98.  
  99. //
  100. // class TStorageOutStream
  101. // ~~~~~ ~~~~~~~~~~~~~~~~~
  102. class _OWLCLASS_RTL TStorageOutStream : public TStorageStreamBase,
  103.                                         public TOutStream {
  104.   public:
  105.     TStorageOutStream(TStorageDocument& doc,  const char far* name, int mode)
  106.                            : TOutStream(doc,         name,     mode),
  107.                     TStorageStreamBase(*doc.StorageI,name,     mode) {}
  108.    ~TStorageOutStream() {}
  109. };
  110.  
  111. #if defined(BI_NAMESPACE)
  112. } // namespace OWL
  113. #endif
  114.  
  115. //----------------------------------------------------------------------------
  116. // class TStorageDocument
  117. //
  118.  
  119. //
  120. //
  121. //
  122. TStorageDocument::~TStorageDocument()
  123. {
  124.   ReleaseDoc();
  125.   SetDirty(false); // ~TDocument() will Close() after destroying children
  126. }
  127.  
  128. //
  129. // Release the IStorage and close the document
  130. //
  131. bool
  132. TStorageDocument::ReleaseDoc()
  133. {
  134.   CanRelease = true; // now we can release the storage
  135.   return Close();
  136. }
  137.  
  138. //
  139. // Open the compound file with a given path
  140. //
  141. bool
  142. TStorageDocument::Open(int omode, const char far* name)
  143. {
  144.   if (StorageI)
  145.     return true;
  146.  
  147.   do {  // establish try block
  148.     HRESULT hr;
  149.     IStorage* parentStg;
  150.     int pmode = 0;
  151.  
  152.     if (!omode)
  153.       omode = GetOpenMode();
  154.  
  155.     if (GetParentDoc()) {
  156.       pmode = GetParentDoc()->GetOpenMode();
  157.       if (!(GetParentDoc()->Open(pmode ? pmode : omode, name)))
  158.         return false;
  159.     }
  160.     ++OpenCount;
  161.     if (!omode)
  162.       omode = pmode;
  163.     if (!(omode & (ofRead | ofWrite)))
  164.       break;
  165.  
  166.     // Provide default share mode flags & enforce root storage restrictions
  167.     // when in direct mode
  168.     //
  169.     if (!(omode & shMask)) {
  170.       if (!(omode & ofTransacted) && !GetParentDoc()) { // direct mode root stg
  171.         if (omode & ofWrite)
  172.           omode |= ofRead | shNone; // let others do nothing if we are writing
  173.         else
  174.           omode |= shRead;          // let others only read if we are readonly
  175.       }
  176.       else {
  177.         if (omode & ofWrite)
  178.           omode |= shRead;       // let others only read if we are writing
  179.         else
  180.           omode |= shReadWrite;  // let others read/write if we are readonly
  181.       }
  182.     }
  183.  
  184.     ThisOpen = omode;
  185.     SetOpenMode(omode);  // remember the open mode
  186.     if (name && name[0])
  187.       SetDocPath(name);
  188.     else
  189.       name = GetDocPath();
  190.     long shareMode = ((omode & shMask) - shCompat) >> 5;
  191.     long grfMode = ((omode & (ofRead|ofWrite)) - 1)
  192.                  | shareMode
  193.                  | ((long)(omode & (ofTransacted|ofPreserve|ofPriority)) << 4)
  194.                  | ((omode & ofTemporary) ? STGM_DELETEONRELEASE : 0);
  195.     long childMode = (grfMode ^ shareMode) | STGM_SHARE_EXCLUSIVE;
  196.  
  197.     bool stgopen = true;
  198.     bool stgcreate = false;
  199.  
  200.     if (omode & ofWrite) {
  201.       if (omode & ofNoReplace) {
  202.         stgopen = false;
  203.         stgcreate = true;
  204.       }
  205.       else if (!(omode & ofNoCreate)) {
  206.         stgcreate = true;
  207.         if (omode & ofTruncate || !(omode & (ofAtEnd | ofAppend))) {
  208.           stgopen = false;
  209.           grfMode |= STGM_CREATE;
  210.           childMode |= STGM_CREATE;
  211.         }
  212.       }
  213.     }
  214.     if (GetParentDoc()) {
  215.       if (!GetParentDoc()->GetProperty(FindProperty("IStorage Instance"),
  216.                                        &parentStg, 0))
  217.         break;
  218.       if (stgopen) {
  219.         hr = parentStg->OpenStorage(OleStr(name), 0, childMode, 0, 0, &StorageI);
  220.         if (SUCCEEDED(hr))
  221.           stgcreate = false;
  222.       }
  223.       if (stgcreate) {
  224.         hr = parentStg->CreateStorage(OleStr(name), childMode, 0, 0, &StorageI);
  225.       }
  226.     }
  227.     else {
  228.       if (stgopen) {
  229.         hr = ::StgOpenStorage(OleStr(name), 0, grfMode, 0, 0, &StorageI);
  230.         if (SUCCEEDED(hr))
  231.           stgcreate = false;
  232.       }
  233.       if (stgcreate) {
  234.         hr = ::StgCreateDocfile(OleStr(name), grfMode, 0, &StorageI);
  235.       }
  236.     }
  237.     RefCountCheck(StorageI);
  238.  
  239.     if (!SUCCEEDED(hr))
  240.       break;
  241.     NotifyViews(vnDocOpened,ThisOpen);
  242.     return true;  // successful return
  243.   } while (0);    // dummy for break scoping, never executed
  244.  
  245.   // exception handling
  246.   //
  247.   if (GetParentDoc())
  248.     GetParentDoc()->Close();
  249.   --OpenCount;
  250.  
  251.   return false;
  252. }
  253.  
  254. const int stgRdWrMask  = (int)(STGM_READWRITE | STGM_READ | STGM_WRITE);
  255. const int stgShareMask = (int)(STGM_SHARE_DENY_NONE | STGM_SHARE_DENY_READ |
  256.                          STGM_SHARE_DENY_WRITE| STGM_SHARE_EXCLUSIVE);
  257. const long stgModeMask  = (STGM_TRANSACTED | STGM_PRIORITY | STGM_CONVERT);
  258.  
  259. //
  260. // Give an IStorage to document. This typically happens for OLE servers.
  261. //
  262. bool
  263. TStorageDocument::SetStorage(IStorage* stg, bool remember)
  264. {
  265.   if (stg == StorageI)
  266.     return true; // already set
  267.  
  268.   if (StorageI) {
  269.     RefCountCheck(StorageI);
  270.     if (remember) {
  271.       StorageI->Release();  // Release the ole one
  272.       OrgStorageI = 0;
  273.     }
  274.     else
  275.       OrgStorageI = StorageI;
  276.   }
  277.  
  278.   StorageI = stg;
  279.   if (!StorageI)
  280.     return true;  // done
  281.  
  282.   StorageI->AddRef();
  283.   RefCountCheck(StorageI);
  284.  
  285.   STATSTG stgInfo;
  286.   if (!SUCCEEDED(stg->Stat(&stgInfo, 0)))
  287.     return false;
  288.  
  289.   SetOpenMode((int)((stgInfo.grfMode & stgRdWrMask) + 1)
  290.            | (int)(((stgInfo.grfMode & stgShareMask) << 5) + shCompat)
  291.            | (int)((stgInfo.grfMode & stgModeMask) >> 4)
  292.            | ((stgInfo.grfMode & STGM_DELETEONRELEASE) ? ofTemporary : 0));
  293.  
  294.   ThisOpen = GetOpenMode();
  295.   if (remember)
  296.     if (stgInfo.pwcsName)
  297.       SetDocPath(OleStr(stgInfo.pwcsName));
  298.     else
  299.       SetDocPath("  ");
  300.  
  301.   if (stgInfo.pwcsName) {
  302.     IMalloc* memmgr;
  303.     if (SUCCEEDED(CoGetMalloc(MEMCTX_TASK, &memmgr))) {
  304.       memmgr->Free(stgInfo.pwcsName);    // Free the string from the Stat call
  305.       memmgr->Release();
  306.     }
  307.   }
  308.  
  309. //  NotifyViews(vnDocOpened,ThisOpen);
  310.   return true;
  311. }
  312.  
  313. //
  314. // Restore the original root IStorage before the save operation
  315. //
  316. bool
  317. TStorageDocument::RestoreStorage()
  318. {
  319.   if (OrgStorageI) {
  320.     if (StorageI)
  321.       StorageI->Release();
  322.  
  323.     StorageI = OrgStorageI;
  324.     OrgStorageI = 0;
  325.   }
  326.  
  327.   return true;
  328. }
  329.  
  330. //
  331. // Get a new IStorage, typically in a SaveAs situation. Release StorageI and
  332. // set it to the new storage if all OK.
  333. //
  334. IStorage*
  335. TStorageDocument::GetNewStorage()
  336. {
  337.   PRECONDITION(StorageI);
  338.  
  339.   STATSTG stgInfo;
  340.   if (!SUCCEEDED(StorageI->Stat(&stgInfo, STATFLAG_NONAME)))
  341.     return 0;
  342.  
  343.   // Create another root storage based on the new doc path
  344.   // Should close the current document and open a new one.
  345.   //
  346.   IStorage* newStorage = 0;
  347.  
  348.   HRESULT hr;
  349.   hr = ::StgOpenStorage(OleStr(GetDocPath()), 0, stgInfo.grfMode, 0, 0, &newStorage);
  350.   if (!SUCCEEDED(hr))
  351.     hr = ::StgCreateDocfile(OleStr(GetDocPath()), stgInfo.grfMode, 0, &newStorage);
  352.  
  353.   if (SUCCEEDED(hr)) {
  354.     StorageI->Release(); // Release the old root storage
  355.     StorageI = newStorage;
  356.   }
  357.  
  358.   return newStorage;
  359. }
  360.  
  361. //
  362. // Create an IStorage based on a memory handle
  363. //
  364. bool
  365. TStorageDocument::OpenHandle(int omode, HANDLE hGlobal)
  366. {
  367.   int pmode = 0;
  368.  
  369.   if (!omode)
  370.     omode = GetOpenMode();
  371.  
  372.   if (!omode)
  373.     omode = pmode;
  374.   if (!(omode & (ofRead | ofWrite)))
  375.     return false;
  376.   if (!(omode & shMask))
  377.     omode |= shNone;
  378.  
  379.   ThisOpen = omode;
  380.   SetOpenMode(omode);  // remember the open mode
  381.   long shareMode = ((omode & shMask) - shCompat) >> 5;
  382.   long grfMode = ((omode & (ofRead|ofWrite)) - 1)
  383.                | shareMode
  384.                | ((long)(omode & (ofTransacted|ofPreserve|ofPriority)) << 4)
  385.                | STGM_CREATE;
  386.   if (!SUCCEEDED(CreateILockBytesOnHGlobal(hGlobal, (omode & ofTemporary)!=0, &LockBytes)))
  387.     return false;
  388.   if (!SUCCEEDED(StgCreateDocfileOnILockBytes(LockBytes, grfMode, 0, &StorageI))) {
  389.     LockBytes->Release();
  390.     LockBytes = 0;
  391.     return false;
  392.   }
  393.   ++OpenCount;
  394.   NotifyViews(vnDocOpened,omode);
  395.   return true;
  396. }
  397.  
  398. //
  399. // Replace the IStorage with an istorage based on a memory handle
  400. //
  401. bool
  402. TStorageDocument::SetHandle(int omode, HANDLE hGlobal, bool create, bool remember)
  403. {
  404.   int pmode = 0;
  405.  
  406.   if (!omode)
  407.     omode = GetOpenMode();
  408.  
  409.   if (!omode)
  410.     omode = pmode;
  411.   if (!(omode & (ofRead | ofWrite)))
  412.     return false;
  413.   if (!(omode & shMask))
  414.     omode |= shNone;
  415.  
  416.   ThisOpen = omode;
  417.   SetOpenMode(omode);  // remember the open mode
  418.   long shareMode = ((omode & shMask) - shCompat) >> 5;
  419.   long grfMode = ((omode & (ofRead|ofWrite)) - 1)
  420.                | shareMode
  421.                | ((long)(omode & (ofTransacted|ofPreserve|ofPriority)) << 4);
  422.   if (!SUCCEEDED(CreateILockBytesOnHGlobal(hGlobal, (omode & ofTemporary)!=0, &LockBytes)))
  423.     return false;
  424.  
  425.   IStorage* storageI = 0;
  426.   if (!SUCCEEDED(StgOpenStorageOnILockBytes(LockBytes, 0, grfMode, 0, 0, &storageI))) {
  427.     if (create && !SUCCEEDED(StgCreateDocfileOnILockBytes(LockBytes,
  428.                              grfMode |STGM_CREATE, 0, &storageI))) {
  429.       LockBytes->Release();
  430.       LockBytes = 0;
  431.       return false;
  432.     }
  433.  
  434.     if (!storageI)
  435.       return false;
  436.   }
  437.  
  438.   RefCountCheck(storageI);
  439.  
  440.   // Don't change the embedded flag
  441.   bool embed = IsEmbedded();
  442.   SetStorage(storageI, remember);
  443.   SetEmbedded(embed);
  444.  
  445.   storageI->Release(); // release extra refcount held by SetStorage
  446.   return true;
  447. }
  448.  
  449. //
  450. // Get the global handle from ILockBytes
  451. //
  452. bool
  453. TStorageDocument::GetHandle(HGLOBAL* handle)
  454. {
  455.   if (!LockBytes)
  456.     return false;
  457.  
  458.   GetHGlobalFromILockBytes(LockBytes, handle);
  459.   return true;
  460. }
  461.  
  462. //
  463. //
  464. //
  465. bool
  466. TStorageDocument::Close()
  467. {
  468.   if (!StorageI || !CanRelease)
  469.     return true;
  470.  
  471.   if (StorageI)
  472.     StorageI->Release();
  473.  
  474.   StorageI = 0;
  475.   NotifyViews(vnDocClosed,ThisOpen);
  476.   SetDirty(false);
  477.   CanRelease = false;
  478.   if (GetParentDoc())
  479.     GetParentDoc()->Close();
  480.   return true;
  481. }
  482.  
  483. //
  484. //
  485. //
  486. void
  487. TStorageDocument::DetachStream(TStream& strm)
  488. {
  489.   TDocument::DetachStream(strm);
  490.   TStorageDocument::Close();
  491. }
  492.  
  493. //
  494. //
  495. //
  496. TInStream*
  497. TStorageDocument::InStream(int omode, const char far* strmId)
  498. {
  499.   TInStream* inStream;
  500.   if (omode == ofParent)
  501.     omode = IsOpen() ? ThisOpen : GetOpenMode();
  502.   if (!(omode & ofRead))
  503.     return 0;
  504.   if (!TStorageDocument::Open(GetOpenMode() ? GetOpenMode() | ofRead : omode, strmId))
  505.     return 0;
  506.  
  507.   inStream = new TStorageInStream(*this, strmId, omode);
  508.   if (inStream && !inStream->good()) {
  509.     delete inStream;
  510.     TStorageDocument::Close();  // close
  511.     return 0;
  512.   }
  513.  
  514.   return inStream;
  515. }
  516.  
  517. //
  518. //
  519. //
  520. TOutStream*
  521. TStorageDocument::OutStream(int omode, const char far* strmId)
  522. {
  523.   TOutStream* outStream;
  524.   if (omode == ofParent)
  525.     omode = IsOpen() ? ThisOpen : GetOpenMode();
  526.   if (!(omode & ofWrite))
  527.     return 0;
  528.   if (!TStorageDocument::Open(GetOpenMode() ? GetOpenMode() | ofWrite : omode, strmId))
  529.     return 0;
  530.   outStream = new TStorageOutStream(*this, strmId, omode); // change
  531.   if (outStream && !outStream->good()) {
  532.     delete outStream;
  533.     TStorageDocument::Close();  // change
  534.     return 0;
  535.   }
  536.   SetDirty();     // we don't really know at this point if it will be dirty!!
  537.   return outStream;
  538. }
  539.  
  540. //
  541. //
  542. //
  543. bool
  544. TStorageDocument::SetDocPath(const char far* path)
  545. {
  546.   TDocument::SetDocPath(path);
  547.   return true;
  548. }
  549.  
  550. //
  551. //
  552. //
  553. bool
  554. TStorageDocument::Commit(bool force)
  555. {
  556.   if (!TDocument::Commit(force))      // flush views and child docs
  557.     return false;
  558.   if (!StorageI)
  559.     return true;                      // return OK if storage already released
  560.  
  561.   CommitTransactedStorage();
  562.   SetDirty(false);
  563.   return true;
  564. }
  565.  
  566. //
  567. //
  568. //
  569. bool
  570. TStorageDocument::CommitTransactedStorage()
  571. {
  572.   HRESULT hr = StorageI->Commit(0);  // try 2phase commit first
  573.   if (!SUCCEEDED(hr)) // check for STG_S_TRYOVERWRITE, but GetScode not in lib
  574.     hr = StorageI->Commit(STGC_OVERWRITE);   // try less robust method
  575.   if (!SUCCEEDED(hr))
  576.     return false;
  577.  
  578.   return true;
  579. }
  580.  
  581. //
  582. //
  583. //
  584. bool
  585. TStorageDocument::Revert(bool clear)
  586. {
  587.   if (!StorageI)
  588.     return true;                    // return OK if storage already released
  589.   if (!TDocument::Revert(clear) || !SUCCEEDED(StorageI->Revert()))
  590.     return false;
  591.   SetDirty(false);
  592.   return true;
  593. }
  594.  
  595. //
  596. //
  597. //
  598. static char* PropNames[] = {
  599.   "Create Time",      // CreateTime
  600.   "Modify Time",      // ModifyTime
  601.   "Access Time",      // AccessTime
  602.   "Storage Size",     // StorageSize
  603.   "IStorage Instance",// IStorageInstance
  604. };
  605.  
  606. //
  607. //
  608. //
  609. static int PropFlags[] = {
  610.   pfGetBinary|pfGetText,   // CreateTime
  611.   pfGetBinary|pfGetText,   // ModifyTime
  612.   pfGetBinary|pfGetText,   // AccessTime
  613.   pfGetBinary|pfGetText,   // StorageSize
  614.   pfGetBinary,             // IStorage
  615. };
  616.  
  617. //
  618. //
  619. //
  620. const char*
  621. TStorageDocument::PropertyName(int index)
  622. {
  623.   if (index <= PrevProperty)
  624.     return TDocument::PropertyName(index);
  625.   else if (index < NextProperty)
  626.     return PropNames[index-PrevProperty-1];
  627.   else
  628.     return 0;
  629. }
  630.  
  631. //
  632. //
  633. //
  634. int
  635. TStorageDocument::PropertyFlags(int index)
  636. {
  637.   if (index <= PrevProperty)
  638.     return TDocument::PropertyFlags(index);
  639.   else if (index < NextProperty)
  640.     return PropFlags[index-PrevProperty-1];
  641.   else
  642.     return 0;
  643. }
  644.  
  645. //
  646. //
  647. //
  648. int
  649. TStorageDocument::FindProperty(const char far* name)
  650. {
  651.   for (int i = 0; i < NextProperty-PrevProperty-1; i++)
  652.     if (strcmp(PropNames[i], name) == 0)
  653.       return i+PrevProperty+1;
  654.   return 0;
  655. }
  656.  
  657. //
  658. //
  659. //
  660. int
  661. TStorageDocument::GetProperty(int prop, void far* dest, int textlen)
  662. {
  663.   STATSTG stgInfo;
  664.  
  665.   switch (prop) {
  666.     case IStorageInstance:
  667.       if (textlen)
  668.         return 0;
  669.       *(IStorage*far*)dest = StorageI;
  670.       return sizeof(IStorage*);
  671.  
  672.     default:
  673.       if (StorageI) {
  674.         StorageI->Stat(&stgInfo, STATFLAG_NONAME);
  675.         switch (prop) {
  676.           case StorageSize:
  677.             if (!textlen) {
  678.               *(ulong far*)dest = uint64(stgInfo.cbSize).LowPart;
  679.               return sizeof(ulong);
  680.             }
  681.             else {
  682.               char buf[10];
  683.               int len = sprintf(buf, "%ld", uint64(stgInfo.cbSize).LowPart);
  684.               if (textlen > len)
  685.                 textlen = len;
  686.               memcpy(dest, buf, textlen);
  687.               *((char far*)dest + textlen) = 0;
  688.               return len;
  689.             }
  690.           case AccessTime:
  691. #if defined(BI_PLAT_WIN32)
  692.             return FormatFileTime(&stgInfo.atime, dest, textlen);
  693. #endif
  694.           case CreateTime:
  695. #if defined(BI_PLAT_WIN32)
  696.             return FormatFileTime(&stgInfo.ctime, dest, textlen);
  697. #endif
  698.           case ModifyTime:
  699.             return FormatFileTime(&stgInfo.mtime, dest, textlen);
  700.         }
  701.       }
  702.       return TDocument::GetProperty(prop, dest, textlen);
  703.   }
  704. }
  705.  
  706. //
  707. //
  708. //
  709. bool
  710. TStorageDocument::SetProperty(int prop, const void far* src)
  711. {
  712.   // docfile properties currently not settable
  713.   //
  714.   return TDocument::SetProperty(prop, src);
  715. }
  716.  
  717. //
  718. //
  719. //
  720. IMPLEMENT_STREAMABLE1(TStorageDocument, TDocument);
  721.  
  722. #if !defined(BI_NO_OBJ_STREAMING)
  723.  
  724. //
  725. //
  726. //
  727. void*
  728. TStorageDocument::Streamer::Read(ipstream& is, uint32 /*version*/) const
  729. {
  730.   ReadBaseObject((TDocument*)GetObject(), is);
  731.   return GetObject();
  732. }
  733.  
  734. //
  735. //
  736. //
  737. void
  738. TStorageDocument::Streamer::Write(opstream& os) const
  739. {
  740.   WriteBaseObject((TDocument*)GetObject(), os);
  741. }
  742.  
  743. //----------------------------------------------------------------------------
  744. //  class TStorageStreamBase
  745. //
  746.  
  747. //
  748. //
  749. //
  750. TStorageStreamBase::TStorageStreamBase(IStorage& stg, const char far* name, int mode)
  751. :
  752.   buf()
  753. {
  754.   ios::init(&buf);
  755.  
  756.   if (buf.is_open())
  757.     clear(ios::failbit);     // fail - already open
  758.   else if (buf.open(stg, name, mode))
  759.     clear(ios::goodbit);     // successful open
  760.   else
  761.     clear(ios::badbit);      // open failed
  762. }
  763.  
  764. void TStorageStreamBase::setbuf(char* newbuf, int len)
  765. {
  766.   if (buf.setbuf(newbuf, len))
  767.     clear(ios::goodbit);
  768.   else
  769.     setstate(ios::failbit);
  770. }
  771.  
  772. void TStorageStreamBase::close()
  773. {
  774.   if (buf.close())
  775.     clear(ios::goodbit);
  776.   else
  777.     setstate(ios::failbit);
  778. }
  779.  
  780. //----------------------------------------------------------------------------
  781. //  class TStorageBuf
  782. //
  783.  
  784. //
  785. // make a closed TStorageBuf
  786. //
  787. TStorageBuf::TStorageBuf()
  788. {
  789.   mode = 0;
  790.   opened = 0;
  791.   char* p = new char[B_size];
  792.   if (p) {
  793.     setb(p, p+B_size, 1);   // ~streambuf() will delete buffer
  794.     setp(p+4, p+4);
  795.     setg(p, p+4, p+4);
  796.   }
  797. }
  798.  
  799. //
  800. // We assume that mode= means that we attached to an already-open file,
  801. // and should not now close it.  We do flush it in any case.
  802. //
  803. TStorageBuf::~TStorageBuf()
  804. {
  805.   if (mode)
  806.     close();
  807.   else
  808.     overflow(EOF);
  809. }
  810.  
  811. //
  812. // Open or create IStream with mode and protection, attach to this TStorageBuf.
  813. //
  814. TStorageBuf* TStorageBuf::open(IStorage& stg, const char far* name, int omode)
  815. {
  816. //int share = omode & shMask;
  817. //if (share < shCompat)
  818. //  share = shNone;
  819. //how = (share-shCompat) >> 5;
  820.  
  821.   if (opened || !omode)
  822.     return 0;
  823.  
  824.   if (!name)
  825.     name = DefaultStreamName;
  826.  
  827.   bool  stgopen = true;
  828.   bool  stgcreate = false;
  829.   uint32 how = STGM_SHARE_EXCLUSIVE;  // must open streams and child stg exclusive
  830.  
  831.   if (omode & ofWrite) {
  832.     if (!(mode & (ofAtEnd | ofAppend | ofRead)))
  833.       omode |= ofTruncate;  // output implies truncate unless in, app, or ate
  834.     if (omode & ofRead)
  835.       how |= STGM_READWRITE;
  836.     else
  837.       how |= STGM_WRITE;
  838.     if (omode & ofNoReplace) {
  839.       stgopen = false;
  840.       stgcreate = true;
  841.     }
  842.     else if (!(omode & ofNoCreate)) {
  843.       stgcreate = true;
  844.       if (omode & ofTruncate) {
  845.         stgopen = false;
  846.         how |= STGM_CREATE;
  847.       }
  848.     }
  849.   }
  850.   else if (omode & ofRead)
  851.     how |= STGM_READ;
  852.   else
  853.     return 0;   // must specfify in, out, or in/out
  854.  
  855. //if (omode & ofAppend)    // what does this mean for docfile?!!
  856. //    how |= O_APPEND;
  857.  
  858.   // Now try to open or create
  859.   //
  860.   if (stgopen) {
  861.     HRESULT hr = stg.OpenStream(OleStr(name), 0, how, 0, &strm);
  862.     if (SUCCEEDED(hr))
  863.       stgcreate = false;
  864.     else
  865.       return 0;
  866.   }
  867.   if (stgcreate) {
  868.     HRESULT hr = stg.CreateStream(OleStr(name), how, 0, 0, &strm);
  869.     if (!SUCCEEDED(hr))
  870.       return 0;
  871.   }
  872.  
  873.   // Finish up
  874.   //
  875.   opened = 1;
  876.   mode = omode;
  877.   if ((omode & ofAtEnd) != 0
  878.       && !SUCCEEDED(strm->Seek(int64(), STREAM_SEEK_END, (ULARGE_INTEGER*)&last_seek))) {
  879.     strm->Release();
  880.     strm = 0;
  881.     return 0;
  882.   }
  883.   char* b = base();       // buffer address
  884.   int pb = b ? ((blen() > 8) ? 4 : 1) : 0;    // putback area size
  885.   setp(b+pb, b+pb);
  886.   setg(b, b+pb, b+pb);
  887.  
  888.   return this;
  889. }
  890.  
  891. #if 0
  892. //
  893. // attach this TStorageBuf to open IStream -- assume fd is actually open
  894. //
  895. TStorageBuf* TStorageBuf::attach(IStream* f)
  896. {
  897.   STATSTG stat;
  898.   if (opened)
  899.     return 0;
  900.  
  901.   if (f->Stat(&stat, STATFLAG_NONAME) != 0)
  902.     return 0;
  903.  
  904.   if (f->CreateStream(STREAMNAME,stat.grfMode & ~STGM_TRANSACTED,0,0,&strm)!)
  905.     return 0;
  906.  
  907.   stg = f;        // assumed to be valid
  908.   opened = 1;
  909.   int rwmode = stat.grfMode & (STGM_READ | STGM_WRITE | STGM_READWRITE);
  910.   mode = rwmode != STGM_WRITE ? ofRead : 0;
  911.   if (rwmode != STGM_READ)
  912.     mode |= ofWrite;
  913.  
  914.   char* b = base();       // buffer address
  915.   if (!b) {
  916.     b = new char[B_size];
  917.     if (b)
  918.       setb(b, b+B_size, 1);   // ~streambuf() will delete buffer
  919.   }
  920.   int pb = b ? ((blen() > 8) ? 4 : 1) : 0;    // putback area size
  921.   setp(b+pb, b+pb);
  922.   setg(b, b+pb, b+pb);
  923.   return this;
  924. }
  925. #endif  // if !defined(BI_NO_OBJ_STREAMING)
  926.  
  927. #endif
  928.  
  929. //
  930. //
  931. //
  932. streambuf*
  933. TStorageBuf::setbuf(char* b, int len)
  934. {
  935.   if (opened && base())
  936.     return 0;        // already open with a buffer -- no change
  937.  
  938.   int pb;            // putback area size
  939.   if (b && len > 0)  // use b as the new buffer
  940.     pb = (len > 8) ? 4 : 1; // guard against tiny buffers
  941.   else {             // unbuffered
  942.     len = pb = 0;
  943.     b = 0;
  944.   }
  945.   setb(b, b+len, 0);      // will delete old buffer if needed
  946.   setp(b+pb, b+pb);
  947.   setg(b, b+pb, b+pb);
  948.   return this;
  949. }
  950.  
  951. //
  952. // Seek file to position.
  953. // We take a simple approach, and don't check for small position changes
  954. // within the current buffer.
  955. //
  956. streampos
  957. TStorageBuf::seekoff(streamoff off, ios::seek_dir dir, int /* mode ignored */)
  958. {
  959.   long loff = off;
  960.   int count = out_waiting();
  961.  
  962.   if (count) {  // flush the output
  963.     ulong actual;
  964.     HRESULT hr = strm->Write(pbase(), (ulong)count, &actual);
  965.     if (!SUCCEEDED(hr) || (int)actual != count)
  966.       return EOF;
  967.   }
  968.   else if (dir == ios::cur) {
  969.     count = in_avail();
  970.     if (count != 0) {
  971.       loff -= count;
  972.  
  973.       // If we're in text mode, need to allow for newlines in the buffer
  974.       //
  975.       if ((mode & ofBinary) == 0) {
  976.         char *tptr = gptr();
  977.         while (tptr != egptr())
  978.           if (*tptr++ == '\n')
  979.             loff--;
  980.       }
  981.     }
  982.   }
  983.  
  984.   uint32 w = (dir == ios::beg) ? STREAM_SEEK_SET
  985.        : ((dir == ios::cur) ? STREAM_SEEK_CUR
  986.        :       /* ios::end */ STREAM_SEEK_END);
  987.  
  988.   if (!SUCCEEDED(strm->Seek(int64(loff), w, (ULARGE_INTEGER*)&last_seek)))
  989.     return EOF; //?!!
  990.   if (!unbuffered() && base()) {      // set up get and put areas
  991.     int pb = (blen() > 8) ? 4 : 1;  // putback area size
  992.     char *b = base();
  993.     setp(b+pb, b+pb);
  994.     setg(b, b+pb, b+pb);
  995.   }
  996.   return last_seek.LowPart;
  997. }
  998.  
  999. //
  1000. //
  1001. //
  1002. int TStorageBuf::sync()
  1003. {
  1004.   if (!opened)
  1005.     return EOF;
  1006.  
  1007.   ulong actual;
  1008.   int count = out_waiting();
  1009.   if (count) {
  1010.     char* curp;
  1011.     char* srcp = pbase();
  1012.     char* endp = srcp + count;
  1013.  
  1014.     // Convert LF's to CR/LF if text mode
  1015.     //
  1016.     if ((mode & ofBinary) == 0) {
  1017.       for (curp = srcp; curp < endp; curp++) {
  1018.         if (*curp == '\n') {
  1019.           *curp = '\r';
  1020.           count = (int)(curp - srcp + 1);
  1021.           HRESULT hr = strm->Write(srcp, (unsigned long)count, &actual);
  1022.           if (!SUCCEEDED(hr) || (int)actual != count)
  1023.             return EOF;
  1024.           *(srcp = curp) = '\n';
  1025.         }
  1026.       }
  1027.       count = (int)(curp - srcp);  // write what remains in the buffer below
  1028.     }
  1029.     HRESULT hr = strm->Write(srcp, (ulong)count, &actual);
  1030.     if (!SUCCEEDED(hr) || (int)actual != count)
  1031.         return EOF;
  1032.  
  1033.     // Reset get and put areas
  1034.     //
  1035.     int pb = (blen() > 8) ? 4 : 1;  // putback area size
  1036.     char *b = base();
  1037.     setp(b+pb, b+blen());
  1038.     setg(b, b+pb, b+pb);
  1039.  
  1040.   }
  1041.   else if (in_avail()) {
  1042.     if (!SUCCEEDED(strm->Seek(int64(long(-in_avail())), STREAM_SEEK_CUR, (ULARGE_INTEGER*)&last_seek)))
  1043.       return EOF;
  1044.     setg(eback(), gptr(), gptr());
  1045.     setp(gptr(), gptr());
  1046.   }
  1047.   return 0;
  1048. }
  1049.  
  1050. //
  1051. //
  1052. //
  1053. int TStorageBuf::underflow()
  1054. {
  1055.   ulong  actual;
  1056.   uint   count;  // input character count
  1057.   int    c;      // the return value
  1058.  
  1059.   if (!opened || (mode & (ofRead | ofWrite)) == ofWrite)
  1060.     return EOF;
  1061.  
  1062.   if (in_avail())                   // no action needed
  1063.     return (uchar)*gptr();
  1064.  
  1065.   if (!unbuffered() && base()) {    // this is buffered
  1066.     if (sync() != 0)
  1067.       return EOF;
  1068.  
  1069.     // find buffer data
  1070.     //
  1071.     int pb = (blen() > 8) ? 4 : 1;  // putback area size
  1072.     char* begp = base() + pb;
  1073.  
  1074.     // read in a new buffer
  1075.     //
  1076.     HRESULT hr = strm->Read(begp, blen()-pb, &actual);
  1077.     if (!SUCCEEDED(hr))
  1078.       return EOF;
  1079.     count = (unsigned)actual;
  1080.  
  1081.     // remove CR's if text mode
  1082.     //
  1083.     if ((mode & ofBinary) == 0) {
  1084.       char* endp = begp + count;
  1085.       char* dstp = 0;
  1086.       char* srcp = 0;
  1087.       char* curp;
  1088.  
  1089.       for (curp = begp;  curp < endp; curp++) {
  1090.         if (*curp == '\r') {
  1091.           if (dstp) {
  1092.             memcpy(dstp, srcp, (int)(curp - srcp));
  1093.             dstp += (int)(curp - srcp);
  1094.           }
  1095.           else
  1096.             dstp = curp;
  1097.           srcp = curp + 1;
  1098.         }
  1099.       }
  1100.       if (dstp) {
  1101.         endp = dstp + (int)(curp - srcp);
  1102.         if (curp != srcp)
  1103.           memcpy(dstp, srcp, (int)(curp - srcp));
  1104.       }
  1105.       count = (int)(endp - begp);
  1106.     }
  1107.  
  1108.     // set up get and put areas
  1109.     //
  1110.     setg(base(), begp, begp + count);
  1111.     setp(begp, begp);
  1112.  
  1113.     if (count)
  1114.       c = (uchar)*gptr();
  1115.  
  1116.   }
  1117.   else {     // this is not buffered
  1118.     for (;;) {
  1119.       HRESULT hr = strm->Read(lahead, 1, &actual);
  1120.       if (!SUCCEEDED(hr) || actual == 0) {
  1121.         c = EOF;
  1122.         setg(0, 0, 0);
  1123.       }
  1124.       else {
  1125.         c = (uchar)lahead[0];
  1126.         if ((mode & ofBinary) == 0  && c == '\r')
  1127.           continue;
  1128.         setg(lahead, lahead, lahead+1);
  1129.       }
  1130.       break;
  1131.     }
  1132.   }
  1133.   if (!count)
  1134.     c = EOF;    // end of file
  1135.   return c;
  1136. }
  1137.  
  1138. //
  1139. // always flush
  1140. //
  1141. int TStorageBuf::overflow(int c)
  1142. {
  1143.   if (!opened || (mode & (ofRead | ofWrite)) == ofRead)
  1144.     return EOF;
  1145.  
  1146.   if (unbuffered() || !base()) {
  1147.     if (c != EOF) {
  1148.       int count;
  1149.       char b[2];
  1150.       if (c == '\n' && (mode & ofBinary) == 0) {
  1151.         b[0] = '\r';
  1152.         b[1] = (char)c;
  1153.         count = 2;
  1154.       }
  1155.       else {
  1156.         b[0] = (char)c;
  1157.         count = 1;
  1158.       }
  1159.       ulong actual = 0;
  1160.       strm->Write(&c, (ulong)count, &actual);
  1161.       if ((int)actual != count)
  1162.         return EOF;
  1163.     }
  1164.   }
  1165.   else {    // now we know this is buffered and state is not bad
  1166.  
  1167.     // resets get and put areas
  1168.     //
  1169.     if (sync() != 0)
  1170.       return EOF;
  1171.  
  1172.     // reset get and put areas
  1173.     //
  1174.     int pb = (blen() > 8) ? 4 : 1;  // putback area size
  1175.     char *b = base();
  1176.     setp(b+pb, b+blen());
  1177.     setg(b, b+pb, b+pb);
  1178.  
  1179.     if (c != EOF) {
  1180.       sputc(c);
  1181.       gbump(1);       // pptr and gptr must be the same
  1182.     }
  1183.   }
  1184.   return 1;
  1185. }
  1186.  
  1187. //
  1188. // flush and close file
  1189. //
  1190. TStorageBuf* TStorageBuf::close()
  1191. {
  1192.   if (!opened)
  1193.     return 0;         // nothing to do
  1194.  
  1195.   int ores = 0;       // result of overflow()
  1196.   if (out_waiting() && overflow(EOF) == EOF)
  1197.     ores = 1;
  1198.   if ((mode & ofWrite) /* && !strm->Commit(0) */)
  1199.     ores = 1;
  1200.  
  1201.   strm->Release();    
  1202.   strm = 0;
  1203.   opened = 0;
  1204.   return ores ? 0 : this;
  1205. }
  1206.