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