1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/rdf/base/src/nsRDFService.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1643 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. 1.9 + * 1.10 + * 1.11 + * This Original Code has been modified by IBM Corporation. 1.12 + * Modifications made by IBM described herein are 1.13 + * Copyright (c) International Business Machines 1.14 + * Corporation, 2000 1.15 + * 1.16 + * Modifications to Mozilla code or documentation 1.17 + * identified per MPL Section 3.3 1.18 + * 1.19 + * Date Modified by Description of modification 1.20 + * 03/27/2000 IBM Corp. Added PR_CALLBACK for Optlink 1.21 + * use in OS2 1.22 + */ 1.23 + 1.24 +/* 1.25 + 1.26 + This file provides the implementation for the RDF service manager. 1.27 + 1.28 + TO DO 1.29 + ----- 1.30 + 1.31 + 1) Implement the CreateDataBase() methods. 1.32 + 1.33 + 2) Cache date and int literals. 1.34 + 1.35 + */ 1.36 + 1.37 +#include "nsRDFService.h" 1.38 +#include "nsCOMPtr.h" 1.39 +#include "nsAutoPtr.h" 1.40 +#include "nsMemory.h" 1.41 +#include "nsIAtom.h" 1.42 +#include "nsIComponentManager.h" 1.43 +#include "nsIRDFDataSource.h" 1.44 +#include "nsIRDFNode.h" 1.45 +#include "nsIRDFRemoteDataSource.h" 1.46 +#include "nsIServiceManager.h" 1.47 +#include "nsIFactory.h" 1.48 +#include "nsRDFCID.h" 1.49 +#include "nsString.h" 1.50 +#include "nsXPIDLString.h" 1.51 +#include "nsNetUtil.h" 1.52 +#include "pldhash.h" 1.53 +#include "plhash.h" 1.54 +#include "plstr.h" 1.55 +#include "prlog.h" 1.56 +#include "prprf.h" 1.57 +#include "prmem.h" 1.58 +#include "rdf.h" 1.59 +#include "nsCRT.h" 1.60 +#include "nsCRTGlue.h" 1.61 +#include "mozilla/HashFunctions.h" 1.62 + 1.63 +using namespace mozilla; 1.64 + 1.65 +//////////////////////////////////////////////////////////////////////// 1.66 + 1.67 +static NS_DEFINE_CID(kRDFXMLDataSourceCID, NS_RDFXMLDATASOURCE_CID); 1.68 +static NS_DEFINE_CID(kRDFDefaultResourceCID, NS_RDFDEFAULTRESOURCE_CID); 1.69 + 1.70 +static NS_DEFINE_IID(kIRDFLiteralIID, NS_IRDFLITERAL_IID); 1.71 +static NS_DEFINE_IID(kIRDFDateIID, NS_IRDFDATE_IID); 1.72 +static NS_DEFINE_IID(kIRDFIntIID, NS_IRDFINT_IID); 1.73 +static NS_DEFINE_IID(kIRDFNodeIID, NS_IRDFNODE_IID); 1.74 +static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); 1.75 + 1.76 +#ifdef PR_LOGGING 1.77 +static PRLogModuleInfo* gLog = nullptr; 1.78 +#endif 1.79 + 1.80 +class BlobImpl; 1.81 + 1.82 +// These functions are copied from nsprpub/lib/ds/plhash.c, with one 1.83 +// change to free the key in DataSourceFreeEntry. 1.84 +// XXX sigh, why were DefaultAllocTable et. al. declared static, anyway? 1.85 + 1.86 +static void * 1.87 +DataSourceAllocTable(void *pool, size_t size) 1.88 +{ 1.89 + return PR_MALLOC(size); 1.90 +} 1.91 + 1.92 +static void 1.93 +DataSourceFreeTable(void *pool, void *item) 1.94 +{ 1.95 + PR_Free(item); 1.96 +} 1.97 + 1.98 +static PLHashEntry * 1.99 +DataSourceAllocEntry(void *pool, const void *key) 1.100 +{ 1.101 + return PR_NEW(PLHashEntry); 1.102 +} 1.103 + 1.104 +static void 1.105 +DataSourceFreeEntry(void *pool, PLHashEntry *he, unsigned flag) 1.106 +{ 1.107 + if (flag == HT_FREE_ENTRY) { 1.108 + PL_strfree((char*) he->key); 1.109 + PR_Free(he); 1.110 + } 1.111 +} 1.112 + 1.113 +static PLHashAllocOps dataSourceHashAllocOps = { 1.114 + DataSourceAllocTable, DataSourceFreeTable, 1.115 + DataSourceAllocEntry, DataSourceFreeEntry 1.116 +}; 1.117 + 1.118 +//---------------------------------------------------------------------- 1.119 +// 1.120 +// For the mResources hashtable. 1.121 +// 1.122 + 1.123 +struct ResourceHashEntry : public PLDHashEntryHdr { 1.124 + const char *mKey; 1.125 + nsIRDFResource *mResource; 1.126 + 1.127 + static PLDHashNumber 1.128 + HashKey(PLDHashTable *table, const void *key) 1.129 + { 1.130 + return HashString(static_cast<const char *>(key)); 1.131 + } 1.132 + 1.133 + static bool 1.134 + MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr, 1.135 + const void *key) 1.136 + { 1.137 + const ResourceHashEntry *entry = 1.138 + static_cast<const ResourceHashEntry *>(hdr); 1.139 + 1.140 + return 0 == nsCRT::strcmp(static_cast<const char *>(key), 1.141 + entry->mKey); 1.142 + } 1.143 +}; 1.144 + 1.145 +static const PLDHashTableOps gResourceTableOps = { 1.146 + PL_DHashAllocTable, 1.147 + PL_DHashFreeTable, 1.148 + ResourceHashEntry::HashKey, 1.149 + ResourceHashEntry::MatchEntry, 1.150 + PL_DHashMoveEntryStub, 1.151 + PL_DHashClearEntryStub, 1.152 + PL_DHashFinalizeStub, 1.153 + nullptr 1.154 +}; 1.155 + 1.156 +// ---------------------------------------------------------------------- 1.157 +// 1.158 +// For the mLiterals hashtable. 1.159 +// 1.160 + 1.161 +struct LiteralHashEntry : public PLDHashEntryHdr { 1.162 + nsIRDFLiteral *mLiteral; 1.163 + const char16_t *mKey; 1.164 + 1.165 + static PLDHashNumber 1.166 + HashKey(PLDHashTable *table, const void *key) 1.167 + { 1.168 + return HashString(static_cast<const char16_t *>(key)); 1.169 + } 1.170 + 1.171 + static bool 1.172 + MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr, 1.173 + const void *key) 1.174 + { 1.175 + const LiteralHashEntry *entry = 1.176 + static_cast<const LiteralHashEntry *>(hdr); 1.177 + 1.178 + return 0 == nsCRT::strcmp(static_cast<const char16_t *>(key), 1.179 + entry->mKey); 1.180 + } 1.181 +}; 1.182 + 1.183 +static const PLDHashTableOps gLiteralTableOps = { 1.184 + PL_DHashAllocTable, 1.185 + PL_DHashFreeTable, 1.186 + LiteralHashEntry::HashKey, 1.187 + LiteralHashEntry::MatchEntry, 1.188 + PL_DHashMoveEntryStub, 1.189 + PL_DHashClearEntryStub, 1.190 + PL_DHashFinalizeStub, 1.191 + nullptr 1.192 +}; 1.193 + 1.194 +// ---------------------------------------------------------------------- 1.195 +// 1.196 +// For the mInts hashtable. 1.197 +// 1.198 + 1.199 +struct IntHashEntry : public PLDHashEntryHdr { 1.200 + nsIRDFInt *mInt; 1.201 + int32_t mKey; 1.202 + 1.203 + static PLDHashNumber 1.204 + HashKey(PLDHashTable *table, const void *key) 1.205 + { 1.206 + return PLDHashNumber(*static_cast<const int32_t *>(key)); 1.207 + } 1.208 + 1.209 + static bool 1.210 + MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr, 1.211 + const void *key) 1.212 + { 1.213 + const IntHashEntry *entry = 1.214 + static_cast<const IntHashEntry *>(hdr); 1.215 + 1.216 + return *static_cast<const int32_t *>(key) == entry->mKey; 1.217 + } 1.218 +}; 1.219 + 1.220 +static const PLDHashTableOps gIntTableOps = { 1.221 + PL_DHashAllocTable, 1.222 + PL_DHashFreeTable, 1.223 + IntHashEntry::HashKey, 1.224 + IntHashEntry::MatchEntry, 1.225 + PL_DHashMoveEntryStub, 1.226 + PL_DHashClearEntryStub, 1.227 + PL_DHashFinalizeStub, 1.228 + nullptr 1.229 +}; 1.230 + 1.231 +// ---------------------------------------------------------------------- 1.232 +// 1.233 +// For the mDates hashtable. 1.234 +// 1.235 + 1.236 +struct DateHashEntry : public PLDHashEntryHdr { 1.237 + nsIRDFDate *mDate; 1.238 + PRTime mKey; 1.239 + 1.240 + static PLDHashNumber 1.241 + HashKey(PLDHashTable *table, const void *key) 1.242 + { 1.243 + // xor the low 32 bits with the high 32 bits. 1.244 + PRTime t = *static_cast<const PRTime *>(key); 1.245 + int32_t h32 = int32_t(t >> 32); 1.246 + int32_t l32 = int32_t(0xffffffff & t); 1.247 + return PLDHashNumber(l32 ^ h32); 1.248 + } 1.249 + 1.250 + static bool 1.251 + MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr, 1.252 + const void *key) 1.253 + { 1.254 + const DateHashEntry *entry = 1.255 + static_cast<const DateHashEntry *>(hdr); 1.256 + 1.257 + return *static_cast<const PRTime *>(key) == entry->mKey; 1.258 + } 1.259 +}; 1.260 + 1.261 +static const PLDHashTableOps gDateTableOps = { 1.262 + PL_DHashAllocTable, 1.263 + PL_DHashFreeTable, 1.264 + DateHashEntry::HashKey, 1.265 + DateHashEntry::MatchEntry, 1.266 + PL_DHashMoveEntryStub, 1.267 + PL_DHashClearEntryStub, 1.268 + PL_DHashFinalizeStub, 1.269 + nullptr 1.270 +}; 1.271 + 1.272 +class BlobImpl : public nsIRDFBlob 1.273 +{ 1.274 +public: 1.275 + struct Data { 1.276 + int32_t mLength; 1.277 + uint8_t *mBytes; 1.278 + }; 1.279 + 1.280 + BlobImpl(const uint8_t *aBytes, int32_t aLength) 1.281 + { 1.282 + mData.mLength = aLength; 1.283 + mData.mBytes = new uint8_t[aLength]; 1.284 + memcpy(mData.mBytes, aBytes, aLength); 1.285 + NS_ADDREF(RDFServiceImpl::gRDFService); 1.286 + RDFServiceImpl::gRDFService->RegisterBlob(this); 1.287 + } 1.288 + 1.289 + virtual ~BlobImpl() 1.290 + { 1.291 + RDFServiceImpl::gRDFService->UnregisterBlob(this); 1.292 + // Use NS_RELEASE2() here, because we want to decrease the 1.293 + // refcount, but not null out the gRDFService pointer (which is 1.294 + // what a vanilla NS_RELEASE() would do). 1.295 + nsrefcnt refcnt; 1.296 + NS_RELEASE2(RDFServiceImpl::gRDFService, refcnt); 1.297 + delete[] mData.mBytes; 1.298 + } 1.299 + 1.300 + NS_DECL_ISUPPORTS 1.301 + NS_DECL_NSIRDFNODE 1.302 + NS_DECL_NSIRDFBLOB 1.303 + 1.304 + Data mData; 1.305 +}; 1.306 + 1.307 +NS_IMPL_ISUPPORTS(BlobImpl, nsIRDFNode, nsIRDFBlob) 1.308 + 1.309 +NS_IMETHODIMP 1.310 +BlobImpl::EqualsNode(nsIRDFNode *aNode, bool *aEquals) 1.311 +{ 1.312 + nsCOMPtr<nsIRDFBlob> blob = do_QueryInterface(aNode); 1.313 + if (blob) { 1.314 + int32_t length; 1.315 + blob->GetLength(&length); 1.316 + 1.317 + if (length == mData.mLength) { 1.318 + const uint8_t *bytes; 1.319 + blob->GetValue(&bytes); 1.320 + 1.321 + if (0 == memcmp(bytes, mData.mBytes, length)) { 1.322 + *aEquals = true; 1.323 + return NS_OK; 1.324 + } 1.325 + } 1.326 + } 1.327 + 1.328 + *aEquals = false; 1.329 + return NS_OK; 1.330 +} 1.331 + 1.332 +NS_IMETHODIMP 1.333 +BlobImpl::GetValue(const uint8_t **aResult) 1.334 +{ 1.335 + *aResult = mData.mBytes; 1.336 + return NS_OK; 1.337 +} 1.338 + 1.339 +NS_IMETHODIMP 1.340 +BlobImpl::GetLength(int32_t *aResult) 1.341 +{ 1.342 + *aResult = mData.mLength; 1.343 + return NS_OK; 1.344 +} 1.345 + 1.346 +// ---------------------------------------------------------------------- 1.347 +// 1.348 +// For the mBlobs hashtable. 1.349 +// 1.350 + 1.351 +struct BlobHashEntry : public PLDHashEntryHdr { 1.352 + BlobImpl *mBlob; 1.353 + 1.354 + static PLDHashNumber 1.355 + HashKey(PLDHashTable *table, const void *key) 1.356 + { 1.357 + const BlobImpl::Data *data = 1.358 + static_cast<const BlobImpl::Data *>(key); 1.359 + return HashBytes(data->mBytes, data->mLength); 1.360 + } 1.361 + 1.362 + static bool 1.363 + MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr, 1.364 + const void *key) 1.365 + { 1.366 + const BlobHashEntry *entry = 1.367 + static_cast<const BlobHashEntry *>(hdr); 1.368 + 1.369 + const BlobImpl::Data *left = &entry->mBlob->mData; 1.370 + 1.371 + const BlobImpl::Data *right = 1.372 + static_cast<const BlobImpl::Data *>(key); 1.373 + 1.374 + return (left->mLength == right->mLength) 1.375 + && 0 == memcmp(left->mBytes, right->mBytes, right->mLength); 1.376 + } 1.377 +}; 1.378 + 1.379 +static const PLDHashTableOps gBlobTableOps = { 1.380 + PL_DHashAllocTable, 1.381 + PL_DHashFreeTable, 1.382 + BlobHashEntry::HashKey, 1.383 + BlobHashEntry::MatchEntry, 1.384 + PL_DHashMoveEntryStub, 1.385 + PL_DHashClearEntryStub, 1.386 + PL_DHashFinalizeStub, 1.387 + nullptr 1.388 +}; 1.389 + 1.390 +//////////////////////////////////////////////////////////////////////// 1.391 +// LiteralImpl 1.392 +// 1.393 +// Currently, all literals are implemented exactly the same way; 1.394 +// i.e., there is are no resource factories to allow you to generate 1.395 +// customer resources. I doubt that makes sense, anyway. 1.396 +// 1.397 +class LiteralImpl : public nsIRDFLiteral { 1.398 +public: 1.399 + static nsresult 1.400 + Create(const char16_t* aValue, nsIRDFLiteral** aResult); 1.401 + 1.402 + // nsISupports 1.403 + NS_DECL_THREADSAFE_ISUPPORTS 1.404 + 1.405 + // nsIRDFNode 1.406 + NS_DECL_NSIRDFNODE 1.407 + 1.408 + // nsIRDFLiteral 1.409 + NS_DECL_NSIRDFLITERAL 1.410 + 1.411 +protected: 1.412 + LiteralImpl(const char16_t* s); 1.413 + virtual ~LiteralImpl(); 1.414 + 1.415 + const char16_t* GetValue() const { 1.416 + size_t objectSize = ((sizeof(LiteralImpl) + sizeof(char16_t) - 1) / sizeof(char16_t)) * sizeof(char16_t); 1.417 + return reinterpret_cast<const char16_t*>(reinterpret_cast<const unsigned char*>(this) + objectSize); 1.418 + } 1.419 +}; 1.420 + 1.421 + 1.422 +nsresult 1.423 +LiteralImpl::Create(const char16_t* aValue, nsIRDFLiteral** aResult) 1.424 +{ 1.425 + // Goofy math to get alignment right. Copied from nsSharedString.h. 1.426 + size_t objectSize = ((sizeof(LiteralImpl) + sizeof(char16_t) - 1) / sizeof(char16_t)) * sizeof(char16_t); 1.427 + size_t stringLen = nsCharTraits<char16_t>::length(aValue); 1.428 + size_t stringSize = (stringLen + 1) * sizeof(char16_t); 1.429 + 1.430 + void* objectPtr = operator new(objectSize + stringSize); 1.431 + if (! objectPtr) 1.432 + return NS_ERROR_NULL_POINTER; 1.433 + 1.434 + char16_t* buf = reinterpret_cast<char16_t*>(static_cast<unsigned char*>(objectPtr) + objectSize); 1.435 + nsCharTraits<char16_t>::copy(buf, aValue, stringLen + 1); 1.436 + 1.437 + NS_ADDREF(*aResult = new (objectPtr) LiteralImpl(buf)); 1.438 + return NS_OK; 1.439 +} 1.440 + 1.441 + 1.442 +LiteralImpl::LiteralImpl(const char16_t* s) 1.443 +{ 1.444 + RDFServiceImpl::gRDFService->RegisterLiteral(this); 1.445 + NS_ADDREF(RDFServiceImpl::gRDFService); 1.446 +} 1.447 + 1.448 +LiteralImpl::~LiteralImpl() 1.449 +{ 1.450 + RDFServiceImpl::gRDFService->UnregisterLiteral(this); 1.451 + 1.452 + // Use NS_RELEASE2() here, because we want to decrease the 1.453 + // refcount, but not null out the gRDFService pointer (which is 1.454 + // what a vanilla NS_RELEASE() would do). 1.455 + nsrefcnt refcnt; 1.456 + NS_RELEASE2(RDFServiceImpl::gRDFService, refcnt); 1.457 +} 1.458 + 1.459 +NS_IMPL_ADDREF(LiteralImpl) 1.460 +NS_IMPL_RELEASE(LiteralImpl) 1.461 + 1.462 +nsresult 1.463 +LiteralImpl::QueryInterface(REFNSIID iid, void** result) 1.464 +{ 1.465 + if (! result) 1.466 + return NS_ERROR_NULL_POINTER; 1.467 + 1.468 + *result = nullptr; 1.469 + if (iid.Equals(kIRDFLiteralIID) || 1.470 + iid.Equals(kIRDFNodeIID) || 1.471 + iid.Equals(kISupportsIID)) { 1.472 + *result = static_cast<nsIRDFLiteral*>(this); 1.473 + AddRef(); 1.474 + return NS_OK; 1.475 + } 1.476 + return NS_NOINTERFACE; 1.477 +} 1.478 + 1.479 +NS_IMETHODIMP 1.480 +LiteralImpl::EqualsNode(nsIRDFNode* aNode, bool* aResult) 1.481 +{ 1.482 + nsresult rv; 1.483 + nsIRDFLiteral* literal; 1.484 + rv = aNode->QueryInterface(kIRDFLiteralIID, (void**) &literal); 1.485 + if (NS_SUCCEEDED(rv)) { 1.486 + *aResult = (static_cast<nsIRDFLiteral*>(this) == literal); 1.487 + NS_RELEASE(literal); 1.488 + return NS_OK; 1.489 + } 1.490 + else if (rv == NS_NOINTERFACE) { 1.491 + *aResult = false; 1.492 + return NS_OK; 1.493 + } 1.494 + else { 1.495 + return rv; 1.496 + } 1.497 +} 1.498 + 1.499 +NS_IMETHODIMP 1.500 +LiteralImpl::GetValue(char16_t* *value) 1.501 +{ 1.502 + NS_ASSERTION(value, "null ptr"); 1.503 + if (! value) 1.504 + return NS_ERROR_NULL_POINTER; 1.505 + 1.506 + const char16_t *temp = GetValue(); 1.507 + *value = temp? NS_strdup(temp) : 0; 1.508 + return NS_OK; 1.509 +} 1.510 + 1.511 + 1.512 +NS_IMETHODIMP 1.513 +LiteralImpl::GetValueConst(const char16_t** aValue) 1.514 +{ 1.515 + *aValue = GetValue(); 1.516 + return NS_OK; 1.517 +} 1.518 + 1.519 +//////////////////////////////////////////////////////////////////////// 1.520 +// DateImpl 1.521 +// 1.522 + 1.523 +class DateImpl : public nsIRDFDate { 1.524 +public: 1.525 + DateImpl(const PRTime s); 1.526 + virtual ~DateImpl(); 1.527 + 1.528 + // nsISupports 1.529 + NS_DECL_ISUPPORTS 1.530 + 1.531 + // nsIRDFNode 1.532 + NS_DECL_NSIRDFNODE 1.533 + 1.534 + // nsIRDFDate 1.535 + NS_IMETHOD GetValue(PRTime *value); 1.536 + 1.537 +private: 1.538 + nsresult EqualsDate(nsIRDFDate* date, bool* result); 1.539 + PRTime mValue; 1.540 +}; 1.541 + 1.542 + 1.543 +DateImpl::DateImpl(const PRTime s) 1.544 + : mValue(s) 1.545 +{ 1.546 + RDFServiceImpl::gRDFService->RegisterDate(this); 1.547 + NS_ADDREF(RDFServiceImpl::gRDFService); 1.548 +} 1.549 + 1.550 +DateImpl::~DateImpl() 1.551 +{ 1.552 + RDFServiceImpl::gRDFService->UnregisterDate(this); 1.553 + 1.554 + // Use NS_RELEASE2() here, because we want to decrease the 1.555 + // refcount, but not null out the gRDFService pointer (which is 1.556 + // what a vanilla NS_RELEASE() would do). 1.557 + nsrefcnt refcnt; 1.558 + NS_RELEASE2(RDFServiceImpl::gRDFService, refcnt); 1.559 +} 1.560 + 1.561 +NS_IMPL_ADDREF(DateImpl) 1.562 +NS_IMPL_RELEASE(DateImpl) 1.563 + 1.564 +nsresult 1.565 +DateImpl::QueryInterface(REFNSIID iid, void** result) 1.566 +{ 1.567 + if (! result) 1.568 + return NS_ERROR_NULL_POINTER; 1.569 + 1.570 + *result = nullptr; 1.571 + if (iid.Equals(kIRDFDateIID) || 1.572 + iid.Equals(kIRDFNodeIID) || 1.573 + iid.Equals(kISupportsIID)) { 1.574 + *result = static_cast<nsIRDFDate*>(this); 1.575 + AddRef(); 1.576 + return NS_OK; 1.577 + } 1.578 + return NS_NOINTERFACE; 1.579 +} 1.580 + 1.581 +NS_IMETHODIMP 1.582 +DateImpl::EqualsNode(nsIRDFNode* node, bool* result) 1.583 +{ 1.584 + nsresult rv; 1.585 + nsIRDFDate* date; 1.586 + if (NS_SUCCEEDED(node->QueryInterface(kIRDFDateIID, (void**) &date))) { 1.587 + rv = EqualsDate(date, result); 1.588 + NS_RELEASE(date); 1.589 + } 1.590 + else { 1.591 + *result = false; 1.592 + rv = NS_OK; 1.593 + } 1.594 + return rv; 1.595 +} 1.596 + 1.597 +NS_IMETHODIMP 1.598 +DateImpl::GetValue(PRTime *value) 1.599 +{ 1.600 + NS_ASSERTION(value, "null ptr"); 1.601 + if (! value) 1.602 + return NS_ERROR_NULL_POINTER; 1.603 + 1.604 + *value = mValue; 1.605 + return NS_OK; 1.606 +} 1.607 + 1.608 + 1.609 +nsresult 1.610 +DateImpl::EqualsDate(nsIRDFDate* date, bool* result) 1.611 +{ 1.612 + NS_ASSERTION(date && result, "null ptr"); 1.613 + if (!date || !result) 1.614 + return NS_ERROR_NULL_POINTER; 1.615 + 1.616 + nsresult rv; 1.617 + PRTime p; 1.618 + if (NS_FAILED(rv = date->GetValue(&p))) 1.619 + return rv; 1.620 + 1.621 + *result = p == mValue; 1.622 + return NS_OK; 1.623 +} 1.624 + 1.625 +//////////////////////////////////////////////////////////////////////// 1.626 +// IntImpl 1.627 +// 1.628 + 1.629 +class IntImpl : public nsIRDFInt { 1.630 +public: 1.631 + IntImpl(int32_t s); 1.632 + virtual ~IntImpl(); 1.633 + 1.634 + // nsISupports 1.635 + NS_DECL_ISUPPORTS 1.636 + 1.637 + // nsIRDFNode 1.638 + NS_DECL_NSIRDFNODE 1.639 + 1.640 + // nsIRDFInt 1.641 + NS_IMETHOD GetValue(int32_t *value); 1.642 + 1.643 +private: 1.644 + nsresult EqualsInt(nsIRDFInt* value, bool* result); 1.645 + int32_t mValue; 1.646 +}; 1.647 + 1.648 + 1.649 +IntImpl::IntImpl(int32_t s) 1.650 + : mValue(s) 1.651 +{ 1.652 + RDFServiceImpl::gRDFService->RegisterInt(this); 1.653 + NS_ADDREF(RDFServiceImpl::gRDFService); 1.654 +} 1.655 + 1.656 +IntImpl::~IntImpl() 1.657 +{ 1.658 + RDFServiceImpl::gRDFService->UnregisterInt(this); 1.659 + 1.660 + // Use NS_RELEASE2() here, because we want to decrease the 1.661 + // refcount, but not null out the gRDFService pointer (which is 1.662 + // what a vanilla NS_RELEASE() would do). 1.663 + nsrefcnt refcnt; 1.664 + NS_RELEASE2(RDFServiceImpl::gRDFService, refcnt); 1.665 +} 1.666 + 1.667 +NS_IMPL_ADDREF(IntImpl) 1.668 +NS_IMPL_RELEASE(IntImpl) 1.669 + 1.670 +nsresult 1.671 +IntImpl::QueryInterface(REFNSIID iid, void** result) 1.672 +{ 1.673 + if (! result) 1.674 + return NS_ERROR_NULL_POINTER; 1.675 + 1.676 + *result = nullptr; 1.677 + if (iid.Equals(kIRDFIntIID) || 1.678 + iid.Equals(kIRDFNodeIID) || 1.679 + iid.Equals(kISupportsIID)) { 1.680 + *result = static_cast<nsIRDFInt*>(this); 1.681 + AddRef(); 1.682 + return NS_OK; 1.683 + } 1.684 + return NS_NOINTERFACE; 1.685 +} 1.686 + 1.687 +NS_IMETHODIMP 1.688 +IntImpl::EqualsNode(nsIRDFNode* node, bool* result) 1.689 +{ 1.690 + nsresult rv; 1.691 + nsIRDFInt* intValue; 1.692 + if (NS_SUCCEEDED(node->QueryInterface(kIRDFIntIID, (void**) &intValue))) { 1.693 + rv = EqualsInt(intValue, result); 1.694 + NS_RELEASE(intValue); 1.695 + } 1.696 + else { 1.697 + *result = false; 1.698 + rv = NS_OK; 1.699 + } 1.700 + return rv; 1.701 +} 1.702 + 1.703 +NS_IMETHODIMP 1.704 +IntImpl::GetValue(int32_t *value) 1.705 +{ 1.706 + NS_ASSERTION(value, "null ptr"); 1.707 + if (! value) 1.708 + return NS_ERROR_NULL_POINTER; 1.709 + 1.710 + *value = mValue; 1.711 + return NS_OK; 1.712 +} 1.713 + 1.714 + 1.715 +nsresult 1.716 +IntImpl::EqualsInt(nsIRDFInt* intValue, bool* result) 1.717 +{ 1.718 + NS_ASSERTION(intValue && result, "null ptr"); 1.719 + if (!intValue || !result) 1.720 + return NS_ERROR_NULL_POINTER; 1.721 + 1.722 + nsresult rv; 1.723 + int32_t p; 1.724 + if (NS_FAILED(rv = intValue->GetValue(&p))) 1.725 + return rv; 1.726 + 1.727 + *result = (p == mValue); 1.728 + return NS_OK; 1.729 +} 1.730 + 1.731 +//////////////////////////////////////////////////////////////////////// 1.732 +// RDFServiceImpl 1.733 + 1.734 +RDFServiceImpl* 1.735 +RDFServiceImpl::gRDFService; 1.736 + 1.737 +RDFServiceImpl::RDFServiceImpl() 1.738 + : mNamedDataSources(nullptr) 1.739 +{ 1.740 + mResources.ops = nullptr; 1.741 + mLiterals.ops = nullptr; 1.742 + mInts.ops = nullptr; 1.743 + mDates.ops = nullptr; 1.744 + mBlobs.ops = nullptr; 1.745 + gRDFService = this; 1.746 +} 1.747 + 1.748 +nsresult 1.749 +RDFServiceImpl::Init() 1.750 +{ 1.751 + nsresult rv; 1.752 + 1.753 + mNamedDataSources = PL_NewHashTable(23, 1.754 + PL_HashString, 1.755 + PL_CompareStrings, 1.756 + PL_CompareValues, 1.757 + &dataSourceHashAllocOps, nullptr); 1.758 + 1.759 + if (! mNamedDataSources) 1.760 + return NS_ERROR_OUT_OF_MEMORY; 1.761 + 1.762 + PL_DHashTableInit(&mResources, &gResourceTableOps, nullptr, 1.763 + sizeof(ResourceHashEntry), PL_DHASH_MIN_SIZE); 1.764 + 1.765 + PL_DHashTableInit(&mLiterals, &gLiteralTableOps, nullptr, 1.766 + sizeof(LiteralHashEntry), PL_DHASH_MIN_SIZE); 1.767 + 1.768 + PL_DHashTableInit(&mInts, &gIntTableOps, nullptr, 1.769 + sizeof(IntHashEntry), PL_DHASH_MIN_SIZE); 1.770 + 1.771 + PL_DHashTableInit(&mDates, &gDateTableOps, nullptr, 1.772 + sizeof(DateHashEntry), PL_DHASH_MIN_SIZE); 1.773 + 1.774 + PL_DHashTableInit(&mBlobs, &gBlobTableOps, nullptr, 1.775 + sizeof(BlobHashEntry), PL_DHASH_MIN_SIZE); 1.776 + 1.777 + mDefaultResourceFactory = do_GetClassObject(kRDFDefaultResourceCID, &rv); 1.778 + NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get default resource factory"); 1.779 + if (NS_FAILED(rv)) return rv; 1.780 + 1.781 +#ifdef PR_LOGGING 1.782 + if (! gLog) 1.783 + gLog = PR_NewLogModule("nsRDFService"); 1.784 +#endif 1.785 + 1.786 + return NS_OK; 1.787 +} 1.788 + 1.789 + 1.790 +RDFServiceImpl::~RDFServiceImpl() 1.791 +{ 1.792 + if (mNamedDataSources) { 1.793 + PL_HashTableDestroy(mNamedDataSources); 1.794 + mNamedDataSources = nullptr; 1.795 + } 1.796 + if (mResources.ops) 1.797 + PL_DHashTableFinish(&mResources); 1.798 + if (mLiterals.ops) 1.799 + PL_DHashTableFinish(&mLiterals); 1.800 + if (mInts.ops) 1.801 + PL_DHashTableFinish(&mInts); 1.802 + if (mDates.ops) 1.803 + PL_DHashTableFinish(&mDates); 1.804 + if (mBlobs.ops) 1.805 + PL_DHashTableFinish(&mBlobs); 1.806 + gRDFService = nullptr; 1.807 +} 1.808 + 1.809 + 1.810 +// static 1.811 +nsresult 1.812 +RDFServiceImpl::CreateSingleton(nsISupports* aOuter, 1.813 + const nsIID& aIID, void **aResult) 1.814 +{ 1.815 + NS_ENSURE_NO_AGGREGATION(aOuter); 1.816 + 1.817 + if (gRDFService) { 1.818 + NS_ERROR("Trying to create RDF serviec twice."); 1.819 + return gRDFService->QueryInterface(aIID, aResult); 1.820 + } 1.821 + 1.822 + nsRefPtr<RDFServiceImpl> serv = new RDFServiceImpl(); 1.823 + if (!serv) 1.824 + return NS_ERROR_OUT_OF_MEMORY; 1.825 + 1.826 + nsresult rv = serv->Init(); 1.827 + if (NS_FAILED(rv)) 1.828 + return rv; 1.829 + 1.830 + return serv->QueryInterface(aIID, aResult); 1.831 +} 1.832 + 1.833 +NS_IMPL_ISUPPORTS(RDFServiceImpl, nsIRDFService, nsISupportsWeakReference) 1.834 + 1.835 +// Per RFC2396. 1.836 +static const uint8_t 1.837 +kLegalSchemeChars[] = { 1.838 + // ASCII Bits Ordered Hex 1.839 + // 01234567 76543210 1.840 + 0x00, // 00-07 1.841 + 0x00, // 08-0F 1.842 + 0x00, // 10-17 1.843 + 0x00, // 18-1F 1.844 + 0x00, // 20-27 !"#$%&' 00000000 00000000 1.845 + 0x28, // 28-2F ()*+,-./ 00010100 00101000 0x28 1.846 + 0xff, // 30-37 01234567 11111111 11111111 0xFF 1.847 + 0x03, // 38-3F 89:;<=>? 11000000 00000011 0x03 1.848 + 0xfe, // 40-47 @ABCDEFG 01111111 11111110 0xFE 1.849 + 0xff, // 48-4F HIJKLMNO 11111111 11111111 0xFF 1.850 + 0xff, // 50-57 PQRSTUVW 11111111 11111111 0xFF 1.851 + 0x87, // 58-5F XYZ[\]^_ 11100001 10000111 0x87 1.852 + 0xfe, // 60-67 `abcdefg 01111111 11111110 0xFE 1.853 + 0xff, // 68-6F hijklmno 11111111 11111111 0xFF 1.854 + 0xff, // 70-77 pqrstuvw 11111111 11111111 0xFF 1.855 + 0x07, // 78-7F xyz{|}~ 11100000 00000111 0x07 1.856 + 0x00, 0x00, 0x00, 0x00, // >= 80 1.857 + 0x00, 0x00, 0x00, 0x00, 1.858 + 0x00, 0x00, 0x00, 0x00, 1.859 + 0x00, 0x00, 0x00, 0x00 1.860 +}; 1.861 + 1.862 +static inline bool 1.863 +IsLegalSchemeCharacter(const char aChar) 1.864 +{ 1.865 + uint8_t mask = kLegalSchemeChars[aChar >> 3]; 1.866 + uint8_t bit = 1u << (aChar & 0x7); 1.867 + return bool((mask & bit) != 0); 1.868 +} 1.869 + 1.870 + 1.871 +NS_IMETHODIMP 1.872 +RDFServiceImpl::GetResource(const nsACString& aURI, nsIRDFResource** aResource) 1.873 +{ 1.874 + // Sanity checks 1.875 + NS_PRECONDITION(aResource != nullptr, "null ptr"); 1.876 + NS_PRECONDITION(!aURI.IsEmpty(), "URI is empty"); 1.877 + if (! aResource) 1.878 + return NS_ERROR_NULL_POINTER; 1.879 + if (aURI.IsEmpty()) 1.880 + return NS_ERROR_INVALID_ARG; 1.881 + 1.882 + const nsAFlatCString& flatURI = PromiseFlatCString(aURI); 1.883 + PR_LOG(gLog, PR_LOG_DEBUG, ("rdfserv get-resource %s", flatURI.get())); 1.884 + 1.885 + // First, check the cache to see if we've already created and 1.886 + // registered this thing. 1.887 + PLDHashEntryHdr *hdr = 1.888 + PL_DHashTableOperate(&mResources, flatURI.get(), PL_DHASH_LOOKUP); 1.889 + 1.890 + if (PL_DHASH_ENTRY_IS_BUSY(hdr)) { 1.891 + ResourceHashEntry *entry = static_cast<ResourceHashEntry *>(hdr); 1.892 + NS_ADDREF(*aResource = entry->mResource); 1.893 + return NS_OK; 1.894 + } 1.895 + 1.896 + // Nope. So go to the repository to create it. 1.897 + 1.898 + // Compute the scheme of the URI. Scan forward until we either: 1.899 + // 1.900 + // 1. Reach the end of the string 1.901 + // 2. Encounter a non-alpha character 1.902 + // 3. Encouter a colon. 1.903 + // 1.904 + // If we encounter a colon _before_ encountering a non-alpha 1.905 + // character, then assume it's the scheme. 1.906 + // 1.907 + // XXX Although it's really not correct, we'll allow underscore 1.908 + // characters ('_'), too. 1.909 + nsACString::const_iterator p, end; 1.910 + aURI.BeginReading(p); 1.911 + aURI.EndReading(end); 1.912 + while (p != end && IsLegalSchemeCharacter(*p)) 1.913 + ++p; 1.914 + 1.915 + nsresult rv; 1.916 + nsCOMPtr<nsIFactory> factory; 1.917 + 1.918 + nsACString::const_iterator begin; 1.919 + aURI.BeginReading(begin); 1.920 + if (*p == ':') { 1.921 + // There _was_ a scheme. First see if it's the same scheme 1.922 + // that we just tried to use... 1.923 + if (mLastFactory && mLastURIPrefix.Equals(Substring(begin, p))) 1.924 + factory = mLastFactory; 1.925 + else { 1.926 + // Try to find a factory using the component manager. 1.927 + nsACString::const_iterator begin; 1.928 + aURI.BeginReading(begin); 1.929 + nsAutoCString contractID; 1.930 + contractID = NS_LITERAL_CSTRING(NS_RDF_RESOURCE_FACTORY_CONTRACTID_PREFIX) + 1.931 + Substring(begin, p); 1.932 + 1.933 + factory = do_GetClassObject(contractID.get()); 1.934 + if (factory) { 1.935 + // Store the factory in our one-element cache. 1.936 + if (p != begin) { 1.937 + mLastFactory = factory; 1.938 + mLastURIPrefix = Substring(begin, p); 1.939 + } 1.940 + } 1.941 + } 1.942 + } 1.943 + 1.944 + if (! factory) { 1.945 + // fall through to using the "default" resource factory if either: 1.946 + // 1.947 + // 1. The URI didn't have a scheme, or 1.948 + // 2. There was no resource factory registered for the scheme. 1.949 + factory = mDefaultResourceFactory; 1.950 + 1.951 + // Store the factory in our one-element cache. 1.952 + if (p != begin) { 1.953 + mLastFactory = factory; 1.954 + mLastURIPrefix = Substring(begin, p); 1.955 + } 1.956 + } 1.957 + 1.958 + nsIRDFResource *result; 1.959 + rv = factory->CreateInstance(nullptr, NS_GET_IID(nsIRDFResource), (void**) &result); 1.960 + if (NS_FAILED(rv)) return rv; 1.961 + 1.962 + // Now initialize it with its URI. At this point, the resource 1.963 + // implementation should register itself with the RDF service. 1.964 + rv = result->Init(flatURI.get()); 1.965 + if (NS_FAILED(rv)) { 1.966 + NS_ERROR("unable to initialize resource"); 1.967 + NS_RELEASE(result); 1.968 + return rv; 1.969 + } 1.970 + 1.971 + *aResource = result; // already refcounted from repository 1.972 + return rv; 1.973 +} 1.974 + 1.975 +NS_IMETHODIMP 1.976 +RDFServiceImpl::GetUnicodeResource(const nsAString& aURI, nsIRDFResource** aResource) 1.977 +{ 1.978 + return GetResource(NS_ConvertUTF16toUTF8(aURI), aResource); 1.979 +} 1.980 + 1.981 + 1.982 +NS_IMETHODIMP 1.983 +RDFServiceImpl::GetAnonymousResource(nsIRDFResource** aResult) 1.984 +{ 1.985 +static uint32_t gCounter = 0; 1.986 +static char gChars[] = "0123456789abcdef" 1.987 + "ghijklmnopqrstuv" 1.988 + "wxyzABCDEFGHIJKL" 1.989 + "MNOPQRSTUVWXYZ.+"; 1.990 + 1.991 +static int32_t kMask = 0x003f; 1.992 +static int32_t kShift = 6; 1.993 + 1.994 + if (! gCounter) { 1.995 + // Start it at a semi-unique value, just to minimize the 1.996 + // chance that we get into a situation where 1.997 + // 1.998 + // 1. An anonymous resource gets serialized out in a graph 1.999 + // 2. Reboot 1.1000 + // 3. The same anonymous resource gets requested, and refers 1.1001 + // to something completely different. 1.1002 + // 4. The serialization is read back in. 1.1003 + gCounter = uint32_t(PR_Now()); 1.1004 + } 1.1005 + 1.1006 + nsresult rv; 1.1007 + nsAutoCString s; 1.1008 + 1.1009 + do { 1.1010 + // Ugh, this is a really sloppy way to do this; I copied the 1.1011 + // implementation from the days when it lived outside the RDF 1.1012 + // service. Now that it's a member we can be more cleverer. 1.1013 + 1.1014 + s.Truncate(); 1.1015 + s.Append("rdf:#$"); 1.1016 + 1.1017 + uint32_t id = ++gCounter; 1.1018 + while (id) { 1.1019 + char ch = gChars[(id & kMask)]; 1.1020 + s.Append(ch); 1.1021 + id >>= kShift; 1.1022 + } 1.1023 + 1.1024 + nsIRDFResource* resource; 1.1025 + rv = GetResource(s, &resource); 1.1026 + if (NS_FAILED(rv)) return rv; 1.1027 + 1.1028 + // XXX an ugly but effective way to make sure that this 1.1029 + // resource is really unique in the world. 1.1030 + resource->AddRef(); 1.1031 + nsrefcnt refcnt = resource->Release(); 1.1032 + 1.1033 + if (refcnt == 1) { 1.1034 + *aResult = resource; 1.1035 + break; 1.1036 + } 1.1037 + 1.1038 + NS_RELEASE(resource); 1.1039 + } while (1); 1.1040 + 1.1041 + return NS_OK; 1.1042 +} 1.1043 + 1.1044 + 1.1045 +NS_IMETHODIMP 1.1046 +RDFServiceImpl::GetLiteral(const char16_t* aValue, nsIRDFLiteral** aLiteral) 1.1047 +{ 1.1048 + NS_PRECONDITION(aValue != nullptr, "null ptr"); 1.1049 + if (! aValue) 1.1050 + return NS_ERROR_NULL_POINTER; 1.1051 + 1.1052 + NS_PRECONDITION(aLiteral != nullptr, "null ptr"); 1.1053 + if (! aLiteral) 1.1054 + return NS_ERROR_NULL_POINTER; 1.1055 + 1.1056 + // See if we have one already cached 1.1057 + PLDHashEntryHdr *hdr = 1.1058 + PL_DHashTableOperate(&mLiterals, aValue, PL_DHASH_LOOKUP); 1.1059 + 1.1060 + if (PL_DHASH_ENTRY_IS_BUSY(hdr)) { 1.1061 + LiteralHashEntry *entry = static_cast<LiteralHashEntry *>(hdr); 1.1062 + NS_ADDREF(*aLiteral = entry->mLiteral); 1.1063 + return NS_OK; 1.1064 + } 1.1065 + 1.1066 + // Nope. Create a new one 1.1067 + return LiteralImpl::Create(aValue, aLiteral); 1.1068 +} 1.1069 + 1.1070 +NS_IMETHODIMP 1.1071 +RDFServiceImpl::GetDateLiteral(PRTime aTime, nsIRDFDate** aResult) 1.1072 +{ 1.1073 + // See if we have one already cached 1.1074 + PLDHashEntryHdr *hdr = 1.1075 + PL_DHashTableOperate(&mDates, &aTime, PL_DHASH_LOOKUP); 1.1076 + 1.1077 + if (PL_DHASH_ENTRY_IS_BUSY(hdr)) { 1.1078 + DateHashEntry *entry = static_cast<DateHashEntry *>(hdr); 1.1079 + NS_ADDREF(*aResult = entry->mDate); 1.1080 + return NS_OK; 1.1081 + } 1.1082 + 1.1083 + DateImpl* result = new DateImpl(aTime); 1.1084 + if (! result) 1.1085 + return NS_ERROR_OUT_OF_MEMORY; 1.1086 + 1.1087 + NS_ADDREF(*aResult = result); 1.1088 + return NS_OK; 1.1089 +} 1.1090 + 1.1091 +NS_IMETHODIMP 1.1092 +RDFServiceImpl::GetIntLiteral(int32_t aInt, nsIRDFInt** aResult) 1.1093 +{ 1.1094 + // See if we have one already cached 1.1095 + PLDHashEntryHdr *hdr = 1.1096 + PL_DHashTableOperate(&mInts, &aInt, PL_DHASH_LOOKUP); 1.1097 + 1.1098 + if (PL_DHASH_ENTRY_IS_BUSY(hdr)) { 1.1099 + IntHashEntry *entry = static_cast<IntHashEntry *>(hdr); 1.1100 + NS_ADDREF(*aResult = entry->mInt); 1.1101 + return NS_OK; 1.1102 + } 1.1103 + 1.1104 + IntImpl* result = new IntImpl(aInt); 1.1105 + if (! result) 1.1106 + return NS_ERROR_OUT_OF_MEMORY; 1.1107 + 1.1108 + NS_ADDREF(*aResult = result); 1.1109 + return NS_OK; 1.1110 +} 1.1111 + 1.1112 +NS_IMETHODIMP 1.1113 +RDFServiceImpl::GetBlobLiteral(const uint8_t *aBytes, int32_t aLength, 1.1114 + nsIRDFBlob **aResult) 1.1115 +{ 1.1116 + BlobImpl::Data key = { aLength, const_cast<uint8_t *>(aBytes) }; 1.1117 + 1.1118 + PLDHashEntryHdr *hdr = 1.1119 + PL_DHashTableOperate(&mBlobs, &key, PL_DHASH_LOOKUP); 1.1120 + 1.1121 + if (PL_DHASH_ENTRY_IS_BUSY(hdr)) { 1.1122 + BlobHashEntry *entry = static_cast<BlobHashEntry *>(hdr); 1.1123 + NS_ADDREF(*aResult = entry->mBlob); 1.1124 + return NS_OK; 1.1125 + } 1.1126 + 1.1127 + BlobImpl *result = new BlobImpl(aBytes, aLength); 1.1128 + if (! result) 1.1129 + return NS_ERROR_OUT_OF_MEMORY; 1.1130 + 1.1131 + NS_ADDREF(*aResult = result); 1.1132 + return NS_OK; 1.1133 +} 1.1134 + 1.1135 +NS_IMETHODIMP 1.1136 +RDFServiceImpl::IsAnonymousResource(nsIRDFResource* aResource, bool* _result) 1.1137 +{ 1.1138 + NS_PRECONDITION(aResource != nullptr, "null ptr"); 1.1139 + if (! aResource) 1.1140 + return NS_ERROR_NULL_POINTER; 1.1141 + 1.1142 + nsresult rv; 1.1143 + 1.1144 + const char* uri; 1.1145 + rv = aResource->GetValueConst(&uri); 1.1146 + if (NS_FAILED(rv)) return rv; 1.1147 + 1.1148 + if ((uri[0] == 'r') && 1.1149 + (uri[1] == 'd') && 1.1150 + (uri[2] == 'f') && 1.1151 + (uri[3] == ':') && 1.1152 + (uri[4] == '#') && 1.1153 + (uri[5] == '$')) { 1.1154 + *_result = true; 1.1155 + } 1.1156 + else { 1.1157 + *_result = false; 1.1158 + } 1.1159 + 1.1160 + return NS_OK; 1.1161 +} 1.1162 + 1.1163 +NS_IMETHODIMP 1.1164 +RDFServiceImpl::RegisterResource(nsIRDFResource* aResource, bool aReplace) 1.1165 +{ 1.1166 + NS_PRECONDITION(aResource != nullptr, "null ptr"); 1.1167 + if (! aResource) 1.1168 + return NS_ERROR_NULL_POINTER; 1.1169 + 1.1170 + nsresult rv; 1.1171 + 1.1172 + const char* uri; 1.1173 + rv = aResource->GetValueConst(&uri); 1.1174 + NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get URI from resource"); 1.1175 + if (NS_FAILED(rv)) return rv; 1.1176 + 1.1177 + NS_ASSERTION(uri != nullptr, "resource has no URI"); 1.1178 + if (! uri) 1.1179 + return NS_ERROR_NULL_POINTER; 1.1180 + 1.1181 + PLDHashEntryHdr *hdr = 1.1182 + PL_DHashTableOperate(&mResources, uri, PL_DHASH_LOOKUP); 1.1183 + 1.1184 + if (PL_DHASH_ENTRY_IS_BUSY(hdr)) { 1.1185 + if (!aReplace) { 1.1186 + NS_WARNING("resource already registered, and replace not specified"); 1.1187 + return NS_ERROR_FAILURE; // already registered 1.1188 + } 1.1189 + 1.1190 + // N.B., we do _not_ release the original resource because we 1.1191 + // only ever held a weak reference to it. We simply replace 1.1192 + // it. 1.1193 + 1.1194 + PR_LOG(gLog, PR_LOG_DEBUG, 1.1195 + ("rdfserv replace-resource [%p] <-- [%p] %s", 1.1196 + static_cast<ResourceHashEntry *>(hdr)->mResource, 1.1197 + aResource, (const char*) uri)); 1.1198 + } 1.1199 + else { 1.1200 + hdr = PL_DHashTableOperate(&mResources, uri, PL_DHASH_ADD); 1.1201 + if (! hdr) 1.1202 + return NS_ERROR_OUT_OF_MEMORY; 1.1203 + 1.1204 + PR_LOG(gLog, PR_LOG_DEBUG, 1.1205 + ("rdfserv register-resource [%p] %s", 1.1206 + aResource, (const char*) uri)); 1.1207 + } 1.1208 + 1.1209 + // N.B., we only hold a weak reference to the resource: that way, 1.1210 + // the resource can be destroyed when the last refcount goes 1.1211 + // away. The single addref that the CreateResource() call made 1.1212 + // will be owned by the callee. 1.1213 + ResourceHashEntry *entry = static_cast<ResourceHashEntry *>(hdr); 1.1214 + entry->mResource = aResource; 1.1215 + entry->mKey = uri; 1.1216 + 1.1217 + return NS_OK; 1.1218 +} 1.1219 + 1.1220 +NS_IMETHODIMP 1.1221 +RDFServiceImpl::UnregisterResource(nsIRDFResource* aResource) 1.1222 +{ 1.1223 + NS_PRECONDITION(aResource != nullptr, "null ptr"); 1.1224 + if (! aResource) 1.1225 + return NS_ERROR_NULL_POINTER; 1.1226 + 1.1227 + nsresult rv; 1.1228 + 1.1229 + const char* uri; 1.1230 + rv = aResource->GetValueConst(&uri); 1.1231 + if (NS_FAILED(rv)) return rv; 1.1232 + 1.1233 + NS_ASSERTION(uri != nullptr, "resource has no URI"); 1.1234 + if (! uri) 1.1235 + return NS_ERROR_UNEXPECTED; 1.1236 + 1.1237 + PR_LOG(gLog, PR_LOG_DEBUG, 1.1238 + ("rdfserv unregister-resource [%p] %s", 1.1239 + aResource, (const char*) uri)); 1.1240 + 1.1241 +#ifdef DEBUG 1.1242 + if (PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mResources, uri, PL_DHASH_LOOKUP))) 1.1243 + NS_WARNING("resource was never registered"); 1.1244 +#endif 1.1245 + 1.1246 + PL_DHashTableOperate(&mResources, uri, PL_DHASH_REMOVE); 1.1247 + return NS_OK; 1.1248 +} 1.1249 + 1.1250 +NS_IMETHODIMP 1.1251 +RDFServiceImpl::RegisterDataSource(nsIRDFDataSource* aDataSource, bool aReplace) 1.1252 +{ 1.1253 + NS_PRECONDITION(aDataSource != nullptr, "null ptr"); 1.1254 + if (! aDataSource) 1.1255 + return NS_ERROR_NULL_POINTER; 1.1256 + 1.1257 + nsresult rv; 1.1258 + 1.1259 + nsXPIDLCString uri; 1.1260 + rv = aDataSource->GetURI(getter_Copies(uri)); 1.1261 + if (NS_FAILED(rv)) return rv; 1.1262 + 1.1263 + PLHashEntry** hep = 1.1264 + PL_HashTableRawLookup(mNamedDataSources, (*mNamedDataSources->keyHash)(uri), uri); 1.1265 + 1.1266 + if (*hep) { 1.1267 + if (! aReplace) 1.1268 + return NS_ERROR_FAILURE; // already registered 1.1269 + 1.1270 + // N.B., we only hold a weak reference to the datasource, so 1.1271 + // just replace the old with the new and don't touch any 1.1272 + // refcounts. 1.1273 + PR_LOG(gLog, PR_LOG_NOTICE, 1.1274 + ("rdfserv replace-datasource [%p] <-- [%p] %s", 1.1275 + (*hep)->value, aDataSource, (const char*) uri)); 1.1276 + 1.1277 + (*hep)->value = aDataSource; 1.1278 + } 1.1279 + else { 1.1280 + const char* key = PL_strdup(uri); 1.1281 + if (! key) 1.1282 + return NS_ERROR_OUT_OF_MEMORY; 1.1283 + 1.1284 + PL_HashTableAdd(mNamedDataSources, key, aDataSource); 1.1285 + 1.1286 + PR_LOG(gLog, PR_LOG_NOTICE, 1.1287 + ("rdfserv register-datasource [%p] %s", 1.1288 + aDataSource, (const char*) uri)); 1.1289 + 1.1290 + // N.B., we only hold a weak reference to the datasource, so don't 1.1291 + // addref. 1.1292 + } 1.1293 + 1.1294 + return NS_OK; 1.1295 +} 1.1296 + 1.1297 +NS_IMETHODIMP 1.1298 +RDFServiceImpl::UnregisterDataSource(nsIRDFDataSource* aDataSource) 1.1299 +{ 1.1300 + NS_PRECONDITION(aDataSource != nullptr, "null ptr"); 1.1301 + if (! aDataSource) 1.1302 + return NS_ERROR_NULL_POINTER; 1.1303 + 1.1304 + nsresult rv; 1.1305 + 1.1306 + nsXPIDLCString uri; 1.1307 + rv = aDataSource->GetURI(getter_Copies(uri)); 1.1308 + if (NS_FAILED(rv)) return rv; 1.1309 + 1.1310 + //NS_ASSERTION(uri != nullptr, "datasource has no URI"); 1.1311 + if (! uri) 1.1312 + return NS_ERROR_UNEXPECTED; 1.1313 + 1.1314 + PLHashEntry** hep = 1.1315 + PL_HashTableRawLookup(mNamedDataSources, (*mNamedDataSources->keyHash)(uri), uri); 1.1316 + 1.1317 + // It may well be that this datasource was never registered. If 1.1318 + // so, don't unregister it. 1.1319 + if (! *hep || ((*hep)->value != aDataSource)) 1.1320 + return NS_OK; 1.1321 + 1.1322 + // N.B., we only held a weak reference to the datasource, so we 1.1323 + // don't release here. 1.1324 + PL_HashTableRawRemove(mNamedDataSources, hep, *hep); 1.1325 + 1.1326 + PR_LOG(gLog, PR_LOG_NOTICE, 1.1327 + ("rdfserv unregister-datasource [%p] %s", 1.1328 + aDataSource, (const char*) uri)); 1.1329 + 1.1330 + return NS_OK; 1.1331 +} 1.1332 + 1.1333 +NS_IMETHODIMP 1.1334 +RDFServiceImpl::GetDataSource(const char* aURI, nsIRDFDataSource** aDataSource) 1.1335 +{ 1.1336 + // Use the other GetDataSource and ask for a non-blocking Refresh. 1.1337 + // If you wanted it loaded synchronously, then you should've tried to do it 1.1338 + // yourself, or used GetDataSourceBlocking. 1.1339 + return GetDataSource( aURI, false, aDataSource ); 1.1340 +} 1.1341 + 1.1342 +NS_IMETHODIMP 1.1343 +RDFServiceImpl::GetDataSourceBlocking(const char* aURI, nsIRDFDataSource** aDataSource) 1.1344 +{ 1.1345 + // Use GetDataSource and ask for a blocking Refresh. 1.1346 + return GetDataSource( aURI, true, aDataSource ); 1.1347 +} 1.1348 + 1.1349 +nsresult 1.1350 +RDFServiceImpl::GetDataSource(const char* aURI, bool aBlock, nsIRDFDataSource** aDataSource) 1.1351 +{ 1.1352 + NS_PRECONDITION(aURI != nullptr, "null ptr"); 1.1353 + if (! aURI) 1.1354 + return NS_ERROR_NULL_POINTER; 1.1355 + 1.1356 + nsresult rv; 1.1357 + 1.1358 + // Attempt to canonify the URI before we look for it in the 1.1359 + // cache. We won't bother doing this on `rdf:' URIs to avoid 1.1360 + // useless (and expensive) protocol handler lookups. 1.1361 + nsAutoCString spec(aURI); 1.1362 + 1.1363 + if (!StringBeginsWith(spec, NS_LITERAL_CSTRING("rdf:"))) { 1.1364 + nsCOMPtr<nsIURI> uri; 1.1365 + NS_NewURI(getter_AddRefs(uri), spec); 1.1366 + if (uri) 1.1367 + uri->GetSpec(spec); 1.1368 + } 1.1369 + 1.1370 + // First, check the cache to see if we already have this 1.1371 + // datasource loaded and initialized. 1.1372 + { 1.1373 + nsIRDFDataSource* cached = 1.1374 + static_cast<nsIRDFDataSource*>(PL_HashTableLookup(mNamedDataSources, spec.get())); 1.1375 + 1.1376 + if (cached) { 1.1377 + NS_ADDREF(cached); 1.1378 + *aDataSource = cached; 1.1379 + return NS_OK; 1.1380 + } 1.1381 + } 1.1382 + 1.1383 + // Nope. So go to the repository to try to create it. 1.1384 + nsCOMPtr<nsIRDFDataSource> ds; 1.1385 + if (StringBeginsWith(spec, NS_LITERAL_CSTRING("rdf:"))) { 1.1386 + // It's a built-in data source. Convert it to a contract ID. 1.1387 + nsAutoCString contractID( 1.1388 + NS_LITERAL_CSTRING(NS_RDF_DATASOURCE_CONTRACTID_PREFIX) + 1.1389 + Substring(spec, 4, spec.Length() - 4)); 1.1390 + 1.1391 + // Strip params to get ``base'' contractID for data source. 1.1392 + int32_t p = contractID.FindChar(char16_t('&')); 1.1393 + if (p >= 0) 1.1394 + contractID.Truncate(p); 1.1395 + 1.1396 + ds = do_GetService(contractID.get(), &rv); 1.1397 + if (NS_FAILED(rv)) return rv; 1.1398 + 1.1399 + nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(ds); 1.1400 + if (remote) { 1.1401 + rv = remote->Init(spec.get()); 1.1402 + if (NS_FAILED(rv)) return rv; 1.1403 + } 1.1404 + } 1.1405 + else { 1.1406 + // Try to load this as an RDF/XML data source 1.1407 + ds = do_CreateInstance(kRDFXMLDataSourceCID, &rv); 1.1408 + if (NS_FAILED(rv)) return rv; 1.1409 + 1.1410 + nsCOMPtr<nsIRDFRemoteDataSource> remote(do_QueryInterface(ds)); 1.1411 + NS_ASSERTION(remote, "not a remote RDF/XML data source!"); 1.1412 + if (! remote) return NS_ERROR_UNEXPECTED; 1.1413 + 1.1414 + rv = remote->Init(spec.get()); 1.1415 + if (NS_FAILED(rv)) return rv; 1.1416 + 1.1417 + rv = remote->Refresh(aBlock); 1.1418 + if (NS_FAILED(rv)) return rv; 1.1419 + } 1.1420 + 1.1421 + *aDataSource = ds; 1.1422 + NS_ADDREF(*aDataSource); 1.1423 + return NS_OK; 1.1424 +} 1.1425 + 1.1426 +//////////////////////////////////////////////////////////////////////// 1.1427 + 1.1428 +nsresult 1.1429 +RDFServiceImpl::RegisterLiteral(nsIRDFLiteral* aLiteral) 1.1430 +{ 1.1431 + const char16_t* value; 1.1432 + aLiteral->GetValueConst(&value); 1.1433 + 1.1434 + NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mLiterals, 1.1435 + value, 1.1436 + PL_DHASH_LOOKUP)), 1.1437 + "literal already registered"); 1.1438 + 1.1439 + PLDHashEntryHdr *hdr = 1.1440 + PL_DHashTableOperate(&mLiterals, value, PL_DHASH_ADD); 1.1441 + 1.1442 + if (! hdr) 1.1443 + return NS_ERROR_OUT_OF_MEMORY; 1.1444 + 1.1445 + LiteralHashEntry *entry = static_cast<LiteralHashEntry *>(hdr); 1.1446 + 1.1447 + // N.B., we only hold a weak reference to the literal: that 1.1448 + // way, the literal can be destroyed when the last refcount 1.1449 + // goes away. The single addref that the CreateLiteral() call 1.1450 + // made will be owned by the callee. 1.1451 + entry->mLiteral = aLiteral; 1.1452 + entry->mKey = value; 1.1453 + 1.1454 + PR_LOG(gLog, PR_LOG_DEBUG, 1.1455 + ("rdfserv register-literal [%p] %s", 1.1456 + aLiteral, (const char16_t*) value)); 1.1457 + 1.1458 + return NS_OK; 1.1459 +} 1.1460 + 1.1461 + 1.1462 +nsresult 1.1463 +RDFServiceImpl::UnregisterLiteral(nsIRDFLiteral* aLiteral) 1.1464 +{ 1.1465 + const char16_t* value; 1.1466 + aLiteral->GetValueConst(&value); 1.1467 + 1.1468 + NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableOperate(&mLiterals, 1.1469 + value, 1.1470 + PL_DHASH_LOOKUP)), 1.1471 + "literal was never registered"); 1.1472 + 1.1473 + PL_DHashTableOperate(&mLiterals, value, PL_DHASH_REMOVE); 1.1474 + 1.1475 + // N.B. that we _don't_ release the literal: we only held a weak 1.1476 + // reference to it in the hashtable. 1.1477 + PR_LOG(gLog, PR_LOG_DEBUG, 1.1478 + ("rdfserv unregister-literal [%p] %s", 1.1479 + aLiteral, (const char16_t*) value)); 1.1480 + 1.1481 + return NS_OK; 1.1482 +} 1.1483 + 1.1484 +//---------------------------------------------------------------------- 1.1485 + 1.1486 +nsresult 1.1487 +RDFServiceImpl::RegisterInt(nsIRDFInt* aInt) 1.1488 +{ 1.1489 + int32_t value; 1.1490 + aInt->GetValue(&value); 1.1491 + 1.1492 + NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mInts, 1.1493 + &value, 1.1494 + PL_DHASH_LOOKUP)), 1.1495 + "int already registered"); 1.1496 + 1.1497 + PLDHashEntryHdr *hdr = 1.1498 + PL_DHashTableOperate(&mInts, &value, PL_DHASH_ADD); 1.1499 + 1.1500 + if (! hdr) 1.1501 + return NS_ERROR_OUT_OF_MEMORY; 1.1502 + 1.1503 + IntHashEntry *entry = static_cast<IntHashEntry *>(hdr); 1.1504 + 1.1505 + // N.B., we only hold a weak reference to the literal: that 1.1506 + // way, the literal can be destroyed when the last refcount 1.1507 + // goes away. The single addref that the CreateInt() call 1.1508 + // made will be owned by the callee. 1.1509 + entry->mInt = aInt; 1.1510 + entry->mKey = value; 1.1511 + 1.1512 + PR_LOG(gLog, PR_LOG_DEBUG, 1.1513 + ("rdfserv register-int [%p] %d", 1.1514 + aInt, value)); 1.1515 + 1.1516 + return NS_OK; 1.1517 +} 1.1518 + 1.1519 + 1.1520 +nsresult 1.1521 +RDFServiceImpl::UnregisterInt(nsIRDFInt* aInt) 1.1522 +{ 1.1523 + int32_t value; 1.1524 + aInt->GetValue(&value); 1.1525 + 1.1526 + NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableOperate(&mInts, 1.1527 + &value, 1.1528 + PL_DHASH_LOOKUP)), 1.1529 + "int was never registered"); 1.1530 + 1.1531 + PL_DHashTableOperate(&mInts, &value, PL_DHASH_REMOVE); 1.1532 + 1.1533 + // N.B. that we _don't_ release the literal: we only held a weak 1.1534 + // reference to it in the hashtable. 1.1535 + PR_LOG(gLog, PR_LOG_DEBUG, 1.1536 + ("rdfserv unregister-int [%p] %d", 1.1537 + aInt, value)); 1.1538 + 1.1539 + return NS_OK; 1.1540 +} 1.1541 + 1.1542 +//---------------------------------------------------------------------- 1.1543 + 1.1544 +nsresult 1.1545 +RDFServiceImpl::RegisterDate(nsIRDFDate* aDate) 1.1546 +{ 1.1547 + PRTime value; 1.1548 + aDate->GetValue(&value); 1.1549 + 1.1550 + NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mDates, 1.1551 + &value, 1.1552 + PL_DHASH_LOOKUP)), 1.1553 + "date already registered"); 1.1554 + 1.1555 + PLDHashEntryHdr *hdr = 1.1556 + PL_DHashTableOperate(&mDates, &value, PL_DHASH_ADD); 1.1557 + 1.1558 + if (! hdr) 1.1559 + return NS_ERROR_OUT_OF_MEMORY; 1.1560 + 1.1561 + DateHashEntry *entry = static_cast<DateHashEntry *>(hdr); 1.1562 + 1.1563 + // N.B., we only hold a weak reference to the literal: that 1.1564 + // way, the literal can be destroyed when the last refcount 1.1565 + // goes away. The single addref that the CreateDate() call 1.1566 + // made will be owned by the callee. 1.1567 + entry->mDate = aDate; 1.1568 + entry->mKey = value; 1.1569 + 1.1570 + PR_LOG(gLog, PR_LOG_DEBUG, 1.1571 + ("rdfserv register-date [%p] %ld", 1.1572 + aDate, value)); 1.1573 + 1.1574 + return NS_OK; 1.1575 +} 1.1576 + 1.1577 + 1.1578 +nsresult 1.1579 +RDFServiceImpl::UnregisterDate(nsIRDFDate* aDate) 1.1580 +{ 1.1581 + PRTime value; 1.1582 + aDate->GetValue(&value); 1.1583 + 1.1584 + NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableOperate(&mDates, 1.1585 + &value, 1.1586 + PL_DHASH_LOOKUP)), 1.1587 + "date was never registered"); 1.1588 + 1.1589 + PL_DHashTableOperate(&mDates, &value, PL_DHASH_REMOVE); 1.1590 + 1.1591 + // N.B. that we _don't_ release the literal: we only held a weak 1.1592 + // reference to it in the hashtable. 1.1593 + PR_LOG(gLog, PR_LOG_DEBUG, 1.1594 + ("rdfserv unregister-date [%p] %ld", 1.1595 + aDate, value)); 1.1596 + 1.1597 + return NS_OK; 1.1598 +} 1.1599 + 1.1600 +nsresult 1.1601 +RDFServiceImpl::RegisterBlob(BlobImpl *aBlob) 1.1602 +{ 1.1603 + NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mBlobs, 1.1604 + &aBlob->mData, 1.1605 + PL_DHASH_LOOKUP)), 1.1606 + "blob already registered"); 1.1607 + 1.1608 + PLDHashEntryHdr *hdr = 1.1609 + PL_DHashTableOperate(&mBlobs, &aBlob->mData, PL_DHASH_ADD); 1.1610 + 1.1611 + if (! hdr) 1.1612 + return NS_ERROR_OUT_OF_MEMORY; 1.1613 + 1.1614 + BlobHashEntry *entry = static_cast<BlobHashEntry *>(hdr); 1.1615 + 1.1616 + // N.B., we only hold a weak reference to the literal: that 1.1617 + // way, the literal can be destroyed when the last refcount 1.1618 + // goes away. The single addref that the CreateInt() call 1.1619 + // made will be owned by the callee. 1.1620 + entry->mBlob = aBlob; 1.1621 + 1.1622 + PR_LOG(gLog, PR_LOG_DEBUG, 1.1623 + ("rdfserv register-blob [%p] %s", 1.1624 + aBlob, aBlob->mData.mBytes)); 1.1625 + 1.1626 + return NS_OK; 1.1627 +} 1.1628 + 1.1629 +nsresult 1.1630 +RDFServiceImpl::UnregisterBlob(BlobImpl *aBlob) 1.1631 +{ 1.1632 + NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableOperate(&mBlobs, 1.1633 + &aBlob->mData, 1.1634 + PL_DHASH_LOOKUP)), 1.1635 + "blob was never registered"); 1.1636 + 1.1637 + PL_DHashTableOperate(&mBlobs, &aBlob->mData, PL_DHASH_REMOVE); 1.1638 + 1.1639 + // N.B. that we _don't_ release the literal: we only held a weak 1.1640 + // reference to it in the hashtable. 1.1641 + PR_LOG(gLog, PR_LOG_DEBUG, 1.1642 + ("rdfserv unregister-blob [%p] %s", 1.1643 + aBlob, aBlob->mData.mBytes)); 1.1644 + 1.1645 + return NS_OK; 1.1646 +}