/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef _MDB_ # include "mdb.h" #endif #ifndef _MORK_ # include "mork.h" #endif #ifndef _MORKNODE_ # include "morkNode.h" #endif #ifndef _MORKCH_ # include "morkCh.h" #endif #ifndef _MORKENV_ # include "morkEnv.h" #endif #ifndef _MORKFACTORY_ # include "morkFactory.h" #endif #include "mozilla/Char16.h" // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 // ````` ````` ````` ````` ````` // { ===== begin morkNode interface ===== /*public virtual*/ void morkEnv::CloseMorkNode( morkEnv* ev) /*i*/ // CloseEnv() only if open { if (this->IsOpenNode()) { this->MarkClosing(); this->CloseEnv(ev); this->MarkShut(); } } /*public virtual*/ morkEnv::~morkEnv() /*i*/ // assert CloseEnv() executed earlier { CloseMorkNode(mMorkEnv); if (mEnv_Heap) { mork_bool ownsHeap = mEnv_OwnsHeap; nsIMdbHeap* saveHeap = mEnv_Heap; if (ownsHeap) { #ifdef MORK_DEBUG_HEAP_STATS printf("%d blocks remaining \n", ((orkinHeap*)saveHeap)->HeapBlockCount()); mork_u4* array = (mork_u4*)this; array -= 3; // null out heap ptr in mem block so we won't crash trying to use it to // delete the env. *array = nullptr; #endif // MORK_DEBUG_HEAP_STATS // whoops, this is our heap - hmm. Can't delete it, or not allocate env's // from an orkinHeap. delete saveHeap; } } // MORK_ASSERT(mEnv_SelfAsMdbEnv==0); MORK_ASSERT(mEnv_ErrorHook == 0); } /* choose morkBool_kTrue or morkBool_kFalse for kBeVerbose: */ #define morkEnv_kBeVerbose morkBool_kFalse /*public non-poly*/ morkEnv::morkEnv(const morkUsage& inUsage, nsIMdbHeap* ioHeap, morkFactory* ioFactory, nsIMdbHeap* ioSlotHeap) : morkObject(inUsage, ioHeap, morkColor_kNone), mEnv_Factory(ioFactory), mEnv_Heap(ioSlotHeap) , mEnv_SelfAsMdbEnv(0), mEnv_ErrorHook(0), mEnv_HandlePool(0) , mEnv_ErrorCount(0), mEnv_WarningCount(0) , mEnv_ErrorCode(NS_OK) , mEnv_DoTrace(morkBool_kFalse), mEnv_AutoClear(morkAble_kDisabled), mEnv_ShouldAbort(morkBool_kFalse), mEnv_BeVerbose(morkEnv_kBeVerbose), mEnv_OwnsHeap(morkBool_kFalse) { MORK_ASSERT(ioSlotHeap && ioFactory); if (ioSlotHeap) { // mEnv_Heap is NOT refcounted: // nsIMdbHeap_SlotStrongHeap(ioSlotHeap, this, &mEnv_Heap); mEnv_HandlePool = new morkPool(morkUsage::kGlobal, (nsIMdbHeap*)0, ioSlotHeap); MORK_ASSERT(mEnv_HandlePool); if (mEnv_HandlePool && this->Good()) { mNode_Derived = morkDerived_kEnv; mNode_Refs += morkEnv_kWeakRefCountEnvBonus; } } } /*public non-poly*/ morkEnv::morkEnv(morkEnv* ev, /*i*/ const morkUsage& inUsage, nsIMdbHeap* ioHeap, nsIMdbEnv* inSelfAsMdbEnv, morkFactory* ioFactory, nsIMdbHeap* ioSlotHeap) : morkObject(ev, inUsage, ioHeap, morkColor_kNone, (morkHandle*)0), mEnv_Factory(ioFactory), mEnv_Heap(ioSlotHeap) , mEnv_SelfAsMdbEnv(inSelfAsMdbEnv), mEnv_ErrorHook(0), mEnv_HandlePool(0) , mEnv_ErrorCount(0), mEnv_WarningCount(0) , mEnv_ErrorCode(NS_OK) , mEnv_DoTrace(morkBool_kFalse), mEnv_AutoClear(morkAble_kDisabled), mEnv_ShouldAbort(morkBool_kFalse), mEnv_BeVerbose(morkEnv_kBeVerbose), mEnv_OwnsHeap(morkBool_kFalse) { // $$$ do we need to refcount the inSelfAsMdbEnv nsIMdbEnv?? if (ioFactory && inSelfAsMdbEnv && ioSlotHeap) { // mEnv_Heap is NOT refcounted: // nsIMdbHeap_SlotStrongHeap(ioSlotHeap, ev, &mEnv_Heap); mEnv_HandlePool = new (*ioSlotHeap, ev) morkPool(ev, morkUsage::kHeap, ioSlotHeap, ioSlotHeap); MORK_ASSERT(mEnv_HandlePool); if (mEnv_HandlePool && ev->Good()) { mNode_Derived = morkDerived_kEnv; mNode_Refs += morkEnv_kWeakRefCountEnvBonus; } } else ev->NilPointerError(); } NS_IMPL_ISUPPORTS_INHERITED(morkEnv, morkObject, nsIMdbEnv) /*public non-poly*/ void morkEnv::CloseEnv( morkEnv* ev) /*i*/ // called by CloseMorkNode(); { if (this->IsNode()) { // $$$ release mEnv_SelfAsMdbEnv?? // $$$ release mEnv_ErrorHook?? mEnv_SelfAsMdbEnv = 0; mEnv_ErrorHook = 0; morkPool* savePool = mEnv_HandlePool; morkPool::SlotStrongPool((morkPool*)0, ev, &mEnv_HandlePool); // free the pool if (mEnv_SelfAsMdbEnv) { if (savePool && mEnv_Heap) mEnv_Heap->Free(this->AsMdbEnv(), savePool); } else { if (savePool) { if (savePool->IsOpenNode()) savePool->CloseMorkNode(ev); delete savePool; } // how do we free this? might need to get rid of asserts. } // mEnv_Factory is NOT refcounted this->MarkShut(); } else this->NonNodeError(ev); } // } ===== end morkNode methods ===== // ````` ````` ````` ````` ````` mork_size morkEnv::OidAsHex(void* outBuf, const mdbOid& inOid) // sprintf(buf, "%lX:^%lX", (long) inOid.mOid_Id, (long) inOid.mOid_Scope); { mork_u1* p = (mork_u1*)outBuf; mork_size outSize = this->TokenAsHex(p, inOid.mOid_Id); p += outSize; *p++ = ':'; mork_scope scope = inOid.mOid_Scope; if (scope < 0x80 && morkCh_IsName((mork_ch)scope)) { *p++ = (mork_u1)scope; *p = 0; // null termination outSize += 2; } else { *p++ = '^'; mork_size scopeSize = this->TokenAsHex(p, scope); outSize += scopeSize + 2; } return outSize; } mork_u1 morkEnv::HexToByte(mork_ch inFirstHex, mork_ch inSecondHex) { mork_u1 hi = 0; // high four hex bits mork_flags f = morkCh_GetFlags(inFirstHex); if (morkFlags_IsDigit(f)) hi = (mork_u1)(inFirstHex - (mork_ch)'0'); else if (morkFlags_IsUpper(f)) hi = (mork_u1)((inFirstHex - (mork_ch)'A') + 10); else if (morkFlags_IsLower(f)) hi = (mork_u1)((inFirstHex - (mork_ch)'a') + 10); mork_u1 lo = 0; // low four hex bits f = morkCh_GetFlags(inSecondHex); if (morkFlags_IsDigit(f)) lo = (mork_u1)(inSecondHex - (mork_ch)'0'); else if (morkFlags_IsUpper(f)) lo = (mork_u1)((inSecondHex - (mork_ch)'A') + 10); else if (morkFlags_IsLower(f)) lo = (mork_u1)((inSecondHex - (mork_ch)'a') + 10); return (mork_u1)((hi << 4) | lo); } // TokenAsHex() is the same as sprintf(outBuf, "%lX", (long) inToken); // Writes up to 32 hex digits, plus a NUL-terminator. So outBuf must // be at least 33 bytes. // Return value is number of characters written, excluding the NUL. mork_size morkEnv::TokenAsHex(void* outBuf, mork_token inToken) { static const char morkEnv_kHexDigits[] = "0123456789ABCDEF"; char* p = (char*)outBuf; char* end = p + 32; // write no more than 32 digits for safety if (inToken) { // first write all the hex digits in backwards order: while (p < end && inToken) // more digits to write? { *p++ = morkEnv_kHexDigits[inToken & 0x0F]; // low four bits inToken >>= 4; // we fervently hope this does not sign extend } *p = 0; // end the string with a null byte char* s = (char*)outBuf; // first byte in string mork_size size = (mork_size)(p - s); // distance from start // now reverse the string in place: // note that p starts on the null byte, so we need predecrement: while (--p > s) // need to swap another byte in the string? { char c = *p; // temp for swap *p = *s; *s++ = c; // move s forward here, and p backward in the test } return size; } else // special case for zero integer { *p++ = '0'; // write a zero digit *p = 0; // end with a null byte return 1; // one digit in hex representation } } void morkEnv::StringToYarn(const PathChar* inString, mdbYarn* outYarn) { if (outYarn) { mdb_fill fill = (inString) ? (mdb_fill)MORK_STRLEN(inString) * sizeof(PathChar) : 0; if (fill) // have nonempty content? { mdb_size size = outYarn->mYarn_Size; // max dest size if (fill > size) // too much string content? { outYarn->mYarn_More = fill - size; // extra string bytes omitted fill = size; // copy no more bytes than size of yarn buffer } void* dest = outYarn->mYarn_Buf; // where bytes are going if (!dest) // nil destination address buffer? fill = 0; // we can't write any content at all if (fill) // anything to copy? MORK_MEMCPY(dest, inString, fill); // copy fill bytes to yarn outYarn->mYarn_Fill = fill; // tell yarn size of copied content } else // no content to put into the yarn { outYarn->mYarn_Fill = 0; // tell yarn that string has no bytes } outYarn->mYarn_Form = 0; // always update the form slot } else this->NilPointerError(); } morkEnv::PathChar* morkEnv::CopyString(nsIMdbHeap* ioHeap, const PathChar* inString) { PathChar* outString = nullptr; if (ioHeap && inString) { mork_size size = (MORK_STRLEN(inString) + 1) * sizeof(PathChar); ioHeap->Alloc(this->AsMdbEnv(), size, (void**)&outString); if (outString) MORK_STRCPY(outString, inString); } else this->NilPointerError(); return outString; } void morkEnv::FreeString(nsIMdbHeap* ioHeap, PathChar* ioString) { if (ioHeap) { if (ioString) ioHeap->Free(this->AsMdbEnv(), ioString); } else this->NilPointerError(); } void morkEnv::NewError(const char* inString) { MORK_ASSERT(morkBool_kFalse); // get developer's attention ++mEnv_ErrorCount; mEnv_ErrorCode = NS_ERROR_FAILURE; if (mEnv_ErrorHook) mEnv_ErrorHook->OnErrorString(this->AsMdbEnv(), inString); } void morkEnv::NewWarning(const char* inString) { MORK_ASSERT(morkBool_kFalse); // get developer's attention ++mEnv_WarningCount; if (mEnv_ErrorHook) mEnv_ErrorHook->OnWarningString(this->AsMdbEnv(), inString); } void morkEnv::StubMethodOnlyError() { this->NewError("method is stub only"); } void morkEnv::OutOfMemoryError() { this->NewError("out of memory"); } void morkEnv::CantMakeWhenBadError() { this->NewError("can't make an object when ev->Bad()"); } static const char morkEnv_kNilPointer[] = "nil pointer"; void morkEnv::NilPointerError() { this->NewError(morkEnv_kNilPointer); } void morkEnv::NilPointerWarning() { this->NewWarning(morkEnv_kNilPointer); } void morkEnv::NewNonEnvError() { this->NewError("non-env instance"); } void morkEnv::NilEnvSlotError() { if (!mEnv_HandlePool || !mEnv_Factory) { if (!mEnv_HandlePool) this->NewError("nil mEnv_HandlePool"); if (!mEnv_Factory) this->NewError("nil mEnv_Factory"); } else this->NewError("unknown nil env slot"); } void morkEnv::NonEnvTypeError(morkEnv* ev) { ev->NewError("non morkEnv"); } void morkEnv::ClearMorkErrorsAndWarnings() { mEnv_ErrorCount = 0; mEnv_WarningCount = 0; mEnv_ErrorCode = NS_OK; mEnv_ShouldAbort = morkBool_kFalse; } void morkEnv::AutoClearMorkErrorsAndWarnings() { if (this->DoAutoClear()) { mEnv_ErrorCount = 0; mEnv_WarningCount = 0; mEnv_ErrorCode = NS_OK; mEnv_ShouldAbort = morkBool_kFalse; } } /*static*/ morkEnv* morkEnv::FromMdbEnv( nsIMdbEnv* ioEnv) // dynamic type checking { morkEnv* outEnv = 0; if (ioEnv) { // Note this cast is expected to perform some address adjustment of the // pointer, so oenv likely does not equal ioEnv. Do not cast to void* // first to force an exactly equal pointer (we tried it and it's wrong). morkEnv* ev = (morkEnv*)ioEnv; if (ev && ev->IsEnv()) { if (ev->DoAutoClear()) { ev->mEnv_ErrorCount = 0; ev->mEnv_WarningCount = 0; ev->mEnv_ErrorCode = NS_OK; } outEnv = ev; } else MORK_ASSERT(outEnv); } else MORK_ASSERT(outEnv); return outEnv; } NS_IMETHODIMP morkEnv::GetErrorCount(mdb_count* outCount, mdb_bool* outShouldAbort) { if (outCount) *outCount = mEnv_ErrorCount; if (outShouldAbort) *outShouldAbort = mEnv_ShouldAbort; return NS_OK; } NS_IMETHODIMP morkEnv::GetWarningCount(mdb_count* outCount, mdb_bool* outShouldAbort) { if (outCount) *outCount = mEnv_WarningCount; if (outShouldAbort) *outShouldAbort = mEnv_ShouldAbort; return NS_OK; } NS_IMETHODIMP morkEnv::GetEnvBeVerbose(mdb_bool* outBeVerbose) { NS_ENSURE_ARG_POINTER(outBeVerbose); *outBeVerbose = mEnv_BeVerbose; return NS_OK; } NS_IMETHODIMP morkEnv::SetEnvBeVerbose(mdb_bool inBeVerbose) { mEnv_BeVerbose = inBeVerbose; return NS_OK; } NS_IMETHODIMP morkEnv::GetDoTrace(mdb_bool* outDoTrace) { NS_ENSURE_ARG_POINTER(outDoTrace); *outDoTrace = mEnv_DoTrace; return NS_OK; } NS_IMETHODIMP morkEnv::SetDoTrace(mdb_bool inDoTrace) { mEnv_DoTrace = inDoTrace; return NS_OK; } NS_IMETHODIMP morkEnv::GetAutoClear(mdb_bool* outAutoClear) { NS_ENSURE_ARG_POINTER(outAutoClear); *outAutoClear = DoAutoClear(); return NS_OK; } NS_IMETHODIMP morkEnv::SetAutoClear(mdb_bool inAutoClear) { if (inAutoClear) EnableAutoClear(); else DisableAutoClear(); return NS_OK; } NS_IMETHODIMP morkEnv::GetErrorHook(nsIMdbErrorHook** acqErrorHook) { NS_ENSURE_ARG_POINTER(acqErrorHook); *acqErrorHook = mEnv_ErrorHook; NS_IF_ADDREF(mEnv_ErrorHook); return NS_OK; } NS_IMETHODIMP morkEnv::SetErrorHook(nsIMdbErrorHook* ioErrorHook) // becomes referenced { mEnv_ErrorHook = ioErrorHook; return NS_OK; } NS_IMETHODIMP morkEnv::GetHeap(nsIMdbHeap** acqHeap) { NS_ENSURE_ARG_POINTER(acqHeap); nsIMdbHeap* outHeap = mEnv_Heap; if (acqHeap) *acqHeap = outHeap; return NS_OK; } NS_IMETHODIMP morkEnv::SetHeap(nsIMdbHeap* ioHeap) // becomes referenced { nsIMdbHeap_SlotStrongHeap(ioHeap, this, &mEnv_Heap); return NS_OK; } // } ----- end attribute methods ----- NS_IMETHODIMP morkEnv::ClearErrors() // clear errors beore re-entering db API { mEnv_ErrorCount = 0; mEnv_ErrorCode = NS_OK; mEnv_ShouldAbort = morkBool_kFalse; return NS_OK; } NS_IMETHODIMP morkEnv::ClearWarnings() // clear warning { mEnv_WarningCount = 0; return NS_OK; } NS_IMETHODIMP morkEnv::ClearErrorsAndWarnings() // clear both errors & warnings { ClearMorkErrorsAndWarnings(); return NS_OK; } // } ===== end nsIMdbEnv methods ===== // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789