import defaultValue from "./defaultValue.js";
|
import defined from "./defined.js";
|
import DeveloperError from "./DeveloperError.js";
|
import RuntimeError from "./RuntimeError.js";
|
|
/**
|
* Reads a string from a Uint8Array.
|
*
|
* @function
|
*
|
* @param {Uint8Array} uint8Array The Uint8Array to read from.
|
* @param {Number} [byteOffset=0] The byte offset to start reading from.
|
* @param {Number} [byteLength] The byte length to read. If byteLength is omitted the remainder of the buffer is read.
|
* @returns {String} The string.
|
*
|
* @private
|
*/
|
function getStringFromTypedArray(uint8Array, byteOffset, byteLength) {
|
//>>includeStart('debug', pragmas.debug);
|
if (!defined(uint8Array)) {
|
throw new DeveloperError("uint8Array is required.");
|
}
|
if (byteOffset < 0) {
|
throw new DeveloperError("byteOffset cannot be negative.");
|
}
|
if (byteLength < 0) {
|
throw new DeveloperError("byteLength cannot be negative.");
|
}
|
if (byteOffset + byteLength > uint8Array.byteLength) {
|
throw new DeveloperError("sub-region exceeds array bounds.");
|
}
|
//>>includeEnd('debug');
|
|
byteOffset = defaultValue(byteOffset, 0);
|
byteLength = defaultValue(byteLength, uint8Array.byteLength - byteOffset);
|
|
uint8Array = uint8Array.subarray(byteOffset, byteOffset + byteLength);
|
|
return getStringFromTypedArray.decode(uint8Array);
|
}
|
|
// Exposed functions for testing
|
getStringFromTypedArray.decodeWithTextDecoder = function (view) {
|
var decoder = new TextDecoder("utf-8");
|
return decoder.decode(view);
|
};
|
|
getStringFromTypedArray.decodeWithFromCharCode = function (view) {
|
var result = "";
|
var codePoints = utf8Handler(view);
|
var length = codePoints.length;
|
for (var i = 0; i < length; ++i) {
|
var cp = codePoints[i];
|
if (cp <= 0xffff) {
|
result += String.fromCharCode(cp);
|
} else {
|
cp -= 0x10000;
|
result += String.fromCharCode((cp >> 10) + 0xd800, (cp & 0x3ff) + 0xdc00);
|
}
|
}
|
return result;
|
};
|
|
function inRange(a, min, max) {
|
return min <= a && a <= max;
|
}
|
|
// This code is inspired by public domain code found here: https://github.com/inexorabletash/text-encoding
|
function utf8Handler(utfBytes) {
|
var codePoint = 0;
|
var bytesSeen = 0;
|
var bytesNeeded = 0;
|
var lowerBoundary = 0x80;
|
var upperBoundary = 0xbf;
|
|
var codePoints = [];
|
var length = utfBytes.length;
|
for (var i = 0; i < length; ++i) {
|
var currentByte = utfBytes[i];
|
|
// If bytesNeeded = 0, then we are starting a new character
|
if (bytesNeeded === 0) {
|
// 1 Byte Ascii character
|
if (inRange(currentByte, 0x00, 0x7f)) {
|
// Return a code point whose value is byte.
|
codePoints.push(currentByte);
|
continue;
|
}
|
|
// 2 Byte character
|
if (inRange(currentByte, 0xc2, 0xdf)) {
|
bytesNeeded = 1;
|
codePoint = currentByte & 0x1f;
|
continue;
|
}
|
|
// 3 Byte character
|
if (inRange(currentByte, 0xe0, 0xef)) {
|
// If byte is 0xE0, set utf-8 lower boundary to 0xA0.
|
if (currentByte === 0xe0) {
|
lowerBoundary = 0xa0;
|
}
|
// If byte is 0xED, set utf-8 upper boundary to 0x9F.
|
if (currentByte === 0xed) {
|
upperBoundary = 0x9f;
|
}
|
|
bytesNeeded = 2;
|
codePoint = currentByte & 0xf;
|
continue;
|
}
|
|
// 4 Byte character
|
if (inRange(currentByte, 0xf0, 0xf4)) {
|
// If byte is 0xF0, set utf-8 lower boundary to 0x90.
|
if (currentByte === 0xf0) {
|
lowerBoundary = 0x90;
|
}
|
// If byte is 0xF4, set utf-8 upper boundary to 0x8F.
|
if (currentByte === 0xf4) {
|
upperBoundary = 0x8f;
|
}
|
|
bytesNeeded = 3;
|
codePoint = currentByte & 0x7;
|
continue;
|
}
|
|
throw new RuntimeError("String decoding failed.");
|
}
|
|
// Out of range, so ignore the first part(s) of the character and continue with this byte on its own
|
if (!inRange(currentByte, lowerBoundary, upperBoundary)) {
|
codePoint = bytesNeeded = bytesSeen = 0;
|
lowerBoundary = 0x80;
|
upperBoundary = 0xbf;
|
--i;
|
continue;
|
}
|
|
// Set appropriate boundaries, since we've now checked byte 2 of a potential longer character
|
lowerBoundary = 0x80;
|
upperBoundary = 0xbf;
|
|
// Add byte to code point
|
codePoint = (codePoint << 6) | (currentByte & 0x3f);
|
|
// We have the correct number of bytes, so push and reset for next character
|
++bytesSeen;
|
if (bytesSeen === bytesNeeded) {
|
codePoints.push(codePoint);
|
codePoint = bytesNeeded = bytesSeen = 0;
|
}
|
}
|
|
return codePoints;
|
}
|
|
if (typeof TextDecoder !== "undefined") {
|
getStringFromTypedArray.decode =
|
getStringFromTypedArray.decodeWithTextDecoder;
|
} else {
|
getStringFromTypedArray.decode =
|
getStringFromTypedArray.decodeWithFromCharCode;
|
}
|
export default getStringFromTypedArray;
|