Too many bugs to mention; tables, skipped content; perf; memory

This commit is contained in:
rickg%netscape.com 1998-08-21 02:04:39 +00:00
Родитель c1d7662228
Коммит d69ea1fb89
8 изменённых файлов: 356 добавлений и 188 удалений

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

@ -217,6 +217,20 @@ eHTMLTags CTagStack::Last() const {
return eHTMLTag_unknown;
}
/**************************************************************
Now define the token deallocator class...
**************************************************************/
class CNavTokenDeallocator: public nsDequeFunctor{
public:
virtual void* operator()(void* anObject) {
CToken* aToken = (CToken*)anObject;
delete aToken;
return 0;
}
};
static CNavTokenDeallocator gTokenKiller;
/**************************************************************
Now define the tokenrecycler class...
**************************************************************/
@ -230,7 +244,7 @@ eHTMLTags CTagStack::Last() const {
class nsCTokenRecycler : public nsITokenRecycler {
public:
enum {eCacheMaxSize=100};
// enum {eCacheMaxSize=100};
nsCTokenRecycler();
virtual ~nsCTokenRecycler();
@ -238,9 +252,8 @@ public:
virtual CToken* CreateTokenOfType(eHTMLTokenTypes aType,eHTMLTags aTag, const nsString& aString);
protected:
CToken* mTokenCache[eToken_last-1][eCacheMaxSize];
PRInt32 mCount[eToken_last-1];
PRInt32 mTotals[eToken_last-1];
nsDeque* mTokenCache[eToken_last-1];
// PRInt32 mTotals[eToken_last-1];
};
@ -250,9 +263,11 @@ protected:
* @param
*/
nsCTokenRecycler::nsCTokenRecycler() : nsITokenRecycler() {
nsCRT::zero(mTokenCache,sizeof(mTokenCache));
nsCRT::zero(mCount,sizeof(mCount));
nsCRT::zero(mTotals,sizeof(mTotals));
int i=0;
for(i=0;i<eToken_last-1;i++) {
mTokenCache[i]=new nsDeque(gTokenKiller);
// mTotals[i]=0;
}
}
/**
@ -260,13 +275,11 @@ nsCTokenRecycler::nsCTokenRecycler() : nsITokenRecycler() {
* @update gess7/25/98
*/
nsCTokenRecycler::~nsCTokenRecycler() {
//begin by deleting all the known (recycled tokens)...
int index1,index2;
for(index1=0;index1<eToken_last-1;index1++){
for(index2=0;index2<mCount[index1];index2++){
if(mTokenCache[index1][index2])
delete mTokenCache[index1][index2];
}
//begin by deleting all the known (recycled) tokens...
//We're also deleting the cache-deques themselves.
int i;
for(i=0;i<eToken_last-1;i++) {
delete mTokenCache[i];
}
}
@ -280,15 +293,7 @@ nsCTokenRecycler::~nsCTokenRecycler() {
void nsCTokenRecycler::RecycleToken(CToken* aToken) {
if(aToken) {
PRInt32 theType=aToken->GetTokenType();
if(mCount[theType-1]<eCacheMaxSize) {
mTokenCache[theType-1][mCount[theType-1]]=aToken;
mCount[theType-1]++;
} else {
//this is an overflow condition. More tokens of a given
//type have been created than we can store in our recycler.
//In this case, just destroy the extra token.
delete aToken;
}
mTokenCache[theType-1]->Push(aToken);
}
}
@ -301,17 +306,13 @@ void nsCTokenRecycler::RecycleToken(CToken* aToken) {
*/
CToken* nsCTokenRecycler::CreateTokenOfType(eHTMLTokenTypes aType,eHTMLTags aTag, const nsString& aString) {
CToken* result;
CToken* result=(CToken*)mTokenCache[aType-1]->Pop();
if(0<mCount[aType-1]) {
int cnt=CToken::GetTokenCount();
result=mTokenCache[aType-1][mCount[aType-1]-1];
if(result) {
result->Reinitialize(aTag,aString);
mTokenCache[aType-1][mCount[aType-1]-1]=0;
mCount[aType-1]--;
}
else {
mTotals[aType-1]++;
// mTotals[aType-1]++;
switch(aType){
case eToken_start: result=new CStartToken(aTag); break;
case eToken_end: result=new CEndToken(aTag); break;
@ -465,17 +466,6 @@ void CNavDTD::InitializeDefaultTokenHandlers() {
}
class CNavTokenDeallocator: public nsDequeFunctor{
public:
virtual void* operator()(void* anObject) {
CToken* aToken = (CToken*)anObject;
delete aToken;
return 0;
}
};
static CNavTokenDeallocator gTokenKiller;
/**
* Default constructor
*
@ -530,7 +520,7 @@ nsresult CNavDTD::CreateNewInstance(nsIDTD** aInstancePtrResult){
* @return
*/
nsITokenRecycler* CNavDTD::GetTokenRecycler(void){
return 0;
// return 0;
return &gTokenRecycler;
}
@ -704,12 +694,14 @@ nsresult CNavDTD::HandleToken(CToken* aToken){
nsresult CNavDTD::HandleDefaultStartToken(CToken* aToken,eHTMLTags aChildTag,nsIParserNode& aNode) {
NS_PRECONDITION(0!=aToken,kNullToken);
eHTMLTags parentTag=GetTopNode();
nsresult result=NS_OK;
PRBool contains=CanContain(parentTag,aChildTag);
eHTMLTags theParentTag=GetTopNode();
nsresult result=NS_OK;
PRBool contains=CanContain(theParentTag,aChildTag);
if(PR_FALSE==contains){
result=CreateContextStackFor(aChildTag);
if(CanPropagate(theParentTag,aChildTag))
result=CreateContextStackFor(aChildTag);
else result=kCantPropagate;
if(NS_OK!=result) {
//if you're here, then the new topmost container can't contain aToken.
//You must determine what container hierarchy you need to hold aToken,
@ -1687,6 +1679,29 @@ PRBool CNavDTD::CanContain(PRInt32 aParent,PRInt32 aChild) const {
return result;
}
/**
* This method is called to determine whether or not
* the necessary intermediate tags should be propagated
* between the given parent and given child.
*
* @update gess 4/8/98
* @param aParent -- tag enum of parent container
* @param aChild -- tag enum of child container
* @return PR_TRUE if propagation should occur
*/
PRBool CNavDTD::CanPropagate(eHTMLTags aParent,eHTMLTags aChild) const {
PRBool result=PR_TRUE;
switch(aParent) {
case eHTMLTag_td:
result=CanContain(aParent,aChild);
break;
default:
break;
}//switch
return result;
}
/**
* This method is called to determine whether or not a tag
@ -2182,18 +2197,43 @@ PRBool CNavDTD::IsGatedFromClosing(eHTMLTags aChildTag) const {
case eHTMLTag_td:
case eHTMLTag_tr:
theGatePos=GetTopmostIndexOf(gTableTags);
{
/***************************************************************************
* This code may seem confusing, so let me explain it.
* We're trying to handle the case where a child tag may be prevented from
* closing a tag already on the stack. Here's a case:
*
* <table>
* <tr>
* <td>
* <table>
* </tr>
*
* In this case, the bottom </tr> is "gated" from closing the bottommost
* table.
*
* HOW THIS CODE WORKS:
*
* This block of code compares all the members of the default parent
* hierarchy for the childtag against the open containers on our stack.
* If they ever match, then the given child should be gated.
***************************************************************************/
int theIndex;
int theTopIndex=mContextStack.mCount-1;
eHTMLTags theParent=GetDefaultParentTagFor(aChildTag);
while(eHTMLTag_unknown!=theParent) {
for(theIndex=theTopIndex;theIndex>tagPos;theIndex--){
if(mContextStack.mTags[theIndex]==theParent){
theGatePos=theIndex;
break;
}
}
theParent=GetDefaultParentTagFor(theParent);
}
}
break;
/*
eHTMLTag_table
eHTMLTag_tbody
eHTMLTag_thead
eHTMLTag_tfoot
eHTMLTag_caption
eHTMLTag_col
eHTMLTag_colgroup
*/
default:
break;
@ -2809,11 +2849,12 @@ nsresult CNavDTD::CreateContextStackFor(eHTMLTags aChildTag){
//now, build up the stack according to the tags
//you have that aren't in the stack...
static CStartToken theToken(gEmpty);
if(PR_TRUE==bResult){
while(kPropagationStack.mCount>0) {
eHTMLTags theTag=kPropagationStack.Pop();
CToken* theToken=gTokenRecycler.CreateTokenOfType(eToken_start,theTag,gEmpty);
HandleStartToken(theToken);
theToken.SetTypeID(theTag); //open the container...
HandleStartToken(&theToken);
}
result=NS_OK;
}

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

@ -306,6 +306,17 @@ CLASS_EXPORT_HTMLPARS CNavDTD : public nsIDTD {
*/
virtual PRBool CanContain(PRInt32 aParent,PRInt32 aChild) const;
/**
* This method is called to determine whether or not a tag
* of one type can contain a tag of another type.
*
* @update gess 3/25/98
* @param aParent -- int tag of parent container
* @param aChild -- int tag of child container
* @return PR_TRUE if parent can contain child
*/
virtual PRBool CanPropagate(eHTMLTags aParent,eHTMLTags aChild) const;
/**
* This method is called to determine whether a tag
* of one of its children can contain a given child tag.

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

@ -1154,33 +1154,67 @@ PRInt32 CSkippedContentToken::GetTokenType(void) {
return eToken_skippedcontent;
}
/*
* Consume content until you find an end sequence that matches
/*
* Consume content until you find an end sequence that matches
* this objects current mTextValue. Note that this is complicated
* by the fact that you can be parsing content that itself
* contains quoted content of the same type (like <SCRIPT>).
* That means we have to look for quote-pairs, and ignore the
* content inside them.
*
* @update gess 7/25/98
* @param aScanner -- controller of underlying input source
* @return error result
*/
nsresult CSkippedContentToken::Consume(PRUnichar,CScanner& aScanner) {
PRBool done=PR_FALSE;
PRInt32 result=kNoError;
nsString temp;
* content inside them.
*
* @update gess 7/25/98
* @param aScanner -- controller of underlying input source
* @return error result
*/
nsresult CSkippedContentToken::Consume(PRUnichar aChar,CScanner& aScanner) {
PRBool done=PR_FALSE;
PRInt32 result=kNoError;
nsString temp;
while((!done) && (kNoError==result)) {
static nsAutoString terminals(">");
result=aScanner.ReadUntil(temp,terminals,PR_TRUE);
done=PRBool(kNotFound!=temp.RFind(mTextValue,PR_TRUE));
}
int len=temp.Length();
temp.Truncate(len-mTextValue.Length());
mTextKey=temp;
return result;
}
//We're going to try a new algorithm here. Rather than scan for the matching
//end tag like we used to do, we're now going to scan for whitespace and comments.
//If we find either, just eat them. If we find text or a tag, then go to the
//target endtag, or the start of another comment.
static nsAutoString kEndTerminal(">");
static nsAutoString kStartTerminal("<");
while((!done) && (kNoError==result)) {
result=aScanner.GetChar(aChar);
if((kNoError==result) && (kLessThan==aChar)) {
//we're reading a tag or a comment...
temp+=aChar;
result=aScanner.GetChar(aChar);
if((kNoError==result) && (kExclamation==aChar)) {
//read a comment...
static CCommentToken theComment;
result=theComment.Consume(aChar,aScanner);
if(kNoError==result) {
temp.Append(theComment.GetStringValueXXX());
}
} else {
//read a tag...
temp+=aChar;
result=aScanner.ReadUntil(temp,kEndTerminal,PR_TRUE);
}
}
else if(0<=gWhitespace.Find(aChar)) {
static CWhitespaceToken theWS;
result=theWS.Consume(aChar,aScanner);
if(kNoError==result) {
temp.Append(theWS.GetStringValueXXX());
}
}
else {
temp+=aChar;
result=aScanner.ReadUntil(temp,kStartTerminal,PR_FALSE);
}
done=PRBool(kNotFound!=temp.RFind(mTextValue,PR_TRUE));
}
int len=temp.Length();
temp.Truncate(len-mTextValue.Length());
mTextKey=temp;
return result;
}
/**

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

@ -395,10 +395,8 @@ PRInt32 nsParser::DidBuildModel(PRInt32 anErrorCode) {
if(mParserContext->mDTD) {
result=mParserContext->mDTD->DidBuildModel(anErrorCode,PRBool(0==mParserContext->mPrevContext));
//Now it's time to recycle our used tokens.
//The current context has a deque full of them,
//and the ones that preceed currentpos are no
//longer needed. Let's recycle them.
//Now recycle any tokens that are still hanging around.
//Come to think of it, there really shouldn't be any.
nsDeque& theDeque=mParserContext->mTokenDeque;
nsITokenRecycler* theRecycler=mParserContext->mDTD->GetTokenRecycler();
if(theRecycler) {
@ -588,25 +586,25 @@ PRInt32 nsParser::BuildModel() {
theRootDTD->Verify(kEmptyString);
}
if(kInterrupted==result) {
*mParserContext->mCurrentPos=theMarkPos;
//Now it's time to recycle our used tokens.
//The current context has a deque full of them,
//and the ones that preceed currentpos are no
//longer needed. Let's recycle them.
nsITokenRecycler* theRecycler=theRootDTD->GetTokenRecycler();
if(theRecycler) {
nsDeque& theDeque=mParserContext->mTokenDeque;
CToken* theCurrentToken=(CToken*)mParserContext->mCurrentPos->GetCurrent();
nsITokenRecycler* theRecycler=theRootDTD->GetTokenRecycler();
if(theRecycler) {
nsDeque& theDeque=mParserContext->mTokenDeque;
CToken* theCurrentToken=(CToken*)mParserContext->mCurrentPos->GetCurrent();
for(;;) {
CToken* theToken=(CToken*)theDeque.Peek();
while(theToken && (theToken!=theCurrentToken)) {
if(theToken && (theToken!=theCurrentToken)){
theDeque.Pop();
theRecycler->RecycleToken(theToken);
}
else break;
}
mParserContext->mCurrentPos->First();
}
return result;
}

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

@ -217,6 +217,20 @@ eHTMLTags CTagStack::Last() const {
return eHTMLTag_unknown;
}
/**************************************************************
Now define the token deallocator class...
**************************************************************/
class CNavTokenDeallocator: public nsDequeFunctor{
public:
virtual void* operator()(void* anObject) {
CToken* aToken = (CToken*)anObject;
delete aToken;
return 0;
}
};
static CNavTokenDeallocator gTokenKiller;
/**************************************************************
Now define the tokenrecycler class...
**************************************************************/
@ -230,7 +244,7 @@ eHTMLTags CTagStack::Last() const {
class nsCTokenRecycler : public nsITokenRecycler {
public:
enum {eCacheMaxSize=100};
// enum {eCacheMaxSize=100};
nsCTokenRecycler();
virtual ~nsCTokenRecycler();
@ -238,9 +252,8 @@ public:
virtual CToken* CreateTokenOfType(eHTMLTokenTypes aType,eHTMLTags aTag, const nsString& aString);
protected:
CToken* mTokenCache[eToken_last-1][eCacheMaxSize];
PRInt32 mCount[eToken_last-1];
PRInt32 mTotals[eToken_last-1];
nsDeque* mTokenCache[eToken_last-1];
// PRInt32 mTotals[eToken_last-1];
};
@ -250,9 +263,11 @@ protected:
* @param
*/
nsCTokenRecycler::nsCTokenRecycler() : nsITokenRecycler() {
nsCRT::zero(mTokenCache,sizeof(mTokenCache));
nsCRT::zero(mCount,sizeof(mCount));
nsCRT::zero(mTotals,sizeof(mTotals));
int i=0;
for(i=0;i<eToken_last-1;i++) {
mTokenCache[i]=new nsDeque(gTokenKiller);
// mTotals[i]=0;
}
}
/**
@ -260,13 +275,11 @@ nsCTokenRecycler::nsCTokenRecycler() : nsITokenRecycler() {
* @update gess7/25/98
*/
nsCTokenRecycler::~nsCTokenRecycler() {
//begin by deleting all the known (recycled tokens)...
int index1,index2;
for(index1=0;index1<eToken_last-1;index1++){
for(index2=0;index2<mCount[index1];index2++){
if(mTokenCache[index1][index2])
delete mTokenCache[index1][index2];
}
//begin by deleting all the known (recycled) tokens...
//We're also deleting the cache-deques themselves.
int i;
for(i=0;i<eToken_last-1;i++) {
delete mTokenCache[i];
}
}
@ -280,15 +293,7 @@ nsCTokenRecycler::~nsCTokenRecycler() {
void nsCTokenRecycler::RecycleToken(CToken* aToken) {
if(aToken) {
PRInt32 theType=aToken->GetTokenType();
if(mCount[theType-1]<eCacheMaxSize) {
mTokenCache[theType-1][mCount[theType-1]]=aToken;
mCount[theType-1]++;
} else {
//this is an overflow condition. More tokens of a given
//type have been created than we can store in our recycler.
//In this case, just destroy the extra token.
delete aToken;
}
mTokenCache[theType-1]->Push(aToken);
}
}
@ -301,17 +306,13 @@ void nsCTokenRecycler::RecycleToken(CToken* aToken) {
*/
CToken* nsCTokenRecycler::CreateTokenOfType(eHTMLTokenTypes aType,eHTMLTags aTag, const nsString& aString) {
CToken* result;
CToken* result=(CToken*)mTokenCache[aType-1]->Pop();
if(0<mCount[aType-1]) {
int cnt=CToken::GetTokenCount();
result=mTokenCache[aType-1][mCount[aType-1]-1];
if(result) {
result->Reinitialize(aTag,aString);
mTokenCache[aType-1][mCount[aType-1]-1]=0;
mCount[aType-1]--;
}
else {
mTotals[aType-1]++;
// mTotals[aType-1]++;
switch(aType){
case eToken_start: result=new CStartToken(aTag); break;
case eToken_end: result=new CEndToken(aTag); break;
@ -465,17 +466,6 @@ void CNavDTD::InitializeDefaultTokenHandlers() {
}
class CNavTokenDeallocator: public nsDequeFunctor{
public:
virtual void* operator()(void* anObject) {
CToken* aToken = (CToken*)anObject;
delete aToken;
return 0;
}
};
static CNavTokenDeallocator gTokenKiller;
/**
* Default constructor
*
@ -530,7 +520,7 @@ nsresult CNavDTD::CreateNewInstance(nsIDTD** aInstancePtrResult){
* @return
*/
nsITokenRecycler* CNavDTD::GetTokenRecycler(void){
return 0;
// return 0;
return &gTokenRecycler;
}
@ -704,12 +694,14 @@ nsresult CNavDTD::HandleToken(CToken* aToken){
nsresult CNavDTD::HandleDefaultStartToken(CToken* aToken,eHTMLTags aChildTag,nsIParserNode& aNode) {
NS_PRECONDITION(0!=aToken,kNullToken);
eHTMLTags parentTag=GetTopNode();
nsresult result=NS_OK;
PRBool contains=CanContain(parentTag,aChildTag);
eHTMLTags theParentTag=GetTopNode();
nsresult result=NS_OK;
PRBool contains=CanContain(theParentTag,aChildTag);
if(PR_FALSE==contains){
result=CreateContextStackFor(aChildTag);
if(CanPropagate(theParentTag,aChildTag))
result=CreateContextStackFor(aChildTag);
else result=kCantPropagate;
if(NS_OK!=result) {
//if you're here, then the new topmost container can't contain aToken.
//You must determine what container hierarchy you need to hold aToken,
@ -1687,6 +1679,29 @@ PRBool CNavDTD::CanContain(PRInt32 aParent,PRInt32 aChild) const {
return result;
}
/**
* This method is called to determine whether or not
* the necessary intermediate tags should be propagated
* between the given parent and given child.
*
* @update gess 4/8/98
* @param aParent -- tag enum of parent container
* @param aChild -- tag enum of child container
* @return PR_TRUE if propagation should occur
*/
PRBool CNavDTD::CanPropagate(eHTMLTags aParent,eHTMLTags aChild) const {
PRBool result=PR_TRUE;
switch(aParent) {
case eHTMLTag_td:
result=CanContain(aParent,aChild);
break;
default:
break;
}//switch
return result;
}
/**
* This method is called to determine whether or not a tag
@ -2182,18 +2197,43 @@ PRBool CNavDTD::IsGatedFromClosing(eHTMLTags aChildTag) const {
case eHTMLTag_td:
case eHTMLTag_tr:
theGatePos=GetTopmostIndexOf(gTableTags);
{
/***************************************************************************
* This code may seem confusing, so let me explain it.
* We're trying to handle the case where a child tag may be prevented from
* closing a tag already on the stack. Here's a case:
*
* <table>
* <tr>
* <td>
* <table>
* </tr>
*
* In this case, the bottom </tr> is "gated" from closing the bottommost
* table.
*
* HOW THIS CODE WORKS:
*
* This block of code compares all the members of the default parent
* hierarchy for the childtag against the open containers on our stack.
* If they ever match, then the given child should be gated.
***************************************************************************/
int theIndex;
int theTopIndex=mContextStack.mCount-1;
eHTMLTags theParent=GetDefaultParentTagFor(aChildTag);
while(eHTMLTag_unknown!=theParent) {
for(theIndex=theTopIndex;theIndex>tagPos;theIndex--){
if(mContextStack.mTags[theIndex]==theParent){
theGatePos=theIndex;
break;
}
}
theParent=GetDefaultParentTagFor(theParent);
}
}
break;
/*
eHTMLTag_table
eHTMLTag_tbody
eHTMLTag_thead
eHTMLTag_tfoot
eHTMLTag_caption
eHTMLTag_col
eHTMLTag_colgroup
*/
default:
break;
@ -2809,11 +2849,12 @@ nsresult CNavDTD::CreateContextStackFor(eHTMLTags aChildTag){
//now, build up the stack according to the tags
//you have that aren't in the stack...
static CStartToken theToken(gEmpty);
if(PR_TRUE==bResult){
while(kPropagationStack.mCount>0) {
eHTMLTags theTag=kPropagationStack.Pop();
CToken* theToken=gTokenRecycler.CreateTokenOfType(eToken_start,theTag,gEmpty);
HandleStartToken(theToken);
theToken.SetTypeID(theTag); //open the container...
HandleStartToken(&theToken);
}
result=NS_OK;
}

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

@ -306,6 +306,17 @@ CLASS_EXPORT_HTMLPARS CNavDTD : public nsIDTD {
*/
virtual PRBool CanContain(PRInt32 aParent,PRInt32 aChild) const;
/**
* This method is called to determine whether or not a tag
* of one type can contain a tag of another type.
*
* @update gess 3/25/98
* @param aParent -- int tag of parent container
* @param aChild -- int tag of child container
* @return PR_TRUE if parent can contain child
*/
virtual PRBool CanPropagate(eHTMLTags aParent,eHTMLTags aChild) const;
/**
* This method is called to determine whether a tag
* of one of its children can contain a given child tag.

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

@ -1154,33 +1154,67 @@ PRInt32 CSkippedContentToken::GetTokenType(void) {
return eToken_skippedcontent;
}
/*
* Consume content until you find an end sequence that matches
/*
* Consume content until you find an end sequence that matches
* this objects current mTextValue. Note that this is complicated
* by the fact that you can be parsing content that itself
* contains quoted content of the same type (like <SCRIPT>).
* That means we have to look for quote-pairs, and ignore the
* content inside them.
*
* @update gess 7/25/98
* @param aScanner -- controller of underlying input source
* @return error result
*/
nsresult CSkippedContentToken::Consume(PRUnichar,CScanner& aScanner) {
PRBool done=PR_FALSE;
PRInt32 result=kNoError;
nsString temp;
* content inside them.
*
* @update gess 7/25/98
* @param aScanner -- controller of underlying input source
* @return error result
*/
nsresult CSkippedContentToken::Consume(PRUnichar aChar,CScanner& aScanner) {
PRBool done=PR_FALSE;
PRInt32 result=kNoError;
nsString temp;
while((!done) && (kNoError==result)) {
static nsAutoString terminals(">");
result=aScanner.ReadUntil(temp,terminals,PR_TRUE);
done=PRBool(kNotFound!=temp.RFind(mTextValue,PR_TRUE));
}
int len=temp.Length();
temp.Truncate(len-mTextValue.Length());
mTextKey=temp;
return result;
}
//We're going to try a new algorithm here. Rather than scan for the matching
//end tag like we used to do, we're now going to scan for whitespace and comments.
//If we find either, just eat them. If we find text or a tag, then go to the
//target endtag, or the start of another comment.
static nsAutoString kEndTerminal(">");
static nsAutoString kStartTerminal("<");
while((!done) && (kNoError==result)) {
result=aScanner.GetChar(aChar);
if((kNoError==result) && (kLessThan==aChar)) {
//we're reading a tag or a comment...
temp+=aChar;
result=aScanner.GetChar(aChar);
if((kNoError==result) && (kExclamation==aChar)) {
//read a comment...
static CCommentToken theComment;
result=theComment.Consume(aChar,aScanner);
if(kNoError==result) {
temp.Append(theComment.GetStringValueXXX());
}
} else {
//read a tag...
temp+=aChar;
result=aScanner.ReadUntil(temp,kEndTerminal,PR_TRUE);
}
}
else if(0<=gWhitespace.Find(aChar)) {
static CWhitespaceToken theWS;
result=theWS.Consume(aChar,aScanner);
if(kNoError==result) {
temp.Append(theWS.GetStringValueXXX());
}
}
else {
temp+=aChar;
result=aScanner.ReadUntil(temp,kStartTerminal,PR_FALSE);
}
done=PRBool(kNotFound!=temp.RFind(mTextValue,PR_TRUE));
}
int len=temp.Length();
temp.Truncate(len-mTextValue.Length());
mTextKey=temp;
return result;
}
/**

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

@ -395,10 +395,8 @@ PRInt32 nsParser::DidBuildModel(PRInt32 anErrorCode) {
if(mParserContext->mDTD) {
result=mParserContext->mDTD->DidBuildModel(anErrorCode,PRBool(0==mParserContext->mPrevContext));
//Now it's time to recycle our used tokens.
//The current context has a deque full of them,
//and the ones that preceed currentpos are no
//longer needed. Let's recycle them.
//Now recycle any tokens that are still hanging around.
//Come to think of it, there really shouldn't be any.
nsDeque& theDeque=mParserContext->mTokenDeque;
nsITokenRecycler* theRecycler=mParserContext->mDTD->GetTokenRecycler();
if(theRecycler) {
@ -588,25 +586,25 @@ PRInt32 nsParser::BuildModel() {
theRootDTD->Verify(kEmptyString);
}
if(kInterrupted==result) {
*mParserContext->mCurrentPos=theMarkPos;
//Now it's time to recycle our used tokens.
//The current context has a deque full of them,
//and the ones that preceed currentpos are no
//longer needed. Let's recycle them.
nsITokenRecycler* theRecycler=theRootDTD->GetTokenRecycler();
if(theRecycler) {
nsDeque& theDeque=mParserContext->mTokenDeque;
CToken* theCurrentToken=(CToken*)mParserContext->mCurrentPos->GetCurrent();
nsITokenRecycler* theRecycler=theRootDTD->GetTokenRecycler();
if(theRecycler) {
nsDeque& theDeque=mParserContext->mTokenDeque;
CToken* theCurrentToken=(CToken*)mParserContext->mCurrentPos->GetCurrent();
for(;;) {
CToken* theToken=(CToken*)theDeque.Peek();
while(theToken && (theToken!=theCurrentToken)) {
if(theToken && (theToken!=theCurrentToken)){
theDeque.Pop();
theRecycler->RecycleToken(theToken);
}
else break;
}
mParserContext->mCurrentPos->First();
}
return result;
}