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: michael@0: michael@0: /** michael@0: * nsTString::Find michael@0: * michael@0: * aOffset specifies starting index michael@0: * aCount specifies number of string compares (iterations) michael@0: */ michael@0: michael@0: int32_t michael@0: nsTString_CharT::Find( const nsCString& aString, bool aIgnoreCase, 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, aString.get(), aString.Length(), aIgnoreCase); michael@0: if (result != kNotFound) michael@0: result += aOffset; michael@0: return result; michael@0: } michael@0: michael@0: int32_t michael@0: nsTString_CharT::Find( const char* aString, bool aIgnoreCase, int32_t aOffset, int32_t aCount) const michael@0: { michael@0: return Find(nsDependentCString(aString), aIgnoreCase, aOffset, aCount); michael@0: } michael@0: michael@0: michael@0: /** michael@0: * nsTString::RFind michael@0: * michael@0: * aOffset specifies starting index michael@0: * aCount specifies number of string compares (iterations) michael@0: */ michael@0: michael@0: int32_t michael@0: nsTString_CharT::RFind( const nsCString& aString, bool aIgnoreCase, 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, aString.get(), aString.Length(), aIgnoreCase); michael@0: if (result != kNotFound) michael@0: result += aOffset; michael@0: return result; michael@0: } michael@0: michael@0: int32_t michael@0: nsTString_CharT::RFind( const char* aString, bool aIgnoreCase, int32_t aOffset, int32_t aCount) const michael@0: { michael@0: return RFind(nsDependentCString(aString), aIgnoreCase, aOffset, aCount); michael@0: } michael@0: michael@0: michael@0: /** michael@0: * nsTString::RFindChar michael@0: */ michael@0: michael@0: int32_t michael@0: nsTString_CharT::RFindChar( char16_t aChar, int32_t aOffset, int32_t aCount) const michael@0: { michael@0: return nsBufferRoutines::rfind_char(mData, mLength, aOffset, aChar, aCount); michael@0: } michael@0: michael@0: michael@0: /** michael@0: * nsTString::FindCharInSet michael@0: */ michael@0: michael@0: int32_t michael@0: nsTString_CharT::FindCharInSet( const char* 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: michael@0: /** michael@0: * nsTString::RFindCharInSet michael@0: */ michael@0: michael@0: int32_t michael@0: nsTString_CharT::RFindCharInSet( const CharT* aSet, int32_t aOffset ) const michael@0: { michael@0: // We want to pass a "data length" to ::RFindCharInSet michael@0: if (aOffset < 0 || aOffset > int32_t(mLength)) michael@0: aOffset = mLength; michael@0: else michael@0: ++aOffset; michael@0: michael@0: return ::RFindCharInSet(mData, aOffset, aSet); michael@0: } michael@0: michael@0: michael@0: // it's a shame to replicate this code. it was done this way in the past michael@0: // to help performance. this function also gets to keep the rickg style michael@0: // indentation :-/ michael@0: int32_t michael@0: nsTString_CharT::ToInteger( nsresult* aErrorCode, uint32_t aRadix ) const michael@0: { michael@0: CharT* cp=mData; michael@0: int32_t theRadix=10; // base 10 unless base 16 detected, or overriden (aRadix != kAutoDetect) michael@0: int32_t result=0; michael@0: bool negate=false; michael@0: CharT theChar=0; michael@0: michael@0: //initial value, override if we find an integer michael@0: *aErrorCode=NS_ERROR_ILLEGAL_VALUE; michael@0: michael@0: if(cp) { michael@0: michael@0: //begin by skipping over leading chars that shouldn't be part of the number... michael@0: michael@0: CharT* endcp=cp+mLength; michael@0: bool done=false; michael@0: michael@0: while((cp='A') && (theChar<='F')) { michael@0: if(10==theRadix) { michael@0: if(kAutoDetect==aRadix){ michael@0: theRadix=16; michael@0: cp=first; //backup michael@0: result=0; michael@0: haveValue = false; michael@0: } michael@0: else { michael@0: *aErrorCode=NS_ERROR_ILLEGAL_VALUE; michael@0: result=0; michael@0: break; michael@0: } michael@0: } michael@0: else { michael@0: result = (theRadix * result) + ((theChar-'A')+10); michael@0: haveValue = true; michael@0: } michael@0: } michael@0: else if((theChar>='a') && (theChar<='f')) { michael@0: if(10==theRadix) { michael@0: if(kAutoDetect==aRadix){ michael@0: theRadix=16; michael@0: cp=first; //backup michael@0: result=0; michael@0: haveValue = false; michael@0: } michael@0: else { michael@0: *aErrorCode=NS_ERROR_ILLEGAL_VALUE; michael@0: result=0; michael@0: break; michael@0: } michael@0: } michael@0: else { michael@0: result = (theRadix * result) + ((theChar-'a')+10); michael@0: haveValue = true; michael@0: } michael@0: } michael@0: else if((('X'==theChar) || ('x'==theChar)) && (!haveValue || result == 0)) { michael@0: continue; michael@0: } michael@0: else if((('#'==theChar) || ('+'==theChar)) && !haveValue) { michael@0: continue; michael@0: } michael@0: else { michael@0: //we've encountered a char that's not a legal number or sign michael@0: break; michael@0: } michael@0: michael@0: if (result < oldresult) { michael@0: // overflow! michael@0: *aErrorCode = NS_ERROR_ILLEGAL_VALUE; michael@0: result = 0; michael@0: break; michael@0: } michael@0: } //while michael@0: if(negate) michael@0: result=-result; michael@0: } //if michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: michael@0: /** michael@0: * nsTString::ToInteger64 michael@0: */ michael@0: int64_t michael@0: nsTString_CharT::ToInteger64( nsresult* aErrorCode, uint32_t aRadix ) const michael@0: { michael@0: CharT* cp=mData; michael@0: int32_t theRadix=10; // base 10 unless base 16 detected, or overriden (aRadix != kAutoDetect) michael@0: int64_t result=0; michael@0: bool negate=false; michael@0: CharT theChar=0; michael@0: michael@0: //initial value, override if we find an integer michael@0: *aErrorCode=NS_ERROR_ILLEGAL_VALUE; michael@0: michael@0: if(cp) { michael@0: michael@0: //begin by skipping over leading chars that shouldn't be part of the number... michael@0: michael@0: CharT* endcp=cp+mLength; michael@0: bool done=false; michael@0: michael@0: while((cp='A') && (theChar<='F')) { michael@0: if(10==theRadix) { michael@0: if(kAutoDetect==aRadix){ michael@0: theRadix=16; michael@0: cp=first; //backup michael@0: result=0; michael@0: haveValue = false; michael@0: } michael@0: else { michael@0: *aErrorCode=NS_ERROR_ILLEGAL_VALUE; michael@0: result=0; michael@0: break; michael@0: } michael@0: } michael@0: else { michael@0: result = (theRadix * result) + ((theChar-'A')+10); michael@0: haveValue = true; michael@0: } michael@0: } michael@0: else if((theChar>='a') && (theChar<='f')) { michael@0: if(10==theRadix) { michael@0: if(kAutoDetect==aRadix){ michael@0: theRadix=16; michael@0: cp=first; //backup michael@0: result=0; michael@0: haveValue = false; michael@0: } michael@0: else { michael@0: *aErrorCode=NS_ERROR_ILLEGAL_VALUE; michael@0: result=0; michael@0: break; michael@0: } michael@0: } michael@0: else { michael@0: result = (theRadix * result) + ((theChar-'a')+10); michael@0: haveValue = true; michael@0: } michael@0: } michael@0: else if((('X'==theChar) || ('x'==theChar)) && (!haveValue || result == 0)) { michael@0: continue; michael@0: } michael@0: else if((('#'==theChar) || ('+'==theChar)) && !haveValue) { michael@0: continue; michael@0: } michael@0: else { michael@0: //we've encountered a char that's not a legal number or sign michael@0: break; michael@0: } michael@0: michael@0: if (result < oldresult) { michael@0: // overflow! michael@0: *aErrorCode = NS_ERROR_ILLEGAL_VALUE; michael@0: result = 0; michael@0: break; michael@0: } michael@0: } //while michael@0: if(negate) michael@0: result=-result; michael@0: } //if michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: michael@0: /** michael@0: * nsTString::Mid michael@0: */ michael@0: michael@0: uint32_t michael@0: nsTString_CharT::Mid( self_type& aResult, index_type aStartPos, size_type aLengthToCopy ) const michael@0: { michael@0: if (aStartPos == 0 && aLengthToCopy >= mLength) michael@0: aResult = *this; michael@0: else michael@0: aResult = Substring(*this, aStartPos, aLengthToCopy); michael@0: michael@0: return aResult.mLength; michael@0: } michael@0: michael@0: michael@0: /** michael@0: * nsTString::SetCharAt michael@0: */ michael@0: michael@0: bool michael@0: nsTString_CharT::SetCharAt( char16_t aChar, uint32_t aIndex ) michael@0: { michael@0: if (aIndex >= mLength) michael@0: return false; michael@0: michael@0: if (!EnsureMutable()) michael@0: NS_ABORT_OOM(mLength); michael@0: michael@0: mData[aIndex] = CharT(aChar); michael@0: return true; michael@0: } michael@0: michael@0: michael@0: /** michael@0: * nsTString::StripChars,StripChar,StripWhitespace michael@0: */ michael@0: michael@0: void michael@0: nsTString_CharT::StripChars( const char* aSet ) michael@0: { michael@0: if (!EnsureMutable()) michael@0: NS_ABORT_OOM(mLength); michael@0: michael@0: mLength = nsBufferRoutines::strip_chars(mData, mLength, aSet); michael@0: } michael@0: michael@0: void michael@0: nsTString_CharT::StripWhitespace() michael@0: { michael@0: StripChars(kWhitespace); michael@0: } michael@0: michael@0: michael@0: /** michael@0: * nsTString::ReplaceChar,ReplaceSubstring michael@0: */ michael@0: michael@0: void michael@0: nsTString_CharT::ReplaceChar( char_type aOldChar, char_type aNewChar ) michael@0: { michael@0: if (!EnsureMutable()) // XXX do this lazily? michael@0: NS_ABORT_OOM(mLength); michael@0: michael@0: for (uint32_t i=0; i(aTarget.Data()), aTarget.Length(), false); michael@0: if (r == kNotFound) michael@0: break; michael@0: michael@0: Replace(i + r, aTarget.Length(), aNewValue); michael@0: i += r + aNewValue.Length(); michael@0: } michael@0: } michael@0: michael@0: michael@0: /** michael@0: * nsTString::Trim michael@0: */ michael@0: michael@0: void michael@0: nsTString_CharT::Trim( const char* aSet, bool aTrimLeading, bool aTrimTrailing, bool aIgnoreQuotes ) michael@0: { michael@0: // the old implementation worried about aSet being null :-/ michael@0: if (!aSet) michael@0: return; michael@0: michael@0: char_type* start = mData; michael@0: char_type* end = mData + mLength; michael@0: michael@0: // skip over quotes if requested michael@0: if (aIgnoreQuotes && mLength > 2 && mData[0] == mData[mLength - 1] && michael@0: (mData[0] == '\'' || mData[0] == '"')) michael@0: { michael@0: ++start; michael@0: --end; michael@0: } michael@0: michael@0: uint32_t setLen = nsCharTraits::length(aSet); michael@0: michael@0: if (aTrimLeading) michael@0: { michael@0: uint32_t cutStart = start - mData; michael@0: uint32_t cutLength = 0; michael@0: michael@0: // walk forward from start to end michael@0: for (; start != end; ++start, ++cutLength) michael@0: { michael@0: int32_t pos = FindChar1(aSet, setLen, 0, *start, setLen); michael@0: if (pos == kNotFound) michael@0: break; michael@0: } michael@0: michael@0: if (cutLength) michael@0: { michael@0: Cut(cutStart, cutLength); michael@0: michael@0: // reset iterators michael@0: start = mData + cutStart; michael@0: end = mData + mLength - cutStart; michael@0: } michael@0: } michael@0: michael@0: if (aTrimTrailing) michael@0: { michael@0: uint32_t cutEnd = end - mData; michael@0: uint32_t cutLength = 0; michael@0: michael@0: // walk backward from end to start michael@0: --end; michael@0: for (; end >= start; --end, ++cutLength) michael@0: { michael@0: int32_t pos = FindChar1(aSet, setLen, 0, *end, setLen); michael@0: if (pos == kNotFound) michael@0: break; michael@0: } michael@0: michael@0: if (cutLength) michael@0: Cut(cutEnd - cutLength, cutLength); michael@0: } michael@0: } michael@0: michael@0: michael@0: /** michael@0: * nsTString::CompressWhitespace michael@0: */ michael@0: michael@0: void michael@0: nsTString_CharT::CompressWhitespace( bool aTrimLeading, bool aTrimTrailing ) michael@0: { michael@0: const char* set = kWhitespace; michael@0: michael@0: ReplaceChar(set, ' '); michael@0: Trim(set, aTrimLeading, aTrimTrailing); michael@0: michael@0: // this one does some questionable fu... just copying the old code! michael@0: mLength = nsBufferRoutines::compress_chars(mData, mLength, set); michael@0: } michael@0: michael@0: michael@0: /** michael@0: * nsTString::AssignWithConversion michael@0: */ michael@0: michael@0: void michael@0: nsTString_CharT::AssignWithConversion( const incompatible_char_type* aData, int32_t aLength ) michael@0: { michael@0: // for compatibility with the old string implementation, we need to allow michael@0: // for a nullptr input buffer :-( michael@0: if (!aData) michael@0: { michael@0: Truncate(); michael@0: } michael@0: else michael@0: { michael@0: if (aLength < 0) michael@0: aLength = nsCharTraits::length(aData); michael@0: michael@0: AssignWithConversion(Substring(aData, aLength)); michael@0: } michael@0: }