summaryrefslogtreecommitdiffstats
path: root/db/mork/src/morkStream.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'db/mork/src/morkStream.cpp')
-rw-r--r--db/mork/src/morkStream.cpp859
1 files changed, 859 insertions, 0 deletions
diff --git a/db/mork/src/morkStream.cpp b/db/mork/src/morkStream.cpp
new file mode 100644
index 000000000..26c6f443e
--- /dev/null
+++ b/db/mork/src/morkStream.cpp
@@ -0,0 +1,859 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _MDB_
+#include "mdb.h"
+#endif
+
+#ifndef _MORK_
+#include "mork.h"
+#endif
+
+#ifndef _MORKNODE_
+#include "morkNode.h"
+#endif
+
+#ifndef _MORKFILE_
+#include "morkFile.h"
+#endif
+
+#ifndef _MORKENV_
+#include "morkEnv.h"
+#endif
+
+#ifndef _MORKSTREAM_
+#include "morkStream.h"
+#endif
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
+
+// ````` ````` ````` ````` `````
+// { ===== begin morkNode interface =====
+
+/*public virtual*/ void
+morkStream::CloseMorkNode(morkEnv* ev) // CloseStream() only if open
+{
+ if ( this->IsOpenNode() )
+ {
+ this->MarkClosing();
+ this->CloseStream(ev);
+ this->MarkShut();
+ }
+}
+
+/*public virtual*/
+morkStream::~morkStream() // assert CloseStream() executed earlier
+{
+ MORK_ASSERT(mStream_ContentFile==0);
+ MORK_ASSERT(mStream_Buf==0);
+}
+
+/*public non-poly*/
+morkStream::morkStream(morkEnv* ev, const morkUsage& inUsage,
+ nsIMdbHeap* ioHeap,
+ nsIMdbFile* ioContentFile, mork_size inBufSize, mork_bool inFrozen)
+: morkFile(ev, inUsage, ioHeap, ioHeap)
+, mStream_At( 0 )
+, mStream_ReadEnd( 0 )
+, mStream_WriteEnd( 0 )
+
+, mStream_ContentFile( 0 )
+
+, mStream_Buf( 0 )
+, mStream_BufSize( inBufSize )
+, mStream_BufPos( 0 )
+, mStream_Dirty( morkBool_kFalse )
+, mStream_HitEof( morkBool_kFalse )
+{
+ if ( ev->Good() )
+ {
+ if ( inBufSize < morkStream_kMinBufSize )
+ mStream_BufSize = inBufSize = morkStream_kMinBufSize;
+ else if ( inBufSize > morkStream_kMaxBufSize )
+ mStream_BufSize = inBufSize = morkStream_kMaxBufSize;
+
+ if ( ioContentFile && ioHeap )
+ {
+ // if ( ioContentFile->FileFrozen() ) // forced to be readonly?
+ // inFrozen = morkBool_kTrue; // override the input value
+
+ nsIMdbFile_SlotStrongFile(ioContentFile, ev, &mStream_ContentFile);
+ if ( ev->Good() )
+ {
+ mork_u1* buf = 0;
+ ioHeap->Alloc(ev->AsMdbEnv(), inBufSize, (void**) &buf);
+ if ( buf )
+ {
+ mStream_At = mStream_Buf = buf;
+
+ if ( !inFrozen )
+ {
+ // physical buffer end never moves:
+ mStream_WriteEnd = buf + inBufSize;
+ }
+ else
+ mStream_WriteEnd = 0; // no writing is allowed
+
+ if ( inFrozen )
+ {
+ // logical buffer end starts at Buf with no content:
+ mStream_ReadEnd = buf;
+ this->SetFileFrozen(inFrozen);
+ }
+ else
+ mStream_ReadEnd = 0; // no reading is allowed
+
+ this->SetFileActive(morkBool_kTrue);
+ this->SetFileIoOpen(morkBool_kTrue);
+ }
+ if ( ev->Good() )
+ mNode_Derived = morkDerived_kStream;
+ }
+ }
+ else ev->NilPointerError();
+ }
+}
+
+/*public non-poly*/ void
+morkStream::CloseStream(morkEnv* ev) // called by CloseMorkNode();
+{
+ if ( this->IsNode() )
+ {
+ nsIMdbFile_SlotStrongFile((nsIMdbFile*) 0, ev, &mStream_ContentFile);
+ nsIMdbHeap* heap = mFile_SlotHeap;
+ mork_u1* buf = mStream_Buf;
+ mStream_Buf = 0;
+
+ if ( heap && buf )
+ heap->Free(ev->AsMdbEnv(), buf);
+
+ this->CloseFile(ev);
+ this->MarkShut();
+ }
+ else
+ this->NonNodeError(ev);
+}
+
+// } ===== end morkNode methods =====
+// ````` ````` ````` ````` `````
+
+#define morkStream_kSpacesPerIndent 1 /* one space per indent */
+#define morkStream_kMaxIndentDepth 70 /* max indent of 70 space bytes */
+static const char morkStream_kSpaces[] // next line to ease length perception
+= " ";
+// 123456789_123456789_123456789_123456789_123456789_123456789_123456789_
+// morkStream_kSpaces above must contain (at least) 70 spaces (ASCII 0x20)
+
+mork_size
+morkStream::PutIndent(morkEnv* ev, mork_count inDepth)
+ // PutIndent() puts a linebreak, and then
+ // "indents" by inDepth, and returns the line length after indentation.
+{
+ mork_size outLength = 0;
+ nsIMdbEnv *mev = ev->AsMdbEnv();
+ if ( ev->Good() )
+ {
+ this->PutLineBreak(ev);
+ if ( ev->Good() )
+ {
+ outLength = inDepth;
+ mdb_size bytesWritten;
+ if ( inDepth )
+ this->Write(mev, morkStream_kSpaces, inDepth, &bytesWritten);
+ }
+ }
+ return outLength;
+}
+
+mork_size
+morkStream::PutByteThenIndent(morkEnv* ev, int inByte, mork_count inDepth)
+ // PutByteThenIndent() puts the byte, then a linebreak, and then
+ // "indents" by inDepth, and returns the line length after indentation.
+{
+ mork_size outLength = 0;
+ nsIMdbEnv *mev = ev->AsMdbEnv();
+
+ if ( inDepth > morkStream_kMaxIndentDepth )
+ inDepth = morkStream_kMaxIndentDepth;
+
+ this->Putc(ev, inByte);
+ if ( ev->Good() )
+ {
+ this->PutLineBreak(ev);
+ if ( ev->Good() )
+ {
+ outLength = inDepth;
+ mdb_size bytesWritten;
+ if ( inDepth )
+ this->Write(mev, morkStream_kSpaces, inDepth, &bytesWritten);
+ }
+ }
+ return outLength;
+}
+
+mork_size
+morkStream::PutStringThenIndent(morkEnv* ev,
+ const char* inString, mork_count inDepth)
+// PutStringThenIndent() puts the string, then a linebreak, and then
+// "indents" by inDepth, and returns the line length after indentation.
+{
+ mork_size outLength = 0;
+ mdb_size bytesWritten;
+ nsIMdbEnv *mev = ev->AsMdbEnv();
+
+ if ( inDepth > morkStream_kMaxIndentDepth )
+ inDepth = morkStream_kMaxIndentDepth;
+
+ if ( inString )
+ {
+ mork_size length = MORK_STRLEN(inString);
+ if ( length && ev->Good() ) // any bytes to write?
+ this->Write(mev, inString, length, &bytesWritten);
+ }
+
+ if ( ev->Good() )
+ {
+ this->PutLineBreak(ev);
+ if ( ev->Good() )
+ {
+ outLength = inDepth;
+ if ( inDepth )
+ this->Write(mev, morkStream_kSpaces, inDepth, &bytesWritten);
+ }
+ }
+ return outLength;
+}
+
+mork_size
+morkStream::PutString(morkEnv* ev, const char* inString)
+{
+ nsIMdbEnv *mev = ev->AsMdbEnv();
+ mork_size outSize = 0;
+ mdb_size bytesWritten;
+ if ( inString )
+ {
+ outSize = MORK_STRLEN(inString);
+ if ( outSize && ev->Good() ) // any bytes to write?
+ {
+ this->Write(mev, inString, outSize, &bytesWritten);
+ }
+ }
+ return outSize;
+}
+
+mork_size
+morkStream::PutStringThenNewline(morkEnv* ev, const char* inString)
+ // PutStringThenNewline() returns total number of bytes written.
+{
+ nsIMdbEnv *mev = ev->AsMdbEnv();
+ mork_size outSize = 0;
+ mdb_size bytesWritten;
+ if ( inString )
+ {
+ outSize = MORK_STRLEN(inString);
+ if ( outSize && ev->Good() ) // any bytes to write?
+ {
+ this->Write(mev, inString, outSize, &bytesWritten);
+ if ( ev->Good() )
+ outSize += this->PutLineBreak(ev);
+ }
+ }
+ return outSize;
+}
+
+mork_size
+morkStream::PutByteThenNewline(morkEnv* ev, int inByte)
+ // PutByteThenNewline() returns total number of bytes written.
+{
+ mork_size outSize = 1; // one for the following byte
+ this->Putc(ev, inByte);
+ if ( ev->Good() )
+ outSize += this->PutLineBreak(ev);
+ return outSize;
+}
+
+mork_size
+morkStream::PutLineBreak(morkEnv* ev)
+{
+#if defined(MORK_MAC)
+
+ this->Putc(ev, mork_kCR);
+ return 1;
+
+#else
+# if defined(MORK_WIN)
+
+ this->Putc(ev, mork_kCR);
+ this->Putc(ev, mork_kLF);
+ return 2;
+
+# else
+# ifdef MORK_UNIX
+
+ this->Putc(ev, mork_kLF);
+ return 1;
+
+# endif /* MORK_UNIX */
+# endif /* MORK_WIN */
+#endif /* MORK_MAC */
+}
+// ````` ````` ````` ````` ````` ````` ````` `````
+// public: // virtual morkFile methods
+
+
+NS_IMETHODIMP
+morkStream::Steal(nsIMdbEnv* mev, nsIMdbFile* ioThief)
+ // Steal: tell this file to close any associated i/o stream in the file
+ // system, because the file ioThief intends to reopen the file in order
+ // to provide the MDB implementation with more exotic file access than is
+ // offered by the nsIMdbFile alone. Presumably the thief knows enough
+ // from Path() in order to know which file to reopen. If Steal() is
+ // successful, this file should probably delegate all future calls to
+ // the nsIMdbFile interface down to the thief files, so that even after
+ // the file has been stolen, it can still be read, written, or forcibly
+ // closed (by a call to CloseMdbObject()).
+{
+ MORK_USED_1(ioThief);
+ morkEnv *ev = morkEnv::FromMdbEnv(mev);
+ ev->StubMethodOnlyError();
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+morkStream::BecomeTrunk(nsIMdbEnv* mev)
+ // If this file is a file version branch created by calling AcquireBud(),
+ // BecomeTrunk() causes this file's content to replace the original
+ // file's content, typically by assuming the original file's identity.
+{
+ morkEnv *ev = morkEnv::FromMdbEnv(mev);
+ ev->StubMethodOnlyError();
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+morkStream::AcquireBud(nsIMdbEnv* mev, nsIMdbHeap* ioHeap, nsIMdbFile **acqBud)
+ // AcquireBud() starts a new "branch" version of the file, empty of content,
+ // so that a new version of the file can be written. This new file
+ // can later be told to BecomeTrunk() the original file, so the branch
+ // created by budding the file will replace the original file. Some
+ // file subclasses might initially take the unsafe but expedient
+ // approach of simply truncating this file down to zero length, and
+ // then returning the same morkFile pointer as this, with an extra
+ // reference count increment. Note that the caller of AcquireBud() is
+ // expected to eventually call CutStrongRef() on the returned file
+ // in order to release the strong reference. High quality versions
+ // of morkFile subclasses will create entirely new files which later
+ // are renamed to become the old file, so that better transactional
+ // behavior is exhibited by the file, so crashes protect old files.
+ // Note that AcquireBud() is an illegal operation on readonly files.
+{
+ MORK_USED_1(ioHeap);
+ morkFile* outFile = 0;
+ nsIMdbFile* file = mStream_ContentFile;
+ morkEnv *ev = morkEnv::FromMdbEnv(mev);
+ if ( this->IsOpenAndActiveFile() && file )
+ {
+ // figure out how this interacts with buffering and mStream_WriteEnd:
+ ev->StubMethodOnlyError();
+ }
+ else this->NewFileDownError(ev);
+
+ *acqBud = outFile;
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+mork_pos
+morkStream::Length(morkEnv* ev) const // eof
+{
+ mork_pos outPos = 0;
+
+ nsIMdbFile* file = mStream_ContentFile;
+ if ( this->IsOpenAndActiveFile() && file )
+ {
+ mork_pos contentEof = 0;
+ file->Eof(ev->AsMdbEnv(), &contentEof);
+ if ( ev->Good() )
+ {
+ if ( mStream_WriteEnd ) // this stream supports writing?
+ {
+ // the local buffer might have buffered content past content eof
+ if ( ev->Good() ) // no error happened during Length() above?
+ {
+ mork_u1* at = mStream_At;
+ mork_u1* buf = mStream_Buf;
+ if ( at >= buf ) // expected cursor order?
+ {
+ mork_pos localContent = mStream_BufPos + (at - buf);
+ if ( localContent > contentEof ) // buffered past eof?
+ contentEof = localContent; // return new logical eof
+
+ outPos = contentEof;
+ }
+ else this->NewBadCursorOrderError(ev);
+ }
+ }
+ else
+ outPos = contentEof; // frozen files get length from content file
+ }
+ }
+ else this->NewFileDownError(ev);
+
+ return outPos;
+}
+
+void morkStream::NewBadCursorSlotsError(morkEnv* ev) const
+{ ev->NewError("bad stream cursor slots"); }
+
+void morkStream::NewNullStreamBufferError(morkEnv* ev) const
+{ ev->NewError("null stream buffer"); }
+
+void morkStream::NewCantReadSinkError(morkEnv* ev) const
+{ ev->NewError("cant read stream sink"); }
+
+void morkStream::NewCantWriteSourceError(morkEnv* ev) const
+{ ev->NewError("cant write stream source"); }
+
+void morkStream::NewPosBeyondEofError(morkEnv* ev) const
+{ ev->NewError("stream pos beyond eof"); }
+
+void morkStream::NewBadCursorOrderError(morkEnv* ev) const
+{ ev->NewError("bad stream cursor order"); }
+
+NS_IMETHODIMP
+morkStream::Tell(nsIMdbEnv* mdbev, mork_pos *aOutPos) const
+{
+ nsresult rv = NS_OK;
+ morkEnv *ev = morkEnv::FromMdbEnv(mdbev);
+
+ NS_ENSURE_ARG_POINTER(aOutPos);
+
+ nsIMdbFile* file = mStream_ContentFile;
+ if ( this->IsOpenAndActiveFile() && file )
+ {
+ mork_u1* buf = mStream_Buf;
+ mork_u1* at = mStream_At;
+
+ mork_u1* readEnd = mStream_ReadEnd; // nonzero only if readonly
+ mork_u1* writeEnd = mStream_WriteEnd; // nonzero only if writeonly
+
+ if ( writeEnd )
+ {
+ if ( buf && at >= buf && at <= writeEnd )
+ {
+ *aOutPos = mStream_BufPos + (at - buf);
+ }
+ else this->NewBadCursorOrderError(ev);
+ }
+ else if ( readEnd )
+ {
+ if ( buf && at >= buf && at <= readEnd )
+ {
+ *aOutPos = mStream_BufPos + (at - buf);
+ }
+ else this->NewBadCursorOrderError(ev);
+ }
+ }
+ else this->NewFileDownError(ev);
+
+ return rv;
+}
+
+NS_IMETHODIMP
+morkStream::Read(nsIMdbEnv* mdbev, void* outBuf, mork_size inSize, mork_size *aOutSize)
+{
+ NS_ENSURE_ARG_POINTER(aOutSize);
+ // First we satisfy the request from buffered bytes, if any. Then
+ // if additional bytes are needed, we satisfy these by direct reads
+ // from the content file without any local buffering (but we still need
+ // to adjust the buffer position to reflect the current i/o point).
+
+ morkEnv *ev = morkEnv::FromMdbEnv(mdbev);
+ nsresult rv = NS_OK;
+
+ nsIMdbFile* file = mStream_ContentFile;
+ if ( this->IsOpenAndActiveFile() && file )
+ {
+ mork_u1* end = mStream_ReadEnd; // byte after last buffered byte
+ if ( end ) // file is open for read access?
+ {
+ if ( inSize ) // caller wants any output?
+ {
+ mork_u1* sink = (mork_u1*) outBuf; // where we plan to write bytes
+ if ( sink ) // caller passed good buffer address?
+ {
+ mork_u1* at = mStream_At;
+ mork_u1* buf = mStream_Buf;
+ if ( at >= buf && at <= end ) // expected cursor order?
+ {
+ mork_num remaining = (mork_num) (end - at); // bytes left in buffer
+
+ mork_num quantum = inSize; // number of bytes to copy
+ if ( quantum > remaining ) // more than buffer content?
+ quantum = remaining; // restrict to buffered bytes
+
+ if ( quantum ) // any bytes left in the buffer?
+ {
+ MORK_MEMCPY(sink, at, quantum); // from buffer bytes
+
+ at += quantum; // advance past read bytes
+ mStream_At = at;
+ *aOutSize += quantum; // this much copied so far
+
+ sink += quantum; // in case we need to copy more
+ inSize -= quantum; // filled this much of request
+ mStream_HitEof = morkBool_kFalse;
+ }
+
+ if ( inSize ) // we still need to read more content?
+ {
+ // We need to read more bytes directly from the
+ // content file, without local buffering. We have
+ // exhausted the local buffer, so we need to show
+ // it is now empty, and adjust the current buf pos.
+
+ mork_num posDelta = (mork_num) (at - buf); // old buf content
+ mStream_BufPos += posDelta; // past now empty buf
+
+ mStream_At = mStream_ReadEnd = buf; // empty buffer
+
+ // file->Seek(ev, mStream_BufPos); // set file pos
+ // if ( ev->Good() ) // no seek error?
+ // {
+ // }
+
+ mork_num actual = 0;
+ nsIMdbEnv* menv = ev->AsMdbEnv();
+ file->Get(menv, sink, inSize, mStream_BufPos, &actual);
+ if ( ev->Good() ) // no read error?
+ {
+ if ( actual )
+ {
+ *aOutSize += actual;
+ mStream_BufPos += actual;
+ mStream_HitEof = morkBool_kFalse;
+ }
+ else if ( !*aOutSize )
+ mStream_HitEof = morkBool_kTrue;
+ }
+ }
+ }
+ else this->NewBadCursorOrderError(ev);
+ }
+ else this->NewNullStreamBufferError(ev);
+ }
+ }
+ else this->NewCantReadSinkError(ev);
+ }
+ else this->NewFileDownError(ev);
+
+ if ( ev->Bad() )
+ *aOutSize = 0;
+
+ return rv;
+}
+
+NS_IMETHODIMP
+morkStream::Seek(nsIMdbEnv * mdbev, mork_pos inPos, mork_pos *aOutPos)
+{
+ NS_ENSURE_ARG_POINTER(aOutPos);
+ morkEnv *ev = morkEnv::FromMdbEnv(mdbev);
+ *aOutPos = 0;
+ nsresult rv = NS_OK;
+ nsIMdbFile* file = mStream_ContentFile;
+ if ( this->IsOpenOrClosingNode() && this->FileActive() && file )
+ {
+ mork_u1* at = mStream_At; // current position in buffer
+ mork_u1* buf = mStream_Buf; // beginning of buffer
+ mork_u1* readEnd = mStream_ReadEnd; // nonzero only if readonly
+ mork_u1* writeEnd = mStream_WriteEnd; // nonzero only if writeonly
+
+ if ( writeEnd ) // file is mutable/writeonly?
+ {
+ if ( mStream_Dirty ) // need to commit buffer changes?
+ this->Flush(mdbev);
+
+ if ( ev->Good() ) // no errors during flush or earlier?
+ {
+ if ( at == buf ) // expected post flush cursor value?
+ {
+ if ( mStream_BufPos != inPos ) // need to change pos?
+ {
+ mork_pos eof = 0;
+ nsIMdbEnv* menv = ev->AsMdbEnv();
+ file->Eof(menv, &eof);
+ if ( ev->Good() ) // no errors getting length?
+ {
+ if ( inPos <= eof ) // acceptable new position?
+ {
+ mStream_BufPos = inPos; // new stream position
+ *aOutPos = inPos;
+ }
+ else this->NewPosBeyondEofError(ev);
+ }
+ }
+ }
+ else this->NewBadCursorOrderError(ev);
+ }
+ }
+ else if ( readEnd ) // file is frozen/readonly?
+ {
+ if ( at >= buf && at <= readEnd ) // expected cursor order?
+ {
+ mork_pos eof = 0;
+ nsIMdbEnv* menv = ev->AsMdbEnv();
+ file->Eof(menv, &eof);
+ if ( ev->Good() ) // no errors getting length?
+ {
+ if ( inPos <= eof ) // acceptable new position?
+ {
+ *aOutPos = inPos;
+ mStream_BufPos = inPos; // new stream position
+ mStream_At = mStream_ReadEnd = buf; // empty buffer
+ if ( inPos == eof ) // notice eof reached?
+ mStream_HitEof = morkBool_kTrue;
+ }
+ else this->NewPosBeyondEofError(ev);
+ }
+ }
+ else this->NewBadCursorOrderError(ev);
+ }
+
+ }
+ else this->NewFileDownError(ev);
+
+ return rv;
+}
+
+NS_IMETHODIMP
+morkStream::Write(nsIMdbEnv* menv, const void* inBuf, mork_size inSize, mork_size *aOutSize)
+{
+ mork_num outActual = 0;
+ morkEnv *ev = morkEnv::FromMdbEnv(menv);
+
+ nsIMdbFile* file = mStream_ContentFile;
+ if ( this->IsOpenActiveAndMutableFile() && file )
+ {
+ mork_u1* end = mStream_WriteEnd; // byte after last buffered byte
+ if ( end ) // file is open for write access?
+ {
+ if ( inSize ) // caller provided any input?
+ {
+ const mork_u1* source = (const mork_u1*) inBuf; // from where
+ if ( source ) // caller passed good buffer address?
+ {
+ mork_u1* at = mStream_At;
+ mork_u1* buf = mStream_Buf;
+ if ( at >= buf && at <= end ) // expected cursor order?
+ {
+ mork_num space = (mork_num) (end - at); // space left in buffer
+
+ mork_num quantum = inSize; // number of bytes to write
+ if ( quantum > space ) // more than buffer size?
+ quantum = space; // restrict to avail space
+
+ if ( quantum ) // any space left in the buffer?
+ {
+ mStream_Dirty = morkBool_kTrue; // to ensure later flush
+ MORK_MEMCPY(at, source, quantum); // into buffer
+
+ mStream_At += quantum; // advance past written bytes
+ outActual += quantum; // this much written so far
+
+ source += quantum; // in case we need to write more
+ inSize -= quantum; // filled this much of request
+ }
+
+ if ( inSize ) // we still need to write more content?
+ {
+ // We need to write more bytes directly to the
+ // content file, without local buffering. We have
+ // exhausted the local buffer, so we need to flush
+ // it and empty it, and adjust the current buf pos.
+ // After flushing, if the rest of the write fits
+ // inside the buffer, we will put bytes into the
+ // buffer rather than write them to content file.
+
+ if ( mStream_Dirty )
+ this->Flush(menv); // will update mStream_BufPos
+
+ at = mStream_At;
+ if ( at < buf || at > end ) // bad cursor?
+ this->NewBadCursorOrderError(ev);
+
+ if ( ev->Good() ) // no errors?
+ {
+ space = (mork_num) (end - at); // space left in buffer
+ if ( space > inSize ) // write to buffer?
+ {
+ mStream_Dirty = morkBool_kTrue; // ensure flush
+ MORK_MEMCPY(at, source, inSize); // copy
+
+ mStream_At += inSize; // past written bytes
+ outActual += inSize; // this much written
+ }
+ else // directly to content file instead
+ {
+ // file->Seek(ev, mStream_BufPos); // set pos
+ // if ( ev->Good() ) // no seek error?
+ // {
+ // }
+
+ mork_num actual = 0;
+ file->Put(menv, source, inSize, mStream_BufPos, &actual);
+ if ( ev->Good() ) // no write error?
+ {
+ outActual += actual;
+ mStream_BufPos += actual;
+ }
+ }
+ }
+ }
+ }
+ else this->NewBadCursorOrderError(ev);
+ }
+ else this->NewNullStreamBufferError(ev);
+ }
+ }
+ else this->NewCantWriteSourceError(ev);
+ }
+ else this->NewFileDownError(ev);
+
+ if ( ev->Bad() )
+ outActual = 0;
+
+ *aOutSize = outActual;
+ return ev->AsErr();
+}
+
+NS_IMETHODIMP
+morkStream::Flush(nsIMdbEnv* ev)
+{
+ morkEnv *mev = morkEnv::FromMdbEnv(ev);
+ nsresult rv = NS_ERROR_FAILURE;
+ nsIMdbFile* file = mStream_ContentFile;
+ if ( this->IsOpenOrClosingNode() && this->FileActive() && file )
+ {
+ if ( mStream_Dirty )
+ this->spill_buf(mev);
+
+ rv = file->Flush(ev);
+ }
+ else this->NewFileDownError(mev);
+ return rv;
+}
+
+// ````` ````` ````` ````` ````` ````` ````` `````
+// protected: // protected non-poly morkStream methods (for char io)
+
+int
+morkStream::fill_getc(morkEnv* ev)
+{
+ int c = EOF;
+
+ nsIMdbFile* file = mStream_ContentFile;
+ if ( this->IsOpenAndActiveFile() && file )
+ {
+ mork_u1* buf = mStream_Buf;
+ mork_u1* end = mStream_ReadEnd; // beyond buf after earlier read
+ if ( end > buf ) // any earlier read bytes buffered?
+ {
+ mStream_BufPos += ( end - buf ); // advance past old read
+ }
+
+ if ( ev->Good() ) // no errors yet?
+ {
+ // file->Seek(ev, mStream_BufPos); // set file pos
+ // if ( ev->Good() ) // no seek error?
+ // {
+ // }
+
+ nsIMdbEnv* menv = ev->AsMdbEnv();
+ mork_num actual = 0;
+ file->Get(menv, buf, mStream_BufSize, mStream_BufPos, &actual);
+ if ( ev->Good() ) // no read errors?
+ {
+ if ( actual > mStream_BufSize ) // more than asked for??
+ actual = mStream_BufSize;
+
+ mStream_At = buf;
+ mStream_ReadEnd = buf + actual;
+ if ( actual ) // any bytes actually read?
+ {
+ c = *mStream_At++; // return first byte from buffer
+ mStream_HitEof = morkBool_kFalse;
+ }
+ else
+ mStream_HitEof = morkBool_kTrue;
+ }
+ }
+ }
+ else this->NewFileDownError(ev);
+
+ return c;
+}
+
+void
+morkStream::spill_putc(morkEnv* ev, int c)
+{
+ this->spill_buf(ev);
+ if ( ev->Good() && mStream_At < mStream_WriteEnd )
+ this->Putc(ev, c);
+}
+
+void
+morkStream::spill_buf(morkEnv* ev) // spill/flush from buffer to file
+{
+ nsIMdbFile* file = mStream_ContentFile;
+ if ( this->IsOpenOrClosingNode() && this->FileActive() && file )
+ {
+ mork_u1* buf = mStream_Buf;
+ if ( mStream_Dirty )
+ {
+ mork_u1* at = mStream_At;
+ if ( at >= buf && at <= mStream_WriteEnd ) // order?
+ {
+ mork_num count = (mork_num) (at - buf); // bytes buffered
+ if ( count ) // anything to write to the string?
+ {
+ if ( count > mStream_BufSize ) // no more than max?
+ {
+ count = mStream_BufSize;
+ mStream_WriteEnd = buf + mStream_BufSize;
+ this->NewBadCursorSlotsError(ev);
+ }
+ if ( ev->Good() )
+ {
+ // file->Seek(ev, mStream_BufPos);
+ // if ( ev->Good() )
+ // {
+ // }
+ nsIMdbEnv* menv = ev->AsMdbEnv();
+ mork_num actual = 0;
+
+ file->Put(menv, buf, count, mStream_BufPos, &actual);
+ if ( ev->Good() )
+ {
+ mStream_BufPos += actual; // past bytes written
+ mStream_At = buf; // reset buffer cursor
+ mStream_Dirty = morkBool_kFalse;
+ }
+ }
+ }
+ }
+ else this->NewBadCursorOrderError(ev);
+ }
+ else
+ {
+#ifdef MORK_DEBUG
+ ev->NewWarning("stream:spill:not:dirty");
+#endif /*MORK_DEBUG*/
+ }
+ }
+ else this->NewFileDownError(ev);
+
+}
+
+
+//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789