1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-  */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #ifndef _MDB_
7 #  include "mdb.h"
8 #endif
9 
10 #ifndef _MORK_
11 #  include "mork.h"
12 #endif
13 
14 #ifndef _MORKNODE_
15 #  include "morkNode.h"
16 #endif
17 
18 #ifndef _MORKCH_
19 #  include "morkCh.h"
20 #endif
21 
22 #ifndef _MORKENV_
23 #  include "morkEnv.h"
24 #endif
25 
26 #ifndef _MORKFACTORY_
27 #  include "morkFactory.h"
28 #endif
29 
30 #include "mozilla/Char16.h"
31 
32 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
33 
34 // ````` ````` ````` ````` `````
35 // { ===== begin morkNode interface =====
36 
CloseMorkNode(morkEnv * ev)37 /*public virtual*/ void morkEnv::CloseMorkNode(
38     morkEnv* ev) /*i*/  // CloseEnv() only if open
39 {
40   if (this->IsOpenNode()) {
41     this->MarkClosing();
42     this->CloseEnv(ev);
43     this->MarkShut();
44   }
45 }
46 
47 /*public virtual*/
~morkEnv()48 morkEnv::~morkEnv() /*i*/  // assert CloseEnv() executed earlier
49 {
50   CloseMorkNode(mMorkEnv);
51   if (mEnv_Heap) {
52     mork_bool ownsHeap = mEnv_OwnsHeap;
53     nsIMdbHeap* saveHeap = mEnv_Heap;
54 
55     if (ownsHeap) {
56 #ifdef MORK_DEBUG_HEAP_STATS
57       printf("%d blocks remaining \n",
58              ((orkinHeap*)saveHeap)->HeapBlockCount());
59       mork_u4* array = (mork_u4*)this;
60       array -= 3;
61       // null out heap ptr in mem block so we won't crash trying to use it to
62       // delete the env.
63       *array = nullptr;
64 #endif  // MORK_DEBUG_HEAP_STATS
65       // whoops, this is our heap - hmm. Can't delete it, or not allocate env's
66       // from an orkinHeap.
67       delete saveHeap;
68     }
69   }
70   //  MORK_ASSERT(mEnv_SelfAsMdbEnv==0);
71   MORK_ASSERT(mEnv_ErrorHook == 0);
72 }
73 
74 /* choose morkBool_kTrue or morkBool_kFalse for kBeVerbose: */
75 #define morkEnv_kBeVerbose morkBool_kFalse
76 
77 /*public non-poly*/
morkEnv(const morkUsage & inUsage,nsIMdbHeap * ioHeap,morkFactory * ioFactory,nsIMdbHeap * ioSlotHeap)78 morkEnv::morkEnv(const morkUsage& inUsage, nsIMdbHeap* ioHeap,
79                  morkFactory* ioFactory, nsIMdbHeap* ioSlotHeap)
80     : morkObject(inUsage, ioHeap, morkColor_kNone),
81       mEnv_Factory(ioFactory),
82       mEnv_Heap(ioSlotHeap)
83 
84       ,
85       mEnv_SelfAsMdbEnv(0),
86       mEnv_ErrorHook(0),
87       mEnv_HandlePool(0)
88 
89       ,
90       mEnv_ErrorCount(0),
91       mEnv_WarningCount(0)
92 
93       ,
94       mEnv_ErrorCode(NS_OK)
95 
96       ,
97       mEnv_DoTrace(morkBool_kFalse),
98       mEnv_AutoClear(morkAble_kDisabled),
99       mEnv_ShouldAbort(morkBool_kFalse),
100       mEnv_BeVerbose(morkEnv_kBeVerbose),
101       mEnv_OwnsHeap(morkBool_kFalse) {
102   MORK_ASSERT(ioSlotHeap && ioFactory);
103   if (ioSlotHeap) {
104     // mEnv_Heap is NOT refcounted:
105     // nsIMdbHeap_SlotStrongHeap(ioSlotHeap, this, &mEnv_Heap);
106 
107     mEnv_HandlePool =
108         new morkPool(morkUsage::kGlobal, (nsIMdbHeap*)0, ioSlotHeap);
109 
110     MORK_ASSERT(mEnv_HandlePool);
111     if (mEnv_HandlePool && this->Good()) {
112       mNode_Derived = morkDerived_kEnv;
113       mNode_Refs += morkEnv_kWeakRefCountEnvBonus;
114     }
115   }
116 }
117 
118 /*public non-poly*/
morkEnv(morkEnv * ev,const morkUsage & inUsage,nsIMdbHeap * ioHeap,nsIMdbEnv * inSelfAsMdbEnv,morkFactory * ioFactory,nsIMdbHeap * ioSlotHeap)119 morkEnv::morkEnv(morkEnv* ev, /*i*/
120                  const morkUsage& inUsage, nsIMdbHeap* ioHeap,
121                  nsIMdbEnv* inSelfAsMdbEnv, morkFactory* ioFactory,
122                  nsIMdbHeap* ioSlotHeap)
123     : morkObject(ev, inUsage, ioHeap, morkColor_kNone, (morkHandle*)0),
124       mEnv_Factory(ioFactory),
125       mEnv_Heap(ioSlotHeap)
126 
127       ,
128       mEnv_SelfAsMdbEnv(inSelfAsMdbEnv),
129       mEnv_ErrorHook(0),
130       mEnv_HandlePool(0)
131 
132       ,
133       mEnv_ErrorCount(0),
134       mEnv_WarningCount(0)
135 
136       ,
137       mEnv_ErrorCode(NS_OK)
138 
139       ,
140       mEnv_DoTrace(morkBool_kFalse),
141       mEnv_AutoClear(morkAble_kDisabled),
142       mEnv_ShouldAbort(morkBool_kFalse),
143       mEnv_BeVerbose(morkEnv_kBeVerbose),
144       mEnv_OwnsHeap(morkBool_kFalse) {
145   // $$$ do we need to refcount the inSelfAsMdbEnv nsIMdbEnv??
146 
147   if (ioFactory && inSelfAsMdbEnv && ioSlotHeap) {
148     // mEnv_Heap is NOT refcounted:
149     // nsIMdbHeap_SlotStrongHeap(ioSlotHeap, ev, &mEnv_Heap);
150 
151     mEnv_HandlePool = new (*ioSlotHeap, ev)
152         morkPool(ev, morkUsage::kHeap, ioSlotHeap, ioSlotHeap);
153 
154     MORK_ASSERT(mEnv_HandlePool);
155     if (mEnv_HandlePool && ev->Good()) {
156       mNode_Derived = morkDerived_kEnv;
157       mNode_Refs += morkEnv_kWeakRefCountEnvBonus;
158     }
159   } else
160     ev->NilPointerError();
161 }
162 
NS_IMPL_ISUPPORTS_INHERITED(morkEnv,morkObject,nsIMdbEnv)163 NS_IMPL_ISUPPORTS_INHERITED(morkEnv, morkObject, nsIMdbEnv)
164 /*public non-poly*/ void morkEnv::CloseEnv(
165     morkEnv* ev) /*i*/  // called by CloseMorkNode();
166 {
167   if (this->IsNode()) {
168     // $$$ release mEnv_SelfAsMdbEnv??
169     // $$$ release mEnv_ErrorHook??
170 
171     mEnv_SelfAsMdbEnv = 0;
172     mEnv_ErrorHook = 0;
173 
174     morkPool* savePool = mEnv_HandlePool;
175     morkPool::SlotStrongPool((morkPool*)0, ev, &mEnv_HandlePool);
176     // free the pool
177     if (mEnv_SelfAsMdbEnv) {
178       if (savePool && mEnv_Heap) mEnv_Heap->Free(this->AsMdbEnv(), savePool);
179     } else {
180       if (savePool) {
181         if (savePool->IsOpenNode()) savePool->CloseMorkNode(ev);
182         delete savePool;
183       }
184       // how do we free this? might need to get rid of asserts.
185     }
186     // mEnv_Factory is NOT refcounted
187 
188     this->MarkShut();
189   } else
190     this->NonNodeError(ev);
191 }
192 
193 // } ===== end morkNode methods =====
194 // ````` ````` ````` ````` `````
195 
OidAsHex(void * outBuf,const mdbOid & inOid)196 mork_size morkEnv::OidAsHex(void* outBuf, const mdbOid& inOid)
197 // sprintf(buf, "%lX:^%lX", (long) inOid.mOid_Id, (long) inOid.mOid_Scope);
198 {
199   mork_u1* p = (mork_u1*)outBuf;
200   mork_size outSize = this->TokenAsHex(p, inOid.mOid_Id);
201   p += outSize;
202   *p++ = ':';
203 
204   mork_scope scope = inOid.mOid_Scope;
205   if (scope < 0x80 && morkCh_IsName((mork_ch)scope)) {
206     *p++ = (mork_u1)scope;
207     *p = 0;  // null termination
208     outSize += 2;
209   } else {
210     *p++ = '^';
211     mork_size scopeSize = this->TokenAsHex(p, scope);
212     outSize += scopeSize + 2;
213   }
214   return outSize;
215 }
216 
HexToByte(mork_ch inFirstHex,mork_ch inSecondHex)217 mork_u1 morkEnv::HexToByte(mork_ch inFirstHex, mork_ch inSecondHex) {
218   mork_u1 hi = 0;  // high four hex bits
219   mork_flags f = morkCh_GetFlags(inFirstHex);
220   if (morkFlags_IsDigit(f))
221     hi = (mork_u1)(inFirstHex - (mork_ch)'0');
222   else if (morkFlags_IsUpper(f))
223     hi = (mork_u1)((inFirstHex - (mork_ch)'A') + 10);
224   else if (morkFlags_IsLower(f))
225     hi = (mork_u1)((inFirstHex - (mork_ch)'a') + 10);
226 
227   mork_u1 lo = 0;  // low four hex bits
228   f = morkCh_GetFlags(inSecondHex);
229   if (morkFlags_IsDigit(f))
230     lo = (mork_u1)(inSecondHex - (mork_ch)'0');
231   else if (morkFlags_IsUpper(f))
232     lo = (mork_u1)((inSecondHex - (mork_ch)'A') + 10);
233   else if (morkFlags_IsLower(f))
234     lo = (mork_u1)((inSecondHex - (mork_ch)'a') + 10);
235 
236   return (mork_u1)((hi << 4) | lo);
237 }
238 
TokenAsHex(void * outBuf,mork_token inToken)239 mork_size morkEnv::TokenAsHex(void* outBuf, mork_token inToken)
240 // TokenAsHex() is the same as sprintf(outBuf, "%lX", (long) inToken);
241 {
242   static const char morkEnv_kHexDigits[] = "0123456789ABCDEF";
243   char* p = (char*)outBuf;
244   char* end = p + 32;  // write no more than 32 digits for safety
245   if (inToken) {
246     // first write all the hex digits in backwards order:
247     while (p < end && inToken)  // more digits to write?
248     {
249       *p++ = morkEnv_kHexDigits[inToken & 0x0F];  // low four bits
250       inToken >>= 4;  // we fervently hope this does not sign extend
251     }
252     *p = 0;                               // end the string with a null byte
253     char* s = (char*)outBuf;              // first byte in string
254     mork_size size = (mork_size)(p - s);  // distance from start
255 
256     // now reverse the string in place:
257     // note that p starts on the null byte, so we need predecrement:
258     while (--p > s)  // need to swap another byte in the string?
259     {
260       char c = *p;  // temp for swap
261       *p = *s;
262       *s++ = c;  // move s forward here, and p backward in the test
263     }
264     return size;
265   } else  // special case for zero integer
266   {
267     *p++ = '0';  // write a zero digit
268     *p = 0;      // end with a null byte
269     return 1;    // one digit in hex representation
270   }
271 }
272 
StringToYarn(const PathChar * inString,mdbYarn * outYarn)273 void morkEnv::StringToYarn(const PathChar* inString, mdbYarn* outYarn) {
274   if (outYarn) {
275     mdb_fill fill =
276         (inString) ? (mdb_fill)MORK_STRLEN(inString) * sizeof(PathChar) : 0;
277 
278     if (fill)  // have nonempty content?
279     {
280       mdb_size size = outYarn->mYarn_Size;  // max dest size
281       if (fill > size)                      // too much string content?
282       {
283         outYarn->mYarn_More = fill - size;  // extra string bytes omitted
284         fill = size;  // copy no more bytes than size of yarn buffer
285       }
286       void* dest = outYarn->mYarn_Buf;  // where bytes are going
287       if (!dest)                        // nil destination address buffer?
288         fill = 0;                       // we can't write any content at all
289 
290       if (fill)                             // anything to copy?
291         MORK_MEMCPY(dest, inString, fill);  // copy fill bytes to yarn
292 
293       outYarn->mYarn_Fill = fill;  // tell yarn size of copied content
294     } else                         // no content to put into the yarn
295     {
296       outYarn->mYarn_Fill = 0;  // tell yarn that string has no bytes
297     }
298     outYarn->mYarn_Form = 0;  // always update the form slot
299   } else
300     this->NilPointerError();
301 }
302 
CopyString(nsIMdbHeap * ioHeap,const PathChar * inString)303 morkEnv::PathChar* morkEnv::CopyString(nsIMdbHeap* ioHeap,
304                                        const PathChar* inString) {
305   PathChar* outString = nullptr;
306   if (ioHeap && inString) {
307     mork_size size = (MORK_STRLEN(inString) + 1) * sizeof(PathChar);
308     ioHeap->Alloc(this->AsMdbEnv(), size, (void**)&outString);
309     if (outString) MORK_STRCPY(outString, inString);
310   } else
311     this->NilPointerError();
312   return outString;
313 }
314 
FreeString(nsIMdbHeap * ioHeap,PathChar * ioString)315 void morkEnv::FreeString(nsIMdbHeap* ioHeap, PathChar* ioString) {
316   if (ioHeap) {
317     if (ioString) ioHeap->Free(this->AsMdbEnv(), ioString);
318   } else
319     this->NilPointerError();
320 }
321 
NewError(const char * inString)322 void morkEnv::NewError(const char* inString) {
323   MORK_ASSERT(morkBool_kFalse);  // get developer's attention
324 
325   ++mEnv_ErrorCount;
326   mEnv_ErrorCode = NS_ERROR_FAILURE;
327 
328   if (mEnv_ErrorHook) mEnv_ErrorHook->OnErrorString(this->AsMdbEnv(), inString);
329 }
330 
NewWarning(const char * inString)331 void morkEnv::NewWarning(const char* inString) {
332   MORK_ASSERT(morkBool_kFalse);  // get developer's attention
333 
334   ++mEnv_WarningCount;
335   if (mEnv_ErrorHook)
336     mEnv_ErrorHook->OnWarningString(this->AsMdbEnv(), inString);
337 }
338 
StubMethodOnlyError()339 void morkEnv::StubMethodOnlyError() { this->NewError("method is stub only"); }
340 
OutOfMemoryError()341 void morkEnv::OutOfMemoryError() { this->NewError("out of memory"); }
342 
CantMakeWhenBadError()343 void morkEnv::CantMakeWhenBadError() {
344   this->NewError("can't make an object when ev->Bad()");
345 }
346 
347 static const char morkEnv_kNilPointer[] = "nil pointer";
348 
NilPointerError()349 void morkEnv::NilPointerError() { this->NewError(morkEnv_kNilPointer); }
350 
NilPointerWarning()351 void morkEnv::NilPointerWarning() { this->NewWarning(morkEnv_kNilPointer); }
352 
NewNonEnvError()353 void morkEnv::NewNonEnvError() { this->NewError("non-env instance"); }
354 
NilEnvSlotError()355 void morkEnv::NilEnvSlotError() {
356   if (!mEnv_HandlePool || !mEnv_Factory) {
357     if (!mEnv_HandlePool) this->NewError("nil mEnv_HandlePool");
358     if (!mEnv_Factory) this->NewError("nil mEnv_Factory");
359   } else
360     this->NewError("unknown nil env slot");
361 }
362 
NonEnvTypeError(morkEnv * ev)363 void morkEnv::NonEnvTypeError(morkEnv* ev) { ev->NewError("non morkEnv"); }
364 
ClearMorkErrorsAndWarnings()365 void morkEnv::ClearMorkErrorsAndWarnings() {
366   mEnv_ErrorCount = 0;
367   mEnv_WarningCount = 0;
368   mEnv_ErrorCode = NS_OK;
369   mEnv_ShouldAbort = morkBool_kFalse;
370 }
371 
AutoClearMorkErrorsAndWarnings()372 void morkEnv::AutoClearMorkErrorsAndWarnings() {
373   if (this->DoAutoClear()) {
374     mEnv_ErrorCount = 0;
375     mEnv_WarningCount = 0;
376     mEnv_ErrorCode = NS_OK;
377     mEnv_ShouldAbort = morkBool_kFalse;
378   }
379 }
380 
FromMdbEnv(nsIMdbEnv * ioEnv)381 /*static*/ morkEnv* morkEnv::FromMdbEnv(
382     nsIMdbEnv* ioEnv)  // dynamic type checking
383 {
384   morkEnv* outEnv = 0;
385   if (ioEnv) {
386     // Note this cast is expected to perform some address adjustment of the
387     // pointer, so oenv likely does not equal ioEnv.  Do not cast to void*
388     // first to force an exactly equal pointer (we tried it and it's wrong).
389     morkEnv* ev = (morkEnv*)ioEnv;
390     if (ev && ev->IsEnv()) {
391       if (ev->DoAutoClear()) {
392         ev->mEnv_ErrorCount = 0;
393         ev->mEnv_WarningCount = 0;
394         ev->mEnv_ErrorCode = NS_OK;
395       }
396       outEnv = ev;
397     } else
398       MORK_ASSERT(outEnv);
399   } else
400     MORK_ASSERT(outEnv);
401   return outEnv;
402 }
403 
404 NS_IMETHODIMP
GetErrorCount(mdb_count * outCount,mdb_bool * outShouldAbort)405 morkEnv::GetErrorCount(mdb_count* outCount, mdb_bool* outShouldAbort) {
406   if (outCount) *outCount = mEnv_ErrorCount;
407   if (outShouldAbort) *outShouldAbort = mEnv_ShouldAbort;
408   return NS_OK;
409 }
410 
411 NS_IMETHODIMP
GetWarningCount(mdb_count * outCount,mdb_bool * outShouldAbort)412 morkEnv::GetWarningCount(mdb_count* outCount, mdb_bool* outShouldAbort) {
413   if (outCount) *outCount = mEnv_WarningCount;
414   if (outShouldAbort) *outShouldAbort = mEnv_ShouldAbort;
415   return NS_OK;
416 }
417 
418 NS_IMETHODIMP
GetEnvBeVerbose(mdb_bool * outBeVerbose)419 morkEnv::GetEnvBeVerbose(mdb_bool* outBeVerbose) {
420   NS_ENSURE_ARG_POINTER(outBeVerbose);
421   *outBeVerbose = mEnv_BeVerbose;
422   return NS_OK;
423 }
424 
425 NS_IMETHODIMP
SetEnvBeVerbose(mdb_bool inBeVerbose)426 morkEnv::SetEnvBeVerbose(mdb_bool inBeVerbose) {
427   mEnv_BeVerbose = inBeVerbose;
428   return NS_OK;
429 }
430 
431 NS_IMETHODIMP
GetDoTrace(mdb_bool * outDoTrace)432 morkEnv::GetDoTrace(mdb_bool* outDoTrace) {
433   NS_ENSURE_ARG_POINTER(outDoTrace);
434   *outDoTrace = mEnv_DoTrace;
435   return NS_OK;
436 }
437 
438 NS_IMETHODIMP
SetDoTrace(mdb_bool inDoTrace)439 morkEnv::SetDoTrace(mdb_bool inDoTrace) {
440   mEnv_DoTrace = inDoTrace;
441   return NS_OK;
442 }
443 
444 NS_IMETHODIMP
GetAutoClear(mdb_bool * outAutoClear)445 morkEnv::GetAutoClear(mdb_bool* outAutoClear) {
446   NS_ENSURE_ARG_POINTER(outAutoClear);
447   *outAutoClear = DoAutoClear();
448   return NS_OK;
449 }
450 
451 NS_IMETHODIMP
SetAutoClear(mdb_bool inAutoClear)452 morkEnv::SetAutoClear(mdb_bool inAutoClear) {
453   if (inAutoClear)
454     EnableAutoClear();
455   else
456     DisableAutoClear();
457   return NS_OK;
458 }
459 
460 NS_IMETHODIMP
GetErrorHook(nsIMdbErrorHook ** acqErrorHook)461 morkEnv::GetErrorHook(nsIMdbErrorHook** acqErrorHook) {
462   NS_ENSURE_ARG_POINTER(acqErrorHook);
463   *acqErrorHook = mEnv_ErrorHook;
464   NS_IF_ADDREF(mEnv_ErrorHook);
465   return NS_OK;
466 }
467 
468 NS_IMETHODIMP
SetErrorHook(nsIMdbErrorHook * ioErrorHook)469 morkEnv::SetErrorHook(nsIMdbErrorHook* ioErrorHook)  // becomes referenced
470 {
471   mEnv_ErrorHook = ioErrorHook;
472   return NS_OK;
473 }
474 
475 NS_IMETHODIMP
GetHeap(nsIMdbHeap ** acqHeap)476 morkEnv::GetHeap(nsIMdbHeap** acqHeap) {
477   NS_ENSURE_ARG_POINTER(acqHeap);
478   nsIMdbHeap* outHeap = mEnv_Heap;
479 
480   if (acqHeap) *acqHeap = outHeap;
481   return NS_OK;
482 }
483 
484 NS_IMETHODIMP
SetHeap(nsIMdbHeap * ioHeap)485 morkEnv::SetHeap(nsIMdbHeap* ioHeap)  // becomes referenced
486 {
487   nsIMdbHeap_SlotStrongHeap(ioHeap, this, &mEnv_Heap);
488   return NS_OK;
489 }
490 // } ----- end attribute methods -----
491 
492 NS_IMETHODIMP
ClearErrors()493 morkEnv::ClearErrors()  // clear errors beore re-entering db API
494 {
495   mEnv_ErrorCount = 0;
496   mEnv_ErrorCode = NS_OK;
497   mEnv_ShouldAbort = morkBool_kFalse;
498 
499   return NS_OK;
500 }
501 
502 NS_IMETHODIMP
ClearWarnings()503 morkEnv::ClearWarnings()  // clear warning
504 {
505   mEnv_WarningCount = 0;
506   return NS_OK;
507 }
508 
509 NS_IMETHODIMP
ClearErrorsAndWarnings()510 morkEnv::ClearErrorsAndWarnings()  // clear both errors & warnings
511 {
512   ClearMorkErrorsAndWarnings();
513   return NS_OK;
514 }
515 // } ===== end nsIMdbEnv methods =====
516 
517 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
518