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