Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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
// 456789_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) {
nsresult rc =
this->Write(mev, morkStream_kSpaces, inDepth, &bytesWritten);
if (NS_FAILED(rc)) {
NS_WARNING("Write failed");
}
}
}
}
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) {
nsresult rc =
this->Write(mev, morkStream_kSpaces, inDepth, &bytesWritten);
if (NS_FAILED(rc)) {
NS_WARNING("Write failed");
}
}
}
}
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 = strlen(inString);
if (length && ev->Good()) // any bytes to write?
{
nsresult rc = this->Write(mev, inString, length, &bytesWritten);
if (NS_FAILED(rc)) {
NS_WARNING("Write failed");
}
}
}
if (ev->Good()) {
this->PutLineBreak(ev);
if (ev->Good()) {
outLength = inDepth;
if (inDepth) {
nsresult rc =
this->Write(mev, morkStream_kSpaces, inDepth, &bytesWritten);
if (NS_FAILED(rc)) {
NS_WARNING("Write failed");
}
}
}
}
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 = strlen(inString);
if (outSize && ev->Good()) // any bytes to write?
{
nsresult rc = this->Write(mev, inString, outSize, &bytesWritten);
if (NS_FAILED(rc)) {
NS_WARNING("Write failed");
}
}
}
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 = strlen(inString);
if (outSize && ev->Good()) // any bytes to write?
{
nsresult rc = this->Write(mev, inString, outSize, &bytesWritten);
if (NS_FAILED(rc)) {
NS_WARNING("Write failed");
}
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("can't read stream sink");
}
void morkStream::NewCantWriteSourceError(morkEnv* ev) const {
ev->NewError("can't 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);
}
// 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789