summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/db/mork/morkSink.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mailnews/db/mork/morkSink.cpp')
-rw-r--r--comm/mailnews/db/mork/morkSink.cpp247
1 files changed, 247 insertions, 0 deletions
diff --git a/comm/mailnews/db/mork/morkSink.cpp b/comm/mailnews/db/mork/morkSink.cpp
new file mode 100644
index 0000000000..daf1bc1b9c
--- /dev/null
+++ b/comm/mailnews/db/mork/morkSink.cpp
@@ -0,0 +1,247 @@
+/* -*- 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