| |
| #if !MINIMAL_RUNTIME // TODO: Reintroduce these to MINIMAL_RUNTIME as library functions |
| |
| // 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. |
| |
| function AsciiToString(ptr) { |
| var str = ''; |
| while (1) { |
| var ch = {{{ makeGetValue('ptr++', 0, 'i8', null, true) }}}; |
| 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. |
| |
| function stringToAscii(str, outPtr) { |
| return writeAsciiToMemory(str, outPtr, false); |
| } |
| |
| #endif |
| |
| // Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the given array that contains uint8 values, returns |
| // a copy of that string as a Javascript String object. |
| |
| #if TEXTDECODER == 2 |
| var UTF8Decoder = new TextDecoder('utf8'); |
| #else // TEXTDECODER == 2 |
| #if TEXTDECODER |
| var UTF8Decoder = typeof TextDecoder !== 'undefined' ? new TextDecoder('utf8') : undefined; |
| #endif // TEXTDECODER |
| #endif // TEXTDECODER == 2 |
| |
| /** |
| * @param {number} idx |
| * @param {number=} maxBytesToRead |
| * @return {string} |
| */ |
| function UTF8ArrayToString(u8Array, idx, maxBytesToRead) { |
| var endIdx = idx + maxBytesToRead; |
| #if TEXTDECODER |
| var endPtr = idx; |
| // 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. |
| // (As a tiny code save trick, compare endPtr against endIdx using a negation, so that undefined means Infinity) |
| while (u8Array[endPtr] && !(endPtr >= endIdx)) ++endPtr; |
| #endif // TEXTDECODER |
| |
| #if TEXTDECODER == 2 |
| return UTF8Decoder.decode( |
| u8Array.subarray ? u8Array.subarray(idx, endPtr) : new Uint8Array(u8Array.slice(idx, endPtr)) |
| ); |
| #else // TEXTDECODER == 2 |
| #if TEXTDECODER |
| if (endPtr - idx > 16 && u8Array.subarray && UTF8Decoder) { |
| return UTF8Decoder.decode(u8Array.subarray(idx, endPtr)); |
| } else { |
| #endif // TEXTDECODER |
| var str = ''; |
| #if TEXTDECODER |
| // If building with TextDecoder, we have already computed the string length above, so test loop end condition against that |
| while (idx < endPtr) { |
| #else |
| while (!(idx >= endIdx)) { |
| #endif |
| // For UTF8 byte structure, see: |
| // http://en.wikipedia.org/wiki/UTF-8#Description |
| // https://www.ietf.org/rfc/rfc2279.txt |
| // https://tools.ietf.org/html/rfc3629 |
| var u0 = u8Array[idx++]; |
| #if !TEXTDECODER |
| // If not building with TextDecoder enabled, we don't know the string length, so scan for \0 byte. |
| // If building with TextDecoder, we know exactly at what byte index the string ends, so checking for nulls here would be redundant. |
| if (!u0) return str; |
| #endif |
| if (!(u0 & 0x80)) { str += String.fromCharCode(u0); continue; } |
| var u1 = u8Array[idx++] & 63; |
| if ((u0 & 0xE0) == 0xC0) { str += String.fromCharCode(((u0 & 31) << 6) | u1); continue; } |
| var u2 = u8Array[idx++] & 63; |
| if ((u0 & 0xF0) == 0xE0) { |
| u0 = ((u0 & 15) << 12) | (u1 << 6) | u2; |
| } else { |
| #if ASSERTIONS |
| if ((u0 & 0xF8) != 0xF0) warnOnce('Invalid UTF-8 leading byte 0x' + u0.toString(16) + ' encountered when deserializing a UTF-8 string on the asm.js/wasm heap to a JS string!'); |
| #endif |
| u0 = ((u0 & 7) << 18) | (u1 << 12) | (u2 << 6) | (u8Array[idx++] & 63); |
| } |
| |
| if (u0 < 0x10000) { |
| str += String.fromCharCode(u0); |
| } else { |
| var ch = u0 - 0x10000; |
| str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF)); |
| } |
| } |
| #if TEXTDECODER |
| } |
| #endif // TEXTDECODER |
| return str; |
| #endif // TEXTDECODER == 2 |
| } |
| |
| // Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the emscripten HEAP, returns a |
| // copy of that string as a Javascript String object. |
| // maxBytesToRead: an optional length that specifies the maximum number of bytes to read. You can omit |
| // this parameter to scan the string until the first \0 byte. If maxBytesToRead is |
| // passed, and the string at [ptr, ptr+maxBytesToReadr[ contains a null byte in the |
| // middle, then the string will cut short at that byte index (i.e. maxBytesToRead will |
| // not produce a string of exact length [ptr, ptr+maxBytesToRead[) |
| // N.B. mixing frequent uses of UTF8ToString() with and without maxBytesToRead may |
| // throw JS JIT optimizations off, so it is worth to consider consistently using one |
| // style or the other. |
| /** |
| * @param {number} ptr |
| * @param {number=} maxBytesToRead |
| * @return {string} |
| */ |
| function UTF8ToString(ptr, maxBytesToRead) { |
| #if TEXTDECODER == 2 |
| if (!ptr) return ''; |
| var maxPtr = ptr + maxBytesToRead; |
| for(var end = ptr; !(end >= maxPtr) && HEAPU8[end];) ++end; |
| return UTF8Decoder.decode(HEAPU8.subarray(ptr, end)); |
| #else |
| return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ''; |
| #endif |
| } |
| |
| // Copies the given Javascript String object 'str' to the given byte array at address 'outIdx', |
| // encoded in UTF8 form and null-terminated. The copy will require at most str.length*4+1 bytes of space in the HEAP. |
| // Use the function lengthBytesUTF8 to compute the exact number of bytes (excluding null terminator) that this function will write. |
| // Parameters: |
| // str: the Javascript string to copy. |
| // outU8Array: the array to copy to. Each index in this array is assumed to be one 8-byte element. |
| // outIdx: The starting offset in the array to begin the copying. |
| // maxBytesToWrite: The maximum number of bytes this function can write to the array. |
| // This count should include the null terminator, |
| // i.e. if maxBytesToWrite=1, only the null terminator will be written and nothing else. |
| // maxBytesToWrite=0 does not write any bytes to the output, not even the null terminator. |
| // Returns the number of bytes written, EXCLUDING the null terminator. |
| |
| function stringToUTF8Array(str, outU8Array, outIdx, maxBytesToWrite) { |
| if (!(maxBytesToWrite > 0)) // Parameter maxBytesToWrite is not optional. Negative values, 0, null, undefined and false each don't write out any bytes. |
| return 0; |
| |
| var startIdx = outIdx; |
| var endIdx = outIdx + maxBytesToWrite - 1; // -1 for string null terminator. |
| 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! So decode UTF16->UTF32->UTF8. |
| // See http://unicode.org/faq/utf_bom.html#utf16-3 |
| // For UTF8 byte structure, see http://en.wikipedia.org/wiki/UTF-8#Description and https://www.ietf.org/rfc/rfc2279.txt and https://tools.ietf.org/html/rfc3629 |
| var u = str.charCodeAt(i); // possibly a lead surrogate |
| if (u >= 0xD800 && u <= 0xDFFF) { |
| var u1 = str.charCodeAt(++i); |
| u = 0x10000 + ((u & 0x3FF) << 10) | (u1 & 0x3FF); |
| } |
| if (u <= 0x7F) { |
| if (outIdx >= endIdx) break; |
| outU8Array[outIdx++] = u; |
| } else if (u <= 0x7FF) { |
| if (outIdx + 1 >= endIdx) break; |
| outU8Array[outIdx++] = 0xC0 | (u >> 6); |
| outU8Array[outIdx++] = 0x80 | (u & 63); |
| } else if (u <= 0xFFFF) { |
| if (outIdx + 2 >= endIdx) break; |
| outU8Array[outIdx++] = 0xE0 | (u >> 12); |
| outU8Array[outIdx++] = 0x80 | ((u >> 6) & 63); |
| outU8Array[outIdx++] = 0x80 | (u & 63); |
| } else { |
| if (outIdx + 3 >= endIdx) break; |
| #if ASSERTIONS |
| if (u >= 0x200000) warnOnce('Invalid Unicode code point 0x' + u.toString(16) + ' encountered when serializing a JS string to an UTF-8 string on the asm.js/wasm heap! (Valid unicode code points should be in range 0-0x1FFFFF).'); |
| #endif |
| outU8Array[outIdx++] = 0xF0 | (u >> 18); |
| outU8Array[outIdx++] = 0x80 | ((u >> 12) & 63); |
| outU8Array[outIdx++] = 0x80 | ((u >> 6) & 63); |
| outU8Array[outIdx++] = 0x80 | (u & 63); |
| } |
| } |
| // Null-terminate the pointer to the buffer. |
| outU8Array[outIdx] = 0; |
| return outIdx - startIdx; |
| } |
| |
| // Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr', |
| // null-terminated and encoded in UTF8 form. The copy will require at most str.length*4+1 bytes of space in the HEAP. |
| // Use the function lengthBytesUTF8 to compute the exact number of bytes (excluding null terminator) that this function will write. |
| // Returns the number of bytes written, EXCLUDING the null terminator. |
| |
| function stringToUTF8(str, outPtr, maxBytesToWrite) { |
| #if ASSERTIONS |
| assert(typeof maxBytesToWrite == 'number', 'stringToUTF8(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!'); |
| #endif |
| return stringToUTF8Array(str, {{{ heapAndOffset('HEAPU8', 'outPtr') }}}, maxBytesToWrite); |
| } |
| |
| // Returns the number of bytes the given Javascript string takes if encoded as a UTF8 byte array, EXCLUDING the null terminator byte. |
| {{{ lengthBytesUTF8 }}} |
| |
| #if !MINIMAL_RUNTIME // TODO: Reintroduce these to MINIMAL_RUNTIME as library functions |
| |
| // 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 == 2 |
| var UTF16Decoder = new TextDecoder('utf-16le'); |
| #else // TEXTDECODER == 2 |
| #if TEXTDECODER |
| var UTF16Decoder = typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-16le') : undefined; |
| #endif // TEXTDECODER |
| #endif // TEXTDECODER == 2 |
| function UTF16ToString(ptr) { |
| #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; |
| while (HEAP16[idx]) ++idx; |
| endPtr = idx << 1; |
| |
| #if TEXTDECODER != 2 |
| if (endPtr - ptr > 32 && UTF16Decoder) { |
| #endif // TEXTDECODER != 2 |
| return UTF16Decoder.decode(HEAPU8.subarray(ptr, endPtr)); |
| #if TEXTDECODER != 2 |
| } else { |
| #endif // TEXTDECODER != 2 |
| #endif // TEXTDECODER |
| var i = 0; |
| |
| var str = ''; |
| while (1) { |
| var codeUnit = {{{ makeGetValue('ptr', 'i*2', 'i16') }}}; |
| if (codeUnit == 0) return str; |
| ++i; |
| // fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through. |
| str += String.fromCharCode(codeUnit); |
| } |
| #if TEXTDECODER && TEXTDECODER != 2 |
| } |
| #endif // TEXTDECODER |
| } |
| |
| // 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. |
| |
| function stringToUTF16(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. |
| |
| function lengthBytesUTF16(str) { |
| return str.length*2; |
| } |
| |
| function UTF32ToString(ptr) { |
| #if ASSERTIONS |
| assert(ptr % 4 == 0, 'Pointer passed to UTF32ToString must be aligned to four bytes!'); |
| #endif |
| var i = 0; |
| |
| var str = ''; |
| while (1) { |
| var utf32 = {{{ makeGetValue('ptr', 'i*4', 'i32') }}}; |
| if (utf32 == 0) |
| return str; |
| ++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); |
| } |
| } |
| } |
| |
| // 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. |
| |
| function stringToUTF32(str, outPtr, maxBytesToWrite) { |
| #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. |
| |
| function lengthBytesUTF32(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. |
| function allocateUTF8(str) { |
| var size = lengthBytesUTF8(str) + 1; |
| var ret = _malloc(size); |
| if (ret) stringToUTF8Array(str, HEAP8, ret, size); |
| return ret; |
| } |
| |
| // Allocate stack space for a JS string, and write it there. |
| function allocateUTF8OnStack(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. |
| /** @deprecated */ |
| function writeStringToMemory(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. |
| } |
| |
| function writeArrayToMemory(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); |
| } |
| |
| function writeAsciiToMemory(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') }}}; |
| } |
| |
| #endif |