Bug 115926. Add support for `blob' literals. r=rjc,tingley; sr=hyatt

This commit is contained in:
waterson%netscape.com 2002-01-15 01:57:17 +00:00
parent cd8149b788
commit 70b7f07e30
3 changed files with 228 additions and 0 deletions

View File

@ -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;
};

View File

@ -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.

View File

@ -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<nsIRDFBlob> 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;
}
////////////////////////////////////////////////////////////////////////