LCOV - code coverage report
Current view: top level - xpcom/string - nsReadableUtils.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 406 643 63.1 %
Date: 2017-07-14 16:53:18 Functions: 60 85 70.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "nsReadableUtils.h"
       8             : #include "nsReadableUtilsImpl.h"
       9             : 
      10             : #include <algorithm>
      11             : 
      12             : #include "mozilla/CheckedInt.h"
      13             : 
      14             : #include "nscore.h"
      15             : #include "nsMemory.h"
      16             : #include "nsString.h"
      17             : #include "nsTArray.h"
      18             : #include "nsUTF8Utils.h"
      19             : 
      20             : using mozilla::IsASCII;
      21             : 
      22             : /**
      23             :  * Fallback implementation for finding the first non-ASCII character in a
      24             :  * UTF-16 string.
      25             :  */
      26             : static inline int32_t
      27           0 : FirstNonASCIIUnvectorized(const char16_t* aBegin, const char16_t* aEnd)
      28             : {
      29             :   typedef mozilla::NonASCIIParameters<sizeof(size_t)> p;
      30           0 :   const size_t kMask = p::mask();
      31           0 :   const uintptr_t kAlignMask = p::alignMask();
      32           0 :   const size_t kNumUnicharsPerWord = p::numUnicharsPerWord();
      33             : 
      34           0 :   const char16_t* idx = aBegin;
      35             : 
      36             :   // Align ourselves to a word boundary.
      37           0 :   for (; idx != aEnd && ((uintptr_t(idx) & kAlignMask) != 0); idx++) {
      38           0 :     if (!IsASCII(*idx)) {
      39           0 :       return idx - aBegin;
      40             :     }
      41             :   }
      42             : 
      43             :   // Check one word at a time.
      44           0 :   const char16_t* wordWalkEnd = mozilla::aligned(aEnd, kAlignMask);
      45           0 :   for (; idx != wordWalkEnd; idx += kNumUnicharsPerWord) {
      46           0 :     const size_t word = *reinterpret_cast<const size_t*>(idx);
      47           0 :     if (word & kMask) {
      48           0 :       return idx - aBegin;
      49             :     }
      50             :   }
      51             : 
      52             :   // Take care of the remainder one character at a time.
      53           0 :   for (; idx != aEnd; idx++) {
      54           0 :     if (!IsASCII(*idx)) {
      55           0 :       return idx - aBegin;
      56             :     }
      57             :   }
      58             : 
      59           0 :   return -1;
      60             : }
      61             : 
      62             : /*
      63             :  * This function returns -1 if all characters in str are ASCII characters.
      64             :  * Otherwise, it returns a value less than or equal to the index of the first
      65             :  * ASCII character in str. For example, if first non-ASCII character is at
      66             :  * position 25, it may return 25, 24, or 16. But it guarantees
      67             :  * there are only ASCII characters before returned value.
      68             :  */
      69             : static inline int32_t
      70        4047 : FirstNonASCII(const char16_t* aBegin, const char16_t* aEnd)
      71             : {
      72             : #ifdef MOZILLA_MAY_SUPPORT_SSE2
      73        4047 :   if (mozilla::supports_sse2()) {
      74        4047 :     return mozilla::SSE2::FirstNonASCII(aBegin, aEnd);
      75             :   }
      76             : #endif
      77             : 
      78           0 :   return FirstNonASCIIUnvectorized(aBegin, aEnd);
      79             : }
      80             : 
      81             : void
      82           0 : LossyCopyUTF16toASCII(const nsAString& aSource, nsACString& aDest)
      83             : {
      84           0 :   aDest.Truncate();
      85           0 :   LossyAppendUTF16toASCII(aSource, aDest);
      86           0 : }
      87             : 
      88             : void
      89         518 : CopyASCIItoUTF16(const nsACString& aSource, nsAString& aDest)
      90             : {
      91         518 :   if (!CopyASCIItoUTF16(aSource, aDest, mozilla::fallible)) {
      92             :     // Note that this may wildly underestimate the allocation that failed, as
      93             :     // we report the length of aSource as UTF-16 instead of UTF-8.
      94           0 :     aDest.AllocFailed(aDest.Length() + aSource.Length());
      95             :   }
      96         518 : }
      97             : 
      98             : bool
      99         518 : CopyASCIItoUTF16(const nsACString& aSource, nsAString& aDest,
     100             :                  const mozilla::fallible_t& aFallible)
     101             : {
     102         518 :   aDest.Truncate();
     103         518 :   return AppendASCIItoUTF16(aSource, aDest, aFallible);
     104             : }
     105             : 
     106             : void
     107           0 : LossyCopyUTF16toASCII(const char16ptr_t aSource, nsACString& aDest)
     108             : {
     109           0 :   aDest.Truncate();
     110           0 :   if (aSource) {
     111           0 :     LossyAppendUTF16toASCII(nsDependentString(aSource), aDest);
     112             :   }
     113           0 : }
     114             : 
     115             : void
     116          56 : CopyASCIItoUTF16(const char* aSource, nsAString& aDest)
     117             : {
     118          56 :   aDest.Truncate();
     119          56 :   if (aSource) {
     120          56 :     AppendASCIItoUTF16(nsDependentCString(aSource), aDest);
     121             :   }
     122          56 : }
     123             : 
     124             : void
     125        2668 : CopyUTF16toUTF8(const nsAString& aSource, nsACString& aDest)
     126             : {
     127        2668 :   if (!CopyUTF16toUTF8(aSource, aDest, mozilla::fallible)) {
     128             :     // Note that this may wildly underestimate the allocation that failed, as
     129             :     // we report the length of aSource as UTF-16 instead of UTF-8.
     130           0 :     aDest.AllocFailed(aDest.Length() + aSource.Length());
     131             :   }
     132        2668 : }
     133             : 
     134             : bool
     135        2668 : CopyUTF16toUTF8(const nsAString& aSource, nsACString& aDest,
     136             :                 const mozilla::fallible_t& aFallible)
     137             : {
     138        2668 :   aDest.Truncate();
     139        2668 :   if (!AppendUTF16toUTF8(aSource, aDest, aFallible)) {
     140           0 :     return false;
     141             :   }
     142        2668 :   return true;
     143             : }
     144             : 
     145             : void
     146        2222 : CopyUTF8toUTF16(const nsACString& aSource, nsAString& aDest)
     147             : {
     148        2222 :   aDest.Truncate();
     149        2222 :   AppendUTF8toUTF16(aSource, aDest);
     150        2222 : }
     151             : 
     152             : void
     153         124 : CopyUTF16toUTF8(const char16ptr_t aSource, nsACString& aDest)
     154             : {
     155         124 :   aDest.Truncate();
     156         124 :   AppendUTF16toUTF8(aSource, aDest);
     157         124 : }
     158             : 
     159             : void
     160           1 : CopyUTF8toUTF16(const char* aSource, nsAString& aDest)
     161             : {
     162           1 :   aDest.Truncate();
     163           1 :   AppendUTF8toUTF16(aSource, aDest);
     164           1 : }
     165             : 
     166             : void
     167        4176 : LossyAppendUTF16toASCII(const nsAString& aSource, nsACString& aDest)
     168             : {
     169        4176 :   uint32_t old_dest_length = aDest.Length();
     170        4176 :   aDest.SetLength(old_dest_length + aSource.Length());
     171             : 
     172        4176 :   nsAString::const_iterator fromBegin, fromEnd;
     173             : 
     174        4176 :   nsACString::iterator dest;
     175        4176 :   aDest.BeginWriting(dest);
     176             : 
     177        4176 :   dest.advance(old_dest_length);
     178             : 
     179             :   // right now, this won't work on multi-fragment destinations
     180        4176 :   LossyConvertEncoding16to8 converter(dest.get());
     181             : 
     182        4176 :   copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd),
     183        4176 :               converter);
     184        4176 : }
     185             : 
     186             : void
     187         749 : AppendASCIItoUTF16(const nsACString& aSource, nsAString& aDest)
     188             : {
     189         749 :   if (!AppendASCIItoUTF16(aSource, aDest, mozilla::fallible)) {
     190           0 :     aDest.AllocFailed(aDest.Length() + aSource.Length());
     191             :   }
     192         749 : }
     193             : 
     194             : bool
     195        1274 : AppendASCIItoUTF16(const nsACString& aSource, nsAString& aDest,
     196             :                    const mozilla::fallible_t& aFallible)
     197             : {
     198        1274 :   uint32_t old_dest_length = aDest.Length();
     199        1274 :   if (!aDest.SetLength(old_dest_length + aSource.Length(),
     200             :                        aFallible)) {
     201           0 :     return false;
     202             :   }
     203             : 
     204        1274 :   nsACString::const_iterator fromBegin, fromEnd;
     205             : 
     206        1274 :   nsAString::iterator dest;
     207        1274 :   aDest.BeginWriting(dest);
     208             : 
     209        1274 :   dest.advance(old_dest_length);
     210             : 
     211             :   // right now, this won't work on multi-fragment destinations
     212        1274 :   LossyConvertEncoding8to16 converter(dest.get());
     213             : 
     214        1274 :   copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd),
     215        1274 :               converter);
     216        1274 :   return true;
     217             : }
     218             : 
     219             : void
     220          25 : LossyAppendUTF16toASCII(const char16ptr_t aSource, nsACString& aDest)
     221             : {
     222          25 :   if (aSource) {
     223          25 :     LossyAppendUTF16toASCII(nsDependentString(aSource), aDest);
     224             :   }
     225          25 : }
     226             : 
     227             : bool
     228           0 : AppendASCIItoUTF16(const char* aSource, nsAString& aDest, const mozilla::fallible_t& aFallible)
     229             : {
     230           0 :   if (aSource) {
     231           0 :     return AppendASCIItoUTF16(nsDependentCString(aSource), aDest, aFallible);
     232             :   }
     233             : 
     234           0 :   return true;
     235             : }
     236             : 
     237             : void
     238         507 : AppendASCIItoUTF16(const char* aSource, nsAString& aDest)
     239             : {
     240         507 :   if (aSource) {
     241         507 :     AppendASCIItoUTF16(nsDependentCString(aSource), aDest);
     242             :   }
     243         507 : }
     244             : 
     245             : void
     246        2022 : AppendUTF16toUTF8(const nsAString& aSource, nsACString& aDest)
     247             : {
     248        2022 :   if (!AppendUTF16toUTF8(aSource, aDest, mozilla::fallible)) {
     249             :     // Note that this may wildly underestimate the allocation that failed, as
     250             :     // we report the length of aSource as UTF-16 instead of UTF-8.
     251           0 :     aDest.AllocFailed(aDest.Length() + aSource.Length());
     252             :   }
     253        2022 : }
     254             : 
     255             : bool
     256        4690 : AppendUTF16toUTF8(const nsAString& aSource, nsACString& aDest,
     257             :                   const mozilla::fallible_t& aFallible)
     258             : {
     259             :   // At 16 characters analysis showed better performance of both the all ASCII
     260             :   // and non-ASCII cases, so we limit calling |FirstNonASCII| to strings of
     261             :   // that length.
     262        4690 :   const nsAString::size_type kFastPathMinLength = 16;
     263             : 
     264        4690 :   int32_t firstNonASCII = 0;
     265        4690 :   if (aSource.Length() >= kFastPathMinLength) {
     266        4047 :     firstNonASCII = FirstNonASCII(aSource.BeginReading(), aSource.EndReading());
     267             :   }
     268             : 
     269        4690 :   if (firstNonASCII == -1) {
     270             :     // This is all ASCII, we can use the more efficient lossy append.
     271        4047 :     mozilla::CheckedInt<nsACString::size_type> new_length(aSource.Length());
     272        4047 :     new_length += aDest.Length();
     273             : 
     274        8094 :     if (!new_length.isValid() ||
     275        4047 :         !aDest.SetCapacity(new_length.value(), aFallible)) {
     276           0 :       return false;
     277             :     }
     278             : 
     279        4047 :     LossyAppendUTF16toASCII(aSource, aDest);
     280        4047 :     return true;
     281             :   }
     282             : 
     283         643 :   nsAString::const_iterator source_start, source_end;
     284         643 :   CalculateUTF8Size calculator;
     285         643 :   aSource.BeginReading(source_start);
     286         643 :   aSource.EndReading(source_end);
     287             : 
     288             :   // Skip the characters that we know are single byte.
     289         643 :   source_start.advance(firstNonASCII);
     290             : 
     291             :   copy_string(source_start,
     292         643 :               source_end, calculator);
     293             : 
     294             :   // Include the ASCII characters that were skipped in the count.
     295         643 :   size_t count = calculator.Size() + firstNonASCII;
     296             : 
     297         643 :   if (count) {
     298         564 :     auto old_dest_length = aDest.Length();
     299             :     // Grow the buffer if we need to.
     300         564 :     mozilla::CheckedInt<nsACString::size_type> new_length(count);
     301         564 :     new_length += old_dest_length;
     302             : 
     303        1128 :     if (!new_length.isValid() ||
     304         564 :         !aDest.SetLength(new_length.value(), aFallible)) {
     305           0 :       return false;
     306             :     }
     307             : 
     308             :     // All ready? Time to convert
     309             : 
     310         564 :     nsAString::const_iterator ascii_end;
     311         564 :     aSource.BeginReading(ascii_end);
     312             : 
     313         564 :     if (firstNonASCII >= static_cast<int32_t>(kFastPathMinLength)) {
     314             :       // Use the more efficient lossy converter for the ASCII portion.
     315             :       LossyConvertEncoding16to8 lossy_converter(
     316           0 :           aDest.BeginWriting() + old_dest_length);
     317           0 :       nsAString::const_iterator ascii_start;
     318           0 :       aSource.BeginReading(ascii_start);
     319           0 :       ascii_end.advance(firstNonASCII);
     320             : 
     321           0 :       copy_string(ascii_start, ascii_end, lossy_converter);
     322             :     } else {
     323             :       // Not using the lossy shortcut, we need to include the leading ASCII
     324             :       // chars.
     325         564 :       firstNonASCII = 0;
     326             :     }
     327             : 
     328             :     ConvertUTF16toUTF8 converter(
     329         564 :         aDest.BeginWriting() + old_dest_length + firstNonASCII);
     330             :     copy_string(ascii_end,
     331         564 :                 aSource.EndReading(source_end), converter);
     332             : 
     333         564 :     NS_ASSERTION(converter.Size() == count - firstNonASCII,
     334             :                  "Unexpected disparity between CalculateUTF8Size and "
     335             :                  "ConvertUTF16toUTF8");
     336             :   }
     337             : 
     338         643 :   return true;
     339             : }
     340             : 
     341             : void
     342        7093 : AppendUTF8toUTF16(const nsACString& aSource, nsAString& aDest)
     343             : {
     344        7093 :   if (!AppendUTF8toUTF16(aSource, aDest, mozilla::fallible)) {
     345           0 :     aDest.AllocFailed(aDest.Length() + aSource.Length());
     346             :   }
     347        7093 : }
     348             : 
     349             : bool
     350        7112 : AppendUTF8toUTF16(const nsACString& aSource, nsAString& aDest,
     351             :                   const mozilla::fallible_t& aFallible)
     352             : {
     353        7112 :   nsACString::const_iterator source_start, source_end;
     354        7112 :   CalculateUTF8Length calculator;
     355        7112 :   copy_string(aSource.BeginReading(source_start),
     356       14224 :               aSource.EndReading(source_end), calculator);
     357             : 
     358        7112 :   uint32_t count = calculator.Length();
     359             : 
     360             :   // Avoid making the string mutable if we're appending an empty string
     361        7112 :   if (count) {
     362        6708 :     uint32_t old_dest_length = aDest.Length();
     363             : 
     364             :     // Grow the buffer if we need to.
     365        6708 :     if (!aDest.SetLength(old_dest_length + count, aFallible)) {
     366           0 :       return false;
     367             :     }
     368             : 
     369             :     // All ready? Time to convert
     370             : 
     371        6708 :     ConvertUTF8toUTF16 converter(aDest.BeginWriting() + old_dest_length);
     372        6708 :     copy_string(aSource.BeginReading(source_start),
     373       13416 :                 aSource.EndReading(source_end), converter);
     374             : 
     375        6708 :     NS_ASSERTION(converter.ErrorEncountered() ||
     376             :                  converter.Length() == count,
     377             :                  "CalculateUTF8Length produced the wrong length");
     378             : 
     379        6708 :     if (converter.ErrorEncountered()) {
     380           0 :       NS_ERROR("Input wasn't UTF8 or incorrect length was calculated");
     381           0 :       aDest.SetLength(old_dest_length);
     382             :     }
     383             :   }
     384             : 
     385        7112 :   return true;
     386             : }
     387             : 
     388             : void
     389         142 : AppendUTF16toUTF8(const char16ptr_t aSource, nsACString& aDest)
     390             : {
     391         142 :   if (aSource) {
     392         142 :     AppendUTF16toUTF8(nsDependentString(aSource), aDest);
     393             :   }
     394         142 : }
     395             : 
     396             : void
     397        4534 : AppendUTF8toUTF16(const char* aSource, nsAString& aDest)
     398             : {
     399        4534 :   if (aSource) {
     400        4534 :     AppendUTF8toUTF16(nsDependentCString(aSource), aDest);
     401             :   }
     402        4534 : }
     403             : 
     404             : 
     405             : /**
     406             :  * A helper function that allocates a buffer of the desired character type big enough to hold a copy of the supplied string (plus a zero terminator).
     407             :  *
     408             :  * @param aSource an string you will eventually be making a copy of
     409             :  * @return a new buffer (of the type specified by the second parameter) which you must free with |free|.
     410             :  *
     411             :  */
     412             : template <class FromStringT, class ToCharT>
     413             : inline
     414             : ToCharT*
     415        6524 : AllocateStringCopy(const FromStringT& aSource, ToCharT*)
     416             : {
     417        6524 :   return static_cast<ToCharT*>(moz_xmalloc(
     418       13048 :     (aSource.Length() + 1) * sizeof(ToCharT)));
     419             : }
     420             : 
     421             : 
     422             : char*
     423          10 : ToNewCString(const nsAString& aSource)
     424             : {
     425          10 :   char* result = AllocateStringCopy(aSource, (char*)0);
     426          10 :   if (!result) {
     427           0 :     return nullptr;
     428             :   }
     429             : 
     430          10 :   nsAString::const_iterator fromBegin, fromEnd;
     431          10 :   LossyConvertEncoding16to8 converter(result);
     432          10 :   copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd),
     433          10 :               converter).write_terminator();
     434          10 :   return result;
     435             : }
     436             : 
     437             : char*
     438           1 : ToNewUTF8String(const nsAString& aSource, uint32_t* aUTF8Count)
     439             : {
     440           1 :   nsAString::const_iterator start, end;
     441           1 :   CalculateUTF8Size calculator;
     442           1 :   copy_string(aSource.BeginReading(start), aSource.EndReading(end),
     443           1 :               calculator);
     444             : 
     445           1 :   if (aUTF8Count) {
     446           0 :     *aUTF8Count = calculator.Size();
     447             :   }
     448             : 
     449             :   char* result = static_cast<char*>
     450           1 :                  (moz_xmalloc(calculator.Size() + 1));
     451           1 :   if (!result) {
     452           0 :     return nullptr;
     453             :   }
     454             : 
     455           1 :   ConvertUTF16toUTF8 converter(result);
     456           1 :   copy_string(aSource.BeginReading(start), aSource.EndReading(end),
     457           1 :               converter).write_terminator();
     458           1 :   NS_ASSERTION(calculator.Size() == converter.Size(), "length mismatch");
     459             : 
     460           1 :   return result;
     461             : }
     462             : 
     463             : char*
     464        4530 : ToNewCString(const nsACString& aSource)
     465             : {
     466             :   // no conversion needed, just allocate a buffer of the correct length and copy into it
     467             : 
     468        4530 :   char* result = AllocateStringCopy(aSource, (char*)0);
     469        4530 :   if (!result) {
     470           0 :     return nullptr;
     471             :   }
     472             : 
     473        4530 :   nsACString::const_iterator fromBegin, fromEnd;
     474        4530 :   char* toBegin = result;
     475        9060 :   *copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd),
     476        9060 :                toBegin) = char(0);
     477        4530 :   return result;
     478             : }
     479             : 
     480             : char16_t*
     481        1984 : ToNewUnicode(const nsAString& aSource)
     482             : {
     483             :   // no conversion needed, just allocate a buffer of the correct length and copy into it
     484             : 
     485        1984 :   char16_t* result = AllocateStringCopy(aSource, (char16_t*)0);
     486        1984 :   if (!result) {
     487           0 :     return nullptr;
     488             :   }
     489             : 
     490        1984 :   nsAString::const_iterator fromBegin, fromEnd;
     491        1984 :   char16_t* toBegin = result;
     492        3968 :   *copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd),
     493        3968 :                toBegin) = char16_t(0);
     494        1984 :   return result;
     495             : }
     496             : 
     497             : char16_t*
     498           0 : ToNewUnicode(const nsACString& aSource)
     499             : {
     500           0 :   char16_t* result = AllocateStringCopy(aSource, (char16_t*)0);
     501           0 :   if (!result) {
     502           0 :     return nullptr;
     503             :   }
     504             : 
     505           0 :   nsACString::const_iterator fromBegin, fromEnd;
     506           0 :   LossyConvertEncoding8to16 converter(result);
     507           0 :   copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd),
     508           0 :               converter).write_terminator();
     509           0 :   return result;
     510             : }
     511             : 
     512             : uint32_t
     513         154 : CalcUTF8ToUnicodeLength(const nsACString& aSource)
     514             : {
     515         154 :   nsACString::const_iterator start, end;
     516         154 :   CalculateUTF8Length calculator;
     517         154 :   copy_string(aSource.BeginReading(start), aSource.EndReading(end),
     518         154 :               calculator);
     519         154 :   return calculator.Length();
     520             : }
     521             : 
     522             : char16_t*
     523         154 : UTF8ToUnicodeBuffer(const nsACString& aSource, char16_t* aBuffer,
     524             :                     uint32_t* aUTF16Count)
     525             : {
     526         154 :   nsACString::const_iterator start, end;
     527         154 :   ConvertUTF8toUTF16 converter(aBuffer);
     528         154 :   copy_string(aSource.BeginReading(start),
     529         154 :               aSource.EndReading(end),
     530         154 :               converter).write_terminator();
     531         154 :   if (aUTF16Count) {
     532         154 :     *aUTF16Count = converter.Length();
     533             :   }
     534         154 :   return aBuffer;
     535             : }
     536             : 
     537             : char16_t*
     538           0 : UTF8ToNewUnicode(const nsACString& aSource, uint32_t* aUTF16Count)
     539             : {
     540           0 :   const uint32_t length = CalcUTF8ToUnicodeLength(aSource);
     541           0 :   const size_t buffer_size = (length + 1) * sizeof(char16_t);
     542           0 :   char16_t* buffer = static_cast<char16_t*>(moz_xmalloc(buffer_size));
     543           0 :   if (!buffer) {
     544           0 :     return nullptr;
     545             :   }
     546             : 
     547             :   uint32_t copied;
     548           0 :   UTF8ToUnicodeBuffer(aSource, buffer, &copied);
     549           0 :   NS_ASSERTION(length == copied, "length mismatch");
     550             : 
     551           0 :   if (aUTF16Count) {
     552           0 :     *aUTF16Count = copied;
     553             :   }
     554           0 :   return buffer;
     555             : }
     556             : 
     557             : char16_t*
     558        4404 : CopyUnicodeTo(const nsAString& aSource, uint32_t aSrcOffset, char16_t* aDest,
     559             :               uint32_t aLength)
     560             : {
     561        4404 :   nsAString::const_iterator fromBegin, fromEnd;
     562        4404 :   char16_t* toBegin = aDest;
     563        4404 :   copy_string(aSource.BeginReading(fromBegin).advance(int32_t(aSrcOffset)),
     564        4404 :               aSource.BeginReading(fromEnd).advance(int32_t(aSrcOffset + aLength)),
     565        4404 :               toBegin);
     566        4404 :   return aDest;
     567             : }
     568             : 
     569             : void
     570           0 : CopyUnicodeTo(const nsAString::const_iterator& aSrcStart,
     571             :               const nsAString::const_iterator& aSrcEnd,
     572             :               nsAString& aDest)
     573             : {
     574           0 :   aDest.SetLength(Distance(aSrcStart, aSrcEnd));
     575             : 
     576           0 :   nsAString::char_iterator dest = aDest.BeginWriting();
     577           0 :   nsAString::const_iterator fromBegin(aSrcStart);
     578             : 
     579           0 :   copy_string(fromBegin, aSrcEnd, dest);
     580           0 : }
     581             : 
     582             : void
     583           0 : AppendUnicodeTo(const nsAString::const_iterator& aSrcStart,
     584             :                 const nsAString::const_iterator& aSrcEnd,
     585             :                 nsAString& aDest)
     586             : {
     587           0 :   uint32_t oldLength = aDest.Length();
     588           0 :   aDest.SetLength(oldLength + Distance(aSrcStart, aSrcEnd));
     589             : 
     590           0 :   nsAString::char_iterator dest = aDest.BeginWriting() + oldLength;
     591           0 :   nsAString::const_iterator fromBegin(aSrcStart);
     592             : 
     593           0 :   copy_string(fromBegin, aSrcEnd, dest);
     594           0 : }
     595             : 
     596             : bool
     597           0 : IsASCII(const nsAString& aString)
     598             : {
     599             :   static const char16_t NOT_ASCII = char16_t(~0x007F);
     600             : 
     601             : 
     602             :   // Don't want to use |copy_string| for this task, since we can stop at the first non-ASCII character
     603             : 
     604           0 :   nsAString::const_iterator iter, done_reading;
     605           0 :   aString.BeginReading(iter);
     606           0 :   aString.EndReading(done_reading);
     607             : 
     608           0 :   const char16_t* c = iter.get();
     609           0 :   const char16_t* end = done_reading.get();
     610             : 
     611           0 :   while (c < end) {
     612           0 :     if (*c++ & NOT_ASCII) {
     613           0 :       return false;
     614             :     }
     615             :   }
     616             : 
     617           0 :   return true;
     618             : }
     619             : 
     620             : bool
     621       14256 : IsASCII(const nsACString& aString)
     622             : {
     623             :   static const char NOT_ASCII = char(~0x7F);
     624             : 
     625             : 
     626             :   // Don't want to use |copy_string| for this task, since we can stop at the first non-ASCII character
     627             : 
     628       14256 :   nsACString::const_iterator iter, done_reading;
     629       14256 :   aString.BeginReading(iter);
     630       14256 :   aString.EndReading(done_reading);
     631             : 
     632       14256 :   const char* c = iter.get();
     633       14256 :   const char* end = done_reading.get();
     634             : 
     635      342268 :   while (c < end) {
     636      164006 :     if (*c++ & NOT_ASCII) {
     637           0 :       return false;
     638             :     }
     639             :   }
     640             : 
     641       14256 :   return true;
     642             : }
     643             : 
     644             : bool
     645        2661 : IsUTF8(const nsACString& aString, bool aRejectNonChar)
     646             : {
     647        2661 :   nsReadingIterator<char> done_reading;
     648        2661 :   aString.EndReading(done_reading);
     649             : 
     650        2661 :   int32_t state = 0;
     651        2661 :   bool overlong = false;
     652        2661 :   bool surrogate = false;
     653        2661 :   bool nonchar = false;
     654        2661 :   uint16_t olupper = 0; // overlong byte upper bound.
     655        2661 :   uint16_t slower = 0;  // surrogate byte lower bound.
     656             : 
     657        2661 :   nsReadingIterator<char> iter;
     658        2661 :   aString.BeginReading(iter);
     659             : 
     660        2661 :   const char* ptr = iter.get();
     661        2661 :   const char* end = done_reading.get();
     662      500091 :   while (ptr < end) {
     663             :     uint8_t c;
     664             : 
     665      248715 :     if (0 == state) {
     666      248715 :       c = *ptr++;
     667             : 
     668      248715 :       if (UTF8traits::isASCII(c)) {
     669      248715 :         continue;
     670             :       }
     671             : 
     672           0 :       if (c <= 0xC1) { // [80-BF] where not expected, [C0-C1] for overlong.
     673           0 :         return false;
     674           0 :       } else if (UTF8traits::is2byte(c)) {
     675           0 :         state = 1;
     676           0 :       } else if (UTF8traits::is3byte(c)) {
     677           0 :         state = 2;
     678           0 :         if (c == 0xE0) { // to exclude E0[80-9F][80-BF]
     679           0 :           overlong = true;
     680           0 :           olupper = 0x9F;
     681           0 :         } else if (c == 0xED) { // ED[A0-BF][80-BF] : surrogate codepoint
     682           0 :           surrogate = true;
     683           0 :           slower = 0xA0;
     684           0 :         } else if (c == 0xEF) { // EF BF [BE-BF] : non-character
     685           0 :           nonchar = true;
     686             :         }
     687           0 :       } else if (c <= 0xF4) { // XXX replace /w UTF8traits::is4byte when it's updated to exclude [F5-F7].(bug 199090)
     688           0 :         state = 3;
     689           0 :         nonchar = true;
     690           0 :         if (c == 0xF0) { // to exclude F0[80-8F][80-BF]{2}
     691           0 :           overlong = true;
     692           0 :           olupper = 0x8F;
     693           0 :         } else if (c == 0xF4) { // to exclude F4[90-BF][80-BF]
     694             :           // actually not surrogates but codepoints beyond 0x10FFFF
     695           0 :           surrogate = true;
     696           0 :           slower = 0x90;
     697             :         }
     698             :       } else {
     699           0 :         return false;  // Not UTF-8 string
     700             :       }
     701             :     }
     702             : 
     703           0 :     if (nonchar && !aRejectNonChar) {
     704           0 :       nonchar = false;
     705             :     }
     706             : 
     707           0 :     while (ptr < end && state) {
     708           0 :       c = *ptr++;
     709           0 :       --state;
     710             : 
     711             :       // non-character : EF BF [BE-BF] or F[0-7] [89AB]F BF [BE-BF]
     712           0 :       if (nonchar &&
     713           0 :           ((!state && c < 0xBE) ||
     714           0 :            (state == 1 && c != 0xBF)  ||
     715           0 :            (state == 2 && 0x0F != (0x0F & c)))) {
     716           0 :         nonchar = false;
     717             :       }
     718             : 
     719           0 :       if (!UTF8traits::isInSeq(c) || (overlong && c <= olupper) ||
     720           0 :           (surrogate && slower <= c) || (nonchar && !state)) {
     721           0 :         return false;  // Not UTF-8 string
     722             :       }
     723             : 
     724           0 :       overlong = surrogate = false;
     725             :     }
     726             :   }
     727        2661 :   return !state; // state != 0 at the end indicates an invalid UTF-8 seq.
     728             : }
     729             : 
     730             : /**
     731             :  * A character sink for in-place case conversion.
     732             :  */
     733             : class ConvertToUpperCase
     734             : {
     735             : public:
     736             :   typedef char value_type;
     737             : 
     738             :   uint32_t
     739           3 :   write(const char* aSource, uint32_t aSourceLength)
     740             :   {
     741           3 :     char* cp = const_cast<char*>(aSource);
     742           3 :     const char* end = aSource + aSourceLength;
     743          21 :     while (cp != end) {
     744           9 :       char ch = *cp;
     745           9 :       if (ch >= 'a' && ch <= 'z') {
     746           0 :         *cp = ch - ('a' - 'A');
     747             :       }
     748           9 :       ++cp;
     749             :     }
     750           3 :     return aSourceLength;
     751             :   }
     752             : };
     753             : 
     754             : void
     755           3 : ToUpperCase(nsACString& aCString)
     756             : {
     757             :   ConvertToUpperCase converter;
     758             :   char* start;
     759           3 :   converter.write(aCString.BeginWriting(start), aCString.Length());
     760           3 : }
     761             : 
     762             : /**
     763             :  * A character sink for copying with case conversion.
     764             :  */
     765             : class CopyToUpperCase
     766             : {
     767             : public:
     768             :   typedef char value_type;
     769             : 
     770           0 :   explicit CopyToUpperCase(nsACString::iterator& aDestIter,
     771             :                            const nsACString::iterator& aEndIter)
     772           0 :     : mIter(aDestIter)
     773           0 :     , mEnd(aEndIter)
     774             :   {
     775           0 :   }
     776             : 
     777             :   uint32_t
     778           0 :   write(const char* aSource, uint32_t aSourceLength)
     779             :   {
     780           0 :     uint32_t len = XPCOM_MIN(uint32_t(mEnd - mIter), aSourceLength);
     781           0 :     char* cp = mIter.get();
     782           0 :     const char* end = aSource + len;
     783           0 :     while (aSource != end) {
     784           0 :       char ch = *aSource;
     785           0 :       if ((ch >= 'a') && (ch <= 'z')) {
     786           0 :         *cp = ch - ('a' - 'A');
     787             :       } else {
     788           0 :         *cp = ch;
     789             :       }
     790           0 :       ++aSource;
     791           0 :       ++cp;
     792             :     }
     793           0 :     mIter.advance(len);
     794           0 :     return len;
     795             :   }
     796             : 
     797             : protected:
     798             :   nsACString::iterator& mIter;
     799             :   const nsACString::iterator& mEnd;
     800             : };
     801             : 
     802             : void
     803           0 : ToUpperCase(const nsACString& aSource, nsACString& aDest)
     804             : {
     805           0 :   nsACString::const_iterator fromBegin, fromEnd;
     806           0 :   nsACString::iterator toBegin, toEnd;
     807           0 :   aDest.SetLength(aSource.Length());
     808             : 
     809           0 :   CopyToUpperCase converter(aDest.BeginWriting(toBegin), aDest.EndWriting(toEnd));
     810           0 :   copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd),
     811           0 :               converter);
     812           0 : }
     813             : 
     814             : /**
     815             :  * A character sink for case conversion.
     816             :  */
     817             : class ConvertToLowerCase
     818             : {
     819             : public:
     820             :   typedef char value_type;
     821             : 
     822             :   uint32_t
     823       19625 :   write(const char* aSource, uint32_t aSourceLength)
     824             :   {
     825       19625 :     char* cp = const_cast<char*>(aSource);
     826       19625 :     const char* end = aSource + aSourceLength;
     827      467921 :     while (cp != end) {
     828      224148 :       char ch = *cp;
     829      224148 :       if ((ch >= 'A') && (ch <= 'Z')) {
     830         358 :         *cp = ch + ('a' - 'A');
     831             :       }
     832      224148 :       ++cp;
     833             :     }
     834       19625 :     return aSourceLength;
     835             :   }
     836             : };
     837             : 
     838             : void
     839       19625 : ToLowerCase(nsACString& aCString)
     840             : {
     841             :   ConvertToLowerCase converter;
     842             :   char* start;
     843       19625 :   converter.write(aCString.BeginWriting(start), aCString.Length());
     844       19625 : }
     845             : 
     846             : /**
     847             :  * A character sink for copying with case conversion.
     848             :  */
     849             : class CopyToLowerCase
     850             : {
     851             : public:
     852             :   typedef char value_type;
     853             : 
     854           9 :   explicit CopyToLowerCase(nsACString::iterator& aDestIter,
     855             :                            const nsACString::iterator& aEndIter)
     856           9 :     : mIter(aDestIter)
     857           9 :     , mEnd(aEndIter)
     858             :   {
     859           9 :   }
     860             : 
     861             :   uint32_t
     862           9 :   write(const char* aSource, uint32_t aSourceLength)
     863             :   {
     864           9 :     uint32_t len = XPCOM_MIN(uint32_t(mEnd - mIter), aSourceLength);
     865           9 :     char* cp = mIter.get();
     866           9 :     const char* end = aSource + len;
     867         227 :     while (aSource != end) {
     868         109 :       char ch = *aSource;
     869         109 :       if ((ch >= 'A') && (ch <= 'Z')) {
     870          14 :         *cp = ch + ('a' - 'A');
     871             :       } else {
     872          95 :         *cp = ch;
     873             :       }
     874         109 :       ++aSource;
     875         109 :       ++cp;
     876             :     }
     877           9 :     mIter.advance(len);
     878           9 :     return len;
     879             :   }
     880             : 
     881             : protected:
     882             :   nsACString::iterator& mIter;
     883             :   const nsACString::iterator& mEnd;
     884             : };
     885             : 
     886             : void
     887           9 : ToLowerCase(const nsACString& aSource, nsACString& aDest)
     888             : {
     889           9 :   nsACString::const_iterator fromBegin, fromEnd;
     890           9 :   nsACString::iterator toBegin, toEnd;
     891           9 :   aDest.SetLength(aSource.Length());
     892             : 
     893           9 :   CopyToLowerCase converter(aDest.BeginWriting(toBegin), aDest.EndWriting(toEnd));
     894           9 :   copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd),
     895           9 :               converter);
     896           9 : }
     897             : 
     898             : bool
     899          41 : ParseString(const nsACString& aSource, char aDelimiter,
     900             :             nsTArray<nsCString>& aArray)
     901             : {
     902          41 :   nsACString::const_iterator start, end;
     903          41 :   aSource.BeginReading(start);
     904          41 :   aSource.EndReading(end);
     905             : 
     906          41 :   uint32_t oldLength = aArray.Length();
     907             : 
     908             :   for (;;) {
     909          71 :     nsACString::const_iterator delimiter = start;
     910          71 :     FindCharInReadable(aDelimiter, delimiter, end);
     911             : 
     912          71 :     if (delimiter != start) {
     913          71 :       if (!aArray.AppendElement(Substring(start, delimiter))) {
     914           0 :         aArray.RemoveElementsAt(oldLength, aArray.Length() - oldLength);
     915           0 :         return false;
     916             :       }
     917             :     }
     918             : 
     919          71 :     if (delimiter == end) {
     920          82 :       break;
     921             :     }
     922          30 :     start = ++delimiter;
     923          30 :     if (start == end) {
     924           0 :       break;
     925             :     }
     926          30 :   }
     927             : 
     928          41 :   return true;
     929             : }
     930             : 
     931             : template <class StringT, class IteratorT, class Comparator>
     932             : bool
     933          94 : FindInReadable_Impl(const StringT& aPattern, IteratorT& aSearchStart,
     934             :                     IteratorT& aSearchEnd, const Comparator& aCompare)
     935             : {
     936          94 :   bool found_it = false;
     937             : 
     938             :   // only bother searching at all if we're given a non-empty range to search
     939          94 :   if (aSearchStart != aSearchEnd) {
     940          94 :     IteratorT aPatternStart, aPatternEnd;
     941          94 :     aPattern.BeginReading(aPatternStart);
     942          94 :     aPattern.EndReading(aPatternEnd);
     943             : 
     944             :     // outer loop keeps searching till we find it or run out of string to search
     945        2470 :     while (!found_it) {
     946             :       // fast inner loop (that's what it's called, not what it is) looks for a potential match
     947       25146 :       while (aSearchStart != aSearchEnd &&
     948        8760 :              aCompare(aPatternStart.get(), aSearchStart.get(), 1, 1)) {
     949        7572 :         ++aSearchStart;
     950             :       }
     951             : 
     952             :       // if we broke out of the `fast' loop because we're out of string ... we're done: no match
     953        1242 :       if (aSearchStart == aSearchEnd) {
     954          54 :         break;
     955             :       }
     956             : 
     957             :       // otherwise, we're at a potential match, let's see if we really hit one
     958        1188 :       IteratorT testPattern(aPatternStart);
     959        1188 :       IteratorT testSearch(aSearchStart);
     960             : 
     961             :       // slow inner loop verifies the potential match (found by the `fast' loop) at the current position
     962             :       for (;;) {
     963             :         // we already compared the first character in the outer loop,
     964             :         //  so we'll advance before the next comparison
     965        1710 :         ++testPattern;
     966        1449 :         ++testSearch;
     967             : 
     968             :         // if we verified all the way to the end of the pattern, then we found it!
     969        1449 :         if (testPattern == aPatternEnd) {
     970          40 :           found_it = true;
     971          40 :           aSearchEnd = testSearch; // return the exact found range through the parameters
     972          40 :           break;
     973             :         }
     974             : 
     975             :         // if we got to end of the string we're searching before we hit the end of the
     976             :         //  pattern, we'll never find what we're looking for
     977        1409 :         if (testSearch == aSearchEnd) {
     978          11 :           aSearchStart = aSearchEnd;
     979          11 :           break;
     980             :         }
     981             : 
     982             :         // else if we mismatched ... it's time to advance to the next search position
     983             :         //  and get back into the `fast' loop
     984        1398 :         if (aCompare(testPattern.get(), testSearch.get(), 1, 1)) {
     985        1137 :           ++aSearchStart;
     986        1137 :           break;
     987             :         }
     988             :       }
     989             :     }
     990             :   }
     991             : 
     992          94 :   return found_it;
     993             : }
     994             : 
     995             : /**
     996             :  * This searches the entire string from right to left, and returns the first match found, if any.
     997             :  */
     998             : template <class StringT, class IteratorT, class Comparator>
     999             : bool
    1000           1 : RFindInReadable_Impl(const StringT& aPattern, IteratorT& aSearchStart,
    1001             :                      IteratorT& aSearchEnd, const Comparator& aCompare)
    1002             : {
    1003           1 :   IteratorT patternStart, patternEnd, searchEnd = aSearchEnd;
    1004           1 :   aPattern.BeginReading(patternStart);
    1005           1 :   aPattern.EndReading(patternEnd);
    1006             : 
    1007             :   // Point to the last character in the pattern
    1008           1 :   --patternEnd;
    1009             :   // outer loop keeps searching till we run out of string to search
    1010          19 :   while (aSearchStart != searchEnd) {
    1011             :     // Point to the end position of the next possible match
    1012           9 :     --searchEnd;
    1013             : 
    1014             :     // Check last character, if a match, explore further from here
    1015           9 :     if (aCompare(patternEnd.get(), searchEnd.get(), 1, 1) == 0) {
    1016             :       // We're at a potential match, let's see if we really hit one
    1017           0 :       IteratorT testPattern(patternEnd);
    1018           0 :       IteratorT testSearch(searchEnd);
    1019             : 
    1020             :       // inner loop verifies the potential match at the current position
    1021           0 :       do {
    1022             :         // if we verified all the way to the end of the pattern, then we found it!
    1023           0 :         if (testPattern == patternStart) {
    1024           0 :           aSearchStart = testSearch;  // point to start of match
    1025           0 :           aSearchEnd = ++searchEnd;   // point to end of match
    1026           0 :           return true;
    1027             :         }
    1028             : 
    1029             :         // if we got to end of the string we're searching before we hit the end of the
    1030             :         //  pattern, we'll never find what we're looking for
    1031           0 :         if (testSearch == aSearchStart) {
    1032           0 :           aSearchStart = aSearchEnd;
    1033           0 :           return false;
    1034             :         }
    1035             : 
    1036             :         // test previous character for a match
    1037           0 :         --testPattern;
    1038           0 :         --testSearch;
    1039           0 :       } while (aCompare(testPattern.get(), testSearch.get(), 1, 1) == 0);
    1040             :     }
    1041             :   }
    1042             : 
    1043           1 :   aSearchStart = aSearchEnd;
    1044           1 :   return false;
    1045             : }
    1046             : 
    1047             : bool
    1048          36 : FindInReadable(const nsAString& aPattern,
    1049             :                nsAString::const_iterator& aSearchStart,
    1050             :                nsAString::const_iterator& aSearchEnd,
    1051             :                const nsStringComparator& aComparator)
    1052             : {
    1053          36 :   return FindInReadable_Impl(aPattern, aSearchStart, aSearchEnd, aComparator);
    1054             : }
    1055             : 
    1056             : bool
    1057          58 : FindInReadable(const nsACString& aPattern,
    1058             :                nsACString::const_iterator& aSearchStart,
    1059             :                nsACString::const_iterator& aSearchEnd,
    1060             :                const nsCStringComparator& aComparator)
    1061             : {
    1062          58 :   return FindInReadable_Impl(aPattern, aSearchStart, aSearchEnd, aComparator);
    1063             : }
    1064             : 
    1065             : bool
    1066           0 : CaseInsensitiveFindInReadable(const nsACString& aPattern,
    1067             :                               nsACString::const_iterator& aSearchStart,
    1068             :                               nsACString::const_iterator& aSearchEnd)
    1069             : {
    1070             :   return FindInReadable_Impl(aPattern, aSearchStart, aSearchEnd,
    1071           0 :                              nsCaseInsensitiveCStringComparator());
    1072             : }
    1073             : 
    1074             : bool
    1075           0 : RFindInReadable(const nsAString& aPattern,
    1076             :                 nsAString::const_iterator& aSearchStart,
    1077             :                 nsAString::const_iterator& aSearchEnd,
    1078             :                 const nsStringComparator& aComparator)
    1079             : {
    1080           0 :   return RFindInReadable_Impl(aPattern, aSearchStart, aSearchEnd, aComparator);
    1081             : }
    1082             : 
    1083             : bool
    1084           1 : RFindInReadable(const nsACString& aPattern,
    1085             :                 nsACString::const_iterator& aSearchStart,
    1086             :                 nsACString::const_iterator& aSearchEnd,
    1087             :                 const nsCStringComparator& aComparator)
    1088             : {
    1089           1 :   return RFindInReadable_Impl(aPattern, aSearchStart, aSearchEnd, aComparator);
    1090             : }
    1091             : 
    1092             : bool
    1093         288 : FindCharInReadable(char16_t aChar, nsAString::const_iterator& aSearchStart,
    1094             :                    const nsAString::const_iterator& aSearchEnd)
    1095             : {
    1096         288 :   int32_t fragmentLength = aSearchEnd.get() - aSearchStart.get();
    1097             : 
    1098             :   const char16_t* charFoundAt =
    1099         288 :     nsCharTraits<char16_t>::find(aSearchStart.get(), fragmentLength, aChar);
    1100         288 :   if (charFoundAt) {
    1101         144 :     aSearchStart.advance(charFoundAt - aSearchStart.get());
    1102         144 :     return true;
    1103             :   }
    1104             : 
    1105         144 :   aSearchStart.advance(fragmentLength);
    1106         144 :   return false;
    1107             : }
    1108             : 
    1109             : bool
    1110         791 : FindCharInReadable(char aChar, nsACString::const_iterator& aSearchStart,
    1111             :                    const nsACString::const_iterator& aSearchEnd)
    1112             : {
    1113         791 :   int32_t fragmentLength = aSearchEnd.get() - aSearchStart.get();
    1114             : 
    1115             :   const char* charFoundAt =
    1116         791 :     nsCharTraits<char>::find(aSearchStart.get(), fragmentLength, aChar);
    1117         791 :   if (charFoundAt) {
    1118         109 :     aSearchStart.advance(charFoundAt - aSearchStart.get());
    1119         109 :     return true;
    1120             :   }
    1121             : 
    1122         682 :   aSearchStart.advance(fragmentLength);
    1123         682 :   return false;
    1124             : }
    1125             : 
    1126             : uint32_t
    1127           0 : CountCharInReadable(const nsAString& aStr, char16_t aChar)
    1128             : {
    1129           0 :   uint32_t count = 0;
    1130           0 :   nsAString::const_iterator begin, end;
    1131             : 
    1132           0 :   aStr.BeginReading(begin);
    1133           0 :   aStr.EndReading(end);
    1134             : 
    1135           0 :   while (begin != end) {
    1136           0 :     if (*begin == aChar) {
    1137           0 :       ++count;
    1138             :     }
    1139           0 :     ++begin;
    1140             :   }
    1141             : 
    1142           0 :   return count;
    1143             : }
    1144             : 
    1145             : uint32_t
    1146           0 : CountCharInReadable(const nsACString& aStr, char aChar)
    1147             : {
    1148           0 :   uint32_t count = 0;
    1149           0 :   nsACString::const_iterator begin, end;
    1150             : 
    1151           0 :   aStr.BeginReading(begin);
    1152           0 :   aStr.EndReading(end);
    1153             : 
    1154           0 :   while (begin != end) {
    1155           0 :     if (*begin == aChar) {
    1156           0 :       ++count;
    1157             :     }
    1158           0 :     ++begin;
    1159             :   }
    1160             : 
    1161           0 :   return count;
    1162             : }
    1163             : 
    1164             : bool
    1165       16482 : StringBeginsWith(const nsAString& aSource, const nsAString& aSubstring)
    1166             : {
    1167       16482 :   nsAString::size_type src_len = aSource.Length(),
    1168       16482 :                        sub_len = aSubstring.Length();
    1169       16482 :   if (sub_len > src_len) {
    1170         364 :     return false;
    1171             :   }
    1172       16118 :   return Substring(aSource, 0, sub_len).Equals(aSubstring);
    1173             : }
    1174             : 
    1175             : bool
    1176          20 : StringBeginsWith(const nsAString& aSource, const nsAString& aSubstring,
    1177             :                  const nsStringComparator& aComparator)
    1178             : {
    1179          20 :   nsAString::size_type src_len = aSource.Length(),
    1180          20 :                        sub_len = aSubstring.Length();
    1181          20 :   if (sub_len > src_len) {
    1182           1 :     return false;
    1183             :   }
    1184          19 :   return Substring(aSource, 0, sub_len).Equals(aSubstring, aComparator);
    1185             : }
    1186             : 
    1187             : bool
    1188        1682 : StringBeginsWith(const nsACString& aSource, const nsACString& aSubstring)
    1189             : {
    1190        1682 :   nsACString::size_type src_len = aSource.Length(),
    1191        1682 :                         sub_len = aSubstring.Length();
    1192        1682 :   if (sub_len > src_len) {
    1193          37 :     return false;
    1194             :   }
    1195        1645 :   return Substring(aSource, 0, sub_len).Equals(aSubstring);
    1196             : }
    1197             : 
    1198             : bool
    1199           0 : StringBeginsWith(const nsACString& aSource, const nsACString& aSubstring,
    1200             :                  const nsCStringComparator& aComparator)
    1201             : {
    1202           0 :   nsACString::size_type src_len = aSource.Length(),
    1203           0 :                         sub_len = aSubstring.Length();
    1204           0 :   if (sub_len > src_len) {
    1205           0 :     return false;
    1206             :   }
    1207           0 :   return Substring(aSource, 0, sub_len).Equals(aSubstring, aComparator);
    1208             : }
    1209             : 
    1210             : bool
    1211           2 : StringEndsWith(const nsAString& aSource, const nsAString& aSubstring)
    1212             : {
    1213           2 :   nsAString::size_type src_len = aSource.Length(),
    1214           2 :                        sub_len = aSubstring.Length();
    1215           2 :   if (sub_len > src_len) {
    1216           0 :     return false;
    1217             :   }
    1218           2 :   return Substring(aSource, src_len - sub_len, sub_len).Equals(aSubstring);
    1219             : }
    1220             : 
    1221             : bool
    1222           0 : StringEndsWith(const nsAString& aSource, const nsAString& aSubstring,
    1223             :                const nsStringComparator& aComparator)
    1224             : {
    1225           0 :   nsAString::size_type src_len = aSource.Length(),
    1226           0 :                        sub_len = aSubstring.Length();
    1227           0 :   if (sub_len > src_len) {
    1228           0 :     return false;
    1229             :   }
    1230           0 :   return Substring(aSource, src_len - sub_len, sub_len).Equals(aSubstring,
    1231           0 :                                                                aComparator);
    1232             : }
    1233             : 
    1234             : bool
    1235         881 : StringEndsWith(const nsACString& aSource, const nsACString& aSubstring)
    1236             : {
    1237         881 :   nsACString::size_type src_len = aSource.Length(),
    1238         881 :                         sub_len = aSubstring.Length();
    1239         881 :   if (sub_len > src_len) {
    1240          13 :     return false;
    1241             :   }
    1242         868 :   return Substring(aSource, src_len - sub_len, sub_len).Equals(aSubstring);
    1243             : }
    1244             : 
    1245             : bool
    1246          30 : StringEndsWith(const nsACString& aSource, const nsACString& aSubstring,
    1247             :                const nsCStringComparator& aComparator)
    1248             : {
    1249          30 :   nsACString::size_type src_len = aSource.Length(),
    1250          30 :                         sub_len = aSubstring.Length();
    1251          30 :   if (sub_len > src_len) {
    1252           0 :     return false;
    1253             :   }
    1254          60 :   return Substring(aSource, src_len - sub_len, sub_len).Equals(aSubstring,
    1255          30 :                                                                aComparator);
    1256             : }
    1257             : 
    1258             : 
    1259             : 
    1260             : static const char16_t empty_buffer[1] = { '\0' };
    1261             : 
    1262             : const nsString&
    1263         897 : EmptyString()
    1264             : {
    1265         897 :   static const nsDependentString sEmpty(empty_buffer);
    1266             : 
    1267         897 :   return sEmpty;
    1268             : }
    1269             : 
    1270             : const nsCString&
    1271       11592 : EmptyCString()
    1272             : {
    1273       11592 :   static const nsDependentCString sEmpty((const char*)empty_buffer);
    1274             : 
    1275       11592 :   return sEmpty;
    1276             : }
    1277             : 
    1278             : const nsString&
    1279          51 : NullString()
    1280             : {
    1281          51 :   static const nsXPIDLString sNull;
    1282             : 
    1283          51 :   return sNull;
    1284             : }
    1285             : 
    1286             : const nsCString&
    1287           1 : NullCString()
    1288             : {
    1289           1 :   static const nsXPIDLCString sNull;
    1290             : 
    1291           1 :   return sNull;
    1292             : }
    1293             : 
    1294             : int32_t
    1295         600 : CompareUTF8toUTF16(const nsACString& aUTF8String,
    1296             :                    const nsAString& aUTF16String)
    1297             : {
    1298             :   static const uint32_t NOT_ASCII = uint32_t(~0x7F);
    1299             : 
    1300             :   const char* u8;
    1301             :   const char* u8end;
    1302         600 :   aUTF8String.BeginReading(u8);
    1303         600 :   aUTF8String.EndReading(u8end);
    1304             : 
    1305             :   const char16_t* u16;
    1306             :   const char16_t* u16end;
    1307         600 :   aUTF16String.BeginReading(u16);
    1308         600 :   aUTF16String.EndReading(u16end);
    1309             : 
    1310        8958 :   while (u8 != u8end && u16 != u16end) {
    1311             :     // Cast away the signedness of *u8 to prevent signextension when
    1312             :     // converting to uint32_t
    1313        4179 :     uint32_t c8_32 = (uint8_t)*u8;
    1314             : 
    1315        4179 :     if (c8_32 & NOT_ASCII) {
    1316             :       bool err;
    1317           0 :       c8_32 = UTF8CharEnumerator::NextChar(&u8, u8end, &err);
    1318           0 :       if (err) {
    1319           0 :         return INT32_MIN;
    1320             :       }
    1321             : 
    1322           0 :       uint32_t c16_32 = UTF16CharEnumerator::NextChar(&u16, u16end);
    1323             :       // The above UTF16CharEnumerator::NextChar() calls can
    1324             :       // fail, but if it does for anything other than no data to
    1325             :       // look at (which can't happen here), it returns the
    1326             :       // Unicode replacement character 0xFFFD for the invalid
    1327             :       // data they were fed. Ignore that error and treat invalid
    1328             :       // UTF16 as 0xFFFD.
    1329             :       //
    1330             :       // This matches what our UTF16 to UTF8 conversion code
    1331             :       // does, and thus a UTF8 string that came from an invalid
    1332             :       // UTF16 string will compare equal to the invalid UTF16
    1333             :       // string it came from. Same is true for any other UTF16
    1334             :       // string differs only in the invalid part of the string.
    1335             : 
    1336           0 :       if (c8_32 != c16_32) {
    1337           0 :         return c8_32 < c16_32 ? -1 : 1;
    1338             :       }
    1339             :     } else {
    1340        4179 :       if (c8_32 != *u16) {
    1341           0 :         return c8_32 > *u16 ? 1 : -1;
    1342             :       }
    1343             : 
    1344        4179 :       ++u8;
    1345        4179 :       ++u16;
    1346             :     }
    1347             :   }
    1348             : 
    1349         600 :   if (u8 != u8end) {
    1350             :     // We get to the end of the UTF16 string, but no to the end of
    1351             :     // the UTF8 string. The UTF8 string is longer than the UTF16
    1352             :     // string
    1353             : 
    1354           0 :     return 1;
    1355             :   }
    1356             : 
    1357         600 :   if (u16 != u16end) {
    1358             :     // We get to the end of the UTF8 string, but no to the end of
    1359             :     // the UTF16 string. The UTF16 string is longer than the UTF8
    1360             :     // string
    1361             : 
    1362           0 :     return -1;
    1363             :   }
    1364             : 
    1365             :   // The two strings match.
    1366             : 
    1367         600 :   return 0;
    1368             : }
    1369             : 
    1370             : void
    1371        1442 : AppendUCS4ToUTF16(const uint32_t aSource, nsAString& aDest)
    1372             : {
    1373        1442 :   NS_ASSERTION(IS_VALID_CHAR(aSource), "Invalid UCS4 char");
    1374        1442 :   if (IS_IN_BMP(aSource)) {
    1375        1442 :     aDest.Append(char16_t(aSource));
    1376             :   } else {
    1377           0 :     aDest.Append(H_SURROGATE(aSource));
    1378           0 :     aDest.Append(L_SURROGATE(aSource));
    1379             :   }
    1380        1442 : }
    1381             : 
    1382             : extern "C" {
    1383             : 
    1384           0 : void Gecko_AppendUTF16toCString(nsACString* aThis, const nsAString* aOther)
    1385             : {
    1386           0 :   AppendUTF16toUTF8(*aOther, *aThis);
    1387           0 : }
    1388             : 
    1389           0 : void Gecko_AppendUTF8toString(nsAString* aThis, const nsACString* aOther)
    1390             : {
    1391           0 :   AppendUTF8toUTF16(*aOther, *aThis);
    1392           0 : }
    1393             : 
    1394           0 : bool Gecko_FallibleAppendUTF16toCString(nsACString* aThis, const nsAString* aOther)
    1395             : {
    1396           0 :   return AppendUTF16toUTF8(*aOther, *aThis, mozilla::fallible);
    1397             : }
    1398             : 
    1399           0 : bool Gecko_FallibleAppendUTF8toString(nsAString* aThis, const nsACString* aOther)
    1400             : {
    1401           0 :   return AppendUTF8toUTF16(*aOther, *aThis, mozilla::fallible);
    1402             : }
    1403             : 
    1404             : }

Generated by: LCOV version 1.13