rdf/base/src/nsRDFService.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial