Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/xpcom/string/nsReadableUtils.cpp
Line
Count
Source (jump to first uncovered line)
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
9
#include <algorithm>
10
11
#include "mozilla/CheckedInt.h"
12
13
#include "nscore.h"
14
#include "nsMemory.h"
15
#include "nsString.h"
16
#include "nsTArray.h"
17
#include "nsUTF8Utils.h"
18
19
using mozilla::MakeSpan;
20
21
/**
22
 * 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).
23
 *
24
 * @param aSource an string you will eventually be making a copy of
25
 * @return a new buffer (of the type specified by the second parameter) which you must free with |free|.
26
 *
27
 */
28
template <class FromStringT, class ToCharT>
29
inline
30
ToCharT*
31
AllocateStringCopy(const FromStringT& aSource, ToCharT*)
32
8
{
33
8
  // Can't overflow due to the definition of nsTSubstring<T>::kMaxCapacity
34
8
  return static_cast<ToCharT*>(
35
8
    moz_xmalloc((size_t(aSource.Length()) + 1) * sizeof(ToCharT)));
36
8
}
Unexecuted instantiation: char* AllocateStringCopy<nsTSubstring<char16_t>, char>(nsTSubstring<char16_t> const&, char*)
char* AllocateStringCopy<nsTSubstring<char>, char>(nsTSubstring<char> const&, char*)
Line
Count
Source
32
5
{
33
5
  // Can't overflow due to the definition of nsTSubstring<T>::kMaxCapacity
34
5
  return static_cast<ToCharT*>(
35
5
    moz_xmalloc((size_t(aSource.Length()) + 1) * sizeof(ToCharT)));
36
5
}
char16_t* AllocateStringCopy<nsTSubstring<char16_t>, char16_t>(nsTSubstring<char16_t> const&, char16_t*)
Line
Count
Source
32
3
{
33
3
  // Can't overflow due to the definition of nsTSubstring<T>::kMaxCapacity
34
3
  return static_cast<ToCharT*>(
35
3
    moz_xmalloc((size_t(aSource.Length()) + 1) * sizeof(ToCharT)));
36
3
}
Unexecuted instantiation: char16_t* AllocateStringCopy<nsTSubstring<char>, char16_t>(nsTSubstring<char> const&, char16_t*)
37
38
39
char*
40
ToNewCString(const nsAString& aSource)
41
0
{
42
0
  char* dest = AllocateStringCopy(aSource, (char*)nullptr);
43
0
  if (!dest) {
44
0
    return nullptr;
45
0
  }
46
0
47
0
  auto len = aSource.Length();
48
0
  LossyConvertUTF16toLatin1(aSource, MakeSpan(dest, len));
49
0
  dest[len] = 0;
50
0
  return dest;
51
0
}
52
53
char*
54
ToNewUTF8String(const nsAString& aSource, uint32_t* aUTF8Count)
55
0
{
56
0
  auto len = aSource.Length();
57
0
  // The uses of this function seem temporary enough that it's not
58
0
  // worthwhile to be fancy about the allocation size. Let's just use
59
0
  // the worst case.
60
0
  // Times 3 plus 2, because ConvertUTF16toUTF8 requires times 3 plus 1 and
61
0
  // then we have the terminator.
62
0
  // Using CheckedInt<uint32_t>, because aUTF8Count is uint32_t* for
63
0
  // historical reasons.
64
0
  mozilla::CheckedInt<uint32_t> destLen(len);
65
0
  destLen *= 3;
66
0
  destLen += 2;
67
0
  if (!destLen.isValid()) {
68
0
    return nullptr;
69
0
  }
70
0
  size_t destLenVal = destLen.value();
71
0
  char* dest = static_cast<char*>(moz_xmalloc(destLenVal));
72
0
73
0
  size_t written = ConvertUTF16toUTF8(aSource, MakeSpan(dest, destLenVal));
74
0
  dest[written] = 0;
75
0
76
0
  if (aUTF8Count) {
77
0
    *aUTF8Count = written;
78
0
  }
79
0
80
0
  return dest;
81
0
}
82
83
char*
84
ToNewCString(const nsACString& aSource)
85
5
{
86
5
  // no conversion needed, just allocate a buffer of the correct length and copy into it
87
5
88
5
  char* dest = AllocateStringCopy(aSource, (char*)nullptr);
89
5
  if (!dest) {
90
0
    return nullptr;
91
0
  }
92
5
93
5
  auto len = aSource.Length();
94
5
  memcpy(dest, aSource.BeginReading(), len * sizeof(char));
95
5
  dest[len] = 0;
96
5
  return dest;
97
5
}
98
99
char16_t*
100
ToNewUnicode(const nsAString& aSource)
101
3
{
102
3
  // no conversion needed, just allocate a buffer of the correct length and copy into it
103
3
104
3
  char16_t* dest = AllocateStringCopy(aSource, (char16_t*)nullptr);
105
3
  if (!dest) {
106
0
    return nullptr;
107
0
  }
108
3
109
3
  auto len = aSource.Length();
110
3
  memcpy(dest, aSource.BeginReading(), len * sizeof(char16_t));
111
3
  dest[len] = 0;
112
3
  return dest;
113
3
}
114
115
char16_t*
116
ToNewUnicode(const nsACString& aSource)
117
0
{
118
0
  char16_t* dest = AllocateStringCopy(aSource, (char16_t*)nullptr);
119
0
  if (!dest) {
120
0
    return nullptr;
121
0
  }
122
0
123
0
  auto len = aSource.Length();
124
0
  ConvertLatin1toUTF16(aSource, MakeSpan(dest, len));
125
0
  dest[len] = 0;
126
0
  return dest;
127
0
}
128
129
char16_t*
130
UTF8ToNewUnicode(const nsACString& aSource, uint32_t* aUTF16Count)
131
0
{
132
0
  // Compute length plus one as required by ConvertUTF8toUTF16
133
0
  uint32_t lengthPlusOne = aSource.Length() + 1; // Can't overflow
134
0
135
0
  mozilla::CheckedInt<size_t> allocLength(lengthPlusOne);
136
0
  // Add space for zero-termination
137
0
  allocLength += 1;
138
0
  // We need UTF-16 units
139
0
  allocLength *= sizeof(char16_t);
140
0
141
0
  if (!allocLength.isValid()) {
142
0
    return nullptr;
143
0
  }
144
0
145
0
  char16_t* dest = (char16_t*)moz_xmalloc(allocLength.value());
146
0
147
0
  size_t written = ConvertUTF8toUTF16(aSource, MakeSpan(dest, lengthPlusOne));
148
0
  dest[written] = 0;
149
0
150
0
  if (aUTF16Count) {
151
0
    *aUTF16Count = written;
152
0
  }
153
0
154
0
  return dest;
155
0
}
156
157
char16_t*
158
CopyUnicodeTo(const nsAString& aSource, uint32_t aSrcOffset, char16_t* aDest,
159
              uint32_t aLength)
160
0
{
161
0
  MOZ_ASSERT(aSrcOffset + aLength <= aSource.Length());
162
0
  memcpy(aDest,
163
0
         aSource.BeginReading() + aSrcOffset,
164
0
         size_t(aLength) * sizeof(char16_t));
165
0
  return aDest;
166
0
}
167
168
void
169
ToUpperCase(nsACString& aCString)
170
12
{
171
12
  char* cp = aCString.BeginWriting();
172
12
  char* end = cp + aCString.Length();
173
36
  while (cp != end) {
174
24
    char ch = *cp;
175
24
    if (ch >= 'a' && ch <= 'z') {
176
0
      *cp = ch - ('a' - 'A');
177
0
    }
178
24
    ++cp;
179
24
  }
180
12
}
181
182
void
183
ToUpperCase(const nsACString& aSource, nsACString& aDest)
184
0
{
185
0
  aDest.SetLength(aSource.Length());
186
0
  const char* src = aSource.BeginReading();
187
0
  const char* end = src + aSource.Length();
188
0
  char* dst = aDest.BeginWriting();
189
0
  while (src != end) {
190
0
    char ch = *src;
191
0
    if (ch >= 'a' && ch <= 'z') {
192
0
      *dst = ch - ('a' - 'A');
193
0
    } else {
194
0
      *dst = ch;
195
0
    }
196
0
    ++src;
197
0
    ++dst;
198
0
  }
199
0
}
200
201
void
202
ToLowerCase(nsACString& aCString)
203
6.91M
{
204
6.91M
  char* cp = aCString.BeginWriting();
205
6.91M
  char* end = cp + aCString.Length();
206
113M
  while (cp != end) {
207
106M
    char ch = *cp;
208
106M
    if (ch >= 'A' && ch <= 'Z') {
209
296k
      *cp = ch + ('a' - 'A');
210
296k
    }
211
106M
    ++cp;
212
106M
  }
213
6.91M
}
214
215
void
216
ToLowerCase(const nsACString& aSource, nsACString& aDest)
217
30
{
218
30
  aDest.SetLength(aSource.Length());
219
30
  const char* src = aSource.BeginReading();
220
30
  const char* end = src + aSource.Length();
221
30
  char* dst = aDest.BeginWriting();
222
456
  while (src != end) {
223
426
    char ch = *src;
224
426
    if (ch >= 'A' && ch <= 'Z') {
225
0
      *dst = ch + ('a' - 'A');
226
426
    } else {
227
426
      *dst = ch;
228
426
    }
229
426
    ++src;
230
426
    ++dst;
231
426
  }
232
30
}
233
234
bool
235
ParseString(const nsACString& aSource, char aDelimiter,
236
            nsTArray<nsCString>& aArray)
237
0
{
238
0
  nsACString::const_iterator start, end;
239
0
  aSource.BeginReading(start);
240
0
  aSource.EndReading(end);
241
0
242
0
  uint32_t oldLength = aArray.Length();
243
0
244
0
  for (;;) {
245
0
    nsACString::const_iterator delimiter = start;
246
0
    FindCharInReadable(aDelimiter, delimiter, end);
247
0
248
0
    if (delimiter != start) {
249
0
      if (!aArray.AppendElement(Substring(start, delimiter))) {
250
0
        aArray.RemoveElementsAt(oldLength, aArray.Length() - oldLength);
251
0
        return false;
252
0
      }
253
0
    }
254
0
255
0
    if (delimiter == end) {
256
0
      break;
257
0
    }
258
0
    start = ++delimiter;
259
0
    if (start == end) {
260
0
      break;
261
0
    }
262
0
  }
263
0
264
0
  return true;
265
0
}
266
267
template <class StringT, class IteratorT, class Comparator>
268
bool
269
FindInReadable_Impl(const StringT& aPattern, IteratorT& aSearchStart,
270
                    IteratorT& aSearchEnd, const Comparator& aCompare)
271
5.28k
{
272
5.28k
  bool found_it = false;
273
5.28k
274
5.28k
  // only bother searching at all if we're given a non-empty range to search
275
5.28k
  if (aSearchStart != aSearchEnd) {
276
5.27k
    IteratorT aPatternStart, aPatternEnd;
277
5.27k
    aPattern.BeginReading(aPatternStart);
278
5.27k
    aPattern.EndReading(aPatternEnd);
279
5.27k
280
5.27k
    // outer loop keeps searching till we find it or run out of string to search
281
8.54k
    while (!found_it) {
282
6.05k
      // fast inner loop (that's what it's called, not what it is) looks for a potential match
283
92.8k
      while (aSearchStart != aSearchEnd &&
284
92.8k
             aCompare(aPatternStart.get(), aSearchStart.get(), 1, 1)) {
285
86.8k
        ++aSearchStart;
286
86.8k
      }
287
6.05k
288
6.05k
      // if we broke out of the `fast' loop because we're out of string ... we're done: no match
289
6.05k
      if (aSearchStart == aSearchEnd) {
290
2.78k
        break;
291
2.78k
      }
292
3.26k
293
3.26k
      // otherwise, we're at a potential match, let's see if we really hit one
294
3.26k
      IteratorT testPattern(aPatternStart);
295
3.26k
      IteratorT testSearch(aSearchStart);
296
3.26k
297
3.26k
      // slow inner loop verifies the potential match (found by the `fast' loop) at the current position
298
5.82k
      for (;;) {
299
5.82k
        // we already compared the first character in the outer loop,
300
5.82k
        //  so we'll advance before the next comparison
301
5.82k
        ++testPattern;
302
5.82k
        ++testSearch;
303
5.82k
304
5.82k
        // if we verified all the way to the end of the pattern, then we found it!
305
5.82k
        if (testPattern == aPatternEnd) {
306
2.49k
          found_it = true;
307
2.49k
          aSearchEnd = testSearch; // return the exact found range through the parameters
308
2.49k
          break;
309
2.49k
        }
310
3.33k
311
3.33k
        // if we got to end of the string we're searching before we hit the end of the
312
3.33k
        //  pattern, we'll never find what we're looking for
313
3.33k
        if (testSearch == aSearchEnd) {
314
5
          aSearchStart = aSearchEnd;
315
5
          break;
316
5
        }
317
3.33k
318
3.33k
        // else if we mismatched ... it's time to advance to the next search position
319
3.33k
        //  and get back into the `fast' loop
320
3.33k
        if (aCompare(testPattern.get(), testSearch.get(), 1, 1)) {
321
767
          ++aSearchStart;
322
767
          break;
323
767
        }
324
3.33k
      }
325
3.26k
    }
326
5.27k
  }
327
5.28k
328
5.28k
  return found_it;
329
5.28k
}
Unexecuted instantiation: bool FindInReadable_Impl<nsTSubstring<char16_t>, nsReadingIterator<char16_t>, nsTStringComparator<char16_t> >(nsTSubstring<char16_t> const&, nsReadingIterator<char16_t>&, nsReadingIterator<char16_t>&, nsTStringComparator<char16_t> const&)
bool FindInReadable_Impl<nsTSubstring<char>, nsReadingIterator<char>, nsTStringComparator<char> >(nsTSubstring<char> const&, nsReadingIterator<char>&, nsReadingIterator<char>&, nsTStringComparator<char> const&)
Line
Count
Source
271
5.28k
{
272
5.28k
  bool found_it = false;
273
5.28k
274
5.28k
  // only bother searching at all if we're given a non-empty range to search
275
5.28k
  if (aSearchStart != aSearchEnd) {
276
5.27k
    IteratorT aPatternStart, aPatternEnd;
277
5.27k
    aPattern.BeginReading(aPatternStart);
278
5.27k
    aPattern.EndReading(aPatternEnd);
279
5.27k
280
5.27k
    // outer loop keeps searching till we find it or run out of string to search
281
8.54k
    while (!found_it) {
282
6.05k
      // fast inner loop (that's what it's called, not what it is) looks for a potential match
283
92.8k
      while (aSearchStart != aSearchEnd &&
284
92.8k
             aCompare(aPatternStart.get(), aSearchStart.get(), 1, 1)) {
285
86.8k
        ++aSearchStart;
286
86.8k
      }
287
6.05k
288
6.05k
      // if we broke out of the `fast' loop because we're out of string ... we're done: no match
289
6.05k
      if (aSearchStart == aSearchEnd) {
290
2.78k
        break;
291
2.78k
      }
292
3.26k
293
3.26k
      // otherwise, we're at a potential match, let's see if we really hit one
294
3.26k
      IteratorT testPattern(aPatternStart);
295
3.26k
      IteratorT testSearch(aSearchStart);
296
3.26k
297
3.26k
      // slow inner loop verifies the potential match (found by the `fast' loop) at the current position
298
5.82k
      for (;;) {
299
5.82k
        // we already compared the first character in the outer loop,
300
5.82k
        //  so we'll advance before the next comparison
301
5.82k
        ++testPattern;
302
5.82k
        ++testSearch;
303
5.82k
304
5.82k
        // if we verified all the way to the end of the pattern, then we found it!
305
5.82k
        if (testPattern == aPatternEnd) {
306
2.49k
          found_it = true;
307
2.49k
          aSearchEnd = testSearch; // return the exact found range through the parameters
308
2.49k
          break;
309
2.49k
        }
310
3.33k
311
3.33k
        // if we got to end of the string we're searching before we hit the end of the
312
3.33k
        //  pattern, we'll never find what we're looking for
313
3.33k
        if (testSearch == aSearchEnd) {
314
5
          aSearchStart = aSearchEnd;
315
5
          break;
316
5
        }
317
3.33k
318
3.33k
        // else if we mismatched ... it's time to advance to the next search position
319
3.33k
        //  and get back into the `fast' loop
320
3.33k
        if (aCompare(testPattern.get(), testSearch.get(), 1, 1)) {
321
767
          ++aSearchStart;
322
767
          break;
323
767
        }
324
3.33k
      }
325
3.26k
    }
326
5.27k
  }
327
5.28k
328
5.28k
  return found_it;
329
5.28k
}
Unexecuted instantiation: bool FindInReadable_Impl<nsTSubstring<char>, nsReadingIterator<char>, nsCaseInsensitiveCStringComparator>(nsTSubstring<char> const&, nsReadingIterator<char>&, nsReadingIterator<char>&, nsCaseInsensitiveCStringComparator const&)
330
331
/**
332
 * This searches the entire string from right to left, and returns the first match found, if any.
333
 */
334
template <class StringT, class IteratorT, class Comparator>
335
bool
336
RFindInReadable_Impl(const StringT& aPattern, IteratorT& aSearchStart,
337
                     IteratorT& aSearchEnd, const Comparator& aCompare)
338
8.72k
{
339
8.72k
  IteratorT patternStart, patternEnd, searchEnd = aSearchEnd;
340
8.72k
  aPattern.BeginReading(patternStart);
341
8.72k
  aPattern.EndReading(patternEnd);
342
8.72k
343
8.72k
  // Point to the last character in the pattern
344
8.72k
  --patternEnd;
345
8.72k
  // outer loop keeps searching till we run out of string to search
346
286k
  while (aSearchStart != searchEnd) {
347
279k
    // Point to the end position of the next possible match
348
279k
    --searchEnd;
349
279k
350
279k
    // Check last character, if a match, explore further from here
351
279k
    if (aCompare(patternEnd.get(), searchEnd.get(), 1, 1) == 0) {
352
3.26k
      // We're at a potential match, let's see if we really hit one
353
3.26k
      IteratorT testPattern(patternEnd);
354
3.26k
      IteratorT testSearch(searchEnd);
355
3.26k
356
3.26k
      // inner loop verifies the potential match at the current position
357
5.74k
      do {
358
5.74k
        // if we verified all the way to the end of the pattern, then we found it!
359
5.74k
        if (testPattern == patternStart) {
360
2.48k
          aSearchStart = testSearch;  // point to start of match
361
2.48k
          aSearchEnd = ++searchEnd;   // point to end of match
362
2.48k
          return true;
363
2.48k
        }
364
3.26k
365
3.26k
        // if we got to end of the string we're searching before we hit the end of the
366
3.26k
        //  pattern, we'll never find what we're looking for
367
3.26k
        if (testSearch == aSearchStart) {
368
50
          aSearchStart = aSearchEnd;
369
50
          return false;
370
50
        }
371
3.21k
372
3.21k
        // test previous character for a match
373
3.21k
        --testPattern;
374
3.21k
        --testSearch;
375
3.21k
      } while (aCompare(testPattern.get(), testSearch.get(), 1, 1) == 0);
376
3.26k
    }
377
279k
  }
378
8.72k
379
8.72k
  aSearchStart = aSearchEnd;
380
6.18k
  return false;
381
8.72k
}
Unexecuted instantiation: bool RFindInReadable_Impl<nsTSubstring<char16_t>, nsReadingIterator<char16_t>, nsTStringComparator<char16_t> >(nsTSubstring<char16_t> const&, nsReadingIterator<char16_t>&, nsReadingIterator<char16_t>&, nsTStringComparator<char16_t> const&)
bool RFindInReadable_Impl<nsTSubstring<char>, nsReadingIterator<char>, nsTStringComparator<char> >(nsTSubstring<char> const&, nsReadingIterator<char>&, nsReadingIterator<char>&, nsTStringComparator<char> const&)
Line
Count
Source
338
8.72k
{
339
8.72k
  IteratorT patternStart, patternEnd, searchEnd = aSearchEnd;
340
8.72k
  aPattern.BeginReading(patternStart);
341
8.72k
  aPattern.EndReading(patternEnd);
342
8.72k
343
8.72k
  // Point to the last character in the pattern
344
8.72k
  --patternEnd;
345
8.72k
  // outer loop keeps searching till we run out of string to search
346
286k
  while (aSearchStart != searchEnd) {
347
279k
    // Point to the end position of the next possible match
348
279k
    --searchEnd;
349
279k
350
279k
    // Check last character, if a match, explore further from here
351
279k
    if (aCompare(patternEnd.get(), searchEnd.get(), 1, 1) == 0) {
352
3.26k
      // We're at a potential match, let's see if we really hit one
353
3.26k
      IteratorT testPattern(patternEnd);
354
3.26k
      IteratorT testSearch(searchEnd);
355
3.26k
356
3.26k
      // inner loop verifies the potential match at the current position
357
5.74k
      do {
358
5.74k
        // if we verified all the way to the end of the pattern, then we found it!
359
5.74k
        if (testPattern == patternStart) {
360
2.48k
          aSearchStart = testSearch;  // point to start of match
361
2.48k
          aSearchEnd = ++searchEnd;   // point to end of match
362
2.48k
          return true;
363
2.48k
        }
364
3.26k
365
3.26k
        // if we got to end of the string we're searching before we hit the end of the
366
3.26k
        //  pattern, we'll never find what we're looking for
367
3.26k
        if (testSearch == aSearchStart) {
368
50
          aSearchStart = aSearchEnd;
369
50
          return false;
370
50
        }
371
3.21k
372
3.21k
        // test previous character for a match
373
3.21k
        --testPattern;
374
3.21k
        --testSearch;
375
3.21k
      } while (aCompare(testPattern.get(), testSearch.get(), 1, 1) == 0);
376
3.26k
    }
377
279k
  }
378
8.72k
379
8.72k
  aSearchStart = aSearchEnd;
380
6.18k
  return false;
381
8.72k
}
382
383
bool
384
FindInReadable(const nsAString& aPattern,
385
               nsAString::const_iterator& aSearchStart,
386
               nsAString::const_iterator& aSearchEnd,
387
               const nsStringComparator& aComparator)
388
0
{
389
0
  return FindInReadable_Impl(aPattern, aSearchStart, aSearchEnd, aComparator);
390
0
}
391
392
bool
393
FindInReadable(const nsACString& aPattern,
394
               nsACString::const_iterator& aSearchStart,
395
               nsACString::const_iterator& aSearchEnd,
396
               const nsCStringComparator& aComparator)
397
5.28k
{
398
5.28k
  return FindInReadable_Impl(aPattern, aSearchStart, aSearchEnd, aComparator);
399
5.28k
}
400
401
bool
402
CaseInsensitiveFindInReadable(const nsACString& aPattern,
403
                              nsACString::const_iterator& aSearchStart,
404
                              nsACString::const_iterator& aSearchEnd)
405
0
{
406
0
  return FindInReadable_Impl(aPattern, aSearchStart, aSearchEnd,
407
0
                             nsCaseInsensitiveCStringComparator());
408
0
}
409
410
bool
411
RFindInReadable(const nsAString& aPattern,
412
                nsAString::const_iterator& aSearchStart,
413
                nsAString::const_iterator& aSearchEnd,
414
                const nsStringComparator& aComparator)
415
0
{
416
0
  return RFindInReadable_Impl(aPattern, aSearchStart, aSearchEnd, aComparator);
417
0
}
418
419
bool
420
RFindInReadable(const nsACString& aPattern,
421
                nsACString::const_iterator& aSearchStart,
422
                nsACString::const_iterator& aSearchEnd,
423
                const nsCStringComparator& aComparator)
424
8.72k
{
425
8.72k
  return RFindInReadable_Impl(aPattern, aSearchStart, aSearchEnd, aComparator);
426
8.72k
}
427
428
bool
429
FindCharInReadable(char16_t aChar, nsAString::const_iterator& aSearchStart,
430
                   const nsAString::const_iterator& aSearchEnd)
431
0
{
432
0
  int32_t fragmentLength = aSearchEnd.get() - aSearchStart.get();
433
0
434
0
  const char16_t* charFoundAt =
435
0
    nsCharTraits<char16_t>::find(aSearchStart.get(), fragmentLength, aChar);
436
0
  if (charFoundAt) {
437
0
    aSearchStart.advance(charFoundAt - aSearchStart.get());
438
0
    return true;
439
0
  }
440
0
441
0
  aSearchStart.advance(fragmentLength);
442
0
  return false;
443
0
}
444
445
bool
446
FindCharInReadable(char aChar, nsACString::const_iterator& aSearchStart,
447
                   const nsACString::const_iterator& aSearchEnd)
448
66
{
449
66
  int32_t fragmentLength = aSearchEnd.get() - aSearchStart.get();
450
66
451
66
  const char* charFoundAt =
452
66
    nsCharTraits<char>::find(aSearchStart.get(), fragmentLength, aChar);
453
66
  if (charFoundAt) {
454
0
    aSearchStart.advance(charFoundAt - aSearchStart.get());
455
0
    return true;
456
0
  }
457
66
458
66
  aSearchStart.advance(fragmentLength);
459
66
  return false;
460
66
}
461
462
bool
463
StringBeginsWith(const nsAString& aSource, const nsAString& aSubstring)
464
3.70k
{
465
3.70k
  nsAString::size_type src_len = aSource.Length(),
466
3.70k
                       sub_len = aSubstring.Length();
467
3.70k
  if (sub_len > src_len) {
468
1.13k
    return false;
469
1.13k
  }
470
2.57k
  return Substring(aSource, 0, sub_len).Equals(aSubstring);
471
2.57k
}
472
473
bool
474
StringBeginsWith(const nsAString& aSource, const nsAString& aSubstring,
475
                 const nsStringComparator& aComparator)
476
204k
{
477
204k
  nsAString::size_type src_len = aSource.Length(),
478
204k
                       sub_len = aSubstring.Length();
479
204k
  if (sub_len > src_len) {
480
181k
    return false;
481
181k
  }
482
22.9k
  return Substring(aSource, 0, sub_len).Equals(aSubstring, aComparator);
483
22.9k
}
484
485
bool
486
StringBeginsWith(const nsACString& aSource, const nsACString& aSubstring)
487
0
{
488
0
  nsACString::size_type src_len = aSource.Length(),
489
0
                        sub_len = aSubstring.Length();
490
0
  if (sub_len > src_len) {
491
0
    return false;
492
0
  }
493
0
  return Substring(aSource, 0, sub_len).Equals(aSubstring);
494
0
}
495
496
bool
497
StringBeginsWith(const nsACString& aSource, const nsACString& aSubstring,
498
                 const nsCStringComparator& aComparator)
499
0
{
500
0
  nsACString::size_type src_len = aSource.Length(),
501
0
                        sub_len = aSubstring.Length();
502
0
  if (sub_len > src_len) {
503
0
    return false;
504
0
  }
505
0
  return Substring(aSource, 0, sub_len).Equals(aSubstring, aComparator);
506
0
}
507
508
bool
509
StringEndsWith(const nsAString& aSource, const nsAString& aSubstring)
510
0
{
511
0
  nsAString::size_type src_len = aSource.Length(),
512
0
                       sub_len = aSubstring.Length();
513
0
  if (sub_len > src_len) {
514
0
    return false;
515
0
  }
516
0
  return Substring(aSource, src_len - sub_len, sub_len).Equals(aSubstring);
517
0
}
518
519
bool
520
StringEndsWith(const nsAString& aSource, const nsAString& aSubstring,
521
               const nsStringComparator& aComparator)
522
0
{
523
0
  nsAString::size_type src_len = aSource.Length(),
524
0
                       sub_len = aSubstring.Length();
525
0
  if (sub_len > src_len) {
526
0
    return false;
527
0
  }
528
0
  return Substring(aSource, src_len - sub_len, sub_len).Equals(aSubstring,
529
0
                                                               aComparator);
530
0
}
531
532
bool
533
StringEndsWith(const nsACString& aSource, const nsACString& aSubstring)
534
1
{
535
1
  nsACString::size_type src_len = aSource.Length(),
536
1
                        sub_len = aSubstring.Length();
537
1
  if (sub_len > src_len) {
538
0
    return false;
539
0
  }
540
1
  return Substring(aSource, src_len - sub_len, sub_len).Equals(aSubstring);
541
1
}
542
543
bool
544
StringEndsWith(const nsACString& aSource, const nsACString& aSubstring,
545
               const nsCStringComparator& aComparator)
546
3
{
547
3
  nsACString::size_type src_len = aSource.Length(),
548
3
                        sub_len = aSubstring.Length();
549
3
  if (sub_len > src_len) {
550
0
    return false;
551
0
  }
552
3
  return Substring(aSource, src_len - sub_len, sub_len).Equals(aSubstring,
553
3
                                                               aComparator);
554
3
}
555
556
557
558
static const char16_t empty_buffer[1] = { '\0' };
559
560
const nsString&
561
EmptyString()
562
1.11M
{
563
1.11M
  static const nsDependentString sEmpty(empty_buffer);
564
1.11M
565
1.11M
  return sEmpty;
566
1.11M
}
567
568
const nsCString&
569
EmptyCString()
570
1.15M
{
571
1.15M
  static const nsDependentCString sEmpty((const char*)empty_buffer);
572
1.15M
573
1.15M
  return sEmpty;
574
1.15M
}
575
576
const nsString&
577
VoidString()
578
0
{
579
0
  static const nsString sNull(mozilla::detail::StringDataFlags::VOIDED);
580
0
581
0
  return sNull;
582
0
}
583
584
const nsCString&
585
VoidCString()
586
24
{
587
24
  static const nsCString sNull(mozilla::detail::StringDataFlags::VOIDED);
588
24
589
24
  return sNull;
590
24
}
591
592
int32_t
593
CompareUTF8toUTF16(const nsACString& aUTF8String,
594
                   const nsAString& aUTF16String,
595
                   bool* aErr)
596
11.7k
{
597
11.7k
  const char* u8;
598
11.7k
  const char* u8end;
599
11.7k
  aUTF8String.BeginReading(u8);
600
11.7k
  aUTF8String.EndReading(u8end);
601
11.7k
602
11.7k
  const char16_t* u16;
603
11.7k
  const char16_t* u16end;
604
11.7k
  aUTF16String.BeginReading(u16);
605
11.7k
  aUTF16String.EndReading(u16end);
606
11.7k
607
116k
  for (;;) {
608
116k
    if (u8 == u8end) {
609
11.7k
      if (u16 == u16end) {
610
11.7k
        return 0;
611
11.7k
      }
612
0
      return -1;
613
0
    }
614
105k
    if (u16 == u16end) {
615
0
      return 1;
616
0
    }
617
105k
    // No need for ASCII optimization, since both NextChar()
618
105k
    // calls get inlined.
619
105k
    uint32_t scalar8 = UTF8CharEnumerator::NextChar(&u8, u8end, aErr);
620
105k
    uint32_t scalar16 = UTF16CharEnumerator::NextChar(&u16, u16end, aErr);
621
105k
    if (scalar16 == scalar8) {
622
105k
      continue;
623
105k
    }
624
0
    if (scalar8 < scalar16) {
625
0
      return -1;
626
0
    }
627
0
    return 1;
628
0
  }
629
11.7k
}
630
631
void
632
AppendUCS4ToUTF16(const uint32_t aSource, nsAString& aDest)
633
0
{
634
0
  NS_ASSERTION(IS_VALID_CHAR(aSource), "Invalid UCS4 char");
635
0
  if (IS_IN_BMP(aSource)) {
636
0
    aDest.Append(char16_t(aSource));
637
0
  } else {
638
0
    aDest.Append(H_SURROGATE(aSource));
639
0
    aDest.Append(L_SURROGATE(aSource));
640
0
  }
641
0
}