diff --git a/htmlparser/src/CParserContext.cpp b/htmlparser/src/CParserContext.cpp index c13ebd900814..8b58ff42934f 100644 --- a/htmlparser/src/CParserContext.cpp +++ b/htmlparser/src/CParserContext.cpp @@ -33,7 +33,7 @@ MOZ_DECL_CTOR_COUNTER(CParserContext); * @param aKey * @param aListener */ -CParserContext::CParserContext(nsScanner* aScanner,void* aKey,nsIStreamObserver* aListener) : +CParserContext::CParserContext(nsScanner* aScanner,void* aKey,nsIStreamObserver* aListener,PRBool aCopyUnused) : mSourceType() //,mTokenDeque(gTokenDeallocator) { @@ -53,6 +53,7 @@ CParserContext::CParserContext(nsScanner* aScanner,void* aKey,nsIStreamObserver* mStreamListenerState=eNone; mMultipart=PR_TRUE; mContextType=eCTNone; + mCopyUnused=aCopyUnused; } diff --git a/htmlparser/src/CParserContext.h b/htmlparser/src/CParserContext.h index e25e5554c915..a54f68f9a6ad 100644 --- a/htmlparser/src/CParserContext.h +++ b/htmlparser/src/CParserContext.h @@ -51,29 +51,32 @@ public: CParserContext( nsScanner* aScanner, void* aKey=0, - nsIStreamObserver* aListener=0); + nsIStreamObserver* aListener=0, + PRBool aCopyUnused=PR_FALSE); ~CParserContext(); - nsString mSourceType; + CParserContext* mPrevContext; + eParseMode mParseMode; + eStreamState mStreamListenerState; //this is really only here for debug purposes. + PRBool mMultipart; + eContextType mContextType; eAutoDetectResult mAutoDetectStatus; + nsString mSourceType; + nsScanner* mScanner; nsIDTD* mDTD; - eParseMode mParseMode; char* mTransferBuffer; nsIStreamObserver* mListener; - CParserContext* mPrevContext; void* mKey; PRUint32 mTransferBufferSize; PRBool mParserEnabled; - eStreamState mStreamListenerState; //this is really only here for debug purposes. - PRBool mMultipart; - eContextType mContextType; + PRBool mCopyUnused; }; diff --git a/htmlparser/src/nsParser.cpp b/htmlparser/src/nsParser.cpp index b37acb09cddc..15f02b8973fc 100644 --- a/htmlparser/src/nsParser.cpp +++ b/htmlparser/src/nsParser.cpp @@ -677,27 +677,24 @@ eParseMode DetermineParseMode(nsParser& aParser) { * @param * @return error code -- 0 if ok, non-zero if error. */ -nsresult nsParser::WillBuildModel(nsString& aFilename,nsIDTD* aDefaultDTD){ +nsresult nsParser::WillBuildModel(nsString& aFilename){ nsresult result=NS_OK; if(mParserContext){ - if(eOnStart==mParserContext->mStreamListenerState) { + if(eUnknownDetect==mParserContext->mAutoDetectStatus) { mMajorIteration=-1; mMinorIteration=-1; - if(eUnknownDetect==mParserContext->mAutoDetectStatus) { - mParserContext->mDTD=aDefaultDTD; - if(PR_TRUE==FindSuitableDTD(*mParserContext,mCommand,mParserContext->mScanner->GetBuffer())) { - mParserContext->mParseMode=DetermineParseMode(*this); - mParserContext->mStreamListenerState=eOnDataAvail; - mParserContext->mDTD->WillBuildModel( aFilename, - PRBool(0==mParserContext->mPrevContext), - mParserContext->mSourceType, - mParserContext->mParseMode, - mCommand, - mSink); - }//if - }//if + if(PR_TRUE==FindSuitableDTD(*mParserContext,mCommand,mParserContext->mScanner->GetBuffer())) { + mParserContext->mParseMode=DetermineParseMode(*this); + // mParserContext->mStreamListenerState=eOnDataAvail; + mParserContext->mDTD->WillBuildModel( aFilename, + PRBool(0==mParserContext->mPrevContext), + mParserContext->mSourceType, + mParserContext->mParseMode, + mCommand, + mSink); + }//if }//if } else result=kInvalidParserContext; @@ -716,7 +713,7 @@ nsresult nsParser::DidBuildModel(nsresult anErrorCode) { //One last thing...close any open containers. nsresult result=anErrorCode; - if(mParserContext->mParserEnabled) { + if((mParserContext) && mParserContext->mParserEnabled) { if((!mParserContext->mPrevContext) && (mParserContext->mDTD)) { result=mParserContext->mDTD->DidBuildModel(anErrorCode,PRBool(0==mParserContext->mPrevContext),this,mSink); } @@ -800,29 +797,28 @@ nsresult nsParser::Terminate(void){ * @return current state */ nsresult nsParser::EnableParser(PRBool aState){ - nsIParser* me = nsnull; // If the stream has already finished, there's a good chance // that we might start closing things down when the parser // is reenabled. To make sure that we're not deleted across // the reenabling process, hold a reference to ourselves. - if (eOnStop == mParserContext->mStreamListenerState) { - me = this; - NS_ADDREF(me); - } + nsresult result=NS_OK; + nsIParser* me = this; + NS_ADDREF(me); // If we're reenabling the parser - mParserContext->mParserEnabled=aState; - nsresult result=NS_OK; - if(aState) { - result=ResumeParse(); - if(result!=NS_OK) - result=mInternalState; + if(mParserContext) { + mParserContext->mParserEnabled=aState; + if(aState) { + result=ResumeParse(); + if(result!=NS_OK) + result=mInternalState; + } + else { + MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: nsParser::EnableParser(), this=%p\n", this)); + MOZ_TIMER_STOP(mParseTime); + } } - else { - MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: nsParser::EnableParser(), this=%p\n", this)); - MOZ_TIMER_STOP(mParseTime); - } // Release reference if we added one at the top of this routine NS_IF_RELEASE(me); @@ -953,10 +949,16 @@ nsresult nsParser::Parse(const nsString& aSourceBuffer,void* aKey,const nsString //only make a new context if we dont have one, OR if we do, but has a different context key... nsScanner* theScanner=new nsScanner(mUnusedInput,mCharset,mCharsetSource); - pc=new CParserContext(theScanner,aKey, 0); + pc=new CParserContext(theScanner,aKey, 0, aLastCall); if(pc && theScanner) { PushContext(*pc); - pc->mStreamListenerState=eOnStart; + + pc->mMultipart=!aLastCall; //by default + if (pc->mPrevContext) { + pc->mMultipart |= pc->mPrevContext->mMultipart; //if available + } + + pc->mStreamListenerState = (pc->mMultipart) ? eOnDataAvail : eOnStop; pc->mContextType=CParserContext::eCTString; pc->mSourceType=aContentType; mUnusedInput.Truncate(0); @@ -973,22 +975,13 @@ nsresult nsParser::Parse(const nsString& aSourceBuffer,void* aKey,const nsString pc->mScanner->Append(aSourceBuffer); - if (nsnull != pc->mPrevContext) { - pc->mMultipart = (pc->mPrevContext->mMultipart || !aLastCall); - } - else { - pc->mMultipart=!aLastCall; - } - result=ResumeParse(); - if(aLastCall) { - pc->mScanner->CopyUnusedData(mUnusedInput); - pc=PopContext(); - delete pc; - }//if + result=ResumeParse(PR_FALSE); + }//if NS_RELEASE(me); return result; -} +} + /** * Call this method to test whether a given fragment is valid within a given context-stack. @@ -1106,88 +1099,127 @@ nsresult nsParser::ParseFragment(const nsString& aSourceBuffer,void* aKey,nsITag /** - * This routine is called to cause the parser to continue - * parsing it's underlying stream. This call allows the - * parse process to happen in chunks, such as when the - * content is push based, and we need to parse in pieces. + * This routine is called to cause the parser to continue parsing it's underlying stream. + * This call allows the parse process to happen in chunks, such as when the content is push + * based, and we need to parse in pieces. * - * @update gess 01/04/99 - * @param + * An interesting change in how the parser gets used has led us to add extra processing to this method. + * The case occurs when the parser is blocked in one context, and gets a parse(string) call in another context. + * In this case, the parserContexts are linked. No problem. + * + * The problem is that Parse(string) assumes that it can proceed unabated, but if the parser is already + * blocked that assumption is false. So we needed to add a mechanism here to allow the parser to continue + * to process (the pop and free) contexts until 1) it get's blocked again; 2) it runs out of contexts. + * + * + * @update rickg 03.10.2000 + * @param allowItertion : set to true if non-script resumption is requested + * @param aIsFinalChunk : tells us when the last chunk of data is provided. * @return error code -- 0 if ok, non-zero if error. */ -nsresult nsParser::ResumeParse(nsIDTD* aDefaultDTD, PRBool aIsFinalChunk) { +nsresult nsParser::ResumeParse(PRBool allowIteration, PRBool aIsFinalChunk) { + nsresult result=NS_OK; + if(mParserContext->mParserEnabled && mInternalState!=NS_ERROR_HTMLPARSER_STOPPARSING) { + MOZ_TIMER_DEBUGLOG(("Start: Parse Time: nsParser::ResumeParse(), this=%p\n", this)); MOZ_TIMER_START(mParseTime); - result=WillBuildModel(mParserContext->mScanner->GetFilename(),aDefaultDTD); + result=WillBuildModel(mParserContext->mScanner->GetFilename()); if(mParserContext->mDTD) { + mParserContext->mDTD->WillResumeParse(); - if(NS_OK==result) { - nsresult theTokenizerResult=NS_OK; - - while(result==NS_OK) { + PRBool theIterationIsOk=(allowIteration||(!mParserContext->mPrevContext)); + + while((result==NS_OK) && (theIterationIsOk)) { - if(mUnusedInput.Length()>0) { - if(mParserContext->mScanner) { - // -- Ref: Bug# 22485 -- - // Insert the unused input into the source buffer - // as if it was read from the input stream. - // Adding Insert() per vidur!! - mParserContext->mScanner->Insert(mUnusedInput); - mUnusedInput.Truncate(0); - } + if(mUnusedInput.Length()>0) { + if(mParserContext->mScanner) { + // -- Ref: Bug# 22485 -- + // Insert the unused input into the source buffer + // as if it was read from the input stream. + // Adding Insert() per vidur!! + mParserContext->mScanner->Insert(mUnusedInput); + mUnusedInput.Truncate(0); } + } - result=Tokenize(aIsFinalChunk); + nsresult theTokenizerResult=Tokenize(aIsFinalChunk); // kEOF==2152596456 + result=BuildModel(); - if(result!=NS_OK) theTokenizerResult=result; + theIterationIsOk=PRBool(kEOF!=theTokenizerResult); + + // Make sure not to stop parsing too early. Therefore, before shutting down the + // parser, it's important to check whether the input buffer has been scanned to + // completion ( theTokenizerResult should be kEOF ). kEOF -> End of buffer. - result=BuildModel(); + // If we're told to block the parser, we disable all further parsing + // (and cache any data coming in) until the parser is re-enabled. + + if(NS_ERROR_HTMLPARSER_BLOCK==result) { + //BLOCK == 2152596464 + mParserContext->mDTD->WillInterruptParse(); + result=EnableParser(PR_FALSE); + return result; + } - if(result==NS_ERROR_HTMLPARSER_STOPPARSING) mInternalState=result; + else if (NS_ERROR_HTMLPARSER_STOPPARSING==result) { + mInternalState=result; + DidBuildModel(mStreamStatus); + return mInternalState; + } + + else if((NS_OK==result) && (theTokenizerResult==kEOF)){ - // Make sure not to stop parsing too early. Therefore, before shutting down the - // parser, it's important to check whether the input buffer has been scanned to - // completion ( theTokenizerResult should be kEOF ). kEOF -> End of buffer. - if((!mParserContext->mMultipart) || (mInternalState==NS_ERROR_HTMLPARSER_STOPPARSING) || - ((eOnStop==mParserContext->mStreamListenerState) && (NS_OK==result) && (theTokenizerResult==kEOF))){ + PRBool theContextIsStringBased=PRBool(CParserContext::eCTString==mParserContext->mContextType); + if( (eOnStop==mParserContext->mStreamListenerState) || + (!mParserContext->mMultipart) || + (theContextIsStringBased)) { - DidBuildModel(mStreamStatus); + if(!mParserContext->mPrevContext) { - MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: nsParser::ResumeParse(), this=%p\n", this)); - MOZ_TIMER_STOP(mParseTime); + DidBuildModel(mStreamStatus); - MOZ_TIMER_LOG(("Parse Time (this=%p): ", this)); - MOZ_TIMER_PRINT(mParseTime); + MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: nsParser::ResumeParse(), this=%p\n", this)); + MOZ_TIMER_STOP(mParseTime); - MOZ_TIMER_LOG(("DTD Time: ")); - MOZ_TIMER_PRINT(mDTDTime); + MOZ_TIMER_LOG(("Parse Time (this=%p): ", this)); + MOZ_TIMER_PRINT(mParseTime); - MOZ_TIMER_LOG(("Tokenize Time: ")); - MOZ_TIMER_PRINT(mTokenizeTime); - - return mInternalState; - } - // If we're told to block the parser, we disable - // all further parsing (and cache any data coming - // in) until the parser is enabled. - //PRUint32 b1=NS_ERROR_HTMLPARSER_BLOCK; - else if(NS_ERROR_HTMLPARSER_BLOCK==result) { - mParserContext->mDTD->WillInterruptParse(); - result=EnableParser(PR_FALSE); - break; - } - // If we're at the end of the current scanner buffer, - // we interrupt parsing and wait for the next one - else if (theTokenizerResult==kEOF) { - mParserContext->mDTD->WillInterruptParse(); - break; - } - }//while - }//if + MOZ_TIMER_LOG(("DTD Time: ")); + MOZ_TIMER_PRINT(mDTDTime); + + MOZ_TIMER_LOG(("Tokenize Time: ")); + MOZ_TIMER_PRINT(mTokenizeTime); + + return result; + + } + else { + + CParserContext* theContext=PopContext(); + if(theContext) { + theIterationIsOk=PRBool(allowIteration && theContextIsStringBased); + if(theContext->mCopyUnused) { + theContext->mScanner->CopyUnusedData(mUnusedInput); + } + delete theContext; + } + result = mInternalState; + //...then intentionally fall through to WillInterruptParse()... + } + + } + + } + + if(kEOF==theTokenizerResult) { + mParserContext->mDTD->WillInterruptParse(); + } + + }//while }//if else { mInternalState=result=NS_ERROR_HTMLPARSER_UNRESOLVEDDTD; @@ -1450,6 +1482,8 @@ nsresult nsParser::OnDataAvailable(nsIChannel* channel, nsISupports* aContext, NS_PRECONDITION(((eOnStart==mParserContext->mStreamListenerState)||(eOnDataAvail==mParserContext->mStreamListenerState)),kOnStartNotCalled); + mParserContext->mStreamListenerState=eOnDataAvail; + if(eInvalidDetect==mParserContext->mAutoDetectStatus) { if(mParserContext->mScanner) { mParserContext->mScanner->GetBuffer().Truncate(); @@ -1549,7 +1583,7 @@ nsresult nsParser::OnStopRequest(nsIChannel* channel, nsISupports* aContext, //What we'll do (for now at least) is construct a blank HTML document. nsAutoString temp(""); mParserContext->mScanner->Append(temp); - result=ResumeParse(nsnull, PR_TRUE); + result=ResumeParse(PR_TRUE,PR_TRUE); } mParserContext->mStreamListenerState=eOnStop; @@ -1559,7 +1593,7 @@ nsresult nsParser::OnStopRequest(nsIChannel* channel, nsISupports* aContext, mParserFilter->Finish(); mParserContext->mScanner->SetIncremental(PR_FALSE); - result=ResumeParse(nsnull, PR_TRUE); + result=ResumeParse(PR_TRUE,PR_TRUE); // If the parser isn't enabled, we don't finish parsing till // it is reenabled. @@ -1575,6 +1609,7 @@ nsresult nsParser::OnStopRequest(nsIChannel* channel, nsISupports* aContext, if(gOutFile){ gOutFile->close(); delete gOutFile; + gOutFile=0; } #endif diff --git a/htmlparser/src/nsParser.h b/htmlparser/src/nsParser.h index c3a7aafea997..33a46c606c05 100644 --- a/htmlparser/src/nsParser.h +++ b/htmlparser/src/nsParser.h @@ -239,7 +239,7 @@ CLASS_EXPORT_HTMLPARS nsParser : public nsIParser, public nsIStreamListener { * @update gess5/11/98 * @return TRUE if all went well, otherwise FALSE */ - virtual nsresult ResumeParse(nsIDTD* mDefaultDTD=0, PRBool aIsFinalChunk=PR_FALSE); + virtual nsresult ResumeParse(PRBool allowIteration=PR_TRUE, PRBool aIsFinalChunk=PR_FALSE); void DebugDumpSource(nsOutputStream& anOutput); @@ -301,7 +301,7 @@ protected: * @param * @return */ - nsresult WillBuildModel(nsString& aFilename,nsIDTD* mDefaultDTD=0); + nsresult WillBuildModel(nsString& aFilename); /** * diff --git a/parser/htmlparser/src/CParserContext.cpp b/parser/htmlparser/src/CParserContext.cpp index c13ebd900814..8b58ff42934f 100644 --- a/parser/htmlparser/src/CParserContext.cpp +++ b/parser/htmlparser/src/CParserContext.cpp @@ -33,7 +33,7 @@ MOZ_DECL_CTOR_COUNTER(CParserContext); * @param aKey * @param aListener */ -CParserContext::CParserContext(nsScanner* aScanner,void* aKey,nsIStreamObserver* aListener) : +CParserContext::CParserContext(nsScanner* aScanner,void* aKey,nsIStreamObserver* aListener,PRBool aCopyUnused) : mSourceType() //,mTokenDeque(gTokenDeallocator) { @@ -53,6 +53,7 @@ CParserContext::CParserContext(nsScanner* aScanner,void* aKey,nsIStreamObserver* mStreamListenerState=eNone; mMultipart=PR_TRUE; mContextType=eCTNone; + mCopyUnused=aCopyUnused; } diff --git a/parser/htmlparser/src/CParserContext.h b/parser/htmlparser/src/CParserContext.h index e25e5554c915..a54f68f9a6ad 100644 --- a/parser/htmlparser/src/CParserContext.h +++ b/parser/htmlparser/src/CParserContext.h @@ -51,29 +51,32 @@ public: CParserContext( nsScanner* aScanner, void* aKey=0, - nsIStreamObserver* aListener=0); + nsIStreamObserver* aListener=0, + PRBool aCopyUnused=PR_FALSE); ~CParserContext(); - nsString mSourceType; + CParserContext* mPrevContext; + eParseMode mParseMode; + eStreamState mStreamListenerState; //this is really only here for debug purposes. + PRBool mMultipart; + eContextType mContextType; eAutoDetectResult mAutoDetectStatus; + nsString mSourceType; + nsScanner* mScanner; nsIDTD* mDTD; - eParseMode mParseMode; char* mTransferBuffer; nsIStreamObserver* mListener; - CParserContext* mPrevContext; void* mKey; PRUint32 mTransferBufferSize; PRBool mParserEnabled; - eStreamState mStreamListenerState; //this is really only here for debug purposes. - PRBool mMultipart; - eContextType mContextType; + PRBool mCopyUnused; }; diff --git a/parser/htmlparser/src/nsParser.cpp b/parser/htmlparser/src/nsParser.cpp index b37acb09cddc..15f02b8973fc 100644 --- a/parser/htmlparser/src/nsParser.cpp +++ b/parser/htmlparser/src/nsParser.cpp @@ -677,27 +677,24 @@ eParseMode DetermineParseMode(nsParser& aParser) { * @param * @return error code -- 0 if ok, non-zero if error. */ -nsresult nsParser::WillBuildModel(nsString& aFilename,nsIDTD* aDefaultDTD){ +nsresult nsParser::WillBuildModel(nsString& aFilename){ nsresult result=NS_OK; if(mParserContext){ - if(eOnStart==mParserContext->mStreamListenerState) { + if(eUnknownDetect==mParserContext->mAutoDetectStatus) { mMajorIteration=-1; mMinorIteration=-1; - if(eUnknownDetect==mParserContext->mAutoDetectStatus) { - mParserContext->mDTD=aDefaultDTD; - if(PR_TRUE==FindSuitableDTD(*mParserContext,mCommand,mParserContext->mScanner->GetBuffer())) { - mParserContext->mParseMode=DetermineParseMode(*this); - mParserContext->mStreamListenerState=eOnDataAvail; - mParserContext->mDTD->WillBuildModel( aFilename, - PRBool(0==mParserContext->mPrevContext), - mParserContext->mSourceType, - mParserContext->mParseMode, - mCommand, - mSink); - }//if - }//if + if(PR_TRUE==FindSuitableDTD(*mParserContext,mCommand,mParserContext->mScanner->GetBuffer())) { + mParserContext->mParseMode=DetermineParseMode(*this); + // mParserContext->mStreamListenerState=eOnDataAvail; + mParserContext->mDTD->WillBuildModel( aFilename, + PRBool(0==mParserContext->mPrevContext), + mParserContext->mSourceType, + mParserContext->mParseMode, + mCommand, + mSink); + }//if }//if } else result=kInvalidParserContext; @@ -716,7 +713,7 @@ nsresult nsParser::DidBuildModel(nsresult anErrorCode) { //One last thing...close any open containers. nsresult result=anErrorCode; - if(mParserContext->mParserEnabled) { + if((mParserContext) && mParserContext->mParserEnabled) { if((!mParserContext->mPrevContext) && (mParserContext->mDTD)) { result=mParserContext->mDTD->DidBuildModel(anErrorCode,PRBool(0==mParserContext->mPrevContext),this,mSink); } @@ -800,29 +797,28 @@ nsresult nsParser::Terminate(void){ * @return current state */ nsresult nsParser::EnableParser(PRBool aState){ - nsIParser* me = nsnull; // If the stream has already finished, there's a good chance // that we might start closing things down when the parser // is reenabled. To make sure that we're not deleted across // the reenabling process, hold a reference to ourselves. - if (eOnStop == mParserContext->mStreamListenerState) { - me = this; - NS_ADDREF(me); - } + nsresult result=NS_OK; + nsIParser* me = this; + NS_ADDREF(me); // If we're reenabling the parser - mParserContext->mParserEnabled=aState; - nsresult result=NS_OK; - if(aState) { - result=ResumeParse(); - if(result!=NS_OK) - result=mInternalState; + if(mParserContext) { + mParserContext->mParserEnabled=aState; + if(aState) { + result=ResumeParse(); + if(result!=NS_OK) + result=mInternalState; + } + else { + MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: nsParser::EnableParser(), this=%p\n", this)); + MOZ_TIMER_STOP(mParseTime); + } } - else { - MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: nsParser::EnableParser(), this=%p\n", this)); - MOZ_TIMER_STOP(mParseTime); - } // Release reference if we added one at the top of this routine NS_IF_RELEASE(me); @@ -953,10 +949,16 @@ nsresult nsParser::Parse(const nsString& aSourceBuffer,void* aKey,const nsString //only make a new context if we dont have one, OR if we do, but has a different context key... nsScanner* theScanner=new nsScanner(mUnusedInput,mCharset,mCharsetSource); - pc=new CParserContext(theScanner,aKey, 0); + pc=new CParserContext(theScanner,aKey, 0, aLastCall); if(pc && theScanner) { PushContext(*pc); - pc->mStreamListenerState=eOnStart; + + pc->mMultipart=!aLastCall; //by default + if (pc->mPrevContext) { + pc->mMultipart |= pc->mPrevContext->mMultipart; //if available + } + + pc->mStreamListenerState = (pc->mMultipart) ? eOnDataAvail : eOnStop; pc->mContextType=CParserContext::eCTString; pc->mSourceType=aContentType; mUnusedInput.Truncate(0); @@ -973,22 +975,13 @@ nsresult nsParser::Parse(const nsString& aSourceBuffer,void* aKey,const nsString pc->mScanner->Append(aSourceBuffer); - if (nsnull != pc->mPrevContext) { - pc->mMultipart = (pc->mPrevContext->mMultipart || !aLastCall); - } - else { - pc->mMultipart=!aLastCall; - } - result=ResumeParse(); - if(aLastCall) { - pc->mScanner->CopyUnusedData(mUnusedInput); - pc=PopContext(); - delete pc; - }//if + result=ResumeParse(PR_FALSE); + }//if NS_RELEASE(me); return result; -} +} + /** * Call this method to test whether a given fragment is valid within a given context-stack. @@ -1106,88 +1099,127 @@ nsresult nsParser::ParseFragment(const nsString& aSourceBuffer,void* aKey,nsITag /** - * This routine is called to cause the parser to continue - * parsing it's underlying stream. This call allows the - * parse process to happen in chunks, such as when the - * content is push based, and we need to parse in pieces. + * This routine is called to cause the parser to continue parsing it's underlying stream. + * This call allows the parse process to happen in chunks, such as when the content is push + * based, and we need to parse in pieces. * - * @update gess 01/04/99 - * @param + * An interesting change in how the parser gets used has led us to add extra processing to this method. + * The case occurs when the parser is blocked in one context, and gets a parse(string) call in another context. + * In this case, the parserContexts are linked. No problem. + * + * The problem is that Parse(string) assumes that it can proceed unabated, but if the parser is already + * blocked that assumption is false. So we needed to add a mechanism here to allow the parser to continue + * to process (the pop and free) contexts until 1) it get's blocked again; 2) it runs out of contexts. + * + * + * @update rickg 03.10.2000 + * @param allowItertion : set to true if non-script resumption is requested + * @param aIsFinalChunk : tells us when the last chunk of data is provided. * @return error code -- 0 if ok, non-zero if error. */ -nsresult nsParser::ResumeParse(nsIDTD* aDefaultDTD, PRBool aIsFinalChunk) { +nsresult nsParser::ResumeParse(PRBool allowIteration, PRBool aIsFinalChunk) { + nsresult result=NS_OK; + if(mParserContext->mParserEnabled && mInternalState!=NS_ERROR_HTMLPARSER_STOPPARSING) { + MOZ_TIMER_DEBUGLOG(("Start: Parse Time: nsParser::ResumeParse(), this=%p\n", this)); MOZ_TIMER_START(mParseTime); - result=WillBuildModel(mParserContext->mScanner->GetFilename(),aDefaultDTD); + result=WillBuildModel(mParserContext->mScanner->GetFilename()); if(mParserContext->mDTD) { + mParserContext->mDTD->WillResumeParse(); - if(NS_OK==result) { - nsresult theTokenizerResult=NS_OK; - - while(result==NS_OK) { + PRBool theIterationIsOk=(allowIteration||(!mParserContext->mPrevContext)); + + while((result==NS_OK) && (theIterationIsOk)) { - if(mUnusedInput.Length()>0) { - if(mParserContext->mScanner) { - // -- Ref: Bug# 22485 -- - // Insert the unused input into the source buffer - // as if it was read from the input stream. - // Adding Insert() per vidur!! - mParserContext->mScanner->Insert(mUnusedInput); - mUnusedInput.Truncate(0); - } + if(mUnusedInput.Length()>0) { + if(mParserContext->mScanner) { + // -- Ref: Bug# 22485 -- + // Insert the unused input into the source buffer + // as if it was read from the input stream. + // Adding Insert() per vidur!! + mParserContext->mScanner->Insert(mUnusedInput); + mUnusedInput.Truncate(0); } + } - result=Tokenize(aIsFinalChunk); + nsresult theTokenizerResult=Tokenize(aIsFinalChunk); // kEOF==2152596456 + result=BuildModel(); - if(result!=NS_OK) theTokenizerResult=result; + theIterationIsOk=PRBool(kEOF!=theTokenizerResult); + + // Make sure not to stop parsing too early. Therefore, before shutting down the + // parser, it's important to check whether the input buffer has been scanned to + // completion ( theTokenizerResult should be kEOF ). kEOF -> End of buffer. - result=BuildModel(); + // If we're told to block the parser, we disable all further parsing + // (and cache any data coming in) until the parser is re-enabled. + + if(NS_ERROR_HTMLPARSER_BLOCK==result) { + //BLOCK == 2152596464 + mParserContext->mDTD->WillInterruptParse(); + result=EnableParser(PR_FALSE); + return result; + } - if(result==NS_ERROR_HTMLPARSER_STOPPARSING) mInternalState=result; + else if (NS_ERROR_HTMLPARSER_STOPPARSING==result) { + mInternalState=result; + DidBuildModel(mStreamStatus); + return mInternalState; + } + + else if((NS_OK==result) && (theTokenizerResult==kEOF)){ - // Make sure not to stop parsing too early. Therefore, before shutting down the - // parser, it's important to check whether the input buffer has been scanned to - // completion ( theTokenizerResult should be kEOF ). kEOF -> End of buffer. - if((!mParserContext->mMultipart) || (mInternalState==NS_ERROR_HTMLPARSER_STOPPARSING) || - ((eOnStop==mParserContext->mStreamListenerState) && (NS_OK==result) && (theTokenizerResult==kEOF))){ + PRBool theContextIsStringBased=PRBool(CParserContext::eCTString==mParserContext->mContextType); + if( (eOnStop==mParserContext->mStreamListenerState) || + (!mParserContext->mMultipart) || + (theContextIsStringBased)) { - DidBuildModel(mStreamStatus); + if(!mParserContext->mPrevContext) { - MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: nsParser::ResumeParse(), this=%p\n", this)); - MOZ_TIMER_STOP(mParseTime); + DidBuildModel(mStreamStatus); - MOZ_TIMER_LOG(("Parse Time (this=%p): ", this)); - MOZ_TIMER_PRINT(mParseTime); + MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: nsParser::ResumeParse(), this=%p\n", this)); + MOZ_TIMER_STOP(mParseTime); - MOZ_TIMER_LOG(("DTD Time: ")); - MOZ_TIMER_PRINT(mDTDTime); + MOZ_TIMER_LOG(("Parse Time (this=%p): ", this)); + MOZ_TIMER_PRINT(mParseTime); - MOZ_TIMER_LOG(("Tokenize Time: ")); - MOZ_TIMER_PRINT(mTokenizeTime); - - return mInternalState; - } - // If we're told to block the parser, we disable - // all further parsing (and cache any data coming - // in) until the parser is enabled. - //PRUint32 b1=NS_ERROR_HTMLPARSER_BLOCK; - else if(NS_ERROR_HTMLPARSER_BLOCK==result) { - mParserContext->mDTD->WillInterruptParse(); - result=EnableParser(PR_FALSE); - break; - } - // If we're at the end of the current scanner buffer, - // we interrupt parsing and wait for the next one - else if (theTokenizerResult==kEOF) { - mParserContext->mDTD->WillInterruptParse(); - break; - } - }//while - }//if + MOZ_TIMER_LOG(("DTD Time: ")); + MOZ_TIMER_PRINT(mDTDTime); + + MOZ_TIMER_LOG(("Tokenize Time: ")); + MOZ_TIMER_PRINT(mTokenizeTime); + + return result; + + } + else { + + CParserContext* theContext=PopContext(); + if(theContext) { + theIterationIsOk=PRBool(allowIteration && theContextIsStringBased); + if(theContext->mCopyUnused) { + theContext->mScanner->CopyUnusedData(mUnusedInput); + } + delete theContext; + } + result = mInternalState; + //...then intentionally fall through to WillInterruptParse()... + } + + } + + } + + if(kEOF==theTokenizerResult) { + mParserContext->mDTD->WillInterruptParse(); + } + + }//while }//if else { mInternalState=result=NS_ERROR_HTMLPARSER_UNRESOLVEDDTD; @@ -1450,6 +1482,8 @@ nsresult nsParser::OnDataAvailable(nsIChannel* channel, nsISupports* aContext, NS_PRECONDITION(((eOnStart==mParserContext->mStreamListenerState)||(eOnDataAvail==mParserContext->mStreamListenerState)),kOnStartNotCalled); + mParserContext->mStreamListenerState=eOnDataAvail; + if(eInvalidDetect==mParserContext->mAutoDetectStatus) { if(mParserContext->mScanner) { mParserContext->mScanner->GetBuffer().Truncate(); @@ -1549,7 +1583,7 @@ nsresult nsParser::OnStopRequest(nsIChannel* channel, nsISupports* aContext, //What we'll do (for now at least) is construct a blank HTML document. nsAutoString temp(""); mParserContext->mScanner->Append(temp); - result=ResumeParse(nsnull, PR_TRUE); + result=ResumeParse(PR_TRUE,PR_TRUE); } mParserContext->mStreamListenerState=eOnStop; @@ -1559,7 +1593,7 @@ nsresult nsParser::OnStopRequest(nsIChannel* channel, nsISupports* aContext, mParserFilter->Finish(); mParserContext->mScanner->SetIncremental(PR_FALSE); - result=ResumeParse(nsnull, PR_TRUE); + result=ResumeParse(PR_TRUE,PR_TRUE); // If the parser isn't enabled, we don't finish parsing till // it is reenabled. @@ -1575,6 +1609,7 @@ nsresult nsParser::OnStopRequest(nsIChannel* channel, nsISupports* aContext, if(gOutFile){ gOutFile->close(); delete gOutFile; + gOutFile=0; } #endif diff --git a/parser/htmlparser/src/nsParser.h b/parser/htmlparser/src/nsParser.h index c3a7aafea997..33a46c606c05 100644 --- a/parser/htmlparser/src/nsParser.h +++ b/parser/htmlparser/src/nsParser.h @@ -239,7 +239,7 @@ CLASS_EXPORT_HTMLPARS nsParser : public nsIParser, public nsIStreamListener { * @update gess5/11/98 * @return TRUE if all went well, otherwise FALSE */ - virtual nsresult ResumeParse(nsIDTD* mDefaultDTD=0, PRBool aIsFinalChunk=PR_FALSE); + virtual nsresult ResumeParse(PRBool allowIteration=PR_TRUE, PRBool aIsFinalChunk=PR_FALSE); void DebugDumpSource(nsOutputStream& anOutput); @@ -301,7 +301,7 @@ protected: * @param * @return */ - nsresult WillBuildModel(nsString& aFilename,nsIDTD* mDefaultDTD=0); + nsresult WillBuildModel(nsString& aFilename); /** *