//---------------------------------------------------------------------------- // ObjectWindows // (C) Copyright 1993, 1994 by Borland International, All Rights Reserved // // Implements classes TFileDocument, TFileInStream, TFileOutStream, TFileBuf //---------------------------------------------------------------------------- #pragma hdrignore SECTION #include #include #if !defined(SECTION) || SECTION == 1 // // class TFileBuf // ----- -------- // class _OWLCLASS_RTL TFileBuf : public streambuf { public: enum { shDefault = shReadWrite }; // default file sharing TFileBuf(int fhdl, int omode, streampos seekpos); ~TFileBuf() {} virtual int overflow(int = EOF); virtual int underflow(); virtual int sync(); virtual streampos seekoff(streamoff, ios::seek_dir, int); int xfd; // the file descriptor, EOF if closed int mode; // the opened mode streampos last_seek; char lahead[2]; // current input char if unbuffered }; // // class TFileStreamBase // ----- --------------- // class _OWLCLASS_RTL TFileStreamBase : virtual public ios { public: TFileStreamBase(int fhdl, int omode, streampos seekpos); ~TFileStreamBase() {} TFileBuf buf; }; // // class TFileInStream // ----- ------------- // class _OWLCLASS_RTL TFileInStream : public TFileStreamBase, public TInStream { public: TFileInStream(TFileDocument& doc, HFILE fhdl, int omode, streampos seekpos) : TInStream (doc,0,omode), TFileStreamBase(fhdl,omode,seekpos){} ~TFileInStream(); }; // // class TFileOutStream // ----- -------------- // class _OWLCLASS_RTL TFileOutStream : public TFileStreamBase, public TOutStream { public: TFileOutStream(TFileDocument& doc, HFILE fhdl, int omode, streampos seekpos) : TOutStream (doc,0,omode), TFileStreamBase(fhdl,omode,seekpos){} ~TFileOutStream(); }; // // class TFileDocument // ----- ------------- // HFILE TFileDocument::OpenThisFile(int omode, const char far* name, streampos* pseekpos){ int how; HFILE fhdl; bool exists = false; int share = omode & shMask; if (share < shCompat) share = (omode & ofWrite) ? shRead : shReadWrite; how = ((unsigned)(share-shCompat)) >> 5; if (omode & ofWrite) { if (!(omode & (ofAtEnd | ofAppend | ofRead))) omode |= ofTruncate; // output implies truncate unless in, app, or ate if (omode & ofRead) how |= OF_READWRITE; else how |= OF_WRITE; if (!((omode & ofNoCreate) && !(omode & ofTruncate))) { if (!((omode & ofTruncate) && !(omode & (ofNoCreate | ofNoReplace)))) { if ((fhdl=::_lopen(name,OF_READ|OF_SHARE_COMPAT)) !=HFILE_ERROR || (fhdl=::_lopen(name,OF_READ|OF_SHARE_DENY_NONE))!=HFILE_ERROR) { ::_lclose(fhdl); exists = true; } } if (!(exists && !(omode & (ofNoCreate | ofNoReplace)))) { if ((exists && (omode & ofNoReplace)) || (!exists && (omode & ofNoCreate)) ) return 0; if ((fhdl = _lcreat(name, 0)) == HFILE_ERROR) return HFILE_ERROR; ::_lclose(fhdl); // close in order to open with share mode } } } else if (omode & ofRead) how |= OF_READ; else return HFILE_ERROR; // must specfify in, out, or in/out if ((fhdl = ::_lopen(name, how)) != HFILE_ERROR) { if ((*pseekpos = ::_llseek(fhdl, 0L, (omode & (ofAtEnd|ofAppend)) ? SEEK_END : SEEK_SET)) == long(HFILE_ERROR)) { ::_lclose(fhdl); return HFILE_ERROR; } } #if defined(BI_PLAT_WIN32) FileLength = GetFileSize((HANDLE)fhdl, 0); InfoPresent = GetFileTime((HANDLE)fhdl, &FileCreateTime, &FileAccessTime, &FileUpdateTime); #else FileLength = filelength(fhdl); getftime(fhdl, (struct ftime*)&FileTime); InfoPresent = true; #endif NotifyViews(vnDocOpened,omode); return fhdl; } void TFileDocument::CloseThisFile(HFILE fhdl, int omode) { if (!IS_PREV_OPEN(omode)) { ::_lclose(fhdl); NotifyViews(vnDocClosed, omode); } } bool TFileDocument::Open(int omode, const char far* path) { long seekpos; if (FHdl != HFILE_ERROR) return false; // if already open at document level if (path) SetDocPath(path); if (omode != 0) SetOpenMode(omode); if ((FHdl = OpenThisFile(GetOpenMode(),GetDocPath(),&seekpos)) == HFILE_ERROR) return false; return true; } bool TFileDocument::Open(HFILE fhdl) { SetOpenMode(PREV_OPEN | ofReadWrite); // can we determine open mode? SetDocPath(0); // can we get path name? FHdl = fhdl; return true; } bool TFileDocument::Close() { if (!TDocument::Close()) // close all children first return false; if (FHdl != HFILE_ERROR) { // if open at document level if (TDocument::IsOpen()) // cannot close document if streams open return false; // ?should we close streams here? CloseThisFile(FHdl, GetOpenMode()); FHdl = HFILE_ERROR; } return true; } bool TFileDocument::Commit(bool force) { if (!TDocument::Commit(force)) // flush views and child docs return false; SetDirty(false); return true; } bool TFileDocument::Revert(bool clear) { if (!TDocument::Revert(clear)) return false; SetDirty(false); return true; } static char* PropNames[] = { "Create Time", // CreateTime "Modify Time", // ModifyTime "Access Time", // AccessTime "Storage Size", // StorageSize "File Handle", // FileHandle }; static int PropFlags[] = { pfGetBinary|pfGetText, // CreateTime pfGetBinary|pfGetText, // ModifyTime pfGetBinary|pfGetText, // AccessTime pfGetBinary|pfGetText, // StorageSize pfGetBinary, // FileHandle }; const char* TFileDocument::PropertyName(int index) { if (index <= PrevProperty) return TDocument::PropertyName(index); else if (index < NextProperty) return PropNames[index-PrevProperty-1]; else return 0; } int TFileDocument::PropertyFlags(int index) { if (index <= PrevProperty) return TDocument::PropertyFlags(index); else if (index < NextProperty) return PropFlags[index-PrevProperty-1]; else return 0; } int TFileDocument::FindProperty(const char far* name) { int i; for (i=0; i < NextProperty-PrevProperty-1; i++) if (strcmp(PropNames[i], name) == 0) return i+PrevProperty+1; return TDocument::FindProperty(name); } int TFileDocument::GetProperty(int prop, void far* dest, int textlen) { switch(prop) { case FileHandle: if (textlen) return 0; *(HFILE FAR*)dest = FHdl; return sizeof(FHdl); default: if (InfoPresent) { switch(prop) { case StorageSize: if (!textlen) { *(unsigned long FAR*)dest = FileLength; return sizeof(FileLength); } else { char buf[10]; int len = wsprintf(buf, "%ld", FileLength); if (textlen > len) textlen = len; memcpy(dest, buf, textlen); *((char far*)dest + textlen) = 0; return len; } #if defined(BI_PLAT_WIN32) case CreateTime: return FormatFileTime(&FileCreateTime, dest, textlen); case ModifyTime: return FormatFileTime(&FileUpdateTime, dest, textlen); case AccessTime: return FormatFileTime(&FileAccessTime, dest, textlen); #else // DOS file system case CreateTime: case ModifyTime: case AccessTime: { struct date propdate; struct time proptime; propdate.da_year = ((struct ftime*)&FileTime)->ft_year+1980; propdate.da_mon = ((struct ftime*)&FileTime)->ft_month; propdate.da_day = ((struct ftime*)&FileTime)->ft_day; proptime.ti_hour = ((struct ftime*)&FileTime)->ft_hour; proptime.ti_min = ((struct ftime*)&FileTime)->ft_min; proptime.ti_sec = ((struct ftime*)&FileTime)->ft_tsec*2; proptime.ti_hund = 0; return FormatDateTime(propdate, proptime, dest, textlen); } #endif } } return TDocument::GetProperty(prop, dest, textlen); } } bool TFileDocument::SetProperty(int prop, const void far* src) { // File properties currently not settable // return TDocument::SetProperty(prop, src); } TInStream* TFileDocument::InStream(int omode, const char far* /*strmId*/) { HFILE fhdl; streampos seekpos; if (omode == ofParent) omode = GetOpenMode(); if (!(omode & ofRead)) return 0; if ((fhdl = FHdl) == HFILE_ERROR) { // if file not open at document level if ((fhdl=OpenThisFile (omode, GetDocPath(), &seekpos)) == HFILE_ERROR) return 0; } else { omode = GetOpenMode() ? (GetOpenMode() & ~ofBinary) | (omode & ofBinary) : omode; omode |= PREV_OPEN; } return new TFileInStream(*this, fhdl, omode, seekpos); } TOutStream* TFileDocument::OutStream(int omode, const char far* /*strmId*/) { HFILE fhdl; streampos seekpos; if (omode == ofParent) omode = GetOpenMode(); if (!(omode & ofWrite)) return 0; if ((fhdl = FHdl) == HFILE_ERROR) { // if file not open at document level if ((fhdl=OpenThisFile (omode, GetDocPath(), &seekpos)) == HFILE_ERROR) return 0; } else { omode = GetOpenMode() ? (GetOpenMode() & ~ofBinary) | (omode & ofBinary) : omode; omode |= PREV_OPEN; } return new TFileOutStream(*this, fhdl, omode, seekpos); } TFileInStream::~TFileInStream() { ((TFileDocument&)Doc).CloseThisFile(buf.xfd, GetOpenMode()); } TFileOutStream::~TFileOutStream() { if (buf.out_waiting()) buf.overflow(EOF); ((TFileDocument&)Doc).CloseThisFile(buf.xfd, GetOpenMode()); } // // class TFileBuf // ----- -------- // const int B_size = 516; // natural size for a file buffer, plus 4 for putback // make a TFileBuf attached to an open fd TFileBuf::TFileBuf(int fhdl, int omode, long seekpos) { xfd = fhdl; // assumed to be valid mode = omode; // this may not represent the actual mode opened previously last_seek = seekpos; char* p = new char[B_size]; if (p) { setb(p, p+B_size, 1); // ~streambuf() will delete buffer setp(p+4, p+4); setg(p, p+4, p+4); } } // Seek file to position. // We take a simple approach, and don't check for small position changes // within the current buffer. streampos TFileBuf::seekoff(streamoff off, ios::seek_dir dir, int /*mode*/) { long loff = off; if (out_waiting()) { // flush the output if (sync() == EOF) return EOF; } else if (dir == ios::cur) { int count = in_avail(); if (count != 0) { loff -= count; // if we're in text mode, need to allow for newlines // in the buffer if ((mode & ofBinary) == 0) { char *tptr = gptr(); while (tptr != egptr()) if (*tptr++ == '\n') loff--; } } } int w = (dir==ios::beg) ? SEEK_SET : ((dir==ios::cur) ? SEEK_CUR:SEEK_END); last_seek = ::_llseek(xfd, loff, w); if (!unbuffered() && base()) { // set up get and put areas int pb = (blen() > 8) ? 4 : 1; // putback area size char *b = base(); setp(b+pb, b+pb); setg(b, b+pb, b+pb); } return (last_seek == long(HFILE_ERROR)) ? EOF : last_seek; } int TFileBuf::sync() { int count = out_waiting(); if (count) { char* curp; char* srcp = pbase(); char* endp = srcp + count; // Convert LF's to CR/LF if text mode // if ((mode & ofBinary) == 0) { for (curp = srcp; curp < endp; curp++) { if (*curp == '\n') { *curp = '\r'; count = (int)(curp - srcp) + 1; if (::_lwrite(xfd, srcp, count) != count) return EOF; *(srcp = curp) = '\n'; } } count = (int)(curp - srcp); // write what remains in the buffer below } if (::_lwrite(xfd, srcp, count) != count) return EOF; // reset get and put areas int pb = (blen() > 8) ? 4 : 1; // putback area size char *b = base(); setp(b+pb, b+blen()); setg(b, b+pb, b+pb); } else if (in_avail()) { last_seek = ::_llseek(xfd, long(-in_avail()), SEEK_CUR); setg(eback(), gptr(), gptr()); setp(gptr(), gptr()); if (last_seek == long(HFILE_ERROR)) return EOF; } return 0; } int TFileBuf::underflow() { if ((mode & (ofRead | ofWrite)) == ofWrite) return EOF; if (in_avail()) // no action needed return (unsigned char) *gptr(); int c = 0; // the return value int count; // input character count if (!unbuffered() && base()) { // this is buffered if (sync() != 0) return EOF; // find buffer data int pb = (blen() > 8) ? 4 : 1; // putback area size char* begp = base() + pb; // read in a new buffer count = ::_lread(xfd, begp, blen()-pb); if (count == HFILE_ERROR) return EOF; // remove CR's if text mode if ((mode & ofBinary) == 0) { char* endp = begp + count; char* dstp = 0; char* srcp = 0; // initialized only to prevent compiler warning char* curp; for (curp = begp; curp < endp; curp++) { if (*curp == '\r') { if (dstp) { memcpy(dstp, srcp, (int)(curp - srcp)); dstp += (int)(curp - srcp); } else dstp = curp; srcp = curp + 1; } } if (dstp) { endp = dstp + (int)(curp - srcp); if (curp != srcp) memcpy(dstp, srcp, (int)(curp - srcp)); } count = (int)(endp - begp); } // set up get and put areas setg(base(), begp, begp + count); setp(begp, begp); if (count) c = (unsigned char) *gptr(); } else { // this is not buffered for (;;) { count = ::_lread(xfd, lahead, 1); if (count == HFILE_ERROR) { c = EOF; setg(0, 0, 0); } else { c = (unsigned char)lahead[0]; if ((mode & ofBinary) == 0 && c == '\r') continue; setg(lahead, lahead, lahead+1); } break; } } if (!count) c = EOF; // end of file return c; } // always flush int TFileBuf::overflow(int c) { if ((mode & (ofRead | ofWrite)) == ofRead) return EOF; if (unbuffered() || !base()) { if (c != EOF) { int count; char b[2]; if (c == '\n' && (mode & ofBinary) == 0) { b[0] = '\r'; b[1] = (char)c; count = 2; } else { b[0] = (char)c; count = 1; } if (::_lwrite(xfd, b, count) != count) return EOF; } } else { // now we know this is buffered and state is not bad // resets get and put areas if (sync() != 0) return EOF; // reset get and put areas int pb = (blen() > 8) ? 4 : 1; // putback area size char *b = base(); setp(b+pb, b+blen()); setg(b, b+pb, b+pb); if (c != EOF) { sputc(c); gbump(1); // pptr and gptr must be the same } } return 1; } // // class TFileStreamBase // ----- --------------- // TFileStreamBase::TFileStreamBase(int fhdl, int omode, streampos seekpos) : buf(fhdl, omode, seekpos) { ios::init(&buf); } #endif #if !defined(SECTION) || SECTION == 2 IMPLEMENT_STREAMABLE1(TFileDocument, TDocument); void* TFileDocument::Streamer::Read(ipstream& is, uint32 /*version*/) const { TFileDocument* o = GetObject(); o->FHdl = HFILE_ERROR; // initialize to closed file o->InfoPresent = false; ReadBaseObject((TDocument*)o, is); return o; } void TFileDocument::Streamer::Write(opstream& os) const { // assumed that document is committed at this point WriteBaseObject((TDocument*)GetObject(), os); } #endif