diff options
Diffstat (limited to 'db/mork/src/morkStream.h')
-rw-r--r-- | db/mork/src/morkStream.h | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/db/mork/src/morkStream.h b/db/mork/src/morkStream.h new file mode 100644 index 000000000..418b68070 --- /dev/null +++ b/db/mork/src/morkStream.h @@ -0,0 +1,251 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef _MORKSTREAM_ +#define _MORKSTREAM_ 1 + +#ifndef _MORK_ +#include "mork.h" +#endif + +#ifndef _MORKNODE_ +#include "morkNode.h" +#endif + +#ifndef _MORKFILE_ +#include "morkFile.h" +#endif + +//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 + +/*============================================================================= + * morkStream: buffered file i/o + */ + +/*| morkStream exists to define an morkFile subclass that provides buffered +**| i/o for an underlying content file. Naturally this arrangement only makes +**| sense when the underlying content file is itself not efficiently buffered +**| (especially for character by character i/o). +**| +**|| morkStream is intended for either reading use or writing use, but not +**| both simultaneously or interleaved. Pick one when the stream is created +**| and don't change your mind. This restriction is intended to avoid obscure +**| and complex bugs that might arise from interleaved reads and writes -- so +**| just don't do it. A stream is either a sink or a source, but not both. +**| +**|| (When the underlying content file is intended to support both reading and +**| writing, a developer might use two instances of morkStream where one is for +**| reading and the other is for writing. In this case, a developer must take +**| care to keep the two streams in sync because each will maintain a separate +**| buffer representing a cache consistency problem for the other. A simple +**| approach is to invalidate the buffer of one when one uses the other, with +**| the assumption that closely mixed reading and writing is not expected, so +**| that little cost is associated with changing read/write streaming modes.) +**| +**|| Exactly one of mStream_ReadEnd or mStream_WriteEnd must be a null pointer, +**| and this will cause the right thing to occur when inlines use them, because +**| mStream_At < mStream_WriteEnd (for example) will always be false and the +**| else branch of the statement calls a function that raises an appropriate +**| error to complain about either reading a sink or writing a source. +**| +**|| morkStream is a direct clone of ab_Stream from Communicator 4.5's +**| address book code, which in turn was based on the stream class in the +**| public domain Mithril programming language. +|*/ + +#define morkStream_kPrintBufSize /*i*/ 512 /* buffer size used by printf() */ + +#define morkStream_kMinBufSize /*i*/ 512 /* buffer no fewer bytes */ +#define morkStream_kMaxBufSize /*i*/ (32 * 1024) /* buffer no more bytes */ + +#define morkDerived_kStream /*i*/ 0x7A74 /* ascii 'zt' */ + +class morkStream /*d*/ : public morkFile { /* from Mithril's AgStream class */ + +// ````` ````` ````` ````` ````` ````` ````` ````` +protected: // protected morkStream members + mork_u1* mStream_At; // pointer into mStream_Buf + mork_u1* mStream_ReadEnd; // null or one byte past last readable byte + mork_u1* mStream_WriteEnd; // null or mStream_Buf + mStream_BufSize + + nsIMdbFile* mStream_ContentFile; // where content is read and written + + mork_u1* mStream_Buf; // dynamically allocated memory to buffer io + mork_size mStream_BufSize; // requested buf size (fixed by min and max) + mork_pos mStream_BufPos; // logical position of byte at mStream_Buf + mork_bool mStream_Dirty; // does the buffer need to be flushed? + mork_bool mStream_HitEof; // has eof been reached? (only frozen streams) + +// { ===== begin morkNode interface ===== +public: // morkNode virtual methods + virtual void CloseMorkNode(morkEnv* ev) override; // CloseStream() only if open + virtual ~morkStream(); // assert that CloseStream() executed earlier + +public: // morkStream construction & destruction + morkStream(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap, + nsIMdbFile* ioContentFile, mork_size inBufSize, mork_bool inFrozen); + void CloseStream(morkEnv* ev); // called by CloseMorkNode(); + +private: // copying is not allowed + morkStream(const morkStream& other); + morkStream& operator=(const morkStream& other); + +public: // dynamic type identification + mork_bool IsStream() const + { return IsNode() && mNode_Derived == morkDerived_kStream; } +// } ===== end morkNode methods ===== + +public: // typing + void NonStreamTypeError(morkEnv* ev); + +// ````` ````` ````` ````` ````` ````` ````` ````` +public: // virtual morkFile methods + + NS_IMETHOD Steal(nsIMdbEnv* ev, nsIMdbFile* ioThief) override; + // 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()). + + NS_IMETHOD BecomeTrunk(nsIMdbEnv* ev) override; + // 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. + + NS_IMETHOD AcquireBud(nsIMdbEnv* ev, nsIMdbHeap* ioHeap, nsIMdbFile** acqBud) override; + // 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. + + virtual mork_pos Length(morkEnv* ev) const override; // eof + NS_IMETHOD Tell(nsIMdbEnv* ev, mork_pos *aOutPos ) const override; + NS_IMETHOD Read(nsIMdbEnv* ev, void* outBuf, mork_size inSize, mork_size *aOutCount) override; + NS_IMETHOD Seek(nsIMdbEnv* ev, mork_pos inPos, mork_pos *aOutPos) override; + NS_IMETHOD Write(nsIMdbEnv* ev, const void* inBuf, mork_size inSize, mork_size *aOutCount) override; + NS_IMETHOD Flush(nsIMdbEnv* ev) override; + +// ````` ````` ````` ````` ````` ````` ````` ````` +protected: // protected non-poly morkStream methods (for char io) + + int fill_getc(morkEnv* ev); + void spill_putc(morkEnv* ev, int c); + void spill_buf(morkEnv* ev); // spill/flush from buffer to file + +// ````` ````` ````` ````` ````` ````` ````` ````` +public: // public non-poly morkStream methods + + void NewBadCursorSlotsError(morkEnv* ev) const; + void NewBadCursorOrderError(morkEnv* ev) const; + void NewNullStreamBufferError(morkEnv* ev) const; + void NewCantReadSinkError(morkEnv* ev) const; + void NewCantWriteSourceError(morkEnv* ev) const; + void NewPosBeyondEofError(morkEnv* ev) const; + + nsIMdbFile* GetStreamContentFile() const { return mStream_ContentFile; } + mork_size GetStreamBufferSize() const { return mStream_BufSize; } + + mork_size PutIndent(morkEnv* ev, mork_count inDepth); + // PutIndent() puts a linebreak, and then + // "indents" by inDepth, and returns the line length after indentation. + + mork_size 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 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 PutString(morkEnv* ev, const char* inString); + // PutString() returns the length of the string written. + + mork_size PutStringThenNewline(morkEnv* ev, const char* inString); + // PutStringThenNewline() returns total number of bytes written. + + mork_size PutByteThenNewline(morkEnv* ev, int inByte); + // PutByteThenNewline() returns total number of bytes written. + + // ````` ````` stdio type methods ````` ````` + void Ungetc(int c) /*i*/ + { if ( mStream_At > mStream_Buf && c > 0 ) *--mStream_At = (mork_u1) c; } + + // Note Getc() returns EOF consistently after any fill_getc() error occurs. + int Getc(morkEnv* ev) /*i*/ + { return ( mStream_At < mStream_ReadEnd )? *mStream_At++ : fill_getc(ev); } + + void Putc(morkEnv* ev, int c) /*i*/ + { + mStream_Dirty = morkBool_kTrue; + if ( mStream_At < mStream_WriteEnd ) + *mStream_At++ = (mork_u1) c; + else + spill_putc(ev, c); + } + + mork_size PutLineBreak(morkEnv* ev); + +public: // typesafe refcounting inlines calling inherited morkNode methods + static void SlotWeakStream(morkStream* me, + morkEnv* ev, morkStream** ioSlot) + { morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); } + + static void SlotStrongStream(morkStream* me, + morkEnv* ev, morkStream** ioSlot) + { morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); } +}; + + +//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 + +#endif /* _MORKSTREAM_ */ |