import defaultValue from './defaultValue.js';
|
import defined from './defined.js';
|
import DeveloperError from './DeveloperError.js';
|
import RuntimeError from './RuntimeError.js';
|
|
/**
|
* @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;
|