cesium
Version:
CesiumJS is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin.
167 lines (144 loc) • 4.87 kB
JavaScript
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;