/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* * 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. */ #include "nsDTDUtils.h" #include "CNavDTD.h" #include "nsIObserverService.h" #include "nsIServiceManager.h" /*************************************************************** First, define the tagstack class ***************************************************************/ /** * Default constructor * @update harishd 04/04/99 * @update gess 04/22/99 */ nsEntryStack::nsEntryStack() { mCapacity=0; mCount=0; mEntries=0; } /** * Default destructor * @update harishd 04/04/99 * @update gess 04/22/99 */ nsEntryStack::~nsEntryStack() { if(mEntries) delete [] mEntries; mCount=mCapacity=0; mEntries=0; } /** * Resets state of stack to be empty. * @update harishd 04/04/99 */ void nsEntryStack::Empty(void) { mCount=0; } /** * * @update gess 04/22/99 */ void nsEntryStack::Push(eHTMLTags aTag) { if(mCount==mCapacity){ nsTagEntry* temp=new nsTagEntry[mCapacity+=50]; if(temp){ PRUint32 index=0; for(index=0;index=0;theIndex--){ if(aTag==TagAt(theIndex)) return theIndex; } return kNotFound; } /*************************************************************** Now define the dtdcontext class ***************************************************************/ /** * * @update gess9/10/98 */ nsDTDContext::nsDTDContext() : mStack(), mSkipped(0), mStyles(0) { #ifdef NS_DEBUG nsCRT::zero(mTags,sizeof(mTags)); #endif } /** * * @update gess9/10/98 */ nsDTDContext::~nsDTDContext() { } /** * * @update gess7/9/98, harishd 04/04/99 */ PRInt32 nsDTDContext::GetCount(void) { return mStack.GetCount(); } /** * * @update gess7/9/98, harishd 04/04/99 */ void nsDTDContext::Push(eHTMLTags aTag) { #ifdef NS_DEBUG if(mStack.mCount < eMaxTags) mTags[mStack.mCount]=aTag; #endif mStack.Push(aTag); } /** * @update gess7/9/98, harishd 04/04/99 */ eHTMLTags nsDTDContext::Pop() { #ifdef NS_DEBUG if ((mStack.mCount>0) && (mStack.mCount <= eMaxTags)) mTags[mStack.mCount-1]=eHTMLTag_unknown; #endif nsEntryStack* theStyles=0; nsTagEntry& theEntry=mStack.EntryAt(mStack.mCount-1); PRInt32 theIndex=theEntry.mStyleIndex; if(-1Push(aTag); } } /** * * @update gess 04/28/99 */ eHTMLTags nsDTDContext::PopStyle(void){ eHTMLTags result=eHTMLTag_unknown; nsTagEntry& theEntry=mStack.EntryAt(mStack.mCount-1); //ok, now go get the right tokenbank deque... nsEntryStack* theStack=0; if(-1Pop(); } return result; } /** * * @update harishd 04/04/99 * @update gess 04/21/99 */ void nsDTDContext::SaveToken(CToken* aToken, PRInt32 aID) { NS_PRECONDITION(aID <= mStack.GetCount() && aID > -1,"Out of bounds"); if(aToken) { nsTagEntry& theEntry=mStack.EntryAt(aID); //ok, now go get the right tokenbank deque... nsDeque* theDeque=0; if(-1Push(aToken); } } /** * * @update harishd 04/04/99 * @update gess 04/21/99 */ CToken* nsDTDContext::RestoreTokenFrom(PRInt32 aID) { NS_PRECONDITION(aID <= mStack.GetCount() && aID > -1,"Out of bounds"); CToken* result=0; if(0PopFront(); } } return result; } /** * * @update harishd 04/04/99 * @update gess 04/21/99 */ PRInt32 nsDTDContext::TokenCountAt(PRInt32 aID) { NS_PRECONDITION(aID <= mStack.GetCount(),"Out of bounds"); nsTagEntry theEntry=mStack.EntryAt(aID); nsDeque* theDeque=(nsDeque*)mSkipped.ObjectAt(theEntry.mBankIndex); if(theDeque){ return theDeque->GetSize(); } return kNotFound; } /************************************************************** Now define the tokenrecycler class... **************************************************************/ /** * * @update gess7/25/98 * @param */ CTokenRecycler::CTokenRecycler() : nsITokenRecycler() { int i=0; for(i=0;iGetTokenType(); CTokenFinder finder(aToken); CToken* theMatch; theMatch=(CToken*)mTokenCache[theType-1]->FirstThat(finder); mTokenCache[theType-1]->Push(aToken); } } /** * * @update vidur 11/12/98 * @param * @return */ CToken* CTokenRecycler::CreateTokenOfType(eHTMLTokenTypes aType,eHTMLTags aTag, const nsString& aString) { CToken* result=(CToken*)mTokenCache[aType-1]->Pop(); if(result) { result->Reinitialize(aTag,aString); } else { #ifdef NS_DEBUG mTotals[aType-1]++; #endif switch(aType){ case eToken_start: result=new CStartToken(aTag); break; case eToken_end: result=new CEndToken(aTag); break; case eToken_comment: result=new CCommentToken(); break; case eToken_entity: result=new CEntityToken(aString); break; case eToken_whitespace: result=new CWhitespaceToken(); break; case eToken_newline: result=new CNewlineToken(); break; case eToken_text: result=new CTextToken(aString); break; case eToken_attribute: result=new CAttributeToken(); break; case eToken_script: result=new CScriptToken(); break; case eToken_style: result=new CStyleToken(); break; case eToken_skippedcontent: result=new CSkippedContentToken(aString); break; case eToken_instruction: result=new CInstructionToken(); break; case eToken_cdatasection: result=new CCDATASectionToken(); break; case eToken_error: result=new CErrorToken(); break; case eToken_doctypeDecl: result=new CDoctypeDeclToken(); break; case eToken_xmlDecl: result=new CXMLDeclToken(); break; default: break; } } return result; } /** * * @update vidur 11/12/98 * @param * @return */ CToken* CTokenRecycler::CreateTokenOfType(eHTMLTokenTypes aType,eHTMLTags aTag) { CToken* result=(CToken*)mTokenCache[aType-1]->Pop(); static nsAutoString theEmpty; if(result) { result->Reinitialize(aTag,theEmpty); } else { #ifdef NS_DEBUG mTotals[aType-1]++; #endif switch(aType){ case eToken_start: result=new CStartToken(aTag); break; case eToken_end: result=new CEndToken(aTag); break; case eToken_comment: result=new CCommentToken(); break; case eToken_attribute: result=new CAttributeToken(); break; case eToken_entity: result=new CEntityToken(); break; case eToken_whitespace: result=new CWhitespaceToken(); break; case eToken_newline: result=new CNewlineToken(); break; case eToken_text: result=new CTextToken(theEmpty); break; case eToken_script: result=new CScriptToken(); break; case eToken_style: result=new CStyleToken(); break; case eToken_skippedcontent: result=new CSkippedContentToken(theEmpty); break; case eToken_instruction: result=new CInstructionToken(); break; case eToken_cdatasection: result=new CCDATASectionToken(); break; case eToken_error: result=new CErrorToken(); break; case eToken_doctypeDecl: result=new CDoctypeDeclToken(); break; case eToken_xmlDecl: result=new CXMLDeclToken(); break; default: break; } } return result; } void DebugDumpContainmentRules(nsIDTD& theDTD,const char* aFilename,const char* aTitle) { #ifdef RICKG_DEBUG #include const char* prefix=" "; fstream out(aFilename,ios::out); out << "==================================================" << endl; out << aTitle << endl; out << "=================================================="; int i,j=0; int written; for(i=1;i" << endl; out << prefix; written=0; if(theDTD.IsContainer(i)) { for(j=1;j> 24) ^ *data_blk_ptr++ ) & 0xff; crc_accum = ( crc_accum << 8 ) ^ crc_table[i]; } return crc_accum; } /****************************************************************************** This class is used to store ref's to tag observers during the parse phase. Note that for simplicity, this is a singleton that is constructed in the CNavDTD and shared for the duration of the application session. Later on it might be nice to use a more dynamic approach that would permit observers to come and go on a document basis. ******************************************************************************/ CObserverDictionary::CObserverDictionary() { nsCRT::zero(mObservers,sizeof(mObservers)); nsAutoString theHTMLTopic("htmlparser"); RegisterObservers(theHTMLTopic); nsAutoString theXMLTopic("xmlparser"); RegisterObservers(theXMLTopic); } CObserverDictionary::~CObserverDictionary() { UnregisterObservers(); } /************************************************************** Define the nsIElementObserver release class... **************************************************************/ class nsObserverReleaser: public nsDequeFunctor{ public: virtual void* operator()(void* anObject) { nsIElementObserver* theObserver= (nsIElementObserver*)anObject; NS_RELEASE(theObserver); return 0; } }; void CObserverDictionary::UnregisterObservers() { int theIndex=0; nsObserverReleaser theReleaser; for(theIndex=0;theIndex<=NS_HTML_TAG_MAX;theIndex++){ if(mObservers[theIndex]){ //nsIElementObserver* theElementObserver=0; mObservers[theIndex]->ForEach(theReleaser); delete mObservers[theIndex]; } } } void CObserverDictionary::RegisterObservers(nsString& aTopic) { nsresult result = NS_OK; nsIObserverService* theObserverService = nsnull; result = nsServiceManager::GetService(NS_OBSERVERSERVICE_PROGID, nsIObserverService::GetIID(), (nsISupports**) &theObserverService, nsnull); if(result == NS_OK){ nsIEnumerator* theEnum; result = theObserverService->EnumerateObserverList(aTopic.GetUnicode(), &theEnum); if(result == NS_OK){ nsIElementObserver* theElementObserver; nsISupports *inst; for (theEnum->First(); theEnum->IsDone() != NS_OK; theEnum->Next()) { result = theEnum->CurrentItem(&inst); if (NS_SUCCEEDED(result)) result = inst->QueryInterface(nsIElementObserver::GetIID(), (void**)&theElementObserver); if(result == NS_OK) { const char* theTagStr = nsnull; PRUint32 theTagIndex = 0; theTagStr = theElementObserver->GetTagNameAt(theTagIndex); while (theTagStr != nsnull) { // XXX - HACK - Hardcoding PI for simplification. PI handling should not // happen along with ** tags **. For now the specific PI, ?xml, is treated // as an unknown tag in the dictionary!!!! eHTMLTags theTag = (nsCRT::strcmp(theTagStr,"?xml") == 0) ? eHTMLTag_unknown : nsHTMLTags::LookupTag(nsCAutoString(theTagStr)); if((eHTMLTag_userdefined!=theTag) && (theTag <= NS_HTML_TAG_MAX)){ if(mObservers[theTag] == nsnull) { mObservers[theTag] = new nsDeque(0); } NS_ADDREF(theElementObserver); mObservers[theTag]->Push(theElementObserver); } theTagIndex++; theTagStr = theElementObserver->GetTagNameAt(theTagIndex); } } } } } } nsDeque* CObserverDictionary::GetObserversForTag(eHTMLTags aTag) { if(aTag <= NS_HTML_TAG_MAX) return mObservers[aTag]; return nsnull; }