1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-  */
2 /* ***** BEGIN LICENSE BLOCK *****
3  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  * http://www.mozilla.org/MPL/
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  *
15  * The Original Code is mozilla.org code.
16  *
17  * The Initial Developer of the Original Code is
18  * Netscape Communications Corporation.
19  * Portions created by the Initial Developer are Copyright (C) 1999
20  * the Initial Developer. All Rights Reserved.
21  *
22  * Contributor(s):
23  *
24  * Alternatively, the contents of this file may be used under the terms of
25  * either of the GNU General Public License Version 2 or later (the "GPL"),
26  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27  * in which case the provisions of the GPL or the LGPL are applicable instead
28  * of those above. If you wish to allow use of your version of this file only
29  * under the terms of either the GPL or the LGPL, and not to allow others to
30  * use your version of this file under the terms of the MPL, indicate your
31  * decision by deleting the provisions above and replace them with the notice
32  * and other provisions required by the GPL or the LGPL. If you do not delete
33  * the provisions above, a recipient may use your version of this file under
34  * the terms of any one of the MPL, the GPL or the LGPL.
35  *
36  * ***** END LICENSE BLOCK ***** */
37 
38 #ifndef _MORKFILE_
39 #define _MORKFILE_ 1
40 
41 #ifndef _MORK_
42 #  include "mork.h"
43 #endif
44 
45 #ifndef _MORKNODE_
46 #  include "morkNode.h"
47 #endif
48 
49 #ifndef _MORKOBJECT_
50 #  include "morkObject.h"
51 #endif
52 
53 #include "mozilla/Path.h"
54 
55 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
56 
57 /*=============================================================================
58  * morkFile: abstract file interface
59  */
60 
61 #define morkDerived_kFile /*i*/ 0x4669 /* ascii 'Fi' */
62 
63 class morkFile /*d*/ : public morkObject,
64                        public nsIMdbFile { /* ````` simple file API ````` */
65   using PathChar = mozilla::filesystem::Path::value_type;
66 
67   // public: // slots inherited from morkNode (meant to inform only)
68   // nsIMdbHeap*    mNode_Heap;
69 
70   // mork_base      mNode_Base;     // must equal morkBase_kNode
71   // mork_derived   mNode_Derived;  // depends on specific node subclass
72 
73   // mork_access    mNode_Access;   // kOpen, kClosing, kShut, or kDead
74   // mork_usage     mNode_Usage;    // kHeap, kStack, kMember, kGlobal, kNone
75   // mork_able      mNode_Mutable;  // can this node be modified?
76   // mork_load      mNode_Load;     // is this node clean or dirty?
77 
78   // mork_uses      mNode_Uses;     // refcount for strong refs
79   // mork_refs      mNode_Refs;     // refcount for strong refs + weak refs
80 
81   // public: // slots inherited from morkObject (meant to inform only)
82 
83   // mork_color   mBead_Color;   // ID for this bead
84   // morkHandle*  mObject_Handle;  // weak ref to handle for this object
85 
86   // ````` ````` ````` `````   ````` ````` ````` `````
87  protected:  // protected morkFile members (similar to public domain IronDoc)
88   virtual ~morkFile();  // assert that CloseFile() executed earlier
89 
90   mork_u1 mFile_Frozen;   // 'F' => file allows only read access
91   mork_u1 mFile_DoTrace;  // 'T' trace if ev->DoTrace()
92   mork_u1 mFile_IoOpen;   // 'O' => io stream is open (& needs a close)
93   mork_u1 mFile_Active;   // 'A' => file is active and usable
94 
95   nsIMdbHeap* mFile_SlotHeap;  // heap for Name and other allocated slots
96   PathChar* mFile_Name;        // can be nil if SetFileName() is never called
97   // mFile_Name convention: managed with morkEnv::CopyString()/FreeString()
98 
99   nsIMdbFile* mFile_Thief;  // from a call to orkinFile::Steal()
100 
101   // { ===== begin morkNode interface =====
102  public:  // morkNode virtual methods
103   NS_DECL_ISUPPORTS_INHERITED
104   virtual void CloseMorkNode(morkEnv* ev) override;  // CloseFile() only if open
105 
106  public:  // morkFile construction & destruction
107   morkFile(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap,
108            nsIMdbHeap* ioSlotHeap);
109   void CloseFile(morkEnv* ev);  // called by CloseMorkNode();
110 
111  private:  // copying is not allowed
112   morkFile(const morkFile& other);
113   morkFile& operator=(const morkFile& other);
114 
115  public:  // dynamic type identification
IsFile()116   mork_bool IsFile() const {
117     return IsNode() && mNode_Derived == morkDerived_kFile;
118   }
119   // } ===== end morkNode methods =====
120 
121   // ````` ````` ````` `````   ````` ````` ````` `````
122  public:  // public static standard file creation entry point
123   static morkFile* OpenOldFile(morkEnv* ev, nsIMdbHeap* ioHeap,
124                                const PathChar* inFilePath, mork_bool inFrozen);
125   // Choose some subclass of morkFile to instantiate, in order to read
126   // (and write if not frozen) the file known by inFilePath.  The file
127   // returned should be open and ready for use, and presumably positioned
128   // at the first byte position of the file.  The exact manner in which
129   // files must be opened is considered a subclass specific detail, and
130   // other portions or Mork source code don't want to know how it's done.
131 
132   static morkFile* CreateNewFile(morkEnv* ev, nsIMdbHeap* ioHeap,
133                                  const PathChar* inFilePath);
134   // Choose some subclass of morkFile to instantiate, in order to read
135   // (and write if not frozen) the file known by inFilePath.  The file
136   // returned should be created and ready for use, and presumably positioned
137   // at the first byte position of the file.  The exact manner in which
138   // files must be opened is considered a subclass specific detail, and
139   // other portions or Mork source code don't want to know how it's done.
140 
141  public:  // non-poly morkFile methods
FileFrozen()142   mork_bool FileFrozen() const { return mFile_Frozen == 'F'; }
FileDoTrace()143   mork_bool FileDoTrace() const { return mFile_DoTrace == 'T'; }
FileIoOpen()144   mork_bool FileIoOpen() const { return mFile_IoOpen == 'O'; }
FileActive()145   mork_bool FileActive() const { return mFile_Active == 'A'; }
146 
SetFileFrozen(mork_bool b)147   void SetFileFrozen(mork_bool b) { mFile_Frozen = (mork_u1)((b) ? 'F' : 0); }
SetFileDoTrace(mork_bool b)148   void SetFileDoTrace(mork_bool b) { mFile_DoTrace = (mork_u1)((b) ? 'T' : 0); }
SetFileIoOpen(mork_bool b)149   void SetFileIoOpen(mork_bool b) { mFile_IoOpen = (mork_u1)((b) ? 'O' : 0); }
SetFileActive(mork_bool b)150   void SetFileActive(mork_bool b) { mFile_Active = (mork_u1)((b) ? 'A' : 0); }
151 
IsOpenActiveAndMutableFile()152   mork_bool IsOpenActiveAndMutableFile() const {
153     return (IsOpenNode() && FileActive() && !FileFrozen());
154   }
155   // call IsOpenActiveAndMutableFile() before writing a file
156 
IsOpenAndActiveFile()157   mork_bool IsOpenAndActiveFile() const {
158     return (this->IsOpenNode() && this->FileActive());
159   }
160   // call IsOpenAndActiveFile() before using a file
161 
GetThief()162   nsIMdbFile* GetThief() const { return mFile_Thief; }
163   void SetThief(morkEnv* ev, nsIMdbFile* ioThief);  // ioThief can be nil
164 
GetFileNameString()165   const PathChar* GetFileNameString() const { return mFile_Name; }
166   void SetFileName(morkEnv* ev, const PathChar* inName);  // inName can be nil
167   static void NilSlotHeapError(morkEnv* ev);
168   static void NilFileNameError(morkEnv* ev);
169   static void NonFileTypeError(morkEnv* ev);
170 
171   void NewMissingIoError(morkEnv* ev) const;
172 
173   void NewFileDownError(morkEnv* ev) const;
174   // call NewFileDownError() when either IsOpenAndActiveFile()
175   // is false, or when IsOpenActiveAndMutableFile() is false.
176 
177   void NewFileErrnoError(morkEnv* ev) const;
178   // call NewFileErrnoError() to convert std C errno into AB fault
179 
180   mork_size WriteNewlines(morkEnv* ev, mork_count inNewlines);
181   // WriteNewlines() returns the number of bytes written.
182 
183  public:  // typesafe refcounting inlines calling inherited morkNode methods
SlotWeakFile(morkFile * me,morkEnv * ev,morkFile ** ioSlot)184   static void SlotWeakFile(morkFile* me, morkEnv* ev, morkFile** ioSlot) {
185     morkNode::SlotWeakNode((morkNode*)me, ev, (morkNode**)ioSlot);
186   }
187 
SlotStrongFile(morkFile * me,morkEnv * ev,morkFile ** ioSlot)188   static void SlotStrongFile(morkFile* me, morkEnv* ev, morkFile** ioSlot) {
189     morkNode::SlotStrongNode((morkNode*)me, ev, (morkNode**)ioSlot);
190   }
191 
192  public:
193   virtual mork_pos Length(morkEnv* ev) const = 0;  // eof
194   // nsIMdbFile methods
195   NS_IMETHOD Tell(nsIMdbEnv* ev, mdb_pos* outPos) const override = 0;
196   NS_IMETHOD Seek(nsIMdbEnv* ev, mdb_pos inPos, mdb_pos* outPos) override = 0;
197   NS_IMETHOD Eof(nsIMdbEnv* ev, mdb_pos* outPos) override;
198   // } ----- end pos methods -----
199 
200   // { ----- begin read methods -----
201   NS_IMETHOD Read(nsIMdbEnv* ev, void* outBuf, mdb_size inSize,
202                   mdb_size* outActualSize) override = 0;
203   NS_IMETHOD Get(nsIMdbEnv* ev, void* outBuf, mdb_size inSize, mdb_pos inPos,
204                  mdb_size* outActualSize) override;
205   // } ----- end read methods -----
206 
207   // { ----- begin write methods -----
208   NS_IMETHOD Write(nsIMdbEnv* ev, const void* inBuf, mdb_size inSize,
209                    mdb_size* outActualSize) override = 0;
210   NS_IMETHOD Put(nsIMdbEnv* ev, const void* inBuf, mdb_size inSize,
211                  mdb_pos inPos, mdb_size* outActualSize) override;
212   NS_IMETHOD Flush(nsIMdbEnv* ev) override = 0;
213   // } ----- end attribute methods -----
214 
215   // { ----- begin path methods -----
216   NS_IMETHOD Path(nsIMdbEnv* ev, mdbYarn* outFilePath) override;
217   // } ----- end path methods -----
218 
219   // { ----- begin replacement methods -----
220   NS_IMETHOD Steal(nsIMdbEnv* ev, nsIMdbFile* ioThief) override = 0;
221   NS_IMETHOD Thief(nsIMdbEnv* ev, nsIMdbFile** acqThief) override;
222   // } ----- end replacement methods -----
223 
224   // { ----- begin versioning methods -----
225   NS_IMETHOD BecomeTrunk(nsIMdbEnv* ev) override = 0;
226 
227   NS_IMETHOD AcquireBud(nsIMdbEnv* ev, nsIMdbHeap* ioHeap,
228                         nsIMdbFile** acqBud) override = 0;
229   // } ----- end versioning methods -----
230 
231   // } ===== end nsIMdbFile methods =====
232 };
233 
234 /*=============================================================================
235  * morkStdioFile: concrete file using standard C file io
236  */
237 
238 #define morkDerived_kStdioFile /*i*/ 0x7346 /* ascii 'sF' */
239 
240 class morkStdioFile /*d*/ : public morkFile { /* `` copied from IronDoc `` */
241   using PathChar = mozilla::filesystem::Path::value_type;
242 
243   // ````` ````` ````` `````   ````` ````` ````` `````
244  protected:  // protected morkStdioFile members
245   void* mStdioFile_File;
246   // actually type FILE*, but using opaque void* type
247 
248   // { ===== begin morkNode interface =====
249  public:  // morkNode virtual methods
250   virtual void CloseMorkNode(
251       morkEnv* ev) override;  // CloseStdioFile() only if open
252   virtual ~morkStdioFile();   // assert that CloseStdioFile() executed earlier
253 
254  public:  // morkStdioFile construction & destruction
255   morkStdioFile(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap,
256                 nsIMdbHeap* ioSlotHeap);
257   void CloseStdioFile(morkEnv* ev);  // called by CloseMorkNode();
258 
259  private:  // copying is not allowed
260   morkStdioFile(const morkStdioFile& other);
261   morkStdioFile& operator=(const morkStdioFile& other);
262 
263  public:  // dynamic type identification
IsStdioFile()264   mork_bool IsStdioFile() const {
265     return IsNode() && mNode_Derived == morkDerived_kStdioFile;
266   }
267   // } ===== end morkNode methods =====
268 
269  public:  // typing
270   static void NonStdioFileTypeError(morkEnv* ev);
271 
272   // ````` ````` ````` `````   ````` ````` ````` `````
273  public:  // compatible with the morkFile::OpenOldFile() entry point
274   static morkStdioFile* OpenOldStdioFile(morkEnv* ev, nsIMdbHeap* ioHeap,
275                                          const PathChar* inFilePath,
276                                          mork_bool inFrozen);
277 
278   static morkStdioFile* CreateNewStdioFile(morkEnv* ev, nsIMdbHeap* ioHeap,
279                                            const PathChar* inFilePath);
280 
281   virtual mork_pos Length(morkEnv* ev) const override;  // eof
282 
283   NS_IMETHOD Tell(nsIMdbEnv* ev, mdb_pos* outPos) const override;
284   NS_IMETHOD Seek(nsIMdbEnv* ev, mdb_pos inPos, mdb_pos* outPos) override;
285   //  NS_IMETHOD Eof(nsIMdbEnv* ev, mdb_pos* outPos);
286   // } ----- end pos methods -----
287 
288   // { ----- begin read methods -----
289   NS_IMETHOD Read(nsIMdbEnv* ev, void* outBuf, mdb_size inSize,
290                   mdb_size* outActualSize) override;
291 
292   // { ----- begin write methods -----
293   NS_IMETHOD Write(nsIMdbEnv* ev, const void* inBuf, mdb_size inSize,
294                    mdb_size* outActualSize) override;
295   //  NS_IMETHOD  Put(nsIMdbEnv* ev, const void* inBuf, mdb_size inSize,
296   //    mdb_pos inPos, mdb_size* outActualSize);
297   NS_IMETHOD Flush(nsIMdbEnv* ev) override;
298   // } ----- end attribute methods -----
299 
300   NS_IMETHOD Steal(nsIMdbEnv* ev, nsIMdbFile* ioThief) override;
301 
302   // { ----- begin versioning methods -----
303   NS_IMETHOD BecomeTrunk(nsIMdbEnv* ev) override;
304 
305   NS_IMETHOD AcquireBud(nsIMdbEnv* ev, nsIMdbHeap* ioHeap,
306                         nsIMdbFile** acqBud) override;
307   // } ----- end versioning methods -----
308 
309   // } ===== end nsIMdbFile methods =====
310 
311   // ````` ````` ````` `````   ````` ````` ````` `````
312 
313   // ````` ````` ````` `````   ````` ````` ````` `````
314  protected:  // protected non-poly morkStdioFile methods
315   void new_stdio_file_fault(morkEnv* ev) const;
316 
317   // ````` ````` ````` `````   ````` ````` ````` `````
318  public:  // public non-poly morkStdioFile methods
319   morkStdioFile(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap,
320                 nsIMdbHeap* ioSlotHeap, const PathChar* inName,
321                 const char* inMode);
322   // calls OpenStdio() after construction
323 
324   morkStdioFile(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap,
325                 nsIMdbHeap* ioSlotHeap, void* ioFile, const PathChar* inName,
326                 mork_bool inFrozen);
327   // calls UseStdio() after construction
328 
329   void OpenStdio(morkEnv* ev, const PathChar* inName, const char* inMode);
330   // Open a new FILE with name inName, using mode flags from inMode.
331 
332   void UseStdio(morkEnv* ev, void* ioFile, const PathChar* inName,
333                 mork_bool inFrozen);
334   // Use an existing file, like stdin/stdout/stderr, which should not
335   // have the io stream closed when the file is closed.  The ioFile
336   // parameter must actually be of type FILE (but we don't want to make
337   // this header file include the stdio.h header file).
338 
339   void CloseStdio(morkEnv* ev);
340   // Close the stream io if both and FileActive() and FileIoOpen(), but
341   // this does not close this instances (like CloseStdioFile() does).
342   // If stream io was made active by means of calling UseStdio(),
343   // then this method does little beyond marking the stream inactive
344   // because FileIoOpen() is false.
345 
346  public:  // typesafe refcounting inlines calling inherited morkNode methods
SlotWeakStdioFile(morkStdioFile * me,morkEnv * ev,morkStdioFile ** ioSlot)347   static void SlotWeakStdioFile(morkStdioFile* me, morkEnv* ev,
348                                 morkStdioFile** ioSlot) {
349     morkNode::SlotWeakNode((morkNode*)me, ev, (morkNode**)ioSlot);
350   }
351 
SlotStrongStdioFile(morkStdioFile * me,morkEnv * ev,morkStdioFile ** ioSlot)352   static void SlotStrongStdioFile(morkStdioFile* me, morkEnv* ev,
353                                   morkStdioFile** ioSlot) {
354     morkNode::SlotStrongNode((morkNode*)me, ev, (morkNode**)ioSlot);
355   }
356 };
357 
358 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
359 
360 #endif /* _MORKFILE_ */
361