1214 lines
29 KiB
C++
1214 lines
29 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
*
|
|
* (C) Copyright The MITRE Corporation 1999 All rights reserved.
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License
|
|
* Version 1.0 (the "License"); you may not use this file except in
|
|
* compliance with the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* The program provided "as is" without any warranty express or
|
|
* implied, including the warranty of non-infringement and the implied
|
|
* warranties of merchantibility and fitness for a particular purpose.
|
|
* The Copyright owner will not be liable for any damages suffered by
|
|
* you as a result of using the Program. In no event will the Copyright
|
|
* owner be liable for any special, indirect or consequential damages or
|
|
* lost profits even if the Copyright owner has been advised of the
|
|
* possibility of their occurrence.
|
|
*
|
|
* Contributor(s):
|
|
*
|
|
* Tom Kneeland
|
|
* -- original author.
|
|
*
|
|
* Keith Visco <kvisco@ziplink.net>
|
|
* Larry Fitzpatrick
|
|
*
|
|
*/
|
|
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "TxString.h"
|
|
#include <iostream.h>
|
|
|
|
//
|
|
//Default Constructor, create an empty String
|
|
//
|
|
String::String()
|
|
{
|
|
strBuffer = NULL;
|
|
bufferLength = 0;
|
|
strLength = 0;
|
|
}
|
|
|
|
//
|
|
//Create an empty String of a specific size
|
|
//
|
|
String::String(PRInt32 initSize)
|
|
{
|
|
strBuffer = new UNICODE_CHAR[initSize];
|
|
bufferLength = initSize;
|
|
strLength = 0;
|
|
}
|
|
|
|
//
|
|
//Create a copy of the source String
|
|
//TK 12/09/1999 - To ensure compatibility with sub classes of String, this
|
|
// constructor has been modified to use String's public
|
|
// interface only.
|
|
//
|
|
String::String(const String& source)
|
|
{
|
|
PRInt32 copyLoop;
|
|
|
|
//Allocate space for the source string
|
|
strLength = source.length();
|
|
|
|
//-- modified by kvisco to only use necessay amount of space
|
|
//-- was: bufferLength = source.bufferLength;
|
|
bufferLength = strLength;
|
|
|
|
strBuffer = new UNICODE_CHAR[bufferLength];
|
|
|
|
//Copy the new string data after the old data
|
|
for (copyLoop=0;copyLoop<strLength;copyLoop++)
|
|
strBuffer[copyLoop] = source.charAt(copyLoop);
|
|
|
|
}
|
|
|
|
//
|
|
//Create a String from the characters
|
|
//
|
|
String::String(const char* source)
|
|
{
|
|
PRInt32 copyLoop;
|
|
|
|
if (source)
|
|
{
|
|
strLength = bufferLength = strlen(source);
|
|
|
|
//Set up the new buffer to be the same size as the input char array.
|
|
strBuffer = new UNICODE_CHAR[bufferLength];
|
|
|
|
//Now store the char array in the new string buffer.
|
|
//Can't use strcpy since the destination is a UNICODE_CHAR buffer.
|
|
//Also make sure to pick up the null terminator at the end of the char
|
|
//array.
|
|
for (copyLoop=0; copyLoop<strLength; copyLoop++)
|
|
strBuffer[copyLoop] = (PRInt32)source[copyLoop];
|
|
}
|
|
else
|
|
{
|
|
//Create an empty string
|
|
strBuffer = NULL;
|
|
bufferLength = 0;
|
|
strLength = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
//Create a String from a null terminated array of UNICODE_CHARs
|
|
//
|
|
String::String(const UNICODE_CHAR* source)
|
|
{
|
|
PRInt32 copyLoop;
|
|
|
|
if (source)
|
|
{
|
|
strLength = bufferLength = UnicodeLength(source);
|
|
|
|
//Set up the new buffer to be the same size as the input char array.
|
|
strBuffer = new UNICODE_CHAR[bufferLength];
|
|
|
|
//Now store the char array in the new string buffer.
|
|
//Can't use strcpy since the destination is a UNICODE_CHAR buffer.
|
|
//Also make sure to pick up the null terminator at the end of the char
|
|
//array.
|
|
for (copyLoop=0; copyLoop<strLength; copyLoop++)
|
|
strBuffer[copyLoop] = source[copyLoop];
|
|
}
|
|
else
|
|
{
|
|
//Create an empty string
|
|
strBuffer = NULL;
|
|
bufferLength = 0;
|
|
strLength = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
//Create a String from a UNICODE_CHAR buffer and a supplied string length
|
|
//
|
|
String::String(const UNICODE_CHAR* source, PRInt32 length)
|
|
{
|
|
PRInt32 copyLoop;
|
|
|
|
if (source)
|
|
{
|
|
strLength = bufferLength = length;
|
|
|
|
//Set up the new buffer to be the same size as the input char array.
|
|
strBuffer = new UNICODE_CHAR[bufferLength];
|
|
|
|
//Now store the char array in the new string buffer.
|
|
//Can't use strcpy since the destination is a UNICODE_CHAR buffer.
|
|
//Also make sure to pick up the null terminator at the end of the char
|
|
//array.
|
|
for (copyLoop=0; copyLoop<strLength; copyLoop++)
|
|
strBuffer[copyLoop] = source[copyLoop];
|
|
}
|
|
else
|
|
{
|
|
//Create an empty string
|
|
strBuffer = NULL;
|
|
bufferLength = 0;
|
|
strLength = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
//Destroy the String, and free memory
|
|
//
|
|
String::~String()
|
|
{
|
|
//cout << "~String() deleting " << *this <<endl;
|
|
if (strBuffer)
|
|
delete strBuffer;
|
|
}
|
|
|
|
//
|
|
//Convert the UNICODE_CHARs of this String to Chars, and output them to the given
|
|
//ostream
|
|
//
|
|
ostream& operator<<(ostream& output, const String& source)
|
|
{
|
|
PRInt32 outputLoop;
|
|
|
|
for (outputLoop=0;outputLoop<source.length();outputLoop++)
|
|
output << (char)source.charAt(outputLoop);
|
|
|
|
return output;
|
|
}
|
|
|
|
|
|
//
|
|
//Overloaded '=' operator to assign the value of the source string to this
|
|
//string.
|
|
//TK 12/09/1999 - Modified to interact only with the public interface of the
|
|
// source "String" object. This ensures compatibility with
|
|
// subclasses of String.
|
|
//
|
|
String& String::operator=(const String& source)
|
|
{
|
|
PRInt32 copyLoop;
|
|
//Make sure string is not being copied onto itself
|
|
if (&source != this) {
|
|
//Check to see if this string is already big enough for source
|
|
//-- set size of current string length to 0 before making this call (kvisco)
|
|
strLength = 0;
|
|
ensureCapacity(source.length());
|
|
|
|
for (copyLoop=0; copyLoop<source.length(); copyLoop++)
|
|
strBuffer[copyLoop] = source.charAt(copyLoop);
|
|
|
|
strLength = copyLoop;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
//
|
|
//Overloaded '=' operator to assign the value of the source C string to this
|
|
//string
|
|
//
|
|
String& String::operator=(const char* source)
|
|
{
|
|
PRInt32 copyLoop;
|
|
PRInt32 sourceLength;
|
|
|
|
if (source)
|
|
{
|
|
sourceLength = strlen(source);
|
|
ensureCapacity(sourceLength);
|
|
|
|
for (copyLoop=0; copyLoop<sourceLength; copyLoop++)
|
|
strBuffer[copyLoop] = source[copyLoop];
|
|
|
|
strLength = copyLoop;
|
|
}
|
|
else
|
|
clear();
|
|
|
|
return *this;
|
|
}
|
|
|
|
//
|
|
//Overloaded '=' operator to assign the value of a UNICODE_CHAR string to this
|
|
//string. Note: The soucre is "NULL" terminated.
|
|
//
|
|
String& String::operator=(const UNICODE_CHAR* source)
|
|
{
|
|
PRInt32 copyLoop;
|
|
PRInt32 sourceLength;
|
|
|
|
if (source)
|
|
{
|
|
sourceLength = UnicodeLength(source);
|
|
ensureCapacity(sourceLength);
|
|
|
|
for (copyLoop=0; copyLoop<sourceLength; copyLoop++)
|
|
strBuffer[copyLoop] = source[copyLoop];
|
|
|
|
strLength = copyLoop;
|
|
}
|
|
else
|
|
clear();
|
|
|
|
return *this;
|
|
}
|
|
|
|
//
|
|
//Overloaded '=' operator to assign an integer to this string.
|
|
//
|
|
String& String::operator=(PRInt32 source)
|
|
{
|
|
ConvertInt(source, *this);
|
|
return *this; //-- added, LF
|
|
} //-- operator=
|
|
|
|
//
|
|
//Grow buffer by 1 if necessary, and append the source character
|
|
//
|
|
void String::append(UNICODE_CHAR source)
|
|
{
|
|
//Enlarge string buffer to fit source character if necessary
|
|
ensureCapacity(1);
|
|
|
|
//Insert the character and increment the length
|
|
strBuffer[strLength++] = source;
|
|
}
|
|
|
|
//
|
|
//Append a character to the string
|
|
//
|
|
void String::append(char source)
|
|
{
|
|
append((UNICODE_CHAR)source);
|
|
}
|
|
|
|
//
|
|
//Append String
|
|
//TK 12/09/199 - Modified to use the "source" String's public interface only,
|
|
// to ensure compatibility with sub classes
|
|
//
|
|
void String::append(const String& source)
|
|
{
|
|
PRInt32 copyLoop;
|
|
|
|
//Enlarge buffer to fit string if necessary
|
|
ensureCapacity(source.length());
|
|
|
|
//Copy the new string data after the old data
|
|
for (copyLoop=0;copyLoop<source.length();copyLoop++)
|
|
strBuffer[strLength+copyLoop] = source.charAt(copyLoop);
|
|
|
|
//Update the length
|
|
strLength += source.length();
|
|
}
|
|
|
|
//
|
|
//Append a string of characters (null terminated arry of chars)
|
|
//
|
|
void String::append(const char* source)
|
|
{
|
|
PRInt32 copyLoop;
|
|
PRInt32 initLength = strlen(source);
|
|
|
|
//Enlarge buffer to fit new string if necessary
|
|
ensureCapacity(initLength);
|
|
|
|
//Copy the new string data after the old data
|
|
for (copyLoop=0;copyLoop<initLength;copyLoop++)
|
|
strBuffer[strLength+copyLoop] = source[copyLoop];
|
|
|
|
//Update the length
|
|
strLength += initLength;
|
|
}
|
|
|
|
//
|
|
//Append a string of unicode chars (null terminated array of Unicode chars)
|
|
//
|
|
void String::append(const UNICODE_CHAR* source)
|
|
{
|
|
append(source, UnicodeLength(source));
|
|
}
|
|
|
|
|
|
//
|
|
//Append a string of DOM Characters whose length is also defined
|
|
//
|
|
void String::append(const UNICODE_CHAR* source, PRInt32 length)
|
|
{
|
|
PRInt32 copyLoop;
|
|
|
|
//Enlarge buffer to fit new string if necessary
|
|
ensureCapacity(length);
|
|
|
|
//Copy the new string data after the old data
|
|
for (copyLoop=0;copyLoop<length;copyLoop++)
|
|
strBuffer[strLength+copyLoop] = source[copyLoop];
|
|
|
|
//Update the length
|
|
strLength += length;
|
|
}
|
|
|
|
//
|
|
//Convert source from an integer to a string, and append it to the current
|
|
//string
|
|
//
|
|
void String::append(PRInt32 source)
|
|
{
|
|
String convertString;
|
|
|
|
append(ConvertInt(source, convertString));
|
|
}
|
|
|
|
//
|
|
//Insert a single UNICODE_CHAR into the string starting at offset
|
|
//
|
|
void String::insert(PRInt32 offset, const UNICODE_CHAR source)
|
|
{
|
|
PRInt32 moveLoop;
|
|
PRInt32 moveIndex;
|
|
|
|
offset = offset < 0 ? 0 : offset;
|
|
|
|
if (offset < strLength)
|
|
{
|
|
moveLoop = strLength - offset;
|
|
moveIndex = strLength - 1;
|
|
|
|
//Enlarge string buffer to fit source character
|
|
ensureCapacity(1);
|
|
|
|
//Bump all characters down one position to make room for new character
|
|
while (moveLoop--)
|
|
strBuffer[moveIndex+1] = strBuffer[moveIndex--];
|
|
|
|
strBuffer[moveIndex+1] = source;
|
|
strLength += 1;
|
|
}
|
|
else
|
|
append(source);
|
|
}
|
|
|
|
//
|
|
//Insert a single C type character into the string starting at offset
|
|
//
|
|
void String::insert(PRInt32 offset, const char source)
|
|
{
|
|
insert(offset, (UNICODE_CHAR)source);
|
|
}
|
|
|
|
//
|
|
//Insert the source string starting at the current offset
|
|
//TK 12/09/1999 - Modified to use the "source" String's public interface only,
|
|
// to ensure compatibility with subclasses of String
|
|
//
|
|
void String::insert(PRInt32 offset, const String& source)
|
|
{
|
|
PRInt32 moveLoop;
|
|
PRInt32 moveIndex;
|
|
PRInt32 copyLoop;
|
|
|
|
offset = offset < 0 ? 0 : offset;
|
|
|
|
if (offset < strLength)
|
|
{
|
|
moveLoop = strLength - offset;
|
|
moveIndex = strLength - 1;
|
|
|
|
//Enlarge string buffer to fit source character
|
|
ensureCapacity(source.length());
|
|
|
|
//Bump all characters down one position to make room for new character
|
|
while (moveLoop--)
|
|
strBuffer[moveIndex+source.length()] = strBuffer[moveIndex--];
|
|
|
|
moveIndex += 1;
|
|
for (copyLoop=0;copyLoop<source.strLength;copyLoop++)
|
|
strBuffer[moveIndex+copyLoop] = source.charAt(copyLoop);
|
|
|
|
strLength += source.length();
|
|
}
|
|
else
|
|
append(source);
|
|
}
|
|
|
|
//
|
|
//Insert the source "C" type string into this string starting at offset
|
|
//
|
|
void String::insert(PRInt32 offset, const char* source)
|
|
{
|
|
PRInt32 moveLoop;
|
|
PRInt32 moveIndex;
|
|
PRInt32 copyLoop;
|
|
PRInt32 sourceLength;
|
|
|
|
offset = offset < 0 ? 0 : offset;
|
|
|
|
if (offset < strLength)
|
|
{
|
|
moveLoop = strLength - offset;
|
|
moveIndex = strLength - 1;
|
|
sourceLength = strlen(source);
|
|
|
|
//Enlarge string buffer to fit source character
|
|
ensureCapacity(sourceLength);
|
|
|
|
//Bump all characters down to make room for new character
|
|
while (moveLoop--)
|
|
strBuffer[moveIndex+sourceLength] = strBuffer[moveIndex--];
|
|
|
|
moveIndex += 1;
|
|
for (copyLoop=0;copyLoop<sourceLength;copyLoop++)
|
|
strBuffer[moveIndex+copyLoop] = source[copyLoop];
|
|
|
|
strLength += sourceLength;
|
|
}
|
|
else
|
|
append(source);
|
|
}
|
|
|
|
//
|
|
//Insert the source UNICODE_CHAR type string into this string starting at
|
|
//offset. Note that the source is Null Terminated.
|
|
//
|
|
void String::insert(PRInt32 offset, const UNICODE_CHAR* source)
|
|
{
|
|
insert(offset, source, UnicodeLength(source));
|
|
}
|
|
|
|
void String::insert(PRInt32 offset, const UNICODE_CHAR* source,
|
|
PRInt32 sourceLength)
|
|
{
|
|
PRInt32 moveLoop;
|
|
PRInt32 moveIndex;
|
|
PRInt32 copyLoop;
|
|
|
|
offset = offset < 0 ? 0 : offset;
|
|
|
|
if (offset < strLength)
|
|
{
|
|
moveLoop = strLength - offset;
|
|
moveIndex = strLength - 1;
|
|
|
|
//Enlarge string buffer to fit source character
|
|
ensureCapacity(sourceLength);
|
|
|
|
//Bump all characters down to make room for new character
|
|
while (moveLoop--)
|
|
strBuffer[moveIndex+sourceLength] = strBuffer[moveIndex--];
|
|
|
|
moveIndex += 1;
|
|
for (copyLoop=0;copyLoop<sourceLength;copyLoop++)
|
|
strBuffer[moveIndex+copyLoop] = source[copyLoop];
|
|
|
|
strLength += sourceLength;
|
|
}
|
|
else
|
|
append(source, sourceLength);
|
|
}
|
|
|
|
//
|
|
//Convert source from an integer to a string, and then insert.
|
|
//
|
|
void String::insert(PRInt32 offset, PRInt32 source)
|
|
{
|
|
String convertString;
|
|
|
|
insert(offset, ConvertInt(source, convertString));
|
|
}
|
|
|
|
//
|
|
//Replace the character specified by offset with the UNICODE_CHAR source
|
|
//
|
|
void String::replace(PRInt32 offset, const UNICODE_CHAR source)
|
|
{
|
|
offset = offset < 0 ? 0 : offset;
|
|
|
|
if (offset < strLength)
|
|
{
|
|
strBuffer[offset] = source;
|
|
}
|
|
else
|
|
append(source);
|
|
}
|
|
|
|
//
|
|
//Replace the character specified by offset with the C style character source
|
|
//
|
|
void String::replace(PRInt32 offset, const char source)
|
|
{
|
|
replace(offset, (UNICODE_CHAR)source);
|
|
}
|
|
|
|
//
|
|
//Replace the substring starting at offset with the String specified by source.
|
|
//Enlarge the string buffer if source will require more characters than
|
|
//currently available.
|
|
//TK 12/09/1999 - Modified to use the "source" String's public interface only,
|
|
// to ensure compatibility with classes derived from String
|
|
//
|
|
void String::replace(PRInt32 offset, const String& source)
|
|
{
|
|
PRInt32 totalOffset = 0;
|
|
PRInt32 replaceLoop;
|
|
|
|
if (offset < strLength)
|
|
{
|
|
offset = offset < 0 ? 0 : offset;
|
|
totalOffset = offset + source.length();
|
|
|
|
if (totalOffset > strLength)
|
|
{
|
|
ensureCapacity(totalOffset - strLength);
|
|
strLength += totalOffset - strLength;
|
|
}
|
|
|
|
for (replaceLoop=0;replaceLoop<source.length();replaceLoop++)
|
|
strBuffer[offset + replaceLoop] = source.charAt(replaceLoop);
|
|
}
|
|
else
|
|
append(source);
|
|
}
|
|
|
|
//
|
|
//Replace the substring starting at offset with the "C" style character string.
|
|
//enlarge the string buffer if source will require more characters than
|
|
//currently available.
|
|
//
|
|
void String::replace(PRInt32 offset, const char* source)
|
|
{
|
|
PRInt32 totalOffset = 0;
|
|
PRInt32 replaceLoop;
|
|
PRInt32 sourceLength;
|
|
|
|
if (offset < strLength)
|
|
{
|
|
offset = offset < 0 ? 0 : offset;
|
|
sourceLength = strlen(source);
|
|
totalOffset = offset + sourceLength;
|
|
|
|
if (totalOffset > strLength)
|
|
{
|
|
ensureCapacity(totalOffset - strLength);
|
|
strLength += totalOffset - strLength;
|
|
}
|
|
|
|
for (replaceLoop=0;replaceLoop<sourceLength;replaceLoop++)
|
|
strBuffer[offset + replaceLoop] = source[replaceLoop];
|
|
}
|
|
else
|
|
append(source);
|
|
}
|
|
|
|
//
|
|
//Replace the substring starting at offset with the Unicode string.
|
|
//enlarge the string buffer if source will require more characters than
|
|
//currently available.
|
|
//TK 12/21/1999 - Simply deffer functionality to the replace function
|
|
// below (accepting a length for the Unicode buffer).
|
|
//
|
|
void String::replace(PRInt32 offset, const UNICODE_CHAR* source)
|
|
{
|
|
replace(offset, source, UnicodeLength(source));
|
|
}
|
|
|
|
//
|
|
//Replace the substring starting at offset with the Unicode string.
|
|
//enlarge the string buffer if source will require more characters than
|
|
//currently available.
|
|
//
|
|
void String::replace(PRInt32 offset, const UNICODE_CHAR* source, PRInt32 srcLength)
|
|
{
|
|
PRInt32 totalOffset = 0;
|
|
PRInt32 replaceLoop;
|
|
|
|
if (offset < strLength)
|
|
{
|
|
offset = offset < 0 ? 0 : offset;
|
|
totalOffset = offset + srcLength;
|
|
|
|
if (totalOffset > strLength)
|
|
{
|
|
ensureCapacity(totalOffset - strLength);
|
|
strLength += totalOffset - strLength;
|
|
}
|
|
|
|
for (replaceLoop=0;replaceLoop<srcLength;replaceLoop++)
|
|
strBuffer[offset + replaceLoop] = source[replaceLoop];
|
|
}
|
|
else
|
|
append(source);
|
|
}
|
|
|
|
|
|
//
|
|
//Convert source from an integer to a String, and perform a replacement.
|
|
//
|
|
void String::replace(PRInt32 offset, PRInt32 source)
|
|
{
|
|
String convertString;
|
|
|
|
replace(offset, ConvertInt(source, convertString));
|
|
}
|
|
|
|
/**
|
|
* Sets the Length of this String, if length is less than 0, it will
|
|
* be set to 0; if length > current length, the string will be extended
|
|
* and padded with '\0' null characters. Otherwise the String
|
|
* will be truncated
|
|
**/
|
|
void String::setLength(PRInt32 length) {
|
|
setLength(length, '\0');
|
|
} //-- setLength
|
|
|
|
/**
|
|
* Sets the Length of this String, if length is less than 0, it will
|
|
* be set to 0; if length > current length, the string will be extended
|
|
* and padded with given pad character. Otherwise the String
|
|
* will be truncated
|
|
**/
|
|
void String::setLength(PRInt32 length, UNICODE_CHAR padChar) {
|
|
if ( length < 0 ) strLength = 0;
|
|
else if ( length > strLength ) {
|
|
PRInt32 diff = length-strLength;
|
|
ensureCapacity(diff);
|
|
for ( PRInt32 i = strLength; i < length; i++ )
|
|
strBuffer[i] = padChar;
|
|
strLength = length;
|
|
}
|
|
else strLength = length;
|
|
} //-- setLength
|
|
|
|
//
|
|
//Delete the "substring" starting at "offset" and proceeding for "count" number
|
|
//of characters (or until the end of the string, whichever comes first).
|
|
//
|
|
void String::deleteChars(PRInt32 offset, PRInt32 count)
|
|
{
|
|
PRInt32 deleteLoop;
|
|
PRInt32 offsetCount;
|
|
|
|
offset = offset < 0 ? 0 : offset;
|
|
offsetCount = offset + count;
|
|
|
|
if (offsetCount < strLength)
|
|
{
|
|
for (deleteLoop=0;deleteLoop<strLength-offsetCount;deleteLoop++)
|
|
strBuffer[offset + deleteLoop] = strBuffer[offsetCount + deleteLoop];
|
|
|
|
strLength -= count;
|
|
}
|
|
else
|
|
strLength = offset;
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns the character at index.
|
|
* If the index is out of bounds, -1 will be returned.
|
|
**/
|
|
UNICODE_CHAR String::charAt(PRInt32 index) const
|
|
{
|
|
if ((index < strLength) && (index >= 0))
|
|
return strBuffer[index];
|
|
else
|
|
return (UNICODE_CHAR)-1;
|
|
}
|
|
|
|
//
|
|
//Clear out the string by simply setting the length to zero. The buffer is
|
|
//left intact.
|
|
//
|
|
void String::clear()
|
|
{
|
|
strLength = 0;
|
|
}
|
|
|
|
//
|
|
//Make sure the buffer has room for 'capacity' UNICODE_CHARS.
|
|
//
|
|
void String::ensureCapacity(PRInt32 capacity)
|
|
{
|
|
UNICODE_CHAR* tempStrBuffer = NULL;
|
|
|
|
//Check for the desired capacity
|
|
PRInt32 freeSpace = bufferLength - strLength; //(added by kvisco)
|
|
|
|
if (freeSpace < capacity) {
|
|
|
|
//-- modified by kvisco to only add needed capacity,
|
|
//-- not extra bytes as before
|
|
//-- old : bufferLength += capacity;
|
|
bufferLength += capacity - freeSpace;
|
|
|
|
tempStrBuffer = new UNICODE_CHAR[bufferLength];
|
|
copyString(tempStrBuffer);
|
|
|
|
//If the old string contained any data, delete it, and save the new.
|
|
if (strBuffer)
|
|
delete strBuffer;
|
|
|
|
strBuffer = tempStrBuffer;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Performs a CASE SENSITIVE search of the string for the first occurence
|
|
* of 'data'. If found return the index, else return NOT_FOUND.
|
|
* -- changed by kvisco to call indexOf(UNICODE_CHAR, PRInt32)
|
|
**/
|
|
PRInt32 String::indexOf(UNICODE_CHAR data) const
|
|
{
|
|
return indexOf(data, 0);
|
|
} //-- indexOf
|
|
|
|
//
|
|
//Starting at 'offset' perform a CASE SENSITIVE search of the string looking
|
|
//for the first occurence of 'data'. If found return the index, else return
|
|
//NOT_FOUND. If the offset is less than zero, then start at zero.
|
|
//
|
|
PRInt32 String::indexOf(UNICODE_CHAR data, PRInt32 offset) const
|
|
{
|
|
PRInt32 searchIndex = offset < 0 ? searchIndex = 0 : searchIndex = offset;
|
|
|
|
while (1)
|
|
{
|
|
if (searchIndex >= strLength)
|
|
return NOT_FOUND;
|
|
else if (strBuffer[searchIndex] == data)
|
|
return searchIndex;
|
|
else
|
|
++searchIndex;
|
|
}
|
|
} //-- indexOf
|
|
|
|
//
|
|
//Returns the index of the first occurence of data
|
|
//TK 12/09/1999 - Modified to simply use indexOf(const String&, PRInt32).
|
|
//
|
|
PRInt32 String::indexOf(const String& data) const
|
|
{
|
|
return indexOf(data, 0);
|
|
}
|
|
|
|
//
|
|
//Returns the index of the first occurrence of data starting at offset
|
|
//TK 12/09/1999 - Modified to use the "data" String's public interface to
|
|
// retreive the Unicode Char buffer when calling isEqual.
|
|
// This ensures compatibility with classes derrived from String.
|
|
//
|
|
PRInt32 String::indexOf(const String& data, PRInt32 offset) const
|
|
{
|
|
PRInt32 searchIndex = offset < 0 ? 0 : offset;
|
|
|
|
while (1)
|
|
{
|
|
if (searchIndex <= (strLength - data.length()))
|
|
{
|
|
if (isEqual(&strBuffer[searchIndex], data.toUnicode(), data.length()))
|
|
return searchIndex;
|
|
}
|
|
else
|
|
return NOT_FOUND;
|
|
|
|
searchIndex++;
|
|
}
|
|
}
|
|
|
|
//
|
|
//Check for equality between this string, and data
|
|
//TK 12/09/1999 - Modified to use data.toUnicode() public member function
|
|
// when working with data's unicode buffer. This ensures
|
|
// compatibility with derrived classes.
|
|
//
|
|
MBool String::isEqual(const String& data) const
|
|
{
|
|
if (strLength != data.length())
|
|
return MB_FALSE;
|
|
return isEqual(strBuffer, data.toUnicode(), data.length());
|
|
}
|
|
|
|
MBool String::isEqualIgnoreCase(const String& data) const
|
|
{
|
|
if (strLength != data.length())
|
|
return MB_FALSE;
|
|
|
|
const UNICODE_CHAR* otherBuffer = data.strBuffer;
|
|
UNICODE_CHAR thisChar, otherChar;
|
|
PRInt32 compLoop = 0;
|
|
while (compLoop < strLength) {
|
|
thisChar = strBuffer[compLoop];
|
|
if ((thisChar >= 'A') && (thisChar <= 'Z'))
|
|
thisChar += 32;
|
|
otherChar = otherBuffer[compLoop];
|
|
if ((otherChar >= 'A') && (otherChar <= 'Z'))
|
|
otherChar += 32;
|
|
if (thisChar != otherChar)
|
|
return MB_FALSE;
|
|
++compLoop;
|
|
}
|
|
return MB_TRUE;
|
|
}
|
|
|
|
/**
|
|
* Returns index of last occurrence of data
|
|
**/
|
|
PRInt32 String::lastIndexOf(UNICODE_CHAR data) const
|
|
{
|
|
return lastIndexOf(data, strLength-1);
|
|
} //-- lastIndexOf
|
|
|
|
/**
|
|
* Returns the index of the last occurrence of data starting at offset
|
|
**/
|
|
PRInt32 String::lastIndexOf(UNICODE_CHAR data, PRInt32 offset) const
|
|
{
|
|
if ((offset < 0) || (offset >= strLength)) return NOT_FOUND;
|
|
|
|
PRInt32 searchIndex = offset;
|
|
while (searchIndex >= 0) {
|
|
if (strBuffer[searchIndex] == data) return searchIndex;
|
|
--searchIndex;
|
|
}
|
|
return NOT_FOUND;
|
|
|
|
} //-- lastIndexOf
|
|
|
|
/**
|
|
* Returns the index of the last occurrence of data
|
|
**/
|
|
PRInt32 String::lastIndexOf(const String& data) const
|
|
{
|
|
return lastIndexOf(data, strLength-1);
|
|
} //-- lastIndexOf
|
|
|
|
/**
|
|
* Returns the index of the last occurrence of data starting at offset
|
|
**/
|
|
PRInt32 String::lastIndexOf(const String& data, PRInt32 offset) const
|
|
{
|
|
PRInt32 searchIndex;
|
|
const UNICODE_CHAR* dataStrBuffer = NULL;
|
|
|
|
if ((offset < 0) || (offset >= strLength))
|
|
return NOT_FOUND;
|
|
else
|
|
{
|
|
searchIndex = offset;
|
|
|
|
//If there is not enough space between searchIndex and the length of the of
|
|
//the string for "data" to appear, then there is no reason to search it.
|
|
if ((strLength - searchIndex) < data.length())
|
|
searchIndex = strLength - data.length();
|
|
|
|
dataStrBuffer = data.toUnicode();
|
|
while (searchIndex >= 0)
|
|
{
|
|
if (isEqual(&strBuffer[searchIndex], data.toUnicode(), data.length()))
|
|
return searchIndex;
|
|
--searchIndex;
|
|
}
|
|
}
|
|
return NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
//Checks whether the string is empty
|
|
//
|
|
MBool String::isEmpty() const
|
|
{
|
|
return (strLength == 0);
|
|
}
|
|
|
|
//
|
|
//Returns the length of the String
|
|
//
|
|
PRInt32 String::length() const
|
|
{
|
|
return strLength;
|
|
}
|
|
|
|
//
|
|
//Returns a subString starting at start
|
|
//TK 12/09/1999 - Modified to simply use subString(PRInt32, PRInt32, String&)
|
|
//
|
|
String& String::subString(PRInt32 start, String& dest) const
|
|
{
|
|
return subString(start, strLength, dest);
|
|
}
|
|
|
|
/**
|
|
* Returns the subString starting at start and ending at end
|
|
* Note: the dest String is cleared before use
|
|
* TK 12/09/1999 - Modified to use the "dest" String's public interface to
|
|
* ensure compatibility wtih derrived classes.
|
|
**/
|
|
String& String::subString(PRInt32 start, PRInt32 end, String& dest) const
|
|
{
|
|
PRInt32 srcLoop;
|
|
|
|
start = start < 0 ? 0 : start;
|
|
end = end > strLength ? strLength : end;
|
|
|
|
dest.clear();
|
|
if (start < end)
|
|
{
|
|
dest.ensureCapacity(end - start);
|
|
for (srcLoop=start;srcLoop<end;srcLoop++)
|
|
dest.append(strBuffer[srcLoop]);
|
|
}
|
|
|
|
return dest;
|
|
}
|
|
|
|
/**
|
|
* Instantiate a new character buffer (remembering the null terminator) and pass
|
|
* it to toChar(char*).
|
|
**/
|
|
char* String::toCharArray() const
|
|
{
|
|
char* tmpBuffer = new char[strLength+1];
|
|
|
|
NS_ASSERTION(tmpBuffer, "out of memory");
|
|
|
|
return toCharArray(tmpBuffer);
|
|
}
|
|
|
|
/**
|
|
* Convert the internally represented string to a character buffer. Store
|
|
* the resultant character array in the buffer provided by the caller. A
|
|
* null terminator will be placed at the end of the array, make sure
|
|
* space has been provided.
|
|
**/
|
|
char* String::toCharArray(char* dest) const
|
|
{
|
|
if (!dest)
|
|
return 0;
|
|
|
|
PRInt32 copyLoop;
|
|
|
|
for (copyLoop = 0; copyLoop < strLength; copyLoop++)
|
|
dest[copyLoop] = (char)strBuffer[copyLoop];
|
|
|
|
//Place a NULL terminator at the end of the character buffer
|
|
dest[copyLoop] = 0;
|
|
|
|
return dest;
|
|
}
|
|
|
|
/**
|
|
* Returns the internal UNICODE_CHAR array so the caller can have access to the
|
|
* to the UNICODE_CHAR representation of the string. Will not place a null
|
|
* terminator at the end of the array, as in a call to toChar will do.
|
|
**/
|
|
UNICODE_CHAR* String::toUnicode(UNICODE_CHAR* dest) const
|
|
{
|
|
PRInt32 copyLoop;
|
|
|
|
for (copyLoop=0;copyLoop<strLength;copyLoop++)
|
|
dest[copyLoop] = strBuffer[copyLoop];
|
|
|
|
//-- removed null terminator at end (kvisco)
|
|
return dest;
|
|
}
|
|
|
|
//
|
|
//This fuction returns the actual UNICODE_CHAR* buffer storing the string.
|
|
//This provides a more efficient means to interact with the buffer in a read
|
|
//only fahsion.
|
|
//
|
|
const UNICODE_CHAR* String::toUnicode() const
|
|
{
|
|
return strBuffer;
|
|
}
|
|
|
|
//
|
|
//Convert String to lowercase
|
|
//
|
|
void String::toLowerCase()
|
|
{
|
|
PRInt32 conversionLoop;
|
|
|
|
for (conversionLoop=0;conversionLoop<strLength;conversionLoop++)
|
|
{
|
|
if ((strBuffer[conversionLoop] >= 'A') &&
|
|
(strBuffer[conversionLoop] <= 'Z'))
|
|
strBuffer[conversionLoop] += 32;
|
|
}
|
|
}
|
|
|
|
//
|
|
//Convert String to uppercase
|
|
//
|
|
void String::toUpperCase()
|
|
{
|
|
PRInt32 conversionLoop;
|
|
|
|
for (conversionLoop=0;conversionLoop<strLength;conversionLoop++)
|
|
{
|
|
if ((strBuffer[conversionLoop] >= 'a') &&
|
|
(strBuffer[conversionLoop] <= 'z'))
|
|
strBuffer[conversionLoop] -= 32;
|
|
}
|
|
}
|
|
|
|
//
|
|
//Trim whitespace from both ends of String
|
|
//
|
|
void String::trim()
|
|
{
|
|
PRInt32 trimLoop = strLength - 1;
|
|
PRInt32 cutLoop;
|
|
MBool done = MB_FALSE;
|
|
|
|
//As long as we are not working on an emtpy string, trim from the right
|
|
//first, so we don't have to move useless spaces when we trim from the left.
|
|
if (strLength > 0)
|
|
{
|
|
while (!done)
|
|
{
|
|
switch (strBuffer[trimLoop])
|
|
{
|
|
case ' ' :
|
|
case '\t' :
|
|
case '\n' :
|
|
case '\r' :
|
|
--strLength;
|
|
--trimLoop;
|
|
break;
|
|
|
|
default :
|
|
done = MB_TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//Now, if there are any characters left to the string, Trim to the left.
|
|
//First count the number of "left" spaces. Then move all characters to the
|
|
//left by that ammount.
|
|
if (strLength > 0)
|
|
{
|
|
done = MB_FALSE;
|
|
trimLoop = 0;
|
|
while (!done)
|
|
{
|
|
switch (strBuffer[trimLoop])
|
|
{
|
|
case ' ' :
|
|
case '\t' :
|
|
case '\n' :
|
|
case '\r' :
|
|
++trimLoop;
|
|
break;
|
|
|
|
default :
|
|
done = MB_TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (trimLoop < strLength)
|
|
{
|
|
for (cutLoop=trimLoop;cutLoop<strLength;cutLoop++)
|
|
strBuffer[cutLoop-trimLoop] = strBuffer[cutLoop];
|
|
}
|
|
|
|
strLength -= trimLoop;
|
|
}
|
|
}
|
|
|
|
//
|
|
//Cause the string to reverse itself
|
|
//
|
|
void String::reverse()
|
|
{
|
|
PRInt32 reverseLoop;
|
|
UNICODE_CHAR tempChar;
|
|
|
|
for (reverseLoop=0;reverseLoop<(strLength/2); reverseLoop++)
|
|
{
|
|
tempChar = strBuffer[reverseLoop];
|
|
strBuffer[reverseLoop] = strBuffer[strLength - reverseLoop - 1];
|
|
strBuffer[strLength - reverseLoop - 1] = tempChar;
|
|
}
|
|
}
|
|
|
|
//
|
|
//String copies itself to the destination
|
|
//
|
|
void String::copyString(UNICODE_CHAR* dest)
|
|
{
|
|
PRInt32 copyLoop;
|
|
|
|
for (copyLoop=0;copyLoop<strLength;copyLoop++)
|
|
dest[copyLoop] = strBuffer[copyLoop];
|
|
}
|
|
|
|
//
|
|
//Compare the two string representations for equality
|
|
//
|
|
MBool String::isEqual(const UNICODE_CHAR* data, const UNICODE_CHAR* search,
|
|
PRInt32 length) const
|
|
{
|
|
PRInt32 compLoop = 0;
|
|
|
|
while (compLoop < length)
|
|
{
|
|
if (data[compLoop] != search[compLoop])
|
|
return MB_FALSE;
|
|
|
|
compLoop++;
|
|
}
|
|
|
|
return MB_TRUE;
|
|
}
|
|
|
|
//
|
|
//Convert an PRInt32 into a String by storing it in target
|
|
//
|
|
String& String::ConvertInt(PRInt32 value, String& target)
|
|
{
|
|
UNICODE_CHAR charDigit;
|
|
|
|
target.clear();
|
|
|
|
while (value)
|
|
{
|
|
charDigit = (value % 10) + 48;
|
|
target.append(charDigit);
|
|
value /=10;
|
|
}
|
|
|
|
target.reverse();
|
|
|
|
return target;
|
|
}
|
|
|
|
//
|
|
//Calculate the length of a null terminated UNICODE_CHAR string
|
|
//
|
|
PRInt32 String::UnicodeLength(const UNICODE_CHAR* data)
|
|
{
|
|
PRInt32 index = 0;
|
|
|
|
//Count UNICODE_CHARs Until a Unicode "NULL" is found.
|
|
while (data[index] != 0x0000)
|
|
index++;
|
|
|
|
return index;
|
|
}
|