michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. michael@0: * michael@0: * michael@0: * This Original Code has been modified by IBM Corporation. michael@0: * Modifications made by IBM described herein are michael@0: * Copyright (c) International Business Machines michael@0: * Corporation, 2000 michael@0: * michael@0: * Modifications to Mozilla code or documentation michael@0: * identified per MPL Section 3.3 michael@0: * michael@0: * Date Modified by Description of modification michael@0: * 03/27/2000 IBM Corp. Added PR_CALLBACK for Optlink michael@0: * use in OS2 michael@0: */ michael@0: michael@0: /* michael@0: michael@0: This file provides the implementation for the RDF service manager. michael@0: michael@0: TO DO michael@0: ----- michael@0: michael@0: 1) Implement the CreateDataBase() methods. michael@0: michael@0: 2) Cache date and int literals. michael@0: michael@0: */ michael@0: michael@0: #include "nsRDFService.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "nsMemory.h" michael@0: #include "nsIAtom.h" michael@0: #include "nsIComponentManager.h" michael@0: #include "nsIRDFDataSource.h" michael@0: #include "nsIRDFNode.h" michael@0: #include "nsIRDFRemoteDataSource.h" michael@0: #include "nsIServiceManager.h" michael@0: #include "nsIFactory.h" michael@0: #include "nsRDFCID.h" michael@0: #include "nsString.h" michael@0: #include "nsXPIDLString.h" michael@0: #include "nsNetUtil.h" michael@0: #include "pldhash.h" michael@0: #include "plhash.h" michael@0: #include "plstr.h" michael@0: #include "prlog.h" michael@0: #include "prprf.h" michael@0: #include "prmem.h" michael@0: #include "rdf.h" michael@0: #include "nsCRT.h" michael@0: #include "nsCRTGlue.h" michael@0: #include "mozilla/HashFunctions.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: //////////////////////////////////////////////////////////////////////// michael@0: michael@0: static NS_DEFINE_CID(kRDFXMLDataSourceCID, NS_RDFXMLDATASOURCE_CID); michael@0: static NS_DEFINE_CID(kRDFDefaultResourceCID, NS_RDFDEFAULTRESOURCE_CID); michael@0: michael@0: static NS_DEFINE_IID(kIRDFLiteralIID, NS_IRDFLITERAL_IID); michael@0: static NS_DEFINE_IID(kIRDFDateIID, NS_IRDFDATE_IID); michael@0: static NS_DEFINE_IID(kIRDFIntIID, NS_IRDFINT_IID); michael@0: static NS_DEFINE_IID(kIRDFNodeIID, NS_IRDFNODE_IID); michael@0: static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); michael@0: michael@0: #ifdef PR_LOGGING michael@0: static PRLogModuleInfo* gLog = nullptr; michael@0: #endif michael@0: michael@0: class BlobImpl; michael@0: michael@0: // These functions are copied from nsprpub/lib/ds/plhash.c, with one michael@0: // change to free the key in DataSourceFreeEntry. michael@0: // XXX sigh, why were DefaultAllocTable et. al. declared static, anyway? michael@0: michael@0: static void * michael@0: DataSourceAllocTable(void *pool, size_t size) michael@0: { michael@0: return PR_MALLOC(size); michael@0: } michael@0: michael@0: static void michael@0: DataSourceFreeTable(void *pool, void *item) michael@0: { michael@0: PR_Free(item); michael@0: } michael@0: michael@0: static PLHashEntry * michael@0: DataSourceAllocEntry(void *pool, const void *key) michael@0: { michael@0: return PR_NEW(PLHashEntry); michael@0: } michael@0: michael@0: static void michael@0: DataSourceFreeEntry(void *pool, PLHashEntry *he, unsigned flag) michael@0: { michael@0: if (flag == HT_FREE_ENTRY) { michael@0: PL_strfree((char*) he->key); michael@0: PR_Free(he); michael@0: } michael@0: } michael@0: michael@0: static PLHashAllocOps dataSourceHashAllocOps = { michael@0: DataSourceAllocTable, DataSourceFreeTable, michael@0: DataSourceAllocEntry, DataSourceFreeEntry michael@0: }; michael@0: michael@0: //---------------------------------------------------------------------- michael@0: // michael@0: // For the mResources hashtable. michael@0: // michael@0: michael@0: struct ResourceHashEntry : public PLDHashEntryHdr { michael@0: const char *mKey; michael@0: nsIRDFResource *mResource; michael@0: michael@0: static PLDHashNumber michael@0: HashKey(PLDHashTable *table, const void *key) michael@0: { michael@0: return HashString(static_cast(key)); michael@0: } michael@0: michael@0: static bool michael@0: MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr, michael@0: const void *key) michael@0: { michael@0: const ResourceHashEntry *entry = michael@0: static_cast(hdr); michael@0: michael@0: return 0 == nsCRT::strcmp(static_cast(key), michael@0: entry->mKey); michael@0: } michael@0: }; michael@0: michael@0: static const PLDHashTableOps gResourceTableOps = { michael@0: PL_DHashAllocTable, michael@0: PL_DHashFreeTable, michael@0: ResourceHashEntry::HashKey, michael@0: ResourceHashEntry::MatchEntry, michael@0: PL_DHashMoveEntryStub, michael@0: PL_DHashClearEntryStub, michael@0: PL_DHashFinalizeStub, michael@0: nullptr michael@0: }; michael@0: michael@0: // ---------------------------------------------------------------------- michael@0: // michael@0: // For the mLiterals hashtable. michael@0: // michael@0: michael@0: struct LiteralHashEntry : public PLDHashEntryHdr { michael@0: nsIRDFLiteral *mLiteral; michael@0: const char16_t *mKey; michael@0: michael@0: static PLDHashNumber michael@0: HashKey(PLDHashTable *table, const void *key) michael@0: { michael@0: return HashString(static_cast(key)); michael@0: } michael@0: michael@0: static bool michael@0: MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr, michael@0: const void *key) michael@0: { michael@0: const LiteralHashEntry *entry = michael@0: static_cast(hdr); michael@0: michael@0: return 0 == nsCRT::strcmp(static_cast(key), michael@0: entry->mKey); michael@0: } michael@0: }; michael@0: michael@0: static const PLDHashTableOps gLiteralTableOps = { michael@0: PL_DHashAllocTable, michael@0: PL_DHashFreeTable, michael@0: LiteralHashEntry::HashKey, michael@0: LiteralHashEntry::MatchEntry, michael@0: PL_DHashMoveEntryStub, michael@0: PL_DHashClearEntryStub, michael@0: PL_DHashFinalizeStub, michael@0: nullptr michael@0: }; michael@0: michael@0: // ---------------------------------------------------------------------- michael@0: // michael@0: // For the mInts hashtable. michael@0: // michael@0: michael@0: struct IntHashEntry : public PLDHashEntryHdr { michael@0: nsIRDFInt *mInt; michael@0: int32_t mKey; michael@0: michael@0: static PLDHashNumber michael@0: HashKey(PLDHashTable *table, const void *key) michael@0: { michael@0: return PLDHashNumber(*static_cast(key)); michael@0: } michael@0: michael@0: static bool michael@0: MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr, michael@0: const void *key) michael@0: { michael@0: const IntHashEntry *entry = michael@0: static_cast(hdr); michael@0: michael@0: return *static_cast(key) == entry->mKey; michael@0: } michael@0: }; michael@0: michael@0: static const PLDHashTableOps gIntTableOps = { michael@0: PL_DHashAllocTable, michael@0: PL_DHashFreeTable, michael@0: IntHashEntry::HashKey, michael@0: IntHashEntry::MatchEntry, michael@0: PL_DHashMoveEntryStub, michael@0: PL_DHashClearEntryStub, michael@0: PL_DHashFinalizeStub, michael@0: nullptr michael@0: }; michael@0: michael@0: // ---------------------------------------------------------------------- michael@0: // michael@0: // For the mDates hashtable. michael@0: // michael@0: michael@0: struct DateHashEntry : public PLDHashEntryHdr { michael@0: nsIRDFDate *mDate; michael@0: PRTime mKey; michael@0: michael@0: static PLDHashNumber michael@0: HashKey(PLDHashTable *table, const void *key) michael@0: { michael@0: // xor the low 32 bits with the high 32 bits. michael@0: PRTime t = *static_cast(key); michael@0: int32_t h32 = int32_t(t >> 32); michael@0: int32_t l32 = int32_t(0xffffffff & t); michael@0: return PLDHashNumber(l32 ^ h32); michael@0: } michael@0: michael@0: static bool michael@0: MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr, michael@0: const void *key) michael@0: { michael@0: const DateHashEntry *entry = michael@0: static_cast(hdr); michael@0: michael@0: return *static_cast(key) == entry->mKey; michael@0: } michael@0: }; michael@0: michael@0: static const PLDHashTableOps gDateTableOps = { michael@0: PL_DHashAllocTable, michael@0: PL_DHashFreeTable, michael@0: DateHashEntry::HashKey, michael@0: DateHashEntry::MatchEntry, michael@0: PL_DHashMoveEntryStub, michael@0: PL_DHashClearEntryStub, michael@0: PL_DHashFinalizeStub, michael@0: nullptr michael@0: }; michael@0: michael@0: class BlobImpl : public nsIRDFBlob michael@0: { michael@0: public: michael@0: struct Data { michael@0: int32_t mLength; michael@0: uint8_t *mBytes; michael@0: }; michael@0: michael@0: BlobImpl(const uint8_t *aBytes, int32_t aLength) michael@0: { michael@0: mData.mLength = aLength; michael@0: mData.mBytes = new uint8_t[aLength]; michael@0: memcpy(mData.mBytes, aBytes, aLength); michael@0: NS_ADDREF(RDFServiceImpl::gRDFService); michael@0: RDFServiceImpl::gRDFService->RegisterBlob(this); michael@0: } michael@0: michael@0: virtual ~BlobImpl() michael@0: { michael@0: RDFServiceImpl::gRDFService->UnregisterBlob(this); michael@0: // Use NS_RELEASE2() here, because we want to decrease the michael@0: // refcount, but not null out the gRDFService pointer (which is michael@0: // what a vanilla NS_RELEASE() would do). michael@0: nsrefcnt refcnt; michael@0: NS_RELEASE2(RDFServiceImpl::gRDFService, refcnt); michael@0: delete[] mData.mBytes; michael@0: } michael@0: michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSIRDFNODE michael@0: NS_DECL_NSIRDFBLOB michael@0: michael@0: Data mData; michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(BlobImpl, nsIRDFNode, nsIRDFBlob) michael@0: michael@0: NS_IMETHODIMP michael@0: BlobImpl::EqualsNode(nsIRDFNode *aNode, bool *aEquals) michael@0: { michael@0: nsCOMPtr blob = do_QueryInterface(aNode); michael@0: if (blob) { michael@0: int32_t length; michael@0: blob->GetLength(&length); michael@0: michael@0: if (length == mData.mLength) { michael@0: const uint8_t *bytes; michael@0: blob->GetValue(&bytes); michael@0: michael@0: if (0 == memcmp(bytes, mData.mBytes, length)) { michael@0: *aEquals = true; michael@0: return NS_OK; michael@0: } michael@0: } michael@0: } michael@0: michael@0: *aEquals = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: BlobImpl::GetValue(const uint8_t **aResult) michael@0: { michael@0: *aResult = mData.mBytes; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: BlobImpl::GetLength(int32_t *aResult) michael@0: { michael@0: *aResult = mData.mLength; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // ---------------------------------------------------------------------- michael@0: // michael@0: // For the mBlobs hashtable. michael@0: // michael@0: michael@0: struct BlobHashEntry : public PLDHashEntryHdr { michael@0: BlobImpl *mBlob; michael@0: michael@0: static PLDHashNumber michael@0: HashKey(PLDHashTable *table, const void *key) michael@0: { michael@0: const BlobImpl::Data *data = michael@0: static_cast(key); michael@0: return HashBytes(data->mBytes, data->mLength); michael@0: } michael@0: michael@0: static bool michael@0: MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr, michael@0: const void *key) michael@0: { michael@0: const BlobHashEntry *entry = michael@0: static_cast(hdr); michael@0: michael@0: const BlobImpl::Data *left = &entry->mBlob->mData; michael@0: michael@0: const BlobImpl::Data *right = michael@0: static_cast(key); michael@0: michael@0: return (left->mLength == right->mLength) michael@0: && 0 == memcmp(left->mBytes, right->mBytes, right->mLength); michael@0: } michael@0: }; michael@0: michael@0: static const PLDHashTableOps gBlobTableOps = { michael@0: PL_DHashAllocTable, michael@0: PL_DHashFreeTable, michael@0: BlobHashEntry::HashKey, michael@0: BlobHashEntry::MatchEntry, michael@0: PL_DHashMoveEntryStub, michael@0: PL_DHashClearEntryStub, michael@0: PL_DHashFinalizeStub, michael@0: nullptr michael@0: }; michael@0: michael@0: //////////////////////////////////////////////////////////////////////// michael@0: // LiteralImpl michael@0: // michael@0: // Currently, all literals are implemented exactly the same way; michael@0: // i.e., there is are no resource factories to allow you to generate michael@0: // customer resources. I doubt that makes sense, anyway. michael@0: // michael@0: class LiteralImpl : public nsIRDFLiteral { michael@0: public: michael@0: static nsresult michael@0: Create(const char16_t* aValue, nsIRDFLiteral** aResult); michael@0: michael@0: // nsISupports michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: michael@0: // nsIRDFNode michael@0: NS_DECL_NSIRDFNODE michael@0: michael@0: // nsIRDFLiteral michael@0: NS_DECL_NSIRDFLITERAL michael@0: michael@0: protected: michael@0: LiteralImpl(const char16_t* s); michael@0: virtual ~LiteralImpl(); michael@0: michael@0: const char16_t* GetValue() const { michael@0: size_t objectSize = ((sizeof(LiteralImpl) + sizeof(char16_t) - 1) / sizeof(char16_t)) * sizeof(char16_t); michael@0: return reinterpret_cast(reinterpret_cast(this) + objectSize); michael@0: } michael@0: }; michael@0: michael@0: michael@0: nsresult michael@0: LiteralImpl::Create(const char16_t* aValue, nsIRDFLiteral** aResult) michael@0: { michael@0: // Goofy math to get alignment right. Copied from nsSharedString.h. michael@0: size_t objectSize = ((sizeof(LiteralImpl) + sizeof(char16_t) - 1) / sizeof(char16_t)) * sizeof(char16_t); michael@0: size_t stringLen = nsCharTraits::length(aValue); michael@0: size_t stringSize = (stringLen + 1) * sizeof(char16_t); michael@0: michael@0: void* objectPtr = operator new(objectSize + stringSize); michael@0: if (! objectPtr) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: char16_t* buf = reinterpret_cast(static_cast(objectPtr) + objectSize); michael@0: nsCharTraits::copy(buf, aValue, stringLen + 1); michael@0: michael@0: NS_ADDREF(*aResult = new (objectPtr) LiteralImpl(buf)); michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: LiteralImpl::LiteralImpl(const char16_t* s) michael@0: { michael@0: RDFServiceImpl::gRDFService->RegisterLiteral(this); michael@0: NS_ADDREF(RDFServiceImpl::gRDFService); michael@0: } michael@0: michael@0: LiteralImpl::~LiteralImpl() michael@0: { michael@0: RDFServiceImpl::gRDFService->UnregisterLiteral(this); michael@0: michael@0: // Use NS_RELEASE2() here, because we want to decrease the michael@0: // refcount, but not null out the gRDFService pointer (which is michael@0: // what a vanilla NS_RELEASE() would do). michael@0: nsrefcnt refcnt; michael@0: NS_RELEASE2(RDFServiceImpl::gRDFService, refcnt); michael@0: } michael@0: michael@0: NS_IMPL_ADDREF(LiteralImpl) michael@0: NS_IMPL_RELEASE(LiteralImpl) michael@0: michael@0: nsresult michael@0: LiteralImpl::QueryInterface(REFNSIID iid, void** result) michael@0: { michael@0: if (! result) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: *result = nullptr; michael@0: if (iid.Equals(kIRDFLiteralIID) || michael@0: iid.Equals(kIRDFNodeIID) || michael@0: iid.Equals(kISupportsIID)) { michael@0: *result = static_cast(this); michael@0: AddRef(); michael@0: return NS_OK; michael@0: } michael@0: return NS_NOINTERFACE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: LiteralImpl::EqualsNode(nsIRDFNode* aNode, bool* aResult) michael@0: { michael@0: nsresult rv; michael@0: nsIRDFLiteral* literal; michael@0: rv = aNode->QueryInterface(kIRDFLiteralIID, (void**) &literal); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: *aResult = (static_cast(this) == literal); michael@0: NS_RELEASE(literal); michael@0: return NS_OK; michael@0: } michael@0: else if (rv == NS_NOINTERFACE) { michael@0: *aResult = false; michael@0: return NS_OK; michael@0: } michael@0: else { michael@0: return rv; michael@0: } michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: LiteralImpl::GetValue(char16_t* *value) michael@0: { michael@0: NS_ASSERTION(value, "null ptr"); michael@0: if (! value) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: const char16_t *temp = GetValue(); michael@0: *value = temp? NS_strdup(temp) : 0; michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: LiteralImpl::GetValueConst(const char16_t** aValue) michael@0: { michael@0: *aValue = GetValue(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////// michael@0: // DateImpl michael@0: // michael@0: michael@0: class DateImpl : public nsIRDFDate { michael@0: public: michael@0: DateImpl(const PRTime s); michael@0: virtual ~DateImpl(); michael@0: michael@0: // nsISupports michael@0: NS_DECL_ISUPPORTS michael@0: michael@0: // nsIRDFNode michael@0: NS_DECL_NSIRDFNODE michael@0: michael@0: // nsIRDFDate michael@0: NS_IMETHOD GetValue(PRTime *value); michael@0: michael@0: private: michael@0: nsresult EqualsDate(nsIRDFDate* date, bool* result); michael@0: PRTime mValue; michael@0: }; michael@0: michael@0: michael@0: DateImpl::DateImpl(const PRTime s) michael@0: : mValue(s) michael@0: { michael@0: RDFServiceImpl::gRDFService->RegisterDate(this); michael@0: NS_ADDREF(RDFServiceImpl::gRDFService); michael@0: } michael@0: michael@0: DateImpl::~DateImpl() michael@0: { michael@0: RDFServiceImpl::gRDFService->UnregisterDate(this); michael@0: michael@0: // Use NS_RELEASE2() here, because we want to decrease the michael@0: // refcount, but not null out the gRDFService pointer (which is michael@0: // what a vanilla NS_RELEASE() would do). michael@0: nsrefcnt refcnt; michael@0: NS_RELEASE2(RDFServiceImpl::gRDFService, refcnt); michael@0: } michael@0: michael@0: NS_IMPL_ADDREF(DateImpl) michael@0: NS_IMPL_RELEASE(DateImpl) michael@0: michael@0: nsresult michael@0: DateImpl::QueryInterface(REFNSIID iid, void** result) michael@0: { michael@0: if (! result) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: *result = nullptr; michael@0: if (iid.Equals(kIRDFDateIID) || michael@0: iid.Equals(kIRDFNodeIID) || michael@0: iid.Equals(kISupportsIID)) { michael@0: *result = static_cast(this); michael@0: AddRef(); michael@0: return NS_OK; michael@0: } michael@0: return NS_NOINTERFACE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: DateImpl::EqualsNode(nsIRDFNode* node, bool* result) michael@0: { michael@0: nsresult rv; michael@0: nsIRDFDate* date; michael@0: if (NS_SUCCEEDED(node->QueryInterface(kIRDFDateIID, (void**) &date))) { michael@0: rv = EqualsDate(date, result); michael@0: NS_RELEASE(date); michael@0: } michael@0: else { michael@0: *result = false; michael@0: rv = NS_OK; michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: DateImpl::GetValue(PRTime *value) michael@0: { michael@0: NS_ASSERTION(value, "null ptr"); michael@0: if (! value) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: *value = mValue; michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: nsresult michael@0: DateImpl::EqualsDate(nsIRDFDate* date, bool* result) michael@0: { michael@0: NS_ASSERTION(date && result, "null ptr"); michael@0: if (!date || !result) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: nsresult rv; michael@0: PRTime p; michael@0: if (NS_FAILED(rv = date->GetValue(&p))) michael@0: return rv; michael@0: michael@0: *result = p == mValue; michael@0: return NS_OK; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////// michael@0: // IntImpl michael@0: // michael@0: michael@0: class IntImpl : public nsIRDFInt { michael@0: public: michael@0: IntImpl(int32_t s); michael@0: virtual ~IntImpl(); michael@0: michael@0: // nsISupports michael@0: NS_DECL_ISUPPORTS michael@0: michael@0: // nsIRDFNode michael@0: NS_DECL_NSIRDFNODE michael@0: michael@0: // nsIRDFInt michael@0: NS_IMETHOD GetValue(int32_t *value); michael@0: michael@0: private: michael@0: nsresult EqualsInt(nsIRDFInt* value, bool* result); michael@0: int32_t mValue; michael@0: }; michael@0: michael@0: michael@0: IntImpl::IntImpl(int32_t s) michael@0: : mValue(s) michael@0: { michael@0: RDFServiceImpl::gRDFService->RegisterInt(this); michael@0: NS_ADDREF(RDFServiceImpl::gRDFService); michael@0: } michael@0: michael@0: IntImpl::~IntImpl() michael@0: { michael@0: RDFServiceImpl::gRDFService->UnregisterInt(this); michael@0: michael@0: // Use NS_RELEASE2() here, because we want to decrease the michael@0: // refcount, but not null out the gRDFService pointer (which is michael@0: // what a vanilla NS_RELEASE() would do). michael@0: nsrefcnt refcnt; michael@0: NS_RELEASE2(RDFServiceImpl::gRDFService, refcnt); michael@0: } michael@0: michael@0: NS_IMPL_ADDREF(IntImpl) michael@0: NS_IMPL_RELEASE(IntImpl) michael@0: michael@0: nsresult michael@0: IntImpl::QueryInterface(REFNSIID iid, void** result) michael@0: { michael@0: if (! result) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: *result = nullptr; michael@0: if (iid.Equals(kIRDFIntIID) || michael@0: iid.Equals(kIRDFNodeIID) || michael@0: iid.Equals(kISupportsIID)) { michael@0: *result = static_cast(this); michael@0: AddRef(); michael@0: return NS_OK; michael@0: } michael@0: return NS_NOINTERFACE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: IntImpl::EqualsNode(nsIRDFNode* node, bool* result) michael@0: { michael@0: nsresult rv; michael@0: nsIRDFInt* intValue; michael@0: if (NS_SUCCEEDED(node->QueryInterface(kIRDFIntIID, (void**) &intValue))) { michael@0: rv = EqualsInt(intValue, result); michael@0: NS_RELEASE(intValue); michael@0: } michael@0: else { michael@0: *result = false; michael@0: rv = NS_OK; michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: IntImpl::GetValue(int32_t *value) michael@0: { michael@0: NS_ASSERTION(value, "null ptr"); michael@0: if (! value) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: *value = mValue; michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: nsresult michael@0: IntImpl::EqualsInt(nsIRDFInt* intValue, bool* result) michael@0: { michael@0: NS_ASSERTION(intValue && result, "null ptr"); michael@0: if (!intValue || !result) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: nsresult rv; michael@0: int32_t p; michael@0: if (NS_FAILED(rv = intValue->GetValue(&p))) michael@0: return rv; michael@0: michael@0: *result = (p == mValue); michael@0: return NS_OK; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////// michael@0: // RDFServiceImpl michael@0: michael@0: RDFServiceImpl* michael@0: RDFServiceImpl::gRDFService; michael@0: michael@0: RDFServiceImpl::RDFServiceImpl() michael@0: : mNamedDataSources(nullptr) michael@0: { michael@0: mResources.ops = nullptr; michael@0: mLiterals.ops = nullptr; michael@0: mInts.ops = nullptr; michael@0: mDates.ops = nullptr; michael@0: mBlobs.ops = nullptr; michael@0: gRDFService = this; michael@0: } michael@0: michael@0: nsresult michael@0: RDFServiceImpl::Init() michael@0: { michael@0: nsresult rv; michael@0: michael@0: mNamedDataSources = PL_NewHashTable(23, michael@0: PL_HashString, michael@0: PL_CompareStrings, michael@0: PL_CompareValues, michael@0: &dataSourceHashAllocOps, nullptr); michael@0: michael@0: if (! mNamedDataSources) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: PL_DHashTableInit(&mResources, &gResourceTableOps, nullptr, michael@0: sizeof(ResourceHashEntry), PL_DHASH_MIN_SIZE); michael@0: michael@0: PL_DHashTableInit(&mLiterals, &gLiteralTableOps, nullptr, michael@0: sizeof(LiteralHashEntry), PL_DHASH_MIN_SIZE); michael@0: michael@0: PL_DHashTableInit(&mInts, &gIntTableOps, nullptr, michael@0: sizeof(IntHashEntry), PL_DHASH_MIN_SIZE); michael@0: michael@0: PL_DHashTableInit(&mDates, &gDateTableOps, nullptr, michael@0: sizeof(DateHashEntry), PL_DHASH_MIN_SIZE); michael@0: michael@0: PL_DHashTableInit(&mBlobs, &gBlobTableOps, nullptr, michael@0: sizeof(BlobHashEntry), PL_DHASH_MIN_SIZE); michael@0: michael@0: mDefaultResourceFactory = do_GetClassObject(kRDFDefaultResourceCID, &rv); michael@0: NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get default resource factory"); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: #ifdef PR_LOGGING michael@0: if (! gLog) michael@0: gLog = PR_NewLogModule("nsRDFService"); michael@0: #endif michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: RDFServiceImpl::~RDFServiceImpl() michael@0: { michael@0: if (mNamedDataSources) { michael@0: PL_HashTableDestroy(mNamedDataSources); michael@0: mNamedDataSources = nullptr; michael@0: } michael@0: if (mResources.ops) michael@0: PL_DHashTableFinish(&mResources); michael@0: if (mLiterals.ops) michael@0: PL_DHashTableFinish(&mLiterals); michael@0: if (mInts.ops) michael@0: PL_DHashTableFinish(&mInts); michael@0: if (mDates.ops) michael@0: PL_DHashTableFinish(&mDates); michael@0: if (mBlobs.ops) michael@0: PL_DHashTableFinish(&mBlobs); michael@0: gRDFService = nullptr; michael@0: } michael@0: michael@0: michael@0: // static michael@0: nsresult michael@0: RDFServiceImpl::CreateSingleton(nsISupports* aOuter, michael@0: const nsIID& aIID, void **aResult) michael@0: { michael@0: NS_ENSURE_NO_AGGREGATION(aOuter); michael@0: michael@0: if (gRDFService) { michael@0: NS_ERROR("Trying to create RDF serviec twice."); michael@0: return gRDFService->QueryInterface(aIID, aResult); michael@0: } michael@0: michael@0: nsRefPtr serv = new RDFServiceImpl(); michael@0: if (!serv) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: nsresult rv = serv->Init(); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: return serv->QueryInterface(aIID, aResult); michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS(RDFServiceImpl, nsIRDFService, nsISupportsWeakReference) michael@0: michael@0: // Per RFC2396. michael@0: static const uint8_t michael@0: kLegalSchemeChars[] = { michael@0: // ASCII Bits Ordered Hex michael@0: // 01234567 76543210 michael@0: 0x00, // 00-07 michael@0: 0x00, // 08-0F michael@0: 0x00, // 10-17 michael@0: 0x00, // 18-1F michael@0: 0x00, // 20-27 !"#$%&' 00000000 00000000 michael@0: 0x28, // 28-2F ()*+,-./ 00010100 00101000 0x28 michael@0: 0xff, // 30-37 01234567 11111111 11111111 0xFF michael@0: 0x03, // 38-3F 89:;<=>? 11000000 00000011 0x03 michael@0: 0xfe, // 40-47 @ABCDEFG 01111111 11111110 0xFE michael@0: 0xff, // 48-4F HIJKLMNO 11111111 11111111 0xFF michael@0: 0xff, // 50-57 PQRSTUVW 11111111 11111111 0xFF michael@0: 0x87, // 58-5F XYZ[\]^_ 11100001 10000111 0x87 michael@0: 0xfe, // 60-67 `abcdefg 01111111 11111110 0xFE michael@0: 0xff, // 68-6F hijklmno 11111111 11111111 0xFF michael@0: 0xff, // 70-77 pqrstuvw 11111111 11111111 0xFF michael@0: 0x07, // 78-7F xyz{|}~ 11100000 00000111 0x07 michael@0: 0x00, 0x00, 0x00, 0x00, // >= 80 michael@0: 0x00, 0x00, 0x00, 0x00, michael@0: 0x00, 0x00, 0x00, 0x00, michael@0: 0x00, 0x00, 0x00, 0x00 michael@0: }; michael@0: michael@0: static inline bool michael@0: IsLegalSchemeCharacter(const char aChar) michael@0: { michael@0: uint8_t mask = kLegalSchemeChars[aChar >> 3]; michael@0: uint8_t bit = 1u << (aChar & 0x7); michael@0: return bool((mask & bit) != 0); michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: RDFServiceImpl::GetResource(const nsACString& aURI, nsIRDFResource** aResource) michael@0: { michael@0: // Sanity checks michael@0: NS_PRECONDITION(aResource != nullptr, "null ptr"); michael@0: NS_PRECONDITION(!aURI.IsEmpty(), "URI is empty"); michael@0: if (! aResource) michael@0: return NS_ERROR_NULL_POINTER; michael@0: if (aURI.IsEmpty()) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: const nsAFlatCString& flatURI = PromiseFlatCString(aURI); michael@0: PR_LOG(gLog, PR_LOG_DEBUG, ("rdfserv get-resource %s", flatURI.get())); michael@0: michael@0: // First, check the cache to see if we've already created and michael@0: // registered this thing. michael@0: PLDHashEntryHdr *hdr = michael@0: PL_DHashTableOperate(&mResources, flatURI.get(), PL_DHASH_LOOKUP); michael@0: michael@0: if (PL_DHASH_ENTRY_IS_BUSY(hdr)) { michael@0: ResourceHashEntry *entry = static_cast(hdr); michael@0: NS_ADDREF(*aResource = entry->mResource); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Nope. So go to the repository to create it. michael@0: michael@0: // Compute the scheme of the URI. Scan forward until we either: michael@0: // michael@0: // 1. Reach the end of the string michael@0: // 2. Encounter a non-alpha character michael@0: // 3. Encouter a colon. michael@0: // michael@0: // If we encounter a colon _before_ encountering a non-alpha michael@0: // character, then assume it's the scheme. michael@0: // michael@0: // XXX Although it's really not correct, we'll allow underscore michael@0: // characters ('_'), too. michael@0: nsACString::const_iterator p, end; michael@0: aURI.BeginReading(p); michael@0: aURI.EndReading(end); michael@0: while (p != end && IsLegalSchemeCharacter(*p)) michael@0: ++p; michael@0: michael@0: nsresult rv; michael@0: nsCOMPtr factory; michael@0: michael@0: nsACString::const_iterator begin; michael@0: aURI.BeginReading(begin); michael@0: if (*p == ':') { michael@0: // There _was_ a scheme. First see if it's the same scheme michael@0: // that we just tried to use... michael@0: if (mLastFactory && mLastURIPrefix.Equals(Substring(begin, p))) michael@0: factory = mLastFactory; michael@0: else { michael@0: // Try to find a factory using the component manager. michael@0: nsACString::const_iterator begin; michael@0: aURI.BeginReading(begin); michael@0: nsAutoCString contractID; michael@0: contractID = NS_LITERAL_CSTRING(NS_RDF_RESOURCE_FACTORY_CONTRACTID_PREFIX) + michael@0: Substring(begin, p); michael@0: michael@0: factory = do_GetClassObject(contractID.get()); michael@0: if (factory) { michael@0: // Store the factory in our one-element cache. michael@0: if (p != begin) { michael@0: mLastFactory = factory; michael@0: mLastURIPrefix = Substring(begin, p); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (! factory) { michael@0: // fall through to using the "default" resource factory if either: michael@0: // michael@0: // 1. The URI didn't have a scheme, or michael@0: // 2. There was no resource factory registered for the scheme. michael@0: factory = mDefaultResourceFactory; michael@0: michael@0: // Store the factory in our one-element cache. michael@0: if (p != begin) { michael@0: mLastFactory = factory; michael@0: mLastURIPrefix = Substring(begin, p); michael@0: } michael@0: } michael@0: michael@0: nsIRDFResource *result; michael@0: rv = factory->CreateInstance(nullptr, NS_GET_IID(nsIRDFResource), (void**) &result); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: // Now initialize it with its URI. At this point, the resource michael@0: // implementation should register itself with the RDF service. michael@0: rv = result->Init(flatURI.get()); michael@0: if (NS_FAILED(rv)) { michael@0: NS_ERROR("unable to initialize resource"); michael@0: NS_RELEASE(result); michael@0: return rv; michael@0: } michael@0: michael@0: *aResource = result; // already refcounted from repository michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: RDFServiceImpl::GetUnicodeResource(const nsAString& aURI, nsIRDFResource** aResource) michael@0: { michael@0: return GetResource(NS_ConvertUTF16toUTF8(aURI), aResource); michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: RDFServiceImpl::GetAnonymousResource(nsIRDFResource** aResult) michael@0: { michael@0: static uint32_t gCounter = 0; michael@0: static char gChars[] = "0123456789abcdef" michael@0: "ghijklmnopqrstuv" michael@0: "wxyzABCDEFGHIJKL" michael@0: "MNOPQRSTUVWXYZ.+"; michael@0: michael@0: static int32_t kMask = 0x003f; michael@0: static int32_t kShift = 6; michael@0: michael@0: if (! gCounter) { michael@0: // Start it at a semi-unique value, just to minimize the michael@0: // chance that we get into a situation where michael@0: // michael@0: // 1. An anonymous resource gets serialized out in a graph michael@0: // 2. Reboot michael@0: // 3. The same anonymous resource gets requested, and refers michael@0: // to something completely different. michael@0: // 4. The serialization is read back in. michael@0: gCounter = uint32_t(PR_Now()); michael@0: } michael@0: michael@0: nsresult rv; michael@0: nsAutoCString s; michael@0: michael@0: do { michael@0: // Ugh, this is a really sloppy way to do this; I copied the michael@0: // implementation from the days when it lived outside the RDF michael@0: // service. Now that it's a member we can be more cleverer. michael@0: michael@0: s.Truncate(); michael@0: s.Append("rdf:#$"); michael@0: michael@0: uint32_t id = ++gCounter; michael@0: while (id) { michael@0: char ch = gChars[(id & kMask)]; michael@0: s.Append(ch); michael@0: id >>= kShift; michael@0: } michael@0: michael@0: nsIRDFResource* resource; michael@0: rv = GetResource(s, &resource); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: // XXX an ugly but effective way to make sure that this michael@0: // resource is really unique in the world. michael@0: resource->AddRef(); michael@0: nsrefcnt refcnt = resource->Release(); michael@0: michael@0: if (refcnt == 1) { michael@0: *aResult = resource; michael@0: break; michael@0: } michael@0: michael@0: NS_RELEASE(resource); michael@0: } while (1); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: RDFServiceImpl::GetLiteral(const char16_t* aValue, nsIRDFLiteral** aLiteral) michael@0: { michael@0: NS_PRECONDITION(aValue != nullptr, "null ptr"); michael@0: if (! aValue) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: NS_PRECONDITION(aLiteral != nullptr, "null ptr"); michael@0: if (! aLiteral) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: // See if we have one already cached michael@0: PLDHashEntryHdr *hdr = michael@0: PL_DHashTableOperate(&mLiterals, aValue, PL_DHASH_LOOKUP); michael@0: michael@0: if (PL_DHASH_ENTRY_IS_BUSY(hdr)) { michael@0: LiteralHashEntry *entry = static_cast(hdr); michael@0: NS_ADDREF(*aLiteral = entry->mLiteral); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Nope. Create a new one michael@0: return LiteralImpl::Create(aValue, aLiteral); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: RDFServiceImpl::GetDateLiteral(PRTime aTime, nsIRDFDate** aResult) michael@0: { michael@0: // See if we have one already cached michael@0: PLDHashEntryHdr *hdr = michael@0: PL_DHashTableOperate(&mDates, &aTime, PL_DHASH_LOOKUP); michael@0: michael@0: if (PL_DHASH_ENTRY_IS_BUSY(hdr)) { michael@0: DateHashEntry *entry = static_cast(hdr); michael@0: NS_ADDREF(*aResult = entry->mDate); michael@0: return NS_OK; michael@0: } michael@0: michael@0: DateImpl* result = new DateImpl(aTime); michael@0: if (! result) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: NS_ADDREF(*aResult = result); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: RDFServiceImpl::GetIntLiteral(int32_t aInt, nsIRDFInt** aResult) michael@0: { michael@0: // See if we have one already cached michael@0: PLDHashEntryHdr *hdr = michael@0: PL_DHashTableOperate(&mInts, &aInt, PL_DHASH_LOOKUP); michael@0: michael@0: if (PL_DHASH_ENTRY_IS_BUSY(hdr)) { michael@0: IntHashEntry *entry = static_cast(hdr); michael@0: NS_ADDREF(*aResult = entry->mInt); michael@0: return NS_OK; michael@0: } michael@0: michael@0: IntImpl* result = new IntImpl(aInt); michael@0: if (! result) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: NS_ADDREF(*aResult = result); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: RDFServiceImpl::GetBlobLiteral(const uint8_t *aBytes, int32_t aLength, michael@0: nsIRDFBlob **aResult) michael@0: { michael@0: BlobImpl::Data key = { aLength, const_cast(aBytes) }; michael@0: michael@0: PLDHashEntryHdr *hdr = michael@0: PL_DHashTableOperate(&mBlobs, &key, PL_DHASH_LOOKUP); michael@0: michael@0: if (PL_DHASH_ENTRY_IS_BUSY(hdr)) { michael@0: BlobHashEntry *entry = static_cast(hdr); michael@0: NS_ADDREF(*aResult = entry->mBlob); michael@0: return NS_OK; michael@0: } michael@0: michael@0: BlobImpl *result = new BlobImpl(aBytes, aLength); michael@0: if (! result) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: NS_ADDREF(*aResult = result); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: RDFServiceImpl::IsAnonymousResource(nsIRDFResource* aResource, bool* _result) michael@0: { michael@0: NS_PRECONDITION(aResource != nullptr, "null ptr"); michael@0: if (! aResource) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: nsresult rv; michael@0: michael@0: const char* uri; michael@0: rv = aResource->GetValueConst(&uri); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: if ((uri[0] == 'r') && michael@0: (uri[1] == 'd') && michael@0: (uri[2] == 'f') && michael@0: (uri[3] == ':') && michael@0: (uri[4] == '#') && michael@0: (uri[5] == '$')) { michael@0: *_result = true; michael@0: } michael@0: else { michael@0: *_result = false; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: RDFServiceImpl::RegisterResource(nsIRDFResource* aResource, bool aReplace) michael@0: { michael@0: NS_PRECONDITION(aResource != nullptr, "null ptr"); michael@0: if (! aResource) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: nsresult rv; michael@0: michael@0: const char* uri; michael@0: rv = aResource->GetValueConst(&uri); michael@0: NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get URI from resource"); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: NS_ASSERTION(uri != nullptr, "resource has no URI"); michael@0: if (! uri) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: PLDHashEntryHdr *hdr = michael@0: PL_DHashTableOperate(&mResources, uri, PL_DHASH_LOOKUP); michael@0: michael@0: if (PL_DHASH_ENTRY_IS_BUSY(hdr)) { michael@0: if (!aReplace) { michael@0: NS_WARNING("resource already registered, and replace not specified"); michael@0: return NS_ERROR_FAILURE; // already registered michael@0: } michael@0: michael@0: // N.B., we do _not_ release the original resource because we michael@0: // only ever held a weak reference to it. We simply replace michael@0: // it. michael@0: michael@0: PR_LOG(gLog, PR_LOG_DEBUG, michael@0: ("rdfserv replace-resource [%p] <-- [%p] %s", michael@0: static_cast(hdr)->mResource, michael@0: aResource, (const char*) uri)); michael@0: } michael@0: else { michael@0: hdr = PL_DHashTableOperate(&mResources, uri, PL_DHASH_ADD); michael@0: if (! hdr) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: PR_LOG(gLog, PR_LOG_DEBUG, michael@0: ("rdfserv register-resource [%p] %s", michael@0: aResource, (const char*) uri)); michael@0: } michael@0: michael@0: // N.B., we only hold a weak reference to the resource: that way, michael@0: // the resource can be destroyed when the last refcount goes michael@0: // away. The single addref that the CreateResource() call made michael@0: // will be owned by the callee. michael@0: ResourceHashEntry *entry = static_cast(hdr); michael@0: entry->mResource = aResource; michael@0: entry->mKey = uri; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: RDFServiceImpl::UnregisterResource(nsIRDFResource* aResource) michael@0: { michael@0: NS_PRECONDITION(aResource != nullptr, "null ptr"); michael@0: if (! aResource) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: nsresult rv; michael@0: michael@0: const char* uri; michael@0: rv = aResource->GetValueConst(&uri); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: NS_ASSERTION(uri != nullptr, "resource has no URI"); michael@0: if (! uri) michael@0: return NS_ERROR_UNEXPECTED; michael@0: michael@0: PR_LOG(gLog, PR_LOG_DEBUG, michael@0: ("rdfserv unregister-resource [%p] %s", michael@0: aResource, (const char*) uri)); michael@0: michael@0: #ifdef DEBUG michael@0: if (PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mResources, uri, PL_DHASH_LOOKUP))) michael@0: NS_WARNING("resource was never registered"); michael@0: #endif michael@0: michael@0: PL_DHashTableOperate(&mResources, uri, PL_DHASH_REMOVE); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: RDFServiceImpl::RegisterDataSource(nsIRDFDataSource* aDataSource, bool aReplace) michael@0: { michael@0: NS_PRECONDITION(aDataSource != nullptr, "null ptr"); michael@0: if (! aDataSource) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: nsresult rv; michael@0: michael@0: nsXPIDLCString uri; michael@0: rv = aDataSource->GetURI(getter_Copies(uri)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: PLHashEntry** hep = michael@0: PL_HashTableRawLookup(mNamedDataSources, (*mNamedDataSources->keyHash)(uri), uri); michael@0: michael@0: if (*hep) { michael@0: if (! aReplace) michael@0: return NS_ERROR_FAILURE; // already registered michael@0: michael@0: // N.B., we only hold a weak reference to the datasource, so michael@0: // just replace the old with the new and don't touch any michael@0: // refcounts. michael@0: PR_LOG(gLog, PR_LOG_NOTICE, michael@0: ("rdfserv replace-datasource [%p] <-- [%p] %s", michael@0: (*hep)->value, aDataSource, (const char*) uri)); michael@0: michael@0: (*hep)->value = aDataSource; michael@0: } michael@0: else { michael@0: const char* key = PL_strdup(uri); michael@0: if (! key) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: PL_HashTableAdd(mNamedDataSources, key, aDataSource); michael@0: michael@0: PR_LOG(gLog, PR_LOG_NOTICE, michael@0: ("rdfserv register-datasource [%p] %s", michael@0: aDataSource, (const char*) uri)); michael@0: michael@0: // N.B., we only hold a weak reference to the datasource, so don't michael@0: // addref. michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: RDFServiceImpl::UnregisterDataSource(nsIRDFDataSource* aDataSource) michael@0: { michael@0: NS_PRECONDITION(aDataSource != nullptr, "null ptr"); michael@0: if (! aDataSource) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: nsresult rv; michael@0: michael@0: nsXPIDLCString uri; michael@0: rv = aDataSource->GetURI(getter_Copies(uri)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: //NS_ASSERTION(uri != nullptr, "datasource has no URI"); michael@0: if (! uri) michael@0: return NS_ERROR_UNEXPECTED; michael@0: michael@0: PLHashEntry** hep = michael@0: PL_HashTableRawLookup(mNamedDataSources, (*mNamedDataSources->keyHash)(uri), uri); michael@0: michael@0: // It may well be that this datasource was never registered. If michael@0: // so, don't unregister it. michael@0: if (! *hep || ((*hep)->value != aDataSource)) michael@0: return NS_OK; michael@0: michael@0: // N.B., we only held a weak reference to the datasource, so we michael@0: // don't release here. michael@0: PL_HashTableRawRemove(mNamedDataSources, hep, *hep); michael@0: michael@0: PR_LOG(gLog, PR_LOG_NOTICE, michael@0: ("rdfserv unregister-datasource [%p] %s", michael@0: aDataSource, (const char*) uri)); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: RDFServiceImpl::GetDataSource(const char* aURI, nsIRDFDataSource** aDataSource) michael@0: { michael@0: // Use the other GetDataSource and ask for a non-blocking Refresh. michael@0: // If you wanted it loaded synchronously, then you should've tried to do it michael@0: // yourself, or used GetDataSourceBlocking. michael@0: return GetDataSource( aURI, false, aDataSource ); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: RDFServiceImpl::GetDataSourceBlocking(const char* aURI, nsIRDFDataSource** aDataSource) michael@0: { michael@0: // Use GetDataSource and ask for a blocking Refresh. michael@0: return GetDataSource( aURI, true, aDataSource ); michael@0: } michael@0: michael@0: nsresult michael@0: RDFServiceImpl::GetDataSource(const char* aURI, bool aBlock, nsIRDFDataSource** aDataSource) michael@0: { michael@0: NS_PRECONDITION(aURI != nullptr, "null ptr"); michael@0: if (! aURI) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: nsresult rv; michael@0: michael@0: // Attempt to canonify the URI before we look for it in the michael@0: // cache. We won't bother doing this on `rdf:' URIs to avoid michael@0: // useless (and expensive) protocol handler lookups. michael@0: nsAutoCString spec(aURI); michael@0: michael@0: if (!StringBeginsWith(spec, NS_LITERAL_CSTRING("rdf:"))) { michael@0: nsCOMPtr uri; michael@0: NS_NewURI(getter_AddRefs(uri), spec); michael@0: if (uri) michael@0: uri->GetSpec(spec); michael@0: } michael@0: michael@0: // First, check the cache to see if we already have this michael@0: // datasource loaded and initialized. michael@0: { michael@0: nsIRDFDataSource* cached = michael@0: static_cast(PL_HashTableLookup(mNamedDataSources, spec.get())); michael@0: michael@0: if (cached) { michael@0: NS_ADDREF(cached); michael@0: *aDataSource = cached; michael@0: return NS_OK; michael@0: } michael@0: } michael@0: michael@0: // Nope. So go to the repository to try to create it. michael@0: nsCOMPtr ds; michael@0: if (StringBeginsWith(spec, NS_LITERAL_CSTRING("rdf:"))) { michael@0: // It's a built-in data source. Convert it to a contract ID. michael@0: nsAutoCString contractID( michael@0: NS_LITERAL_CSTRING(NS_RDF_DATASOURCE_CONTRACTID_PREFIX) + michael@0: Substring(spec, 4, spec.Length() - 4)); michael@0: michael@0: // Strip params to get ``base'' contractID for data source. michael@0: int32_t p = contractID.FindChar(char16_t('&')); michael@0: if (p >= 0) michael@0: contractID.Truncate(p); michael@0: michael@0: ds = do_GetService(contractID.get(), &rv); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr remote = do_QueryInterface(ds); michael@0: if (remote) { michael@0: rv = remote->Init(spec.get()); michael@0: if (NS_FAILED(rv)) return rv; michael@0: } michael@0: } michael@0: else { michael@0: // Try to load this as an RDF/XML data source michael@0: ds = do_CreateInstance(kRDFXMLDataSourceCID, &rv); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr remote(do_QueryInterface(ds)); michael@0: NS_ASSERTION(remote, "not a remote RDF/XML data source!"); michael@0: if (! remote) return NS_ERROR_UNEXPECTED; michael@0: michael@0: rv = remote->Init(spec.get()); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: rv = remote->Refresh(aBlock); michael@0: if (NS_FAILED(rv)) return rv; michael@0: } michael@0: michael@0: *aDataSource = ds; michael@0: NS_ADDREF(*aDataSource); michael@0: return NS_OK; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////// michael@0: michael@0: nsresult michael@0: RDFServiceImpl::RegisterLiteral(nsIRDFLiteral* aLiteral) michael@0: { michael@0: const char16_t* value; michael@0: aLiteral->GetValueConst(&value); michael@0: michael@0: NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mLiterals, michael@0: value, michael@0: PL_DHASH_LOOKUP)), michael@0: "literal already registered"); michael@0: michael@0: PLDHashEntryHdr *hdr = michael@0: PL_DHashTableOperate(&mLiterals, value, PL_DHASH_ADD); michael@0: michael@0: if (! hdr) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: LiteralHashEntry *entry = static_cast(hdr); michael@0: michael@0: // N.B., we only hold a weak reference to the literal: that michael@0: // way, the literal can be destroyed when the last refcount michael@0: // goes away. The single addref that the CreateLiteral() call michael@0: // made will be owned by the callee. michael@0: entry->mLiteral = aLiteral; michael@0: entry->mKey = value; michael@0: michael@0: PR_LOG(gLog, PR_LOG_DEBUG, michael@0: ("rdfserv register-literal [%p] %s", michael@0: aLiteral, (const char16_t*) value)); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: nsresult michael@0: RDFServiceImpl::UnregisterLiteral(nsIRDFLiteral* aLiteral) michael@0: { michael@0: const char16_t* value; michael@0: aLiteral->GetValueConst(&value); michael@0: michael@0: NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableOperate(&mLiterals, michael@0: value, michael@0: PL_DHASH_LOOKUP)), michael@0: "literal was never registered"); michael@0: michael@0: PL_DHashTableOperate(&mLiterals, value, PL_DHASH_REMOVE); michael@0: michael@0: // N.B. that we _don't_ release the literal: we only held a weak michael@0: // reference to it in the hashtable. michael@0: PR_LOG(gLog, PR_LOG_DEBUG, michael@0: ("rdfserv unregister-literal [%p] %s", michael@0: aLiteral, (const char16_t*) value)); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: nsresult michael@0: RDFServiceImpl::RegisterInt(nsIRDFInt* aInt) michael@0: { michael@0: int32_t value; michael@0: aInt->GetValue(&value); michael@0: michael@0: NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mInts, michael@0: &value, michael@0: PL_DHASH_LOOKUP)), michael@0: "int already registered"); michael@0: michael@0: PLDHashEntryHdr *hdr = michael@0: PL_DHashTableOperate(&mInts, &value, PL_DHASH_ADD); michael@0: michael@0: if (! hdr) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: IntHashEntry *entry = static_cast(hdr); michael@0: michael@0: // N.B., we only hold a weak reference to the literal: that michael@0: // way, the literal can be destroyed when the last refcount michael@0: // goes away. The single addref that the CreateInt() call michael@0: // made will be owned by the callee. michael@0: entry->mInt = aInt; michael@0: entry->mKey = value; michael@0: michael@0: PR_LOG(gLog, PR_LOG_DEBUG, michael@0: ("rdfserv register-int [%p] %d", michael@0: aInt, value)); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: nsresult michael@0: RDFServiceImpl::UnregisterInt(nsIRDFInt* aInt) michael@0: { michael@0: int32_t value; michael@0: aInt->GetValue(&value); michael@0: michael@0: NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableOperate(&mInts, michael@0: &value, michael@0: PL_DHASH_LOOKUP)), michael@0: "int was never registered"); michael@0: michael@0: PL_DHashTableOperate(&mInts, &value, PL_DHASH_REMOVE); michael@0: michael@0: // N.B. that we _don't_ release the literal: we only held a weak michael@0: // reference to it in the hashtable. michael@0: PR_LOG(gLog, PR_LOG_DEBUG, michael@0: ("rdfserv unregister-int [%p] %d", michael@0: aInt, value)); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: nsresult michael@0: RDFServiceImpl::RegisterDate(nsIRDFDate* aDate) michael@0: { michael@0: PRTime value; michael@0: aDate->GetValue(&value); michael@0: michael@0: NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mDates, michael@0: &value, michael@0: PL_DHASH_LOOKUP)), michael@0: "date already registered"); michael@0: michael@0: PLDHashEntryHdr *hdr = michael@0: PL_DHashTableOperate(&mDates, &value, PL_DHASH_ADD); michael@0: michael@0: if (! hdr) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: DateHashEntry *entry = static_cast(hdr); michael@0: michael@0: // N.B., we only hold a weak reference to the literal: that michael@0: // way, the literal can be destroyed when the last refcount michael@0: // goes away. The single addref that the CreateDate() call michael@0: // made will be owned by the callee. michael@0: entry->mDate = aDate; michael@0: entry->mKey = value; michael@0: michael@0: PR_LOG(gLog, PR_LOG_DEBUG, michael@0: ("rdfserv register-date [%p] %ld", michael@0: aDate, value)); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: nsresult michael@0: RDFServiceImpl::UnregisterDate(nsIRDFDate* aDate) michael@0: { michael@0: PRTime value; michael@0: aDate->GetValue(&value); michael@0: michael@0: NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableOperate(&mDates, michael@0: &value, michael@0: PL_DHASH_LOOKUP)), michael@0: "date was never registered"); michael@0: michael@0: PL_DHashTableOperate(&mDates, &value, PL_DHASH_REMOVE); michael@0: michael@0: // N.B. that we _don't_ release the literal: we only held a weak michael@0: // reference to it in the hashtable. michael@0: PR_LOG(gLog, PR_LOG_DEBUG, michael@0: ("rdfserv unregister-date [%p] %ld", michael@0: aDate, value)); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: RDFServiceImpl::RegisterBlob(BlobImpl *aBlob) michael@0: { michael@0: NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mBlobs, michael@0: &aBlob->mData, michael@0: PL_DHASH_LOOKUP)), michael@0: "blob already registered"); michael@0: michael@0: PLDHashEntryHdr *hdr = michael@0: PL_DHashTableOperate(&mBlobs, &aBlob->mData, PL_DHASH_ADD); michael@0: michael@0: if (! hdr) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: BlobHashEntry *entry = static_cast(hdr); michael@0: michael@0: // N.B., we only hold a weak reference to the literal: that michael@0: // way, the literal can be destroyed when the last refcount michael@0: // goes away. The single addref that the CreateInt() call michael@0: // made will be owned by the callee. michael@0: entry->mBlob = aBlob; michael@0: michael@0: PR_LOG(gLog, PR_LOG_DEBUG, michael@0: ("rdfserv register-blob [%p] %s", michael@0: aBlob, aBlob->mData.mBytes)); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: RDFServiceImpl::UnregisterBlob(BlobImpl *aBlob) michael@0: { michael@0: NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableOperate(&mBlobs, michael@0: &aBlob->mData, michael@0: PL_DHASH_LOOKUP)), michael@0: "blob was never registered"); michael@0: michael@0: PL_DHashTableOperate(&mBlobs, &aBlob->mData, PL_DHASH_REMOVE); michael@0: michael@0: // N.B. that we _don't_ release the literal: we only held a weak michael@0: // reference to it in the hashtable. michael@0: PR_LOG(gLog, PR_LOG_DEBUG, michael@0: ("rdfserv unregister-blob [%p] %s", michael@0: aBlob, aBlob->mData.mBytes)); michael@0: michael@0: return NS_OK; michael@0: }