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