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

108 lines
3.8 KiB
JavaScript

import { decodeVarintInt32 } from "../../decoding/integerDecodingUtils";
import { columnTypeHasChildren, columnTypeHasName, decodeColumnType } from "./typeMap";
const textDecoder = new TextDecoder();
const SUPPORTED_COLUMN_TYPES = "0-3(ID), 4(GEOMETRY), 10-29(scalars), 30(STRUCT)";
const SUPPORTED_FIELD_TYPES = "10-29(scalars), 30(STRUCT)";
/**
* Decodes a length-prefixed UTF-8 string.
* Layout: [len: varint32][bytes: len]
*/
function decodeString(src, offset) {
const length = decodeVarintInt32(src, offset, 1)[0];
if (length === 0) {
return "";
}
const start = offset.get();
const end = start + length;
const view = src.subarray(start, end);
offset.add(length);
return textDecoder.decode(view);
}
/**
* Converts a Column to a Field.
* Used when decoding Field metadata which has the same format as Column.
*/
function columnToField(column) {
return {
name: column.name,
nullable: column.nullable,
scalarField: column.scalarType,
complexField: column.complexType,
type: column.type === "scalarType" ? "scalarField" : "complexField",
};
}
/**
* Decodes a Field used as part of complex types (STRUCT children).
*/
export function decodeField(src, offset) {
const typeCode = decodeVarintInt32(src, offset, 1)[0] >>> 0;
if (typeCode < 10 || typeCode > 30) {
throw new Error(`Unsupported field type code ${typeCode}. Supported: ${SUPPORTED_FIELD_TYPES}`);
}
const column = decodeColumnType(typeCode);
if (columnTypeHasName(typeCode)) {
column.name = decodeString(src, offset);
}
if (columnTypeHasChildren(typeCode)) {
const childCount = decodeVarintInt32(src, offset, 1)[0] >>> 0;
column.complexType.children = new Array(childCount);
for (let i = 0; i < childCount; i++) {
column.complexType.children[i] = decodeField(src, offset);
}
}
return columnToField(column);
}
/**
* The typeCode encodes the column type, nullable flag, and whether it has name/children.
*/
function decodeColumn(src, offset) {
const typeCode = decodeVarintInt32(src, offset, 1)[0] >>> 0;
const column = decodeColumnType(typeCode);
if (!column) {
throw new Error(`Unsupported column type code ${typeCode}. Supported: ${SUPPORTED_COLUMN_TYPES}`);
}
if (columnTypeHasName(typeCode)) {
column.name = decodeString(src, offset);
}
else {
// ID and GEOMETRY columns have implicit names
if (typeCode >= 0 && typeCode <= 3) {
column.name = "id";
}
else if (typeCode === 4) {
column.name = "geometry";
}
}
if (columnTypeHasChildren(typeCode)) {
// Only STRUCT (typeCode 30) has children
const childCount = decodeVarintInt32(src, offset, 1)[0] >>> 0;
const complexCol = column.complexType;
complexCol.children = new Array(childCount);
for (let i = 0; i < childCount; i++) {
complexCol.children[i] = decodeField(src, offset);
}
}
return column;
}
/**
* Top-level decoder for embedded tileset metadata.
* Reads exactly ONE FeatureTableSchema from the stream.
*
* @param bytes The byte array containing the metadata
* @param offset The current offset in the byte array (will be advanced)
*/
export function decodeEmbeddedTileSetMetadata(bytes, offset) {
const meta = {};
meta.featureTables = [];
const table = {};
table.name = decodeString(bytes, offset);
const extent = decodeVarintInt32(bytes, offset, 1)[0] >>> 0;
const columnCount = decodeVarintInt32(bytes, offset, 1)[0] >>> 0;
table.columns = new Array(columnCount);
for (let j = 0; j < columnCount; j++) {
table.columns[j] = decodeColumn(bytes, offset);
}
meta.featureTables.push(table);
return [meta, extent];
}
//# sourceMappingURL=embeddedTilesetMetadataDecoder.js.map