Bumping gaia.json for 2 gaia revision(s) a=gaia-bump
[gecko.git] / rdf / base / nsRDFService.cpp
blob8e6d133d2409e3dd6b66bfa45253dcdef5db9771
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 * This Original Code has been modified by IBM Corporation.
9 * Modifications made by IBM described herein are
10 * Copyright (c) International Business Machines
11 * Corporation, 2000
13 * Modifications to Mozilla code or documentation
14 * identified per MPL Section 3.3
16 * Date Modified by Description of modification
17 * 03/27/2000 IBM Corp. Added PR_CALLBACK for Optlink
18 * use in OS2
23 This file provides the implementation for the RDF service manager.
25 TO DO
26 -----
28 1) Implement the CreateDataBase() methods.
30 2) Cache date and int literals.
34 #include "nsRDFService.h"
35 #include "nsCOMPtr.h"
36 #include "nsAutoPtr.h"
37 #include "nsMemory.h"
38 #include "nsIAtom.h"
39 #include "nsIComponentManager.h"
40 #include "nsIRDFDataSource.h"
41 #include "nsIRDFNode.h"
42 #include "nsIRDFRemoteDataSource.h"
43 #include "nsIServiceManager.h"
44 #include "nsIFactory.h"
45 #include "nsRDFCID.h"
46 #include "nsString.h"
47 #include "nsXPIDLString.h"
48 #include "nsNetUtil.h"
49 #include "pldhash.h"
50 #include "plhash.h"
51 #include "plstr.h"
52 #include "prlog.h"
53 #include "prprf.h"
54 #include "prmem.h"
55 #include "rdf.h"
56 #include "nsCRT.h"
57 #include "nsCRTGlue.h"
58 #include "mozilla/HashFunctions.h"
60 using namespace mozilla;
62 ////////////////////////////////////////////////////////////////////////
64 static NS_DEFINE_CID(kRDFXMLDataSourceCID, NS_RDFXMLDATASOURCE_CID);
65 static NS_DEFINE_CID(kRDFDefaultResourceCID, NS_RDFDEFAULTRESOURCE_CID);
67 static NS_DEFINE_IID(kIRDFLiteralIID, NS_IRDFLITERAL_IID);
68 static NS_DEFINE_IID(kIRDFDateIID, NS_IRDFDATE_IID);
69 static NS_DEFINE_IID(kIRDFIntIID, NS_IRDFINT_IID);
70 static NS_DEFINE_IID(kIRDFNodeIID, NS_IRDFNODE_IID);
71 static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
73 #ifdef PR_LOGGING
74 static PRLogModuleInfo* gLog = nullptr;
75 #endif
77 class BlobImpl;
79 // These functions are copied from nsprpub/lib/ds/plhash.c, with one
80 // change to free the key in DataSourceFreeEntry.
81 // XXX sigh, why were DefaultAllocTable et. al. declared static, anyway?
83 static void *
84 DataSourceAllocTable(void *pool, size_t size)
86 return PR_MALLOC(size);
89 static void
90 DataSourceFreeTable(void *pool, void *item)
92 PR_Free(item);
95 static PLHashEntry *
96 DataSourceAllocEntry(void *pool, const void *key)
98 return PR_NEW(PLHashEntry);
101 static void
102 DataSourceFreeEntry(void *pool, PLHashEntry *he, unsigned flag)
104 if (flag == HT_FREE_ENTRY) {
105 PL_strfree((char*) he->key);
106 PR_Free(he);
110 static PLHashAllocOps dataSourceHashAllocOps = {
111 DataSourceAllocTable, DataSourceFreeTable,
112 DataSourceAllocEntry, DataSourceFreeEntry
115 //----------------------------------------------------------------------
117 // For the mResources hashtable.
120 struct ResourceHashEntry : public PLDHashEntryHdr {
121 const char *mKey;
122 nsIRDFResource *mResource;
124 static PLDHashNumber
125 HashKey(PLDHashTable *table, const void *key)
127 return HashString(static_cast<const char *>(key));
130 static bool
131 MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
132 const void *key)
134 const ResourceHashEntry *entry =
135 static_cast<const ResourceHashEntry *>(hdr);
137 return 0 == nsCRT::strcmp(static_cast<const char *>(key),
138 entry->mKey);
142 static const PLDHashTableOps gResourceTableOps = {
143 PL_DHashAllocTable,
144 PL_DHashFreeTable,
145 ResourceHashEntry::HashKey,
146 ResourceHashEntry::MatchEntry,
147 PL_DHashMoveEntryStub,
148 PL_DHashClearEntryStub,
149 PL_DHashFinalizeStub,
150 nullptr
153 // ----------------------------------------------------------------------
155 // For the mLiterals hashtable.
158 struct LiteralHashEntry : public PLDHashEntryHdr {
159 nsIRDFLiteral *mLiteral;
160 const char16_t *mKey;
162 static PLDHashNumber
163 HashKey(PLDHashTable *table, const void *key)
165 return HashString(static_cast<const char16_t *>(key));
168 static bool
169 MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
170 const void *key)
172 const LiteralHashEntry *entry =
173 static_cast<const LiteralHashEntry *>(hdr);
175 return 0 == nsCRT::strcmp(static_cast<const char16_t *>(key),
176 entry->mKey);
180 static const PLDHashTableOps gLiteralTableOps = {
181 PL_DHashAllocTable,
182 PL_DHashFreeTable,
183 LiteralHashEntry::HashKey,
184 LiteralHashEntry::MatchEntry,
185 PL_DHashMoveEntryStub,
186 PL_DHashClearEntryStub,
187 PL_DHashFinalizeStub,
188 nullptr
191 // ----------------------------------------------------------------------
193 // For the mInts hashtable.
196 struct IntHashEntry : public PLDHashEntryHdr {
197 nsIRDFInt *mInt;
198 int32_t mKey;
200 static PLDHashNumber
201 HashKey(PLDHashTable *table, const void *key)
203 return PLDHashNumber(*static_cast<const int32_t *>(key));
206 static bool
207 MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
208 const void *key)
210 const IntHashEntry *entry =
211 static_cast<const IntHashEntry *>(hdr);
213 return *static_cast<const int32_t *>(key) == entry->mKey;
217 static const PLDHashTableOps gIntTableOps = {
218 PL_DHashAllocTable,
219 PL_DHashFreeTable,
220 IntHashEntry::HashKey,
221 IntHashEntry::MatchEntry,
222 PL_DHashMoveEntryStub,
223 PL_DHashClearEntryStub,
224 PL_DHashFinalizeStub,
225 nullptr
228 // ----------------------------------------------------------------------
230 // For the mDates hashtable.
233 struct DateHashEntry : public PLDHashEntryHdr {
234 nsIRDFDate *mDate;
235 PRTime mKey;
237 static PLDHashNumber
238 HashKey(PLDHashTable *table, const void *key)
240 // xor the low 32 bits with the high 32 bits.
241 PRTime t = *static_cast<const PRTime *>(key);
242 int32_t h32 = int32_t(t >> 32);
243 int32_t l32 = int32_t(0xffffffff & t);
244 return PLDHashNumber(l32 ^ h32);
247 static bool
248 MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
249 const void *key)
251 const DateHashEntry *entry =
252 static_cast<const DateHashEntry *>(hdr);
254 return *static_cast<const PRTime *>(key) == entry->mKey;
258 static const PLDHashTableOps gDateTableOps = {
259 PL_DHashAllocTable,
260 PL_DHashFreeTable,
261 DateHashEntry::HashKey,
262 DateHashEntry::MatchEntry,
263 PL_DHashMoveEntryStub,
264 PL_DHashClearEntryStub,
265 PL_DHashFinalizeStub,
266 nullptr
269 class BlobImpl : public nsIRDFBlob
271 public:
272 struct Data {
273 int32_t mLength;
274 uint8_t *mBytes;
277 BlobImpl(const uint8_t *aBytes, int32_t aLength)
279 mData.mLength = aLength;
280 mData.mBytes = new uint8_t[aLength];
281 memcpy(mData.mBytes, aBytes, aLength);
282 NS_ADDREF(RDFServiceImpl::gRDFService);
283 RDFServiceImpl::gRDFService->RegisterBlob(this);
286 protected:
287 virtual ~BlobImpl()
289 RDFServiceImpl::gRDFService->UnregisterBlob(this);
290 // Use NS_RELEASE2() here, because we want to decrease the
291 // refcount, but not null out the gRDFService pointer (which is
292 // what a vanilla NS_RELEASE() would do).
293 nsrefcnt refcnt;
294 NS_RELEASE2(RDFServiceImpl::gRDFService, refcnt);
295 delete[] mData.mBytes;
298 public:
299 NS_DECL_ISUPPORTS
300 NS_DECL_NSIRDFNODE
301 NS_DECL_NSIRDFBLOB
303 Data mData;
306 NS_IMPL_ISUPPORTS(BlobImpl, nsIRDFNode, nsIRDFBlob)
308 NS_IMETHODIMP
309 BlobImpl::EqualsNode(nsIRDFNode *aNode, bool *aEquals)
311 nsCOMPtr<nsIRDFBlob> blob = do_QueryInterface(aNode);
312 if (blob) {
313 int32_t length;
314 blob->GetLength(&length);
316 if (length == mData.mLength) {
317 const uint8_t *bytes;
318 blob->GetValue(&bytes);
320 if (0 == memcmp(bytes, mData.mBytes, length)) {
321 *aEquals = true;
322 return NS_OK;
327 *aEquals = false;
328 return NS_OK;
331 NS_IMETHODIMP
332 BlobImpl::GetValue(const uint8_t **aResult)
334 *aResult = mData.mBytes;
335 return NS_OK;
338 NS_IMETHODIMP
339 BlobImpl::GetLength(int32_t *aResult)
341 *aResult = mData.mLength;
342 return NS_OK;
345 // ----------------------------------------------------------------------
347 // For the mBlobs hashtable.
350 struct BlobHashEntry : public PLDHashEntryHdr {
351 BlobImpl *mBlob;
353 static PLDHashNumber
354 HashKey(PLDHashTable *table, const void *key)
356 const BlobImpl::Data *data =
357 static_cast<const BlobImpl::Data *>(key);
358 return HashBytes(data->mBytes, data->mLength);
361 static bool
362 MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
363 const void *key)
365 const BlobHashEntry *entry =
366 static_cast<const BlobHashEntry *>(hdr);
368 const BlobImpl::Data *left = &entry->mBlob->mData;
370 const BlobImpl::Data *right =
371 static_cast<const BlobImpl::Data *>(key);
373 return (left->mLength == right->mLength)
374 && 0 == memcmp(left->mBytes, right->mBytes, right->mLength);
378 static const PLDHashTableOps gBlobTableOps = {
379 PL_DHashAllocTable,
380 PL_DHashFreeTable,
381 BlobHashEntry::HashKey,
382 BlobHashEntry::MatchEntry,
383 PL_DHashMoveEntryStub,
384 PL_DHashClearEntryStub,
385 PL_DHashFinalizeStub,
386 nullptr
389 ////////////////////////////////////////////////////////////////////////
390 // LiteralImpl
392 // Currently, all literals are implemented exactly the same way;
393 // i.e., there is are no resource factories to allow you to generate
394 // customer resources. I doubt that makes sense, anyway.
396 class LiteralImpl : public nsIRDFLiteral {
397 public:
398 static nsresult
399 Create(const char16_t* aValue, nsIRDFLiteral** aResult);
401 // nsISupports
402 NS_DECL_THREADSAFE_ISUPPORTS
404 // nsIRDFNode
405 NS_DECL_NSIRDFNODE
407 // nsIRDFLiteral
408 NS_DECL_NSIRDFLITERAL
410 protected:
411 explicit LiteralImpl(const char16_t* s);
412 virtual ~LiteralImpl();
414 const char16_t* GetValue() const {
415 size_t objectSize = ((sizeof(LiteralImpl) + sizeof(char16_t) - 1) / sizeof(char16_t)) * sizeof(char16_t);
416 return reinterpret_cast<const char16_t*>(reinterpret_cast<const unsigned char*>(this) + objectSize);
421 nsresult
422 LiteralImpl::Create(const char16_t* aValue, nsIRDFLiteral** aResult)
424 // Goofy math to get alignment right. Copied from nsSharedString.h.
425 size_t objectSize = ((sizeof(LiteralImpl) + sizeof(char16_t) - 1) / sizeof(char16_t)) * sizeof(char16_t);
426 size_t stringLen = nsCharTraits<char16_t>::length(aValue);
427 size_t stringSize = (stringLen + 1) * sizeof(char16_t);
429 void* objectPtr = operator new(objectSize + stringSize);
430 if (! objectPtr)
431 return NS_ERROR_NULL_POINTER;
433 char16_t* buf = reinterpret_cast<char16_t*>(static_cast<unsigned char*>(objectPtr) + objectSize);
434 nsCharTraits<char16_t>::copy(buf, aValue, stringLen + 1);
436 NS_ADDREF(*aResult = new (objectPtr) LiteralImpl(buf));
437 return NS_OK;
441 LiteralImpl::LiteralImpl(const char16_t* s)
443 RDFServiceImpl::gRDFService->RegisterLiteral(this);
444 NS_ADDREF(RDFServiceImpl::gRDFService);
447 LiteralImpl::~LiteralImpl()
449 RDFServiceImpl::gRDFService->UnregisterLiteral(this);
451 // Use NS_RELEASE2() here, because we want to decrease the
452 // refcount, but not null out the gRDFService pointer (which is
453 // what a vanilla NS_RELEASE() would do).
454 nsrefcnt refcnt;
455 NS_RELEASE2(RDFServiceImpl::gRDFService, refcnt);
458 NS_IMPL_ADDREF(LiteralImpl)
459 NS_IMPL_RELEASE(LiteralImpl)
461 nsresult
462 LiteralImpl::QueryInterface(REFNSIID iid, void** result)
464 if (! result)
465 return NS_ERROR_NULL_POINTER;
467 *result = nullptr;
468 if (iid.Equals(kIRDFLiteralIID) ||
469 iid.Equals(kIRDFNodeIID) ||
470 iid.Equals(kISupportsIID)) {
471 *result = static_cast<nsIRDFLiteral*>(this);
472 AddRef();
473 return NS_OK;
475 return NS_NOINTERFACE;
478 NS_IMETHODIMP
479 LiteralImpl::EqualsNode(nsIRDFNode* aNode, bool* aResult)
481 nsresult rv;
482 nsIRDFLiteral* literal;
483 rv = aNode->QueryInterface(kIRDFLiteralIID, (void**) &literal);
484 if (NS_SUCCEEDED(rv)) {
485 *aResult = (static_cast<nsIRDFLiteral*>(this) == literal);
486 NS_RELEASE(literal);
487 return NS_OK;
489 else if (rv == NS_NOINTERFACE) {
490 *aResult = false;
491 return NS_OK;
493 else {
494 return rv;
498 NS_IMETHODIMP
499 LiteralImpl::GetValue(char16_t* *value)
501 NS_ASSERTION(value, "null ptr");
502 if (! value)
503 return NS_ERROR_NULL_POINTER;
505 const char16_t *temp = GetValue();
506 *value = temp? NS_strdup(temp) : 0;
507 return NS_OK;
511 NS_IMETHODIMP
512 LiteralImpl::GetValueConst(const char16_t** aValue)
514 *aValue = GetValue();
515 return NS_OK;
518 ////////////////////////////////////////////////////////////////////////
519 // DateImpl
522 class DateImpl : public nsIRDFDate {
523 public:
524 explicit DateImpl(const PRTime s);
526 // nsISupports
527 NS_DECL_ISUPPORTS
529 // nsIRDFNode
530 NS_DECL_NSIRDFNODE
532 // nsIRDFDate
533 NS_IMETHOD GetValue(PRTime *value);
535 private:
536 virtual ~DateImpl();
538 nsresult EqualsDate(nsIRDFDate* date, bool* result);
539 PRTime mValue;
543 DateImpl::DateImpl(const PRTime s)
544 : mValue(s)
546 RDFServiceImpl::gRDFService->RegisterDate(this);
547 NS_ADDREF(RDFServiceImpl::gRDFService);
550 DateImpl::~DateImpl()
552 RDFServiceImpl::gRDFService->UnregisterDate(this);
554 // Use NS_RELEASE2() here, because we want to decrease the
555 // refcount, but not null out the gRDFService pointer (which is
556 // what a vanilla NS_RELEASE() would do).
557 nsrefcnt refcnt;
558 NS_RELEASE2(RDFServiceImpl::gRDFService, refcnt);
561 NS_IMPL_ADDREF(DateImpl)
562 NS_IMPL_RELEASE(DateImpl)
564 nsresult
565 DateImpl::QueryInterface(REFNSIID iid, void** result)
567 if (! result)
568 return NS_ERROR_NULL_POINTER;
570 *result = nullptr;
571 if (iid.Equals(kIRDFDateIID) ||
572 iid.Equals(kIRDFNodeIID) ||
573 iid.Equals(kISupportsIID)) {
574 *result = static_cast<nsIRDFDate*>(this);
575 AddRef();
576 return NS_OK;
578 return NS_NOINTERFACE;
581 NS_IMETHODIMP
582 DateImpl::EqualsNode(nsIRDFNode* node, bool* result)
584 nsresult rv;
585 nsIRDFDate* date;
586 if (NS_SUCCEEDED(node->QueryInterface(kIRDFDateIID, (void**) &date))) {
587 rv = EqualsDate(date, result);
588 NS_RELEASE(date);
590 else {
591 *result = false;
592 rv = NS_OK;
594 return rv;
597 NS_IMETHODIMP
598 DateImpl::GetValue(PRTime *value)
600 NS_ASSERTION(value, "null ptr");
601 if (! value)
602 return NS_ERROR_NULL_POINTER;
604 *value = mValue;
605 return NS_OK;
609 nsresult
610 DateImpl::EqualsDate(nsIRDFDate* date, bool* result)
612 NS_ASSERTION(date && result, "null ptr");
613 if (!date || !result)
614 return NS_ERROR_NULL_POINTER;
616 nsresult rv;
617 PRTime p;
618 if (NS_FAILED(rv = date->GetValue(&p)))
619 return rv;
621 *result = p == mValue;
622 return NS_OK;
625 ////////////////////////////////////////////////////////////////////////
626 // IntImpl
629 class IntImpl : public nsIRDFInt {
630 public:
631 explicit IntImpl(int32_t s);
633 // nsISupports
634 NS_DECL_ISUPPORTS
636 // nsIRDFNode
637 NS_DECL_NSIRDFNODE
639 // nsIRDFInt
640 NS_IMETHOD GetValue(int32_t *value);
642 private:
643 virtual ~IntImpl();
645 nsresult EqualsInt(nsIRDFInt* value, bool* result);
646 int32_t mValue;
650 IntImpl::IntImpl(int32_t s)
651 : mValue(s)
653 RDFServiceImpl::gRDFService->RegisterInt(this);
654 NS_ADDREF(RDFServiceImpl::gRDFService);
657 IntImpl::~IntImpl()
659 RDFServiceImpl::gRDFService->UnregisterInt(this);
661 // Use NS_RELEASE2() here, because we want to decrease the
662 // refcount, but not null out the gRDFService pointer (which is
663 // what a vanilla NS_RELEASE() would do).
664 nsrefcnt refcnt;
665 NS_RELEASE2(RDFServiceImpl::gRDFService, refcnt);
668 NS_IMPL_ADDREF(IntImpl)
669 NS_IMPL_RELEASE(IntImpl)
671 nsresult
672 IntImpl::QueryInterface(REFNSIID iid, void** result)
674 if (! result)
675 return NS_ERROR_NULL_POINTER;
677 *result = nullptr;
678 if (iid.Equals(kIRDFIntIID) ||
679 iid.Equals(kIRDFNodeIID) ||
680 iid.Equals(kISupportsIID)) {
681 *result = static_cast<nsIRDFInt*>(this);
682 AddRef();
683 return NS_OK;
685 return NS_NOINTERFACE;
688 NS_IMETHODIMP
689 IntImpl::EqualsNode(nsIRDFNode* node, bool* result)
691 nsresult rv;
692 nsIRDFInt* intValue;
693 if (NS_SUCCEEDED(node->QueryInterface(kIRDFIntIID, (void**) &intValue))) {
694 rv = EqualsInt(intValue, result);
695 NS_RELEASE(intValue);
697 else {
698 *result = false;
699 rv = NS_OK;
701 return rv;
704 NS_IMETHODIMP
705 IntImpl::GetValue(int32_t *value)
707 NS_ASSERTION(value, "null ptr");
708 if (! value)
709 return NS_ERROR_NULL_POINTER;
711 *value = mValue;
712 return NS_OK;
716 nsresult
717 IntImpl::EqualsInt(nsIRDFInt* intValue, bool* result)
719 NS_ASSERTION(intValue && result, "null ptr");
720 if (!intValue || !result)
721 return NS_ERROR_NULL_POINTER;
723 nsresult rv;
724 int32_t p;
725 if (NS_FAILED(rv = intValue->GetValue(&p)))
726 return rv;
728 *result = (p == mValue);
729 return NS_OK;
732 ////////////////////////////////////////////////////////////////////////
733 // RDFServiceImpl
735 RDFServiceImpl*
736 RDFServiceImpl::gRDFService;
738 RDFServiceImpl::RDFServiceImpl()
739 : mNamedDataSources(nullptr)
741 mResources.ops = nullptr;
742 mLiterals.ops = nullptr;
743 mInts.ops = nullptr;
744 mDates.ops = nullptr;
745 mBlobs.ops = nullptr;
746 gRDFService = this;
749 nsresult
750 RDFServiceImpl::Init()
752 nsresult rv;
754 mNamedDataSources = PL_NewHashTable(23,
755 PL_HashString,
756 PL_CompareStrings,
757 PL_CompareValues,
758 &dataSourceHashAllocOps, nullptr);
760 if (! mNamedDataSources)
761 return NS_ERROR_OUT_OF_MEMORY;
763 PL_DHashTableInit(&mResources, &gResourceTableOps, nullptr,
764 sizeof(ResourceHashEntry));
766 PL_DHashTableInit(&mLiterals, &gLiteralTableOps, nullptr,
767 sizeof(LiteralHashEntry));
769 PL_DHashTableInit(&mInts, &gIntTableOps, nullptr,
770 sizeof(IntHashEntry));
772 PL_DHashTableInit(&mDates, &gDateTableOps, nullptr,
773 sizeof(DateHashEntry));
775 PL_DHashTableInit(&mBlobs, &gBlobTableOps, nullptr,
776 sizeof(BlobHashEntry));
778 mDefaultResourceFactory = do_GetClassObject(kRDFDefaultResourceCID, &rv);
779 NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get default resource factory");
780 if (NS_FAILED(rv)) return rv;
782 #ifdef PR_LOGGING
783 if (! gLog)
784 gLog = PR_NewLogModule("nsRDFService");
785 #endif
787 return NS_OK;
791 RDFServiceImpl::~RDFServiceImpl()
793 if (mNamedDataSources) {
794 PL_HashTableDestroy(mNamedDataSources);
795 mNamedDataSources = nullptr;
797 if (mResources.ops)
798 PL_DHashTableFinish(&mResources);
799 if (mLiterals.ops)
800 PL_DHashTableFinish(&mLiterals);
801 if (mInts.ops)
802 PL_DHashTableFinish(&mInts);
803 if (mDates.ops)
804 PL_DHashTableFinish(&mDates);
805 if (mBlobs.ops)
806 PL_DHashTableFinish(&mBlobs);
807 gRDFService = nullptr;
811 // static
812 nsresult
813 RDFServiceImpl::CreateSingleton(nsISupports* aOuter,
814 const nsIID& aIID, void **aResult)
816 NS_ENSURE_NO_AGGREGATION(aOuter);
818 if (gRDFService) {
819 NS_ERROR("Trying to create RDF serviec twice.");
820 return gRDFService->QueryInterface(aIID, aResult);
823 nsRefPtr<RDFServiceImpl> serv = new RDFServiceImpl();
824 if (!serv)
825 return NS_ERROR_OUT_OF_MEMORY;
827 nsresult rv = serv->Init();
828 if (NS_FAILED(rv))
829 return rv;
831 return serv->QueryInterface(aIID, aResult);
834 NS_IMPL_ISUPPORTS(RDFServiceImpl, nsIRDFService, nsISupportsWeakReference)
836 // Per RFC2396.
837 static const uint8_t
838 kLegalSchemeChars[] = {
839 // ASCII Bits Ordered Hex
840 // 01234567 76543210
841 0x00, // 00-07
842 0x00, // 08-0F
843 0x00, // 10-17
844 0x00, // 18-1F
845 0x00, // 20-27 !"#$%&' 00000000 00000000
846 0x28, // 28-2F ()*+,-./ 00010100 00101000 0x28
847 0xff, // 30-37 01234567 11111111 11111111 0xFF
848 0x03, // 38-3F 89:;<=>? 11000000 00000011 0x03
849 0xfe, // 40-47 @ABCDEFG 01111111 11111110 0xFE
850 0xff, // 48-4F HIJKLMNO 11111111 11111111 0xFF
851 0xff, // 50-57 PQRSTUVW 11111111 11111111 0xFF
852 0x87, // 58-5F XYZ[\]^_ 11100001 10000111 0x87
853 0xfe, // 60-67 `abcdefg 01111111 11111110 0xFE
854 0xff, // 68-6F hijklmno 11111111 11111111 0xFF
855 0xff, // 70-77 pqrstuvw 11111111 11111111 0xFF
856 0x07, // 78-7F xyz{|}~ 11100000 00000111 0x07
857 0x00, 0x00, 0x00, 0x00, // >= 80
858 0x00, 0x00, 0x00, 0x00,
859 0x00, 0x00, 0x00, 0x00,
860 0x00, 0x00, 0x00, 0x00
863 static inline bool
864 IsLegalSchemeCharacter(const char aChar)
866 uint8_t mask = kLegalSchemeChars[aChar >> 3];
867 uint8_t bit = 1u << (aChar & 0x7);
868 return bool((mask & bit) != 0);
872 NS_IMETHODIMP
873 RDFServiceImpl::GetResource(const nsACString& aURI, nsIRDFResource** aResource)
875 // Sanity checks
876 NS_PRECONDITION(aResource != nullptr, "null ptr");
877 NS_PRECONDITION(!aURI.IsEmpty(), "URI is empty");
878 if (! aResource)
879 return NS_ERROR_NULL_POINTER;
880 if (aURI.IsEmpty())
881 return NS_ERROR_INVALID_ARG;
883 const nsAFlatCString& flatURI = PromiseFlatCString(aURI);
884 PR_LOG(gLog, PR_LOG_DEBUG, ("rdfserv get-resource %s", flatURI.get()));
886 // First, check the cache to see if we've already created and
887 // registered this thing.
888 PLDHashEntryHdr *hdr =
889 PL_DHashTableLookup(&mResources, flatURI.get());
891 if (PL_DHASH_ENTRY_IS_BUSY(hdr)) {
892 ResourceHashEntry *entry = static_cast<ResourceHashEntry *>(hdr);
893 NS_ADDREF(*aResource = entry->mResource);
894 return NS_OK;
897 // Nope. So go to the repository to create it.
899 // Compute the scheme of the URI. Scan forward until we either:
901 // 1. Reach the end of the string
902 // 2. Encounter a non-alpha character
903 // 3. Encouter a colon.
905 // If we encounter a colon _before_ encountering a non-alpha
906 // character, then assume it's the scheme.
908 // XXX Although it's really not correct, we'll allow underscore
909 // characters ('_'), too.
910 nsACString::const_iterator p, end;
911 aURI.BeginReading(p);
912 aURI.EndReading(end);
913 while (p != end && IsLegalSchemeCharacter(*p))
914 ++p;
916 nsresult rv;
917 nsCOMPtr<nsIFactory> factory;
919 nsACString::const_iterator begin;
920 aURI.BeginReading(begin);
921 if (*p == ':') {
922 // There _was_ a scheme. First see if it's the same scheme
923 // that we just tried to use...
924 if (mLastFactory && mLastURIPrefix.Equals(Substring(begin, p)))
925 factory = mLastFactory;
926 else {
927 // Try to find a factory using the component manager.
928 nsACString::const_iterator begin;
929 aURI.BeginReading(begin);
930 nsAutoCString contractID;
931 contractID = NS_LITERAL_CSTRING(NS_RDF_RESOURCE_FACTORY_CONTRACTID_PREFIX) +
932 Substring(begin, p);
934 factory = do_GetClassObject(contractID.get());
935 if (factory) {
936 // Store the factory in our one-element cache.
937 if (p != begin) {
938 mLastFactory = factory;
939 mLastURIPrefix = Substring(begin, p);
945 if (! factory) {
946 // fall through to using the "default" resource factory if either:
948 // 1. The URI didn't have a scheme, or
949 // 2. There was no resource factory registered for the scheme.
950 factory = mDefaultResourceFactory;
952 // Store the factory in our one-element cache.
953 if (p != begin) {
954 mLastFactory = factory;
955 mLastURIPrefix = Substring(begin, p);
959 nsIRDFResource *result;
960 rv = factory->CreateInstance(nullptr, NS_GET_IID(nsIRDFResource), (void**) &result);
961 if (NS_FAILED(rv)) return rv;
963 // Now initialize it with its URI. At this point, the resource
964 // implementation should register itself with the RDF service.
965 rv = result->Init(flatURI.get());
966 if (NS_FAILED(rv)) {
967 NS_ERROR("unable to initialize resource");
968 NS_RELEASE(result);
969 return rv;
972 *aResource = result; // already refcounted from repository
973 return rv;
976 NS_IMETHODIMP
977 RDFServiceImpl::GetUnicodeResource(const nsAString& aURI, nsIRDFResource** aResource)
979 return GetResource(NS_ConvertUTF16toUTF8(aURI), aResource);
983 NS_IMETHODIMP
984 RDFServiceImpl::GetAnonymousResource(nsIRDFResource** aResult)
986 static uint32_t gCounter = 0;
987 static char gChars[] = "0123456789abcdef"
988 "ghijklmnopqrstuv"
989 "wxyzABCDEFGHIJKL"
990 "MNOPQRSTUVWXYZ.+";
992 static int32_t kMask = 0x003f;
993 static int32_t kShift = 6;
995 if (! gCounter) {
996 // Start it at a semi-unique value, just to minimize the
997 // chance that we get into a situation where
999 // 1. An anonymous resource gets serialized out in a graph
1000 // 2. Reboot
1001 // 3. The same anonymous resource gets requested, and refers
1002 // to something completely different.
1003 // 4. The serialization is read back in.
1004 gCounter = uint32_t(PR_Now());
1007 nsresult rv;
1008 nsAutoCString s;
1010 do {
1011 // Ugh, this is a really sloppy way to do this; I copied the
1012 // implementation from the days when it lived outside the RDF
1013 // service. Now that it's a member we can be more cleverer.
1015 s.Truncate();
1016 s.AppendLiteral("rdf:#$");
1018 uint32_t id = ++gCounter;
1019 while (id) {
1020 char ch = gChars[(id & kMask)];
1021 s.Append(ch);
1022 id >>= kShift;
1025 nsIRDFResource* resource;
1026 rv = GetResource(s, &resource);
1027 if (NS_FAILED(rv)) return rv;
1029 // XXX an ugly but effective way to make sure that this
1030 // resource is really unique in the world.
1031 resource->AddRef();
1032 nsrefcnt refcnt = resource->Release();
1034 if (refcnt == 1) {
1035 *aResult = resource;
1036 break;
1039 NS_RELEASE(resource);
1040 } while (1);
1042 return NS_OK;
1046 NS_IMETHODIMP
1047 RDFServiceImpl::GetLiteral(const char16_t* aValue, nsIRDFLiteral** aLiteral)
1049 NS_PRECONDITION(aValue != nullptr, "null ptr");
1050 if (! aValue)
1051 return NS_ERROR_NULL_POINTER;
1053 NS_PRECONDITION(aLiteral != nullptr, "null ptr");
1054 if (! aLiteral)
1055 return NS_ERROR_NULL_POINTER;
1057 // See if we have one already cached
1058 PLDHashEntryHdr *hdr =
1059 PL_DHashTableLookup(&mLiterals, aValue);
1061 if (PL_DHASH_ENTRY_IS_BUSY(hdr)) {
1062 LiteralHashEntry *entry = static_cast<LiteralHashEntry *>(hdr);
1063 NS_ADDREF(*aLiteral = entry->mLiteral);
1064 return NS_OK;
1067 // Nope. Create a new one
1068 return LiteralImpl::Create(aValue, aLiteral);
1071 NS_IMETHODIMP
1072 RDFServiceImpl::GetDateLiteral(PRTime aTime, nsIRDFDate** aResult)
1074 // See if we have one already cached
1075 PLDHashEntryHdr *hdr =
1076 PL_DHashTableLookup(&mDates, &aTime);
1078 if (PL_DHASH_ENTRY_IS_BUSY(hdr)) {
1079 DateHashEntry *entry = static_cast<DateHashEntry *>(hdr);
1080 NS_ADDREF(*aResult = entry->mDate);
1081 return NS_OK;
1084 DateImpl* result = new DateImpl(aTime);
1085 if (! result)
1086 return NS_ERROR_OUT_OF_MEMORY;
1088 NS_ADDREF(*aResult = result);
1089 return NS_OK;
1092 NS_IMETHODIMP
1093 RDFServiceImpl::GetIntLiteral(int32_t aInt, nsIRDFInt** aResult)
1095 // See if we have one already cached
1096 PLDHashEntryHdr *hdr =
1097 PL_DHashTableLookup(&mInts, &aInt);
1099 if (PL_DHASH_ENTRY_IS_BUSY(hdr)) {
1100 IntHashEntry *entry = static_cast<IntHashEntry *>(hdr);
1101 NS_ADDREF(*aResult = entry->mInt);
1102 return NS_OK;
1105 IntImpl* result = new IntImpl(aInt);
1106 if (! result)
1107 return NS_ERROR_OUT_OF_MEMORY;
1109 NS_ADDREF(*aResult = result);
1110 return NS_OK;
1113 NS_IMETHODIMP
1114 RDFServiceImpl::GetBlobLiteral(const uint8_t *aBytes, int32_t aLength,
1115 nsIRDFBlob **aResult)
1117 BlobImpl::Data key = { aLength, const_cast<uint8_t *>(aBytes) };
1119 PLDHashEntryHdr *hdr =
1120 PL_DHashTableLookup(&mBlobs, &key);
1122 if (PL_DHASH_ENTRY_IS_BUSY(hdr)) {
1123 BlobHashEntry *entry = static_cast<BlobHashEntry *>(hdr);
1124 NS_ADDREF(*aResult = entry->mBlob);
1125 return NS_OK;
1128 BlobImpl *result = new BlobImpl(aBytes, aLength);
1129 if (! result)
1130 return NS_ERROR_OUT_OF_MEMORY;
1132 NS_ADDREF(*aResult = result);
1133 return NS_OK;
1136 NS_IMETHODIMP
1137 RDFServiceImpl::IsAnonymousResource(nsIRDFResource* aResource, bool* _result)
1139 NS_PRECONDITION(aResource != nullptr, "null ptr");
1140 if (! aResource)
1141 return NS_ERROR_NULL_POINTER;
1143 nsresult rv;
1145 const char* uri;
1146 rv = aResource->GetValueConst(&uri);
1147 if (NS_FAILED(rv)) return rv;
1149 if ((uri[0] == 'r') &&
1150 (uri[1] == 'd') &&
1151 (uri[2] == 'f') &&
1152 (uri[3] == ':') &&
1153 (uri[4] == '#') &&
1154 (uri[5] == '$')) {
1155 *_result = true;
1157 else {
1158 *_result = false;
1161 return NS_OK;
1164 NS_IMETHODIMP
1165 RDFServiceImpl::RegisterResource(nsIRDFResource* aResource, bool aReplace)
1167 NS_PRECONDITION(aResource != nullptr, "null ptr");
1168 if (! aResource)
1169 return NS_ERROR_NULL_POINTER;
1171 nsresult rv;
1173 const char* uri;
1174 rv = aResource->GetValueConst(&uri);
1175 NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get URI from resource");
1176 if (NS_FAILED(rv)) return rv;
1178 NS_ASSERTION(uri != nullptr, "resource has no URI");
1179 if (! uri)
1180 return NS_ERROR_NULL_POINTER;
1182 PLDHashEntryHdr *hdr =
1183 PL_DHashTableLookup(&mResources, uri);
1185 if (PL_DHASH_ENTRY_IS_BUSY(hdr)) {
1186 if (!aReplace) {
1187 NS_WARNING("resource already registered, and replace not specified");
1188 return NS_ERROR_FAILURE; // already registered
1191 // N.B., we do _not_ release the original resource because we
1192 // only ever held a weak reference to it. We simply replace
1193 // it.
1195 PR_LOG(gLog, PR_LOG_DEBUG,
1196 ("rdfserv replace-resource [%p] <-- [%p] %s",
1197 static_cast<ResourceHashEntry *>(hdr)->mResource,
1198 aResource, (const char*) uri));
1200 else {
1201 hdr = PL_DHashTableAdd(&mResources, uri);
1202 if (! hdr)
1203 return NS_ERROR_OUT_OF_MEMORY;
1205 PR_LOG(gLog, PR_LOG_DEBUG,
1206 ("rdfserv register-resource [%p] %s",
1207 aResource, (const char*) uri));
1210 // N.B., we only hold a weak reference to the resource: that way,
1211 // the resource can be destroyed when the last refcount goes
1212 // away. The single addref that the CreateResource() call made
1213 // will be owned by the callee.
1214 ResourceHashEntry *entry = static_cast<ResourceHashEntry *>(hdr);
1215 entry->mResource = aResource;
1216 entry->mKey = uri;
1218 return NS_OK;
1221 NS_IMETHODIMP
1222 RDFServiceImpl::UnregisterResource(nsIRDFResource* aResource)
1224 NS_PRECONDITION(aResource != nullptr, "null ptr");
1225 if (! aResource)
1226 return NS_ERROR_NULL_POINTER;
1228 nsresult rv;
1230 const char* uri;
1231 rv = aResource->GetValueConst(&uri);
1232 if (NS_FAILED(rv)) return rv;
1234 NS_ASSERTION(uri != nullptr, "resource has no URI");
1235 if (! uri)
1236 return NS_ERROR_UNEXPECTED;
1238 PR_LOG(gLog, PR_LOG_DEBUG,
1239 ("rdfserv unregister-resource [%p] %s",
1240 aResource, (const char*) uri));
1242 #ifdef DEBUG
1243 if (PL_DHASH_ENTRY_IS_FREE(PL_DHashTableLookup(&mResources, uri)))
1244 NS_WARNING("resource was never registered");
1245 #endif
1247 PL_DHashTableRemove(&mResources, uri);
1248 return NS_OK;
1251 NS_IMETHODIMP
1252 RDFServiceImpl::RegisterDataSource(nsIRDFDataSource* aDataSource, bool aReplace)
1254 NS_PRECONDITION(aDataSource != nullptr, "null ptr");
1255 if (! aDataSource)
1256 return NS_ERROR_NULL_POINTER;
1258 nsresult rv;
1260 nsXPIDLCString uri;
1261 rv = aDataSource->GetURI(getter_Copies(uri));
1262 if (NS_FAILED(rv)) return rv;
1264 PLHashEntry** hep =
1265 PL_HashTableRawLookup(mNamedDataSources, (*mNamedDataSources->keyHash)(uri), uri);
1267 if (*hep) {
1268 if (! aReplace)
1269 return NS_ERROR_FAILURE; // already registered
1271 // N.B., we only hold a weak reference to the datasource, so
1272 // just replace the old with the new and don't touch any
1273 // refcounts.
1274 PR_LOG(gLog, PR_LOG_NOTICE,
1275 ("rdfserv replace-datasource [%p] <-- [%p] %s",
1276 (*hep)->value, aDataSource, (const char*) uri));
1278 (*hep)->value = aDataSource;
1280 else {
1281 const char* key = PL_strdup(uri);
1282 if (! key)
1283 return NS_ERROR_OUT_OF_MEMORY;
1285 PL_HashTableAdd(mNamedDataSources, key, aDataSource);
1287 PR_LOG(gLog, PR_LOG_NOTICE,
1288 ("rdfserv register-datasource [%p] %s",
1289 aDataSource, (const char*) uri));
1291 // N.B., we only hold a weak reference to the datasource, so don't
1292 // addref.
1295 return NS_OK;
1298 NS_IMETHODIMP
1299 RDFServiceImpl::UnregisterDataSource(nsIRDFDataSource* aDataSource)
1301 NS_PRECONDITION(aDataSource != nullptr, "null ptr");
1302 if (! aDataSource)
1303 return NS_ERROR_NULL_POINTER;
1305 nsresult rv;
1307 nsXPIDLCString uri;
1308 rv = aDataSource->GetURI(getter_Copies(uri));
1309 if (NS_FAILED(rv)) return rv;
1311 //NS_ASSERTION(uri != nullptr, "datasource has no URI");
1312 if (! uri)
1313 return NS_ERROR_UNEXPECTED;
1315 PLHashEntry** hep =
1316 PL_HashTableRawLookup(mNamedDataSources, (*mNamedDataSources->keyHash)(uri), uri);
1318 // It may well be that this datasource was never registered. If
1319 // so, don't unregister it.
1320 if (! *hep || ((*hep)->value != aDataSource))
1321 return NS_OK;
1323 // N.B., we only held a weak reference to the datasource, so we
1324 // don't release here.
1325 PL_HashTableRawRemove(mNamedDataSources, hep, *hep);
1327 PR_LOG(gLog, PR_LOG_NOTICE,
1328 ("rdfserv unregister-datasource [%p] %s",
1329 aDataSource, (const char*) uri));
1331 return NS_OK;
1334 NS_IMETHODIMP
1335 RDFServiceImpl::GetDataSource(const char* aURI, nsIRDFDataSource** aDataSource)
1337 // Use the other GetDataSource and ask for a non-blocking Refresh.
1338 // If you wanted it loaded synchronously, then you should've tried to do it
1339 // yourself, or used GetDataSourceBlocking.
1340 return GetDataSource( aURI, false, aDataSource );
1343 NS_IMETHODIMP
1344 RDFServiceImpl::GetDataSourceBlocking(const char* aURI, nsIRDFDataSource** aDataSource)
1346 // Use GetDataSource and ask for a blocking Refresh.
1347 return GetDataSource( aURI, true, aDataSource );
1350 nsresult
1351 RDFServiceImpl::GetDataSource(const char* aURI, bool aBlock, nsIRDFDataSource** aDataSource)
1353 NS_PRECONDITION(aURI != nullptr, "null ptr");
1354 if (! aURI)
1355 return NS_ERROR_NULL_POINTER;
1357 nsresult rv;
1359 // Attempt to canonify the URI before we look for it in the
1360 // cache. We won't bother doing this on `rdf:' URIs to avoid
1361 // useless (and expensive) protocol handler lookups.
1362 nsAutoCString spec(aURI);
1364 if (!StringBeginsWith(spec, NS_LITERAL_CSTRING("rdf:"))) {
1365 nsCOMPtr<nsIURI> uri;
1366 NS_NewURI(getter_AddRefs(uri), spec);
1367 if (uri)
1368 uri->GetSpec(spec);
1371 // First, check the cache to see if we already have this
1372 // datasource loaded and initialized.
1374 nsIRDFDataSource* cached =
1375 static_cast<nsIRDFDataSource*>(PL_HashTableLookup(mNamedDataSources, spec.get()));
1377 if (cached) {
1378 NS_ADDREF(cached);
1379 *aDataSource = cached;
1380 return NS_OK;
1384 // Nope. So go to the repository to try to create it.
1385 nsCOMPtr<nsIRDFDataSource> ds;
1386 if (StringBeginsWith(spec, NS_LITERAL_CSTRING("rdf:"))) {
1387 // It's a built-in data source. Convert it to a contract ID.
1388 nsAutoCString contractID(
1389 NS_LITERAL_CSTRING(NS_RDF_DATASOURCE_CONTRACTID_PREFIX) +
1390 Substring(spec, 4, spec.Length() - 4));
1392 // Strip params to get ``base'' contractID for data source.
1393 int32_t p = contractID.FindChar(char16_t('&'));
1394 if (p >= 0)
1395 contractID.Truncate(p);
1397 ds = do_GetService(contractID.get(), &rv);
1398 if (NS_FAILED(rv)) return rv;
1400 nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(ds);
1401 if (remote) {
1402 rv = remote->Init(spec.get());
1403 if (NS_FAILED(rv)) return rv;
1406 else {
1407 // Try to load this as an RDF/XML data source
1408 ds = do_CreateInstance(kRDFXMLDataSourceCID, &rv);
1409 if (NS_FAILED(rv)) return rv;
1411 nsCOMPtr<nsIRDFRemoteDataSource> remote(do_QueryInterface(ds));
1412 NS_ASSERTION(remote, "not a remote RDF/XML data source!");
1413 if (! remote) return NS_ERROR_UNEXPECTED;
1415 rv = remote->Init(spec.get());
1416 if (NS_FAILED(rv)) return rv;
1418 rv = remote->Refresh(aBlock);
1419 if (NS_FAILED(rv)) return rv;
1422 *aDataSource = ds;
1423 NS_ADDREF(*aDataSource);
1424 return NS_OK;
1427 ////////////////////////////////////////////////////////////////////////
1429 nsresult
1430 RDFServiceImpl::RegisterLiteral(nsIRDFLiteral* aLiteral)
1432 const char16_t* value;
1433 aLiteral->GetValueConst(&value);
1435 NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableLookup(&mLiterals,
1436 value)),
1437 "literal already registered");
1439 PLDHashEntryHdr *hdr =
1440 PL_DHashTableAdd(&mLiterals, value);
1442 if (! hdr)
1443 return NS_ERROR_OUT_OF_MEMORY;
1445 LiteralHashEntry *entry = static_cast<LiteralHashEntry *>(hdr);
1447 // N.B., we only hold a weak reference to the literal: that
1448 // way, the literal can be destroyed when the last refcount
1449 // goes away. The single addref that the CreateLiteral() call
1450 // made will be owned by the callee.
1451 entry->mLiteral = aLiteral;
1452 entry->mKey = value;
1454 PR_LOG(gLog, PR_LOG_DEBUG,
1455 ("rdfserv register-literal [%p] %s",
1456 aLiteral, (const char16_t*) value));
1458 return NS_OK;
1462 nsresult
1463 RDFServiceImpl::UnregisterLiteral(nsIRDFLiteral* aLiteral)
1465 const char16_t* value;
1466 aLiteral->GetValueConst(&value);
1468 NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableLookup(&mLiterals,
1469 value)),
1470 "literal was never registered");
1472 PL_DHashTableRemove(&mLiterals, value);
1474 // N.B. that we _don't_ release the literal: we only held a weak
1475 // reference to it in the hashtable.
1476 PR_LOG(gLog, PR_LOG_DEBUG,
1477 ("rdfserv unregister-literal [%p] %s",
1478 aLiteral, (const char16_t*) value));
1480 return NS_OK;
1483 //----------------------------------------------------------------------
1485 nsresult
1486 RDFServiceImpl::RegisterInt(nsIRDFInt* aInt)
1488 int32_t value;
1489 aInt->GetValue(&value);
1491 NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableLookup(&mInts,
1492 &value)),
1493 "int already registered");
1495 PLDHashEntryHdr *hdr =
1496 PL_DHashTableAdd(&mInts, &value);
1498 if (! hdr)
1499 return NS_ERROR_OUT_OF_MEMORY;
1501 IntHashEntry *entry = static_cast<IntHashEntry *>(hdr);
1503 // N.B., we only hold a weak reference to the literal: that
1504 // way, the literal can be destroyed when the last refcount
1505 // goes away. The single addref that the CreateInt() call
1506 // made will be owned by the callee.
1507 entry->mInt = aInt;
1508 entry->mKey = value;
1510 PR_LOG(gLog, PR_LOG_DEBUG,
1511 ("rdfserv register-int [%p] %d",
1512 aInt, value));
1514 return NS_OK;
1518 nsresult
1519 RDFServiceImpl::UnregisterInt(nsIRDFInt* aInt)
1521 int32_t value;
1522 aInt->GetValue(&value);
1524 NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableLookup(&mInts,
1525 &value)),
1526 "int was never registered");
1528 PL_DHashTableRemove(&mInts, &value);
1530 // N.B. that we _don't_ release the literal: we only held a weak
1531 // reference to it in the hashtable.
1532 PR_LOG(gLog, PR_LOG_DEBUG,
1533 ("rdfserv unregister-int [%p] %d",
1534 aInt, value));
1536 return NS_OK;
1539 //----------------------------------------------------------------------
1541 nsresult
1542 RDFServiceImpl::RegisterDate(nsIRDFDate* aDate)
1544 PRTime value;
1545 aDate->GetValue(&value);
1547 NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableLookup(&mDates,
1548 &value)),
1549 "date already registered");
1551 PLDHashEntryHdr *hdr =
1552 PL_DHashTableAdd(&mDates, &value);
1554 if (! hdr)
1555 return NS_ERROR_OUT_OF_MEMORY;
1557 DateHashEntry *entry = static_cast<DateHashEntry *>(hdr);
1559 // N.B., we only hold a weak reference to the literal: that
1560 // way, the literal can be destroyed when the last refcount
1561 // goes away. The single addref that the CreateDate() call
1562 // made will be owned by the callee.
1563 entry->mDate = aDate;
1564 entry->mKey = value;
1566 PR_LOG(gLog, PR_LOG_DEBUG,
1567 ("rdfserv register-date [%p] %ld",
1568 aDate, value));
1570 return NS_OK;
1574 nsresult
1575 RDFServiceImpl::UnregisterDate(nsIRDFDate* aDate)
1577 PRTime value;
1578 aDate->GetValue(&value);
1580 NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableLookup(&mDates,
1581 &value)),
1582 "date was never registered");
1584 PL_DHashTableRemove(&mDates, &value);
1586 // N.B. that we _don't_ release the literal: we only held a weak
1587 // reference to it in the hashtable.
1588 PR_LOG(gLog, PR_LOG_DEBUG,
1589 ("rdfserv unregister-date [%p] %ld",
1590 aDate, value));
1592 return NS_OK;
1595 nsresult
1596 RDFServiceImpl::RegisterBlob(BlobImpl *aBlob)
1598 NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableLookup(&mBlobs,
1599 &aBlob->mData)),
1600 "blob already registered");
1602 PLDHashEntryHdr *hdr =
1603 PL_DHashTableAdd(&mBlobs, &aBlob->mData);
1605 if (! hdr)
1606 return NS_ERROR_OUT_OF_MEMORY;
1608 BlobHashEntry *entry = static_cast<BlobHashEntry *>(hdr);
1610 // N.B., we only hold a weak reference to the literal: that
1611 // way, the literal can be destroyed when the last refcount
1612 // goes away. The single addref that the CreateInt() call
1613 // made will be owned by the callee.
1614 entry->mBlob = aBlob;
1616 PR_LOG(gLog, PR_LOG_DEBUG,
1617 ("rdfserv register-blob [%p] %s",
1618 aBlob, aBlob->mData.mBytes));
1620 return NS_OK;
1623 nsresult
1624 RDFServiceImpl::UnregisterBlob(BlobImpl *aBlob)
1626 NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableLookup(&mBlobs,
1627 &aBlob->mData)),
1628 "blob was never registered");
1630 PL_DHashTableRemove(&mBlobs, &aBlob->mData);
1632 // N.B. that we _don't_ release the literal: we only held a weak
1633 // reference to it in the hashtable.
1634 PR_LOG(gLog, PR_LOG_DEBUG,
1635 ("rdfserv unregister-blob [%p] %s",
1636 aBlob, aBlob->mData.mBytes));
1638 return NS_OK;