mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-07 20:17:37 +00:00
815 lines
23 KiB
C++
815 lines
23 KiB
C++
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||
|
*
|
||
|
* The contents of this file are subject to the Netscape Public License
|
||
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
||
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
||
|
* http://www.mozilla.org/NPL/
|
||
|
*
|
||
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||
|
* for the specific language governing rights and limitations under the
|
||
|
* NPL.
|
||
|
*
|
||
|
* The Initial Developer of this code under the NPL is Netscape
|
||
|
* Communications Corporation. Portions created by Netscape are
|
||
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||
|
* Reserved.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
|
||
|
A data source that can read itself from and write itself to an
|
||
|
RDF/XML stream.
|
||
|
|
||
|
TO DO
|
||
|
-----
|
||
|
|
||
|
1) Right now, the only kind of stream data sources that are writable
|
||
|
are "file:" URIs. (In fact, <em>all</em> "file:" URIs are
|
||
|
writable, modulo flie system permissions; this may lead to some
|
||
|
surprising behavior.) Eventually, it'd be great if we could open
|
||
|
an arbitrary nsIOutputStream on *any* URL, and Netlib could just
|
||
|
do the magic.
|
||
|
|
||
|
2) We need a way to decide whether or not the stream should be read
|
||
|
with a blocking read or an asynchronous read. This issue is
|
||
|
particularly important for consumers that expect to be able to
|
||
|
Init() a data source and then have it be 100% ready for use
|
||
|
(e.g., the regsitry). Does this warrant a new interface? Right
|
||
|
now, we just assume that "file:" and "resource:" URIs should be
|
||
|
read synchronously.
|
||
|
|
||
|
*/
|
||
|
|
||
|
#include "nsFileSpec.h"
|
||
|
#include "nsFileStream.h"
|
||
|
#include "nsIDTD.h"
|
||
|
#include "nsIInputStream.h"
|
||
|
#include "nsINameSpaceManager.h"
|
||
|
#include "nsIOutputStream.h"
|
||
|
#include "nsIParser.h"
|
||
|
#include "nsIRDFContentSink.h"
|
||
|
#include "nsIRDFCursor.h"
|
||
|
#include "nsIRDFNode.h"
|
||
|
#include "nsIRDFService.h"
|
||
|
#include "nsIRDFXMLDataSource.h"
|
||
|
#include "nsIRDFXMLSource.h"
|
||
|
#include "nsIServiceManager.h"
|
||
|
#include "nsIStreamListener.h"
|
||
|
#include "nsIURL.h"
|
||
|
#include "nsLayoutCID.h" // for NS_NAMESPACEMANAGER_CID.
|
||
|
#include "nsParserCIID.h"
|
||
|
#include "nsRDFCID.h"
|
||
|
#include "nsVoidArray.h"
|
||
|
#include "plstr.h"
|
||
|
#include "prio.h"
|
||
|
#include "prthread.h"
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
static NS_DEFINE_IID(kIDTDIID, NS_IDTD_IID);
|
||
|
static NS_DEFINE_IID(kIInputStreamIID, NS_IINPUTSTREAM_IID);
|
||
|
static NS_DEFINE_IID(kINameSpaceManagerIID, NS_INAMESPACEMANAGER_IID);
|
||
|
static NS_DEFINE_IID(kIOutputStreamIID, NS_IOUTPUTSTREAM_IID);
|
||
|
static NS_DEFINE_IID(kIParserIID, NS_IPARSER_IID);
|
||
|
static NS_DEFINE_IID(kIRDFDataSourceIID, NS_IRDFDATASOURCE_IID);
|
||
|
static NS_DEFINE_IID(kIRDFContentSinkIID, NS_IRDFCONTENTSINK_IID);
|
||
|
static NS_DEFINE_IID(kIRDFServiceIID, NS_IRDFSERVICE_IID);
|
||
|
static NS_DEFINE_IID(kIRDFXMLDataSourceIID, NS_IRDFXMLDATASOURCE_IID);
|
||
|
static NS_DEFINE_IID(kIRDFXMLSourceIID, NS_IRDFXMLSOURCE_IID);
|
||
|
static NS_DEFINE_IID(kIStreamListenerIID, NS_ISTREAMLISTENER_IID);
|
||
|
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
|
||
|
|
||
|
static NS_DEFINE_CID(kNameSpaceManagerCID, NS_NAMESPACEMANAGER_CID);
|
||
|
static NS_DEFINE_CID(kParserCID, NS_PARSER_IID); // XXX
|
||
|
static NS_DEFINE_CID(kRDFInMemoryDataSourceCID, NS_RDFINMEMORYDATASOURCE_CID);
|
||
|
static NS_DEFINE_CID(kRDFContentSinkCID, NS_RDFCONTENTSINK_CID);
|
||
|
static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
|
||
|
static NS_DEFINE_CID(kWellFormedDTDCID, NS_WELLFORMEDDTD_CID);
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
// FileOutputStreamImpl
|
||
|
|
||
|
class FileOutputStreamImpl : public nsIOutputStream
|
||
|
{
|
||
|
private:
|
||
|
nsOutputFileStream mStream;
|
||
|
|
||
|
public:
|
||
|
FileOutputStreamImpl(const nsFilePath& path)
|
||
|
: mStream(path)
|
||
|
{
|
||
|
NS_INIT_REFCNT();
|
||
|
}
|
||
|
|
||
|
virtual ~FileOutputStreamImpl(void) {
|
||
|
Close();
|
||
|
}
|
||
|
|
||
|
// nsISupports interface
|
||
|
NS_DECL_ISUPPORTS
|
||
|
|
||
|
// nsIBaseStream interface
|
||
|
NS_IMETHOD Close(void) {
|
||
|
mStream.close();
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
// nsIOutputStream interface
|
||
|
NS_IMETHOD Write(const char* aBuf,
|
||
|
PRUint32 aOffset,
|
||
|
PRUint32 aCount,
|
||
|
PRUint32 *aWriteCount)
|
||
|
{
|
||
|
PRInt32 written = mStream.write(aBuf + aOffset, aCount);
|
||
|
if (written == -1) {
|
||
|
*aWriteCount = 0;
|
||
|
return NS_ERROR_FAILURE; // XXX right error code?
|
||
|
}
|
||
|
else {
|
||
|
*aWriteCount = written;
|
||
|
return NS_OK;
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
NS_IMPL_ISUPPORTS(FileOutputStreamImpl, kIOutputStreamIID);
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
class ProxyStream : public nsIInputStream
|
||
|
{
|
||
|
private:
|
||
|
const char* mBuffer;
|
||
|
PRUint32 mSize;
|
||
|
PRUint32 mIndex;
|
||
|
|
||
|
public:
|
||
|
ProxyStream(void) : mBuffer(nsnull)
|
||
|
{
|
||
|
NS_INIT_REFCNT();
|
||
|
}
|
||
|
|
||
|
virtual ~ProxyStream(void) {
|
||
|
}
|
||
|
|
||
|
// nsISupports
|
||
|
NS_DECL_ISUPPORTS
|
||
|
|
||
|
// nsIBaseStream
|
||
|
NS_IMETHOD Close(void) {
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
// nsIInputStream
|
||
|
NS_IMETHOD GetLength(PRUint32 *aLength) {
|
||
|
*aLength = mSize - mIndex;
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHOD Read(char* aBuf, PRUint32 aOffset, PRUint32 aCount, PRUint32 *aReadCount) {
|
||
|
PRUint32 readCount = 0;
|
||
|
aBuf += aOffset;
|
||
|
while (mIndex < mSize && aCount > 0) {
|
||
|
*aBuf = mBuffer[mIndex];
|
||
|
aBuf++;
|
||
|
mIndex++;
|
||
|
readCount++;
|
||
|
aCount--;
|
||
|
}
|
||
|
*aReadCount = readCount;
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
// Implementation
|
||
|
void SetBuffer(const char* aBuffer, PRUint32 aSize) {
|
||
|
mBuffer = aBuffer;
|
||
|
mSize = aSize;
|
||
|
mIndex = 0;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
NS_IMPL_ISUPPORTS(ProxyStream, kIInputStreamIID);
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
// RDFXMLDataSourceImpl
|
||
|
|
||
|
class RDFXMLDataSourceImpl : public nsIRDFXMLDataSource,
|
||
|
public nsIRDFXMLSource
|
||
|
{
|
||
|
protected:
|
||
|
nsIRDFDataSource* mInner;
|
||
|
PRBool mIsWritable;
|
||
|
PRBool mIsDirty;
|
||
|
nsVoidArray mObservers;
|
||
|
char** mNamedDataSourceURIs;
|
||
|
PRInt32 mNumNamedDataSourceURIs;
|
||
|
nsIURL** mCSSStyleSheetURLs;
|
||
|
PRInt32 mNumCSSStyleSheetURLs;
|
||
|
nsIRDFResource* mRootResource;
|
||
|
PRBool mIsLoading;
|
||
|
|
||
|
public:
|
||
|
RDFXMLDataSourceImpl(void);
|
||
|
virtual ~RDFXMLDataSourceImpl(void);
|
||
|
|
||
|
// nsISupports
|
||
|
NS_DECL_ISUPPORTS
|
||
|
|
||
|
// nsIRDFDataSource
|
||
|
NS_IMETHOD Init(const char* uri);
|
||
|
|
||
|
NS_IMETHOD GetURI(const char* *uri) const {
|
||
|
return mInner->GetURI(uri);
|
||
|
}
|
||
|
|
||
|
NS_IMETHOD GetSource(nsIRDFResource* property,
|
||
|
nsIRDFNode* target,
|
||
|
PRBool tv,
|
||
|
nsIRDFResource** source) {
|
||
|
return mInner->GetSource(property, target, tv, source);
|
||
|
}
|
||
|
|
||
|
NS_IMETHOD GetSources(nsIRDFResource* property,
|
||
|
nsIRDFNode* target,
|
||
|
PRBool tv,
|
||
|
nsIRDFAssertionCursor** sources) {
|
||
|
return mInner->GetSources(property, target, tv, sources);
|
||
|
}
|
||
|
|
||
|
NS_IMETHOD GetTarget(nsIRDFResource* source,
|
||
|
nsIRDFResource* property,
|
||
|
PRBool tv,
|
||
|
nsIRDFNode** target) {
|
||
|
return mInner->GetTarget(source, property, tv, target);
|
||
|
}
|
||
|
|
||
|
NS_IMETHOD GetTargets(nsIRDFResource* source,
|
||
|
nsIRDFResource* property,
|
||
|
PRBool tv,
|
||
|
nsIRDFAssertionCursor** targets) {
|
||
|
return mInner->GetTargets(source, property, tv, targets);
|
||
|
}
|
||
|
|
||
|
NS_IMETHOD Assert(nsIRDFResource* source,
|
||
|
nsIRDFResource* property,
|
||
|
nsIRDFNode* target,
|
||
|
PRBool tv);
|
||
|
|
||
|
NS_IMETHOD Unassert(nsIRDFResource* source,
|
||
|
nsIRDFResource* property,
|
||
|
nsIRDFNode* target);
|
||
|
|
||
|
NS_IMETHOD HasAssertion(nsIRDFResource* source,
|
||
|
nsIRDFResource* property,
|
||
|
nsIRDFNode* target,
|
||
|
PRBool tv,
|
||
|
PRBool* hasAssertion) {
|
||
|
return mInner->HasAssertion(source, property, target, tv, hasAssertion);
|
||
|
}
|
||
|
|
||
|
NS_IMETHOD AddObserver(nsIRDFObserver* n) {
|
||
|
return mInner->AddObserver(n);
|
||
|
}
|
||
|
|
||
|
NS_IMETHOD RemoveObserver(nsIRDFObserver* n) {
|
||
|
return mInner->RemoveObserver(n);
|
||
|
}
|
||
|
|
||
|
NS_IMETHOD ArcLabelsIn(nsIRDFNode* node,
|
||
|
nsIRDFArcsInCursor** labels) {
|
||
|
return mInner->ArcLabelsIn(node, labels);
|
||
|
}
|
||
|
|
||
|
NS_IMETHOD ArcLabelsOut(nsIRDFResource* source,
|
||
|
nsIRDFArcsOutCursor** labels) {
|
||
|
return mInner->ArcLabelsOut(source, labels);
|
||
|
}
|
||
|
|
||
|
NS_IMETHOD Flush(void);
|
||
|
|
||
|
NS_IMETHOD IsCommandEnabled(const char* aCommand,
|
||
|
nsIRDFResource* aCommandTarget,
|
||
|
PRBool* aResult) {
|
||
|
return mInner->IsCommandEnabled(aCommand, aCommandTarget, aResult);
|
||
|
}
|
||
|
|
||
|
NS_IMETHOD DoCommand(const char* aCommand,
|
||
|
nsIRDFResource* aCommandTarget) {
|
||
|
// XXX Uh oh, this could cause problems wrt. the "dirty" flag
|
||
|
// if it changes the in-memory store's internal state.
|
||
|
return mInner->DoCommand(aCommand, aCommandTarget);
|
||
|
}
|
||
|
|
||
|
// nsIRDFXMLDataSource interface
|
||
|
NS_IMETHOD BeginLoad(void);
|
||
|
NS_IMETHOD Interrupt(void);
|
||
|
NS_IMETHOD Resume(void);
|
||
|
NS_IMETHOD EndLoad(void);
|
||
|
NS_IMETHOD SetRootResource(nsIRDFResource* aResource);
|
||
|
NS_IMETHOD GetRootResource(nsIRDFResource** aResource);
|
||
|
NS_IMETHOD AddCSSStyleSheetURL(nsIURL* aStyleSheetURL);
|
||
|
NS_IMETHOD GetCSSStyleSheetURLs(nsIURL*** aStyleSheetURLs, PRInt32* aCount);
|
||
|
NS_IMETHOD AddNamedDataSourceURI(const char* aNamedDataSourceURI);
|
||
|
NS_IMETHOD GetNamedDataSourceURIs(const char* const** aNamedDataSourceURIs, PRInt32* aCount);
|
||
|
NS_IMETHOD AddXMLStreamObserver(nsIRDFXMLDataSourceObserver* aObserver);
|
||
|
NS_IMETHOD RemoveXMLStreamObserver(nsIRDFXMLDataSourceObserver* aObserver);
|
||
|
|
||
|
// nsIRDFXMLSource interface
|
||
|
NS_IMETHOD Serialize(nsIOutputStream* aStream);
|
||
|
|
||
|
// Implementation methods
|
||
|
};
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
nsresult
|
||
|
NS_NewRDFXMLDataSource(nsIRDFXMLDataSource** result)
|
||
|
{
|
||
|
RDFXMLDataSourceImpl* ds = new RDFXMLDataSourceImpl();
|
||
|
if (! ds)
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
|
||
|
*result = ds;
|
||
|
NS_ADDREF(*result);
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
RDFXMLDataSourceImpl::RDFXMLDataSourceImpl(void)
|
||
|
: mIsWritable(PR_FALSE),
|
||
|
mNamedDataSourceURIs(nsnull),
|
||
|
mNumNamedDataSourceURIs(0),
|
||
|
mCSSStyleSheetURLs(nsnull),
|
||
|
mNumCSSStyleSheetURLs(0),
|
||
|
mIsLoading(PR_FALSE)
|
||
|
{
|
||
|
nsresult rv;
|
||
|
if (NS_FAILED(rv = nsRepository::CreateInstance(kRDFInMemoryDataSourceCID,
|
||
|
nsnull,
|
||
|
kIRDFDataSourceIID,
|
||
|
(void**) &mInner)))
|
||
|
PR_ASSERT(0);
|
||
|
|
||
|
NS_INIT_REFCNT();
|
||
|
}
|
||
|
|
||
|
|
||
|
RDFXMLDataSourceImpl::~RDFXMLDataSourceImpl(void)
|
||
|
{
|
||
|
nsIRDFService* rdfService;
|
||
|
if (NS_SUCCEEDED(nsServiceManager::GetService(kRDFServiceCID,
|
||
|
kIRDFServiceIID,
|
||
|
(nsISupports**) &rdfService))) {
|
||
|
rdfService->UnregisterDataSource(this);
|
||
|
nsServiceManager::ReleaseService(kRDFServiceCID, rdfService);
|
||
|
}
|
||
|
|
||
|
Flush();
|
||
|
|
||
|
while (--mNumNamedDataSourceURIs >= 0)
|
||
|
delete mNamedDataSourceURIs[mNumNamedDataSourceURIs];
|
||
|
|
||
|
delete mNamedDataSourceURIs;
|
||
|
|
||
|
while (--mNumCSSStyleSheetURLs >= 0)
|
||
|
NS_RELEASE(mCSSStyleSheetURLs[mNumCSSStyleSheetURLs]);
|
||
|
|
||
|
delete mCSSStyleSheetURLs;
|
||
|
}
|
||
|
|
||
|
|
||
|
NS_IMPL_ADDREF(RDFXMLDataSourceImpl);
|
||
|
NS_IMPL_RELEASE(RDFXMLDataSourceImpl);
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
RDFXMLDataSourceImpl::QueryInterface(REFNSIID iid, void** result)
|
||
|
{
|
||
|
if (! result)
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
|
||
|
if (iid.Equals(kISupportsIID) ||
|
||
|
iid.Equals(kIRDFDataSourceIID) ||
|
||
|
iid.Equals(kIRDFXMLDataSourceIID)) {
|
||
|
*result = NS_STATIC_CAST(nsIRDFDataSource*, this);
|
||
|
NS_ADDREF(this);
|
||
|
return NS_OK;
|
||
|
}
|
||
|
else if (iid.Equals(kIRDFXMLSourceIID)) {
|
||
|
*result = NS_STATIC_CAST(nsIRDFXMLSource*, this);
|
||
|
NS_ADDREF(this);
|
||
|
return NS_OK;
|
||
|
}
|
||
|
else {
|
||
|
*result = nsnull;
|
||
|
return NS_NOINTERFACE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
static nsresult
|
||
|
rdf_BlockingParse(nsIURL* aURL, nsIStreamListener* aConsumer)
|
||
|
{
|
||
|
nsresult rv;
|
||
|
|
||
|
nsIInputStream* in;
|
||
|
if (NS_FAILED(rv = NS_OpenURL(aURL, &in, nsnull /* XXX aConsumer */)))
|
||
|
return rv;
|
||
|
|
||
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
||
|
ProxyStream* proxy = new ProxyStream();
|
||
|
if (! proxy)
|
||
|
goto done;
|
||
|
|
||
|
// XXX shouldn't netlib be doing this???
|
||
|
aConsumer->OnStartBinding(aURL, "text/rdf");
|
||
|
while (PR_TRUE) {
|
||
|
char buf[1024];
|
||
|
PRUint32 readCount;
|
||
|
|
||
|
if (NS_FAILED(rv = in->Read(buf, 0, sizeof(buf), &readCount)))
|
||
|
break; // error or eof
|
||
|
|
||
|
if (readCount == 0)
|
||
|
break; // eof
|
||
|
|
||
|
proxy->SetBuffer(buf, readCount);
|
||
|
|
||
|
// XXX shouldn't netlib be doing this???
|
||
|
if (NS_FAILED(rv = aConsumer->OnDataAvailable(aURL, proxy, readCount)))
|
||
|
break;
|
||
|
}
|
||
|
if (rv == NS_BASE_STREAM_EOF) {
|
||
|
rv = NS_OK;
|
||
|
}
|
||
|
// XXX shouldn't netlib be doing this???
|
||
|
aConsumer->OnStopBinding(aURL, 0, nsnull);
|
||
|
|
||
|
done:
|
||
|
NS_RELEASE(in);
|
||
|
return rv;
|
||
|
}
|
||
|
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
RDFXMLDataSourceImpl::Init(const char* uri)
|
||
|
{
|
||
|
static const char kFileURIPrefix[] = "file:";
|
||
|
static const char kResourceURIPrefix[] = "resource:";
|
||
|
|
||
|
NS_PRECONDITION(mInner != nsnull, "not initialized");
|
||
|
if (! mInner)
|
||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||
|
|
||
|
nsresult rv;
|
||
|
|
||
|
// XXX this is a hack: any "file:" URI is considered writable. All
|
||
|
// others are considered read-only.
|
||
|
if (PL_strncmp(uri, kFileURIPrefix, sizeof(kFileURIPrefix) - 1) == 0)
|
||
|
mIsWritable = PR_TRUE;
|
||
|
|
||
|
nsIRDFService* rdfService = nsnull;
|
||
|
nsINameSpaceManager* ns = nsnull;
|
||
|
nsIRDFContentSink* sink = nsnull;
|
||
|
nsIParser* parser = nsnull;
|
||
|
nsIDTD* dtd = nsnull;
|
||
|
nsIStreamListener* lsnr = nsnull;
|
||
|
nsIURL* url = nsnull;
|
||
|
|
||
|
if (NS_FAILED(rv = NS_NewURL(&url, uri)))
|
||
|
goto done;
|
||
|
|
||
|
if (NS_FAILED(rv = mInner->Init(uri)))
|
||
|
goto done;
|
||
|
|
||
|
if (NS_FAILED(rv = nsServiceManager::GetService(kRDFServiceCID,
|
||
|
kIRDFServiceIID,
|
||
|
(nsISupports**) &rdfService)))
|
||
|
goto done;
|
||
|
|
||
|
if (NS_FAILED(rv = rdfService->RegisterDataSource(this)))
|
||
|
goto done;
|
||
|
|
||
|
if (NS_FAILED(rv = nsRepository::CreateInstance(kNameSpaceManagerCID,
|
||
|
nsnull,
|
||
|
kINameSpaceManagerIID,
|
||
|
(void**) &ns)))
|
||
|
goto done;
|
||
|
|
||
|
if (NS_FAILED(rv = nsRepository::CreateInstance(kRDFContentSinkCID,
|
||
|
nsnull,
|
||
|
kIRDFContentSinkIID,
|
||
|
(void**) &sink)))
|
||
|
goto done;
|
||
|
|
||
|
if (NS_FAILED(sink->Init(url, ns)))
|
||
|
goto done;
|
||
|
|
||
|
// We set the content sink's data source directly to our in-memory
|
||
|
// store. This allows the initial content to be generated "directly".
|
||
|
if (NS_FAILED(rv = sink->SetDataSource(this)))
|
||
|
goto done;
|
||
|
|
||
|
if (NS_FAILED(rv = nsRepository::CreateInstance(kParserCID,
|
||
|
nsnull,
|
||
|
kIParserIID,
|
||
|
(void**) &parser)))
|
||
|
goto done;
|
||
|
|
||
|
parser->SetContentSink(sink);
|
||
|
|
||
|
// XXX this should eventually be kRDFDTDCID (oh boy, that's a
|
||
|
// pretty identifier). The RDF DTD will be a much more
|
||
|
// RDF-resilient parser.
|
||
|
if (NS_FAILED(rv = nsRepository::CreateInstance(kWellFormedDTDCID,
|
||
|
nsnull,
|
||
|
kIDTDIID,
|
||
|
(void**) &dtd)))
|
||
|
goto done;
|
||
|
|
||
|
parser->RegisterDTD(dtd);
|
||
|
|
||
|
if (NS_FAILED(rv = parser->QueryInterface(kIStreamListenerIID, (void**) &lsnr)))
|
||
|
goto done;
|
||
|
|
||
|
if (NS_FAILED(parser->Parse(url)))
|
||
|
goto done;
|
||
|
|
||
|
// XXX Yet another hack to get the registry stuff
|
||
|
// bootstrapped. Force "file:" and "resource:" URIs to be loaded
|
||
|
// by a blocking read. Maybe there needs to be a distinct
|
||
|
// interface for stream data sources?
|
||
|
if ((PL_strncmp(uri, kFileURIPrefix, sizeof(kFileURIPrefix) - 1) == 0) ||
|
||
|
(PL_strncmp(uri, kResourceURIPrefix, sizeof(kResourceURIPrefix) - 1) == 0)) {
|
||
|
rdf_BlockingParse(url, lsnr);
|
||
|
}
|
||
|
else {
|
||
|
if (NS_FAILED(NS_OpenURL(url, lsnr)))
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
done:
|
||
|
NS_IF_RELEASE(lsnr);
|
||
|
NS_IF_RELEASE(dtd);
|
||
|
NS_IF_RELEASE(parser);
|
||
|
NS_IF_RELEASE(sink);
|
||
|
if (rdfService) {
|
||
|
nsServiceManager::ReleaseService(kRDFServiceCID, rdfService);
|
||
|
rdfService = nsnull;
|
||
|
}
|
||
|
NS_IF_RELEASE(url);
|
||
|
return rv;
|
||
|
}
|
||
|
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
RDFXMLDataSourceImpl::Assert(nsIRDFResource* source,
|
||
|
nsIRDFResource* property,
|
||
|
nsIRDFNode* target,
|
||
|
PRBool tv)
|
||
|
{
|
||
|
if (!mIsLoading && !mIsWritable)
|
||
|
return NS_ERROR_FAILURE; // XXX right error code?
|
||
|
|
||
|
nsresult rv;
|
||
|
if (NS_SUCCEEDED(rv = mInner->Assert(source, property, target, tv))) {
|
||
|
if (!mIsLoading)
|
||
|
mIsDirty = PR_TRUE;
|
||
|
}
|
||
|
|
||
|
return rv;
|
||
|
}
|
||
|
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
RDFXMLDataSourceImpl::Unassert(nsIRDFResource* source,
|
||
|
nsIRDFResource* property,
|
||
|
nsIRDFNode* target)
|
||
|
{
|
||
|
if (!mIsLoading && !mIsWritable)
|
||
|
return NS_ERROR_FAILURE; // XXX right error code?
|
||
|
|
||
|
nsresult rv;
|
||
|
if (NS_SUCCEEDED(rv = mInner->Unassert(source, property, target))) {
|
||
|
if (!mIsLoading)
|
||
|
mIsDirty = PR_TRUE;
|
||
|
}
|
||
|
|
||
|
return rv;
|
||
|
}
|
||
|
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
RDFXMLDataSourceImpl::Flush(void)
|
||
|
{
|
||
|
if (!mIsWritable || !mIsDirty)
|
||
|
return NS_OK;
|
||
|
|
||
|
nsresult rv;
|
||
|
|
||
|
const char* uri;
|
||
|
if (NS_FAILED(rv = mInner->GetURI(&uri)))
|
||
|
return rv;
|
||
|
|
||
|
nsFileURL url(uri);
|
||
|
nsFilePath path(url);
|
||
|
|
||
|
FileOutputStreamImpl* out = new FileOutputStreamImpl(path);
|
||
|
if (! out)
|
||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||
|
|
||
|
if (NS_FAILED(rv = Serialize(out)))
|
||
|
goto done;
|
||
|
|
||
|
mIsDirty = PR_FALSE;
|
||
|
|
||
|
done:
|
||
|
NS_IF_RELEASE(out);
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
// nsIRDFXMLDataSource methods
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
RDFXMLDataSourceImpl::BeginLoad(void)
|
||
|
{
|
||
|
mIsLoading = PR_TRUE;
|
||
|
for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
|
||
|
nsIRDFXMLDataSourceObserver* obs = (nsIRDFXMLDataSourceObserver*) mObservers[i];
|
||
|
obs->OnBeginLoad(this);
|
||
|
}
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
RDFXMLDataSourceImpl::Interrupt(void)
|
||
|
{
|
||
|
mIsLoading = PR_FALSE;
|
||
|
for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
|
||
|
nsIRDFXMLDataSourceObserver* obs = (nsIRDFXMLDataSourceObserver*) mObservers[i];
|
||
|
obs->OnInterrupt(this);
|
||
|
}
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
RDFXMLDataSourceImpl::Resume(void)
|
||
|
{
|
||
|
for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
|
||
|
nsIRDFXMLDataSourceObserver* obs = (nsIRDFXMLDataSourceObserver*) mObservers[i];
|
||
|
obs->OnResume(this);
|
||
|
}
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
RDFXMLDataSourceImpl::EndLoad(void)
|
||
|
{
|
||
|
for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
|
||
|
nsIRDFXMLDataSourceObserver* obs = (nsIRDFXMLDataSourceObserver*) mObservers[i];
|
||
|
obs->OnEndLoad(this);
|
||
|
}
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
RDFXMLDataSourceImpl::SetRootResource(nsIRDFResource* aResource)
|
||
|
{
|
||
|
NS_PRECONDITION(aResource != nsnull, "null ptr");
|
||
|
if (! aResource)
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
|
||
|
NS_ADDREF(aResource);
|
||
|
mRootResource = aResource;
|
||
|
|
||
|
for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
|
||
|
nsIRDFXMLDataSourceObserver* obs = (nsIRDFXMLDataSourceObserver*) mObservers[i];
|
||
|
obs->OnRootResourceFound(this, mRootResource);
|
||
|
}
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
RDFXMLDataSourceImpl::GetRootResource(nsIRDFResource** aResource)
|
||
|
{
|
||
|
NS_ADDREF(mRootResource);
|
||
|
*aResource = mRootResource;
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
RDFXMLDataSourceImpl::AddCSSStyleSheetURL(nsIURL* aCSSStyleSheetURL)
|
||
|
{
|
||
|
NS_PRECONDITION(aCSSStyleSheetURL != nsnull, "null ptr");
|
||
|
if (! aCSSStyleSheetURL)
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
|
||
|
nsIURL** p = new nsIURL*[mNumCSSStyleSheetURLs + 1];
|
||
|
if (! p)
|
||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||
|
|
||
|
PRInt32 i;
|
||
|
for (i = mNumCSSStyleSheetURLs - 1; i >= 0; --i)
|
||
|
p[i] = mCSSStyleSheetURLs[i];
|
||
|
|
||
|
NS_ADDREF(aCSSStyleSheetURL);
|
||
|
p[mNumCSSStyleSheetURLs] = aCSSStyleSheetURL;
|
||
|
|
||
|
++mNumCSSStyleSheetURLs;
|
||
|
mCSSStyleSheetURLs = p;
|
||
|
|
||
|
for (i = mObservers.Count() - 1; i >= 0; --i) {
|
||
|
nsIRDFXMLDataSourceObserver* obs = (nsIRDFXMLDataSourceObserver*) mObservers[i];
|
||
|
obs->OnCSSStyleSheetAdded(this, aCSSStyleSheetURL);
|
||
|
}
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
RDFXMLDataSourceImpl::GetCSSStyleSheetURLs(nsIURL*** aCSSStyleSheetURLs, PRInt32* aCount)
|
||
|
{
|
||
|
*aCSSStyleSheetURLs = mCSSStyleSheetURLs;
|
||
|
*aCount = mNumCSSStyleSheetURLs;
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
RDFXMLDataSourceImpl::AddNamedDataSourceURI(const char* aNamedDataSourceURI)
|
||
|
{
|
||
|
NS_PRECONDITION(aNamedDataSourceURI != nsnull, "null ptr");
|
||
|
if (! aNamedDataSourceURI)
|
||
|
return NS_ERROR_NULL_POINTER;
|
||
|
|
||
|
char** p = new char*[mNumNamedDataSourceURIs + 1];
|
||
|
if (! p)
|
||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||
|
|
||
|
PRInt32 i;
|
||
|
for (i = mNumNamedDataSourceURIs - 1; i >= 0; --i)
|
||
|
p[i] = mNamedDataSourceURIs[i];
|
||
|
|
||
|
PRInt32 len = PL_strlen(aNamedDataSourceURI);
|
||
|
char* buf = new char[len + 1];
|
||
|
if (! buf) {
|
||
|
delete p;
|
||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||
|
}
|
||
|
|
||
|
PL_strcpy(buf, aNamedDataSourceURI);
|
||
|
p[mNumNamedDataSourceURIs] = buf;
|
||
|
|
||
|
++mNumNamedDataSourceURIs;
|
||
|
mNamedDataSourceURIs = p;
|
||
|
|
||
|
for (i = mObservers.Count() - 1; i >= 0; --i) {
|
||
|
nsIRDFXMLDataSourceObserver* obs = (nsIRDFXMLDataSourceObserver*) mObservers[i];
|
||
|
obs->OnNamedDataSourceAdded(this, aNamedDataSourceURI);
|
||
|
}
|
||
|
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
RDFXMLDataSourceImpl::GetNamedDataSourceURIs(const char* const** aNamedDataSourceURIs, PRInt32* aCount)
|
||
|
{
|
||
|
*aNamedDataSourceURIs = mNamedDataSourceURIs;
|
||
|
*aCount = mNumNamedDataSourceURIs;
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
RDFXMLDataSourceImpl::AddXMLStreamObserver(nsIRDFXMLDataSourceObserver* aObserver)
|
||
|
{
|
||
|
mObservers.AppendElement(aObserver);
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
RDFXMLDataSourceImpl::RemoveXMLStreamObserver(nsIRDFXMLDataSourceObserver* aObserver)
|
||
|
{
|
||
|
mObservers.RemoveElement(aObserver);
|
||
|
return NS_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
// nsIRDFXMLSource methods
|
||
|
|
||
|
NS_IMETHODIMP
|
||
|
RDFXMLDataSourceImpl::Serialize(nsIOutputStream* stream)
|
||
|
{
|
||
|
nsresult rv;
|
||
|
nsIRDFXMLSource* source;
|
||
|
if (NS_SUCCEEDED(rv = mInner->QueryInterface(kIRDFXMLSourceIID, (void**) &source))) {
|
||
|
rv = source->Serialize(stream);
|
||
|
NS_RELEASE(source);
|
||
|
}
|
||
|
return rv;
|
||
|
}
|
||
|
|