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