summaryrefslogtreecommitdiffstats
path: root/xpcom/string/nsReadableUtils.h
blob: 803c6b5d2f27c67515547218ea91e0f0e9f38c31 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// IWYU pragma: private, include "nsString.h"

#ifndef nsReadableUtils_h___
#define nsReadableUtils_h___

/**
 * I guess all the routines in this file are all mis-named.
 * According to our conventions, they should be |NS_xxx|.
 */

#include "mozilla/Assertions.h"
#include "nsAString.h"
#include "mozilla/TextUtils.h"

#include "nsTArrayForwardDeclare.h"

// From the nsstring crate
extern "C" {
bool nsstring_fallible_append_utf8_impl(nsAString* aThis, const char* aOther,
                                        size_t aOtherLen, size_t aOldLen);

bool nsstring_fallible_append_latin1_impl(nsAString* aThis, const char* aOther,
                                          size_t aOtherLen, size_t aOldLen,
                                          bool aAllowShrinking);

bool nscstring_fallible_append_utf16_to_utf8_impl(nsACString* aThis,
                                                  const char16_t*,
                                                  size_t aOtherLen,
                                                  size_t aOldLen);

bool nscstring_fallible_append_utf16_to_latin1_lossy_impl(nsACString* aThis,
                                                          const char16_t*,
                                                          size_t aOtherLen,
                                                          size_t aOldLen,
                                                          bool aAllowShrinking);

bool nscstring_fallible_append_utf8_to_latin1_lossy_check(
    nsACString* aThis, const nsACString* aOther, size_t aOldLen);

bool nscstring_fallible_append_latin1_to_utf8_check(nsACString* aThis,
                                                    const nsACString* aOther,
                                                    size_t aOldLen);
}

inline size_t Distance(const nsReadingIterator<char16_t>& aStart,
                       const nsReadingIterator<char16_t>& aEnd) {
  MOZ_ASSERT(aStart.get() <= aEnd.get());
  return static_cast<size_t>(aEnd.get() - aStart.get());
}

inline size_t Distance(const nsReadingIterator<char>& aStart,
                       const nsReadingIterator<char>& aEnd) {
  MOZ_ASSERT(aStart.get() <= aEnd.get());
  return static_cast<size_t>(aEnd.get() - aStart.get());
}

// NOTE: Operations that don't need an operand to be an XPCOM string
// are in mozilla/TextUtils.h and mozilla/Utf8.h.

// UTF-8 to UTF-16
// Invalid UTF-8 byte sequences are replaced with the REPLACEMENT CHARACTER.

[[nodiscard]] inline bool CopyUTF8toUTF16(mozilla::Span<const char> aSource,
                                          nsAString& aDest,
                                          const mozilla::fallible_t&) {
  return nsstring_fallible_append_utf8_impl(&aDest, aSource.Elements(),
                                            aSource.Length(), 0);
}

inline void CopyUTF8toUTF16(mozilla::Span<const char> aSource,
                            nsAString& aDest) {
  if (MOZ_UNLIKELY(!CopyUTF8toUTF16(aSource, aDest, mozilla::fallible))) {
    aDest.AllocFailed(aSource.Length());
  }
}

[[nodiscard]] inline bool AppendUTF8toUTF16(mozilla::Span<const char> aSource,
                                            nsAString& aDest,
                                            const mozilla::fallible_t&) {
  return nsstring_fallible_append_utf8_impl(&aDest, aSource.Elements(),
                                            aSource.Length(), aDest.Length());
}

inline void AppendUTF8toUTF16(mozilla::Span<const char> aSource,
                              nsAString& aDest) {
  if (MOZ_UNLIKELY(!AppendUTF8toUTF16(aSource, aDest, mozilla::fallible))) {
    aDest.AllocFailed(aDest.Length() + aSource.Length());
  }
}

// Latin1 to UTF-16
// Interpret each incoming unsigned byte value as a Unicode scalar value (not
// windows-1252!). The function names say "ASCII" instead of "Latin1" for
// legacy reasons.

[[nodiscard]] inline bool CopyASCIItoUTF16(mozilla::Span<const char> aSource,
                                           nsAString& aDest,
                                           const mozilla::fallible_t&) {
  return nsstring_fallible_append_latin1_impl(&aDest, aSource.Elements(),
                                              aSource.Length(), 0, true);
}

inline void CopyASCIItoUTF16(mozilla::Span<const char> aSource,
                             nsAString& aDest) {
  if (MOZ_UNLIKELY(!CopyASCIItoUTF16(aSource, aDest, mozilla::fallible))) {
    aDest.AllocFailed(aSource.Length());
  }
}

[[nodiscard]] inline bool AppendASCIItoUTF16(mozilla::Span<const char> aSource,
                                             nsAString& aDest,
                                             const mozilla::fallible_t&) {
  return nsstring_fallible_append_latin1_impl(
      &aDest, aSource.Elements(), aSource.Length(), aDest.Length(), false);
}

inline void AppendASCIItoUTF16(mozilla::Span<const char> aSource,
                               nsAString& aDest) {
  if (MOZ_UNLIKELY(!AppendASCIItoUTF16(aSource, aDest, mozilla::fallible))) {
    aDest.AllocFailed(aDest.Length() + aSource.Length());
  }
}

// UTF-16 to UTF-8
// Unpaired surrogates are replaced with the REPLACEMENT CHARACTER.

[[nodiscard]] inline bool CopyUTF16toUTF8(mozilla::Span<const char16_t> aSource,
                                          nsACString& aDest,
                                          const mozilla::fallible_t&) {
  return nscstring_fallible_append_utf16_to_utf8_impl(
      &aDest, aSource.Elements(), aSource.Length(), 0);
}

inline void CopyUTF16toUTF8(mozilla::Span<const char16_t> aSource,
                            nsACString& aDest) {
  if (MOZ_UNLIKELY(!CopyUTF16toUTF8(aSource, aDest, mozilla::fallible))) {
    aDest.AllocFailed(aSource.Length());
  }
}

[[nodiscard]] inline bool AppendUTF16toUTF8(
    mozilla::Span<const char16_t> aSource, nsACString& aDest,
    const mozilla::fallible_t&) {
  return nscstring_fallible_append_utf16_to_utf8_impl(
      &aDest, aSource.Elements(), aSource.Length(), aDest.Length());
}

inline void AppendUTF16toUTF8(mozilla::Span<const char16_t> aSource,
                              nsACString& aDest) {
  if (MOZ_UNLIKELY(!AppendUTF16toUTF8(aSource, aDest, mozilla::fallible))) {
    aDest.AllocFailed(aDest.Length() + aSource.Length());
  }
}

// UTF-16 to Latin1
// If all code points in the input are below U+0100, represents each scalar
// value as an unsigned byte. (This is not windows-1252!) If there are code
// points above U+00FF, memory-safely produces garbage and will likely start
// asserting in future debug builds. The nature of the garbage may differ
// based on CPU architecture and must not be relied upon. The names say
// "ASCII" instead of "Latin1" for legacy reasons.

[[nodiscard]] inline bool LossyCopyUTF16toASCII(
    mozilla::Span<const char16_t> aSource, nsACString& aDest,
    const mozilla::fallible_t&) {
  return nscstring_fallible_append_utf16_to_latin1_lossy_impl(
      &aDest, aSource.Elements(), aSource.Length(), 0, true);
}

inline void LossyCopyUTF16toASCII(mozilla::Span<const char16_t> aSource,
                                  nsACString& aDest) {
  if (MOZ_UNLIKELY(!LossyCopyUTF16toASCII(aSource, aDest, mozilla::fallible))) {
    aDest.AllocFailed(aSource.Length());
  }
}

[[nodiscard]] inline bool LossyAppendUTF16toASCII(
    mozilla::Span<const char16_t> aSource, nsACString& aDest,
    const mozilla::fallible_t&) {
  return nscstring_fallible_append_utf16_to_latin1_lossy_impl(
      &aDest, aSource.Elements(), aSource.Length(), aDest.Length(), false);
}

inline void LossyAppendUTF16toASCII(mozilla::Span<const char16_t> aSource,
                                    nsACString& aDest) {
  if (MOZ_UNLIKELY(
          !LossyAppendUTF16toASCII(aSource, aDest, mozilla::fallible))) {
    aDest.AllocFailed(aDest.Length() + aSource.Length());
  }
}

// Latin1 to UTF-8
// Interpret each incoming unsigned byte value as a Unicode scalar value (not
// windows-1252!).
// If the input is ASCII, the heap-allocated nsStringBuffer is shared if
// possible.

[[nodiscard]] inline bool CopyLatin1toUTF8(const nsACString& aSource,
                                           nsACString& aDest,
                                           const mozilla::fallible_t&) {
  return nscstring_fallible_append_latin1_to_utf8_check(&aDest, &aSource, 0);
}

inline void CopyLatin1toUTF8(const nsACString& aSource, nsACString& aDest) {
  if (MOZ_UNLIKELY(!CopyLatin1toUTF8(aSource, aDest, mozilla::fallible))) {
    aDest.AllocFailed(aSource.Length());
  }
}

[[nodiscard]] inline bool AppendLatin1toUTF8(const nsACString& aSource,
                                             nsACString& aDest,
                                             const mozilla::fallible_t&) {
  return nscstring_fallible_append_latin1_to_utf8_check(&aDest, &aSource,
                                                        aDest.Length());
}

inline void AppendLatin1toUTF8(const nsACString& aSource, nsACString& aDest) {
  if (MOZ_UNLIKELY(!AppendLatin1toUTF8(aSource, aDest, mozilla::fallible))) {
    aDest.AllocFailed(aDest.Length() + aSource.Length());
  }
}

// UTF-8 to Latin1
// If all code points in the input are below U+0100, represents each scalar
// value as an unsigned byte. (This is not windows-1252!) If there are code
// points above U+00FF, memory-safely produces garbage in release builds and
// asserts in debug builds. The nature of the garbage may differ
// based on CPU architecture and must not be relied upon.
// If the input is ASCII, the heap-allocated nsStringBuffer is shared if
// possible.

[[nodiscard]] inline bool LossyCopyUTF8toLatin1(const nsACString& aSource,
                                                nsACString& aDest,
                                                const mozilla::fallible_t&) {
  return nscstring_fallible_append_utf8_to_latin1_lossy_check(&aDest, &aSource,
                                                              0);
}

inline void LossyCopyUTF8toLatin1(const nsACString& aSource,
                                  nsACString& aDest) {
  if (MOZ_UNLIKELY(!LossyCopyUTF8toLatin1(aSource, aDest, mozilla::fallible))) {
    aDest.AllocFailed(aSource.Length());
  }
}

[[nodiscard]] inline bool LossyAppendUTF8toLatin1(const nsACString& aSource,
                                                  nsACString& aDest,
                                                  const mozilla::fallible_t&) {
  return nscstring_fallible_append_utf8_to_latin1_lossy_check(&aDest, &aSource,
                                                              aDest.Length());
}

inline void LossyAppendUTF8toLatin1(const nsACString& aSource,
                                    nsACString& aDest) {
  if (MOZ_UNLIKELY(
          !LossyAppendUTF8toLatin1(aSource, aDest, mozilla::fallible))) {
    aDest.AllocFailed(aDest.Length() + aSource.Length());
  }
}

/**
 * Returns a new |char| buffer containing a zero-terminated copy of |aSource|.
 *
 * Infallibly allocates and returns a new |char| buffer which you must
 * free with |free|.
 * Performs a conversion with LossyConvertUTF16toLatin1() writing into the
 * newly-allocated buffer.
 *
 * The new buffer is zero-terminated, but that may not help you if |aSource|
 * contains embedded nulls.
 *
 * @param aSource a 16-bit wide string
 * @return a new |char| buffer you must free with |free|.
 */
char* ToNewCString(const nsAString& aSource);

/* A fallible version of ToNewCString. Returns nullptr on failure. */
char* ToNewCString(const nsAString& aSource,
                   const mozilla::fallible_t& aFallible);

/**
 * Returns a new |char| buffer containing a zero-terminated copy of |aSource|.
 *
 * Infallibly allocates and returns a new |char| buffer which you must
 * free with |free|.
 *
 * The new buffer is zero-terminated, but that may not help you if |aSource|
 * contains embedded nulls.
 *
 * @param aSource an 8-bit wide string
 * @return a new |char| buffer you must free with |free|.
 */
char* ToNewCString(const nsACString& aSource);

/* A fallible version of ToNewCString. Returns nullptr on failure. */
char* ToNewCString(const nsACString& aSource,
                   const mozilla::fallible_t& aFallible);

/**
 * Returns a new |char| buffer containing a zero-terminated copy of |aSource|.
 *
 * Infallibly allocates and returns a new |char| buffer which you must
 * free with |free|.
 * Performs an encoding conversion from a UTF-16 string to a UTF-8 string with
 * unpaired surrogates replaced with the REPLACEMENT CHARACTER copying
 * |aSource| to your new buffer.
 *
 * The new buffer is zero-terminated, but that may not help you if |aSource|
 * contains embedded nulls.
 *
 * @param aSource a UTF-16 string (made of char16_t's)
 * @param aUTF8Count the number of 8-bit units that was returned
 * @return a new |char| buffer you must free with |free|.
 */
char* ToNewUTF8String(const nsAString& aSource, uint32_t* aUTF8Count = nullptr);

/* A fallible version of ToNewUTF8String. Returns nullptr on failure. */
char* ToNewUTF8String(const nsAString& aSource, uint32_t* aUTF8Count,
                      const mozilla::fallible_t& aFallible);

/**
 * Returns a new |char16_t| buffer containing a zero-terminated copy
 * of |aSource|.
 *
 * Infallibly allocates and returns a new |char16_t| buffer which you must
 * free with |free|.
 *
 * The new buffer is zero-terminated, but that may not help you if |aSource|
 * contains embedded nulls.
 *
 * @param aSource a UTF-16 string
 * @return a new |char16_t| buffer you must free with |free|.
 */
char16_t* ToNewUnicode(const nsAString& aSource);

/* A fallible version of ToNewUnicode. Returns nullptr on failure. */
char16_t* ToNewUnicode(const nsAString& aSource,
                       const mozilla::fallible_t& aFallible);

/**
 * Returns a new |char16_t| buffer containing a zero-terminated copy
 * of |aSource|.
 *
 * Infallibly allocates and returns a new |char16_t| buffer which you must
 * free with|free|.
 *
 * Performs an encoding conversion by 0-padding 8-bit wide characters up to
 * 16-bits wide (i.e. Latin1 to UTF-16 conversion) while copying |aSource|
 * to your new buffer.
 *
 * The new buffer is zero-terminated, but that may not help you if |aSource|
 * contains embedded nulls.
 *
 * @param aSource a Latin1 string
 * @return a new |char16_t| buffer you must free with |free|.
 */
char16_t* ToNewUnicode(const nsACString& aSource);

/* A fallible version of ToNewUnicode. Returns nullptr on failure. */
char16_t* ToNewUnicode(const nsACString& aSource,
                       const mozilla::fallible_t& aFallible);

/**
 * Returns a new |char16_t| buffer containing a zero-terminated copy
 * of |aSource|.
 *
 * Infallibly allocates and returns a new |char| buffer which you must
 * free with |free|.  Performs an encoding conversion from UTF-8 to UTF-16
 * while copying |aSource| to your new buffer.  Malformed byte sequences
 * are replaced with the REPLACEMENT CHARACTER.
 *
 * The new buffer is zero-terminated, but that may not help you if |aSource|
 * contains embedded nulls.
 *
 * @param aSource an 8-bit wide string, UTF-8 encoded
 * @param aUTF16Count the number of 16-bit units that was returned
 * @return a new |char16_t| buffer you must free with |free|.
 *         (UTF-16 encoded)
 */
char16_t* UTF8ToNewUnicode(const nsACString& aSource,
                           uint32_t* aUTF16Count = nullptr);

/* A fallible version of UTF8ToNewUnicode. Returns nullptr on failure. */
char16_t* UTF8ToNewUnicode(const nsACString& aSource, uint32_t* aUTF16Count,
                           const mozilla::fallible_t& aFallible);

/**
 * Copies |aLength| 16-bit code units from the start of |aSource| to the
 * |char16_t| buffer |aDest|.
 *
 * After this operation |aDest| is not null terminated.
 *
 * @param aSource a UTF-16 string
 * @param aSrcOffset start offset in the source string
 * @param aDest a |char16_t| buffer
 * @param aLength the number of 16-bit code units to copy
 * @return pointer to destination buffer - identical to |aDest|
 */
char16_t* CopyUnicodeTo(const nsAString& aSource, uint32_t aSrcOffset,
                        char16_t* aDest, uint32_t aLength);

/**
 * Replaces unpaired surrogates with U+FFFD in the argument.
 *
 * Copies a shared string buffer or an otherwise read-only
 * buffer only if there are unpaired surrogates.
 */
[[nodiscard]] inline bool EnsureUTF16Validity(nsAString& aString) {
  size_t upTo = mozilla::Utf16ValidUpTo(aString);
  size_t len = aString.Length();
  if (upTo == len) {
    return true;
  }
  char16_t* ptr = aString.BeginWriting(mozilla::fallible);
  if (!ptr) {
    return false;
  }
  auto span = mozilla::Span(ptr, len);
  span[upTo] = 0xFFFD;
  mozilla::EnsureUtf16ValiditySpan(span.From(upTo + 1));
  return true;
}

void ParseString(const nsACString& aSource, char aDelimiter,
                 nsTArray<nsCString>& aArray);

namespace mozilla::detail {

constexpr auto kStringJoinAppendDefault =
    [](auto& aResult, const auto& aValue) { aResult.Append(aValue); };

}  // namespace mozilla::detail

/**
 * Join a sequence of items, each optionally transformed to a string, with a
 * given separator, appending to a given string.
 *
 * \tparam CharType char or char16_t
 * \tparam InputRange a range usable with range-based for
 * \tparam Func optionally, a functor accepting a nsTSubstring<CharType>& and
 *   an item of InputRange which appends the latter to the former
 */
template <
    typename CharType, typename InputRange,
    typename Func = const decltype(mozilla::detail::kStringJoinAppendDefault)&>
void StringJoinAppend(
    nsTSubstring<CharType>& aOutput,
    const nsTLiteralString<CharType>& aSeparator, const InputRange& aInputRange,
    Func&& aFunc = mozilla::detail::kStringJoinAppendDefault) {
  bool first = true;
  for (const auto& item : aInputRange) {
    if (first) {
      first = false;
    } else {
      aOutput.Append(aSeparator);
    }

    aFunc(aOutput, item);
  }
}

/**
 * Join a sequence of items, each optionally transformed to a string, with a
 * given separator, returning a new string.
 *
 * \tparam CharType char or char16_t
 * \tparam InputRange a range usable with range-based for
 * \tparam Func optionally, a functor accepting a nsTSubstring<CharType>& and
 *   an item of InputRange which appends the latter to the former

 */
template <
    typename CharType, typename InputRange,
    typename Func = const decltype(mozilla::detail::kStringJoinAppendDefault)&>
auto StringJoin(const nsTLiteralString<CharType>& aSeparator,
                const InputRange& aInputRange,
                Func&& aFunc = mozilla::detail::kStringJoinAppendDefault) {
  nsTAutoString<CharType> res;
  StringJoinAppend(res, aSeparator, aInputRange, std::forward<Func>(aFunc));
  return res;
}

/**
 * Converts case in place in the argument string.
 */
void ToUpperCase(nsACString&);

void ToLowerCase(nsACString&);

void ToUpperCase(nsACString&);

void ToLowerCase(nsACString&);

/**
 * Converts case from string aSource to aDest.
 */
void ToUpperCase(const nsACString& aSource, nsACString& aDest);

void ToLowerCase(const nsACString& aSource, nsACString& aDest);

/**
 * Finds the leftmost occurrence of |aPattern|, if any in the range
 * |aSearchStart|..|aSearchEnd|.
 *
 * Returns |true| if a match was found, and adjusts |aSearchStart| and
 * |aSearchEnd| to point to the match.  If no match was found, returns |false|
 * and makes |aSearchStart == aSearchEnd|.
 *
 * Currently, this is equivalent to the O(m*n) implementation previously on
 * |ns[C]String|.
 *
 * If we need something faster, then we can implement that later.
 */

bool FindInReadable(const nsAString& aPattern, nsAString::const_iterator&,
                    nsAString::const_iterator&,
                    nsStringComparator = nsTDefaultStringComparator);
bool FindInReadable(const nsACString& aPattern, nsACString::const_iterator&,
                    nsACString::const_iterator&,
                    nsCStringComparator = nsTDefaultStringComparator);

/* sometimes we don't care about where the string was, just that we
 * found it or not */
inline bool FindInReadable(
    const nsAString& aPattern, const nsAString& aSource,
    nsStringComparator aCompare = nsTDefaultStringComparator) {
  nsAString::const_iterator start, end;
  aSource.BeginReading(start);
  aSource.EndReading(end);
  return FindInReadable(aPattern, start, end, aCompare);
}

inline bool FindInReadable(
    const nsACString& aPattern, const nsACString& aSource,
    nsCStringComparator aCompare = nsTDefaultStringComparator) {
  nsACString::const_iterator start, end;
  aSource.BeginReading(start);
  aSource.EndReading(end);
  return FindInReadable(aPattern, start, end, aCompare);
}

bool CaseInsensitiveFindInReadable(const nsACString& aPattern,
                                   nsACString::const_iterator&,
                                   nsACString::const_iterator&);

/**
 * Finds the rightmost occurrence of |aPattern|
 * Returns |true| if a match was found, and adjusts |aSearchStart| and
 * |aSearchEnd| to point to the match.  If no match was found, returns |false|
 * and makes |aSearchStart == aSearchEnd|.
 */
bool RFindInReadable(const nsAString& aPattern, nsAString::const_iterator&,
                     nsAString::const_iterator&,
                     nsStringComparator = nsTDefaultStringComparator);
bool RFindInReadable(const nsACString& aPattern, nsACString::const_iterator&,
                     nsACString::const_iterator&,
                     nsCStringComparator = nsTDefaultStringComparator);

/**
 * Finds the leftmost occurrence of |aChar|, if any in the range
 * |aSearchStart|..|aSearchEnd|.
 *
 * Returns |true| if a match was found, and adjusts |aSearchStart| to
 * point to the match.  If no match was found, returns |false| and
 * makes |aSearchStart == aSearchEnd|.
 */
bool FindCharInReadable(char16_t aChar, nsAString::const_iterator& aSearchStart,
                        const nsAString::const_iterator& aSearchEnd);
bool FindCharInReadable(char aChar, nsACString::const_iterator& aSearchStart,
                        const nsACString::const_iterator& aSearchEnd);

bool StringBeginsWith(const nsAString& aSource, const nsAString& aSubstring);
bool StringBeginsWith(const nsAString& aSource, const nsAString& aSubstring,
                      nsStringComparator);
bool StringBeginsWith(const nsACString& aSource, const nsACString& aSubstring);
bool StringBeginsWith(const nsACString& aSource, const nsACString& aSubstring,
                      nsCStringComparator);
bool StringEndsWith(const nsAString& aSource, const nsAString& aSubstring);
bool StringEndsWith(const nsAString& aSource, const nsAString& aSubstring,
                    nsStringComparator);
bool StringEndsWith(const nsACString& aSource, const nsACString& aSubstring);
bool StringEndsWith(const nsACString& aSource, const nsACString& aSubstring,
                    nsCStringComparator);

const nsString& EmptyString();
const nsCString& EmptyCString();

const nsString& VoidString();
const nsCString& VoidCString();

/**
 * Compare a UTF-8 string to an UTF-16 string.
 *
 * Returns 0 if the strings are equal, -1 if aUTF8String is less
 * than aUTF16Count, and 1 in the reverse case. Errors are replaced
 * with U+FFFD and then the U+FFFD is compared as if it had occurred
 * in the input. If aErr is not nullptr, *aErr is set to true if
 * either string had malformed sequences.
 */
int32_t CompareUTF8toUTF16(const nsACString& aUTF8String,
                           const nsAString& aUTF16String, bool* aErr = nullptr);

void AppendUCS4ToUTF16(const uint32_t aSource, nsAString& aDest);

#endif  // !defined(nsReadableUtils_h___)