diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /xpcom/string/nsStringObsolete.cpp | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'xpcom/string/nsStringObsolete.cpp')
-rw-r--r-- | xpcom/string/nsStringObsolete.cpp | 1002 |
1 files changed, 1002 insertions, 0 deletions
diff --git a/xpcom/string/nsStringObsolete.cpp b/xpcom/string/nsStringObsolete.cpp new file mode 100644 index 0000000000..23d9dad1f9 --- /dev/null +++ b/xpcom/string/nsStringObsolete.cpp @@ -0,0 +1,1002 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsString.h" + +/** + * nsTString obsolete API support + */ + +#if MOZ_STRING_WITH_OBSOLETE_API + +# include "nsDependentString.h" +# include "nsDependentSubstring.h" +# include "nsReadableUtils.h" +# include "nsCRT.h" +# include "nsUTF8Utils.h" +# include "prdtoa.h" + +/* ***** BEGIN RICKG BLOCK ***** + * + * NOTE: This section of code was extracted from rickg's bufferRoutines.h file. + * For the most part it remains unmodified. We want to eliminate (or at + * least clean up) this code at some point. If you find the formatting + * in this section somewhat inconsistent, don't blame me! ;-) + */ + +// avoid STDC's tolower since it may do weird things with non-ASCII bytes +inline char ascii_tolower(char aChar) { + if (aChar >= 'A' && aChar <= 'Z') return aChar + ('a' - 'A'); + return aChar; +} + +//----------------------------------------------------------------------------- +// +// This set of methods is used to search a buffer looking for a char. +// + +/** + * This methods cans the given buffer for the given char + * + * @update gess 02/17/00 + * @param aDest is the buffer to be searched + * @param aDestLength is the size (in char-units, not bytes) of the buffer + * @param anOffset is the start pos to begin searching + * @param aChar is the target character we're looking for + * @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) + */ +static int32_t FindChar1(const char* aDest, uint32_t aDestLength, + int32_t anOffset, const char16_t aChar, + int32_t aCount) { + if (anOffset < 0) anOffset = 0; + + if (aCount < 0) aCount = (int32_t)aDestLength; + + if ((aChar < 256) && (0 < aDestLength) && + ((uint32_t)anOffset < aDestLength)) { + // 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 char* left = aDest + anOffset; + const char* last = left + aCount; + const char* max = aDest + aDestLength; + const char* end = (last < max) ? last : max; + + int32_t theMax = end - left; + if (0 < theMax) { + unsigned char theChar = (unsigned char)aChar; + const char* result = (const char*)memchr(left, (int)theChar, theMax); + + if (result) return result - aDest; + } + } + } + + return kNotFound; +} + +/** + * This methods cans the given buffer for the given char + * + * @update gess 3/25/98 + * @param aDest is the buffer to be searched + * @param aDestLength is the size (in char-units, not bytes) of the buffer + * @param anOffset is the start pos to begin searching + * @param aChar is the target character we're looking for + * @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) + */ +static int32_t FindChar2(const char16_t* aDest, uint32_t aDestLength, + int32_t anOffset, const char16_t aChar, + int32_t aCount) { + if (anOffset < 0) anOffset = 0; + + if (aCount < 0) aCount = (int32_t)aDestLength; + + if ((0 < aDestLength) && ((uint32_t)anOffset < aDestLength)) { + if (0 < aCount) { + const char16_t* root = aDest; + const char16_t* left = root + anOffset; + const char16_t* last = left + aCount; + const char16_t* max = root + aDestLength; + const char16_t* end = (last < max) ? last : max; + + while (left < end) { + if (*left == aChar) return (left - root); + + ++left; + } + } + } + + 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 aDestLength is the size (in char-units, not bytes) of the buffer + * @param anOffset is the start pos to begin searching + * @param aChar is the target character we're looking for + * @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) + */ + +static int32_t RFindChar1(const char* aDest, uint32_t aDestLength, + int32_t anOffset, const char16_t aChar, + int32_t aCount) { + if (anOffset < 0) anOffset = (int32_t)aDestLength - 1; + + if (aCount < 0) aCount = int32_t(aDestLength); + + if ((aChar < 256) && (0 < aDestLength) && + ((uint32_t)anOffset < aDestLength)) { + // 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 char* rightmost = aDest + anOffset; + const char* min = rightmost - aCount + 1; + const char* leftmost = (min < aDest) ? aDest : min; + + char theChar = (char)aChar; + while (leftmost <= rightmost) { + if ((*rightmost) == theChar) return rightmost - aDest; + + --rightmost; + } + } + } + + return kNotFound; +} + +/** + * This methods cans the given buffer for the given char + * + * @update gess 3/25/98 + * @param aDest is the buffer to be searched + * @param aDestLength is the size (in char-units, not bytes) of the buffer + * @param anOffset is the start pos to begin searching + * @param aChar is the target character we're looking for + * @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) + */ +static int32_t RFindChar2(const char16_t* aDest, uint32_t aDestLength, + int32_t anOffset, const char16_t aChar, + int32_t aCount) { + if (anOffset < 0) anOffset = (int32_t)aDestLength - 1; + + if (aCount < 0) aCount = int32_t(aDestLength); + + if ((0 < aDestLength) && ((uint32_t)anOffset < aDestLength)) { + if (0 < aCount) { + const char16_t* root = aDest; + const char16_t* rightmost = root + anOffset; + const char16_t* min = rightmost - aCount + 1; + const char16_t* leftmost = (min < root) ? root : min; + + while (leftmost <= rightmost) { + if ((*rightmost) == aChar) return rightmost - root; + + --rightmost; + } + } + } + + return kNotFound; +} + +//----------------------------------------------------------------------------- +// +// This set of methods is used to compare one buffer onto another. The +// functions are differentiated by the size of source and dest character +// sizes. WARNING: Your destination buffer MUST be big enough to hold all the +// source bytes. We don't validate these ranges here (this should be done in +// higher level routines). +// + +/** + * This method compares the data in one buffer with another + * @update gess 01/04/99 + * @param aStr1 is the first buffer to be compared + * @param aStr2 is the 2nd buffer to be compared + * @param aCount is the number of chars to compare + * @param aIgnoreCase tells us whether to use a case-sensitive comparison + * @return -1,0,1 depending on <,==,> + */ +static +# ifdef __SUNPRO_CC + inline +# endif /* __SUNPRO_CC */ + int32_t + Compare1To1(const char* aStr1, const char* aStr2, uint32_t aCount, + bool aIgnoreCase) { + int32_t result = 0; + if (aIgnoreCase) + result = int32_t(PL_strncasecmp(aStr1, aStr2, aCount)); + else + result = nsCharTraits<char>::compare(aStr1, aStr2, aCount); + + // alien comparisons may return out-of-bound answers + // instead of the -1, 0, 1 expected by most clients + if (result < -1) + result = -1; + else if (result > 1) + result = 1; + return result; +} + +/** + * This method compares the data in one buffer with another + * @update gess 01/04/99 + * @param aStr1 is the first buffer to be compared + * @param aStr2 is the 2nd buffer to be compared + * @param aCount is the number of chars to compare + * @param aIgnoreCase tells us whether to use a case-sensitive comparison + * @return -1,0,1 depending on <,==,> + */ +static +# ifdef __SUNPRO_CC + inline +# endif /* __SUNPRO_CC */ + int32_t + Compare2To2(const char16_t* aStr1, const char16_t* aStr2, uint32_t aCount) { + int32_t result; + + if (aStr1 && aStr2) + result = nsCharTraits<char16_t>::compare(aStr1, aStr2, aCount); + + // The following cases are rare and survivable caller errors. + // Two null pointers are equal, but any string, even 0 length + // is greater than a null pointer. It might not really matter, + // but we pick something reasonable anyway. + else if (!aStr1 && !aStr2) + result = 0; + else if (aStr1) + result = 1; + else + result = -1; + + // alien comparisons may give answers outside the -1, 0, 1 expected by callers + if (result < -1) + result = -1; + else if (result > 1) + result = 1; + return result; +} + +/** + * This method compares the data in one buffer with another + * @update gess 01/04/99 + * @param aStr1 is the first buffer to be compared + * @param aStr2 is the 2nd buffer to be compared + * @param aCount is the number of chars to compare + * @param aIgnoreCase tells us whether to use a case-sensitive comparison + * @return -1,0,1 depending on <,==,> + */ +static +# ifdef __SUNPRO_CC + inline +# endif /* __SUNPRO_CC */ + int32_t + Compare2To1(const char16_t* aStr1, const char* aStr2, uint32_t aCount, + bool aIgnoreCase) { + const char16_t* s1 = aStr1; + const char* s2 = aStr2; + + if (aStr1 && aStr2) { + if (aCount != 0) { + do { + char16_t c1 = *s1++; + char16_t c2 = char16_t((unsigned char)*s2++); + + if (c1 != c2) { +# ifdef DEBUG + // we won't warn on c1>=128 (the 2-byte value) because often + // it is just fine to compare an constant, ascii value (i.e. "body") + // against some non-ascii value (i.e. a unicode string that + // was downloaded from a web page) + if (aIgnoreCase && c2 >= 128) + NS_WARNING( + "got a non-ASCII string, but we can't do an accurate case " + "conversion!"); +# endif + + // can't do case conversion on characters out of our range + if (aIgnoreCase && c1 < 128 && c2 < 128) { + c1 = ascii_tolower(char(c1)); + c2 = ascii_tolower(char(c2)); + + if (c1 == c2) continue; + } + + if (c1 < c2) return -1; + return 1; + } + } while (--aCount); + } + } + return 0; +} + +/** + * This method compares the data in one buffer with another + * @update gess 01/04/99 + * @param aStr1 is the first buffer to be compared + * @param aStr2 is the 2nd buffer to be compared + * @param aCount is the number of chars to compare + * @param aIgnoreCase tells us whether to use a case-sensitive comparison + * @return -1,0,1 depending on <,==,> + */ +inline int32_t Compare1To2(const char* aStr1, const char16_t* aStr2, + uint32_t aCount, bool aIgnoreCase) { + return Compare2To1(aStr2, aStr1, aCount, aIgnoreCase) * -1; +} + +//----------------------------------------------------------------------------- +// +// This set of methods is used compress char sequences in a buffer... +// + +/** + * This method compresses duplicate runs of a given char from the given buffer + * + * @update rickg 03.23.2000 + * @param aString is the buffer to be manipulated + * @param aLength is the length of the buffer + * @param aSet tells us which chars to compress from given buffer + * @param aEliminateLeading tells us whether to strip chars from the start of + * the buffer + * @param aEliminateTrailing tells us whether to strip chars from the start + * of the buffer + * @return the new length of the given buffer + */ +static int32_t CompressChars1(char* aString, uint32_t aLength, + const char* aSet) { + char* from = aString; + char* end = aString + aLength; + char* to = from; + + // this code converts /n, /t, /r into normal space ' '; + // it also compresses runs of whitespace down to a single char... + if (aSet && aString && (0 < aLength)) { + uint32_t aSetLen = strlen(aSet); + + while (from < end) { + char theChar = *from++; + + *to++ = theChar; // always copy this char... + + if ((kNotFound != FindChar1(aSet, aSetLen, 0, theChar, aSetLen))) { + while (from < end) { + theChar = *from++; + if (kNotFound == FindChar1(aSet, aSetLen, 0, theChar, aSetLen)) { + *to++ = theChar; + break; + } + } // while + } // if + } // if + *to = 0; + } + return to - aString; +} + +/** + * This method compresses duplicate runs of a given char from the given buffer + * + * @update rickg 03.23.2000 + * @param aString is the buffer to be manipulated + * @param aLength is the length of the buffer + * @param aSet tells us which chars to compress from given buffer + * @param aEliminateLeading tells us whether to strip chars from the start of + * the buffer + * @param aEliminateTrailing tells us whether to strip chars from the start + * of the buffer + * @return the new length of the given buffer + */ +static int32_t CompressChars2(char16_t* aString, uint32_t aLength, + const char* aSet) { + char16_t* from = aString; + char16_t* end = from + aLength; + char16_t* to = from; + + // this code converts /n, /t, /r into normal space ' '; + // it also compresses runs of whitespace down to a single char... + if (aSet && aString && (0 < aLength)) { + uint32_t aSetLen = strlen(aSet); + + while (from < end) { + char16_t theChar = *from++; + + *to++ = theChar; // always copy this char... + + if ((theChar < 256) && + (kNotFound != FindChar1(aSet, aSetLen, 0, theChar, aSetLen))) { + while (from < end) { + theChar = *from++; + if (kNotFound == FindChar1(aSet, aSetLen, 0, theChar, aSetLen)) { + *to++ = theChar; + break; + } + } // while + } // if + } // if + *to = 0; + } + return to - (char16_t*)aString; +} + +/** + * This method strips chars in a given set from the given buffer + * + * @update gess 01/04/99 + * @param aString is the buffer to be manipulated + * @param aLength is the length of the buffer + * @param aSet tells us which chars to compress from given buffer + * @param aEliminateLeading tells us whether to strip chars from the start of + * the buffer + * @param aEliminateTrailing tells us whether to strip chars from the start + * of the buffer + * @return the new length of the given buffer + */ +static int32_t StripChars1(char* aString, uint32_t aLength, const char* aSet) { + // XXX(darin): this code should defer writing until necessary. + + char* to = aString; + char* from = aString - 1; + char* end = aString + aLength; + + if (aSet && aString && (0 < aLength)) { + uint32_t aSetLen = strlen(aSet); + while (++from < end) { + char theChar = *from; + if (kNotFound == FindChar1(aSet, aSetLen, 0, theChar, aSetLen)) { + *to++ = theChar; + } + } + *to = 0; + } + return to - (char*)aString; +} + +/** + * This method strips chars in a given set from the given buffer + * + * @update gess 01/04/99 + * @param aString is the buffer to be manipulated + * @param aLength is the length of the buffer + * @param aSet tells us which chars to compress from given buffer + * @param aEliminateLeading tells us whether to strip chars from the start of + * the buffer + * @param aEliminateTrailing tells us whether to strip chars from the start + * of the buffer + * @return the new length of the given buffer + */ +static int32_t StripChars2(char16_t* aString, uint32_t aLength, + const char* aSet) { + // XXX(darin): this code should defer writing until necessary. + + char16_t* to = aString; + char16_t* from = aString - 1; + char16_t* end = to + aLength; + + if (aSet && aString && (0 < aLength)) { + uint32_t aSetLen = strlen(aSet); + while (++from < end) { + char16_t theChar = *from; + // Note the test for ascii range below. If you have a real unicode char, + // and you're searching for chars in the (given) ascii string, there's no + // point in doing the real search since it's out of the ascii range. + if ((255 < theChar) || + (kNotFound == FindChar1(aSet, aSetLen, 0, theChar, aSetLen))) { + *to++ = theChar; + } + } + *to = 0; + } + return to - (char16_t*)aString; +} + +/* ***** END RICKG BLOCK ***** */ + +// This function is used to implement FindCharInSet and friends +template <class CharT> +# ifndef __SUNPRO_CC +static +# endif /* !__SUNPRO_CC */ + CharT + GetFindInSetFilter(const CharT* set) { + CharT filter = ~CharT(0); // All bits set + while (*set) { + filter &= ~(*set); + ++set; + } + return filter; +} + +// This template class is used by our code to access rickg's buffer routines. +template <class CharT> +struct nsBufferRoutines {}; + +template <> +struct nsBufferRoutines<char> { + static int32_t compare(const char* a, const char* b, uint32_t max, bool ic) { + return Compare1To1(a, b, max, ic); + } + + static int32_t compare(const char* a, const char16_t* b, uint32_t max, + bool ic) { + return Compare1To2(a, b, max, ic); + } + + static int32_t find_char(const char* s, uint32_t max, int32_t offset, + const char16_t c, int32_t count) { + return FindChar1(s, max, offset, c, count); + } + + static int32_t rfind_char(const char* s, uint32_t max, int32_t offset, + const char16_t c, int32_t count) { + return RFindChar1(s, max, offset, c, count); + } + + static char get_find_in_set_filter(const char* set) { + return GetFindInSetFilter(set); + } + + static int32_t strip_chars(char* s, uint32_t len, const char* set) { + return StripChars1(s, len, set); + } + + static int32_t compress_chars(char* s, uint32_t len, const char* set) { + return CompressChars1(s, len, set); + } +}; + +template <> +struct nsBufferRoutines<char16_t> { + static int32_t compare(const char16_t* a, const char16_t* b, uint32_t max, + bool ic) { + NS_ASSERTION(!ic, "no case-insensitive compare here"); + return Compare2To2(a, b, max); + } + + static int32_t compare(const char16_t* a, const char* b, uint32_t max, + bool ic) { + return Compare2To1(a, b, max, ic); + } + + static int32_t find_char(const char16_t* s, uint32_t max, int32_t offset, + const char16_t c, int32_t count) { + return FindChar2(s, max, offset, c, count); + } + + static int32_t rfind_char(const char16_t* s, uint32_t max, int32_t offset, + const char16_t c, int32_t count) { + return RFindChar2(s, max, offset, c, count); + } + + static char16_t get_find_in_set_filter(const char16_t* set) { + return GetFindInSetFilter(set); + } + + static char16_t get_find_in_set_filter(const char* set) { + return (~char16_t(0) ^ ~char(0)) | GetFindInSetFilter(set); + } + + static int32_t strip_chars(char16_t* s, uint32_t max, const char* set) { + return StripChars2(s, max, set); + } + + static int32_t compress_chars(char16_t* s, uint32_t len, const char* set) { + return CompressChars2(s, len, set); + } +}; + +//----------------------------------------------------------------------------- + +template <class L, class R> +# ifndef __SUNPRO_CC +static +# endif /* !__SUNPRO_CC */ + int32_t + FindSubstring(const L* big, uint32_t bigLen, const R* little, + uint32_t littleLen, bool ignoreCase) { + if (littleLen > bigLen) return kNotFound; + + int32_t i, max = int32_t(bigLen - littleLen); + for (i = 0; i <= max; ++i, ++big) { + if (nsBufferRoutines<L>::compare(big, little, littleLen, ignoreCase) == 0) + return i; + } + + return kNotFound; +} + +template <class L, class R> +# ifndef __SUNPRO_CC +static +# endif /* !__SUNPRO_CC */ + int32_t + RFindSubstring(const L* big, uint32_t bigLen, const R* little, + uint32_t littleLen, bool ignoreCase) { + if (littleLen > bigLen) return kNotFound; + + int32_t i, max = int32_t(bigLen - littleLen); + + const L* iter = big + max; + for (i = max; iter >= big; --i, --iter) { + if (nsBufferRoutines<L>::compare(iter, little, littleLen, ignoreCase) == 0) + return i; + } + + return kNotFound; +} + +template <class CharT, class SetCharT> +# ifndef __SUNPRO_CC +static +# endif /* !__SUNPRO_CC */ + int32_t + FindCharInSet(const CharT* data, uint32_t dataLen, const SetCharT* set) { + CharT filter = nsBufferRoutines<CharT>::get_find_in_set_filter(set); + + const CharT* end = data + dataLen; + for (const CharT* iter = data; iter < end; ++iter) { + CharT currentChar = *iter; + if (currentChar & filter) + continue; // char is not in filter set; go on with next char. + + // test all chars + const SetCharT* charInSet = set; + CharT setChar = CharT(*charInSet); + while (setChar) { + if (setChar == currentChar) + return iter - data; // found it! return index of the found char. + + setChar = CharT(*(++charInSet)); + } + } + return kNotFound; +} + +template <class CharT, class SetCharT> +# ifndef __SUNPRO_CC +static +# endif /* !__SUNPRO_CC */ + int32_t + RFindCharInSet(const CharT* data, uint32_t dataLen, const SetCharT* set) { + CharT filter = nsBufferRoutines<CharT>::get_find_in_set_filter(set); + + for (const CharT* iter = data + dataLen - 1; iter >= data; --iter) { + CharT currentChar = *iter; + if (currentChar & filter) + continue; // char is not in filter set; go on with next char. + + // test all chars + const CharT* charInSet = set; + CharT setChar = *charInSet; + while (setChar) { + if (setChar == currentChar) + return iter - data; // found it! return index of the found char. + + setChar = *(++charInSet); + } + } + return kNotFound; +} + +/** + * this method changes the meaning of |offset| and |count|: + * + * upon return, + * |offset| specifies start of search range + * |count| specifies length of search range + */ +static void Find_ComputeSearchRange(uint32_t bigLen, uint32_t littleLen, + int32_t& offset, int32_t& count) { + // |count| specifies how many iterations to make from |offset| + + if (offset < 0) { + offset = 0; + } else if (uint32_t(offset) > bigLen) { + count = 0; + return; + } + + int32_t maxCount = bigLen - offset; + if (count < 0 || count > maxCount) { + count = maxCount; + } else { + count += littleLen; + if (count > maxCount) count = maxCount; + } +} + +/** + * this method changes the meaning of |offset| and |count|: + * + * upon entry, + * |offset| specifies the end point from which to search backwards + * |count| specifies the number of iterations from |offset| + * + * upon return, + * |offset| specifies start of search range + * |count| specifies length of search range + * + * + * EXAMPLE + * + * + -- littleLen=4 -- + + * : : + * |____|____|____|____|____|____|____|____|____|____|____|____| + * : : + * offset=5 bigLen=12 + * + * if count = 4, then we expect this function to return offset = 2 and + * count = 7. + * + */ +static void RFind_ComputeSearchRange(uint32_t bigLen, uint32_t littleLen, + int32_t& offset, int32_t& count) { + if (littleLen > bigLen) { + offset = 0; + count = 0; + return; + } + + if (offset < 0) offset = bigLen - littleLen; + if (count < 0) count = offset + 1; + + int32_t start = offset - count + 1; + if (start < 0) start = 0; + + count = offset + littleLen - start; + offset = start; +} + +//----------------------------------------------------------------------------- + +# include "nsTStringObsolete.cpp" + +//----------------------------------------------------------------------------- + +// specialized methods: + +template <typename T> +template <typename Q, typename EnableIfChar16> +int32_t nsTString<T>::Find(const self_type& aString, int32_t aOffset, + int32_t aCount) const { + // this method changes the meaning of aOffset and aCount: + Find_ComputeSearchRange(this->mLength, aString.Length(), aOffset, aCount); + + // Capture the raw buffer locally to help msvc deduce the type. + const char_type* str = aString.get(); + int32_t result = FindSubstring(this->mData + aOffset, aCount, str, + aString.Length(), false); + if (result != kNotFound) result += aOffset; + return result; +} + +template int32_t nsTString<char16_t>::Find(const self_type&, int32_t, + int32_t) const; + +template <typename T> +template <typename Q, typename EnableIfChar16> +int32_t nsTString<T>::Find(const char_type* aString, int32_t aOffset, + int32_t aCount) const { + return Find(nsTDependentString<T>(aString), aOffset, aCount); +} + +template int32_t nsTString<char16_t>::Find(const char_type*, int32_t, + int32_t) const; + +template <typename T> +template <typename Q, typename EnableIfChar16> +int32_t nsTString<T>::RFind(const self_type& aString, int32_t aOffset, + int32_t aCount) const { + // this method changes the meaning of aOffset and aCount: + RFind_ComputeSearchRange(this->mLength, aString.Length(), aOffset, aCount); + + // Capture the raw buffer locally to help msvc deduce the type. + const char_type* str = aString.get(); + int32_t result = RFindSubstring(this->mData + aOffset, aCount, str, + aString.Length(), false); + if (result != kNotFound) result += aOffset; + return result; +} + +template int32_t nsTString<char16_t>::RFind(const self_type&, int32_t, + int32_t) const; + +template <typename T> +template <typename Q, typename EnableIfChar16> +int32_t nsTString<T>::RFind(const char_type* aString, int32_t aOffset, + int32_t aCount) const { + return RFind(nsTDependentString<T>(aString), aOffset, aCount); +} + +template int32_t nsTString<char16_t>::RFind(const char_type*, int32_t, + int32_t) const; + +template <typename T> +template <typename Q, typename EnableIfChar16> +int32_t nsTString<T>::FindCharInSet(const char* aSet, int32_t aOffset) const { + if (aOffset < 0) + aOffset = 0; + else if (aOffset >= int32_t(this->mLength)) + return kNotFound; + + int32_t result = + ::FindCharInSet(this->mData + aOffset, this->mLength - aOffset, aSet); + if (result != kNotFound) result += aOffset; + return result; +} + +template int32_t nsTString<char16_t>::FindCharInSet(const char*, int32_t) const; + +template <typename T> +template <typename Q, typename EnableIfChar16> +void nsTString<T>::ReplaceChar(const char* aSet, char16_t aNewChar) { + if (!this->EnsureMutable()) // XXX do this lazily? + this->AllocFailed(this->mLength); + + char16_t* data = this->mData; + uint32_t lenRemaining = this->mLength; + + while (lenRemaining) { + int32_t i = ::FindCharInSet(data, lenRemaining, aSet); + if (i == kNotFound) break; + + data[i++] = aNewChar; + data += i; + lenRemaining -= i; + } +} + +namespace mozilla { +namespace detail { + +template <typename T> +template <typename Q, typename EnableIfChar> +int32_t nsTStringRepr<T>::Compare(const char_type* aString, bool aIgnoreCase, + int32_t aCount) const { + uint32_t strLen = char_traits::length(aString); + + int32_t maxCount = int32_t(XPCOM_MIN(this->mLength, strLen)); + + int32_t compareCount; + if (aCount < 0 || aCount > maxCount) + compareCount = maxCount; + else + compareCount = aCount; + + int32_t result = nsBufferRoutines<T>::compare(this->mData, aString, + compareCount, aIgnoreCase); + + if (result == 0 && (aCount < 0 || strLen < uint32_t(aCount) || + this->mLength < uint32_t(aCount))) { + // Since the caller didn't give us a length to test, or strings shorter + // than aCount, and compareCount characters matched, we have to assume + // that the longer string is greater. + + if (this->mLength != strLen) result = (this->mLength < strLen) ? -1 : 1; + } + return result; +} + +template int32_t nsTStringRepr<char>::Compare(const char_type*, bool, + int32_t) const; + +template <typename T> +template <typename Q, typename EnableIfChar16> +bool nsTStringRepr<T>::EqualsIgnoreCase(const incompatible_char_type* aString, + int32_t aCount) const { + uint32_t strLen = nsCharTraits<char>::length(aString); + + int32_t maxCount = int32_t(XPCOM_MIN(this->mLength, strLen)); + + int32_t compareCount; + if (aCount < 0 || aCount > maxCount) + compareCount = maxCount; + else + compareCount = aCount; + + int32_t result = + nsBufferRoutines<T>::compare(this->mData, aString, compareCount, true); + + if (result == 0 && (aCount < 0 || strLen < uint32_t(aCount) || + this->mLength < uint32_t(aCount))) { + // Since the caller didn't give us a length to test, or strings shorter + // than aCount, and compareCount characters matched, we have to assume + // that the longer string is greater. + + if (this->mLength != strLen) + result = 1; // Arbitrarily using any number != 0 + } + return result == 0; +} + +template bool nsTStringRepr<char16_t>::EqualsIgnoreCase( + const incompatible_char_type*, int32_t) const; + +} // namespace detail +} // namespace mozilla + +/** + * nsTString::ToDouble + */ + +template <> +double nsTString<char>::ToDouble(TrailingCharsPolicy aTrailingCharsPolicy, + nsresult* aErrorCode) const { + double res = 0.0; + if (this->mLength > 0) { + char* conv_stopped; + const char* str = this->mData; + // Use PR_strtod, not strtod, since we don't want locale involved. + res = PR_strtod(str, &conv_stopped); + if (aTrailingCharsPolicy == TrailingCharsPolicy::Allow && + conv_stopped != str) { + *aErrorCode = NS_OK; + } else if (aTrailingCharsPolicy == TrailingCharsPolicy::Disallow && + conv_stopped == str + this->mLength) { + *aErrorCode = NS_OK; + } else { + *aErrorCode = NS_ERROR_ILLEGAL_VALUE; + } + } else { + // The string was too short (0 characters) + *aErrorCode = NS_ERROR_ILLEGAL_VALUE; + } + return res; +} + +template <> +double nsTString<char>::ToDouble(nsresult* aErrorCode) const { + return ToDouble(TrailingCharsPolicy::Disallow, aErrorCode); +} + +template <> +double nsTString<char16_t>::ToDouble(nsresult* aErrorCode) const { + return NS_LossyConvertUTF16toASCII(*this).ToDouble(aErrorCode); +} + +template <typename T> +float nsTString<T>::ToFloat(nsresult* aErrorCode) const { + return (float)ToDouble(aErrorCode); +} + +template <> +double nsTString<char>::ToDoubleAllowTrailingChars(nsresult* aErrorCode) const { + return ToDouble(TrailingCharsPolicy::Allow, aErrorCode); +} + +template <> +double nsTString<char16_t>::ToDoubleAllowTrailingChars( + nsresult* aErrorCode) const { + return NS_LossyConvertUTF16toASCII(*this).ToDoubleAllowTrailingChars( + aErrorCode); +} + +template <typename T> +float nsTString<T>::ToFloatAllowTrailingChars(nsresult* aErrorCode) const { + return (float)ToDoubleAllowTrailingChars(aErrorCode); +} + +template class nsTString<char>; +template class nsTString<char16_t>; + +#endif // !MOZ_STRING_WITH_OBSOLETE_API |