rdf/base/src/nsRDFService.cpp

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:492018812ece
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 *
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/.
6 *
7 *
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
12 *
13 * Modifications to Mozilla code or documentation
14 * identified per MPL Section 3.3
15 *
16 * Date Modified by Description of modification
17 * 03/27/2000 IBM Corp. Added PR_CALLBACK for Optlink
18 * use in OS2
19 */
20
21 /*
22
23 This file provides the implementation for the RDF service manager.
24
25 TO DO
26 -----
27
28 1) Implement the CreateDataBase() methods.
29
30 2) Cache date and int literals.
31
32 */
33
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"
59
60 using namespace mozilla;
61
62 ////////////////////////////////////////////////////////////////////////
63
64 static NS_DEFINE_CID(kRDFXMLDataSourceCID, NS_RDFXMLDATASOURCE_CID);
65 static NS_DEFINE_CID(kRDFDefaultResourceCID, NS_RDFDEFAULTRESOURCE_CID);
66
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);
72
73 #ifdef PR_LOGGING
74 static PRLogModuleInfo* gLog = nullptr;
75 #endif
76
77 class BlobImpl;
78
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?
82
83 static void *
84 DataSourceAllocTable(void *pool, size_t size)
85 {
86 return PR_MALLOC(size);
87 }
88
89 static void
90 DataSourceFreeTable(void *pool, void *item)
91 {
92 PR_Free(item);
93 }
94
95 static PLHashEntry *
96 DataSourceAllocEntry(void *pool, const void *key)
97 {
98 return PR_NEW(PLHashEntry);
99 }
100
101 static void
102 DataSourceFreeEntry(void *pool, PLHashEntry *he, unsigned flag)
103 {
104 if (flag == HT_FREE_ENTRY) {
105 PL_strfree((char*) he->key);
106 PR_Free(he);
107 }
108 }
109
110 static PLHashAllocOps dataSourceHashAllocOps = {
111 DataSourceAllocTable, DataSourceFreeTable,
112 DataSourceAllocEntry, DataSourceFreeEntry
113 };
114
115 //----------------------------------------------------------------------
116 //
117 // For the mResources hashtable.
118 //
119
120 struct ResourceHashEntry : public PLDHashEntryHdr {
121 const char *mKey;
122 nsIRDFResource *mResource;
123
124 static PLDHashNumber
125 HashKey(PLDHashTable *table, const void *key)
126 {
127 return HashString(static_cast<const char *>(key));
128 }
129
130 static bool
131 MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
132 const void *key)
133 {
134 const ResourceHashEntry *entry =
135 static_cast<const ResourceHashEntry *>(hdr);
136
137 return 0 == nsCRT::strcmp(static_cast<const char *>(key),
138 entry->mKey);
139 }
140 };
141
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
151 };
152
153 // ----------------------------------------------------------------------
154 //
155 // For the mLiterals hashtable.
156 //
157
158 struct LiteralHashEntry : public PLDHashEntryHdr {
159 nsIRDFLiteral *mLiteral;
160 const char16_t *mKey;
161
162 static PLDHashNumber
163 HashKey(PLDHashTable *table, const void *key)
164 {
165 return HashString(static_cast<const char16_t *>(key));
166 }
167
168 static bool
169 MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
170 const void *key)
171 {
172 const LiteralHashEntry *entry =
173 static_cast<const LiteralHashEntry *>(hdr);
174
175 return 0 == nsCRT::strcmp(static_cast<const char16_t *>(key),
176 entry->mKey);
177 }
178 };
179
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
189 };
190
191 // ----------------------------------------------------------------------
192 //
193 // For the mInts hashtable.
194 //
195
196 struct IntHashEntry : public PLDHashEntryHdr {
197 nsIRDFInt *mInt;
198 int32_t mKey;
199
200 static PLDHashNumber
201 HashKey(PLDHashTable *table, const void *key)
202 {
203 return PLDHashNumber(*static_cast<const int32_t *>(key));
204 }
205
206 static bool
207 MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
208 const void *key)
209 {
210 const IntHashEntry *entry =
211 static_cast<const IntHashEntry *>(hdr);
212
213 return *static_cast<const int32_t *>(key) == entry->mKey;
214 }
215 };
216
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
226 };
227
228 // ----------------------------------------------------------------------
229 //
230 // For the mDates hashtable.
231 //
232
233 struct DateHashEntry : public PLDHashEntryHdr {
234 nsIRDFDate *mDate;
235 PRTime mKey;
236
237 static PLDHashNumber
238 HashKey(PLDHashTable *table, const void *key)
239 {
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);
245 }
246
247 static bool
248 MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
249 const void *key)
250 {
251 const DateHashEntry *entry =
252 static_cast<const DateHashEntry *>(hdr);
253
254 return *static_cast<const PRTime *>(key) == entry->mKey;
255 }
256 };
257
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
267 };
268
269 class BlobImpl : public nsIRDFBlob
270 {
271 public:
272 struct Data {
273 int32_t mLength;
274 uint8_t *mBytes;
275 };
276
277 BlobImpl(const uint8_t *aBytes, int32_t aLength)
278 {
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);
284 }
285
286 virtual ~BlobImpl()
287 {
288 RDFServiceImpl::gRDFService->UnregisterBlob(this);
289 // Use NS_RELEASE2() here, because we want to decrease the
290 // refcount, but not null out the gRDFService pointer (which is
291 // what a vanilla NS_RELEASE() would do).
292 nsrefcnt refcnt;
293 NS_RELEASE2(RDFServiceImpl::gRDFService, refcnt);
294 delete[] mData.mBytes;
295 }
296
297 NS_DECL_ISUPPORTS
298 NS_DECL_NSIRDFNODE
299 NS_DECL_NSIRDFBLOB
300
301 Data mData;
302 };
303
304 NS_IMPL_ISUPPORTS(BlobImpl, nsIRDFNode, nsIRDFBlob)
305
306 NS_IMETHODIMP
307 BlobImpl::EqualsNode(nsIRDFNode *aNode, bool *aEquals)
308 {
309 nsCOMPtr<nsIRDFBlob> blob = do_QueryInterface(aNode);
310 if (blob) {
311 int32_t length;
312 blob->GetLength(&length);
313
314 if (length == mData.mLength) {
315 const uint8_t *bytes;
316 blob->GetValue(&bytes);
317
318 if (0 == memcmp(bytes, mData.mBytes, length)) {
319 *aEquals = true;
320 return NS_OK;
321 }
322 }
323 }
324
325 *aEquals = false;
326 return NS_OK;
327 }
328
329 NS_IMETHODIMP
330 BlobImpl::GetValue(const uint8_t **aResult)
331 {
332 *aResult = mData.mBytes;
333 return NS_OK;
334 }
335
336 NS_IMETHODIMP
337 BlobImpl::GetLength(int32_t *aResult)
338 {
339 *aResult = mData.mLength;
340 return NS_OK;
341 }
342
343 // ----------------------------------------------------------------------
344 //
345 // For the mBlobs hashtable.
346 //
347
348 struct BlobHashEntry : public PLDHashEntryHdr {
349 BlobImpl *mBlob;
350
351 static PLDHashNumber
352 HashKey(PLDHashTable *table, const void *key)
353 {
354 const BlobImpl::Data *data =
355 static_cast<const BlobImpl::Data *>(key);
356 return HashBytes(data->mBytes, data->mLength);
357 }
358
359 static bool
360 MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
361 const void *key)
362 {
363 const BlobHashEntry *entry =
364 static_cast<const BlobHashEntry *>(hdr);
365
366 const BlobImpl::Data *left = &entry->mBlob->mData;
367
368 const BlobImpl::Data *right =
369 static_cast<const BlobImpl::Data *>(key);
370
371 return (left->mLength == right->mLength)
372 && 0 == memcmp(left->mBytes, right->mBytes, right->mLength);
373 }
374 };
375
376 static const PLDHashTableOps gBlobTableOps = {
377 PL_DHashAllocTable,
378 PL_DHashFreeTable,
379 BlobHashEntry::HashKey,
380 BlobHashEntry::MatchEntry,
381 PL_DHashMoveEntryStub,
382 PL_DHashClearEntryStub,
383 PL_DHashFinalizeStub,
384 nullptr
385 };
386
387 ////////////////////////////////////////////////////////////////////////
388 // LiteralImpl
389 //
390 // Currently, all literals are implemented exactly the same way;
391 // i.e., there is are no resource factories to allow you to generate
392 // customer resources. I doubt that makes sense, anyway.
393 //
394 class LiteralImpl : public nsIRDFLiteral {
395 public:
396 static nsresult
397 Create(const char16_t* aValue, nsIRDFLiteral** aResult);
398
399 // nsISupports
400 NS_DECL_THREADSAFE_ISUPPORTS
401
402 // nsIRDFNode
403 NS_DECL_NSIRDFNODE
404
405 // nsIRDFLiteral
406 NS_DECL_NSIRDFLITERAL
407
408 protected:
409 LiteralImpl(const char16_t* s);
410 virtual ~LiteralImpl();
411
412 const char16_t* GetValue() const {
413 size_t objectSize = ((sizeof(LiteralImpl) + sizeof(char16_t) - 1) / sizeof(char16_t)) * sizeof(char16_t);
414 return reinterpret_cast<const char16_t*>(reinterpret_cast<const unsigned char*>(this) + objectSize);
415 }
416 };
417
418
419 nsresult
420 LiteralImpl::Create(const char16_t* aValue, nsIRDFLiteral** aResult)
421 {
422 // Goofy math to get alignment right. Copied from nsSharedString.h.
423 size_t objectSize = ((sizeof(LiteralImpl) + sizeof(char16_t) - 1) / sizeof(char16_t)) * sizeof(char16_t);
424 size_t stringLen = nsCharTraits<char16_t>::length(aValue);
425 size_t stringSize = (stringLen + 1) * sizeof(char16_t);
426
427 void* objectPtr = operator new(objectSize + stringSize);
428 if (! objectPtr)
429 return NS_ERROR_NULL_POINTER;
430
431 char16_t* buf = reinterpret_cast<char16_t*>(static_cast<unsigned char*>(objectPtr) + objectSize);
432 nsCharTraits<char16_t>::copy(buf, aValue, stringLen + 1);
433
434 NS_ADDREF(*aResult = new (objectPtr) LiteralImpl(buf));
435 return NS_OK;
436 }
437
438
439 LiteralImpl::LiteralImpl(const char16_t* s)
440 {
441 RDFServiceImpl::gRDFService->RegisterLiteral(this);
442 NS_ADDREF(RDFServiceImpl::gRDFService);
443 }
444
445 LiteralImpl::~LiteralImpl()
446 {
447 RDFServiceImpl::gRDFService->UnregisterLiteral(this);
448
449 // Use NS_RELEASE2() here, because we want to decrease the
450 // refcount, but not null out the gRDFService pointer (which is
451 // what a vanilla NS_RELEASE() would do).
452 nsrefcnt refcnt;
453 NS_RELEASE2(RDFServiceImpl::gRDFService, refcnt);
454 }
455
456 NS_IMPL_ADDREF(LiteralImpl)
457 NS_IMPL_RELEASE(LiteralImpl)
458
459 nsresult
460 LiteralImpl::QueryInterface(REFNSIID iid, void** result)
461 {
462 if (! result)
463 return NS_ERROR_NULL_POINTER;
464
465 *result = nullptr;
466 if (iid.Equals(kIRDFLiteralIID) ||
467 iid.Equals(kIRDFNodeIID) ||
468 iid.Equals(kISupportsIID)) {
469 *result = static_cast<nsIRDFLiteral*>(this);
470 AddRef();
471 return NS_OK;
472 }
473 return NS_NOINTERFACE;
474 }
475
476 NS_IMETHODIMP
477 LiteralImpl::EqualsNode(nsIRDFNode* aNode, bool* aResult)
478 {
479 nsresult rv;
480 nsIRDFLiteral* literal;
481 rv = aNode->QueryInterface(kIRDFLiteralIID, (void**) &literal);
482 if (NS_SUCCEEDED(rv)) {
483 *aResult = (static_cast<nsIRDFLiteral*>(this) == literal);
484 NS_RELEASE(literal);
485 return NS_OK;
486 }
487 else if (rv == NS_NOINTERFACE) {
488 *aResult = false;
489 return NS_OK;
490 }
491 else {
492 return rv;
493 }
494 }
495
496 NS_IMETHODIMP
497 LiteralImpl::GetValue(char16_t* *value)
498 {
499 NS_ASSERTION(value, "null ptr");
500 if (! value)
501 return NS_ERROR_NULL_POINTER;
502
503 const char16_t *temp = GetValue();
504 *value = temp? NS_strdup(temp) : 0;
505 return NS_OK;
506 }
507
508
509 NS_IMETHODIMP
510 LiteralImpl::GetValueConst(const char16_t** aValue)
511 {
512 *aValue = GetValue();
513 return NS_OK;
514 }
515
516 ////////////////////////////////////////////////////////////////////////
517 // DateImpl
518 //
519
520 class DateImpl : public nsIRDFDate {
521 public:
522 DateImpl(const PRTime s);
523 virtual ~DateImpl();
524
525 // nsISupports
526 NS_DECL_ISUPPORTS
527
528 // nsIRDFNode
529 NS_DECL_NSIRDFNODE
530
531 // nsIRDFDate
532 NS_IMETHOD GetValue(PRTime *value);
533
534 private:
535 nsresult EqualsDate(nsIRDFDate* date, bool* result);
536 PRTime mValue;
537 };
538
539
540 DateImpl::DateImpl(const PRTime s)
541 : mValue(s)
542 {
543 RDFServiceImpl::gRDFService->RegisterDate(this);
544 NS_ADDREF(RDFServiceImpl::gRDFService);
545 }
546
547 DateImpl::~DateImpl()
548 {
549 RDFServiceImpl::gRDFService->UnregisterDate(this);
550
551 // Use NS_RELEASE2() here, because we want to decrease the
552 // refcount, but not null out the gRDFService pointer (which is
553 // what a vanilla NS_RELEASE() would do).
554 nsrefcnt refcnt;
555 NS_RELEASE2(RDFServiceImpl::gRDFService, refcnt);
556 }
557
558 NS_IMPL_ADDREF(DateImpl)
559 NS_IMPL_RELEASE(DateImpl)
560
561 nsresult
562 DateImpl::QueryInterface(REFNSIID iid, void** result)
563 {
564 if (! result)
565 return NS_ERROR_NULL_POINTER;
566
567 *result = nullptr;
568 if (iid.Equals(kIRDFDateIID) ||
569 iid.Equals(kIRDFNodeIID) ||
570 iid.Equals(kISupportsIID)) {
571 *result = static_cast<nsIRDFDate*>(this);
572 AddRef();
573 return NS_OK;
574 }
575 return NS_NOINTERFACE;
576 }
577
578 NS_IMETHODIMP
579 DateImpl::EqualsNode(nsIRDFNode* node, bool* result)
580 {
581 nsresult rv;
582 nsIRDFDate* date;
583 if (NS_SUCCEEDED(node->QueryInterface(kIRDFDateIID, (void**) &date))) {
584 rv = EqualsDate(date, result);
585 NS_RELEASE(date);
586 }
587 else {
588 *result = false;
589 rv = NS_OK;
590 }
591 return rv;
592 }
593
594 NS_IMETHODIMP
595 DateImpl::GetValue(PRTime *value)
596 {
597 NS_ASSERTION(value, "null ptr");
598 if (! value)
599 return NS_ERROR_NULL_POINTER;
600
601 *value = mValue;
602 return NS_OK;
603 }
604
605
606 nsresult
607 DateImpl::EqualsDate(nsIRDFDate* date, bool* result)
608 {
609 NS_ASSERTION(date && result, "null ptr");
610 if (!date || !result)
611 return NS_ERROR_NULL_POINTER;
612
613 nsresult rv;
614 PRTime p;
615 if (NS_FAILED(rv = date->GetValue(&p)))
616 return rv;
617
618 *result = p == mValue;
619 return NS_OK;
620 }
621
622 ////////////////////////////////////////////////////////////////////////
623 // IntImpl
624 //
625
626 class IntImpl : public nsIRDFInt {
627 public:
628 IntImpl(int32_t s);
629 virtual ~IntImpl();
630
631 // nsISupports
632 NS_DECL_ISUPPORTS
633
634 // nsIRDFNode
635 NS_DECL_NSIRDFNODE
636
637 // nsIRDFInt
638 NS_IMETHOD GetValue(int32_t *value);
639
640 private:
641 nsresult EqualsInt(nsIRDFInt* value, bool* result);
642 int32_t mValue;
643 };
644
645
646 IntImpl::IntImpl(int32_t s)
647 : mValue(s)
648 {
649 RDFServiceImpl::gRDFService->RegisterInt(this);
650 NS_ADDREF(RDFServiceImpl::gRDFService);
651 }
652
653 IntImpl::~IntImpl()
654 {
655 RDFServiceImpl::gRDFService->UnregisterInt(this);
656
657 // Use NS_RELEASE2() here, because we want to decrease the
658 // refcount, but not null out the gRDFService pointer (which is
659 // what a vanilla NS_RELEASE() would do).
660 nsrefcnt refcnt;
661 NS_RELEASE2(RDFServiceImpl::gRDFService, refcnt);
662 }
663
664 NS_IMPL_ADDREF(IntImpl)
665 NS_IMPL_RELEASE(IntImpl)
666
667 nsresult
668 IntImpl::QueryInterface(REFNSIID iid, void** result)
669 {
670 if (! result)
671 return NS_ERROR_NULL_POINTER;
672
673 *result = nullptr;
674 if (iid.Equals(kIRDFIntIID) ||
675 iid.Equals(kIRDFNodeIID) ||
676 iid.Equals(kISupportsIID)) {
677 *result = static_cast<nsIRDFInt*>(this);
678 AddRef();
679 return NS_OK;
680 }
681 return NS_NOINTERFACE;
682 }
683
684 NS_IMETHODIMP
685 IntImpl::EqualsNode(nsIRDFNode* node, bool* result)
686 {
687 nsresult rv;
688 nsIRDFInt* intValue;
689 if (NS_SUCCEEDED(node->QueryInterface(kIRDFIntIID, (void**) &intValue))) {
690 rv = EqualsInt(intValue, result);
691 NS_RELEASE(intValue);
692 }
693 else {
694 *result = false;
695 rv = NS_OK;
696 }
697 return rv;
698 }
699
700 NS_IMETHODIMP
701 IntImpl::GetValue(int32_t *value)
702 {
703 NS_ASSERTION(value, "null ptr");
704 if (! value)
705 return NS_ERROR_NULL_POINTER;
706
707 *value = mValue;
708 return NS_OK;
709 }
710
711
712 nsresult
713 IntImpl::EqualsInt(nsIRDFInt* intValue, bool* result)
714 {
715 NS_ASSERTION(intValue && result, "null ptr");
716 if (!intValue || !result)
717 return NS_ERROR_NULL_POINTER;
718
719 nsresult rv;
720 int32_t p;
721 if (NS_FAILED(rv = intValue->GetValue(&p)))
722 return rv;
723
724 *result = (p == mValue);
725 return NS_OK;
726 }
727
728 ////////////////////////////////////////////////////////////////////////
729 // RDFServiceImpl
730
731 RDFServiceImpl*
732 RDFServiceImpl::gRDFService;
733
734 RDFServiceImpl::RDFServiceImpl()
735 : mNamedDataSources(nullptr)
736 {
737 mResources.ops = nullptr;
738 mLiterals.ops = nullptr;
739 mInts.ops = nullptr;
740 mDates.ops = nullptr;
741 mBlobs.ops = nullptr;
742 gRDFService = this;
743 }
744
745 nsresult
746 RDFServiceImpl::Init()
747 {
748 nsresult rv;
749
750 mNamedDataSources = PL_NewHashTable(23,
751 PL_HashString,
752 PL_CompareStrings,
753 PL_CompareValues,
754 &dataSourceHashAllocOps, nullptr);
755
756 if (! mNamedDataSources)
757 return NS_ERROR_OUT_OF_MEMORY;
758
759 PL_DHashTableInit(&mResources, &gResourceTableOps, nullptr,
760 sizeof(ResourceHashEntry), PL_DHASH_MIN_SIZE);
761
762 PL_DHashTableInit(&mLiterals, &gLiteralTableOps, nullptr,
763 sizeof(LiteralHashEntry), PL_DHASH_MIN_SIZE);
764
765 PL_DHashTableInit(&mInts, &gIntTableOps, nullptr,
766 sizeof(IntHashEntry), PL_DHASH_MIN_SIZE);
767
768 PL_DHashTableInit(&mDates, &gDateTableOps, nullptr,
769 sizeof(DateHashEntry), PL_DHASH_MIN_SIZE);
770
771 PL_DHashTableInit(&mBlobs, &gBlobTableOps, nullptr,
772 sizeof(BlobHashEntry), PL_DHASH_MIN_SIZE);
773
774 mDefaultResourceFactory = do_GetClassObject(kRDFDefaultResourceCID, &rv);
775 NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get default resource factory");
776 if (NS_FAILED(rv)) return rv;
777
778 #ifdef PR_LOGGING
779 if (! gLog)
780 gLog = PR_NewLogModule("nsRDFService");
781 #endif
782
783 return NS_OK;
784 }
785
786
787 RDFServiceImpl::~RDFServiceImpl()
788 {
789 if (mNamedDataSources) {
790 PL_HashTableDestroy(mNamedDataSources);
791 mNamedDataSources = nullptr;
792 }
793 if (mResources.ops)
794 PL_DHashTableFinish(&mResources);
795 if (mLiterals.ops)
796 PL_DHashTableFinish(&mLiterals);
797 if (mInts.ops)
798 PL_DHashTableFinish(&mInts);
799 if (mDates.ops)
800 PL_DHashTableFinish(&mDates);
801 if (mBlobs.ops)
802 PL_DHashTableFinish(&mBlobs);
803 gRDFService = nullptr;
804 }
805
806
807 // static
808 nsresult
809 RDFServiceImpl::CreateSingleton(nsISupports* aOuter,
810 const nsIID& aIID, void **aResult)
811 {
812 NS_ENSURE_NO_AGGREGATION(aOuter);
813
814 if (gRDFService) {
815 NS_ERROR("Trying to create RDF serviec twice.");
816 return gRDFService->QueryInterface(aIID, aResult);
817 }
818
819 nsRefPtr<RDFServiceImpl> serv = new RDFServiceImpl();
820 if (!serv)
821 return NS_ERROR_OUT_OF_MEMORY;
822
823 nsresult rv = serv->Init();
824 if (NS_FAILED(rv))
825 return rv;
826
827 return serv->QueryInterface(aIID, aResult);
828 }
829
830 NS_IMPL_ISUPPORTS(RDFServiceImpl, nsIRDFService, nsISupportsWeakReference)
831
832 // Per RFC2396.
833 static const uint8_t
834 kLegalSchemeChars[] = {
835 // ASCII Bits Ordered Hex
836 // 01234567 76543210
837 0x00, // 00-07
838 0x00, // 08-0F
839 0x00, // 10-17
840 0x00, // 18-1F
841 0x00, // 20-27 !"#$%&' 00000000 00000000
842 0x28, // 28-2F ()*+,-./ 00010100 00101000 0x28
843 0xff, // 30-37 01234567 11111111 11111111 0xFF
844 0x03, // 38-3F 89:;<=>? 11000000 00000011 0x03
845 0xfe, // 40-47 @ABCDEFG 01111111 11111110 0xFE
846 0xff, // 48-4F HIJKLMNO 11111111 11111111 0xFF
847 0xff, // 50-57 PQRSTUVW 11111111 11111111 0xFF
848 0x87, // 58-5F XYZ[\]^_ 11100001 10000111 0x87
849 0xfe, // 60-67 `abcdefg 01111111 11111110 0xFE
850 0xff, // 68-6F hijklmno 11111111 11111111 0xFF
851 0xff, // 70-77 pqrstuvw 11111111 11111111 0xFF
852 0x07, // 78-7F xyz{|}~ 11100000 00000111 0x07
853 0x00, 0x00, 0x00, 0x00, // >= 80
854 0x00, 0x00, 0x00, 0x00,
855 0x00, 0x00, 0x00, 0x00,
856 0x00, 0x00, 0x00, 0x00
857 };
858
859 static inline bool
860 IsLegalSchemeCharacter(const char aChar)
861 {
862 uint8_t mask = kLegalSchemeChars[aChar >> 3];
863 uint8_t bit = 1u << (aChar & 0x7);
864 return bool((mask & bit) != 0);
865 }
866
867
868 NS_IMETHODIMP
869 RDFServiceImpl::GetResource(const nsACString& aURI, nsIRDFResource** aResource)
870 {
871 // Sanity checks
872 NS_PRECONDITION(aResource != nullptr, "null ptr");
873 NS_PRECONDITION(!aURI.IsEmpty(), "URI is empty");
874 if (! aResource)
875 return NS_ERROR_NULL_POINTER;
876 if (aURI.IsEmpty())
877 return NS_ERROR_INVALID_ARG;
878
879 const nsAFlatCString& flatURI = PromiseFlatCString(aURI);
880 PR_LOG(gLog, PR_LOG_DEBUG, ("rdfserv get-resource %s", flatURI.get()));
881
882 // First, check the cache to see if we've already created and
883 // registered this thing.
884 PLDHashEntryHdr *hdr =
885 PL_DHashTableOperate(&mResources, flatURI.get(), PL_DHASH_LOOKUP);
886
887 if (PL_DHASH_ENTRY_IS_BUSY(hdr)) {
888 ResourceHashEntry *entry = static_cast<ResourceHashEntry *>(hdr);
889 NS_ADDREF(*aResource = entry->mResource);
890 return NS_OK;
891 }
892
893 // Nope. So go to the repository to create it.
894
895 // Compute the scheme of the URI. Scan forward until we either:
896 //
897 // 1. Reach the end of the string
898 // 2. Encounter a non-alpha character
899 // 3. Encouter a colon.
900 //
901 // If we encounter a colon _before_ encountering a non-alpha
902 // character, then assume it's the scheme.
903 //
904 // XXX Although it's really not correct, we'll allow underscore
905 // characters ('_'), too.
906 nsACString::const_iterator p, end;
907 aURI.BeginReading(p);
908 aURI.EndReading(end);
909 while (p != end && IsLegalSchemeCharacter(*p))
910 ++p;
911
912 nsresult rv;
913 nsCOMPtr<nsIFactory> factory;
914
915 nsACString::const_iterator begin;
916 aURI.BeginReading(begin);
917 if (*p == ':') {
918 // There _was_ a scheme. First see if it's the same scheme
919 // that we just tried to use...
920 if (mLastFactory && mLastURIPrefix.Equals(Substring(begin, p)))
921 factory = mLastFactory;
922 else {
923 // Try to find a factory using the component manager.
924 nsACString::const_iterator begin;
925 aURI.BeginReading(begin);
926 nsAutoCString contractID;
927 contractID = NS_LITERAL_CSTRING(NS_RDF_RESOURCE_FACTORY_CONTRACTID_PREFIX) +
928 Substring(begin, p);
929
930 factory = do_GetClassObject(contractID.get());
931 if (factory) {
932 // Store the factory in our one-element cache.
933 if (p != begin) {
934 mLastFactory = factory;
935 mLastURIPrefix = Substring(begin, p);
936 }
937 }
938 }
939 }
940
941 if (! factory) {
942 // fall through to using the "default" resource factory if either:
943 //
944 // 1. The URI didn't have a scheme, or
945 // 2. There was no resource factory registered for the scheme.
946 factory = mDefaultResourceFactory;
947
948 // Store the factory in our one-element cache.
949 if (p != begin) {
950 mLastFactory = factory;
951 mLastURIPrefix = Substring(begin, p);
952 }
953 }
954
955 nsIRDFResource *result;
956 rv = factory->CreateInstance(nullptr, NS_GET_IID(nsIRDFResource), (void**) &result);
957 if (NS_FAILED(rv)) return rv;
958
959 // Now initialize it with its URI. At this point, the resource
960 // implementation should register itself with the RDF service.
961 rv = result->Init(flatURI.get());
962 if (NS_FAILED(rv)) {
963 NS_ERROR("unable to initialize resource");
964 NS_RELEASE(result);
965 return rv;
966 }
967
968 *aResource = result; // already refcounted from repository
969 return rv;
970 }
971
972 NS_IMETHODIMP
973 RDFServiceImpl::GetUnicodeResource(const nsAString& aURI, nsIRDFResource** aResource)
974 {
975 return GetResource(NS_ConvertUTF16toUTF8(aURI), aResource);
976 }
977
978
979 NS_IMETHODIMP
980 RDFServiceImpl::GetAnonymousResource(nsIRDFResource** aResult)
981 {
982 static uint32_t gCounter = 0;
983 static char gChars[] = "0123456789abcdef"
984 "ghijklmnopqrstuv"
985 "wxyzABCDEFGHIJKL"
986 "MNOPQRSTUVWXYZ.+";
987
988 static int32_t kMask = 0x003f;
989 static int32_t kShift = 6;
990
991 if (! gCounter) {
992 // Start it at a semi-unique value, just to minimize the
993 // chance that we get into a situation where
994 //
995 // 1. An anonymous resource gets serialized out in a graph
996 // 2. Reboot
997 // 3. The same anonymous resource gets requested, and refers
998 // to something completely different.
999 // 4. The serialization is read back in.
1000 gCounter = uint32_t(PR_Now());
1001 }
1002
1003 nsresult rv;
1004 nsAutoCString s;
1005
1006 do {
1007 // Ugh, this is a really sloppy way to do this; I copied the
1008 // implementation from the days when it lived outside the RDF
1009 // service. Now that it's a member we can be more cleverer.
1010
1011 s.Truncate();
1012 s.Append("rdf:#$");
1013
1014 uint32_t id = ++gCounter;
1015 while (id) {
1016 char ch = gChars[(id & kMask)];
1017 s.Append(ch);
1018 id >>= kShift;
1019 }
1020
1021 nsIRDFResource* resource;
1022 rv = GetResource(s, &resource);
1023 if (NS_FAILED(rv)) return rv;
1024
1025 // XXX an ugly but effective way to make sure that this
1026 // resource is really unique in the world.
1027 resource->AddRef();
1028 nsrefcnt refcnt = resource->Release();
1029
1030 if (refcnt == 1) {
1031 *aResult = resource;
1032 break;
1033 }
1034
1035 NS_RELEASE(resource);
1036 } while (1);
1037
1038 return NS_OK;
1039 }
1040
1041
1042 NS_IMETHODIMP
1043 RDFServiceImpl::GetLiteral(const char16_t* aValue, nsIRDFLiteral** aLiteral)
1044 {
1045 NS_PRECONDITION(aValue != nullptr, "null ptr");
1046 if (! aValue)
1047 return NS_ERROR_NULL_POINTER;
1048
1049 NS_PRECONDITION(aLiteral != nullptr, "null ptr");
1050 if (! aLiteral)
1051 return NS_ERROR_NULL_POINTER;
1052
1053 // See if we have one already cached
1054 PLDHashEntryHdr *hdr =
1055 PL_DHashTableOperate(&mLiterals, aValue, PL_DHASH_LOOKUP);
1056
1057 if (PL_DHASH_ENTRY_IS_BUSY(hdr)) {
1058 LiteralHashEntry *entry = static_cast<LiteralHashEntry *>(hdr);
1059 NS_ADDREF(*aLiteral = entry->mLiteral);
1060 return NS_OK;
1061 }
1062
1063 // Nope. Create a new one
1064 return LiteralImpl::Create(aValue, aLiteral);
1065 }
1066
1067 NS_IMETHODIMP
1068 RDFServiceImpl::GetDateLiteral(PRTime aTime, nsIRDFDate** aResult)
1069 {
1070 // See if we have one already cached
1071 PLDHashEntryHdr *hdr =
1072 PL_DHashTableOperate(&mDates, &aTime, PL_DHASH_LOOKUP);
1073
1074 if (PL_DHASH_ENTRY_IS_BUSY(hdr)) {
1075 DateHashEntry *entry = static_cast<DateHashEntry *>(hdr);
1076 NS_ADDREF(*aResult = entry->mDate);
1077 return NS_OK;
1078 }
1079
1080 DateImpl* result = new DateImpl(aTime);
1081 if (! result)
1082 return NS_ERROR_OUT_OF_MEMORY;
1083
1084 NS_ADDREF(*aResult = result);
1085 return NS_OK;
1086 }
1087
1088 NS_IMETHODIMP
1089 RDFServiceImpl::GetIntLiteral(int32_t aInt, nsIRDFInt** aResult)
1090 {
1091 // See if we have one already cached
1092 PLDHashEntryHdr *hdr =
1093 PL_DHashTableOperate(&mInts, &aInt, PL_DHASH_LOOKUP);
1094
1095 if (PL_DHASH_ENTRY_IS_BUSY(hdr)) {
1096 IntHashEntry *entry = static_cast<IntHashEntry *>(hdr);
1097 NS_ADDREF(*aResult = entry->mInt);
1098 return NS_OK;
1099 }
1100
1101 IntImpl* result = new IntImpl(aInt);
1102 if (! result)
1103 return NS_ERROR_OUT_OF_MEMORY;
1104
1105 NS_ADDREF(*aResult = result);
1106 return NS_OK;
1107 }
1108
1109 NS_IMETHODIMP
1110 RDFServiceImpl::GetBlobLiteral(const uint8_t *aBytes, int32_t aLength,
1111 nsIRDFBlob **aResult)
1112 {
1113 BlobImpl::Data key = { aLength, const_cast<uint8_t *>(aBytes) };
1114
1115 PLDHashEntryHdr *hdr =
1116 PL_DHashTableOperate(&mBlobs, &key, PL_DHASH_LOOKUP);
1117
1118 if (PL_DHASH_ENTRY_IS_BUSY(hdr)) {
1119 BlobHashEntry *entry = static_cast<BlobHashEntry *>(hdr);
1120 NS_ADDREF(*aResult = entry->mBlob);
1121 return NS_OK;
1122 }
1123
1124 BlobImpl *result = new BlobImpl(aBytes, aLength);
1125 if (! result)
1126 return NS_ERROR_OUT_OF_MEMORY;
1127
1128 NS_ADDREF(*aResult = result);
1129 return NS_OK;
1130 }
1131
1132 NS_IMETHODIMP
1133 RDFServiceImpl::IsAnonymousResource(nsIRDFResource* aResource, bool* _result)
1134 {
1135 NS_PRECONDITION(aResource != nullptr, "null ptr");
1136 if (! aResource)
1137 return NS_ERROR_NULL_POINTER;
1138
1139 nsresult rv;
1140
1141 const char* uri;
1142 rv = aResource->GetValueConst(&uri);
1143 if (NS_FAILED(rv)) return rv;
1144
1145 if ((uri[0] == 'r') &&
1146 (uri[1] == 'd') &&
1147 (uri[2] == 'f') &&
1148 (uri[3] == ':') &&
1149 (uri[4] == '#') &&
1150 (uri[5] == '$')) {
1151 *_result = true;
1152 }
1153 else {
1154 *_result = false;
1155 }
1156
1157 return NS_OK;
1158 }
1159
1160 NS_IMETHODIMP
1161 RDFServiceImpl::RegisterResource(nsIRDFResource* aResource, bool aReplace)
1162 {
1163 NS_PRECONDITION(aResource != nullptr, "null ptr");
1164 if (! aResource)
1165 return NS_ERROR_NULL_POINTER;
1166
1167 nsresult rv;
1168
1169 const char* uri;
1170 rv = aResource->GetValueConst(&uri);
1171 NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get URI from resource");
1172 if (NS_FAILED(rv)) return rv;
1173
1174 NS_ASSERTION(uri != nullptr, "resource has no URI");
1175 if (! uri)
1176 return NS_ERROR_NULL_POINTER;
1177
1178 PLDHashEntryHdr *hdr =
1179 PL_DHashTableOperate(&mResources, uri, PL_DHASH_LOOKUP);
1180
1181 if (PL_DHASH_ENTRY_IS_BUSY(hdr)) {
1182 if (!aReplace) {
1183 NS_WARNING("resource already registered, and replace not specified");
1184 return NS_ERROR_FAILURE; // already registered
1185 }
1186
1187 // N.B., we do _not_ release the original resource because we
1188 // only ever held a weak reference to it. We simply replace
1189 // it.
1190
1191 PR_LOG(gLog, PR_LOG_DEBUG,
1192 ("rdfserv replace-resource [%p] <-- [%p] %s",
1193 static_cast<ResourceHashEntry *>(hdr)->mResource,
1194 aResource, (const char*) uri));
1195 }
1196 else {
1197 hdr = PL_DHashTableOperate(&mResources, uri, PL_DHASH_ADD);
1198 if (! hdr)
1199 return NS_ERROR_OUT_OF_MEMORY;
1200
1201 PR_LOG(gLog, PR_LOG_DEBUG,
1202 ("rdfserv register-resource [%p] %s",
1203 aResource, (const char*) uri));
1204 }
1205
1206 // N.B., we only hold a weak reference to the resource: that way,
1207 // the resource can be destroyed when the last refcount goes
1208 // away. The single addref that the CreateResource() call made
1209 // will be owned by the callee.
1210 ResourceHashEntry *entry = static_cast<ResourceHashEntry *>(hdr);
1211 entry->mResource = aResource;
1212 entry->mKey = uri;
1213
1214 return NS_OK;
1215 }
1216
1217 NS_IMETHODIMP
1218 RDFServiceImpl::UnregisterResource(nsIRDFResource* aResource)
1219 {
1220 NS_PRECONDITION(aResource != nullptr, "null ptr");
1221 if (! aResource)
1222 return NS_ERROR_NULL_POINTER;
1223
1224 nsresult rv;
1225
1226 const char* uri;
1227 rv = aResource->GetValueConst(&uri);
1228 if (NS_FAILED(rv)) return rv;
1229
1230 NS_ASSERTION(uri != nullptr, "resource has no URI");
1231 if (! uri)
1232 return NS_ERROR_UNEXPECTED;
1233
1234 PR_LOG(gLog, PR_LOG_DEBUG,
1235 ("rdfserv unregister-resource [%p] %s",
1236 aResource, (const char*) uri));
1237
1238 #ifdef DEBUG
1239 if (PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mResources, uri, PL_DHASH_LOOKUP)))
1240 NS_WARNING("resource was never registered");
1241 #endif
1242
1243 PL_DHashTableOperate(&mResources, uri, PL_DHASH_REMOVE);
1244 return NS_OK;
1245 }
1246
1247 NS_IMETHODIMP
1248 RDFServiceImpl::RegisterDataSource(nsIRDFDataSource* aDataSource, bool aReplace)
1249 {
1250 NS_PRECONDITION(aDataSource != nullptr, "null ptr");
1251 if (! aDataSource)
1252 return NS_ERROR_NULL_POINTER;
1253
1254 nsresult rv;
1255
1256 nsXPIDLCString uri;
1257 rv = aDataSource->GetURI(getter_Copies(uri));
1258 if (NS_FAILED(rv)) return rv;
1259
1260 PLHashEntry** hep =
1261 PL_HashTableRawLookup(mNamedDataSources, (*mNamedDataSources->keyHash)(uri), uri);
1262
1263 if (*hep) {
1264 if (! aReplace)
1265 return NS_ERROR_FAILURE; // already registered
1266
1267 // N.B., we only hold a weak reference to the datasource, so
1268 // just replace the old with the new and don't touch any
1269 // refcounts.
1270 PR_LOG(gLog, PR_LOG_NOTICE,
1271 ("rdfserv replace-datasource [%p] <-- [%p] %s",
1272 (*hep)->value, aDataSource, (const char*) uri));
1273
1274 (*hep)->value = aDataSource;
1275 }
1276 else {
1277 const char* key = PL_strdup(uri);
1278 if (! key)
1279 return NS_ERROR_OUT_OF_MEMORY;
1280
1281 PL_HashTableAdd(mNamedDataSources, key, aDataSource);
1282
1283 PR_LOG(gLog, PR_LOG_NOTICE,
1284 ("rdfserv register-datasource [%p] %s",
1285 aDataSource, (const char*) uri));
1286
1287 // N.B., we only hold a weak reference to the datasource, so don't
1288 // addref.
1289 }
1290
1291 return NS_OK;
1292 }
1293
1294 NS_IMETHODIMP
1295 RDFServiceImpl::UnregisterDataSource(nsIRDFDataSource* aDataSource)
1296 {
1297 NS_PRECONDITION(aDataSource != nullptr, "null ptr");
1298 if (! aDataSource)
1299 return NS_ERROR_NULL_POINTER;
1300
1301 nsresult rv;
1302
1303 nsXPIDLCString uri;
1304 rv = aDataSource->GetURI(getter_Copies(uri));
1305 if (NS_FAILED(rv)) return rv;
1306
1307 //NS_ASSERTION(uri != nullptr, "datasource has no URI");
1308 if (! uri)
1309 return NS_ERROR_UNEXPECTED;
1310
1311 PLHashEntry** hep =
1312 PL_HashTableRawLookup(mNamedDataSources, (*mNamedDataSources->keyHash)(uri), uri);
1313
1314 // It may well be that this datasource was never registered. If
1315 // so, don't unregister it.
1316 if (! *hep || ((*hep)->value != aDataSource))
1317 return NS_OK;
1318
1319 // N.B., we only held a weak reference to the datasource, so we
1320 // don't release here.
1321 PL_HashTableRawRemove(mNamedDataSources, hep, *hep);
1322
1323 PR_LOG(gLog, PR_LOG_NOTICE,
1324 ("rdfserv unregister-datasource [%p] %s",
1325 aDataSource, (const char*) uri));
1326
1327 return NS_OK;
1328 }
1329
1330 NS_IMETHODIMP
1331 RDFServiceImpl::GetDataSource(const char* aURI, nsIRDFDataSource** aDataSource)
1332 {
1333 // Use the other GetDataSource and ask for a non-blocking Refresh.
1334 // If you wanted it loaded synchronously, then you should've tried to do it
1335 // yourself, or used GetDataSourceBlocking.
1336 return GetDataSource( aURI, false, aDataSource );
1337 }
1338
1339 NS_IMETHODIMP
1340 RDFServiceImpl::GetDataSourceBlocking(const char* aURI, nsIRDFDataSource** aDataSource)
1341 {
1342 // Use GetDataSource and ask for a blocking Refresh.
1343 return GetDataSource( aURI, true, aDataSource );
1344 }
1345
1346 nsresult
1347 RDFServiceImpl::GetDataSource(const char* aURI, bool aBlock, nsIRDFDataSource** aDataSource)
1348 {
1349 NS_PRECONDITION(aURI != nullptr, "null ptr");
1350 if (! aURI)
1351 return NS_ERROR_NULL_POINTER;
1352
1353 nsresult rv;
1354
1355 // Attempt to canonify the URI before we look for it in the
1356 // cache. We won't bother doing this on `rdf:' URIs to avoid
1357 // useless (and expensive) protocol handler lookups.
1358 nsAutoCString spec(aURI);
1359
1360 if (!StringBeginsWith(spec, NS_LITERAL_CSTRING("rdf:"))) {
1361 nsCOMPtr<nsIURI> uri;
1362 NS_NewURI(getter_AddRefs(uri), spec);
1363 if (uri)
1364 uri->GetSpec(spec);
1365 }
1366
1367 // First, check the cache to see if we already have this
1368 // datasource loaded and initialized.
1369 {
1370 nsIRDFDataSource* cached =
1371 static_cast<nsIRDFDataSource*>(PL_HashTableLookup(mNamedDataSources, spec.get()));
1372
1373 if (cached) {
1374 NS_ADDREF(cached);
1375 *aDataSource = cached;
1376 return NS_OK;
1377 }
1378 }
1379
1380 // Nope. So go to the repository to try to create it.
1381 nsCOMPtr<nsIRDFDataSource> ds;
1382 if (StringBeginsWith(spec, NS_LITERAL_CSTRING("rdf:"))) {
1383 // It's a built-in data source. Convert it to a contract ID.
1384 nsAutoCString contractID(
1385 NS_LITERAL_CSTRING(NS_RDF_DATASOURCE_CONTRACTID_PREFIX) +
1386 Substring(spec, 4, spec.Length() - 4));
1387
1388 // Strip params to get ``base'' contractID for data source.
1389 int32_t p = contractID.FindChar(char16_t('&'));
1390 if (p >= 0)
1391 contractID.Truncate(p);
1392
1393 ds = do_GetService(contractID.get(), &rv);
1394 if (NS_FAILED(rv)) return rv;
1395
1396 nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(ds);
1397 if (remote) {
1398 rv = remote->Init(spec.get());
1399 if (NS_FAILED(rv)) return rv;
1400 }
1401 }
1402 else {
1403 // Try to load this as an RDF/XML data source
1404 ds = do_CreateInstance(kRDFXMLDataSourceCID, &rv);
1405 if (NS_FAILED(rv)) return rv;
1406
1407 nsCOMPtr<nsIRDFRemoteDataSource> remote(do_QueryInterface(ds));
1408 NS_ASSERTION(remote, "not a remote RDF/XML data source!");
1409 if (! remote) return NS_ERROR_UNEXPECTED;
1410
1411 rv = remote->Init(spec.get());
1412 if (NS_FAILED(rv)) return rv;
1413
1414 rv = remote->Refresh(aBlock);
1415 if (NS_FAILED(rv)) return rv;
1416 }
1417
1418 *aDataSource = ds;
1419 NS_ADDREF(*aDataSource);
1420 return NS_OK;
1421 }
1422
1423 ////////////////////////////////////////////////////////////////////////
1424
1425 nsresult
1426 RDFServiceImpl::RegisterLiteral(nsIRDFLiteral* aLiteral)
1427 {
1428 const char16_t* value;
1429 aLiteral->GetValueConst(&value);
1430
1431 NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mLiterals,
1432 value,
1433 PL_DHASH_LOOKUP)),
1434 "literal already registered");
1435
1436 PLDHashEntryHdr *hdr =
1437 PL_DHashTableOperate(&mLiterals, value, PL_DHASH_ADD);
1438
1439 if (! hdr)
1440 return NS_ERROR_OUT_OF_MEMORY;
1441
1442 LiteralHashEntry *entry = static_cast<LiteralHashEntry *>(hdr);
1443
1444 // N.B., we only hold a weak reference to the literal: that
1445 // way, the literal can be destroyed when the last refcount
1446 // goes away. The single addref that the CreateLiteral() call
1447 // made will be owned by the callee.
1448 entry->mLiteral = aLiteral;
1449 entry->mKey = value;
1450
1451 PR_LOG(gLog, PR_LOG_DEBUG,
1452 ("rdfserv register-literal [%p] %s",
1453 aLiteral, (const char16_t*) value));
1454
1455 return NS_OK;
1456 }
1457
1458
1459 nsresult
1460 RDFServiceImpl::UnregisterLiteral(nsIRDFLiteral* aLiteral)
1461 {
1462 const char16_t* value;
1463 aLiteral->GetValueConst(&value);
1464
1465 NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableOperate(&mLiterals,
1466 value,
1467 PL_DHASH_LOOKUP)),
1468 "literal was never registered");
1469
1470 PL_DHashTableOperate(&mLiterals, value, PL_DHASH_REMOVE);
1471
1472 // N.B. that we _don't_ release the literal: we only held a weak
1473 // reference to it in the hashtable.
1474 PR_LOG(gLog, PR_LOG_DEBUG,
1475 ("rdfserv unregister-literal [%p] %s",
1476 aLiteral, (const char16_t*) value));
1477
1478 return NS_OK;
1479 }
1480
1481 //----------------------------------------------------------------------
1482
1483 nsresult
1484 RDFServiceImpl::RegisterInt(nsIRDFInt* aInt)
1485 {
1486 int32_t value;
1487 aInt->GetValue(&value);
1488
1489 NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mInts,
1490 &value,
1491 PL_DHASH_LOOKUP)),
1492 "int already registered");
1493
1494 PLDHashEntryHdr *hdr =
1495 PL_DHashTableOperate(&mInts, &value, PL_DHASH_ADD);
1496
1497 if (! hdr)
1498 return NS_ERROR_OUT_OF_MEMORY;
1499
1500 IntHashEntry *entry = static_cast<IntHashEntry *>(hdr);
1501
1502 // N.B., we only hold a weak reference to the literal: that
1503 // way, the literal can be destroyed when the last refcount
1504 // goes away. The single addref that the CreateInt() call
1505 // made will be owned by the callee.
1506 entry->mInt = aInt;
1507 entry->mKey = value;
1508
1509 PR_LOG(gLog, PR_LOG_DEBUG,
1510 ("rdfserv register-int [%p] %d",
1511 aInt, value));
1512
1513 return NS_OK;
1514 }
1515
1516
1517 nsresult
1518 RDFServiceImpl::UnregisterInt(nsIRDFInt* aInt)
1519 {
1520 int32_t value;
1521 aInt->GetValue(&value);
1522
1523 NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableOperate(&mInts,
1524 &value,
1525 PL_DHASH_LOOKUP)),
1526 "int was never registered");
1527
1528 PL_DHashTableOperate(&mInts, &value, PL_DHASH_REMOVE);
1529
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));
1535
1536 return NS_OK;
1537 }
1538
1539 //----------------------------------------------------------------------
1540
1541 nsresult
1542 RDFServiceImpl::RegisterDate(nsIRDFDate* aDate)
1543 {
1544 PRTime value;
1545 aDate->GetValue(&value);
1546
1547 NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mDates,
1548 &value,
1549 PL_DHASH_LOOKUP)),
1550 "date already registered");
1551
1552 PLDHashEntryHdr *hdr =
1553 PL_DHashTableOperate(&mDates, &value, PL_DHASH_ADD);
1554
1555 if (! hdr)
1556 return NS_ERROR_OUT_OF_MEMORY;
1557
1558 DateHashEntry *entry = static_cast<DateHashEntry *>(hdr);
1559
1560 // N.B., we only hold a weak reference to the literal: that
1561 // way, the literal can be destroyed when the last refcount
1562 // goes away. The single addref that the CreateDate() call
1563 // made will be owned by the callee.
1564 entry->mDate = aDate;
1565 entry->mKey = value;
1566
1567 PR_LOG(gLog, PR_LOG_DEBUG,
1568 ("rdfserv register-date [%p] %ld",
1569 aDate, value));
1570
1571 return NS_OK;
1572 }
1573
1574
1575 nsresult
1576 RDFServiceImpl::UnregisterDate(nsIRDFDate* aDate)
1577 {
1578 PRTime value;
1579 aDate->GetValue(&value);
1580
1581 NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableOperate(&mDates,
1582 &value,
1583 PL_DHASH_LOOKUP)),
1584 "date was never registered");
1585
1586 PL_DHashTableOperate(&mDates, &value, PL_DHASH_REMOVE);
1587
1588 // N.B. that we _don't_ release the literal: we only held a weak
1589 // reference to it in the hashtable.
1590 PR_LOG(gLog, PR_LOG_DEBUG,
1591 ("rdfserv unregister-date [%p] %ld",
1592 aDate, value));
1593
1594 return NS_OK;
1595 }
1596
1597 nsresult
1598 RDFServiceImpl::RegisterBlob(BlobImpl *aBlob)
1599 {
1600 NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mBlobs,
1601 &aBlob->mData,
1602 PL_DHASH_LOOKUP)),
1603 "blob already registered");
1604
1605 PLDHashEntryHdr *hdr =
1606 PL_DHashTableOperate(&mBlobs, &aBlob->mData, PL_DHASH_ADD);
1607
1608 if (! hdr)
1609 return NS_ERROR_OUT_OF_MEMORY;
1610
1611 BlobHashEntry *entry = static_cast<BlobHashEntry *>(hdr);
1612
1613 // N.B., we only hold a weak reference to the literal: that
1614 // way, the literal can be destroyed when the last refcount
1615 // goes away. The single addref that the CreateInt() call
1616 // made will be owned by the callee.
1617 entry->mBlob = aBlob;
1618
1619 PR_LOG(gLog, PR_LOG_DEBUG,
1620 ("rdfserv register-blob [%p] %s",
1621 aBlob, aBlob->mData.mBytes));
1622
1623 return NS_OK;
1624 }
1625
1626 nsresult
1627 RDFServiceImpl::UnregisterBlob(BlobImpl *aBlob)
1628 {
1629 NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableOperate(&mBlobs,
1630 &aBlob->mData,
1631 PL_DHASH_LOOKUP)),
1632 "blob was never registered");
1633
1634 PL_DHashTableOperate(&mBlobs, &aBlob->mData, PL_DHASH_REMOVE);
1635
1636 // N.B. that we _don't_ release the literal: we only held a weak
1637 // reference to it in the hashtable.
1638 PR_LOG(gLog, PR_LOG_DEBUG,
1639 ("rdfserv unregister-blob [%p] %s",
1640 aBlob, aBlob->mData.mBytes));
1641
1642 return NS_OK;
1643 }

mercurial