/* -*- 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 static const char* kFoolMsg = "Error: Some fool overwrote the shared buffer."; //---------------------------------------------------------------------------------------- /** * * @update gess10/30/98 * @param * @return */ char* GetSharedEmptyBuffer() { static char* gCommonEmptyBuffer=0; if(!gCommonEmptyBuffer) { const size_t theDfltSize=25; gCommonEmptyBuffer=new char[theDfltSize]; if(gCommonEmptyBuffer){ nsCRT::zero(gCommonEmptyBuffer,theDfltSize); gCommonEmptyBuffer[0]=0; } else { printf("%s\n","Memory allocation error!"); } } return gCommonEmptyBuffer; } /** * * @update gess10/30/98 * @param * @return */ void nsStr::Initialize(nsStr& aDest,eCharSize aCharSize) { aDest.mStr=GetSharedEmptyBuffer(); aDest.mLength=0; aDest.mCapacity=0; aDest.mMultibyte=aCharSize; aDest.mOwnsBuffer=0; NS_ASSERTION(aDest.mStr[0]==0,kFoolMsg); } /** * * @update gess10/30/98 * @param * @return */ nsIMemoryAgent* GetDefaultAgent(void){ static nsIMemoryAgent* gDefaultAgent=0; if(!gDefaultAgent) gDefaultAgent=new nsMemoryAgent(); NS_ASSERTION(gDefaultAgent,"You MUST always have an allocator!"); return gDefaultAgent; } /** * * @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."); } } } /** * * @update gess11/12/98 * @param * @return */ PRUnichar nsStr::GetCharAt(const nsStr& aDest,PRUint32 anIndex) { PRUnichar result=0; if((anIndex>=0) && (anIndexaString.mCapacity) { nsIMemoryAgent* theAgent=(anAgent) ? anAgent : GetDefaultAgent(); theAgent->Realloc(aString,aNewLength); AddNullTerminator(aString); } } /** * 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,(eCharSize)aDest.mMultibyte); nsIMemoryAgent* theAgent=(anAgent) ? anAgent : GetDefaultAgent(); EnsureCapacity(theTempStr,aNewLength,theAgent); if(0Free(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; } } /** * 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){ 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 gess 04/04/99 * @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.mMultibyte][aDest.mMultibyte])(aDest.mStr,aDest.mLength,aSource.mStr,anOffset,theLength); aDest.mLength+=theLength; AddNullTerminator(aDest); } } } /** * 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) && (aTarget.mLength>0)){ PRInt32 theNewStartPos=-1; PRUnichar theFirstTargetChar=nsStr::GetCharAt(aTarget,0); PRUnichar theLastTargetChar=nsStr::GetCharAt(aTarget,aTarget.mLength-1); PRInt32 theTargetMax=aTarget.mLength; while(++index<=theMax) { PRInt32 theSubIndex=-1; PRBool matches=PR_TRUE; while((++theSubIndex0) { if(theFirstTargetChar==theChar){ PRUnichar theDestJumpChar=nsStr::GetCharAt(aDest,index+theTargetMax); if(theDestJumpChar==theLastTargetChar) { theNewStartPos=index; //this lets us jump ahead during our search where possible. }//if }//if }//if PRUnichar theTargetChar=nsStr::GetCharAt(aTarget,theSubIndex); matches=PRBool(theChar==theTargetChar); } if(matches) return index; if(-10) && (aTarget.mLength>0)){ PRInt32 theNewStartPos=-1; PRUnichar theFirstTargetChar=nsStr::GetCharAt(aTarget,0); PRUnichar theLastTargetChar=nsStr::GetCharAt(aTarget,aTarget.mLength-1); PRInt32 theTargetMax=aTarget.mLength; while(index--) { PRInt32 theSubIndex=-1; PRBool matches=PR_TRUE; if(anOffset+aTarget.mLength<=aDest.mLength) { while((++theSubIndex0) { if(theFirstTargetChar==theChar){ PRUnichar theDestJumpChar=nsStr::GetCharAt(aDest,index+theTargetMax); if(theDestJumpChar==theLastTargetChar) { theNewStartPos=index; //this lets us jump ahead during our search where possible. }//if }//if }//if PRUnichar theTargetChar=nsStr::GetCharAt(aTarget,theSubIndex); matches=PRBool(theChar==theTargetChar); } //while } //if if(matches) return index; if(-1=0) { PRUnichar theChar=GetCharAt(aDest,PRUint32(offset)); thePos=gRFindChars[aSet.mMultibyte](aSet.mStr,aSet.mLength,0,theChar,aIgnoreCase); if(kNotFound!=thePos) return offset; } //while return kNotFound; } /** * * @update gess11/12/98 * @param * @return aDestaSource=1 */ PRInt32 nsStr::Compare(const nsStr& aDest,const nsStr& aSource,PRInt32 /*aCount*/,PRBool aIgnoreCase) { int minlen=(aSource.mLength