home *** CD-ROM | disk | FTP | other *** search
/ C Programming Starter Kit 2.0 / SamsPublishing-CProgrammingStarterKit-v2.0-Win31.iso / bc45 / owlsrc.pak / STGDOC.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-07-24  |  27.4 KB  |  1,147 lines

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