tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

String.h (24850B)


      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 /* JavaScript string operations. */
      8 
      9 #ifndef js_String_h
     10 #define js_String_h
     11 
     12 #include "js/shadow/String.h"  // JS::shadow::String
     13 
     14 #include "mozilla/Assertions.h"    // MOZ_ASSERT
     15 #include "mozilla/Attributes.h"    // MOZ_ALWAYS_INLINE
     16 #include "mozilla/Likely.h"        // MOZ_LIKELY
     17 #include "mozilla/Maybe.h"         // mozilla::Maybe
     18 #include "mozilla/Range.h"         // mozilla::Range
     19 #include "mozilla/RefPtr.h"        // RefPtr
     20 #include "mozilla/Span.h"          // mozilla::Span
     21                                   // std::tuple
     22 #include "mozilla/StringBuffer.h"  // mozilla::StringBuffer
     23 
     24 #include <algorithm>  // std::copy_n
     25 #include <stddef.h>   // size_t
     26 #include <stdint.h>   // uint32_t, uint64_t, INT32_MAX
     27 
     28 #include "jstypes.h"  // JS_PUBLIC_API
     29 
     30 #include "js/CharacterEncoding.h"  // JS::UTF8Chars, JS::ConstUTF8CharsZ
     31 #include "js/RootingAPI.h"         // JS::Handle
     32 #include "js/TypeDecls.h"          // JS::Latin1Char
     33 #include "js/UniquePtr.h"          // JS::UniquePtr
     34 #include "js/Utility.h"            // JS::FreePolicy, JS::UniqueTwoByteChars
     35 #include "js/Value.h"              // JS::Value
     36 
     37 struct JS_PUBLIC_API JSContext;
     38 class JS_PUBLIC_API JSAtom;
     39 class JSLinearString;
     40 class JS_PUBLIC_API JSString;
     41 
     42 namespace JS {
     43 
     44 class JS_PUBLIC_API AutoRequireNoGC;
     45 
     46 }  // namespace JS
     47 
     48 extern JS_PUBLIC_API JSString* JS_GetEmptyString(JSContext* cx);
     49 
     50 // Don't want to export data, so provide accessors for non-inline Values.
     51 extern JS_PUBLIC_API JS::Value JS_GetEmptyStringValue(JSContext* cx);
     52 
     53 /*
     54 * String creation.
     55 *
     56 * NB: JS_NewUCString takes ownership of bytes on success, avoiding a copy;
     57 * but on error (signified by null return), it leaves chars owned by the
     58 * caller. So the caller must free bytes in the error case, if it has no use
     59 * for them. In contrast, all the JS_New*StringCopy* functions do not take
     60 * ownership of the character memory passed to them -- they copy it.
     61 */
     62 
     63 extern JS_PUBLIC_API JSString* JS_NewStringCopyN(JSContext* cx, const char* s,
     64                                                 size_t n);
     65 
     66 extern JS_PUBLIC_API JSString* JS_NewStringCopyZ(JSContext* cx, const char* s);
     67 
     68 extern JS_PUBLIC_API JSString* JS_NewStringCopyUTF8Z(
     69    JSContext* cx, const JS::ConstUTF8CharsZ s);
     70 
     71 extern JS_PUBLIC_API JSString* JS_NewStringCopyUTF8N(JSContext* cx,
     72                                                     const JS::UTF8Chars& s);
     73 
     74 extern JS_PUBLIC_API JSString* JS_AtomizeStringN(JSContext* cx, const char* s,
     75                                                 size_t length);
     76 
     77 extern JS_PUBLIC_API JSString* JS_AtomizeString(JSContext* cx, const char* s);
     78 
     79 // Note: unlike the non-pinning JS_Atomize* functions, this can be called
     80 // without entering a realm/zone.
     81 extern JS_PUBLIC_API JSString* JS_AtomizeAndPinStringN(JSContext* cx,
     82                                                       const char* s,
     83                                                       size_t length);
     84 
     85 // Note: unlike the non-pinning JS_Atomize* functions, this can be called
     86 // without entering a realm/zone.
     87 extern JS_PUBLIC_API JSString* JS_AtomizeAndPinString(JSContext* cx,
     88                                                      const char* s);
     89 
     90 extern JS_PUBLIC_API JSString* JS_NewLatin1String(
     91    JSContext* cx, js::UniquePtr<JS::Latin1Char[], JS::FreePolicy> chars,
     92    size_t length);
     93 
     94 extern JS_PUBLIC_API JSString* JS_NewUCString(JSContext* cx,
     95                                              JS::UniqueTwoByteChars chars,
     96                                              size_t length);
     97 
     98 extern JS_PUBLIC_API JSString* JS_NewUCStringDontDeflate(
     99    JSContext* cx, JS::UniqueTwoByteChars chars, size_t length);
    100 
    101 extern JS_PUBLIC_API JSString* JS_NewUCStringCopyN(JSContext* cx,
    102                                                   const char16_t* s, size_t n);
    103 
    104 extern JS_PUBLIC_API JSString* JS_NewUCStringCopyZ(JSContext* cx,
    105                                                   const char16_t* s);
    106 
    107 namespace JS {
    108 
    109 /**
    110 * Create a new JSString possibly backed by |buffer|. The contents of |buffer|
    111 * will be interpreted as an array of Latin1 characters.
    112 *
    113 * Note that the returned string is not guaranteed to use |buffer|: as an
    114 * optimization, this API can return an inline string or a previously allocated
    115 * string.
    116 *
    117 * Increments the buffer's refcount iff the JS string holds a reference to it.
    118 */
    119 extern JS_PUBLIC_API JSString* NewStringFromLatin1Buffer(
    120    JSContext* cx, RefPtr<mozilla::StringBuffer> buffer, size_t length);
    121 
    122 /**
    123 * Like NewStringFromLatin1Buffer, but can be used to avoid refcounting overhead
    124 * in cases where the returned string doesn't use the buffer. The caller must
    125 * ensure the buffer outlives this call.
    126 */
    127 extern JS_PUBLIC_API JSString* NewStringFromKnownLiveLatin1Buffer(
    128    JSContext* cx, mozilla::StringBuffer* buffer, size_t length);
    129 
    130 /**
    131 * Similar to NewStringFromLatin1Buffer but for char16_t buffers.
    132 */
    133 extern JS_PUBLIC_API JSString* NewStringFromTwoByteBuffer(
    134    JSContext* cx, RefPtr<mozilla::StringBuffer> buffer, size_t length);
    135 
    136 /**
    137 * Similar to NewStringFromKnownLiveLatin1Buffer but for char16_t buffers.
    138 */
    139 extern JS_PUBLIC_API JSString* NewStringFromKnownLiveTwoByteBuffer(
    140    JSContext* cx, mozilla::StringBuffer* buffer, size_t length);
    141 
    142 /**
    143 * Similar to NewStringFromLatin1Buffer but for UTF8 buffers.
    144 *
    145 * This can create a Latin1 string backed by |buffer| iff the utf8 buffer
    146 * contains only ASCII chars. If there are non-ASCII chars, |buffer| can't be
    147 * used so this API will copy and inflate the characters for the new JS string.
    148 *
    149 * Note that |length| must be the (byte) length of the UTF8 buffer.
    150 */
    151 extern JS_PUBLIC_API JSString* NewStringFromUTF8Buffer(
    152    JSContext* cx, RefPtr<mozilla::StringBuffer> buffer, size_t length);
    153 
    154 /**
    155 * Like NewStringFromUTF8Buffer, but can be used to avoid refcounting overhead
    156 * in cases where the returned string doesn't use the buffer. The caller must
    157 * ensure the buffer outlives this call.
    158 */
    159 extern JS_PUBLIC_API JSString* NewStringFromKnownLiveUTF8Buffer(
    160    JSContext* cx, mozilla::StringBuffer* buffer, size_t length);
    161 
    162 }  // namespace JS
    163 
    164 extern JS_PUBLIC_API JSString* JS_AtomizeUCStringN(JSContext* cx,
    165                                                   const char16_t* s,
    166                                                   size_t length);
    167 
    168 extern JS_PUBLIC_API JSString* JS_AtomizeUCString(JSContext* cx,
    169                                                  const char16_t* s);
    170 
    171 extern JS_PUBLIC_API bool JS_CompareStrings(JSContext* cx, JSString* str1,
    172                                            JSString* str2, int32_t* result);
    173 
    174 [[nodiscard]] extern JS_PUBLIC_API bool JS_StringEqualsAscii(
    175    JSContext* cx, JSString* str, const char* asciiBytes, bool* match);
    176 
    177 // Same as above, but when the length of asciiBytes (excluding the
    178 // trailing null, if any) is known.
    179 [[nodiscard]] extern JS_PUBLIC_API bool JS_StringEqualsAscii(
    180    JSContext* cx, JSString* str, const char* asciiBytes, size_t length,
    181    bool* match);
    182 
    183 template <size_t N>
    184 [[nodiscard]] bool JS_StringEqualsLiteral(JSContext* cx, JSString* str,
    185                                          const char (&asciiBytes)[N],
    186                                          bool* match) {
    187  MOZ_ASSERT(asciiBytes[N - 1] == '\0');
    188  return JS_StringEqualsAscii(cx, str, asciiBytes, N - 1, match);
    189 }
    190 
    191 extern JS_PUBLIC_API size_t JS_PutEscapedString(JSContext* cx, char* buffer,
    192                                                size_t size, JSString* str,
    193                                                char quote);
    194 
    195 /*
    196 * Extracting string characters and length.
    197 *
    198 * While getting the length of a string is infallible, getting the chars can
    199 * fail. As indicated by the lack of a JSContext parameter, there are two
    200 * special cases where getting the chars is infallible:
    201 *
    202 * The first case is for strings that have been atomized, e.g. directly by
    203 * JS_AtomizeAndPinString or implicitly because it is stored in a jsid.
    204 *
    205 * The second case is "linear" strings that have been explicitly prepared in a
    206 * fallible context by JS_EnsureLinearString. To catch errors, a separate opaque
    207 * JSLinearString type is returned by JS_EnsureLinearString and expected by
    208 * JS_Get{Latin1,TwoByte}StringCharsAndLength. Note, though, that this is purely
    209 * a syntactic distinction: the input and output of JS_EnsureLinearString are
    210 * the same actual GC-thing. If a JSString is known to be linear,
    211 * JS_ASSERT_STRING_IS_LINEAR can be used to make a debug-checked cast. Example:
    212 *
    213 *   // In a fallible context.
    214 *   JSLinearString* lstr = JS_EnsureLinearString(cx, str);
    215 *   if (!lstr) {
    216 *     return false;
    217 *   }
    218 *   MOZ_ASSERT(lstr == JS_ASSERT_STRING_IS_LINEAR(str));
    219 *
    220 *   // In an infallible context, for the same 'str'.
    221 *   AutoCheckCannotGC nogc;
    222 *   const char16_t* chars = JS::GetTwoByteLinearStringChars(nogc, lstr)
    223 *   MOZ_ASSERT(chars);
    224 *
    225 * Note: JS strings (including linear strings and atoms) are not
    226 * null-terminated!
    227 *
    228 * Additionally, string characters are stored as either Latin1Char (8-bit)
    229 * or char16_t (16-bit). Clients can use JS::StringHasLatin1Chars and can then
    230 * call either the Latin1* or TwoByte* functions. Some functions like
    231 * JS_CopyStringChars and JS_GetStringCharAt accept both Latin1 and TwoByte
    232 * strings.
    233 */
    234 
    235 extern JS_PUBLIC_API size_t JS_GetStringLength(JSString* str);
    236 
    237 extern JS_PUBLIC_API bool JS_StringIsLinear(JSString* str);
    238 
    239 extern JS_PUBLIC_API const JS::Latin1Char* JS_GetLatin1StringCharsAndLength(
    240    JSContext* cx, const JS::AutoRequireNoGC& nogc, JSString* str,
    241    size_t* length);
    242 
    243 extern JS_PUBLIC_API const char16_t* JS_GetTwoByteStringCharsAndLength(
    244    JSContext* cx, const JS::AutoRequireNoGC& nogc, JSString* str,
    245    size_t* length);
    246 
    247 extern JS_PUBLIC_API bool JS_GetStringCharAt(JSContext* cx, JSString* str,
    248                                             size_t index, char16_t* res);
    249 
    250 extern JS_PUBLIC_API const char16_t* JS_GetTwoByteExternalStringChars(
    251    JSString* str);
    252 
    253 extern JS_PUBLIC_API bool JS_CopyStringChars(
    254    JSContext* cx, const mozilla::Range<char16_t>& dest, JSString* str);
    255 
    256 /**
    257 * Copies the string's characters to a null-terminated char16_t buffer.
    258 *
    259 * Returns nullptr on OOM.
    260 */
    261 extern JS_PUBLIC_API JS::UniqueTwoByteChars JS_CopyStringCharsZ(JSContext* cx,
    262                                                                JSString* str);
    263 
    264 extern JS_PUBLIC_API JSLinearString* JS_EnsureLinearString(JSContext* cx,
    265                                                           JSString* str);
    266 
    267 static MOZ_ALWAYS_INLINE JSLinearString* JS_ASSERT_STRING_IS_LINEAR(
    268    JSString* str) {
    269  MOZ_ASSERT(JS_StringIsLinear(str));
    270  return reinterpret_cast<JSLinearString*>(str);
    271 }
    272 
    273 static MOZ_ALWAYS_INLINE JSString* JS_FORGET_STRING_LINEARNESS(
    274    JSLinearString* str) {
    275  return reinterpret_cast<JSString*>(str);
    276 }
    277 
    278 /*
    279 * Additional APIs that avoid fallibility when given a linear string.
    280 */
    281 
    282 extern JS_PUBLIC_API bool JS_LinearStringEqualsAscii(JSLinearString* str,
    283                                                     const char* asciiBytes);
    284 extern JS_PUBLIC_API bool JS_LinearStringEqualsAscii(JSLinearString* str,
    285                                                     const char* asciiBytes,
    286                                                     size_t length);
    287 
    288 template <size_t N>
    289 bool JS_LinearStringEqualsLiteral(JSLinearString* str,
    290                                  const char (&asciiBytes)[N]) {
    291  MOZ_ASSERT(asciiBytes[N - 1] == '\0');
    292  return JS_LinearStringEqualsAscii(str, asciiBytes, N - 1);
    293 }
    294 
    295 extern JS_PUBLIC_API size_t JS_PutEscapedLinearString(char* buffer, size_t size,
    296                                                      JSLinearString* str,
    297                                                      char quote);
    298 
    299 /**
    300 * Create a dependent string, i.e., a string that owns no character storage,
    301 * but that refers to a slice of another string's chars.  Dependent strings
    302 * are mutable by definition, so the thread safety comments above apply.
    303 */
    304 extern JS_PUBLIC_API JSString* JS_NewDependentString(JSContext* cx,
    305                                                     JS::Handle<JSString*> str,
    306                                                     size_t start,
    307                                                     size_t length);
    308 
    309 /**
    310 * Concatenate two strings, possibly resulting in a rope.
    311 * See above for thread safety comments.
    312 */
    313 extern JS_PUBLIC_API JSString* JS_ConcatStrings(JSContext* cx,
    314                                                JS::Handle<JSString*> left,
    315                                                JS::Handle<JSString*> right);
    316 
    317 /**
    318 * For JS_DecodeBytes, set *dstlenp to the size of the destination buffer before
    319 * the call; on return, *dstlenp contains the number of characters actually
    320 * stored. To determine the necessary destination buffer size, make a sizing
    321 * call that passes nullptr for dst.
    322 *
    323 * On errors, the functions report the error. In that case, *dstlenp contains
    324 * the number of characters or bytes transferred so far.  If cx is nullptr, no
    325 * error is reported on failure, and the functions simply return false.
    326 *
    327 * NB: This function does not store an additional zero byte or char16_t after
    328 * the transcoded string.
    329 */
    330 JS_PUBLIC_API bool JS_DecodeBytes(JSContext* cx, const char* src, size_t srclen,
    331                                  char16_t* dst, size_t* dstlenp);
    332 
    333 /**
    334 * Get number of bytes in the string encoding (without accounting for a
    335 * terminating zero bytes. The function returns (size_t) -1 if the string
    336 * can not be encoded into bytes and reports an error using cx accordingly.
    337 */
    338 JS_PUBLIC_API size_t JS_GetStringEncodingLength(JSContext* cx, JSString* str);
    339 
    340 /**
    341 * Encode string into a buffer. The function does not stores an additional
    342 * zero byte. The function returns (size_t) -1 if the string can not be
    343 * encoded into bytes with no error reported. Otherwise it returns the number
    344 * of bytes that are necessary to encode the string. If that exceeds the
    345 * length parameter, the string will be cut and only length bytes will be
    346 * written into the buffer.
    347 */
    348 [[nodiscard]] JS_PUBLIC_API bool JS_EncodeStringToBuffer(JSContext* cx,
    349                                                         JSString* str,
    350                                                         char* buffer,
    351                                                         size_t length);
    352 
    353 /**
    354 * Encode as many scalar values of the string as UTF-8 as can fit
    355 * into the caller-provided buffer replacing unpaired surrogates
    356 * with the REPLACEMENT CHARACTER.
    357 *
    358 * If JS::StringHasLatin1Chars(str) returns true, the function
    359 * is guaranteed to convert the entire string if
    360 * buffer.Length() >= 2 * JS_GetStringLength(str). Otherwise,
    361 * the function is guaranteed to convert the entire string if
    362 * buffer.Length() >= 3 * JS_GetStringLength(str).
    363 *
    364 * This function does not alter the representation of |str| or
    365 * any |JSString*| substring that is a constituent part of it.
    366 * Returns mozilla::Nothing() on OOM, without reporting an error;
    367 * some data may have been written to |buffer| when this happens.
    368 *
    369 * If there's no OOM, returns the number of code units read and
    370 * the number of code units written.
    371 *
    372 * The semantics of this method match the semantics of
    373 * TextEncoder.encodeInto().
    374 *
    375 * The function does not store an additional zero byte.
    376 */
    377 JS_PUBLIC_API mozilla::Maybe<std::tuple<size_t, size_t>>
    378 JS_EncodeStringToUTF8BufferPartial(JSContext* cx, JSString* str,
    379                                   mozilla::Span<char> buffer);
    380 
    381 namespace JS {
    382 
    383 /**
    384 * Maximum length of a JS string. This is chosen so that the number of bytes
    385 * allocated for a null-terminated TwoByte string still fits in int32_t.
    386 */
    387 static constexpr uint32_t MaxStringLength = (1 << 30) - 2;
    388 
    389 static_assert((uint64_t(MaxStringLength) + 1) * sizeof(char16_t) <= INT32_MAX,
    390              "size of null-terminated JSString char buffer must fit in "
    391              "INT32_MAX");
    392 
    393 /** Compute the length of a string. */
    394 MOZ_ALWAYS_INLINE size_t GetStringLength(JSString* s) {
    395  return shadow::AsShadowString(s)->length();
    396 }
    397 
    398 /** Compute the length of a linear string. */
    399 MOZ_ALWAYS_INLINE size_t GetLinearStringLength(JSLinearString* s) {
    400  return shadow::AsShadowString(s)->length();
    401 }
    402 
    403 /** Return true iff the given linear string uses Latin-1 storage. */
    404 MOZ_ALWAYS_INLINE bool LinearStringHasLatin1Chars(JSLinearString* s) {
    405  return shadow::AsShadowString(s)->hasLatin1Chars();
    406 }
    407 
    408 /** Return true iff the given string uses Latin-1 storage. */
    409 MOZ_ALWAYS_INLINE bool StringHasLatin1Chars(JSString* s) {
    410  return shadow::AsShadowString(s)->hasLatin1Chars();
    411 }
    412 
    413 /**
    414 * Given a linear string known to use Latin-1 storage, return a pointer to that
    415 * storage.  This pointer remains valid only as long as no GC occurs.
    416 */
    417 MOZ_ALWAYS_INLINE const Latin1Char* GetLatin1LinearStringChars(
    418    const AutoRequireNoGC& nogc, JSLinearString* linear) {
    419  return shadow::AsShadowString(linear)->latin1LinearChars();
    420 }
    421 
    422 /**
    423 * Given a linear string known to use two-byte storage, return a pointer to that
    424 * storage.  This pointer remains valid only as long as no GC occurs.
    425 */
    426 MOZ_ALWAYS_INLINE const char16_t* GetTwoByteLinearStringChars(
    427    const AutoRequireNoGC& nogc, JSLinearString* linear) {
    428  return shadow::AsShadowString(linear)->twoByteLinearChars();
    429 }
    430 
    431 /**
    432 * Given an in-range index into the provided string, return the character at
    433 * that index.
    434 */
    435 MOZ_ALWAYS_INLINE char16_t GetLinearStringCharAt(JSLinearString* linear,
    436                                                 size_t index) {
    437  shadow::String* s = shadow::AsShadowString(linear);
    438  MOZ_ASSERT(index < s->length());
    439 
    440  return s->hasLatin1Chars() ? s->latin1LinearChars()[index]
    441                             : s->twoByteLinearChars()[index];
    442 }
    443 
    444 /**
    445 * Convert an atom to a linear string.  All atoms are linear, so this
    446 * operation is infallible.
    447 */
    448 MOZ_ALWAYS_INLINE JSLinearString* AtomToLinearString(JSAtom* atom) {
    449  return reinterpret_cast<JSLinearString*>(atom);
    450 }
    451 
    452 /**
    453 * If the provided string uses externally-managed latin-1 storage, return true
    454 * and set |*callbacks| to the external-string callbacks used to create it and
    455 * |*chars| to a pointer to its latin1 storage.  (These pointers remain valid
    456 * as long as the provided string is kept alive.)
    457 */
    458 MOZ_ALWAYS_INLINE bool IsExternalStringLatin1(
    459    JSString* str, const JSExternalStringCallbacks** callbacks,
    460    const JS::Latin1Char** chars) {
    461  shadow::String* s = shadow::AsShadowString(str);
    462 
    463  if (!s->isExternal() || !s->hasLatin1Chars()) {
    464    return false;
    465  }
    466 
    467  *callbacks = s->externalCallbacks;
    468  *chars = s->nonInlineCharsLatin1;
    469  return true;
    470 }
    471 
    472 /**
    473 * If the provided string uses externally-managed two-byte storage, return true
    474 * and set |*callbacks| to the external-string callbacks used to create it and
    475 * |*chars| to a pointer to its two-byte storage.  (These pointers remain valid
    476 * as long as the provided string is kept alive.)
    477 */
    478 MOZ_ALWAYS_INLINE bool IsExternalUCString(
    479    JSString* str, const JSExternalStringCallbacks** callbacks,
    480    const char16_t** chars) {
    481  shadow::String* s = shadow::AsShadowString(str);
    482 
    483  if (!s->isExternal() || s->hasLatin1Chars()) {
    484    return false;
    485  }
    486 
    487  *callbacks = s->externalCallbacks;
    488  *chars = s->nonInlineCharsTwoByte;
    489  return true;
    490 }
    491 
    492 /**
    493 * If the provided string is backed by a StringBuffer for latin-1 storage,
    494 * return true and set |*buffer| to the string buffer.
    495 *
    496 * Note: this function doesn't increment the buffer's refcount. The buffer
    497 * remains valid as long as the provided string is kept alive.
    498 */
    499 MOZ_ALWAYS_INLINE bool IsLatin1StringWithStringBuffer(
    500    JSString* str, mozilla::StringBuffer** buffer) {
    501  shadow::String* s = shadow::AsShadowString(str);
    502 
    503  if (!s->hasStringBuffer() || !s->hasLatin1Chars()) {
    504    return false;
    505  }
    506 
    507  void* data = const_cast<JS::Latin1Char*>(s->nonInlineCharsLatin1);
    508  *buffer = mozilla::StringBuffer::FromData(data);
    509  return true;
    510 }
    511 
    512 /**
    513 * If the provided string is backed by a StringBuffer for char16_t storage,
    514 * return true and set |*buffer| to the string buffer.
    515 *
    516 * Note: this function doesn't increment the buffer's refcount. The buffer
    517 * remains valid as long as the provided string is kept alive.
    518 */
    519 MOZ_ALWAYS_INLINE bool IsTwoByteStringWithStringBuffer(
    520    JSString* str, mozilla::StringBuffer** buffer) {
    521  shadow::String* s = shadow::AsShadowString(str);
    522 
    523  if (!s->hasStringBuffer() || s->hasLatin1Chars()) {
    524    return false;
    525  }
    526 
    527  void* data = const_cast<char16_t*>(s->nonInlineCharsTwoByte);
    528  *buffer = mozilla::StringBuffer::FromData(data);
    529  return true;
    530 }
    531 
    532 namespace detail {
    533 
    534 extern JS_PUBLIC_API JSLinearString* StringToLinearStringSlow(JSContext* cx,
    535                                                              JSString* str);
    536 
    537 }  // namespace detail
    538 
    539 /** Convert a string to a linear string. */
    540 MOZ_ALWAYS_INLINE JSLinearString* StringToLinearString(JSContext* cx,
    541                                                       JSString* str) {
    542  if (MOZ_LIKELY(shadow::AsShadowString(str)->isLinear())) {
    543    return reinterpret_cast<JSLinearString*>(str);
    544  }
    545 
    546  return detail::StringToLinearStringSlow(cx, str);
    547 }
    548 
    549 /** Copy characters in |s[start..start + len]| to |dest[0..len]|. */
    550 MOZ_ALWAYS_INLINE void CopyLinearStringChars(char16_t* dest, JSLinearString* s,
    551                                             size_t len, size_t start = 0) {
    552 #ifdef DEBUG
    553  size_t stringLen = GetLinearStringLength(s);
    554  MOZ_ASSERT(start <= stringLen);
    555  MOZ_ASSERT(len <= stringLen - start);
    556 #endif
    557 
    558  shadow::String* str = shadow::AsShadowString(s);
    559 
    560  if (str->hasLatin1Chars()) {
    561    const Latin1Char* src = str->latin1LinearChars();
    562    for (size_t i = 0; i < len; i++) {
    563      dest[i] = src[start + i];
    564    }
    565  } else {
    566    const char16_t* src = str->twoByteLinearChars();
    567    std::copy_n(src + start, len, dest);
    568  }
    569 }
    570 
    571 /**
    572 * Copy characters in |s[start..start + len]| to |dest[0..len]|, lossily
    573 * truncating 16-bit values to |char| if necessary.
    574 */
    575 MOZ_ALWAYS_INLINE void LossyCopyLinearStringChars(char* dest, JSLinearString* s,
    576                                                  size_t len,
    577                                                  size_t start = 0) {
    578 #ifdef DEBUG
    579  size_t stringLen = GetLinearStringLength(s);
    580  MOZ_ASSERT(start <= stringLen);
    581  MOZ_ASSERT(len <= stringLen - start);
    582 #endif
    583 
    584  shadow::String* str = shadow::AsShadowString(s);
    585 
    586  if (LinearStringHasLatin1Chars(s)) {
    587    const Latin1Char* src = str->latin1LinearChars();
    588    for (size_t i = 0; i < len; i++) {
    589      dest[i] = char(src[start + i]);
    590    }
    591  } else {
    592    const char16_t* src = str->twoByteLinearChars();
    593    for (size_t i = 0; i < len; i++) {
    594      dest[i] = char(src[start + i]);
    595    }
    596  }
    597 }
    598 
    599 /**
    600 * Copy characters in |s[start..start + len]| to |dest[0..len]|.
    601 *
    602 * This function is fallible.  If you already have a linear string, use the
    603 * infallible |JS::CopyLinearStringChars| above instead.
    604 */
    605 [[nodiscard]] inline bool CopyStringChars(JSContext* cx, char16_t* dest,
    606                                          JSString* s, size_t len,
    607                                          size_t start = 0) {
    608  JSLinearString* linear = StringToLinearString(cx, s);
    609  if (!linear) {
    610    return false;
    611  }
    612 
    613  CopyLinearStringChars(dest, linear, len, start);
    614  return true;
    615 }
    616 
    617 /**
    618 * Copy characters in |s[start..start + len]| to |dest[0..len]|, lossily
    619 * truncating 16-bit values to |char| if necessary.
    620 *
    621 * This function is fallible.  If you already have a linear string, use the
    622 * infallible |JS::LossyCopyLinearStringChars| above instead.
    623 */
    624 [[nodiscard]] inline bool LossyCopyStringChars(JSContext* cx, char* dest,
    625                                               JSString* s, size_t len,
    626                                               size_t start = 0) {
    627  JSLinearString* linear = StringToLinearString(cx, s);
    628  if (!linear) {
    629    return false;
    630  }
    631 
    632  LossyCopyLinearStringChars(dest, linear, len, start);
    633  return true;
    634 }
    635 
    636 }  // namespace JS
    637 
    638 /** DO NOT USE, only present for Rust bindings as a temporary hack */
    639 [[deprecated]] extern JS_PUBLIC_API bool JS_DeprecatedStringHasLatin1Chars(
    640    JSString* str);
    641 
    642 // JSString* is an aligned pointer, but this information isn't available in the
    643 // public header. We specialize HasFreeLSB here so that JS::Result<JSString*>
    644 // compiles.
    645 
    646 namespace mozilla {
    647 namespace detail {
    648 template <>
    649 struct HasFreeLSB<JSString*> {
    650  static constexpr bool value = true;
    651 };
    652 }  // namespace detail
    653 }  // namespace mozilla
    654 
    655 #endif  // js_String_h