| /** |
| * @license |
| * Copyright 2020 The Emscripten Authors |
| * SPDX-License-Identifier: MIT |
| */ |
| |
| #include "arrayUtils.js" |
| |
| mergeInto(LibraryManager.library, { |
| $intArrayFromString__docs: '/** @type {function(string, boolean=, number=)} */', |
| $intArrayFromString: intArrayFromString, |
| $intArrayToString: intArrayToString, |
| |
| // Given a pointer 'ptr' to a null-terminated ASCII-encoded string in the |
| // emscripten HEAP, returns a copy of that string as a Javascript String |
| // object. |
| $AsciiToString: function(ptr) { |
| #if CAN_ADDRESS_2GB |
| ptr >>>= 0; |
| #endif |
| var str = ''; |
| while (1) { |
| var ch = {{{ makeGetValue('ptr++', 0, 'u8') }}}; |
| if (!ch) return str; |
| str += String.fromCharCode(ch); |
| } |
| }, |
| |
| // Copies the given Javascript String object 'str' to the emscripten HEAP at |
| // address 'outPtr', null-terminated and encoded in ASCII form. The copy will |
| // require at most str.length+1 bytes of space in the HEAP. |
| $stringToAscii__deps: ['$writeAsciiToMemory'], |
| $stringToAscii: function(str, outPtr) { |
| return writeAsciiToMemory(str, outPtr, false); |
| }, |
| |
| #if TEXTDECODER == 2 |
| $UTF16Decoder: "new TextDecoder('utf-16le');", |
| #elif TEXTDECODER == 1 |
| $UTF16Decoder: "typeof TextDecoder != 'undefined' ? new TextDecoder('utf-16le') : undefined;", |
| #endif |
| |
| // Given a pointer 'ptr' to a null-terminated UTF16LE-encoded string in the |
| // emscripten HEAP, returns a copy of that string as a Javascript String |
| // object. |
| #if TEXTDECODER |
| $UTF16ToString__deps: ['$UTF16Decoder'], |
| #endif |
| $UTF16ToString: function(ptr, maxBytesToRead) { |
| #if ASSERTIONS |
| assert(ptr % 2 == 0, 'Pointer passed to UTF16ToString must be aligned to two bytes!'); |
| #endif |
| #if TEXTDECODER |
| var endPtr = ptr; |
| // TextDecoder needs to know the byte length in advance, it doesn't stop on |
| // null terminator by itself. |
| // Also, use the length info to avoid running tiny strings through |
| // TextDecoder, since .subarray() allocates garbage. |
| var idx = endPtr >> 1; |
| var maxIdx = idx + maxBytesToRead / 2; |
| // If maxBytesToRead is not passed explicitly, it will be undefined, and this |
| // will always evaluate to true. This saves on code size. |
| while (!(idx >= maxIdx) && HEAPU16[idx]) ++idx; |
| endPtr = idx << 1; |
| |
| #if TEXTDECODER != 2 |
| if (endPtr - ptr > 32 && UTF16Decoder) |
| #endif // TEXTDECODER != 2 |
| return UTF16Decoder.decode({{{ getUnsharedTextDecoderView('HEAPU8', 'ptr', 'endPtr') }}}); |
| #endif // TEXTDECODER |
| |
| #if TEXTDECODER != 2 |
| // Fallback: decode without UTF16Decoder |
| var str = ''; |
| |
| // If maxBytesToRead is not passed explicitly, it will be undefined, and the |
| // for-loop's condition will always evaluate to true. The loop is then |
| // terminated on the first null char. |
| for (var i = 0; !(i >= maxBytesToRead / 2); ++i) { |
| var codeUnit = {{{ makeGetValue('ptr', 'i*2', 'i16') }}}; |
| if (codeUnit == 0) break; |
| // fromCharCode constructs a character from a UTF-16 code unit, so we can |
| // pass the UTF16 string right through. |
| str += String.fromCharCode(codeUnit); |
| } |
| |
| return str; |
| #endif // TEXTDECODER != 2 |
| }, |
| |
| // Copies the given Javascript String object 'str' to the emscripten HEAP at |
| // address 'outPtr', null-terminated and encoded in UTF16 form. The copy will |
| // require at most str.length*4+2 bytes of space in the HEAP. Use the |
| // function lengthBytesUTF16() to compute the exact number of bytes (excluding |
| // null terminator) that this function will write. |
| // Parameters: |
| // str: the Javascript string to copy. |
| // outPtr: Byte address in Emscripten HEAP where to write the string to. |
| // maxBytesToWrite: The maximum number of bytes this function can write to |
| // the array. This count should include the null |
| // terminator, i.e. if maxBytesToWrite=2, only the null |
| // terminator will be written and nothing else. |
| // maxBytesToWrite<2 does not write any bytes to the |
| // output, not even the null terminator. |
| // Returns the number of bytes written, EXCLUDING the null terminator. |
| $stringToUTF16: function(str, outPtr, maxBytesToWrite) { |
| #if ASSERTIONS |
| assert(outPtr % 2 == 0, 'Pointer passed to stringToUTF16 must be aligned to two bytes!'); |
| #endif |
| #if ASSERTIONS |
| assert(typeof maxBytesToWrite == 'number', 'stringToUTF16(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!'); |
| #endif |
| // Backwards compatibility: if max bytes is not specified, assume unsafe unbounded write is allowed. |
| if (maxBytesToWrite === undefined) { |
| maxBytesToWrite = 0x7FFFFFFF; |
| } |
| if (maxBytesToWrite < 2) return 0; |
| maxBytesToWrite -= 2; // Null terminator. |
| var startPtr = outPtr; |
| var numCharsToWrite = (maxBytesToWrite < str.length*2) ? (maxBytesToWrite / 2) : str.length; |
| for (var i = 0; i < numCharsToWrite; ++i) { |
| // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP. |
| var codeUnit = str.charCodeAt(i); // possibly a lead surrogate |
| {{{ makeSetValue('outPtr', 0, 'codeUnit', 'i16') }}}; |
| outPtr += 2; |
| } |
| // Null-terminate the pointer to the HEAP. |
| {{{ makeSetValue('outPtr', 0, 0, 'i16') }}}; |
| return outPtr - startPtr; |
| }, |
| |
| // Returns the number of bytes the given Javascript string takes if encoded as |
| // a UTF16 byte array, EXCLUDING the null terminator byte. |
| $lengthBytesUTF16: function(str) { |
| return str.length*2; |
| }, |
| |
| $UTF32ToString: function(ptr, maxBytesToRead) { |
| #if ASSERTIONS |
| assert(ptr % 4 == 0, 'Pointer passed to UTF32ToString must be aligned to four bytes!'); |
| #endif |
| var i = 0; |
| |
| var str = ''; |
| // If maxBytesToRead is not passed explicitly, it will be undefined, and this |
| // will always evaluate to true. This saves on code size. |
| while (!(i >= maxBytesToRead / 4)) { |
| var utf32 = {{{ makeGetValue('ptr', 'i*4', 'i32') }}}; |
| if (utf32 == 0) break; |
| ++i; |
| // Gotcha: fromCharCode constructs a character from a UTF-16 encoded code (pair), not from a Unicode code point! So encode the code point to UTF-16 for constructing. |
| // See http://unicode.org/faq/utf_bom.html#utf16-3 |
| if (utf32 >= 0x10000) { |
| var ch = utf32 - 0x10000; |
| str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF)); |
| } else { |
| str += String.fromCharCode(utf32); |
| } |
| } |
| return str; |
| }, |
| |
| // Copies the given Javascript String object 'str' to the emscripten HEAP at |
| // address 'outPtr', null-terminated and encoded in UTF32 form. The copy will |
| // require at most str.length*4+4 bytes of space in the HEAP. |
| // Use the function lengthBytesUTF32() to compute the exact number of bytes |
| // (excluding null terminator) that this function will write. |
| // Parameters: |
| // str: the Javascript string to copy. |
| // outPtr: Byte address in Emscripten HEAP where to write the string to. |
| // maxBytesToWrite: The maximum number of bytes this function can write to |
| // the array. This count should include the null |
| // terminator, i.e. if maxBytesToWrite=4, only the null |
| // terminator will be written and nothing else. |
| // maxBytesToWrite<4 does not write any bytes to the |
| // output, not even the null terminator. |
| // Returns the number of bytes written, EXCLUDING the null terminator. |
| $stringToUTF32: function(str, outPtr, maxBytesToWrite) { |
| #if CAN_ADDRESS_2GB |
| outPtr >>>= 0; |
| #endif |
| #if ASSERTIONS |
| assert(outPtr % 4 == 0, 'Pointer passed to stringToUTF32 must be aligned to four bytes!'); |
| #endif |
| #if ASSERTIONS |
| assert(typeof maxBytesToWrite == 'number', 'stringToUTF32(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!'); |
| #endif |
| // Backwards compatibility: if max bytes is not specified, assume unsafe unbounded write is allowed. |
| if (maxBytesToWrite === undefined) { |
| maxBytesToWrite = 0x7FFFFFFF; |
| } |
| if (maxBytesToWrite < 4) return 0; |
| var startPtr = outPtr; |
| var endPtr = startPtr + maxBytesToWrite - 4; |
| for (var i = 0; i < str.length; ++i) { |
| // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! We must decode the string to UTF-32 to the heap. |
| // See http://unicode.org/faq/utf_bom.html#utf16-3 |
| var codeUnit = str.charCodeAt(i); // possibly a lead surrogate |
| if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) { |
| var trailSurrogate = str.charCodeAt(++i); |
| codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF); |
| } |
| {{{ makeSetValue('outPtr', 0, 'codeUnit', 'i32') }}}; |
| outPtr += 4; |
| if (outPtr + 4 > endPtr) break; |
| } |
| // Null-terminate the pointer to the HEAP. |
| {{{ makeSetValue('outPtr', 0, 0, 'i32') }}}; |
| return outPtr - startPtr; |
| }, |
| |
| // Returns the number of bytes the given Javascript string takes if encoded as |
| // a UTF16 byte array, EXCLUDING the null terminator byte. |
| $lengthBytesUTF32: function(str) { |
| var len = 0; |
| for (var i = 0; i < str.length; ++i) { |
| // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! We must decode the string to UTF-32 to the heap. |
| // See http://unicode.org/faq/utf_bom.html#utf16-3 |
| var codeUnit = str.charCodeAt(i); |
| if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) ++i; // possibly a lead surrogate, so skip over the tail surrogate. |
| len += 4; |
| } |
| |
| return len; |
| }, |
| |
| // Allocate heap space for a JS string, and write it there. |
| // It is the responsibility of the caller to free() that memory. |
| $allocateUTF8: function(str) { |
| var size = lengthBytesUTF8(str) + 1; |
| var ret = {{{ makeMalloc('allocateUTF8', 'size') }}}; |
| if (ret) stringToUTF8Array(str, HEAP8, ret, size); |
| return ret; |
| }, |
| |
| // Allocate stack space for a JS string, and write it there. |
| $allocateUTF8OnStack: function(str) { |
| var size = lengthBytesUTF8(str) + 1; |
| var ret = stackAlloc(size); |
| stringToUTF8Array(str, HEAP8, ret, size); |
| return ret; |
| }, |
| |
| // Deprecated: This function should not be called because it is unsafe and |
| // does not provide a maximum length limit of how many bytes it is allowed to |
| // write. Prefer calling the function stringToUTF8Array() instead, which takes |
| // in a maximum length that can be used to be secure from out of bounds |
| // writes. |
| $writeStringToMemory__docs: '/** @deprecated @param {boolean=} dontAddNull */', |
| $writeStringToMemory: function(string, buffer, dontAddNull) { |
| warnOnce('writeStringToMemory is deprecated and should not be called! Use stringToUTF8() instead!'); |
| |
| var /** @type {number} */ lastChar, /** @type {number} */ end; |
| if (dontAddNull) { |
| // stringToUTF8Array always appends null. If we don't want to do that, remember the |
| // character that existed at the location where the null will be placed, and restore |
| // that after the write (below). |
| end = buffer + lengthBytesUTF8(string); |
| lastChar = HEAP8[end]; |
| } |
| stringToUTF8(string, buffer, Infinity); |
| if (dontAddNull) HEAP8[end] = lastChar; // Restore the value under the null character. |
| }, |
| |
| $writeArrayToMemory: function(array, buffer) { |
| #if ASSERTIONS |
| assert(array.length >= 0, 'writeArrayToMemory array must have a length (should be an array or typed array)') |
| #endif |
| HEAP8.set(array, buffer); |
| }, |
| |
| $writeAsciiToMemory__docs: '/** @param {boolean=} dontAddNull */', |
| $writeAsciiToMemory: function(str, buffer, dontAddNull) { |
| for (var i = 0; i < str.length; ++i) { |
| #if ASSERTIONS |
| assert(str.charCodeAt(i) === (str.charCodeAt(i) & 0xff)); |
| #endif |
| {{{ makeSetValue('buffer++', 0, 'str.charCodeAt(i)', 'i8') }}}; |
| } |
| // Null-terminate the pointer to the HEAP. |
| if (!dontAddNull) {{{ makeSetValue('buffer', 0, 0, 'i8') }}}; |
| }, |
| }); |