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 : }
|