/* -*- 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. */ /****************************************************************************************** MODULE NOTES: This file contains the nsStr data structure. This general purpose buffer management class is used as the basis for our strings. It's benefits include: 1. An efficient set of library style functions for manipulating nsStrs 2. Support for 1 and 2 byte character strings (which can easily be increased to n) 3. Unicode awareness and interoperability. *******************************************************************************************/ #include "nsStr.h" #include "bufferRoutines.h" #include "stdio.h" //only used for printf #include "nsCRT.h" #include "nsDeque.h" static const char* kFoolMsg = "Error: Some fool overwrote the shared buffer."; //---------------------------------------------------------------------------------------- // The following is a memory agent who knows how to recycled (pool) freed memory... //---------------------------------------------------------------------------------------- /************************************************************** Define the char* (pooled) deallocator class... **************************************************************/ /* class nsBufferDeallocator: public nsDequeFunctor{ public: virtual void* operator()(void* anObject) { char* aCString= (char*)anObject; delete [] aCString; return 0; } }; class nsPoolingMemoryAgent : public nsMemoryAgent{ public: nsPoolingMemoryAgent() { memset(mPools,0,sizeof(mPools)); } virtual ~nsPoolingMemoryAgent() { nsBufferDeallocator theDeallocator; int i=0; for(i=0;i<10;i++){ if(mPools[i]){ mPools[i]->ForEach(theDeallocator); //now delete the buffers } delete mPools[i]; mPools[i]=0; } } virtual PRBool Alloc(nsStr& aDest,PRUint32 aCount) { //we're given the acount value in charunits; we have to scale up by the charsize. int theShift=4; PRUint32 theNewCapacity=eDefaultSize; while(theNewCapacityPop(); } if(!aDest.mStr) { //we're given the acount value in charunits; we have to scale up by the charsize. size_t theSize=(theNewCapacity<Push(aDest.mStr); } else delete [] aDest.mStr; //it's too big. Just delete it. } aDest.mStr=0; aDest.mOwnsBuffer=0; return PR_TRUE; } return PR_FALSE; } nsDeque* mPools[16]; }; */ static char* gCommonEmptyBuffer=0; /** * * @update gess10/30/98 * @param * @return */ char* GetSharedEmptyBuffer() { if(!gCommonEmptyBuffer) { const size_t theDfltSize=5; gCommonEmptyBuffer=new char[theDfltSize]; if(gCommonEmptyBuffer){ nsCRT::zero(gCommonEmptyBuffer,theDfltSize); gCommonEmptyBuffer[0]=0; } else { printf("%s\n","Memory allocation error!"); } } return gCommonEmptyBuffer; } /** * This method initializes all the members of the nsStr structure * * @update gess10/30/98 * @param * @return */ void nsStr::Initialize(nsStr& aDest,eCharSize aCharSize) { aDest.mStr=GetSharedEmptyBuffer(); aDest.mLength=0; aDest.mCapacity=0; aDest.mCharSize=aCharSize; aDest.mOwnsBuffer=0; NS_ASSERTION(gCommonEmptyBuffer[0]==0,kFoolMsg); } /** * This method initializes all the members of the nsStr structure * @update gess10/30/98 * @param * @return */ void nsStr::Initialize(nsStr& aDest,char* aCString,PRUint32 aCapacity,PRUint32 aLength,eCharSize aCharSize,PRBool aOwnsBuffer){ aDest.mStr=(aCString) ? aCString : GetSharedEmptyBuffer(); aDest.mLength=aLength; aDest.mCapacity=aCapacity; aDest.mCharSize=aCharSize; aDest.mOwnsBuffer=aOwnsBuffer; NS_ASSERTION(gCommonEmptyBuffer[0]==0,kFoolMsg); } /** * * @update gess10/30/98 * @param * @return */ nsIMemoryAgent* GetDefaultAgent(void){ // static nsPoolingMemoryAgent gDefaultAgent; static nsMemoryAgent gDefaultAgent; return (nsIMemoryAgent*)&gDefaultAgent; } /** * This member destroys the memory buffer owned by an nsStr object (if it actually owns it) * @update gess10/30/98 * @param * @return */ void nsStr::Destroy(nsStr& aDest,nsIMemoryAgent* anAgent) { if((aDest.mStr) && (aDest.mStr!=GetSharedEmptyBuffer())) { if(!anAgent) anAgent=GetDefaultAgent(); if(anAgent) { anAgent->Free(aDest); } else{ printf("%s\n","Leak occured in nsStr."); } } } /** * This method gets called when the internal buffer needs * to grow to a given size. The original contents are not preserved. * @update gess 3/30/98 * @param aNewLength -- new capacity of string in charSize units * @return void */ void nsStr::EnsureCapacity(nsStr& aString,PRUint32 aNewLength,nsIMemoryAgent* anAgent) { if(aNewLength>aString.mCapacity) { nsIMemoryAgent* theAgent=(anAgent) ? anAgent : GetDefaultAgent(); theAgent->Realloc(aString,aNewLength); AddNullTerminator(aString); } NS_ASSERTION(gCommonEmptyBuffer[0]==0,kFoolMsg); } /** * This method gets called when the internal buffer needs * to grow to a given size. The original contents ARE preserved. * @update gess 3/30/98 * @param aNewLength -- new capacity of string in charSize units * @return void */ void nsStr::GrowCapacity(nsStr& aDest,PRUint32 aNewLength,nsIMemoryAgent* anAgent) { if(aNewLength>aDest.mCapacity) { nsStr theTempStr; nsStr::Initialize(theTempStr,aDest.mCharSize); nsIMemoryAgent* theAgent=(anAgent) ? anAgent : GetDefaultAgent(); EnsureCapacity(theTempStr,aNewLength,theAgent); if(aDest.mLength) { Append(theTempStr,aDest,0,aDest.mLength,theAgent); } theAgent->Free(aDest); aDest.mStr = theTempStr.mStr; theTempStr.mStr=0; //make sure to null this out so that you don't lose the buffer you just stole... aDest.mLength=theTempStr.mLength; aDest.mCapacity=theTempStr.mCapacity; aDest.mOwnsBuffer=theTempStr.mOwnsBuffer; } NS_ASSERTION(gCommonEmptyBuffer[0]==0,kFoolMsg); } /** * Replaces the contents of aDest with aSource, up to aCount of chars. * @update gess10/30/98 * @param aDest is the nsStr that gets changed. * @param aSource is where chars are copied from * @param aCount is the number of chars copied from aSource */ void nsStr::Assign(nsStr& aDest,const nsStr& aSource,PRUint32 anOffset,PRInt32 aCount,nsIMemoryAgent* anAgent){ if(&aDest!=&aSource){ Truncate(aDest,0,anAgent); Append(aDest,aSource,anOffset,aCount,anAgent); } } /** * This method appends the given nsStr to this one. Note that we have to * pay attention to the underlying char-size of both structs. * @update gess10/30/98 * @param aDest is the nsStr to be manipulated * @param aSource is where char are copied from * @aCount is the number of bytes to be copied */ void nsStr::Append(nsStr& aDest,const nsStr& aSource,PRUint32 anOffset,PRInt32 aCount,nsIMemoryAgent* anAgent){ if(anOffset aDest.mCapacity) { GrowCapacity(aDest,aDest.mLength+theLength,anAgent); } //now append new chars, starting at offset (*gCopyChars[aSource.mCharSize][aDest.mCharSize])(aDest.mStr,aDest.mLength,aSource.mStr,anOffset,theLength); aDest.mLength+=theLength; } } AddNullTerminator(aDest); NS_ASSERTION(gCommonEmptyBuffer[0]==0,kFoolMsg); } /** * This method inserts up to "aCount" chars from a source nsStr into a dest nsStr. * @update gess10/30/98 * @param aDest is the nsStr that gets changed * @param aDestOffset is where in aDest the insertion is to occur * @param aSource is where chars are copied from * @param aSrcOffset is where in aSource chars are copied from * @param aCount is the number of chars from aSource to be inserted into aDest */ void nsStr::Insert( nsStr& aDest,PRUint32 aDestOffset,const nsStr& aSource,PRUint32 aSrcOffset,PRInt32 aCount,nsIMemoryAgent* anAgent){ //there are a few cases for insert: // 1. You're inserting chars into an empty string (assign) // 2. You're inserting onto the end of a string (append) // 3. You're inserting onto the 1..n-1 pos of a string (the hard case). if(00) && aSet){ PRInt32 theIndex=-1; PRInt32 theMax=aDest.mLength; PRInt32 theSetLen=nsCRT::strlen(aSet); if(aEliminateLeading) { while(++theIndex<=theMax) { PRUnichar theChar=GetCharAt(aDest,theIndex); PRInt32 thePos=gFindChars[eOneByte](aSet,theSetLen,0,theChar,PR_FALSE); if(kNotFound==thePos) break; } if(00) { PRUnichar theChar=GetCharAt(aDest,theIndex); //read at end now... PRInt32 thePos=gFindChars[eOneByte](aSet,theSetLen,0,theChar,PR_FALSE); if(kNotFound=aTarget.mLength) && (aTarget.mLength>0) && (index>=0)){ PRInt32 theTargetMax=aTarget.mLength; while(index<=theMax) { PRInt32 theSubIndex=-1; PRBool matches=PR_TRUE; while((++theSubIndex=aTarget.mLength) && (aTarget.mLength>0) && (index>=0)){ nsStr theCopy; nsStr::Initialize(theCopy,eOneByte); nsStr::Assign(theCopy,aTarget,0,aTarget.mLength,0); if(aIgnoreCase){ nsStr::ChangeCase(theCopy,PR_FALSE); //force to lowercase } PRInt32 theTargetMax=theCopy.mLength; while(index>=0) { PRInt32 theSubIndex=-1; PRBool matches=PR_FALSE; if(index+theCopy.mLength<=aDest.mLength) { matches=PR_TRUE; while((++theSubIndex=0) { PRUnichar theChar=GetCharAt(aDest,offset); thePos=gRFindChars[aSet.mCharSize](aSet.mStr,aSet.mLength,0,theChar,aIgnoreCase); if(kNotFound!=thePos) return offset; } //while return kNotFound; } /** * Compare source and dest strings, up to an (optional max) number of chars * @param aDest is the first str to compare * @param aSource is the second str to compare * @param aCount -- if (-1), then we use length of longer string; if (0aSource=1 */ PRInt32 nsStr::Compare(const nsStr& aDest,const nsStr& aSource,PRInt32 aCount,PRBool aIgnoreCase) { PRInt32 result=0; if(aCount) { PRInt32 minlen=(aSource.mLength1) { mCapacity=aCapacity-1; mLength=(-1==aLength) ? strlen(aString) : aLength; if(mLength>PRInt32(mCapacity)) mLength=mCapacity; } } CSharedStrBuffer::CSharedStrBuffer(PRUnichar* aString,PRBool aStackBased,PRUint32 aCapacity,PRInt32 aLength) { mBuffer=(char*)aString; mCharSize=eTwoByte; mStackBased=aStackBased; mLength=mCapacity=0; if(aString && aCapacity>1) { mCapacity=aCapacity-1; mLength=(-1==aLength) ? nsCRT::strlen(aString) : aLength; if(mLength>PRInt32(mCapacity)) mLength=mCapacity; } } //----------------------------------------------------------------------------------------