154 lines
5.6 KiB
JavaScript
154 lines
5.6 KiB
JavaScript
import { VectorType } from "../vector/vectorType";
|
|
import { decodeStreamMetadata } from "../metadata/tile/streamMetadataDecoder";
|
|
import { unpackNullableBoolean, unpackNullable } from "./unpackNullableUtils";
|
|
export function skipColumn(numStreams, tile, offset) {
|
|
//TODO: add size of column in Mlt for fast skipping
|
|
for (let i = 0; i < numStreams; i++) {
|
|
const streamMetadata = decodeStreamMetadata(tile, offset);
|
|
offset.add(streamMetadata.byteLength);
|
|
}
|
|
}
|
|
export function decodeBooleanRle(buffer, numBooleans, byteLength, pos, nullabilityBuffer) {
|
|
const numBytes = Math.ceil(numBooleans / 8.0);
|
|
const values = decodeByteRle(buffer, numBytes, byteLength, pos);
|
|
if (nullabilityBuffer) {
|
|
return unpackNullableBoolean(values, numBooleans, nullabilityBuffer);
|
|
}
|
|
return values;
|
|
}
|
|
export function decodeByteRle(buffer, numBytes, byteLength, pos) {
|
|
const values = new Uint8Array(numBytes);
|
|
let valueOffset = 0;
|
|
const streamEndPos = pos.get() + byteLength;
|
|
while (valueOffset < numBytes) {
|
|
if (pos.get() >= streamEndPos) {
|
|
break;
|
|
}
|
|
const header = buffer[pos.increment()];
|
|
/* Runs */
|
|
if (header <= 0x7f) {
|
|
const numRuns = header + 3;
|
|
const value = buffer[pos.increment()];
|
|
const endValueOffset = Math.min(valueOffset + numRuns, numBytes);
|
|
values.fill(value, valueOffset, endValueOffset);
|
|
valueOffset = endValueOffset;
|
|
}
|
|
else {
|
|
/* Literals */
|
|
const numLiterals = 256 - header;
|
|
for (let i = 0; i < numLiterals && valueOffset < numBytes; i++) {
|
|
values[valueOffset++] = buffer[pos.increment()];
|
|
}
|
|
}
|
|
}
|
|
pos.set(streamEndPos);
|
|
return values;
|
|
}
|
|
export function decodeFloatsLE(encodedValues, pos, numValues, nullabilityBuffer) {
|
|
const currentPos = pos.get();
|
|
const newOffset = currentPos + numValues * Float32Array.BYTES_PER_ELEMENT;
|
|
const newBuf = new Uint8Array(encodedValues.subarray(currentPos, newOffset)).buffer;
|
|
const fb = new Float32Array(newBuf);
|
|
pos.set(newOffset);
|
|
if (nullabilityBuffer) {
|
|
return unpackNullable(fb, nullabilityBuffer, 0);
|
|
}
|
|
return fb;
|
|
}
|
|
export function decodeDoublesLE(encodedValues, pos, numValues, nullabilityBuffer) {
|
|
const currentPos = pos.get();
|
|
const newOffset = currentPos + numValues * Float64Array.BYTES_PER_ELEMENT;
|
|
const newBuf = new Uint8Array(encodedValues.subarray(currentPos, newOffset)).buffer;
|
|
const fb = new Float64Array(newBuf);
|
|
pos.set(newOffset);
|
|
if (nullabilityBuffer) {
|
|
return unpackNullable(fb, nullabilityBuffer, 0);
|
|
}
|
|
return fb;
|
|
}
|
|
const TEXT_DECODER_MIN_LENGTH = 12;
|
|
const utf8TextDecoder = new TextDecoder();
|
|
// Source: https://github.com/mapbox/pbf/issues/106
|
|
export function decodeString(buf, pos, end) {
|
|
if (end - pos >= TEXT_DECODER_MIN_LENGTH) {
|
|
// longer strings are fast with the built-in browser TextDecoder API
|
|
return utf8TextDecoder.decode(buf.subarray(pos, end));
|
|
}
|
|
// short strings are fast with custom implementation
|
|
return readUtf8(buf, pos, end);
|
|
}
|
|
function readUtf8(buf, pos, end) {
|
|
let str = "";
|
|
let i = pos;
|
|
while (i < end) {
|
|
const b0 = buf[i];
|
|
let c = null; // codepoint
|
|
let bytesPerSequence = b0 > 0xef ? 4 : b0 > 0xdf ? 3 : b0 > 0xbf ? 2 : 1;
|
|
if (i + bytesPerSequence > end)
|
|
break;
|
|
let b1;
|
|
let b2;
|
|
let b3;
|
|
if (bytesPerSequence === 1) {
|
|
if (b0 < 0x80) {
|
|
c = b0;
|
|
}
|
|
}
|
|
else if (bytesPerSequence === 2) {
|
|
b1 = buf[i + 1];
|
|
if ((b1 & 0xc0) === 0x80) {
|
|
c = ((b0 & 0x1f) << 0x6) | (b1 & 0x3f);
|
|
if (c <= 0x7f) {
|
|
c = null;
|
|
}
|
|
}
|
|
}
|
|
else if (bytesPerSequence === 3) {
|
|
b1 = buf[i + 1];
|
|
b2 = buf[i + 2];
|
|
if ((b1 & 0xc0) === 0x80 && (b2 & 0xc0) === 0x80) {
|
|
c = ((b0 & 0xf) << 0xc) | ((b1 & 0x3f) << 0x6) | (b2 & 0x3f);
|
|
if (c <= 0x7ff || (c >= 0xd800 && c <= 0xdfff)) {
|
|
c = null;
|
|
}
|
|
}
|
|
}
|
|
else if (bytesPerSequence === 4) {
|
|
b1 = buf[i + 1];
|
|
b2 = buf[i + 2];
|
|
b3 = buf[i + 3];
|
|
if ((b1 & 0xc0) === 0x80 && (b2 & 0xc0) === 0x80 && (b3 & 0xc0) === 0x80) {
|
|
c = ((b0 & 0xf) << 0x12) | ((b1 & 0x3f) << 0xc) | ((b2 & 0x3f) << 0x6) | (b3 & 0x3f);
|
|
if (c <= 0xffff || c >= 0x110000) {
|
|
c = null;
|
|
}
|
|
}
|
|
}
|
|
if (c === null) {
|
|
c = 0xfffd;
|
|
bytesPerSequence = 1;
|
|
}
|
|
else if (c > 0xffff) {
|
|
c -= 0x10000;
|
|
str += String.fromCharCode(((c >>> 10) & 0x3ff) | 0xd800);
|
|
c = 0xdc00 | (c & 0x3ff);
|
|
}
|
|
str += String.fromCharCode(c);
|
|
i += bytesPerSequence;
|
|
}
|
|
return str;
|
|
}
|
|
export function getVectorTypeBooleanStream(numFeatures, byteLength, data, offset) {
|
|
const valuesPerRun = 0x83;
|
|
// TODO: use VectorType metadata field for to test which VectorType is used
|
|
return Math.ceil(numFeatures / valuesPerRun) * 2 === byteLength &&
|
|
/* Test the first value byte if all bits are set to true */
|
|
(data[offset.get() + 1] & 0xff) === (bitCount(numFeatures) << 2) - 1
|
|
? VectorType.CONST
|
|
: VectorType.FLAT;
|
|
}
|
|
function bitCount(number) {
|
|
//TODO: refactor to get rid of special case handling
|
|
return number === 0 ? 1 : Math.floor(Math.log2(number) + 1);
|
|
}
|
|
//# sourceMappingURL=decodingUtils.js.map
|