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

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