/* -*- 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 * Larry Fitzpatrick * */ #include #include #include "TxString.h" #include // //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) { ensureCapacity(totalOffset - strLength); strLength += totalOffset - strLength; } for (replaceLoop=0;replaceLoop strLength) { ensureCapacity(totalOffset - strLength); strLength += totalOffset - strLength; } for (replaceLoop=0;replaceLoop strLength) { ensureCapacity(totalOffset - strLength); strLength += totalOffset - strLength; } for (replaceLoop=0;replaceLoop 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= 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= 'A') && (strBuffer[conversionLoop] <= 'Z')) strBuffer[conversionLoop] += 32; } } // //Convert String to uppercase // void String::toUpperCase() { PRInt32 conversionLoop; for (conversionLoop=0;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