Files
Projekt-Visualisierung/node_modules/@maplibre/mlt/dist/decoding/decodingUtils.js
2026-04-15 17:08:39 +02:00

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