/* -*- 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 _MORKSINK_ # include "morkSink.h" #endif #ifndef _MORKENV_ # include "morkEnv.h" #endif #ifndef _MORKBLOB_ # include "morkBlob.h" #endif // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 /*virtual*/ morkSink::~morkSink() { mSink_At = 0; mSink_End = 0; } /*virtual*/ void morkSpool::FlushSink( morkEnv* ev) // sync mSpool_Coil->mBuf_Fill { morkCoil* coil = mSpool_Coil; if (coil) { mork_u1* body = (mork_u1*)coil->mBuf_Body; if (body) { mork_u1* at = mSink_At; mork_u1* end = mSink_End; if (at >= body && at <= end) // expected cursor order? { mork_fill fill = (mork_fill)(at - body); // current content size if (fill <= coil->mBlob_Size) coil->mBuf_Fill = fill; else { coil->BlobFillOverSizeError(ev); coil->mBuf_Fill = coil->mBlob_Size; // make it safe } } else this->BadSpoolCursorOrderError(ev); } else coil->NilBufBodyError(ev); } else this->NilSpoolCoilError(ev); } /*virtual*/ void morkSpool::SpillPutc(morkEnv* ev, int c) // grow coil and write byte { morkCoil* coil = mSpool_Coil; if (coil) { mork_u1* body = (mork_u1*)coil->mBuf_Body; if (body) { mork_u1* at = mSink_At; mork_u1* end = mSink_End; if (at >= body && at <= end) // expected cursor order? { mork_size size = coil->mBlob_Size; mork_fill fill = (mork_fill)(at - body); // current content size if (fill <= size) // less content than medium size? { coil->mBuf_Fill = fill; if (at >= end) // need to grow the coil? { if (size > 2048) // grow slower over 2K? size += 512; else { mork_size growth = (size * 4) / 3; // grow by 33% if (growth < 64) // grow faster under (64 * 3)? growth = 64; size += growth; } if (coil->GrowCoil(ev, size)) // made coil bigger? { body = (mork_u1*)coil->mBuf_Body; if (body) // have a coil body? { mSink_At = at = body + fill; mSink_End = end = body + coil->mBlob_Size; } else coil->NilBufBodyError(ev); } } if (ev->Good()) // seem ready to write byte c? { if (at < end) // morkSink::Putc() would succeed? { *at++ = (mork_u1)c; mSink_At = at; coil->mBuf_Fill = fill + 1; } else this->BadSpoolCursorOrderError(ev); } } else // fill exceeds size { coil->BlobFillOverSizeError(ev); coil->mBuf_Fill = coil->mBlob_Size; // make it safe } } else this->BadSpoolCursorOrderError(ev); } else coil->NilBufBodyError(ev); } else this->NilSpoolCoilError(ev); } // ````` ````` ````` ````` ````` ````` ````` ````` // public: // public non-poly morkSink methods /*virtual*/ morkSpool::~morkSpool() // Zero all slots to show this sink is disabled, but destroy no memory. // Note it is typically unnecessary to flush this coil sink, since all // content is written directly to the coil without any buffering. { mSink_At = 0; mSink_End = 0; mSpool_Coil = 0; } morkSpool::morkSpool(morkEnv* ev, morkCoil* ioCoil) // After installing the coil, calls Seek(ev, 0) to prepare for writing. : morkSink(), mSpool_Coil(0) { mSink_At = 0; // set correctly later in Seek() mSink_End = 0; // set correctly later in Seek() if (ev->Good()) { if (ioCoil) { mSpool_Coil = ioCoil; this->Seek(ev, /*pos*/ 0); } else ev->NilPointerError(); } } // ----- All boolean return values below are equal to ev->Good(): ----- /*static*/ void morkSpool::BadSpoolCursorOrderError(morkEnv* ev) { ev->NewError("bad morkSpool cursor order"); } /*static*/ void morkSpool::NilSpoolCoilError(morkEnv* ev) { ev->NewError("nil mSpool_Coil"); } mork_bool morkSpool::Seek(morkEnv* ev, mork_pos inPos) // Changed the current write position in coil's buffer to inPos. // For example, to start writing the coil from scratch, use inPos==0. { morkCoil* coil = mSpool_Coil; if (coil) { mork_size minSize = (mork_size)(inPos + 64); if (coil->mBlob_Size < minSize) coil->GrowCoil(ev, minSize); if (ev->Good()) { coil->mBuf_Fill = (mork_fill)inPos; mork_u1* body = (mork_u1*)coil->mBuf_Body; if (body) { mSink_At = body + inPos; mSink_End = body + coil->mBlob_Size; } else coil->NilBufBodyError(ev); } } else this->NilSpoolCoilError(ev); return ev->Good(); } mork_bool morkSpool::Write(morkEnv* ev, const void* inBuf, mork_size inSize) // write inSize bytes of inBuf to current position inside coil's buffer { // This method is conceptually very similar to morkStream::Write(), // and this code was written while looking at that method for clues. morkCoil* coil = mSpool_Coil; if (coil) { mork_u1* body = (mork_u1*)coil->mBuf_Body; if (body) { if (inBuf && inSize) // anything to write? { mork_u1* at = mSink_At; mork_u1* end = mSink_End; if (at >= body && at <= end) // expected cursor order? { // note coil->mBuf_Fill can be stale after morkSink::Putc(): mork_pos fill = at - body; // current content size mork_num space = (mork_num)(end - at); // space left in body if (space < inSize) // not enough to hold write? { mork_size minGrowth = space + 16; mork_size minSize = coil->mBlob_Size + minGrowth; if (coil->GrowCoil(ev, minSize)) { body = (mork_u1*)coil->mBuf_Body; if (body) { mSink_At = at = body + fill; mSink_End = end = body + coil->mBlob_Size; space = (mork_num)(end - at); // space left in body } else coil->NilBufBodyError(ev); } } if (ev->Good()) { if (space >= inSize) // enough room to hold write? { MORK_MEMCPY(at, inBuf, inSize); // into body mSink_At = at + inSize; // advance past written bytes coil->mBuf_Fill = fill + inSize; // "flush" to fix fill } else ev->NewError("insufficient morkSpool space"); } } else this->BadSpoolCursorOrderError(ev); } } else coil->NilBufBodyError(ev); } else this->NilSpoolCoilError(ev); return ev->Good(); } mork_bool morkSpool::PutString(morkEnv* ev, const char* inString) // call Write() with inBuf=inString and inSize=strlen(inString), // unless inString is null, in which case we then do nothing at all. { if (inString) { mork_size size = strlen(inString); this->Write(ev, inString, size); } return ev->Good(); } // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789