/* -*- 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 //3456789_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 = MORK_STRLEN(inString); this->Write(ev, inString, size); } return ev->Good(); } //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789