Add an async mode to the SAX stuff. Bug 334304, patch by Robert Sayre

<sayrer@gmail.com>, r=biesi, sr=bzbarsky
This commit is contained in:
bzbarsky%mit.edu 2006-04-24 17:01:40 +00:00
Родитель 1d0e188239
Коммит aa75391cba
3 изменённых файлов: 146 добавлений и 59 удалений

Просмотреть файл

@ -35,7 +35,7 @@
*
* ***** END LICENSE BLOCK ***** */
#include "nsISupports.idl"
#include "nsIStreamListener.idl"
interface nsIInputStream;
interface nsIRequestObserver;
@ -56,14 +56,8 @@ interface nsISAXLexicalHandler;
* handlers for document processing, and to initiate a document
* parse.
*/
[scriptable, uuid(6e7236da-d847-4b8e-80af-d3f157acb50d)]
interface nsISAXXMLReader : nsISupports {
/**
* Determines whether the parser blocks the current thread.
* Defaults to false.
*/
attribute boolean async;
[scriptable, uuid(5556997e-d816-4218-8b54-803d4261206e)]
interface nsISAXXMLReader : nsIStreamListener {
/**
* The base URI.
@ -213,4 +207,16 @@ interface nsISAXXMLReader : nsISupports {
void parseFromStream(in nsIInputStream stream,
in string charset,
in string contentType);
/**
* Begin an asynchronous parse. This method initializes the parser,
* and must be called before any nsIStreamListener methods. It is
* then the caller's duty to call nsIStreamListener methods to drive
* the parser. Once this method is called, the caller must not call
* one of the other parse methods.
*
* @param observer The nsIRequestObserver to notify upon start or stop.
* Can be NULL.
*/
void parseAsync(in nsIRequestObserver observer);
};

Просмотреть файл

@ -49,11 +49,12 @@
static NS_DEFINE_CID(kParserCID, NS_PARSER_CID);
NS_IMPL_ISUPPORTS4(nsSAXXMLReader, nsISAXXMLReader,
NS_IMPL_ISUPPORTS6(nsSAXXMLReader, nsISAXXMLReader,
nsIExpatSink, nsIExtendedExpatSink,
nsIContentSink)
nsIContentSink, nsIRequestObserver,
nsIStreamListener)
nsSAXXMLReader::nsSAXXMLReader() : mAsync(PR_TRUE)
nsSAXXMLReader::nsSAXXMLReader() : mIsAsyncParse(PR_FALSE)
{
}
@ -73,14 +74,12 @@ nsSAXXMLReader::DidBuildModel()
if (mContentHandler) {
return mContentHandler->EndDocument();
}
mParser = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsSAXXMLReader::SetParser(nsIParser* aParser)
nsSAXXMLReader::SetParser(nsIParser *aParser)
{
mParser = aParser;
return NS_OK;
}
@ -93,7 +92,7 @@ nsSAXXMLReader::HandleStartElement(const PRUnichar *aName,
PRUint32 aLineNumber)
{
if (!mContentHandler) {
return NS_OK;;
return NS_OK;
}
nsCOMPtr<nsSAXAttributes> atts = new nsSAXAttributes();
@ -296,20 +295,7 @@ nsSAXXMLReader::ReportError(const PRUnichar* aErrorText,
return NS_OK;
}
NS_IMETHODIMP
nsSAXXMLReader::GetAsync(PRBool *aAsync)
{
*aAsync = mAsync;
return NS_OK;
}
NS_IMETHODIMP
nsSAXXMLReader::SetAsync(PRBool aAsync)
{
mAsync = aAsync;
return NS_OK;
}
// nsISAXXMLReader
NS_IMETHODIMP
nsSAXXMLReader::GetBaseURI(nsIURI **aBaseURI)
@ -409,6 +395,9 @@ NS_IMETHODIMP
nsSAXXMLReader::ParseFromString(const nsAString &aStr,
const char *aContentType)
{
// Don't call this in the middle of an async parse
NS_ENSURE_TRUE(!mIsAsyncParse, NS_ERROR_FAILURE);
NS_ConvertUTF16toUTF8 data(aStr);
// The new stream holds a reference to the buffer
@ -425,6 +414,9 @@ nsSAXXMLReader::ParseFromStream(nsIInputStream *aStream,
const char *aCharset,
const char *aContentType)
{
// Don't call this in the middle of an async parse
NS_ENSURE_TRUE(!mIsAsyncParse, NS_ERROR_FAILURE);
NS_ENSURE_ARG(aStream);
NS_ENSURE_ARG(aContentType);
@ -438,40 +430,125 @@ nsSAXXMLReader::ParseFromStream(nsIInputStream *aStream,
aStream = bufferedStream;
}
rv = InitParser(nsnull);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIChannel> parserChannel;
rv = NS_NewInputStreamChannel(getter_AddRefs(parserChannel), mBaseURI,
aStream, nsDependentCString(aContentType));
if (!parserChannel || NS_FAILED(rv)) {
mListener = nsnull;
return NS_ERROR_FAILURE;
}
if (aCharset)
parserChannel->SetContentCharset(nsDependentCString(aCharset));
rv = mListener->OnStartRequest(parserChannel, nsnull);
if (NS_FAILED(rv))
parserChannel->Cancel(rv);
nsresult status;
parserChannel->GetStatus(&status);
PRUint32 offset = 0;
while (NS_SUCCEEDED(rv) && NS_SUCCEEDED(status)) {
PRUint32 available;
rv = aStream->Available(&available);
if (rv == NS_BASE_STREAM_CLOSED) {
rv = NS_OK;
available = 0;
}
if (NS_FAILED(rv)) {
parserChannel->Cancel(rv);
break;
}
if (! available)
break; // blocking input stream has none available when done
rv = mListener->OnDataAvailable(parserChannel, nsnull,
aStream, offset, available);
if (NS_SUCCEEDED(rv))
offset += available;
else
parserChannel->Cancel(rv);
parserChannel->GetStatus(&status);
}
rv = mListener->OnStopRequest(parserChannel, nsnull, status);
mListener = nsnull;
return rv;
}
NS_IMETHODIMP
nsSAXXMLReader::ParseAsync(nsIRequestObserver *aObserver)
{
mParserObserver = aObserver;
mIsAsyncParse = PR_TRUE;
return NS_OK;
}
// nsIRequestObserver
NS_IMETHODIMP
nsSAXXMLReader::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
{
NS_ENSURE_TRUE(mIsAsyncParse, NS_ERROR_FAILURE);
nsresult rv = InitParser(mParserObserver);
NS_ENSURE_SUCCESS(rv, rv);
// we don't need or want this anymore
mParserObserver = nsnull;
return mListener->OnStartRequest(aRequest, aContext);
}
NS_IMETHODIMP
nsSAXXMLReader::OnStopRequest(nsIRequest *aRequest, nsISupports *aContext,
nsresult status)
{
NS_ENSURE_TRUE(mIsAsyncParse, NS_ERROR_FAILURE);
NS_ENSURE_STATE(mListener);
nsresult rv = mListener->OnStopRequest(aRequest, aContext, status);
mListener = nsnull;
mIsAsyncParse = PR_FALSE;
return rv;
}
// nsIStreamListener
NS_IMETHODIMP
nsSAXXMLReader::OnDataAvailable(nsIRequest *aRequest, nsISupports *aContext,
nsIInputStream *aInputStream, PRUint32 offset,
PRUint32 count)
{
NS_ENSURE_TRUE(mIsAsyncParse, NS_ERROR_FAILURE);
NS_ENSURE_STATE(mListener);
return mListener->OnDataAvailable(aRequest, aContext, aInputStream, offset,
count);
}
nsresult
nsSAXXMLReader::InitParser(nsIRequestObserver *aObserver)
{
nsresult rv;
// setup the parser
nsCOMPtr<nsIParser> parser = do_CreateInstance(kParserCID, &rv);
parser->SetContentSink(this);
nsCOMPtr<nsIURI> baseURI;
if (mBaseURI) {
baseURI = mBaseURI;
} else {
rv = NS_NewURI(getter_AddRefs(baseURI), "about:blank");
if (!mBaseURI) {
rv = NS_NewURI(getter_AddRefs(mBaseURI), "about:blank");
NS_ENSURE_SUCCESS(rv, rv);
}
if (!mAsync) {
// XXX This doesn't call DidBuildModel
rv = parser->Parse(aStream, nsDependentCString(aContentType));
} else {
nsCOMPtr<nsIChannel> parserChannel;
NS_NewInputStreamChannel(getter_AddRefs(parserChannel), baseURI, aStream,
nsDependentCString(aContentType), nsnull);
NS_ENSURE_STATE(parserChannel);
#ifdef MOZILLA_1_8_BRANCH
rv = parser->Parse(mBaseURI, aObserver, PR_FALSE);
#else
rv = parser->Parse(mBaseURI, aObserver);
#endif
NS_ENSURE_SUCCESS(rv, rv);
if (aCharset)
parserChannel->SetContentCharset(nsDependentCString(aCharset));
nsCOMPtr<nsIInputStreamChannel> inputChannel =
do_QueryInterface(parserChannel, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = parser->Parse(baseURI, nsnull);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIStreamListener> listener = do_QueryInterface(parser, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = parserChannel->AsyncOpen(listener, nsnull);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
mListener = do_QueryInterface(parser, &rv);
return rv;
}
nsresult

Просмотреть файл

@ -64,6 +64,8 @@ public:
NS_DECL_NSIEXPATSINK
NS_DECL_NSIEXTENDEDEXPATSINK
NS_DECL_NSISAXXMLREADER
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
nsSAXXMLReader();
@ -102,8 +104,10 @@ private:
nsCOMPtr<nsISAXErrorHandler> mErrorHandler;
nsCOMPtr<nsISAXLexicalHandler> mLexicalHandler;
nsCOMPtr<nsIURI> mBaseURI;
nsCOMPtr<nsIParser> mParser;
PRBool mAsync;
nsCOMPtr<nsIStreamListener> mListener;
nsCOMPtr<nsIRequestObserver> mParserObserver;
PRBool mIsAsyncParse;
nsresult InitParser(nsIRequestObserver *aListener);
nsresult SplitExpatName(const PRUnichar *aExpatName,
nsString &aURI,
nsString &aLocalName,