michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim:set ts=2 sw=2 sts=2 et cindent: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsString.h" michael@0: michael@0: michael@0: /** michael@0: * nsTString obsolete API support michael@0: */ michael@0: michael@0: #if MOZ_STRING_WITH_OBSOLETE_API michael@0: michael@0: #include "nsDependentString.h" michael@0: #include "nsDependentSubstring.h" michael@0: #include "nsReadableUtils.h" michael@0: #include "nsCRT.h" michael@0: #include "nsUTF8Utils.h" michael@0: #include "prdtoa.h" michael@0: michael@0: /* ***** BEGIN RICKG BLOCK ***** michael@0: * michael@0: * NOTE: This section of code was extracted from rickg's bufferRoutines.h file. michael@0: * For the most part it remains unmodified. We want to eliminate (or at michael@0: * least clean up) this code at some point. If you find the formatting michael@0: * in this section somewhat inconsistent, don't blame me! ;-) michael@0: */ michael@0: michael@0: // avoid STDC's tolower since it may do weird things with non-ASCII bytes michael@0: inline char michael@0: ascii_tolower(char aChar) michael@0: { michael@0: if (aChar >= 'A' && aChar <= 'Z') michael@0: return aChar + ('a' - 'A'); michael@0: return aChar; michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // michael@0: // This set of methods is used to search a buffer looking for a char. michael@0: // michael@0: michael@0: michael@0: /** michael@0: * This methods cans the given buffer for the given char michael@0: * michael@0: * @update gess 02/17/00 michael@0: * @param aDest is the buffer to be searched michael@0: * @param aDestLength is the size (in char-units, not bytes) of the buffer michael@0: * @param anOffset is the start pos to begin searching michael@0: * @param aChar is the target character we're looking for michael@0: * @param aCount tells us how many characters to iterate through (which may be different than aLength); -1 means use full length. michael@0: * @return index of pos if found, else -1 (kNotFound) michael@0: */ michael@0: static int32_t michael@0: FindChar1(const char* aDest,uint32_t aDestLength,int32_t anOffset,const char16_t aChar,int32_t aCount) { michael@0: michael@0: if(anOffset < 0) michael@0: anOffset=0; michael@0: michael@0: if(aCount < 0) michael@0: aCount = (int32_t)aDestLength; michael@0: michael@0: if((aChar < 256) && (0 < aDestLength) && ((uint32_t)anOffset < aDestLength)) { michael@0: michael@0: //We'll only search if the given aChar is within the normal ascii a range, michael@0: //(Since this string is definitely within the ascii range). michael@0: michael@0: if(0 michael@0: */ michael@0: static michael@0: #ifdef __SUNPRO_CC michael@0: inline michael@0: #endif /* __SUNPRO_CC */ michael@0: int32_t michael@0: Compare1To1(const char* aStr1,const char* aStr2,uint32_t aCount,bool aIgnoreCase){ michael@0: int32_t result=0; michael@0: if(aIgnoreCase) michael@0: result=int32_t(PL_strncasecmp(aStr1, aStr2, aCount)); michael@0: else michael@0: result=nsCharTraits::compare(aStr1,aStr2,aCount); michael@0: michael@0: // alien comparisons may return out-of-bound answers michael@0: // instead of the -1, 0, 1 expected by most clients michael@0: if ( result < -1 ) michael@0: result = -1; michael@0: else if ( result > 1 ) michael@0: result = 1; michael@0: return result; michael@0: } michael@0: michael@0: /** michael@0: * This method compares the data in one buffer with another michael@0: * @update gess 01/04/99 michael@0: * @param aStr1 is the first buffer to be compared michael@0: * @param aStr2 is the 2nd buffer to be compared michael@0: * @param aCount is the number of chars to compare michael@0: * @param aIgnoreCase tells us whether to use a case-sensitive comparison michael@0: * @return -1,0,1 depending on <,==,> michael@0: */ michael@0: static michael@0: #ifdef __SUNPRO_CC michael@0: inline michael@0: #endif /* __SUNPRO_CC */ michael@0: int32_t michael@0: Compare2To2(const char16_t* aStr1,const char16_t* aStr2,uint32_t aCount){ michael@0: int32_t result; michael@0: michael@0: if ( aStr1 && aStr2 ) michael@0: result = nsCharTraits::compare(aStr1, aStr2, aCount); michael@0: michael@0: // The following cases are rare and survivable caller errors. michael@0: // Two null pointers are equal, but any string, even 0 length michael@0: // is greater than a null pointer. It might not really matter, michael@0: // but we pick something reasonable anyway. michael@0: else if ( !aStr1 && !aStr2 ) michael@0: result = 0; michael@0: else if ( aStr1 ) michael@0: result = 1; michael@0: else michael@0: result = -1; michael@0: michael@0: // alien comparisons may give answers outside the -1, 0, 1 expected by callers michael@0: if ( result < -1 ) michael@0: result = -1; michael@0: else if ( result > 1 ) michael@0: result = 1; michael@0: return result; michael@0: } michael@0: michael@0: michael@0: /** michael@0: * This method compares the data in one buffer with another michael@0: * @update gess 01/04/99 michael@0: * @param aStr1 is the first buffer to be compared michael@0: * @param aStr2 is the 2nd buffer to be compared michael@0: * @param aCount is the number of chars to compare michael@0: * @param aIgnoreCase tells us whether to use a case-sensitive comparison michael@0: * @return -1,0,1 depending on <,==,> michael@0: */ michael@0: static michael@0: #ifdef __SUNPRO_CC michael@0: inline michael@0: #endif /* __SUNPRO_CC */ michael@0: int32_t michael@0: Compare2To1(const char16_t* aStr1,const char* aStr2,uint32_t aCount,bool aIgnoreCase){ michael@0: const char16_t* s1 = aStr1; michael@0: const char *s2 = aStr2; michael@0: michael@0: if (aStr1 && aStr2) { michael@0: if (aCount != 0) { michael@0: do { michael@0: michael@0: char16_t c1 = *s1++; michael@0: char16_t c2 = char16_t((unsigned char)*s2++); michael@0: michael@0: if (c1 != c2) { michael@0: #ifdef DEBUG michael@0: // we won't warn on c1>=128 (the 2-byte value) because often michael@0: // it is just fine to compare an constant, ascii value (i.e. "body") michael@0: // against some non-ascii value (i.e. a unicode string that michael@0: // was downloaded from a web page) michael@0: if (aIgnoreCase && c2>=128) michael@0: NS_WARNING("got a non-ASCII string, but we can't do an accurate case conversion!"); michael@0: #endif michael@0: michael@0: // can't do case conversion on characters out of our range michael@0: if (aIgnoreCase && c1<128 && c2<128) { michael@0: michael@0: c1 = ascii_tolower(char(c1)); michael@0: c2 = ascii_tolower(char(c2)); michael@0: michael@0: if (c1 == c2) continue; michael@0: } michael@0: michael@0: if (c1 < c2) return -1; michael@0: return 1; michael@0: } michael@0: } while (--aCount); michael@0: } michael@0: } michael@0: return 0; michael@0: } michael@0: michael@0: michael@0: /** michael@0: * This method compares the data in one buffer with another michael@0: * @update gess 01/04/99 michael@0: * @param aStr1 is the first buffer to be compared michael@0: * @param aStr2 is the 2nd buffer to be compared michael@0: * @param aCount is the number of chars to compare michael@0: * @param aIgnoreCase tells us whether to use a case-sensitive comparison michael@0: * @return -1,0,1 depending on <,==,> michael@0: */ michael@0: inline int32_t michael@0: Compare1To2(const char* aStr1,const char16_t* aStr2,uint32_t aCount,bool aIgnoreCase){ michael@0: return Compare2To1(aStr2, aStr1, aCount, aIgnoreCase) * -1; michael@0: } michael@0: michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // michael@0: // This set of methods is used compress char sequences in a buffer... michael@0: // michael@0: michael@0: michael@0: /** michael@0: * This method compresses duplicate runs of a given char from the given buffer michael@0: * michael@0: * @update rickg 03.23.2000 michael@0: * @param aString is the buffer to be manipulated michael@0: * @param aLength is the length of the buffer michael@0: * @param aSet tells us which chars to compress from given buffer michael@0: * @param aEliminateLeading tells us whether to strip chars from the start of the buffer michael@0: * @param aEliminateTrailing tells us whether to strip chars from the start of the buffer michael@0: * @return the new length of the given buffer michael@0: */ michael@0: static int32_t michael@0: CompressChars1(char* aString,uint32_t aLength,const char* aSet){ michael@0: michael@0: char* from = aString; michael@0: char* end = aString + aLength; michael@0: char* to = from; michael@0: michael@0: //this code converts /n, /t, /r into normal space ' '; michael@0: //it also compresses runs of whitespace down to a single char... michael@0: if(aSet && aString && (0 < aLength)){ michael@0: uint32_t aSetLen=strlen(aSet); michael@0: michael@0: while (from < end) { michael@0: char theChar = *from++; michael@0: michael@0: *to++=theChar; //always copy this char... michael@0: michael@0: if((kNotFound!=FindChar1(aSet,aSetLen,0,theChar,aSetLen))){ michael@0: while (from < end) { michael@0: theChar = *from++; michael@0: if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen)){ michael@0: *to++ = theChar; michael@0: break; michael@0: } michael@0: } //while michael@0: } //if michael@0: } //if michael@0: *to = 0; michael@0: } michael@0: return to - aString; michael@0: } michael@0: michael@0: michael@0: michael@0: /** michael@0: * This method compresses duplicate runs of a given char from the given buffer michael@0: * michael@0: * @update rickg 03.23.2000 michael@0: * @param aString is the buffer to be manipulated michael@0: * @param aLength is the length of the buffer michael@0: * @param aSet tells us which chars to compress from given buffer michael@0: * @param aEliminateLeading tells us whether to strip chars from the start of the buffer michael@0: * @param aEliminateTrailing tells us whether to strip chars from the start of the buffer michael@0: * @return the new length of the given buffer michael@0: */ michael@0: static int32_t michael@0: CompressChars2(char16_t* aString,uint32_t aLength,const char* aSet){ michael@0: michael@0: char16_t* from = aString; michael@0: char16_t* end = from + aLength; michael@0: char16_t* to = from; michael@0: michael@0: //this code converts /n, /t, /r into normal space ' '; michael@0: //it also compresses runs of whitespace down to a single char... michael@0: if(aSet && aString && (0 < aLength)){ michael@0: uint32_t aSetLen=strlen(aSet); michael@0: michael@0: while (from < end) { michael@0: char16_t theChar = *from++; michael@0: michael@0: *to++=theChar; //always copy this char... michael@0: michael@0: if((theChar<256) && (kNotFound!=FindChar1(aSet,aSetLen,0,theChar,aSetLen))){ michael@0: while (from < end) { michael@0: theChar = *from++; michael@0: if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen)){ michael@0: *to++ = theChar; michael@0: break; michael@0: } michael@0: } //while michael@0: } //if michael@0: } //if michael@0: *to = 0; michael@0: } michael@0: return to - (char16_t*)aString; michael@0: } michael@0: michael@0: /** michael@0: * This method strips chars in a given set from the given buffer michael@0: * michael@0: * @update gess 01/04/99 michael@0: * @param aString is the buffer to be manipulated michael@0: * @param aLength is the length of the buffer michael@0: * @param aSet tells us which chars to compress from given buffer michael@0: * @param aEliminateLeading tells us whether to strip chars from the start of the buffer michael@0: * @param aEliminateTrailing tells us whether to strip chars from the start of the buffer michael@0: * @return the new length of the given buffer michael@0: */ michael@0: static int32_t michael@0: StripChars1(char* aString,uint32_t aLength,const char* aSet){ michael@0: michael@0: // XXX(darin): this code should defer writing until necessary. michael@0: michael@0: char* to = aString; michael@0: char* from = aString-1; michael@0: char* end = aString + aLength; michael@0: michael@0: if(aSet && aString && (0 < aLength)){ michael@0: uint32_t aSetLen=strlen(aSet); michael@0: while (++from < end) { michael@0: char theChar = *from; michael@0: if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen)){ michael@0: *to++ = theChar; michael@0: } michael@0: } michael@0: *to = 0; michael@0: } michael@0: return to - (char*)aString; michael@0: } michael@0: michael@0: michael@0: /** michael@0: * This method strips chars in a given set from the given buffer michael@0: * michael@0: * @update gess 01/04/99 michael@0: * @param aString is the buffer to be manipulated michael@0: * @param aLength is the length of the buffer michael@0: * @param aSet tells us which chars to compress from given buffer michael@0: * @param aEliminateLeading tells us whether to strip chars from the start of the buffer michael@0: * @param aEliminateTrailing tells us whether to strip chars from the start of the buffer michael@0: * @return the new length of the given buffer michael@0: */ michael@0: static int32_t michael@0: StripChars2(char16_t* aString,uint32_t aLength,const char* aSet){ michael@0: michael@0: // XXX(darin): this code should defer writing until necessary. michael@0: michael@0: char16_t* to = aString; michael@0: char16_t* from = aString-1; michael@0: char16_t* end = to + aLength; michael@0: michael@0: if(aSet && aString && (0 < aLength)){ michael@0: uint32_t aSetLen=strlen(aSet); michael@0: while (++from < end) { michael@0: char16_t theChar = *from; michael@0: //Note the test for ascii range below. If you have a real unicode char, michael@0: //and you're searching for chars in the (given) ascii string, there's no michael@0: //point in doing the real search since it's out of the ascii range. michael@0: if((255 michael@0: #ifndef __SUNPRO_CC michael@0: static michael@0: #endif /* !__SUNPRO_CC */ michael@0: CharT michael@0: GetFindInSetFilter( const CharT* set) michael@0: { michael@0: CharT filter = ~CharT(0); // All bits set michael@0: while (*set) { michael@0: filter &= ~(*set); michael@0: ++set; michael@0: } michael@0: return filter; michael@0: } michael@0: michael@0: // This template class is used by our code to access rickg's buffer routines. michael@0: template struct nsBufferRoutines {}; michael@0: michael@0: template <> michael@0: struct nsBufferRoutines michael@0: { michael@0: static michael@0: int32_t compare( const char* a, const char* b, uint32_t max, bool ic ) michael@0: { michael@0: return Compare1To1(a, b, max, ic); michael@0: } michael@0: michael@0: static michael@0: int32_t compare( const char* a, const char16_t* b, uint32_t max, bool ic ) michael@0: { michael@0: return Compare1To2(a, b, max, ic); michael@0: } michael@0: michael@0: static michael@0: int32_t find_char( const char* s, uint32_t max, int32_t offset, const char16_t c, int32_t count ) michael@0: { michael@0: return FindChar1(s, max, offset, c, count); michael@0: } michael@0: michael@0: static michael@0: int32_t rfind_char( const char* s, uint32_t max, int32_t offset, const char16_t c, int32_t count ) michael@0: { michael@0: return RFindChar1(s, max, offset, c, count); michael@0: } michael@0: michael@0: static michael@0: char get_find_in_set_filter( const char* set ) michael@0: { michael@0: return GetFindInSetFilter(set); michael@0: } michael@0: michael@0: static michael@0: int32_t strip_chars( char* s, uint32_t len, const char* set ) michael@0: { michael@0: return StripChars1(s, len, set); michael@0: } michael@0: michael@0: static michael@0: int32_t compress_chars( char* s, uint32_t len, const char* set ) michael@0: { michael@0: return CompressChars1(s, len, set); michael@0: } michael@0: }; michael@0: michael@0: template <> michael@0: struct nsBufferRoutines michael@0: { michael@0: static michael@0: int32_t compare( const char16_t* a, const char16_t* b, uint32_t max, bool ic ) michael@0: { michael@0: NS_ASSERTION(!ic, "no case-insensitive compare here"); michael@0: return Compare2To2(a, b, max); michael@0: } michael@0: michael@0: static michael@0: int32_t compare( const char16_t* a, const char* b, uint32_t max, bool ic ) michael@0: { michael@0: return Compare2To1(a, b, max, ic); michael@0: } michael@0: michael@0: static michael@0: int32_t find_char( const char16_t* s, uint32_t max, int32_t offset, const char16_t c, int32_t count ) michael@0: { michael@0: return FindChar2(s, max, offset, c, count); michael@0: } michael@0: michael@0: static michael@0: int32_t rfind_char( const char16_t* s, uint32_t max, int32_t offset, const char16_t c, int32_t count ) michael@0: { michael@0: return RFindChar2(s, max, offset, c, count); michael@0: } michael@0: michael@0: static michael@0: char16_t get_find_in_set_filter( const char16_t* set ) michael@0: { michael@0: return GetFindInSetFilter(set); michael@0: } michael@0: michael@0: static michael@0: char16_t get_find_in_set_filter( const char* set ) michael@0: { michael@0: return (~char16_t(0)^~char(0)) | GetFindInSetFilter(set); michael@0: } michael@0: michael@0: static michael@0: int32_t strip_chars( char16_t* s, uint32_t max, const char* set ) michael@0: { michael@0: return StripChars2(s, max, set); michael@0: } michael@0: michael@0: static michael@0: int32_t compress_chars( char16_t* s, uint32_t len, const char* set ) michael@0: { michael@0: return CompressChars2(s, len, set); michael@0: } michael@0: }; michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: template michael@0: #ifndef __SUNPRO_CC michael@0: static michael@0: #endif /* !__SUNPRO_CC */ michael@0: int32_t michael@0: FindSubstring( const L* big, uint32_t bigLen, michael@0: const R* little, uint32_t littleLen, michael@0: bool ignoreCase ) michael@0: { michael@0: if (littleLen > bigLen) michael@0: return kNotFound; michael@0: michael@0: int32_t i, max = int32_t(bigLen - littleLen); michael@0: for (i=0; i<=max; ++i, ++big) michael@0: { michael@0: if (nsBufferRoutines::compare(big, little, littleLen, ignoreCase) == 0) michael@0: return i; michael@0: } michael@0: michael@0: return kNotFound; michael@0: } michael@0: michael@0: template michael@0: #ifndef __SUNPRO_CC michael@0: static michael@0: #endif /* !__SUNPRO_CC */ michael@0: int32_t michael@0: RFindSubstring( const L* big, uint32_t bigLen, michael@0: const R* little, uint32_t littleLen, michael@0: bool ignoreCase ) michael@0: { michael@0: if (littleLen > bigLen) michael@0: return kNotFound; michael@0: michael@0: int32_t i, max = int32_t(bigLen - littleLen); michael@0: michael@0: const L* iter = big + max; michael@0: for (i=max; iter >= big; --i, --iter) michael@0: { michael@0: if (nsBufferRoutines::compare(iter, little, littleLen, ignoreCase) == 0) michael@0: return i; michael@0: } michael@0: michael@0: return kNotFound; michael@0: } michael@0: michael@0: template michael@0: #ifndef __SUNPRO_CC michael@0: static michael@0: #endif /* !__SUNPRO_CC */ michael@0: int32_t michael@0: FindCharInSet( const CharT* data, uint32_t dataLen, const SetCharT* set ) michael@0: { michael@0: CharT filter = nsBufferRoutines::get_find_in_set_filter(set); michael@0: michael@0: const CharT* end = data + dataLen; michael@0: for (const CharT* iter = data; iter < end; ++iter) michael@0: { michael@0: CharT currentChar = *iter; michael@0: if (currentChar & filter) michael@0: continue; // char is not in filter set; go on with next char. michael@0: michael@0: // test all chars michael@0: const SetCharT* charInSet = set; michael@0: CharT setChar = CharT(*charInSet); michael@0: while (setChar) michael@0: { michael@0: if (setChar == currentChar) michael@0: return iter - data; // found it! return index of the found char. michael@0: michael@0: setChar = CharT(*(++charInSet)); michael@0: } michael@0: } michael@0: return kNotFound; michael@0: } michael@0: michael@0: template michael@0: #ifndef __SUNPRO_CC michael@0: static michael@0: #endif /* !__SUNPRO_CC */ michael@0: int32_t michael@0: RFindCharInSet( const CharT* data, uint32_t dataLen, const SetCharT* set ) michael@0: { michael@0: CharT filter = nsBufferRoutines::get_find_in_set_filter(set); michael@0: michael@0: for (const CharT* iter = data + dataLen - 1; iter >= data; --iter) michael@0: { michael@0: CharT currentChar = *iter; michael@0: if (currentChar & filter) michael@0: continue; // char is not in filter set; go on with next char. michael@0: michael@0: // test all chars michael@0: const CharT* charInSet = set; michael@0: CharT setChar = *charInSet; michael@0: while (setChar) michael@0: { michael@0: if (setChar == currentChar) michael@0: return iter - data; // found it! return index of the found char. michael@0: michael@0: setChar = *(++charInSet); michael@0: } michael@0: } michael@0: return kNotFound; michael@0: } michael@0: michael@0: /** michael@0: * this method changes the meaning of |offset| and |count|: michael@0: * michael@0: * upon return, michael@0: * |offset| specifies start of search range michael@0: * |count| specifies length of search range michael@0: */ michael@0: static void michael@0: Find_ComputeSearchRange( uint32_t bigLen, uint32_t littleLen, int32_t& offset, int32_t& count ) michael@0: { michael@0: // |count| specifies how many iterations to make from |offset| michael@0: michael@0: if (offset < 0) michael@0: { michael@0: offset = 0; michael@0: } michael@0: else if (uint32_t(offset) > bigLen) michael@0: { michael@0: count = 0; michael@0: return; michael@0: } michael@0: michael@0: int32_t maxCount = bigLen - offset; michael@0: if (count < 0 || count > maxCount) michael@0: { michael@0: count = maxCount; michael@0: } michael@0: else michael@0: { michael@0: count += littleLen; michael@0: if (count > maxCount) michael@0: count = maxCount; michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * this method changes the meaning of |offset| and |count|: michael@0: * michael@0: * upon entry, michael@0: * |offset| specifies the end point from which to search backwards michael@0: * |count| specifies the number of iterations from |offset| michael@0: * michael@0: * upon return, michael@0: * |offset| specifies start of search range michael@0: * |count| specifies length of search range michael@0: * michael@0: * michael@0: * EXAMPLE michael@0: * michael@0: * + -- littleLen=4 -- + michael@0: * : : michael@0: * |____|____|____|____|____|____|____|____|____|____|____|____| michael@0: * : : michael@0: * offset=5 bigLen=12 michael@0: * michael@0: * if count = 4, then we expect this function to return offset = 2 and michael@0: * count = 7. michael@0: * michael@0: */ michael@0: static void michael@0: RFind_ComputeSearchRange( uint32_t bigLen, uint32_t littleLen, int32_t& offset, int32_t& count ) michael@0: { michael@0: if (littleLen > bigLen) michael@0: { michael@0: offset = 0; michael@0: count = 0; michael@0: return; michael@0: } michael@0: michael@0: if (offset < 0) michael@0: offset = bigLen - littleLen; michael@0: if (count < 0) michael@0: count = offset + 1; michael@0: michael@0: int32_t start = offset - count + 1; michael@0: if (start < 0) michael@0: start = 0; michael@0: michael@0: count = offset + littleLen - start; michael@0: offset = start; michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: // define nsString obsolete methods michael@0: #include "string-template-def-unichar.h" michael@0: #include "nsTStringObsolete.cpp" michael@0: #include "string-template-undef.h" michael@0: michael@0: // define nsCString obsolete methods michael@0: #include "string-template-def-char.h" michael@0: #include "nsTStringObsolete.cpp" michael@0: #include "string-template-undef.h" michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: // specialized methods: michael@0: michael@0: int32_t michael@0: nsString::Find( const nsAFlatString& aString, int32_t aOffset, int32_t aCount ) const michael@0: { michael@0: // this method changes the meaning of aOffset and aCount: michael@0: Find_ComputeSearchRange(mLength, aString.Length(), aOffset, aCount); michael@0: michael@0: int32_t result = FindSubstring(mData + aOffset, aCount, static_cast(aString.get()), aString.Length(), false); michael@0: if (result != kNotFound) michael@0: result += aOffset; michael@0: return result; michael@0: } michael@0: michael@0: int32_t michael@0: nsString::Find( const char16_t* aString, int32_t aOffset, int32_t aCount ) const michael@0: { michael@0: return Find(nsDependentString(aString), aOffset, aCount); michael@0: } michael@0: michael@0: int32_t michael@0: nsString::RFind( const nsAFlatString& aString, int32_t aOffset, int32_t aCount ) const michael@0: { michael@0: // this method changes the meaning of aOffset and aCount: michael@0: RFind_ComputeSearchRange(mLength, aString.Length(), aOffset, aCount); michael@0: michael@0: int32_t result = RFindSubstring(mData + aOffset, aCount, static_cast(aString.get()), aString.Length(), false); michael@0: if (result != kNotFound) michael@0: result += aOffset; michael@0: return result; michael@0: } michael@0: michael@0: int32_t michael@0: nsString::RFind( const char16_t* aString, int32_t aOffset, int32_t aCount ) const michael@0: { michael@0: return RFind(nsDependentString(aString), aOffset, aCount); michael@0: } michael@0: michael@0: int32_t michael@0: nsString::FindCharInSet( const char16_t* aSet, int32_t aOffset ) const michael@0: { michael@0: if (aOffset < 0) michael@0: aOffset = 0; michael@0: else if (aOffset >= int32_t(mLength)) michael@0: return kNotFound; michael@0: michael@0: int32_t result = ::FindCharInSet(mData + aOffset, mLength - aOffset, aSet); michael@0: if (result != kNotFound) michael@0: result += aOffset; michael@0: return result; michael@0: } michael@0: michael@0: void michael@0: nsString::ReplaceChar( const char16_t* aSet, char16_t aNewChar ) michael@0: { michael@0: if (!EnsureMutable()) // XXX do this lazily? michael@0: NS_ABORT_OOM(mLength); michael@0: michael@0: char16_t* data = mData; michael@0: uint32_t lenRemaining = mLength; michael@0: michael@0: while (lenRemaining) michael@0: { michael@0: int32_t i = ::FindCharInSet(data, lenRemaining, aSet); michael@0: if (i == kNotFound) michael@0: break; michael@0: michael@0: data[i++] = aNewChar; michael@0: data += i; michael@0: lenRemaining -= i; michael@0: } michael@0: } michael@0: michael@0: michael@0: /** michael@0: * nsTString::Compare,CompareWithConversion,etc. michael@0: */ michael@0: michael@0: int32_t michael@0: nsCString::Compare( const char* aString, bool aIgnoreCase, int32_t aCount ) const michael@0: { michael@0: uint32_t strLen = char_traits::length(aString); michael@0: michael@0: int32_t maxCount = int32_t(XPCOM_MIN(mLength, strLen)); michael@0: michael@0: int32_t compareCount; michael@0: if (aCount < 0 || aCount > maxCount) michael@0: compareCount = maxCount; michael@0: else michael@0: compareCount = aCount; michael@0: michael@0: int32_t result = michael@0: nsBufferRoutines::compare(mData, aString, compareCount, aIgnoreCase); michael@0: michael@0: if (result == 0 && michael@0: (aCount < 0 || strLen < uint32_t(aCount) || mLength < uint32_t(aCount))) michael@0: { michael@0: // Since the caller didn't give us a length to test, or strings shorter michael@0: // than aCount, and compareCount characters matched, we have to assume michael@0: // that the longer string is greater. michael@0: michael@0: if (mLength != strLen) michael@0: result = (mLength < strLen) ? -1 : 1; michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: bool michael@0: nsString::EqualsIgnoreCase( const char* aString, int32_t aCount ) const michael@0: { michael@0: uint32_t strLen = nsCharTraits::length(aString); michael@0: michael@0: int32_t maxCount = int32_t(XPCOM_MIN(mLength, strLen)); michael@0: michael@0: int32_t compareCount; michael@0: if (aCount < 0 || aCount > maxCount) michael@0: compareCount = maxCount; michael@0: else michael@0: compareCount = aCount; michael@0: michael@0: int32_t result = michael@0: nsBufferRoutines::compare(mData, aString, compareCount, true); michael@0: michael@0: if (result == 0 && michael@0: (aCount < 0 || strLen < uint32_t(aCount) || mLength < uint32_t(aCount))) michael@0: { michael@0: // Since the caller didn't give us a length to test, or strings shorter michael@0: // than aCount, and compareCount characters matched, we have to assume michael@0: // that the longer string is greater. michael@0: michael@0: if (mLength != strLen) michael@0: result = 1; // Arbitrarily using any number != 0 michael@0: } michael@0: return result == 0; michael@0: } michael@0: michael@0: michael@0: /** michael@0: * nsTString::ToDouble michael@0: */ michael@0: michael@0: double michael@0: nsCString::ToDouble(nsresult* aErrorCode) const michael@0: { michael@0: double res = 0.0; michael@0: if (mLength > 0) michael@0: { michael@0: char *conv_stopped; michael@0: const char *str = mData; michael@0: // Use PR_strtod, not strtod, since we don't want locale involved. michael@0: res = PR_strtod(str, &conv_stopped); michael@0: if (conv_stopped == str+mLength) michael@0: *aErrorCode = NS_OK; michael@0: else // Not all the string was scanned michael@0: *aErrorCode = NS_ERROR_ILLEGAL_VALUE; michael@0: } michael@0: else michael@0: { michael@0: // The string was too short (0 characters) michael@0: *aErrorCode = NS_ERROR_ILLEGAL_VALUE; michael@0: } michael@0: return res; michael@0: } michael@0: michael@0: double michael@0: nsString::ToDouble(nsresult* aErrorCode) const michael@0: { michael@0: return NS_LossyConvertUTF16toASCII(*this).ToDouble(aErrorCode); michael@0: } michael@0: michael@0: michael@0: /** michael@0: * nsTString::AssignWithConversion michael@0: */ michael@0: michael@0: void michael@0: nsCString::AssignWithConversion( const nsAString& aData ) michael@0: { michael@0: LossyCopyUTF16toASCII(aData, *this); michael@0: } michael@0: michael@0: void michael@0: nsString::AssignWithConversion( const nsACString& aData ) michael@0: { michael@0: CopyASCIItoUTF16(aData, *this); michael@0: } michael@0: michael@0: #endif // !MOZ_STRING_WITH_OBSOLETE_API