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

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // Copyright (c) 1993, 1997 by Borland International, All Rights Reserved
  4. //
  5. //$Revision:   10.10  $
  6. //
  7. // Implementation of classes TFileDocument, TFileInStream, TFileOutStream,
  8. // TFileBuf
  9. //----------------------------------------------------------------------------
  10. #pragma hdrignore SECTION
  11. #include <owl/pch.h>
  12. #if !defined(OWL_FILEDOC_H)
  13. # include <owl/filedoc.h>
  14. #endif
  15. #include <stdio.h>
  16.  
  17. OWL_DIAGINFO;
  18.  
  19. #if !defined(SECTION) || SECTION == 1
  20.  
  21. #if defined(BI_NAMESPACE)
  22. namespace OWL {
  23. #endif
  24.  
  25. //
  26. // class TFileBuf
  27. // ~~~~~ ~~~~~~~~
  28. class _OWLCLASS_RTL TFileBuf : public streambuf {
  29.   public:
  30.     enum { shDefault = shReadWrite };  // default file sharing
  31.  
  32.     TFileBuf(int fhdl, int omode, streampos seekpos);
  33.    ~TFileBuf() {}
  34.  
  35.     virtual int overflow(int = EOF);
  36.     virtual int underflow();
  37.     virtual int sync();
  38.     virtual streampos  seekoff(streamoff, ios::seek_dir, int);
  39.  
  40.     int       xfd;       // the file descriptor, EOF if closed
  41.     int       mode;      // the opened mode
  42.     streampos last_seek;
  43.     char      lahead[2]; // current input char if unbuffered
  44. };
  45.  
  46. //
  47. // class TFileStreamBase
  48. // ~~~~~ ~~~~~~~~~~~~~~~
  49. //
  50. class _OWLCLASS_RTL TFileStreamBase : virtual public ios {
  51.   public:
  52.     TFileStreamBase(int fhdl, int omode, streampos seekpos);
  53.    ~TFileStreamBase() {}
  54.     TFileBuf buf;
  55. };
  56.  
  57. //
  58. // class TFileInStream
  59. // ~~~~~ ~~~~~~~~~~~~~
  60. class _OWLCLASS_RTL TFileInStream : public TFileStreamBase, public TInStream {
  61.   public:
  62.     TFileInStream(TFileDocument& doc, HFILE fhdl, int omode, streampos seekpos)
  63.                : TInStream (doc,0,omode), TFileStreamBase(fhdl,omode,seekpos){}
  64.    ~TFileInStream();
  65. };
  66.  
  67. //
  68. // class TFileOutStream
  69. // ~~~~~ ~~~~~~~~~~~~~~
  70. class _OWLCLASS_RTL TFileOutStream : public TFileStreamBase, public TOutStream {
  71.   public:
  72.     TFileOutStream(TFileDocument& doc, HFILE fhdl, int omode, streampos seekpos)
  73.               : TOutStream (doc,0,omode), TFileStreamBase(fhdl,omode,seekpos){}
  74.    ~TFileOutStream();
  75. };
  76.  
  77. #if defined(BI_NAMESPACE)
  78. } // namespace OWL
  79. #endif
  80.  
  81. //----------------------------------------------------------------------------
  82.  
  83. //
  84. //
  85. //
  86. HFILE
  87. TFileDocument::OpenThisFile(int omode, const char far* name, streampos* pseekpos){
  88.   int how;
  89.   HFILE fhdl;
  90.   bool exists = false;
  91.   int share = omode & shMask;
  92.  
  93.   if (share < shCompat)
  94.     share = (omode & ofWrite) ? shRead : shReadWrite;
  95.  
  96.   how = ((unsigned)(share-shCompat)) >> 5;
  97.  
  98.   if (omode & ofWrite) {
  99.     if (!(omode & (ofAtEnd | ofAppend | ofRead)))
  100.       omode |= ofTruncate; // output implies truncate unless in, app, or ate
  101.  
  102.     if (omode & ofRead)
  103.       how |= OF_READWRITE;
  104.     else
  105.       how |= OF_WRITE;
  106.     if (!((omode & ofNoCreate) && !(omode & ofTruncate))) {
  107.       if (!((omode & ofTruncate) && !(omode & (ofNoCreate | ofNoReplace)))) {
  108.         if ((fhdl=::_lopen(name,OF_READ|OF_SHARE_COMPAT))   !=HFILE_ERROR
  109.         ||  (fhdl=::_lopen(name,OF_READ|OF_SHARE_DENY_NONE))!=HFILE_ERROR) {
  110.           ::_lclose(fhdl);
  111.           exists = true;
  112.           }
  113.         }
  114.       if (!(exists && !(omode & (ofNoCreate | ofNoReplace)))) {
  115.         if ((exists && (omode & ofNoReplace))
  116.         || (!exists && (omode & ofNoCreate)) )
  117.             return 0;
  118.         if ((fhdl = _lcreat(name, 0)) == HFILE_ERROR)
  119.             return HFILE_ERROR;
  120.         ::_lclose(fhdl);   // close in order to open with share mode
  121.         }
  122.       }
  123.     }
  124.   else if (omode & ofRead)
  125.     how |= OF_READ;
  126.   else
  127.     return HFILE_ERROR;   // must specfify in, out, or in/out
  128.  
  129.   if ((fhdl = ::_lopen(name, how)) != HFILE_ERROR) {
  130.     if ((*pseekpos = ::_llseek(fhdl, 0, (omode & (ofAtEnd|ofAppend))
  131.                              ? SEEK_END : SEEK_SET)) == long(HFILE_ERROR)) {
  132.       ::_lclose(fhdl);
  133.       return HFILE_ERROR;
  134.     }
  135.   }
  136. #if defined(BI_PLAT_WIN32)
  137.   FileLength = GetFileSize((HANDLE)fhdl, 0);
  138.   InfoPresent = GetFileTime((HANDLE)fhdl, &FileCreateTime, &FileAccessTime,
  139.                             &FileUpdateTime);
  140. #else
  141.   FileLength = CalcFileLength(fhdl);
  142.   getftime(fhdl, (struct ftime*)&FileTime);
  143.   InfoPresent = true;
  144. #endif
  145.   NotifyViews(vnDocOpened,omode);
  146.   return fhdl;
  147. }
  148.  
  149. //
  150. // Private function used in 16-bit because it's not a good idea to call
  151. // filelength() on a file handle returned from _lopen().
  152. //
  153. #if !defined(BI_PLAT_WIN32)
  154. #define FILE_BEGIN   0
  155. #define FILE_CURRENT 1
  156. #define FILE_END     2
  157.  
  158. ulong
  159. TFileDocument::CalcFileLength(HFILE file)
  160. {
  161.   long pos = _llseek(file, 0, FILE_CURRENT);
  162.   long length = _llseek(file, 0, FILE_END);
  163.   _llseek(file, pos, FILE_BEGIN);
  164.   return length;
  165. }
  166. #endif
  167.  
  168. //
  169. //
  170. //
  171. void
  172. TFileDocument::CloseThisFile(HFILE fhdl, int omode)
  173. {
  174.   if (!IS_PREV_OPEN(omode)) {
  175.     ::_lclose(fhdl);
  176.     NotifyViews(vnDocClosed, omode);
  177.   }
  178. }
  179.  
  180. //
  181. //
  182. //
  183. bool
  184. TFileDocument::Open(int omode, const char far* path)
  185. {
  186.   if (FHdl != HFILE_ERROR)
  187.     return false;    // if already open at document level
  188.  
  189.   if (path)
  190.     SetDocPath(path);
  191.   if (omode != 0)
  192.     SetOpenMode(omode);
  193.  
  194.   long seekpos;
  195.   if ((FHdl = OpenThisFile(GetOpenMode(),GetDocPath(),&seekpos)) == HFILE_ERROR)
  196.     return false;
  197.   return true;
  198. }
  199.  
  200. //
  201. //
  202. //
  203. bool
  204. TFileDocument::Open(HFILE fhdl)
  205. {
  206.   SetOpenMode(PREV_OPEN | ofReadWrite);  
  207.   SetDocPath(0); 
  208.   FHdl = fhdl;
  209.   return true;
  210. }
  211.  
  212. //
  213. //
  214. //
  215. bool
  216. TFileDocument::Close()
  217. {
  218.   if (!TDocument::Close())     // close all children first
  219.     return false;
  220.   if (FHdl != HFILE_ERROR) {   // if open at document level
  221.     if (TDocument::IsOpen())   // cannot close document if streams open
  222.       return false;       // ?should we close streams here?
  223.     CloseThisFile(FHdl, GetOpenMode());
  224.     FHdl = HFILE_ERROR;
  225.   }
  226.   return true;
  227. }
  228.  
  229. //
  230. //
  231. //
  232. bool
  233. TFileDocument::Commit(bool force)
  234. {
  235.   if (!TDocument::Commit(force))      // flush views and child docs
  236.     return false;
  237.   SetDirty(false);
  238.   return true;
  239. }
  240.  
  241. //
  242. //
  243. //
  244. bool
  245. TFileDocument::Revert(bool clear)
  246. {
  247.   if (!TDocument::Revert(clear))
  248.     return false;
  249.   SetDirty(false);
  250.   return true;
  251. }
  252.  
  253. static char* PropNames[] = {
  254.   "Create Time",   // CreateTime
  255.   "Modify Time",   // ModifyTime
  256.   "Access Time",   // AccessTime
  257.   "Storage Size",  // StorageSize
  258.   "File Handle",   // FileHandle
  259. };
  260.  
  261. static int PropFlags[] = {
  262.   pfGetBinary|pfGetText,   // CreateTime
  263.   pfGetBinary|pfGetText,   // ModifyTime
  264.   pfGetBinary|pfGetText,   // AccessTime
  265.   pfGetBinary|pfGetText,   // StorageSize
  266.   pfGetBinary,             // FileHandle
  267. };
  268.  
  269. //
  270. //
  271. //
  272. const char*
  273. TFileDocument::PropertyName(int index)
  274. {
  275.   if (index <= PrevProperty)
  276.     return TDocument::PropertyName(index);
  277.   else if (index < NextProperty)
  278.     return PropNames[index-PrevProperty-1];
  279.   else
  280.     return 0;
  281. }
  282.  
  283. //
  284. //
  285. //
  286. int
  287. TFileDocument::PropertyFlags(int index)
  288. {
  289.   if (index <= PrevProperty)
  290.     return TDocument::PropertyFlags(index);
  291.   else if (index < NextProperty)
  292.     return PropFlags[index-PrevProperty-1];
  293.   else
  294.     return 0;
  295. }
  296.  
  297. //
  298. //
  299. //
  300. int
  301. TFileDocument::FindProperty(const char far* name)
  302. {
  303.   int i;
  304.   for (i=0; i < NextProperty-PrevProperty-1; i++)
  305.     if (strcmp(PropNames[i], name) == 0)
  306.       return i+PrevProperty+1;
  307.   return TDocument::FindProperty(name);
  308. }
  309.  
  310. //
  311. //
  312. //
  313. int
  314. TFileDocument::GetProperty(int prop, void far* dest, int textlen)
  315. {
  316.   switch(prop) {
  317.     case FileHandle:
  318.       if (textlen)
  319.         return 0;
  320.       *(HFILE FAR*)dest = FHdl;
  321.       return sizeof(FHdl);
  322.     default:
  323.       if (InfoPresent) {
  324.         switch(prop) {
  325.           case StorageSize:
  326.             if (!textlen) {
  327.               *(unsigned long FAR*)dest = FileLength;
  328.               return sizeof(FileLength);
  329.             }
  330.             else {
  331.               char buf[10];
  332.               int len = sprintf(buf, "%ld", FileLength);
  333.               if (textlen > len)
  334.                 textlen = len;
  335.               memcpy(dest, buf, textlen);
  336.               *((char far*)dest + textlen) = 0;
  337.               return len;
  338.             }
  339. #if defined(BI_PLAT_WIN32)
  340.           case CreateTime:
  341.             return FormatFileTime(&FileCreateTime, dest, textlen);
  342.           case ModifyTime:
  343.             return FormatFileTime(&FileUpdateTime, dest, textlen);
  344.           case AccessTime:
  345.             return FormatFileTime(&FileAccessTime, dest, textlen);
  346.  
  347. #else  // DOS file system
  348.           case CreateTime:
  349.           case ModifyTime:
  350.           case AccessTime: {
  351.             struct date  propdate;
  352.             struct time  proptime;
  353.             propdate.da_year = ((struct ftime*)&FileTime)->ft_year+1980;
  354.             propdate.da_mon  = ((struct ftime*)&FileTime)->ft_month;
  355.             propdate.da_day  = ((struct ftime*)&FileTime)->ft_day;
  356.             proptime.ti_hour = ((struct ftime*)&FileTime)->ft_hour;
  357.             proptime.ti_min  = ((struct ftime*)&FileTime)->ft_min;
  358.             proptime.ti_sec  = ((struct ftime*)&FileTime)->ft_tsec*2;
  359.             proptime.ti_hund = 0;
  360.             return FormatDateTime(propdate, proptime, dest, textlen);
  361.           }
  362. #endif
  363.         }
  364.       }
  365.       return TDocument::GetProperty(prop, dest, textlen);
  366.   }
  367. }
  368.  
  369. //
  370. //
  371. //
  372. bool
  373. TFileDocument::SetProperty(int prop, const void far* src)
  374. {
  375.   // File properties currently not settable
  376.   //
  377.   return TDocument::SetProperty(prop, src);
  378. }
  379.  
  380. //
  381. //
  382. //
  383. TInStream*
  384. TFileDocument::InStream(int omode, const char far* /*strmId*/)
  385. {
  386.   HFILE fhdl;
  387.   streampos seekpos;
  388.   if (omode == ofParent)
  389.     omode = GetOpenMode();
  390.   if (!(omode & ofRead))
  391.     return 0;
  392.   if ((fhdl = FHdl) == HFILE_ERROR) {   // if file not open at document level
  393.     if ((fhdl=OpenThisFile (omode, GetDocPath(), &seekpos)) == HFILE_ERROR)
  394.       return 0;
  395.   }
  396.   else {
  397.     omode = GetOpenMode() ? (GetOpenMode() & ~ofBinary) | (omode & ofBinary)
  398.                           : omode;
  399.     omode |= PREV_OPEN;
  400.   }
  401.   return new TFileInStream(*this, fhdl, omode, seekpos);
  402. }
  403.  
  404. //
  405. //
  406. //
  407. TOutStream*
  408. TFileDocument::OutStream(int omode, const char far* /*strmId*/)
  409. {
  410.   HFILE fhdl;
  411.   streampos seekpos;
  412.   if (omode == ofParent)
  413.     omode = GetOpenMode();
  414.   if (!(omode & ofWrite))
  415.     return 0;
  416.   if ((fhdl = FHdl) == HFILE_ERROR) {   // if file not open at document level
  417.     if ((fhdl=OpenThisFile (omode, GetDocPath(), &seekpos)) == HFILE_ERROR)
  418.       return 0;
  419.   }
  420.   else {
  421.     omode = GetOpenMode() ? (GetOpenMode() & ~ofBinary) | (omode & ofBinary)
  422.                           : omode;
  423.     omode |= PREV_OPEN;
  424.   }
  425.   return new TFileOutStream(*this, fhdl, omode, seekpos);
  426. }
  427.  
  428. //----------------------------------------------------------------------------
  429.  
  430. //
  431. //
  432. //
  433. TFileInStream::~TFileInStream()
  434. {
  435.   ((TFileDocument&)Doc).CloseThisFile(buf.xfd, GetOpenMode());
  436. }
  437.  
  438. //
  439. //
  440. //
  441. TFileOutStream::~TFileOutStream()
  442. {
  443.   if (buf.out_waiting())
  444.     buf.overflow(EOF);
  445.   ((TFileDocument&)Doc).CloseThisFile(buf.xfd, GetOpenMode());
  446. }
  447.  
  448. //----------------------------------------------------------------------------
  449. // class TFileBuf
  450. //
  451.  
  452. const int B_size = 516; // natural size for a file buffer, plus 4 for putback;
  453.  
  454. //
  455. // Make a TFileBuf attached to an open fd
  456. //
  457. TFileBuf::TFileBuf(int fhdl, int omode, long seekpos)
  458. {
  459.   xfd = fhdl;     // assumed to be valid
  460.   mode = omode;   // this may not represent the actual mode opened previously
  461.   last_seek = seekpos;
  462.   char* p = new char[B_size];
  463.   if (p) {
  464.     setb(p, p+B_size, 1);   // ~streambuf() will delete buffer
  465.     setp(p+4, p+4);
  466.     setg(p, p+4, p+4);
  467.   }
  468. }
  469.  
  470. //
  471. // Seek file to position.
  472. // We take a simple approach, and don't check for small position changes
  473. // within the current buffer.
  474. //
  475. streampos TFileBuf::seekoff(streamoff off, ios::seek_dir dir, int /*mode*/)
  476. {
  477.   long loff = off;
  478.   if (out_waiting()) {       // flush the output
  479.     if (sync() == EOF)
  480.         return EOF;
  481.   }
  482.   else if (dir == ios::cur) {
  483.     int count = in_avail();
  484.     if (count != 0) {
  485.       loff -= count;
  486.  
  487.       //  if we're in text mode, need to allow for newlines
  488.       //  in the buffer
  489.       if ((mode & ofBinary) == 0) {
  490.         char *tptr = gptr();
  491.         while (tptr != egptr())
  492.           if (*tptr++ == '\n')
  493.             loff--;
  494.       }
  495.     }
  496.   }
  497.   int w = (dir==ios::beg) ? SEEK_SET : ((dir==ios::cur) ? SEEK_CUR:SEEK_END);
  498.   last_seek = ::_llseek(xfd, loff, w);
  499.   if (!unbuffered() && base()) {      // set up get and put areas
  500.     int pb = (blen() > 8) ? 4 : 1;  // putback area size
  501.     char *b = base();
  502.     setp(b+pb, b+pb);
  503.     setg(b, b+pb, b+pb);
  504.   }
  505.   return (last_seek == long(HFILE_ERROR)) ? EOF : last_seek;
  506. }
  507.  
  508. //
  509. //
  510. //
  511. int TFileBuf::sync()
  512. {
  513.   uint count = out_waiting();
  514.   if (count) {
  515.     char* curp;
  516.     char* srcp = pbase();
  517.     char* endp = srcp + count;
  518.  
  519.     // Convert LF's to CR/LF if text mode
  520.     //
  521.     if ((mode & ofBinary) == 0) {
  522.       for (curp = srcp; curp < endp; curp++) {
  523.         if (*curp == '\n') {
  524.           *curp = '\r';
  525.           count = (int)(curp - srcp) + 1;
  526.           if (::_lwrite(xfd, srcp, count) != count)
  527.             return EOF;
  528.           *(srcp = curp) = '\n';
  529.         }
  530.       }
  531.       count = (uint)(curp - srcp);  // write what remains in the buffer below
  532.     }
  533.     if (::_lwrite(xfd, srcp, count) != count)
  534.       return EOF;
  535.  
  536.     // reset get and put areas
  537.     int pb = (blen() > 8) ? 4 : 1;  // putback area size
  538.     char *b = base();
  539.     setp(b+pb, b+blen());
  540.     setg(b, b+pb, b+pb);
  541.   }
  542.   else if (in_avail()) {
  543.     last_seek = ::_llseek(xfd, long(-in_avail()), SEEK_CUR);
  544.     setg(eback(), gptr(), gptr());
  545.     setp(gptr(), gptr());
  546.     if (last_seek == long(HFILE_ERROR))
  547.       return EOF;
  548.   }
  549.   return 0;
  550. }
  551.  
  552. //
  553. //
  554. //
  555. int TFileBuf::underflow()
  556. {
  557.   if ((mode & (ofRead | ofWrite)) == ofWrite)
  558.     return EOF;
  559.  
  560.   if (in_avail())    // no action needed
  561.     return (uchar) *gptr();
  562.  
  563.   int c = 0;  // the return value
  564.   int count;  // input character count
  565.  
  566.   if (!unbuffered() && base()) {     // this is buffered
  567.     if (sync() != 0)
  568.       return EOF;
  569.  
  570.     // find buffer data
  571.     int pb = (blen() > 8) ? 4 : 1;  // putback area size
  572.     char* begp = base() + pb;
  573.  
  574.     // read in a new buffer
  575.     count = ::_lread(xfd, begp, blen()-pb);
  576.     if (count == HFILE_ERROR)
  577.       return EOF;
  578.  
  579.     // remove CR's if text mode
  580.     if ((mode & ofBinary) == 0) {
  581.       char* endp = begp + count;
  582.       char* dstp = 0;
  583.       char* srcp = 0; // initialized only to prevent compiler warning
  584.       char* curp;
  585.  
  586.       for (curp = begp;  curp < endp; curp++) {
  587.         if (*curp == '\r') {
  588.           if (dstp) {
  589.             memcpy(dstp, srcp, (int)(curp - srcp));
  590.             dstp += (int)(curp - srcp);
  591.           }
  592.           else
  593.             dstp = curp;
  594.           srcp = curp + 1;
  595.         }
  596.       }
  597.       if (dstp) {
  598.         endp = dstp + (int)(curp - srcp);
  599.         if (curp != srcp)
  600.           memcpy(dstp, srcp, (int)(curp - srcp));
  601.       }
  602.       count = (int)(endp - begp);
  603.     }
  604.     // set up get and put areas
  605.     setg(base(), begp, begp + count);
  606.     setp(begp, begp);
  607.  
  608.     if (count)
  609.       c = (uchar) *gptr();
  610.   }
  611.   else {     // this is not buffered
  612.     for (;;) {
  613.       count = ::_lread(xfd, lahead, 1);
  614.       if (count == HFILE_ERROR) {
  615.         c = EOF;
  616.         setg(0, 0, 0);
  617.       }
  618.       else {
  619.         c = (uchar)lahead[0];
  620.         if ((mode & ofBinary) == 0  && c == '\r')
  621.           continue;
  622.         setg(lahead, lahead, lahead+1);
  623.       }
  624.       break;
  625.     }
  626.   }
  627.   if (!count)
  628.     c = EOF;    // end of file
  629.   return c;
  630. }
  631.  
  632. //
  633. // Always flush
  634. //
  635. int TFileBuf::overflow(int c)
  636. {
  637.   if ((mode & (ofRead | ofWrite)) == ofRead)
  638.     return EOF;
  639.  
  640.   if (unbuffered() || !base()) {
  641.     if (c != EOF) {
  642.       uint count;
  643.       char b[2];
  644.       if (c == '\n' && (mode & ofBinary) == 0) {
  645.         b[0] = '\r';
  646.         b[1] = (char)c;
  647.         count = 2;
  648.       }
  649.       else {
  650.         b[0] = (char)c;
  651.         count = 1;
  652.       }
  653.       if (::_lwrite(xfd, b, count) != count)
  654.         return EOF;
  655.     }
  656.   }
  657.   else {   // now we know this is buffered and state is not bad
  658.  
  659.     // resets get and put areas
  660.     if (sync() != 0)
  661.       return EOF;
  662.  
  663.     // reset get and put areas
  664.     int pb = (blen() > 8) ? 4 : 1;  // putback area size
  665.     char *b = base();
  666.     setp(b+pb, b+blen());
  667.     setg(b, b+pb, b+pb);
  668.  
  669.     if (c != EOF) {
  670.       sputc(c);
  671.       gbump(1);       // pptr and gptr must be the same
  672.     }
  673.   }
  674.   return 1;
  675. }
  676.  
  677. //----------------------------------------------------------------------------
  678. // class TFileStreamBase
  679. //
  680.  
  681. //
  682. //
  683. //
  684. TFileStreamBase::TFileStreamBase(int fhdl, int omode, streampos seekpos)
  685. :
  686.   buf(fhdl, omode, seekpos)
  687. {
  688.   ios::init(&buf);
  689. }
  690.  
  691. #endif
  692. //----------------------------------------------------------------------------
  693. #if !defined(SECTION) || SECTION == 2
  694.  
  695. IMPLEMENT_STREAMABLE1(TFileDocument, TDocument);
  696.  
  697. #if !defined(BI_NO_OBJ_STREAMING)
  698.  
  699. //
  700. //
  701. //
  702. void*
  703. TFileDocument::Streamer::Read(ipstream& is, uint32 /*version*/) const
  704. {
  705.   TFileDocument* o = GetObject();
  706.   o->FHdl = HFILE_ERROR;    // initialize to closed file
  707.   o->InfoPresent = false;
  708.   ReadBaseObject((TDocument*)o, is);
  709.   return o;
  710. }
  711.  
  712. //
  713. //
  714. //
  715. void
  716. TFileDocument::Streamer::Write(opstream& os) const
  717. {
  718.   //  assumed that document is committed at this point
  719.   WriteBaseObject((TDocument*)GetObject(), os);
  720. }
  721.  
  722. #endif  // if !defined(BI_NO_OBJ_STREAMING)
  723.  
  724. #endif
  725.