michael@0: /* vim:set ts=2 sw=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 "nscore.h" michael@0: #include "nsCRTGlue.h" michael@0: #include "prprf.h" michael@0: #include "nsStringAPI.h" michael@0: #include "nsXPCOMStrings.h" michael@0: #include "nsDebug.h" michael@0: michael@0: #include michael@0: michael@0: #ifdef XP_WIN michael@0: #define snprintf _snprintf michael@0: #endif michael@0: michael@0: // nsAString michael@0: michael@0: uint32_t michael@0: nsAString::BeginReading(const char_type **begin, const char_type **end) const michael@0: { michael@0: uint32_t len = NS_StringGetData(*this, begin); michael@0: if (end) michael@0: *end = *begin + len; michael@0: michael@0: return len; michael@0: } michael@0: michael@0: const nsAString::char_type* michael@0: nsAString::BeginReading() const michael@0: { michael@0: const char_type *data; michael@0: NS_StringGetData(*this, &data); michael@0: return data; michael@0: } michael@0: michael@0: const nsAString::char_type* michael@0: nsAString::EndReading() const michael@0: { michael@0: const char_type *data; michael@0: uint32_t len = NS_StringGetData(*this, &data); michael@0: return data + len; michael@0: } michael@0: michael@0: uint32_t michael@0: nsAString::BeginWriting(char_type **begin, char_type **end, uint32_t newSize) michael@0: { michael@0: uint32_t len = NS_StringGetMutableData(*this, newSize, begin); michael@0: if (end) michael@0: *end = *begin + len; michael@0: michael@0: return len; michael@0: } michael@0: michael@0: nsAString::char_type* michael@0: nsAString::BeginWriting(uint32_t aLen) michael@0: { michael@0: char_type *data; michael@0: NS_StringGetMutableData(*this, aLen, &data); michael@0: return data; michael@0: } michael@0: michael@0: nsAString::char_type* michael@0: nsAString::EndWriting() michael@0: { michael@0: char_type *data; michael@0: uint32_t len = NS_StringGetMutableData(*this, UINT32_MAX, &data); michael@0: return data + len; michael@0: } michael@0: michael@0: bool michael@0: nsAString::SetLength(uint32_t aLen) michael@0: { michael@0: char_type *data; michael@0: NS_StringGetMutableData(*this, aLen, &data); michael@0: return data != nullptr; michael@0: } michael@0: michael@0: void michael@0: nsAString::AssignLiteral(const char *aStr) michael@0: { michael@0: uint32_t len = strlen(aStr); michael@0: char16_t *buf = BeginWriting(len); michael@0: if (!buf) michael@0: return; michael@0: michael@0: for (; *aStr; ++aStr, ++buf) michael@0: *buf = *aStr; michael@0: } michael@0: michael@0: void michael@0: nsAString::AppendLiteral(const char *aASCIIStr) michael@0: { michael@0: uint32_t appendLen = strlen(aASCIIStr); michael@0: michael@0: uint32_t thisLen = Length(); michael@0: char16_t *begin, *end; michael@0: BeginWriting(&begin, &end, appendLen + thisLen); michael@0: if (!begin) michael@0: return; michael@0: michael@0: for (begin += thisLen; begin < end; ++begin, ++aASCIIStr) michael@0: *begin = *aASCIIStr; michael@0: } michael@0: michael@0: void michael@0: nsAString::StripChars(const char *aSet) michael@0: { michael@0: nsString copy(*this); michael@0: michael@0: const char_type *source, *sourceEnd; michael@0: copy.BeginReading(&source, &sourceEnd); michael@0: michael@0: char_type *dest; michael@0: BeginWriting(&dest); michael@0: if (!dest) michael@0: return; michael@0: michael@0: char_type *curDest = dest; michael@0: michael@0: for (; source < sourceEnd; ++source) { michael@0: const char *test; michael@0: for (test = aSet; *test; ++test) { michael@0: if (*source == char_type(*test)) michael@0: break; michael@0: } michael@0: michael@0: if (!*test) { michael@0: // not stripped, copy this char michael@0: *curDest = *source; michael@0: ++curDest; michael@0: } michael@0: } michael@0: michael@0: SetLength(curDest - dest); michael@0: } michael@0: michael@0: void michael@0: nsAString::Trim(const char *aSet, bool aLeading, bool aTrailing) michael@0: { michael@0: NS_ASSERTION(aLeading || aTrailing, "Ineffective Trim"); michael@0: michael@0: const char16_t *start, *end; michael@0: uint32_t cutLen; michael@0: michael@0: if (aLeading) { michael@0: BeginReading(&start, &end); michael@0: for (cutLen = 0; start < end; ++start, ++cutLen) { michael@0: const char *test; michael@0: for (test = aSet; *test; ++test) { michael@0: if (*test == *start) michael@0: break; michael@0: } michael@0: if (!*test) michael@0: break; michael@0: } michael@0: if (cutLen) { michael@0: NS_StringCutData(*this, 0, cutLen); michael@0: } michael@0: } michael@0: if (aTrailing) { michael@0: uint32_t len = BeginReading(&start, &end); michael@0: --end; michael@0: for (cutLen = 0; end >= start; --end, ++cutLen) { michael@0: const char *test; michael@0: for (test = aSet; *test; ++test) { michael@0: if (*test == *end) michael@0: break; michael@0: } michael@0: if (!*test) michael@0: break; michael@0: } michael@0: if (cutLen) { michael@0: NS_StringCutData(*this, len - cutLen, cutLen); michael@0: } michael@0: } michael@0: } michael@0: michael@0: int32_t michael@0: nsAString::DefaultComparator(const char_type *a, const char_type *b, michael@0: uint32_t len) michael@0: { michael@0: for (const char_type *end = a + len; a < end; ++a, ++b) { michael@0: if (*a == *b) michael@0: continue; michael@0: michael@0: return *a < *b ? -1 : 1; michael@0: } michael@0: michael@0: return 0; michael@0: } michael@0: michael@0: int32_t michael@0: nsAString::Compare(const char_type *other, ComparatorFunc c) const michael@0: { michael@0: const char_type *cself; michael@0: uint32_t selflen = NS_StringGetData(*this, &cself); michael@0: uint32_t otherlen = NS_strlen(other); michael@0: uint32_t comparelen = selflen <= otherlen ? selflen : otherlen; michael@0: michael@0: int32_t result = c(cself, other, comparelen); michael@0: if (result == 0) { michael@0: if (selflen < otherlen) michael@0: return -1; michael@0: else if (selflen > otherlen) michael@0: return 1; michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: int32_t michael@0: nsAString::Compare(const self_type &other, ComparatorFunc c) const michael@0: { michael@0: const char_type *cself, *cother; michael@0: uint32_t selflen = NS_StringGetData(*this, &cself); michael@0: uint32_t otherlen = NS_StringGetData(other, &cother); michael@0: uint32_t comparelen = selflen <= otherlen ? selflen : otherlen; michael@0: michael@0: int32_t result = c(cself, cother, comparelen); michael@0: if (result == 0) { michael@0: if (selflen < otherlen) michael@0: return -1; michael@0: else if (selflen > otherlen) michael@0: return 1; michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: bool michael@0: nsAString::Equals(const char_type *other, ComparatorFunc c) const michael@0: { michael@0: const char_type *cself; michael@0: uint32_t selflen = NS_StringGetData(*this, &cself); michael@0: uint32_t otherlen = NS_strlen(other); michael@0: michael@0: if (selflen != otherlen) michael@0: return false; michael@0: michael@0: return c(cself, other, selflen) == 0; michael@0: } michael@0: michael@0: bool michael@0: nsAString::Equals(const self_type &other, ComparatorFunc c) const michael@0: { michael@0: const char_type *cself; michael@0: const char_type *cother; michael@0: uint32_t selflen = NS_StringGetData(*this, &cself); michael@0: uint32_t otherlen = NS_StringGetData(other, &cother); michael@0: michael@0: if (selflen != otherlen) michael@0: return false; michael@0: michael@0: return c(cself, cother, selflen) == 0; michael@0: } michael@0: michael@0: bool michael@0: nsAString::EqualsLiteral(const char *aASCIIString) const michael@0: { michael@0: const char16_t *begin, *end; michael@0: BeginReading(&begin, &end); michael@0: michael@0: for (; begin < end; ++begin, ++aASCIIString) { michael@0: if (!*aASCIIString || !NS_IsAscii(*begin) || michael@0: (char) *begin != *aASCIIString) { michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: return *aASCIIString == '\0'; michael@0: } michael@0: michael@0: bool michael@0: nsAString::LowerCaseEqualsLiteral(const char *aASCIIString) const michael@0: { michael@0: const char16_t *begin, *end; michael@0: BeginReading(&begin, &end); michael@0: michael@0: for (; begin < end; ++begin, ++aASCIIString) { michael@0: if (!*aASCIIString || !NS_IsAscii(*begin) || michael@0: NS_ToLower((char) *begin) != *aASCIIString) { michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: return *aASCIIString == '\0'; michael@0: } michael@0: michael@0: int32_t michael@0: nsAString::Find(const self_type& aStr, uint32_t aOffset, michael@0: ComparatorFunc c) const michael@0: { michael@0: const char_type *begin, *end; michael@0: uint32_t selflen = BeginReading(&begin, &end); michael@0: michael@0: if (aOffset > selflen) michael@0: return -1; michael@0: michael@0: const char_type *other; michael@0: uint32_t otherlen = aStr.BeginReading(&other); michael@0: michael@0: if (otherlen > selflen - aOffset) michael@0: return -1; michael@0: michael@0: // We want to stop searching otherlen characters before the end of the string michael@0: end -= otherlen; michael@0: michael@0: for (const char_type *cur = begin + aOffset; cur <= end; ++cur) { michael@0: if (!c(cur, other, otherlen)) michael@0: return cur - begin; michael@0: } michael@0: return -1; michael@0: } michael@0: michael@0: static bool ns_strnmatch(const char16_t *aStr, const char* aSubstring, michael@0: uint32_t aLen) michael@0: { michael@0: for (; aLen; ++aStr, ++aSubstring, --aLen) { michael@0: if (!NS_IsAscii(*aStr)) michael@0: return false; michael@0: michael@0: if ((char) *aStr != *aSubstring) michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: static bool ns_strnimatch(const char16_t *aStr, const char* aSubstring, michael@0: uint32_t aLen) michael@0: { michael@0: for (; aLen; ++aStr, ++aSubstring, --aLen) { michael@0: if (!NS_IsAscii(*aStr)) michael@0: return false; michael@0: michael@0: if (NS_ToLower((char) *aStr) != NS_ToLower(*aSubstring)) michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: int32_t michael@0: nsAString::Find(const char *aStr, uint32_t aOffset, bool aIgnoreCase) const michael@0: { michael@0: bool (*match)(const char16_t*, const char*, uint32_t) = michael@0: aIgnoreCase ? ns_strnimatch : ns_strnmatch; michael@0: michael@0: const char_type *begin, *end; michael@0: uint32_t selflen = BeginReading(&begin, &end); michael@0: michael@0: if (aOffset > selflen) michael@0: return -1; michael@0: michael@0: uint32_t otherlen = strlen(aStr); michael@0: michael@0: if (otherlen > selflen - aOffset) michael@0: return -1; michael@0: michael@0: // We want to stop searching otherlen characters before the end of the string michael@0: end -= otherlen; michael@0: michael@0: for (const char_type *cur = begin + aOffset; cur <= end; ++cur) { michael@0: if (match(cur, aStr, otherlen)) { michael@0: return cur - begin; michael@0: } michael@0: } michael@0: return -1; michael@0: } michael@0: michael@0: int32_t michael@0: nsAString::RFind(const self_type& aStr, int32_t aOffset, ComparatorFunc c) const michael@0: { michael@0: const char_type *begin, *end; michael@0: uint32_t selflen = BeginReading(&begin, &end); michael@0: michael@0: const char_type *other; michael@0: uint32_t otherlen = aStr.BeginReading(&other); michael@0: michael@0: if (selflen < otherlen) michael@0: return -1; michael@0: michael@0: if (aOffset < 0 || uint32_t(aOffset) > (selflen - otherlen)) michael@0: end -= otherlen; michael@0: else michael@0: end = begin + aOffset; michael@0: michael@0: for (const char_type *cur = end; cur >= begin; --cur) { michael@0: if (!c(cur, other, otherlen)) michael@0: return cur - begin; michael@0: } michael@0: return -1; michael@0: } michael@0: michael@0: int32_t michael@0: nsAString::RFind(const char *aStr, int32_t aOffset, bool aIgnoreCase) const michael@0: { michael@0: bool (*match)(const char16_t*, const char*, uint32_t) = michael@0: aIgnoreCase ? ns_strnimatch : ns_strnmatch; michael@0: michael@0: const char_type *begin, *end; michael@0: uint32_t selflen = BeginReading(&begin, &end); michael@0: uint32_t otherlen = strlen(aStr); michael@0: michael@0: if (selflen < otherlen) michael@0: return -1; michael@0: michael@0: if (aOffset < 0 || uint32_t(aOffset) > (selflen - otherlen)) michael@0: end -= otherlen; michael@0: else michael@0: end = begin + aOffset; michael@0: michael@0: for (const char_type *cur = end; cur >= begin; --cur) { michael@0: if (match(cur, aStr, otherlen)) { michael@0: return cur - begin; michael@0: } michael@0: } michael@0: return -1; michael@0: } michael@0: michael@0: int32_t michael@0: nsAString::FindChar(char_type aChar, uint32_t aOffset) const michael@0: { michael@0: const char_type *start, *end; michael@0: uint32_t len = BeginReading(&start, &end); michael@0: if (aOffset > len) michael@0: return -1; michael@0: michael@0: const char_type *cur; michael@0: michael@0: for (cur = start + aOffset; cur < end; ++cur) { michael@0: if (*cur == aChar) michael@0: return cur - start; michael@0: } michael@0: michael@0: return -1; michael@0: } michael@0: michael@0: int32_t michael@0: nsAString::RFindChar(char_type aChar) const michael@0: { michael@0: const char16_t *start, *end; michael@0: BeginReading(&start, &end); michael@0: michael@0: do { michael@0: --end; michael@0: michael@0: if (*end == aChar) michael@0: return end - start; michael@0: michael@0: } while (end >= start); michael@0: michael@0: return -1; michael@0: } michael@0: michael@0: void michael@0: nsAString::AppendInt(int aInt, int32_t aRadix) michael@0: { michael@0: const char *fmt; michael@0: switch (aRadix) { michael@0: case 8: michael@0: fmt = "%o"; michael@0: break; michael@0: michael@0: case 10: michael@0: fmt = "%d"; michael@0: break; michael@0: michael@0: case 16: michael@0: fmt = "%x"; michael@0: break; michael@0: michael@0: default: michael@0: NS_ERROR("Unrecognized radix"); michael@0: fmt = ""; michael@0: }; michael@0: michael@0: char buf[20]; michael@0: int len = snprintf(buf, sizeof(buf), fmt, aInt); michael@0: buf[sizeof(buf) - 1] = '\0'; michael@0: michael@0: Append(NS_ConvertASCIItoUTF16(buf, len)); michael@0: } michael@0: michael@0: // Strings michael@0: michael@0: #ifndef XPCOM_GLUE_AVOID_NSPR michael@0: int32_t michael@0: nsAString::ToInteger(nsresult *aErrorCode, uint32_t aRadix) const michael@0: { michael@0: NS_ConvertUTF16toUTF8 narrow(*this); michael@0: michael@0: const char *fmt; michael@0: switch (aRadix) { michael@0: case 10: michael@0: fmt = "%i"; michael@0: break; michael@0: michael@0: case 16: michael@0: fmt = "%x"; michael@0: break; michael@0: michael@0: default: michael@0: NS_ERROR("Unrecognized radix!"); michael@0: *aErrorCode = NS_ERROR_INVALID_ARG; michael@0: return 0; michael@0: } michael@0: michael@0: int32_t result = 0; michael@0: if (PR_sscanf(narrow.get(), fmt, &result) == 1) michael@0: *aErrorCode = NS_OK; michael@0: else michael@0: *aErrorCode = NS_ERROR_FAILURE; michael@0: michael@0: return result; michael@0: } michael@0: michael@0: int64_t michael@0: nsAString::ToInteger64(nsresult *aErrorCode, uint32_t aRadix) const michael@0: { michael@0: NS_ConvertUTF16toUTF8 narrow(*this); michael@0: michael@0: const char *fmt; michael@0: switch (aRadix) { michael@0: case 10: michael@0: fmt = "%lli"; michael@0: break; michael@0: michael@0: case 16: michael@0: fmt = "%llx"; michael@0: break; michael@0: michael@0: default: michael@0: NS_ERROR("Unrecognized radix!"); michael@0: *aErrorCode = NS_ERROR_INVALID_ARG; michael@0: return 0; michael@0: } michael@0: michael@0: int64_t result = 0; michael@0: if (PR_sscanf(narrow.get(), fmt, &result) == 1) michael@0: *aErrorCode = NS_OK; michael@0: else michael@0: *aErrorCode = NS_ERROR_FAILURE; michael@0: michael@0: return result; michael@0: } michael@0: #endif // XPCOM_GLUE_AVOID_NSPR michael@0: michael@0: // nsACString michael@0: michael@0: uint32_t michael@0: nsACString::BeginReading(const char_type **begin, const char_type **end) const michael@0: { michael@0: uint32_t len = NS_CStringGetData(*this, begin); michael@0: if (end) michael@0: *end = *begin + len; michael@0: michael@0: return len; michael@0: } michael@0: michael@0: const nsACString::char_type* michael@0: nsACString::BeginReading() const michael@0: { michael@0: const char_type *data; michael@0: NS_CStringGetData(*this, &data); michael@0: return data; michael@0: } michael@0: michael@0: const nsACString::char_type* michael@0: nsACString::EndReading() const michael@0: { michael@0: const char_type *data; michael@0: uint32_t len = NS_CStringGetData(*this, &data); michael@0: return data + len; michael@0: } michael@0: michael@0: uint32_t michael@0: nsACString::BeginWriting(char_type **begin, char_type **end, uint32_t newSize) michael@0: { michael@0: uint32_t len = NS_CStringGetMutableData(*this, newSize, begin); michael@0: if (end) michael@0: *end = *begin + len; michael@0: michael@0: return len; michael@0: } michael@0: michael@0: nsACString::char_type* michael@0: nsACString::BeginWriting(uint32_t aLen) michael@0: { michael@0: char_type *data; michael@0: NS_CStringGetMutableData(*this, aLen, &data); michael@0: return data; michael@0: } michael@0: michael@0: nsACString::char_type* michael@0: nsACString::EndWriting() michael@0: { michael@0: char_type *data; michael@0: uint32_t len = NS_CStringGetMutableData(*this, UINT32_MAX, &data); michael@0: return data + len; michael@0: } michael@0: michael@0: bool michael@0: nsACString::SetLength(uint32_t aLen) michael@0: { michael@0: char_type *data; michael@0: NS_CStringGetMutableData(*this, aLen, &data); michael@0: return data != nullptr; michael@0: } michael@0: michael@0: void michael@0: nsACString::StripChars(const char *aSet) michael@0: { michael@0: nsCString copy(*this); michael@0: michael@0: const char_type *source, *sourceEnd; michael@0: copy.BeginReading(&source, &sourceEnd); michael@0: michael@0: char_type *dest; michael@0: BeginWriting(&dest); michael@0: if (!dest) michael@0: return; michael@0: michael@0: char_type *curDest = dest; michael@0: michael@0: for (; source < sourceEnd; ++source) { michael@0: const char *test; michael@0: for (test = aSet; *test; ++test) { michael@0: if (*source == char_type(*test)) michael@0: break; michael@0: } michael@0: michael@0: if (!*test) { michael@0: // not stripped, copy this char michael@0: *curDest = *source; michael@0: ++curDest; michael@0: } michael@0: } michael@0: michael@0: SetLength(curDest - dest); michael@0: } michael@0: michael@0: void michael@0: nsACString::Trim(const char *aSet, bool aLeading, bool aTrailing) michael@0: { michael@0: NS_ASSERTION(aLeading || aTrailing, "Ineffective Trim"); michael@0: michael@0: const char *start, *end; michael@0: uint32_t cutLen; michael@0: michael@0: if (aLeading) { michael@0: BeginReading(&start, &end); michael@0: for (cutLen = 0; start < end; ++start, ++cutLen) { michael@0: const char *test; michael@0: for (test = aSet; *test; ++test) { michael@0: if (*test == *start) michael@0: break; michael@0: } michael@0: if (!*test) michael@0: break; michael@0: } michael@0: if (cutLen) { michael@0: NS_CStringCutData(*this, 0, cutLen); michael@0: } michael@0: } michael@0: if (aTrailing) { michael@0: uint32_t len = BeginReading(&start, &end); michael@0: --end; michael@0: for (cutLen = 0; end >= start; --end, ++cutLen) { michael@0: const char *test; michael@0: for (test = aSet; *test; ++test) { michael@0: if (*test == *end) michael@0: break; michael@0: } michael@0: if (!*test) michael@0: break; michael@0: } michael@0: if (cutLen) { michael@0: NS_CStringCutData(*this, len - cutLen, cutLen); michael@0: } michael@0: } michael@0: } michael@0: michael@0: int32_t michael@0: nsACString::DefaultComparator(const char_type *a, const char_type *b, michael@0: uint32_t len) michael@0: { michael@0: return memcmp(a, b, len); michael@0: } michael@0: michael@0: int32_t michael@0: nsACString::Compare(const char_type *other, ComparatorFunc c) const michael@0: { michael@0: const char_type *cself; michael@0: uint32_t selflen = NS_CStringGetData(*this, &cself); michael@0: uint32_t otherlen = strlen(other); michael@0: uint32_t comparelen = selflen <= otherlen ? selflen : otherlen; michael@0: michael@0: int32_t result = c(cself, other, comparelen); michael@0: if (result == 0) { michael@0: if (selflen < otherlen) michael@0: return -1; michael@0: else if (selflen > otherlen) michael@0: return 1; michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: int32_t michael@0: nsACString::Compare(const self_type &other, ComparatorFunc c) const michael@0: { michael@0: const char_type *cself, *cother; michael@0: uint32_t selflen = NS_CStringGetData(*this, &cself); michael@0: uint32_t otherlen = NS_CStringGetData(other, &cother); michael@0: uint32_t comparelen = selflen <= otherlen ? selflen : otherlen; michael@0: michael@0: int32_t result = c(cself, cother, comparelen); michael@0: if (result == 0) { michael@0: if (selflen < otherlen) michael@0: return -1; michael@0: else if (selflen > otherlen) michael@0: return 1; michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: bool michael@0: nsACString::Equals(const char_type *other, ComparatorFunc c) const michael@0: { michael@0: const char_type *cself; michael@0: uint32_t selflen = NS_CStringGetData(*this, &cself); michael@0: uint32_t otherlen = strlen(other); michael@0: michael@0: if (selflen != otherlen) michael@0: return false; michael@0: michael@0: return c(cself, other, selflen) == 0; michael@0: } michael@0: michael@0: bool michael@0: nsACString::Equals(const self_type &other, ComparatorFunc c) const michael@0: { michael@0: const char_type *cself; michael@0: const char_type *cother; michael@0: uint32_t selflen = NS_CStringGetData(*this, &cself); michael@0: uint32_t otherlen = NS_CStringGetData(other, &cother); michael@0: michael@0: if (selflen != otherlen) michael@0: return false; michael@0: michael@0: return c(cself, cother, selflen) == 0; michael@0: } michael@0: michael@0: int32_t michael@0: nsACString::Find(const self_type& aStr, uint32_t aOffset, michael@0: ComparatorFunc c) const michael@0: { michael@0: const char_type *begin, *end; michael@0: uint32_t selflen = BeginReading(&begin, &end); michael@0: michael@0: if (aOffset > selflen) michael@0: return -1; michael@0: michael@0: const char_type *other; michael@0: uint32_t otherlen = aStr.BeginReading(&other); michael@0: michael@0: if (otherlen > selflen - aOffset) michael@0: return -1; michael@0: michael@0: // We want to stop searching otherlen characters before the end of the string michael@0: end -= otherlen; michael@0: michael@0: for (const char_type *cur = begin + aOffset; cur <= end; ++cur) { michael@0: if (!c(cur, other, otherlen)) michael@0: return cur - begin; michael@0: } michael@0: return -1; michael@0: } michael@0: michael@0: int32_t michael@0: nsACString::Find(const char_type *aStr, ComparatorFunc c) const michael@0: { michael@0: return Find(aStr, strlen(aStr), c); michael@0: } michael@0: michael@0: int32_t michael@0: nsACString::Find(const char_type *aStr, uint32_t aLen, ComparatorFunc c) const michael@0: { michael@0: const char_type *begin, *end; michael@0: uint32_t selflen = BeginReading(&begin, &end); michael@0: michael@0: if (aLen == 0) { michael@0: NS_WARNING("Searching for zero-length string."); michael@0: return -1; michael@0: } michael@0: michael@0: if (aLen > selflen) michael@0: return -1; michael@0: michael@0: // We want to stop searching otherlen characters before the end of the string michael@0: end -= aLen; michael@0: michael@0: for (const char_type *cur = begin; cur <= end; ++cur) { michael@0: if (!c(cur, aStr, aLen)) michael@0: return cur - begin; michael@0: } michael@0: return -1; michael@0: } michael@0: michael@0: int32_t michael@0: nsACString::RFind(const self_type& aStr, int32_t aOffset, ComparatorFunc c) const michael@0: { michael@0: const char_type *begin, *end; michael@0: uint32_t selflen = BeginReading(&begin, &end); michael@0: michael@0: const char_type *other; michael@0: uint32_t otherlen = aStr.BeginReading(&other); michael@0: michael@0: if (selflen < otherlen) michael@0: return -1; michael@0: michael@0: if (aOffset < 0 || uint32_t(aOffset) > (selflen - otherlen)) michael@0: end -= otherlen; michael@0: else michael@0: end = begin + aOffset; michael@0: michael@0: for (const char_type *cur = end; cur >= begin; --cur) { michael@0: if (!c(cur, other, otherlen)) michael@0: return cur - begin; michael@0: } michael@0: return -1; michael@0: } michael@0: michael@0: int32_t michael@0: nsACString::RFind(const char_type *aStr, ComparatorFunc c) const michael@0: { michael@0: return RFind(aStr, strlen(aStr), c); michael@0: } michael@0: michael@0: int32_t michael@0: nsACString::RFind(const char_type *aStr, int32_t aLen, ComparatorFunc c) const michael@0: { michael@0: const char_type *begin, *end; michael@0: uint32_t selflen = BeginReading(&begin, &end); michael@0: michael@0: if (aLen <= 0) { michael@0: NS_WARNING("Searching for zero-length string."); michael@0: return -1; michael@0: } michael@0: michael@0: if (uint32_t(aLen) > selflen) michael@0: return -1; michael@0: michael@0: // We want to start searching otherlen characters before the end of the string michael@0: end -= aLen; michael@0: michael@0: for (const char_type *cur = end; cur >= begin; --cur) { michael@0: if (!c(cur, aStr, aLen)) michael@0: return cur - begin; michael@0: } michael@0: return -1; michael@0: } michael@0: michael@0: int32_t michael@0: nsACString::FindChar(char_type aChar, uint32_t aOffset) const michael@0: { michael@0: const char_type *start, *end; michael@0: uint32_t len = BeginReading(&start, &end); michael@0: if (aOffset > len) michael@0: return -1; michael@0: michael@0: const char_type *cur; michael@0: michael@0: for (cur = start + aOffset; cur < end; ++cur) { michael@0: if (*cur == aChar) michael@0: return cur - start; michael@0: } michael@0: michael@0: return -1; michael@0: } michael@0: michael@0: int32_t michael@0: nsACString::RFindChar(char_type aChar) const michael@0: { michael@0: const char *start, *end; michael@0: BeginReading(&start, &end); michael@0: michael@0: for (; end >= start; --end) { michael@0: if (*end == aChar) michael@0: return end - start; michael@0: } michael@0: michael@0: return -1; michael@0: } michael@0: michael@0: void michael@0: nsACString::AppendInt(int aInt, int32_t aRadix) michael@0: { michael@0: const char *fmt; michael@0: switch (aRadix) { michael@0: case 8: michael@0: fmt = "%o"; michael@0: break; michael@0: michael@0: case 10: michael@0: fmt = "%d"; michael@0: break; michael@0: michael@0: case 16: michael@0: fmt = "%x"; michael@0: break; michael@0: michael@0: default: michael@0: NS_ERROR("Unrecognized radix"); michael@0: fmt = ""; michael@0: }; michael@0: michael@0: char buf[20]; michael@0: int len = snprintf(buf, sizeof(buf), fmt, aInt); michael@0: buf[sizeof(buf) - 1] = '\0'; michael@0: michael@0: Append(buf, len); michael@0: } michael@0: michael@0: #ifndef XPCOM_GLUE_AVOID_NSPR michael@0: int32_t michael@0: nsACString::ToInteger(nsresult *aErrorCode, uint32_t aRadix) const michael@0: { michael@0: const char *fmt; michael@0: switch (aRadix) { michael@0: case 10: michael@0: fmt = "%i"; michael@0: break; michael@0: michael@0: case 16: michael@0: fmt = "%x"; michael@0: break; michael@0: michael@0: default: michael@0: NS_ERROR("Unrecognized radix!"); michael@0: *aErrorCode = NS_ERROR_INVALID_ARG; michael@0: return 0; michael@0: } michael@0: michael@0: int32_t result = 0; michael@0: if (PR_sscanf(nsCString(*this).get(), fmt, &result) == 1) michael@0: *aErrorCode = NS_OK; michael@0: else michael@0: *aErrorCode = NS_ERROR_FAILURE; michael@0: michael@0: return result; michael@0: } michael@0: michael@0: int64_t michael@0: nsACString::ToInteger64(nsresult *aErrorCode, uint32_t aRadix) const michael@0: { michael@0: const char *fmt; michael@0: switch (aRadix) { michael@0: case 10: michael@0: fmt = "%lli"; michael@0: break; michael@0: michael@0: case 16: michael@0: fmt = "%llx"; michael@0: break; michael@0: michael@0: default: michael@0: NS_ERROR("Unrecognized radix!"); michael@0: *aErrorCode = NS_ERROR_INVALID_ARG; michael@0: return 0; michael@0: } michael@0: michael@0: int64_t result = 0; michael@0: if (PR_sscanf(nsCString(*this).get(), fmt, &result) == 1) michael@0: *aErrorCode = NS_OK; michael@0: else michael@0: *aErrorCode = NS_ERROR_FAILURE; michael@0: michael@0: return result; michael@0: } michael@0: #endif // XPCOM_GLUE_AVOID_NSPR michael@0: michael@0: // Substrings michael@0: michael@0: nsDependentSubstring::nsDependentSubstring(const abstract_string_type& aStr, michael@0: uint32_t aStartPos) michael@0: { michael@0: const char16_t* data; michael@0: uint32_t len = NS_StringGetData(aStr, &data); michael@0: michael@0: if (aStartPos > len) michael@0: aStartPos = len; michael@0: michael@0: NS_StringContainerInit2(*this, data + aStartPos, len - aStartPos, michael@0: NS_STRING_CONTAINER_INIT_DEPEND | michael@0: NS_STRING_CONTAINER_INIT_SUBSTRING); michael@0: } michael@0: michael@0: nsDependentSubstring::nsDependentSubstring(const abstract_string_type& aStr, michael@0: uint32_t aStartPos, michael@0: uint32_t aLength) michael@0: { michael@0: const char16_t* data; michael@0: uint32_t len = NS_StringGetData(aStr, &data); michael@0: michael@0: if (aStartPos > len) michael@0: aStartPos = len; michael@0: michael@0: if (aStartPos + aLength > len) michael@0: aLength = len - aStartPos; michael@0: michael@0: NS_StringContainerInit2(*this, data + aStartPos, aLength, michael@0: NS_STRING_CONTAINER_INIT_DEPEND | michael@0: NS_STRING_CONTAINER_INIT_SUBSTRING); michael@0: } michael@0: michael@0: nsDependentCSubstring::nsDependentCSubstring(const abstract_string_type& aStr, michael@0: uint32_t aStartPos) michael@0: { michael@0: const char* data; michael@0: uint32_t len = NS_CStringGetData(aStr, &data); michael@0: michael@0: if (aStartPos > len) michael@0: aStartPos = len; michael@0: michael@0: NS_CStringContainerInit2(*this, data + aStartPos, len - aStartPos, michael@0: NS_CSTRING_CONTAINER_INIT_DEPEND | michael@0: NS_CSTRING_CONTAINER_INIT_SUBSTRING); michael@0: } michael@0: michael@0: nsDependentCSubstring::nsDependentCSubstring(const abstract_string_type& aStr, michael@0: uint32_t aStartPos, michael@0: uint32_t aLength) michael@0: { michael@0: const char* data; michael@0: uint32_t len = NS_CStringGetData(aStr, &data); michael@0: michael@0: if (aStartPos > len) michael@0: aStartPos = len; michael@0: michael@0: if (aStartPos + aLength > len) michael@0: aLength = len - aStartPos; michael@0: michael@0: NS_CStringContainerInit2(*this, data + aStartPos, aLength, michael@0: NS_CSTRING_CONTAINER_INIT_DEPEND | michael@0: NS_CSTRING_CONTAINER_INIT_SUBSTRING); michael@0: } michael@0: michael@0: // Utils michael@0: michael@0: char* michael@0: ToNewUTF8String(const nsAString& aSource) michael@0: { michael@0: nsCString temp; michael@0: CopyUTF16toUTF8(aSource, temp); michael@0: return NS_CStringCloneData(temp); michael@0: } michael@0: michael@0: void michael@0: CompressWhitespace(nsAString& aString) michael@0: { michael@0: char16_t *start; michael@0: uint32_t len = NS_StringGetMutableData(aString, UINT32_MAX, &start); michael@0: char16_t *end = start + len; michael@0: char16_t *from = start, *to = start; michael@0: michael@0: // Skip any leading whitespace michael@0: while (from < end && NS_IsAsciiWhitespace(*from)) michael@0: from++; michael@0: michael@0: while (from < end) { michael@0: char16_t theChar = *from++; michael@0: michael@0: if (NS_IsAsciiWhitespace(theChar)) { michael@0: // We found a whitespace char, so skip over any more michael@0: while (from < end && NS_IsAsciiWhitespace(*from)) michael@0: from++; michael@0: michael@0: // Turn all whitespace into spaces michael@0: theChar = ' '; michael@0: } michael@0: michael@0: *to++ = theChar; michael@0: } michael@0: michael@0: // Drop any trailing space michael@0: if (to > start && to[-1] == ' ') michael@0: to--; michael@0: michael@0: // Re-terminate the string michael@0: *to = '\0'; michael@0: michael@0: // Set the new length michael@0: aString.SetLength(to - start); michael@0: } michael@0: michael@0: uint32_t michael@0: ToLowerCase(nsACString& aStr) michael@0: { michael@0: char *begin, *end; michael@0: uint32_t len = aStr.BeginWriting(&begin, &end); michael@0: michael@0: for (; begin < end; ++begin) { michael@0: *begin = NS_ToLower(*begin); michael@0: } michael@0: michael@0: return len; michael@0: } michael@0: michael@0: uint32_t michael@0: ToUpperCase(nsACString& aStr) michael@0: { michael@0: char *begin, *end; michael@0: uint32_t len = aStr.BeginWriting(&begin, &end); michael@0: michael@0: for (; begin < end; ++begin) { michael@0: *begin = NS_ToUpper(*begin); michael@0: } michael@0: michael@0: return len; michael@0: } michael@0: michael@0: uint32_t michael@0: ToLowerCase(const nsACString& aSrc, nsACString& aDest) michael@0: { michael@0: const char *begin, *end; michael@0: uint32_t len = aSrc.BeginReading(&begin, &end); michael@0: michael@0: char *dest; michael@0: NS_CStringGetMutableData(aDest, len, &dest); michael@0: michael@0: for (; begin < end; ++begin, ++dest) { michael@0: *dest = NS_ToLower(*begin); michael@0: } michael@0: michael@0: return len; michael@0: } michael@0: michael@0: uint32_t michael@0: ToUpperCase(const nsACString& aSrc, nsACString& aDest) michael@0: { michael@0: const char *begin, *end; michael@0: uint32_t len = aSrc.BeginReading(&begin, &end); michael@0: michael@0: char *dest; michael@0: NS_CStringGetMutableData(aDest, len, &dest); michael@0: michael@0: for (; begin < end; ++begin, ++dest) { michael@0: *dest = NS_ToUpper(*begin); michael@0: } michael@0: michael@0: return len; michael@0: } michael@0: michael@0: int32_t michael@0: CaseInsensitiveCompare(const char *a, const char *b, michael@0: uint32_t len) michael@0: { michael@0: for (const char *aend = a + len; a < aend; ++a, ++b) { michael@0: char la = NS_ToLower(*a); michael@0: char lb = NS_ToLower(*b); michael@0: michael@0: if (la == lb) michael@0: continue; michael@0: michael@0: return la < lb ? -1 : 1; michael@0: } michael@0: michael@0: return 0; michael@0: } michael@0: michael@0: bool michael@0: ParseString(const nsACString& aSource, char aDelimiter, michael@0: nsTArray& aArray) michael@0: { michael@0: int32_t start = 0; michael@0: int32_t end = aSource.Length(); michael@0: michael@0: uint32_t oldLength = aArray.Length(); michael@0: michael@0: for (;;) { michael@0: int32_t delimiter = aSource.FindChar(aDelimiter, start); michael@0: if (delimiter < 0) { michael@0: delimiter = end; michael@0: } michael@0: michael@0: if (delimiter != start) { michael@0: if (!aArray.AppendElement(Substring(aSource, start, delimiter - start))) { michael@0: aArray.RemoveElementsAt(oldLength, aArray.Length() - oldLength); michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: if (delimiter == end) michael@0: break; michael@0: start = ++delimiter; michael@0: if (start == end) michael@0: break; michael@0: } michael@0: michael@0: return true; michael@0: }