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