2000-03-03 12:04:50 +03:00
|
|
|
/*************************************************************************************
|
|
|
|
*
|
|
|
|
* MODULES NOTES:
|
|
|
|
*
|
|
|
|
* 1. See nsStringImpl.h
|
|
|
|
*
|
2000-03-09 13:50:02 +03:00
|
|
|
* Contributor(s):
|
|
|
|
* Rick Gessner <rickg@netscape.com>
|
|
|
|
*
|
|
|
|
* History:
|
2000-03-03 12:04:50 +03:00
|
|
|
*
|
|
|
|
* 02.29.2000: Original files (rickg)
|
|
|
|
* 03.02.2000: Flesh out the interface to be compatible with old library (rickg)
|
2000-03-09 13:50:02 +03:00
|
|
|
* 03.03.2000: Finished mapping original nsStr functionality to template form (rickg)
|
2000-03-03 12:04:50 +03:00
|
|
|
*
|
|
|
|
*************************************************************************************/
|
|
|
|
|
|
|
|
#ifndef NS_BUFFERMANAGER_
|
|
|
|
#define NS_BUFFERMANAGER_
|
|
|
|
|
|
|
|
|
|
|
|
#include "nsStringValue.h"
|
|
|
|
#include <string.h>
|
2000-03-09 13:50:02 +03:00
|
|
|
#include "nsCRT.h"
|
2000-03-03 12:04:50 +03:00
|
|
|
|
2000-03-09 13:50:02 +03:00
|
|
|
class nsAReadableString;
|
|
|
|
class nsAReadableStringIterator;
|
2000-03-03 12:04:50 +03:00
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
*
|
|
|
|
* The following (hack) template functions will go away, but for now they
|
|
|
|
* provide basic string copying and appending for my prototype. (rickg)
|
|
|
|
*
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
inline size_t stringlen(const PRUnichar* theString) {
|
|
|
|
const PRUnichar* theEnd=theString;
|
|
|
|
while(*theEnd++); //skip to end of aDest...
|
|
|
|
size_t result=theEnd-theString-1;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline size_t stringlen(const char* theString) {
|
|
|
|
return ::strlen(theString);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <class CharType1,class CharType2>
|
|
|
|
void strncopy(CharType1* aDest,const CharType2* aSource, size_t aLength) {
|
|
|
|
const CharType2* aLast=aSource+aLength;
|
|
|
|
while(aSource<aLast) {
|
|
|
|
*aDest++=(CharType1)*aSource++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class CharType1,class CharType2>
|
|
|
|
void strcatn(CharType1* aDest,const CharType2* aSource, size_t aLength) {
|
|
|
|
while(*aDest++); //skip to end of aDest...
|
|
|
|
strncopy(aDest,aSource,aLength);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************************
|
|
|
|
*
|
|
|
|
* These methods offer the low level buffer manipulation routines used throughout
|
|
|
|
* the string hierarchy. T1 and T2 will be types of stringvalues. (rickg)
|
|
|
|
*
|
|
|
|
*************************************************************************************/
|
|
|
|
|
|
|
|
template <class T1,class T2>
|
|
|
|
inline PRInt32 MinInt(T1 anInt1,T2 anInt2){
|
2000-03-09 13:50:02 +03:00
|
|
|
return (anInt1<(T1)anInt2) ? anInt1 : anInt2;
|
2000-03-03 12:04:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class T1,class T2>
|
|
|
|
inline PRInt32 MaxInt(T1 anInt1,T2 anInt2){
|
2000-03-09 13:50:02 +03:00
|
|
|
return (anInt1<(T1)anInt2) ? anInt2 : anInt1;
|
2000-03-03 12:04:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class CharType>
|
|
|
|
inline void SVAddNullTerminator( nsStringValueImpl<CharType>& aDest) {
|
|
|
|
if(aDest.mBuffer) {
|
|
|
|
aDest.mBuffer[aDest.mLength]=0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static const PRUnichar gCommonEmptyBuffer[1] = {0};
|
|
|
|
static nsresult gStringAcquiredMemory = NS_OK;
|
|
|
|
|
|
|
|
template <class CharType>
|
2000-03-09 13:50:02 +03:00
|
|
|
inline nsresult SVAlloc( nsStringValueImpl<CharType>& aDest, PRUint32 aCount) {
|
|
|
|
|
|
|
|
nsresult result=NS_OK;
|
2000-03-03 12:04:50 +03:00
|
|
|
|
|
|
|
static int mAllocCount=0;
|
|
|
|
mAllocCount++;
|
|
|
|
|
|
|
|
//we're given the acount value in charunits; now scale up to next multiple.
|
2000-03-09 13:50:02 +03:00
|
|
|
aDest.mCapacity=kDefaultStringSize;
|
|
|
|
while(aDest.mCapacity<aCount){
|
|
|
|
aDest.mCapacity<<=1;
|
2000-03-03 12:04:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
aDest.mBuffer = new CharType[1+aDest.mCapacity];
|
|
|
|
|
|
|
|
// PRUint32 theSize=(theNewCapacity<<aDest.mCharSize);
|
|
|
|
// aDest.mBuffer = (char*)nsAllocator::Alloc(theSize);
|
|
|
|
|
|
|
|
if(aDest.mBuffer) {
|
2000-03-09 13:50:02 +03:00
|
|
|
aDest.mBuffer[0]=0;
|
2000-03-03 12:04:50 +03:00
|
|
|
gStringAcquiredMemory=PR_TRUE;
|
|
|
|
}
|
2000-03-09 13:50:02 +03:00
|
|
|
else {
|
|
|
|
gStringAcquiredMemory=PR_FALSE;
|
|
|
|
result=NS_MEMORY_ERROR;
|
|
|
|
}
|
|
|
|
return result;
|
2000-03-03 12:04:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Free memory from given stringvalueimpl
|
|
|
|
*
|
|
|
|
* @update rickg 03.02.2000
|
|
|
|
* @return memory error (usually returns NS_OK)
|
|
|
|
*/
|
|
|
|
template <class CharType>
|
2000-03-09 13:50:02 +03:00
|
|
|
inline nsresult SVFree( nsStringValueImpl<CharType>& aDest){
|
2000-03-03 12:04:50 +03:00
|
|
|
if(aDest.mBuffer){
|
2000-03-09 13:50:02 +03:00
|
|
|
|
|
|
|
delete [] aDest.mBuffer; // nsAllocator::Free(aDest.mBuffer);
|
2000-03-03 12:04:50 +03:00
|
|
|
aDest.mBuffer=0;
|
|
|
|
}
|
2000-03-09 13:50:02 +03:00
|
|
|
return NS_OK;
|
2000-03-03 12:04:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Realloc memory from given stringvalueimpl
|
|
|
|
*
|
|
|
|
* @update rickg 03.02.2000
|
|
|
|
* @return memory error (usually returns NS_OK)
|
|
|
|
*/
|
|
|
|
template <class CharType>
|
2000-03-09 13:50:02 +03:00
|
|
|
inline nsresult SVRealloc(nsStringValueImpl<CharType>&aDest,PRUint32 aCount){
|
2000-03-03 12:04:50 +03:00
|
|
|
|
|
|
|
nsStringValueImpl<CharType> temp(aDest);
|
|
|
|
|
2000-03-09 13:50:02 +03:00
|
|
|
nsresult result=SVAlloc<CharType>(temp,aCount);
|
|
|
|
if(NS_SUCCESS(result)) {
|
|
|
|
SVFree<CharType>(aDest);
|
2000-03-03 12:04:50 +03:00
|
|
|
aDest.mBuffer=temp.mBuffer;
|
|
|
|
aDest.mCapacity=temp.mCapacity;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve last memory error
|
|
|
|
*
|
2000-03-09 13:50:02 +03:00
|
|
|
* @update rickg 03.02.2000
|
2000-03-03 12:04:50 +03:00
|
|
|
* @return memory error (usually returns NS_OK)
|
|
|
|
*/
|
2000-03-09 13:50:02 +03:00
|
|
|
static PRBool DidAcquireMemory(void) {
|
2000-03-03 12:04:50 +03:00
|
|
|
return gStringAcquiredMemory;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This is the low-level buffer copying routine between 2 stringvalues.
|
|
|
|
*
|
2000-03-09 13:50:02 +03:00
|
|
|
* @update rickg 03.01.2000
|
|
|
|
* @param aDest is the destination stringvalue
|
|
|
|
* @param aSource is the source stringvalue (you must account for offset yourself in calling routine)
|
|
|
|
* @param aLength tells us how many chars to copy from aSource
|
|
|
|
*/
|
|
|
|
template <class CharType1,class CharType2>
|
|
|
|
inline nsresult SVCopyBuffer_( CharType1* aDest, const CharType2* aSource, PRInt32 aLength) {
|
|
|
|
|
|
|
|
if(sizeof(CharType1)==sizeof(CharType2)) {
|
|
|
|
memcpy(aDest,aSource,aLength*sizeof(CharType1));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
const CharType2* aLast=aSource+aLength;
|
|
|
|
while(aSource<aLast) {
|
|
|
|
*aDest++=(CharType1)*aSource++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This is the low-level buffer copying routine between 2 stringvalues.
|
|
|
|
*
|
|
|
|
* @update rickg 03.01.2000
|
2000-03-03 12:04:50 +03:00
|
|
|
* @param aDest is the destination stringvalue
|
|
|
|
* @param aSource is the source stringvalue
|
|
|
|
* @param anOffset tells us where in aSource to begin copying from
|
|
|
|
* @param aLength tells us how many chars to copy from aSource
|
|
|
|
*/
|
|
|
|
template <class CharType1,class CharType2>
|
2000-03-09 13:50:02 +03:00
|
|
|
inline nsresult SVCopyBuffer( nsStringValueImpl<CharType1>& aDest,const nsStringValueImpl<CharType2>& aSource,PRInt32 aLength,PRInt32 aSrcOffset) {
|
|
|
|
nsresult result=NS_OK;
|
2000-03-03 12:04:50 +03:00
|
|
|
if((0<aSource.mLength)) {
|
2000-03-09 13:50:02 +03:00
|
|
|
|
|
|
|
CharType1* theDest = aDest.mBuffer;
|
|
|
|
CharType2* theSource= aSource.mBuffer;
|
|
|
|
CharType2* from = theSource+aSrcOffset;
|
|
|
|
|
|
|
|
result=SVCopyBuffer_<CharType1,CharType2>(aDest.mBuffer,aSource.mBuffer,aLength);
|
|
|
|
|
2000-03-03 12:04:50 +03:00
|
|
|
}
|
2000-03-09 13:50:02 +03:00
|
|
|
return result;
|
2000-03-03 12:04:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method destroys the given stringvalue, and *MAY*
|
|
|
|
* deallocate it's memory depending on the setting
|
|
|
|
* of the internal mOwnsBUffer flag.
|
|
|
|
*
|
2000-03-09 13:50:02 +03:00
|
|
|
* @update rickg 03.01.2000
|
2000-03-03 12:04:50 +03:00
|
|
|
* @param aStringValue is the stringvalue to be destroyed
|
|
|
|
*/
|
|
|
|
template <class CharType>
|
2000-03-09 13:50:02 +03:00
|
|
|
inline nsresult SVDestroy(nsStringValueImpl<CharType> &aStringValue) {
|
|
|
|
nsresult result=NS_OK;
|
|
|
|
return result;
|
2000-03-03 12:04:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* These methods are where memory allocation/reallocation occur.
|
|
|
|
*
|
2000-03-09 13:50:02 +03:00
|
|
|
* @update rickg 03.01.2000
|
2000-03-03 12:04:50 +03:00
|
|
|
* @param aString is the stringvalue to be manipulated
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
template <class CharType>
|
2000-03-09 13:50:02 +03:00
|
|
|
inline nsresult SVEnsureCapacity(nsStringValueImpl<CharType>& aString,PRUint32 aNewLength){
|
2000-03-03 12:04:50 +03:00
|
|
|
|
2000-03-09 13:50:02 +03:00
|
|
|
nsresult result=NS_OK;
|
2000-03-03 12:04:50 +03:00
|
|
|
if(aNewLength>aString.mCapacity) {
|
2000-03-09 13:50:02 +03:00
|
|
|
result=SVRealloc< CharType>(aString,aNewLength);
|
2000-03-03 12:04:50 +03:00
|
|
|
SVAddNullTerminator<CharType>(aString);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Attempt to grow the capacity of the given stringvalueimp by given amount
|
|
|
|
* (It's possible the length is already larger, so this can fall out.)
|
|
|
|
*
|
|
|
|
* @update rickg 03.02.2000
|
|
|
|
* @return memory error (usually returns NS_OK)
|
|
|
|
*/
|
|
|
|
template <class CharType>
|
2000-03-09 13:50:02 +03:00
|
|
|
inline nsresult SVGrowCapacity(nsStringValueImpl<CharType>& aDest,PRUint32 aNewLength){
|
|
|
|
nsresult result=NS_OK;
|
2000-03-03 12:04:50 +03:00
|
|
|
if(aNewLength>aDest.mCapacity) {
|
|
|
|
|
|
|
|
nsStringValueImpl<CharType> theTempStr;
|
2000-03-09 13:50:02 +03:00
|
|
|
nsresult result=SVAlloc<CharType>(theTempStr,aNewLength);
|
|
|
|
if(NS_SUCCESS(result)) {
|
2000-03-03 12:04:50 +03:00
|
|
|
|
2000-03-09 13:50:02 +03:00
|
|
|
if(0<aDest.mLength) {
|
|
|
|
result=SVCopyBuffer_<CharType,CharType>(theTempStr.mBuffer,aDest.mBuffer,aDest.mLength);
|
|
|
|
theTempStr.mLength=aDest.mLength;
|
|
|
|
SVAddNullTerminator<CharType>(aDest);
|
|
|
|
}
|
|
|
|
|
|
|
|
result=SVFree<CharType>(aDest);
|
2000-03-03 12:04:50 +03:00
|
|
|
aDest=theTempStr;
|
|
|
|
theTempStr.mBuffer=0; //make sure to null this out so that you don't lose the buffer you just stole...
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method deletes chars from the given str.
|
|
|
|
* The given allocator may choose to resize the str as well.
|
|
|
|
*
|
2000-03-09 13:50:02 +03:00
|
|
|
* @update rickg 03.01.2000
|
2000-03-03 12:04:50 +03:00
|
|
|
* @param aDest is the stringvalue to be modified
|
|
|
|
* @param aDestOffset tells us where in dest to start deleting
|
|
|
|
* @param aCount tells us the (max) # of chars to delete
|
|
|
|
*/
|
|
|
|
template <class CharType>
|
2000-03-09 13:50:02 +03:00
|
|
|
inline nsresult SVDelete( nsStringValueImpl<CharType>& aDest,PRUint32 aDestOffset,PRInt32 aCount){
|
|
|
|
nsresult result=NS_OK;
|
|
|
|
|
|
|
|
if((0<aCount) && (aDestOffset<aDest.mLength)){
|
|
|
|
|
|
|
|
CharType* root=aDest.mBuffer;
|
|
|
|
CharType* dst1=root+aDestOffset;
|
|
|
|
CharType* dst2=dst1+aCount;
|
|
|
|
CharType* end =root+aDest.mLength;
|
|
|
|
CharType* last = (dst2<end) ? dst2 : end;
|
|
|
|
|
|
|
|
if(last<end) {
|
|
|
|
aDest.mLength-=(last-dst1);
|
|
|
|
memmove(dst1,last,(end-last)*sizeof(CharType));
|
|
|
|
}
|
|
|
|
else aDest.mLength=aDestOffset;
|
|
|
|
SVAddNullTerminator<CharType>(aDest);
|
|
|
|
|
|
|
|
}
|
|
|
|
return result;
|
2000-03-03 12:04:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method is used to truncate the given string.
|
|
|
|
* The given allocator may choose to resize the str as well (but it's not likely).
|
|
|
|
*
|
2000-03-09 13:50:02 +03:00
|
|
|
* @update rickg 03.01.2000
|
2000-03-03 12:04:50 +03:00
|
|
|
* @param aDest is the stringvalue to be modified
|
|
|
|
* @param aDestOffset tells us where in dest to truncate
|
|
|
|
*/
|
|
|
|
template <class CharType>
|
2000-03-09 13:50:02 +03:00
|
|
|
inline void SVTruncate( nsStringValueImpl<CharType>& aDest,PRUint32 aDestOffset) {
|
2000-03-03 12:04:50 +03:00
|
|
|
if(aDestOffset<aDest.mLength){
|
|
|
|
aDest.mLength=aDestOffset;
|
|
|
|
SVAddNullTerminator<CharType>(aDest);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* These methods are used to append content to the given stringvalue
|
|
|
|
*
|
2000-03-09 13:50:02 +03:00
|
|
|
* @update rickg 03.01.2000
|
2000-03-03 12:04:50 +03:00
|
|
|
* @param aDest is the stringvalue to be modified
|
|
|
|
* @param aSource is the buffer to be copied from
|
|
|
|
* @param anOffset tells us where in source to start copying
|
|
|
|
* @param aCount tells us the (max) # of chars to copy
|
|
|
|
*/
|
|
|
|
template <class CharType1, class CharType2>
|
2000-03-09 13:50:02 +03:00
|
|
|
inline nsresult SVAppend( nsStringValueImpl<CharType1>& aDest,const nsStringValueImpl<CharType2>& aSource,PRInt32 aCount,PRInt32 aSrcOffset){
|
|
|
|
|
|
|
|
nsresult result=NS_OK;
|
|
|
|
|
|
|
|
if(aSrcOffset<(PRInt32)aSource.mLength){
|
2000-03-03 12:04:50 +03:00
|
|
|
PRInt32 theRealLen=(aCount<0) ? aSource.mLength : MinInt(aCount,aSource.mLength);
|
2000-03-09 13:50:02 +03:00
|
|
|
PRInt32 theLength=(aSrcOffset+theRealLen<(PRInt32)aSource.mLength) ? theRealLen : (aSource.mLength-aSrcOffset);
|
2000-03-03 12:04:50 +03:00
|
|
|
if(0<theLength){
|
|
|
|
|
|
|
|
PRBool isBigEnough=PR_TRUE;
|
|
|
|
if(aDest.mLength+theLength > aDest.mCapacity) {
|
2000-03-09 13:50:02 +03:00
|
|
|
result=SVGrowCapacity<CharType1>(aDest,aDest.mLength+theLength);
|
2000-03-03 12:04:50 +03:00
|
|
|
}
|
|
|
|
|
2000-03-09 13:50:02 +03:00
|
|
|
if(NS_SUCCESS(result)) {
|
|
|
|
|
2000-03-03 12:04:50 +03:00
|
|
|
//now append new chars, starting at offset
|
|
|
|
|
2000-03-09 13:50:02 +03:00
|
|
|
CharType1* theDest = &aDest.mBuffer[aDest.mLength];
|
|
|
|
CharType2* theSource = &aSource.mBuffer[aSrcOffset];
|
|
|
|
CharType2 *theLastChar = theSource+theLength;
|
|
|
|
|
|
|
|
result=SVCopyBuffer_<CharType1,CharType2>(theDest,theSource,theLength);
|
2000-03-03 12:04:50 +03:00
|
|
|
|
|
|
|
aDest.mLength+=theLength;
|
|
|
|
}
|
2000-03-09 13:50:02 +03:00
|
|
|
SVAddNullTerminator<CharType1>(aDest);
|
2000-03-03 12:04:50 +03:00
|
|
|
}
|
|
|
|
}
|
2000-03-09 13:50:02 +03:00
|
|
|
return result;
|
2000-03-03 12:04:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2000-03-09 13:50:02 +03:00
|
|
|
* This method is used to append content to the given stringvalue from an nsAReadableString
|
2000-03-03 12:04:50 +03:00
|
|
|
*
|
2000-03-09 13:50:02 +03:00
|
|
|
* @update rickg 03.01.2000
|
2000-03-03 12:04:50 +03:00
|
|
|
* @param aDest is the stringvalue to be modified
|
|
|
|
* @param aSource is the readablestring to be copied from
|
|
|
|
* @param anOffset tells us where in source to start copying
|
|
|
|
* @param aCount tells us the (max) # of chars to copy
|
|
|
|
*/
|
|
|
|
template <class CharType1>
|
2000-03-09 13:50:02 +03:00
|
|
|
inline nsresult SVAppendReadable( nsStringValueImpl<CharType1>& aDest,const nsAReadableString& aSource,PRInt32 aCount,PRInt32 anSrcOffset){
|
|
|
|
nsresult result=NS_OK;
|
2000-03-03 12:04:50 +03:00
|
|
|
/*
|
|
|
|
//I expect a pattern similar to this that could work on any readable string
|
|
|
|
|
2000-03-09 13:50:02 +03:00
|
|
|
nsAReadableStringIterator theFirst=aSource.First();
|
|
|
|
nsAReadableStringIterator theLast=aSource.Last();
|
2000-03-03 12:04:50 +03:00
|
|
|
CharType1 *theDest=aDest.mBuffer;
|
|
|
|
while(theFirst<theLast) {
|
|
|
|
*theDest++=theFirst++;
|
|
|
|
}
|
|
|
|
*/
|
2000-03-09 13:50:02 +03:00
|
|
|
return result;
|
2000-03-03 12:04:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* These methods are used to assign contents of a source string to dest string
|
|
|
|
*
|
2000-03-09 13:50:02 +03:00
|
|
|
* @update rickg 03.01.2000
|
2000-03-03 12:04:50 +03:00
|
|
|
* @param aDest is the stringvalue to be modified
|
|
|
|
* @param aSource is the buffer to be copied from
|
|
|
|
* @param anOffset tells us where in source to start copying
|
|
|
|
* @param aCount tells us the (max) # of chars to copy
|
|
|
|
*/
|
|
|
|
|
|
|
|
template <class CharType1, class CharType2>
|
2000-03-09 13:50:02 +03:00
|
|
|
inline nsresult SVAssign(nsStringValueImpl<CharType1>& aDest,const nsStringValueImpl<CharType2>& aSource,PRInt32 aCount,PRInt32 aSrcOffset) {
|
|
|
|
nsresult result=NS_OK;
|
|
|
|
if((void*)aDest.mBuffer!=(void*)aSource.mBuffer){
|
2000-03-03 12:04:50 +03:00
|
|
|
SVTruncate(aDest,0);
|
2000-03-09 13:50:02 +03:00
|
|
|
SVAppend(aDest,aSource,aCount,aSrcOffset);
|
2000-03-03 12:04:50 +03:00
|
|
|
}
|
2000-03-09 13:50:02 +03:00
|
|
|
return result;
|
2000-03-03 12:04:50 +03:00
|
|
|
}
|
|
|
|
|
2000-03-09 13:50:02 +03:00
|
|
|
|
|
|
|
|
2000-03-03 12:04:50 +03:00
|
|
|
/**
|
|
|
|
* These methods are used to insert content from source string to the dest stringvalue
|
|
|
|
*
|
2000-03-09 13:50:02 +03:00
|
|
|
* @update rickg 03.01.2000
|
2000-03-03 12:04:50 +03:00
|
|
|
* @param aDest is the stringvalue to be modified
|
|
|
|
* @param aDestOffset tells us where in dest to start insertion
|
|
|
|
* @param aSource is the buffer to be copied from
|
|
|
|
* @param aSrcOffset tells us where in source to start copying
|
|
|
|
* @param aCount tells us the (max) # of chars to insert
|
|
|
|
*/
|
|
|
|
template <class CharType1, class CharType2>
|
2000-03-09 13:50:02 +03:00
|
|
|
inline nsresult SVInsert( nsStringValueImpl<CharType1>& aDest,PRUint32 aDestOffset,const nsStringValueImpl<CharType2>& aSource,PRInt32 aCount,PRInt32 aSrcOffset) {
|
|
|
|
nsresult result=NS_OK;
|
|
|
|
|
|
|
|
//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(0<aSource.mLength){
|
|
|
|
if(aDest.mLength){
|
|
|
|
if(aDestOffset<aDest.mLength){
|
|
|
|
PRUint32 theRealLen=(aCount<0) ? aSource.mLength : MinInt(aCount,aSource.mLength);
|
|
|
|
PRUint32 theLength=(aSrcOffset+theRealLen<aSource.mLength) ? theRealLen : (aSource.mLength-aSrcOffset);
|
|
|
|
|
|
|
|
if(aSrcOffset<(PRInt32)aSource.mLength) {
|
|
|
|
//here's the only new case we have to handle.
|
|
|
|
//chars are really being inserted into our buffer...
|
|
|
|
|
|
|
|
if(aDest.mLength+theLength > aDest.mCapacity) {
|
|
|
|
|
|
|
|
nsStringValueImpl<CharType1> theTempStr;
|
|
|
|
result=SVEnsureCapacity<CharType1>(theTempStr,aDest.mLength+theLength);
|
|
|
|
|
|
|
|
if(NS_SUCCESS(result)) {
|
|
|
|
if(aDestOffset) {
|
|
|
|
SVAppend(theTempStr,aDest,aDestOffset,0); //first copy leftmost data...
|
|
|
|
}
|
|
|
|
|
|
|
|
SVAppend(theTempStr,aSource,aSource.mLength,0); //next copy inserted (new) data
|
|
|
|
|
|
|
|
PRUint32 theRemains=aDest.mLength-aDestOffset;
|
|
|
|
if(theRemains) {
|
|
|
|
SVAppend(theTempStr,aDest,theRemains,aDestOffset); //next copy rightmost data
|
|
|
|
}
|
|
|
|
|
|
|
|
SVFree(aDest);
|
|
|
|
aDest=theTempStr;
|
|
|
|
theTempStr.mBuffer=0; //make sure to null this out so that you don't lose the buffer you just stole...
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else {
|
|
|
|
CharType1* root=aDest.mBuffer;
|
|
|
|
CharType1* end= root+aDest.mLength;
|
|
|
|
CharType1* dst2 = root+aDestOffset;
|
|
|
|
CharType1* dst1 = root+aDestOffset+aCount;
|
|
|
|
|
|
|
|
memmove(dst1,dst2,sizeof(CharType1)*(end-dst2));
|
|
|
|
|
|
|
|
nsStringValueImpl<CharType1> theString(dst2,theLength);
|
|
|
|
result=SVCopyBuffer< CharType1, CharType2 >(theString,aSource,theLength,aSrcOffset);
|
|
|
|
//finally, make sure to update the string length...
|
|
|
|
aDest.mLength+=theLength;
|
|
|
|
SVAddNullTerminator(aDest);
|
|
|
|
}
|
|
|
|
}//if
|
|
|
|
//else nothing to do!
|
|
|
|
}
|
|
|
|
else SVAppend(aDest,aSource,aCount,0);
|
|
|
|
}
|
|
|
|
else SVAppend(aDest,aSource,aCount,0);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method compares characters strings of two types, and ignores case
|
|
|
|
*
|
|
|
|
* @update rickg 03.01.2000
|
|
|
|
* @param aLeft
|
|
|
|
* @param aLast
|
|
|
|
* @param aMax
|
|
|
|
* @param anEnd
|
|
|
|
* @param aTarget
|
|
|
|
* @return aDest<aSource=-1;aDest==aSource==0;aDest>aSource=1
|
|
|
|
*/
|
|
|
|
template <class CharType1,class CharType2>
|
|
|
|
inline PRInt32 SVCompareCase_(const CharType1* aLeft,const CharType1* anEnd,const CharType2* aTarget){
|
|
|
|
|
|
|
|
while(aLeft<anEnd){
|
|
|
|
PRUnichar theChar=(PRUnichar)nsCRT::ToUpper(*aLeft++);
|
|
|
|
PRUnichar theTargetChar=(PRUnichar)nsCRT::ToUpper(*aTarget++);
|
|
|
|
if(theChar<theTargetChar)
|
|
|
|
return -1;
|
|
|
|
else if(theTargetChar<theChar)
|
|
|
|
return 1;
|
|
|
|
} //while
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method compares characters strings of two types (case sensitive)
|
|
|
|
*
|
|
|
|
* @update rickg 03.01.2000
|
|
|
|
* @param aLeft
|
|
|
|
* @param aLast
|
|
|
|
* @param aMax
|
|
|
|
* @param anEnd
|
|
|
|
* @param aTarget
|
|
|
|
* @return aDest<aSource=-1;aDest==aSource==0;aDest>aSource=1
|
|
|
|
*/
|
|
|
|
template <class CharType1,class CharType2>
|
|
|
|
inline PRInt32 SVCompare_(const CharType1* aLeft,const CharType1* anEnd,const CharType2* aTarget){
|
|
|
|
|
|
|
|
while(aLeft<anEnd){
|
|
|
|
CharType1 theChar=*aLeft++;
|
|
|
|
CharType2 theTargetChar=*aTarget++;
|
|
|
|
if(theChar<theTargetChar)
|
|
|
|
return -1;
|
|
|
|
else if(theTargetChar<theChar)
|
|
|
|
return 1;
|
|
|
|
} //while
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method removes characters from the given set from this string.
|
|
|
|
* NOTE: aSet is a char*, and it's length is computed using strlen, which assumes null termination.
|
|
|
|
*
|
|
|
|
* @update rickg 03.01.2000
|
|
|
|
* @param aDest
|
|
|
|
* @param aString
|
|
|
|
* @param aIgnoreCase
|
|
|
|
* @param aCount --- tells us how many iterations to make.
|
|
|
|
* @return aDest<aSource=-1;aDest==aSource==0;aDest>aSource=1
|
|
|
|
*/
|
|
|
|
template <class CharType1,class CharType2>
|
|
|
|
inline PRInt32 SVCompare(const nsStringValueImpl<CharType1>& aDest,const nsStringValueImpl<CharType2>& aSource,PRBool aIgnoreCase, PRUint32 aCount){
|
|
|
|
|
|
|
|
PRInt32 result=0;
|
|
|
|
|
|
|
|
if(aCount) {
|
|
|
|
PRUint32 minlen=(aSource.mLength<aDest.mLength) ? aSource.mLength : aDest.mLength;
|
|
|
|
|
|
|
|
if(0==minlen) {
|
|
|
|
if ((aDest.mLength == 0) && (aSource.mLength == 0))
|
|
|
|
return 0;
|
|
|
|
if (aDest.mLength == 0)
|
|
|
|
return -1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRUint32 theCount = (aCount<0) ? minlen: MinInt(aCount,minlen);
|
|
|
|
|
|
|
|
const CharType1* left= aDest.mBuffer;
|
|
|
|
const CharType1* last= left+theCount;
|
|
|
|
const CharType1* max = left+aDest.mLength;
|
|
|
|
const CharType1* end = (last<max) ? last : max;
|
|
|
|
const CharType2* target = aSource.mBuffer;
|
|
|
|
|
|
|
|
if(aIgnoreCase)
|
|
|
|
result = SVCompareCase_<CharType1,CharType2>(left,end,target) ;
|
|
|
|
else result =SVCompare_<CharType1,CharType2>(left,end,target);
|
|
|
|
|
|
|
|
if (0==result) {
|
|
|
|
if(-1==aCount) {
|
|
|
|
|
|
|
|
//Since the caller didn't give us a length to test, and minlen characters matched,
|
|
|
|
//we have to assume that the longer string is greater.
|
|
|
|
|
|
|
|
if (aDest.mLength != aSource.mLength) {
|
|
|
|
//we think they match, but we've only compared minlen characters.
|
|
|
|
//if the string lengths are different, then they don't really match.
|
|
|
|
result = (aDest.mLength<aSource.mLength) ? -1 : 1;
|
|
|
|
}
|
|
|
|
} //if
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method removes characters from the given set from this string.
|
|
|
|
* NOTE: aSet is a char*, and it's length is computed using strlen, which assumes null termination.
|
|
|
|
*
|
|
|
|
* @update rickg 03.01.2000
|
|
|
|
* @param aDest
|
|
|
|
* @param aTarget
|
|
|
|
* @param aIgnoreCase
|
|
|
|
* @param aCount : tells us how many iterations to make, starting at offset
|
|
|
|
* @param aOffset: tells us where to start searching within aDest
|
|
|
|
* @return nothing
|
|
|
|
*/
|
|
|
|
template <class CharType1,class CharType2>
|
|
|
|
inline PRInt32 SVFind(const nsStringValueImpl<CharType1>& aDest,const nsStringValueImpl<CharType2>& aTarget,PRBool aIgnoreCase,PRInt32 aCount,PRInt32 aSrcOffset) {
|
|
|
|
|
|
|
|
PRUint32 minlen=(aTarget.mLength<aDest.mLength) ? aTarget.mLength : aDest.mLength;
|
|
|
|
|
|
|
|
aCount = (-1==aCount) ? aDest.mLength-minlen : aCount;
|
|
|
|
|
|
|
|
if((0<aCount) && minlen) {
|
|
|
|
|
|
|
|
const CharType1* root = aDest.mBuffer;
|
|
|
|
const CharType1* left = root+aSrcOffset;
|
|
|
|
const CharType1* last = left+aCount;
|
|
|
|
const CharType1* max = root+aDest.mLength;
|
|
|
|
const CharType1* end = (last<max) ? last : max;
|
|
|
|
|
|
|
|
PRInt32 cmp=0;
|
|
|
|
|
|
|
|
if(aIgnoreCase) {
|
|
|
|
while(left<=end) {
|
|
|
|
cmp = SVCompareCase_<CharType1,CharType2>(left,left+minlen,aTarget.mBuffer) ;
|
|
|
|
if(0==cmp) {
|
|
|
|
return left-root;
|
|
|
|
}
|
|
|
|
left++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
PRBool theFastWay = ((1==sizeof(CharType1)) && (1==sizeof(CharType2)));
|
|
|
|
|
|
|
|
while(left<=end) {
|
|
|
|
if(theFastWay) {
|
|
|
|
size_t theCount=end-left;
|
|
|
|
cmp = memcmp(left,aTarget.mBuffer,minlen);
|
|
|
|
}
|
|
|
|
else cmp =SVCompare_<CharType1,CharType2>(left,left+minlen,aTarget.mBuffer);
|
|
|
|
if(0==cmp) {
|
|
|
|
return left-root;
|
|
|
|
}
|
|
|
|
left++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return kNotFound;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This searches for the given char withing the given string
|
|
|
|
* NOTE: aSet is a char*, and it's length is computed using strlen, which assumes null termination.
|
|
|
|
*
|
|
|
|
* @update rickg 03.02.2000
|
|
|
|
* @param aDest
|
|
|
|
* @param aSet
|
|
|
|
* @param aEliminateLeading
|
|
|
|
* @param aEliminateTrailing
|
|
|
|
* @return nothing
|
|
|
|
*/
|
|
|
|
template <class CharType>
|
|
|
|
PRInt32 SVFindChar(const nsStringValueImpl<CharType>& aDest,PRUnichar aChar,PRBool aIgnoreCase,PRInt32 aCount,PRInt32 aSrcOffset) {
|
|
|
|
|
|
|
|
if(aSrcOffset<0)
|
|
|
|
aSrcOffset=0;
|
|
|
|
|
|
|
|
if(aCount<0)
|
|
|
|
aCount = (PRInt32)aDest.mLength;
|
|
|
|
|
|
|
|
size_t theCharSize=sizeof(CharType);
|
|
|
|
if((2==theCharSize) || (aChar<256)) {
|
|
|
|
if((0<aDest.mLength) && ((PRUint32)aSrcOffset<aDest.mLength)) {
|
|
|
|
|
|
|
|
//We'll only search if the given aChar is within the normal ascii a range,
|
|
|
|
//(Since this string is definitely within the ascii range).
|
|
|
|
|
|
|
|
if(0<aCount) {
|
|
|
|
|
|
|
|
const CharType* root= aDest.mBuffer;
|
|
|
|
const CharType* left= root+aSrcOffset;
|
|
|
|
const CharType* last= left+aCount;
|
|
|
|
const CharType* max = left+aDest.mLength;
|
|
|
|
const CharType* end = (last<max) ? last : max;
|
|
|
|
|
|
|
|
if(aIgnoreCase) {
|
|
|
|
|
|
|
|
CharType theChar=(CharType)nsCRT::ToUpper(aChar);
|
|
|
|
while(left<end){
|
|
|
|
if(nsCRT::ToUpper(*left)==theChar)
|
|
|
|
return left-root;
|
|
|
|
++left;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (1==theCharSize){
|
|
|
|
|
|
|
|
PRInt32 theMax = end-left;
|
|
|
|
if(0<theMax) {
|
|
|
|
CharType theChar=(CharType)aChar;
|
|
|
|
const char* result=(const char*)memchr(left, theChar, theMax);
|
|
|
|
if(result) {
|
|
|
|
return result-(char*)root;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
while(left<end){
|
|
|
|
if(*left==aChar)
|
|
|
|
return (left-root);
|
|
|
|
++left;
|
|
|
|
} //while
|
|
|
|
} //else
|
|
|
|
}
|
|
|
|
} //if
|
|
|
|
}//if
|
|
|
|
|
|
|
|
return kNotFound;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This searches for the given char withing the given string
|
|
|
|
* NOTE: aSet is a char*, and it's length is computed using strlen, which assumes null termination.
|
|
|
|
*
|
|
|
|
* @update rickg 03.02.2000
|
|
|
|
* @param aDest
|
|
|
|
* @param aSet
|
|
|
|
* @param aEliminateLeading
|
|
|
|
* @param aEliminateTrailing
|
|
|
|
* @return nothing
|
|
|
|
*/
|
|
|
|
template <class CharType1,class CharType2>
|
|
|
|
inline PRInt32 SVFindCharInSet(const nsStringValueImpl<CharType1>& aDest,const nsStringValueImpl<CharType2>& aSet,PRBool aIgnoreCase,PRInt32 aCount,PRInt32 anOffset) {
|
|
|
|
|
|
|
|
if(anOffset<0)
|
|
|
|
anOffset=0;
|
|
|
|
|
|
|
|
if(aCount<0)
|
|
|
|
aCount = (PRInt32)aDest.mLength;
|
|
|
|
|
|
|
|
if((0<aCount) && (0<aSet.mLength)){
|
|
|
|
|
|
|
|
const CharType1* root = aDest.mBuffer;
|
|
|
|
const CharType1* left = root+anOffset;
|
|
|
|
const CharType1* last = left+aCount;
|
|
|
|
const CharType1* max = root+aDest.mLength;
|
|
|
|
const CharType1* end = (last<max) ? last : max;
|
|
|
|
|
|
|
|
PRInt32 cmp=0;
|
|
|
|
while(left<=end) {
|
|
|
|
|
|
|
|
PRUnichar theChar=(PRUnichar)*left;
|
|
|
|
|
|
|
|
PRInt32 thePos=SVFindChar<CharType2>(aSet,theChar,aIgnoreCase,aSet.mLength,0);
|
|
|
|
if(kNotFound<thePos) {
|
|
|
|
return left-root;
|
|
|
|
}
|
|
|
|
left++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return kNotFound;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method removes characters from the given set from this string.
|
|
|
|
* NOTE: aSet is a char*, and it's length is computed using strlen, which assumes null termination.
|
|
|
|
*
|
|
|
|
* @update rickg 03.01.2000
|
|
|
|
* @param aDest
|
|
|
|
* @param aSet
|
|
|
|
* @param aEliminateLeading
|
|
|
|
* @param aEliminateTrailing
|
|
|
|
* @return nothing
|
|
|
|
*/
|
|
|
|
template <class CharType1,class CharType2>
|
|
|
|
inline PRInt32 SVRFind(const nsStringValueImpl<CharType1>& aDest,const nsStringValueImpl<CharType2>& aTarget,PRBool aIgnoreCase,PRInt32 aCount,PRInt32 aSrcOffset) {
|
|
|
|
|
|
|
|
if(aSrcOffset<0)
|
|
|
|
aSrcOffset=(PRInt32)aDest.mLength-1;
|
|
|
|
|
|
|
|
if(aCount<0)
|
|
|
|
aCount = aSrcOffset;
|
|
|
|
|
|
|
|
size_t theCharSize=sizeof(CharType1);
|
|
|
|
if((0<aTarget.mLength) && (0<aDest.mLength) && ((PRUint32)aSrcOffset<aDest.mLength)) {
|
|
|
|
|
|
|
|
//We'll only search if the given aChar is within the normal ascii a range,
|
|
|
|
//(Since this string is definitely within the ascii range).
|
|
|
|
|
|
|
|
if(0<aCount) {
|
|
|
|
|
|
|
|
const CharType1* root = aDest.mBuffer;
|
|
|
|
const CharType1* rightmost = root+aSrcOffset;
|
|
|
|
const CharType1* min = rightmost-aCount+1;
|
|
|
|
const CharType1* leftmost = (min<root) ? root : min;
|
|
|
|
|
|
|
|
PRInt32 cmp=0;
|
|
|
|
while(leftmost<=rightmost) {
|
|
|
|
|
|
|
|
if(aIgnoreCase)
|
|
|
|
cmp = SVCompareCase_<CharType1,CharType2>(rightmost,rightmost+aTarget.mLength,aTarget.mBuffer) ;
|
|
|
|
else cmp =SVCompare_<CharType1,CharType2>(rightmost,rightmost+aTarget.mLength,aTarget.mBuffer);
|
|
|
|
|
|
|
|
if(0==cmp) {
|
|
|
|
return rightmost-root;
|
|
|
|
}
|
|
|
|
rightmost--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return kNotFound;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This methods cans the given buffer (in reverse) for the given char
|
|
|
|
*
|
|
|
|
* @update gess 02/17/00
|
|
|
|
* @param aDest is the buffer to be searched
|
|
|
|
* @param anOffset is the start pos to begin searching
|
|
|
|
* @param aChar is the target character we're looking for
|
|
|
|
* @param aIgnorecase tells us whether to use a case sensitive search
|
|
|
|
* @param aCount tells us how many characters to iterate through (which may be different than aLength); -1 means use full length.
|
|
|
|
* @return index of pos if found, else -1 (kNotFound)
|
|
|
|
*/
|
|
|
|
template <class CharType>
|
|
|
|
PRInt32 SVRFindChar(const nsStringValueImpl<CharType>& aDest,PRUnichar aChar,PRBool aIgnoreCase,PRInt32 aCount,PRInt32 aSrcOffset) {
|
|
|
|
|
|
|
|
if(aSrcOffset<0)
|
|
|
|
aSrcOffset=(PRInt32)aDest.mLength-1;
|
|
|
|
|
|
|
|
if(aCount<0)
|
|
|
|
aCount = aSrcOffset;
|
|
|
|
|
|
|
|
size_t theCharSize=sizeof(CharType);
|
|
|
|
if((2==theCharSize) || (aChar<256)) {
|
|
|
|
if((0<aDest.mLength) && ((PRUint32)aSrcOffset<aDest.mLength)) {
|
|
|
|
|
|
|
|
//We'll only search if the given aChar is within the normal ascii a range,
|
|
|
|
//(Since this string is definitely within the ascii range).
|
|
|
|
|
|
|
|
if(0<aCount) {
|
|
|
|
|
|
|
|
const CharType* root = aDest.mBuffer;
|
|
|
|
const CharType* rightmost = root+aSrcOffset;
|
|
|
|
const CharType* min = rightmost-aCount+1;
|
|
|
|
const CharType* leftmost = (min<root) ? root : min;
|
|
|
|
|
|
|
|
CharType theChar=(CharType)aChar;
|
|
|
|
if(aIgnoreCase) {
|
|
|
|
|
|
|
|
while(leftmost<=rightmost){
|
|
|
|
if(nsCRT::ToUpper(*rightmost)==theChar)
|
|
|
|
return rightmost-root;
|
|
|
|
--rightmost;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
while(leftmost<=rightmost){
|
|
|
|
if((*rightmost)==theChar)
|
|
|
|
return rightmost-root;
|
|
|
|
--rightmost;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return kNotFound;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This methods cans the given buffer (in reverse) for the given char
|
|
|
|
*
|
|
|
|
* @update gess 02/17/00
|
|
|
|
* @param aDest is the buffer to be searched
|
|
|
|
* @param anOffset is the start pos to begin searching
|
|
|
|
* @param aChar is the target character we're looking for
|
|
|
|
* @param aIgnorecase tells us whether to use a case sensitive search
|
|
|
|
* @param aCount tells us how many characters to iterate through (which may be different than aLength); -1 means use full length.
|
|
|
|
* @return index of pos if found, else -1 (kNotFound)
|
|
|
|
*/
|
|
|
|
template <class CharType1,class CharType2>
|
|
|
|
inline PRInt32 SVRFindCharInSet(const nsStringValueImpl<CharType1>& aDest,const nsStringValueImpl<CharType2>& aSet,PRBool aIgnoreCase,PRInt32 aCount,PRInt32 aSrcOffset) {
|
|
|
|
|
|
|
|
if(aSrcOffset<0)
|
|
|
|
aSrcOffset=(PRInt32)aDest.mLength-1;
|
|
|
|
|
|
|
|
if(aCount<0)
|
|
|
|
aCount = aSrcOffset;
|
|
|
|
|
|
|
|
if((0<aDest.mLength) && ((PRUint32)aSrcOffset<aDest.mLength)) {
|
|
|
|
|
|
|
|
//We'll only search if the given aChar is within the normal ascii a range,
|
|
|
|
//(Since this string is definitely within the ascii range).
|
|
|
|
|
|
|
|
if(0<aCount) {
|
|
|
|
|
|
|
|
const CharType1* root = aDest.mBuffer;
|
|
|
|
const CharType1* rightmost = root+aSrcOffset;
|
|
|
|
|
|
|
|
while(root<=--rightmost){
|
|
|
|
|
|
|
|
CharType1 theChar=(aIgnoreCase) ? nsCRT::ToUpper(*rightmost) : *rightmost;
|
|
|
|
PRInt32 thePos=SVFindChar<CharType2>(aSet,theChar,aIgnoreCase,aSet.mLength,0);
|
|
|
|
if(kNotFound<thePos) {
|
|
|
|
return rightmost-root;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return kNotFound;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method removes characters from the given set from this string.
|
|
|
|
* NOTE: aSet is a char*, and it's length is computed using strlen, which assumes null termination.
|
|
|
|
*
|
|
|
|
* @update rickg 03.01.2000
|
|
|
|
* @param aDest
|
|
|
|
* @param aSet
|
|
|
|
* @param aEliminateLeading
|
|
|
|
* @param aEliminateTrailing
|
|
|
|
* @return nothing
|
|
|
|
*/
|
|
|
|
template <class CharType>
|
|
|
|
nsresult SVTrim(nsStringValueImpl<CharType>& aDest,const char* aSet,PRBool aEliminateLeading,PRBool aEliminateTrailing){
|
|
|
|
|
|
|
|
nsresult result=NS_OK;
|
|
|
|
|
|
|
|
if(0<aDest.mLength) {
|
|
|
|
CharType *root= aDest.mBuffer;
|
|
|
|
CharType *end = root+aDest.mLength;
|
|
|
|
|
|
|
|
nsStringValueImpl<char> theSet(const_cast<char*>(aSet));
|
|
|
|
|
|
|
|
|
|
|
|
if(aEliminateTrailing) {
|
|
|
|
|
|
|
|
while(root<=--end) {
|
|
|
|
CharType theChar=*end;
|
|
|
|
PRInt32 thePos=SVFindChar<char>(theSet,theChar,PR_FALSE,theSet.mLength,0);
|
|
|
|
if(kNotFound==thePos)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
*(end+1)=0;
|
|
|
|
aDest.mLength=(end-root)+1;
|
|
|
|
}
|
|
|
|
|
|
|
|
CharType *cp = root-1;
|
|
|
|
|
|
|
|
if(aEliminateLeading) {
|
|
|
|
while(++cp<end) {
|
|
|
|
CharType theChar=*cp;
|
|
|
|
PRInt32 thePos=SVFindChar<char>(theSet,theChar,PR_FALSE,theSet.mLength,0);
|
|
|
|
if(kNotFound==thePos)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
size_t theCount=cp-root;
|
|
|
|
if(0<theCount) {
|
|
|
|
result=SVDelete(aDest,0,theCount);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method removes characters from the given set from this string.
|
|
|
|
* NOTE: aSet is a char*, and it's length is computed using strlen, which assumes null termination.
|
|
|
|
*
|
|
|
|
* @update rickg 03.01.2000
|
|
|
|
* @param aDest
|
|
|
|
* @param aSet
|
|
|
|
* @param aEliminateLeading
|
|
|
|
* @param aEliminateTrailing
|
|
|
|
* @return nothing
|
|
|
|
*/
|
|
|
|
template <class CharType>
|
|
|
|
nsresult SVStripCharsInSet(nsStringValueImpl<CharType>& aDest,const char* aSet,PRInt32 aCount,PRInt32 aSrcOffset) {
|
|
|
|
|
|
|
|
if((0<aDest.mLength) && aSet && (aSrcOffset<(PRInt32)aDest.mLength)){
|
|
|
|
|
|
|
|
CharType* left= aDest.mBuffer+aSrcOffset;
|
|
|
|
CharType* theWriteCP= left;
|
|
|
|
const CharType* last= left+aCount;
|
|
|
|
const CharType* max = left+aDest.mLength;
|
|
|
|
const CharType* end = (last<max) ? last : max;
|
|
|
|
|
|
|
|
nsStringValueImpl<char> theSet(const_cast<char*>(aSet));
|
|
|
|
|
|
|
|
while(left<end){
|
|
|
|
CharType theChar=*left;
|
|
|
|
PRInt32 thePos=SVFindChar<char>(theSet,theChar,PR_FALSE,theSet.mLength,0);
|
|
|
|
if(kNotFound==thePos) {
|
|
|
|
*theWriteCP++=*left;
|
|
|
|
}
|
|
|
|
++left;
|
|
|
|
} //while
|
|
|
|
*theWriteCP=0;
|
|
|
|
aDest.mLength-=(left-theWriteCP);
|
|
|
|
} //if
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method removes a given char the underlying stringvalue
|
|
|
|
*
|
|
|
|
* @update rickg 03.01.2000
|
|
|
|
* @param aDest is the stringvalue to be modified
|
|
|
|
* @param anOffset tells us where in source to start copying
|
|
|
|
* @param aCount tells us the (max) # of chars to copy
|
|
|
|
*/
|
|
|
|
template <class CharType>
|
|
|
|
nsresult SVStripChar( nsStringValueImpl<CharType>& aDest, CharType aChar,PRInt32 aCount,PRInt32 anOffset) {
|
|
|
|
|
|
|
|
nsresult result=NS_OK;
|
|
|
|
|
|
|
|
if(anOffset<(PRInt32)aDest.mLength){
|
|
|
|
|
|
|
|
CharType *theCP=&aDest.mBuffer[anOffset];
|
|
|
|
CharType *theWriteCP=theCP;
|
|
|
|
CharType *theEndCP=theCP+aDest.mLength;
|
|
|
|
|
|
|
|
while(theCP<theEndCP) {
|
|
|
|
if(*theCP!=aChar) {
|
|
|
|
*theWriteCP++=*theCP;
|
|
|
|
}
|
|
|
|
theCP++;
|
|
|
|
}
|
|
|
|
*theWriteCP=0;
|
|
|
|
aDest.mLength-=(theCP-theWriteCP);
|
|
|
|
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method removes a given char the underlying stringvalue
|
|
|
|
*
|
|
|
|
* @update rickg 03.01.2000
|
|
|
|
* @param aDest is the stringvalue to be modified
|
|
|
|
* @param anOffset tells us where in source to start copying
|
|
|
|
* @param aCount tells us the (max) # of chars to copy
|
|
|
|
*/
|
|
|
|
template <class CharType1,class CharType2>
|
|
|
|
nsresult SVReplace( nsStringValueImpl<CharType1> &aDest,
|
|
|
|
const nsStringValueImpl<CharType2> &aTarget,
|
|
|
|
const nsStringValueImpl<CharType2> &aNewValue,
|
|
|
|
PRInt32 aCount,
|
|
|
|
PRInt32 anOffset) {
|
|
|
|
|
|
|
|
nsresult result=NS_OK;
|
|
|
|
|
|
|
|
if((aTarget.mLength) && (aNewValue.mLength)) {
|
|
|
|
|
|
|
|
nsStringValueImpl<CharType1> theTempString;
|
|
|
|
PRUint32 thePrevOffset=0;
|
|
|
|
PRInt32 thePos=SVFind(aDest,aTarget,PR_FALSE,aDest.mLength,thePrevOffset);
|
|
|
|
|
|
|
|
while(kNotFound<thePos) {
|
|
|
|
if(0<thePos) {
|
|
|
|
SVAppend(theTempString,aDest,thePos-thePrevOffset,thePrevOffset);
|
|
|
|
}
|
|
|
|
SVAppend(theTempString,aNewValue,aNewValue.mLength,0);
|
|
|
|
thePrevOffset=thePos+aTarget.mLength;
|
|
|
|
thePos=SVFind(aDest,aTarget,PR_FALSE,aDest.mLength-thePrevOffset,thePrevOffset);
|
|
|
|
}
|
|
|
|
if(thePrevOffset<aDest.mLength) {
|
|
|
|
SVAppend(theTempString,aDest,aDest.mLength-thePrevOffset,thePrevOffset);
|
|
|
|
}
|
|
|
|
SVFree(aDest);
|
|
|
|
aDest=theTempString;
|
|
|
|
theTempString.mBuffer=0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method removes a given char the underlying stringvalue
|
|
|
|
*
|
|
|
|
* @update rickg 03.01.2000
|
|
|
|
* @param aDest is the stringvalue to be modified
|
|
|
|
* @param anOffset tells us where in source to start copying
|
|
|
|
* @param aCount tells us the (max) # of chars to copy
|
|
|
|
*/
|
|
|
|
template <class CharType>
|
|
|
|
nsresult SVReplaceChar( nsStringValueImpl<CharType>& aDest, CharType anOldChar, CharType aNewChar, PRInt32 aCount,PRInt32 anOffset) {
|
|
|
|
|
|
|
|
nsresult result=NS_OK;
|
|
|
|
|
|
|
|
if(anOffset<(PRInt32)aDest.mLength){
|
|
|
|
|
|
|
|
CharType *theCP=&aDest.mBuffer[anOffset];
|
|
|
|
CharType *theWriteCP=theCP;
|
|
|
|
CharType *theEndCP=theCP+aDest.mLength;
|
|
|
|
|
|
|
|
while(theCP<theEndCP) {
|
|
|
|
if(*theCP==anOldChar) {
|
|
|
|
*theCP=aNewChar;
|
|
|
|
}
|
|
|
|
theCP++;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method removes characters from the given set from this string.
|
|
|
|
* NOTE: aSet is a char*, and it's length is computed using strlen, which assumes null termination.
|
|
|
|
*
|
|
|
|
* @update rickg 03.01.2000
|
|
|
|
* @param aDest
|
|
|
|
* @param aSet
|
|
|
|
* @param aEliminateLeading
|
|
|
|
* @param aEliminateTrailing
|
|
|
|
* @return nothing
|
|
|
|
*/
|
|
|
|
template <class CharType>
|
|
|
|
nsresult SVReplaceCharsInSet(nsStringValueImpl<CharType>& aDest,const nsStringValueImpl<char> &aSet,PRUnichar aNewChar,PRInt32 aCount,PRInt32 anOffset) {
|
|
|
|
|
|
|
|
if((0<aDest.mLength) && (anOffset<(PRInt32)aDest.mLength)){
|
|
|
|
|
|
|
|
CharType* left= aDest.mBuffer+anOffset;
|
|
|
|
const CharType* theWriteCP= left;
|
|
|
|
const CharType* last= left+aCount;
|
|
|
|
const CharType* max = left+aDest.mLength;
|
|
|
|
const CharType* end = (last<max) ? last : max;
|
|
|
|
|
|
|
|
nsStringValueImpl<char> theSet(aSet);
|
|
|
|
|
|
|
|
while(left<end){
|
|
|
|
CharType theChar=*left;
|
|
|
|
PRInt32 thePos=SVFindChar(theSet,theChar,PR_FALSE,theSet.mLength,0);
|
|
|
|
if(kNotFound!=thePos) {
|
|
|
|
*left=(CharType)aNewChar;
|
|
|
|
}
|
|
|
|
++left;
|
|
|
|
} //while
|
|
|
|
} //if
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method removes characters from the given set from this string.
|
|
|
|
* NOTE: aSet is a char*, and it's length is computed using strlen, which assumes null termination.
|
|
|
|
*
|
|
|
|
* @update rickg 03.01.2000
|
|
|
|
* @param aDest
|
|
|
|
* @param aSet
|
|
|
|
* @param aEliminateLeading
|
|
|
|
* @param aEliminateTrailing
|
|
|
|
* @return nothing
|
|
|
|
*/
|
|
|
|
template <class CharType>
|
|
|
|
nsresult SVCompressSet(nsStringValueImpl<CharType>& aDest,nsStringValueImpl<char> &aSet, PRUnichar aChar,PRBool aEliminateLeading=PR_TRUE,PRBool aEliminateTrailing=PR_TRUE){
|
|
|
|
|
|
|
|
nsresult result=NS_OK;
|
|
|
|
|
|
|
|
if(0<aDest.mLength){
|
|
|
|
|
|
|
|
result=SVReplaceCharsInSet<CharType>(aDest, aSet, aChar, aDest.mLength,0);
|
|
|
|
SVTrim<CharType>(aDest,aSet,aEliminateLeading,aEliminateTrailing);
|
|
|
|
|
|
|
|
CharType* root = aDest.mBuffer;
|
|
|
|
CharType* end = root + aDest.mLength;
|
|
|
|
CharType* to = root;
|
|
|
|
|
|
|
|
//this code converts /n, /t, /r into normal space ' ';
|
|
|
|
//it also compresses runs of whitespace down to a single char...
|
|
|
|
PRUint32 aSetLen=strlen(aSet);
|
|
|
|
while (root < end) {
|
|
|
|
CharType theChar = *root++;
|
|
|
|
if((255<theChar) || (kNotFound!=SVFindChar<char>(aSet,theChar,PR_FALSE,aSet.mLength,0))){
|
|
|
|
*to++=theChar;
|
|
|
|
while (root <= end) {
|
|
|
|
theChar = *root++;
|
|
|
|
PRInt32 thePos=SVFindChar<char>(aSet,theChar,PR_FALSE,aSet.mLength,0);
|
|
|
|
if(kNotFound==thePos){
|
|
|
|
*to++ = theChar;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
*to++ = theChar;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*to = 0;
|
|
|
|
aDest.mLength = to - (CharType*)aDest.mBuffer;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <class CharType>
|
|
|
|
void SVToLowerCase(nsStringValueImpl<CharType> &aString) {
|
|
|
|
|
|
|
|
CharType *theCP=aString.mBuffer;
|
|
|
|
CharType *theEndCP=theCP+aString.mLength;
|
|
|
|
|
|
|
|
while(theCP<theEndCP) {
|
|
|
|
CharType theChar=*theCP;
|
|
|
|
if ((theChar >= 'A') && (theChar <= 'Z')) {
|
|
|
|
*theCP = 'a' + (theChar - 'A');
|
|
|
|
}
|
|
|
|
theCP++;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class CharType>
|
|
|
|
void SVToUpperCase(nsStringValueImpl<CharType> &aString) {
|
|
|
|
CharType *theCP=aString.mBuffer;
|
|
|
|
CharType *theEndCP=theCP+aString.mLength;
|
|
|
|
|
|
|
|
while(theCP<theEndCP) {
|
|
|
|
CharType theChar=*theCP;
|
|
|
|
if ((theChar>= 'a') && (theChar<= 'z')) {
|
|
|
|
*theCP= 'A' + (theChar - 'a');
|
|
|
|
}
|
|
|
|
theCP++;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class CharType>
|
|
|
|
PRInt32 SVCountChar(const nsStringValueImpl<CharType> &aString,PRUnichar aChar) {
|
|
|
|
PRInt32 result=0;
|
|
|
|
if(aString.mLength) {
|
|
|
|
const CharType* cp=aString.mBuffer-1;
|
|
|
|
const CharType* endcp=cp+aString.mLength;
|
|
|
|
|
|
|
|
while(++cp<endcp) {
|
|
|
|
if(*cp==aChar)
|
|
|
|
result++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
//This will not work correctly for any unicode set other than ascii
|
|
|
|
template <class CharType>
|
|
|
|
void SVDebugDump(const nsStringValueImpl<CharType> &aString) {
|
|
|
|
if(aString.mLength) {
|
|
|
|
|
|
|
|
CharType* cp=aString.mBuffer;
|
|
|
|
CharType* endcp=cp+aString.mLength;
|
|
|
|
|
|
|
|
char theBuffer[256];
|
|
|
|
char* outp=theBuffer;
|
|
|
|
char* outendp=&theBuffer[255];
|
|
|
|
|
|
|
|
while(++cp<endcp) {
|
|
|
|
if(outp==outendp) {
|
|
|
|
*outp=0; //write null
|
|
|
|
printf("%s",theBuffer);
|
|
|
|
outp=theBuffer;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*outp++=(char)*cp;
|
|
|
|
}
|
|
|
|
} //while
|
|
|
|
*outp=0; //force a null
|
|
|
|
printf("%s",theBuffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Perform string to int conversion.
|
|
|
|
* @param aErrorCode will contain error if one occurs
|
|
|
|
* @param aRadix tells us which radix to assume; kAutoDetect tells us to determine the radix for you.
|
|
|
|
* @return int rep of string value, and possible (out) error code
|
|
|
|
*/
|
|
|
|
template <class CharType>
|
|
|
|
PRInt32 SVToInteger(const nsStringValueImpl<CharType> &aString,PRInt32* anErrorCode,PRUint32 aRadix=kAutoDetect) {
|
|
|
|
|
|
|
|
CharType* cp=aString.mBuffer;
|
|
|
|
PRInt32 theRadix = (kAutoDetect==aRadix) ? 10 : aRadix;
|
|
|
|
PRInt32 result=0;
|
|
|
|
PRBool negate=PR_FALSE;
|
|
|
|
PRUnichar theChar=0;
|
|
|
|
|
|
|
|
*anErrorCode=NS_ERROR_ILLEGAL_VALUE;
|
|
|
|
|
|
|
|
if(cp) {
|
|
|
|
|
|
|
|
//begin by skipping over leading chars that shouldn't be part of the number...
|
|
|
|
|
|
|
|
CharType* endcp=cp+aString.mLength;
|
|
|
|
PRBool done=PR_FALSE;
|
|
|
|
|
|
|
|
while((cp<endcp) && (!done)){
|
|
|
|
theChar=*cp;
|
|
|
|
switch(*cp++) {
|
|
|
|
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
|
|
|
|
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
|
|
|
|
theRadix=16;
|
|
|
|
done=PR_TRUE;
|
|
|
|
break;
|
|
|
|
case '0': case '1': case '2': case '3': case '4':
|
|
|
|
case '5': case '6': case '7': case '8': case '9':
|
|
|
|
done=PR_TRUE;
|
|
|
|
break;
|
|
|
|
case '-':
|
|
|
|
negate=PR_TRUE; //fall through...
|
|
|
|
break;
|
|
|
|
case 'X': case 'x':
|
|
|
|
theRadix=16;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
} //switch
|
|
|
|
}
|
|
|
|
|
|
|
|
//if you don't have any valid chars, return 0, but set the error;
|
|
|
|
if(cp<=endcp) {
|
|
|
|
|
|
|
|
*anErrorCode = NS_OK;
|
|
|
|
|
|
|
|
//now iterate the numeric chars and build our result
|
|
|
|
CharType* first=--cp; //in case we have to back up.
|
|
|
|
|
|
|
|
while(cp<=endcp){
|
|
|
|
theChar=*cp++;
|
|
|
|
if(('0'<=theChar) && (theChar<='9')){
|
|
|
|
result = (theRadix * result) + (theChar-'0');
|
|
|
|
}
|
|
|
|
else if((theChar>='A') && (theChar<='F')) {
|
|
|
|
if(10==theRadix) {
|
|
|
|
if(kAutoDetect==aRadix){
|
|
|
|
theRadix=16;
|
|
|
|
cp=first; //backup
|
|
|
|
result=0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*anErrorCode=NS_ERROR_ILLEGAL_VALUE;
|
|
|
|
result=0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
result = (theRadix * result) + ((theChar-'A')+10);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if((theChar>='a') && (theChar<='f')) {
|
|
|
|
if(10==theRadix) {
|
|
|
|
if(kAutoDetect==aRadix){
|
|
|
|
theRadix=16;
|
|
|
|
cp=first; //backup
|
|
|
|
result=0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*anErrorCode=NS_ERROR_ILLEGAL_VALUE;
|
|
|
|
result=0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
result = (theRadix * result) + ((theChar-'a')+10);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(('X'==theChar) || ('x'==theChar) || ('#'==theChar) || ('+'==theChar)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
//we've encountered a char that's not a legal number or sign
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} //while
|
|
|
|
if(negate)
|
|
|
|
result=-result;
|
|
|
|
} //if
|
|
|
|
}
|
|
|
|
return result;
|
2000-03-03 12:04:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2000-03-09 13:50:02 +03:00
|
|
|
|