Back to index

lightning-sunbird  0.9+nobinonly
morkStream.h
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-  */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #ifndef _MORKSTREAM_
00039 #define _MORKSTREAM_ 1
00040 
00041 #ifndef _MORK_
00042 #include "mork.h"
00043 #endif
00044 
00045 #ifndef _MORKNODE_
00046 #include "morkNode.h"
00047 #endif
00048 
00049 #ifndef _MORKFILE_
00050 #include "morkFile.h"
00051 #endif
00052 
00053 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
00054 
00055 /*=============================================================================
00056  * morkStream: buffered file i/o
00057  */
00058 
00059 /*| morkStream exists to define an morkFile subclass that provides buffered
00060 **| i/o for an underlying content file.  Naturally this arrangement only makes
00061 **| sense when the underlying content file is itself not efficiently buffered
00062 **| (especially for character by character i/o).
00063 **|
00064 **|| morkStream is intended for either reading use or writing use, but not
00065 **| both simultaneously or interleaved.  Pick one when the stream is created
00066 **| and don't change your mind.  This restriction is intended to avoid obscure
00067 **| and complex bugs that might arise from interleaved reads and writes -- so
00068 **| just don't do it.  A stream is either a sink or a source, but not both.
00069 **|
00070 **|| (When the underlying content file is intended to support both reading and
00071 **| writing, a developer might use two instances of morkStream where one is for
00072 **| reading and the other is for writing.  In this case, a developer must take
00073 **| care to keep the two streams in sync because each will maintain a separate
00074 **| buffer representing a cache consistency problem for the other.  A simple
00075 **| approach is to invalidate the buffer of one when one uses the other, with
00076 **| the assumption that closely mixed reading and writing is not expected, so
00077 **| that little cost is associated with changing read/write streaming modes.)
00078 **|
00079 **|| Exactly one of mStream_ReadEnd or mStream_WriteEnd must be a null pointer,
00080 **| and this will cause the right thing to occur when inlines use them, because
00081 **| mStream_At < mStream_WriteEnd (for example) will always be false and the
00082 **| else branch of the statement calls a function that raises an appropriate
00083 **| error to complain about either reading a sink or writing a source.
00084 **|
00085 **|| morkStream is a direct clone of ab_Stream from Communicator 4.5's
00086 **| address book code, which in turn was based on the stream class in the
00087 **| public domain Mithril programming language.
00088 |*/
00089 
00090 #define morkStream_kPrintBufSize /*i*/ 512 /* buffer size used by printf() */ 
00091 
00092 #define morkStream_kMinBufSize /*i*/ 512 /* buffer no fewer bytes */ 
00093 #define morkStream_kMaxBufSize /*i*/ (32 * 1024) /* buffer no more bytes */ 
00094 
00095 #define morkDerived_kStream     /*i*/ 0x7A74 /* ascii 'zt' */
00096 
00097 class morkStream /*d*/ : public morkFile { /* from Mithril's AgStream class */
00098 
00099 // ````` ````` ````` `````   ````` ````` ````` `````  
00100 protected: // protected morkStream members
00101   mork_u1*    mStream_At;       // pointer into mStream_Buf
00102   mork_u1*    mStream_ReadEnd;  // null or one byte past last readable byte
00103   mork_u1*    mStream_WriteEnd; // null or mStream_Buf + mStream_BufSize
00104 
00105   nsIMdbFile* mStream_ContentFile;  // where content is read and written
00106 
00107   mork_u1*    mStream_Buf;      // dynamically allocated memory to buffer io
00108   mork_size   mStream_BufSize;  // requested buf size (fixed by min and max)
00109   mork_pos    mStream_BufPos;   // logical position of byte at mStream_Buf
00110   mork_bool   mStream_Dirty;    // does the buffer need to be flushed?
00111   mork_bool   mStream_HitEof;   // has eof been reached? (only frozen streams)
00112   
00113 // { ===== begin morkNode interface =====
00114 public: // morkNode virtual methods
00115   virtual void CloseMorkNode(morkEnv* ev); // CloseStream() only if open
00116   virtual ~morkStream(); // assert that CloseStream() executed earlier
00117   
00118 public: // morkStream construction & destruction
00119   morkStream(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap,
00120       nsIMdbFile* ioContentFile, mork_size inBufSize, mork_bool inFrozen);
00121   void CloseStream(morkEnv* ev); // called by CloseMorkNode();
00122 
00123 private: // copying is not allowed
00124   morkStream(const morkStream& other);
00125   morkStream& operator=(const morkStream& other);
00126 
00127 public: // dynamic type identification
00128   mork_bool IsStream() const
00129   { return IsNode() && mNode_Derived == morkDerived_kStream; }
00130 // } ===== end morkNode methods =====
00131 
00132 public: // typing
00133   void NonStreamTypeError(morkEnv* ev);
00134 
00135 // ````` ````` ````` `````   ````` ````` ````` `````  
00136 public: // virtual morkFile methods
00137 
00138   NS_IMETHOD Steal(nsIMdbEnv* ev, nsIMdbFile* ioThief);
00139   // Steal: tell this file to close any associated i/o stream in the file
00140   // system, because the file ioThief intends to reopen the file in order
00141   // to provide the MDB implementation with more exotic file access than is
00142   // offered by the nsIMdbFile alone.  Presumably the thief knows enough
00143   // from Path() in order to know which file to reopen.  If Steal() is
00144   // successful, this file should probably delegate all future calls to
00145   // the nsIMdbFile interface down to the thief files, so that even after
00146   // the file has been stolen, it can still be read, written, or forcibly
00147   // closed (by a call to CloseMdbObject()).
00148 
00149   NS_IMETHOD BecomeTrunk(nsIMdbEnv* ev);
00150   // If this file is a file version branch created by calling AcquireBud(),
00151   // BecomeTrunk() causes this file's content to replace the original
00152   // file's content, typically by assuming the original file's identity.
00153 
00154   NS_IMETHOD AcquireBud(nsIMdbEnv* ev, nsIMdbHeap* ioHeap, nsIMdbFile** acqBud);
00155   // AcquireBud() starts a new "branch" version of the file, empty of content,
00156   // so that a new version of the file can be written.  This new file
00157   // can later be told to BecomeTrunk() the original file, so the branch
00158   // created by budding the file will replace the original file.  Some
00159   // file subclasses might initially take the unsafe but expedient
00160   // approach of simply truncating this file down to zero length, and
00161   // then returning the same morkFile pointer as this, with an extra
00162   // reference count increment.  Note that the caller of AcquireBud() is
00163   // expected to eventually call CutStrongRef() on the returned file
00164   // in order to release the strong reference.  High quality versions
00165   // of morkFile subclasses will create entirely new files which later
00166   // are renamed to become the old file, so that better transactional
00167   // behavior is exhibited by the file, so crashes protect old files.
00168   // Note that AcquireBud() is an illegal operation on readonly files.
00169   
00170   virtual mork_pos Length(morkEnv* ev) const; // eof
00171   NS_IMETHOD  Tell(nsIMdbEnv* ev, mork_pos *aOutPos  ) const;
00172   NS_IMETHOD  Read(nsIMdbEnv* ev, void* outBuf, mork_size inSize, mork_size *aOutCount);
00173   NS_IMETHOD  Seek(nsIMdbEnv* ev, mork_pos inPos, mork_pos *aOutPos);
00174   NS_IMETHOD  Write(nsIMdbEnv* ev, const void* inBuf, mork_size inSize, mork_size *aOutCount);
00175   NS_IMETHOD  Flush(nsIMdbEnv* ev);
00176     
00177 // ````` ````` ````` `````   ````` ````` ````` `````  
00178 protected: // protected non-poly morkStream methods (for char io)
00179 
00180   int     fill_getc(morkEnv* ev);
00181   void    spill_putc(morkEnv* ev, int c);
00182   void    spill_buf(morkEnv* ev); // spill/flush from buffer to file
00183       
00184 // ````` ````` ````` `````   ````` ````` ````` `````  
00185 public: // public non-poly morkStream methods
00186     
00187   void NewBadCursorSlotsError(morkEnv* ev) const;
00188   void NewBadCursorOrderError(morkEnv* ev) const;
00189   void NewNullStreamBufferError(morkEnv* ev) const;
00190   void NewCantReadSinkError(morkEnv* ev) const;
00191   void NewCantWriteSourceError(morkEnv* ev) const;
00192   void NewPosBeyondEofError(morkEnv* ev) const;
00193       
00194   nsIMdbFile* GetStreamContentFile() const { return mStream_ContentFile; }
00195   mork_size   GetStreamBufferSize() const { return mStream_BufSize; }
00196   
00197   mork_size  PutIndent(morkEnv* ev, mork_count inDepth);
00198   // PutIndent() puts a linebreak, and then
00199   // "indents" by inDepth, and returns the line length after indentation.
00200   
00201   mork_size  PutByteThenIndent(morkEnv* ev, int inByte, mork_count inDepth);
00202   // PutByteThenIndent() puts the byte, then a linebreak, and then
00203   // "indents" by inDepth, and returns the line length after indentation.
00204   
00205   mork_size  PutStringThenIndent(morkEnv* ev,
00206     const char* inString, mork_count inDepth);
00207   // PutStringThenIndent() puts the string, then a linebreak, and then
00208   // "indents" by inDepth, and returns the line length after indentation.
00209   
00210   mork_size  PutString(morkEnv* ev, const char* inString);
00211   // PutString() returns the length of the string written.
00212   
00213   mork_size  PutStringThenNewline(morkEnv* ev, const char* inString);
00214   // PutStringThenNewline() returns total number of bytes written.
00215 
00216   mork_size  PutByteThenNewline(morkEnv* ev, int inByte);
00217   // PutByteThenNewline() returns total number of bytes written.
00218 
00219   // ````` ````` stdio type methods ````` ````` 
00220   void    Ungetc(int c) /*i*/
00221   { if ( mStream_At > mStream_Buf && c > 0 ) *--mStream_At = (mork_u1) c; }
00222   
00223   // Note Getc() returns EOF consistently after any fill_getc() error occurs.
00224   int     Getc(morkEnv* ev) /*i*/
00225   { return ( mStream_At < mStream_ReadEnd )? *mStream_At++ : fill_getc(ev); }
00226   
00227   void    Putc(morkEnv* ev, int c) /*i*/
00228   { 
00229     mStream_Dirty = morkBool_kTrue;
00230     if ( mStream_At < mStream_WriteEnd )
00231       *mStream_At++ = (mork_u1) c;
00232     else
00233       spill_putc(ev, c);
00234   }
00235 
00236   mork_size PutLineBreak(morkEnv* ev);
00237   
00238 public: // typesafe refcounting inlines calling inherited morkNode methods
00239   static void SlotWeakStream(morkStream* me,
00240     morkEnv* ev, morkStream** ioSlot)
00241   { morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
00242   
00243   static void SlotStrongStream(morkStream* me,
00244     morkEnv* ev, morkStream** ioSlot)
00245   { morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
00246 };
00247 
00248 
00249 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
00250 
00251 #endif /* _MORKSTREAM_ */