From 2cc83dae119b5c4a4278c459df739fb099f90a6d Mon Sep 17 00:00:00 2001 From: "waterson%netscape.com" Date: Tue, 15 Jan 2002 01:57:17 +0000 Subject: [PATCH] Bug 115926. Add support for `blob' literals. r=rjc,tingley; sr=hyatt --- rdf/base/idl/nsIRDFLiteral.idl | 18 +++ rdf/base/idl/nsIRDFService.idl | 3 + rdf/base/src/nsRDFService.cpp | 207 +++++++++++++++++++++++++++++++++ 3 files changed, 228 insertions(+) diff --git a/rdf/base/idl/nsIRDFLiteral.idl b/rdf/base/idl/nsIRDFLiteral.idl index ff83887ea12..97aab6631e0 100644 --- a/rdf/base/idl/nsIRDFLiteral.idl +++ b/rdf/base/idl/nsIRDFLiteral.idl @@ -41,6 +41,8 @@ #include "nscore.h" // for PRUnichar %} +[ptr] native octet_ptr(PRUint8); + /** * A literal node in the graph, whose value is a string. */ @@ -80,3 +82,19 @@ interface nsIRDFInt : nsIRDFNode { readonly attribute long Value; }; +/** + * A literal node in the graph, whose value is arbitrary + * binary data. + */ +[scriptable, uuid(237f85a2-1dd2-11b2-94af-8122582fc45e)] +interface nsIRDFBlob : nsIRDFNode { + /** + * The binary data. + */ + [noscript] readonly attribute octet_ptr value; + + /** + * The data's length. + */ + readonly attribute long length; +}; diff --git a/rdf/base/idl/nsIRDFService.idl b/rdf/base/idl/nsIRDFService.idl index 901ff1d5b78..098ec101b14 100644 --- a/rdf/base/idl/nsIRDFService.idl +++ b/rdf/base/idl/nsIRDFService.idl @@ -68,6 +68,9 @@ interface nsIRDFService : nsISupports { // Construct an RDF literal from an int. nsIRDFInt GetIntLiteral(in long aValue); + // Construct an RDF literal from a data blob + [noscript] nsIRDFBlob getBlobLiteral(in octet_ptr aValue, in long aLength); + boolean IsAnonymousResource(in nsIRDFResource aResource); // Registers a resource with the RDF system, making it unique w.r.t. diff --git a/rdf/base/src/nsRDFService.cpp b/rdf/base/src/nsRDFService.cpp index a35f59451d4..9e7569cb6a3 100644 --- a/rdf/base/src/nsRDFService.cpp +++ b/rdf/base/src/nsRDFService.cpp @@ -85,6 +85,8 @@ static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); static PRLogModuleInfo* gLog = nsnull; #endif +class BlobImpl; + //////////////////////////////////////////////////////////////////////// // RDFServiceImpl // @@ -99,6 +101,7 @@ protected: PLDHashTable mLiterals; PLDHashTable mInts; PLDHashTable mDates; + PLDHashTable mBlobs; char mLastURIPrefix[16]; PRInt32 mLastPrefixlen; @@ -126,6 +129,8 @@ public: nsresult UnregisterInt(nsIRDFInt* aInt); nsresult RegisterDate(nsIRDFDate* aDate); nsresult UnregisterDate(nsIRDFDate* aDate); + nsresult RegisterBlob(BlobImpl* aBlob); + nsresult UnregisterBlob(BlobImpl* aBlob); nsresult GetDataSource(const char *aURI, PRBool aBlock, nsIRDFDataSource **aDataSource ); }; @@ -376,6 +381,134 @@ static PLDHashTableOps gDateTableOps = { nsnull }; +class BlobImpl : public nsIRDFBlob +{ +public: + struct Data { + PRInt32 mLength; + PRUint8 *mBytes; + }; + + BlobImpl(PRUint8 *aBytes, PRInt32 aLength) + { + NS_INIT_REFCNT(); + mData.mLength = aLength; + mData.mBytes = new PRUint8[aLength]; + nsCRT::memcpy(mData.mBytes, aBytes, aLength); + NS_ADDREF(gRDFService); + gRDFService->RegisterBlob(this); + } + + virtual ~BlobImpl() + { + gRDFService->UnregisterBlob(this); + NS_RELEASE(gRDFService); + delete[] mData.mBytes; + } + + NS_DECL_ISUPPORTS + NS_DECL_NSIRDFNODE + NS_DECL_NSIRDFBLOB + + Data mData; +}; + +NS_IMPL_ISUPPORTS2(BlobImpl, nsIRDFNode, nsIRDFBlob) + +NS_IMETHODIMP +BlobImpl::EqualsNode(nsIRDFNode *aNode, PRBool *aEquals) +{ + nsCOMPtr blob = do_QueryInterface(aNode); + if (blob) { + PRInt32 length; + blob->GetLength(&length); + + if (length == mData.mLength) { + PRUint8 *bytes; + blob->GetValue(&bytes); + + if (0 == nsCRT::memcmp(bytes, mData.mBytes, length)) { + *aEquals = PR_TRUE; + return NS_OK; + } + } + } + + *aEquals = PR_FALSE; + return NS_OK; +} + +NS_IMETHODIMP +BlobImpl::GetValue(PRUint8 **aResult) +{ + *aResult = mData.mBytes; + return NS_OK; +} + +NS_IMETHODIMP +BlobImpl::GetLength(PRInt32 *aResult) +{ + *aResult = mData.mLength; + return NS_OK; +} + +// ---------------------------------------------------------------------- +// +// For the mBlobs hashtable. +// + +struct BlobHashEntry : public PLDHashEntryHdr { + BlobImpl *mBlob; + + static const void * PR_CALLBACK + GetKey(PLDHashTable *table, PLDHashEntryHdr *hdr) + { + BlobHashEntry *entry = NS_STATIC_CAST(BlobHashEntry *, hdr); + return &entry->mBlob->mData; + } + + static PLDHashNumber PR_CALLBACK + HashKey(PLDHashTable *table, const void *key) + { + const BlobImpl::Data *data = + NS_STATIC_CAST(const BlobImpl::Data *, key); + + const PRUint8 *p = data->mBytes, *limit = p + data->mLength; + PLDHashNumber h = 0; + for ( ; p < limit; ++p) + h = (h >> 28) ^ (h << 4) ^ *p; + return h; + } + + static PRBool PR_CALLBACK + MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr, + const void *key) + { + const BlobHashEntry *entry = + NS_STATIC_CAST(const BlobHashEntry *, hdr); + + const BlobImpl::Data *left = &entry->mBlob->mData; + + const BlobImpl::Data *right = + NS_STATIC_CAST(const BlobImpl::Data *, key); + + return (left->mLength == right->mLength) + && 0 == nsCRT::memcmp(left->mBytes, right->mBytes, right->mLength); + } +}; + +static PLDHashTableOps gBlobTableOps = { + PL_DHashAllocTable, + PL_DHashFreeTable, + BlobHashEntry::GetKey, + BlobHashEntry::HashKey, + BlobHashEntry::MatchEntry, + PL_DHashMoveEntryStub, + PL_DHashClearEntryStub, + PL_DHashFinalizeStub, + nsnull +}; + //////////////////////////////////////////////////////////////////////// // LiteralImpl // @@ -756,6 +889,9 @@ RDFServiceImpl::Init() PL_DHashTableInit(&mDates, &gDateTableOps, nsnull, sizeof(DateHashEntry), PL_DHASH_MIN_SIZE); + PL_DHashTableInit(&mBlobs, &gBlobTableOps, nsnull, + sizeof(BlobHashEntry), PL_DHASH_MIN_SIZE); + rv = nsComponentManager::FindFactory(kRDFDefaultResourceCID, getter_AddRefs(mDefaultResourceFactory)); NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get default resource factory"); if (NS_FAILED(rv)) return rv; @@ -779,6 +915,7 @@ RDFServiceImpl::~RDFServiceImpl() PL_DHashTableFinish(&mLiterals); PL_DHashTableFinish(&mInts); PL_DHashTableFinish(&mDates); + PL_DHashTableFinish(&mBlobs); gRDFService = nsnull; } @@ -1115,6 +1252,29 @@ RDFServiceImpl::GetIntLiteral(PRInt32 aInt, nsIRDFInt** aResult) return NS_OK; } +NS_IMETHODIMP +RDFServiceImpl::GetBlobLiteral(PRUint8 *aBytes, PRInt32 aLength, + nsIRDFBlob **aResult) +{ + BlobImpl::Data key = { aLength, aBytes }; + + PLDHashEntryHdr *hdr = + PL_DHashTableOperate(&mBlobs, &key, PL_DHASH_LOOKUP); + + if (PL_DHASH_ENTRY_IS_BUSY(hdr)) { + BlobHashEntry *entry = NS_STATIC_CAST(BlobHashEntry *, hdr); + NS_ADDREF(*aResult = entry->mBlob); + return NS_OK; + } + + BlobImpl *result = new BlobImpl(aBytes, aLength); + if (! result) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(*aResult = result); + return NS_OK; +} + NS_IMETHODIMP RDFServiceImpl::IsAnonymousResource(nsIRDFResource* aResource, PRBool* _result) { @@ -1581,6 +1741,53 @@ RDFServiceImpl::UnregisterDate(nsIRDFDate* aDate) return NS_OK; } +nsresult +RDFServiceImpl::RegisterBlob(BlobImpl *aBlob) +{ + NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mBlobs, + &aBlob->mData, + PL_DHASH_LOOKUP)), + "blob already registered"); + + PLDHashEntryHdr *hdr = + PL_DHashTableOperate(&mBlobs, &aBlob->mData, PL_DHASH_ADD); + + if (! hdr) + return NS_ERROR_OUT_OF_MEMORY; + + BlobHashEntry *entry = NS_STATIC_CAST(BlobHashEntry *, hdr); + + // N.B., we only hold a weak reference to the literal: that + // way, the literal can be destroyed when the last refcount + // goes away. The single addref that the CreateInt() call + // made will be owned by the callee. + entry->mBlob = aBlob; + + PR_LOG(gLog, PR_LOG_DEBUG, + ("rdfserv register-blob [%p] %s", + aBlob, aBlob->mData.mBytes)); + + return NS_OK; +} + +nsresult +RDFServiceImpl::UnregisterBlob(BlobImpl *aBlob) +{ + NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableOperate(&mBlobs, + &aBlob->mData, + PL_DHASH_LOOKUP)), + "blob was never registered"); + + PL_DHashTableOperate(&mBlobs, &aBlob->mData, PL_DHASH_REMOVE); + + // N.B. that we _don't_ release the literal: we only held a weak + // reference to it in the hashtable. + PR_LOG(gLog, PR_LOG_DEBUG, + ("rdfserv unregister-blob [%p] %s", + aBlob, aBlob->mData.mBytes)); + + return NS_OK; +} ////////////////////////////////////////////////////////////////////////