"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// dist/index.js
var dist_exports = {};
__export(dist_exports, {
NetCDFLoader: () => NetCDFLoader,
NetCDFReader: () => NetCDFReader
});
module.exports = __toCommonJS(dist_exports);
// dist/iobuffer/iobuffer.js
var DEFAULT_BYTE_LENGTH = 1024 * 8;
var IOBuffer = class {
/**
* Reference to the internal ArrayBuffer object.
*/
buffer;
/**
* Byte length of the internal ArrayBuffer.
*/
byteLength;
/**
* Byte offset of the internal ArrayBuffer.
*/
byteOffset;
/**
* Byte length of the internal ArrayBuffer.
*/
length;
/**
* The current offset of the buffer's pointer.
*/
offset;
lastWrittenByte;
littleEndian;
_data;
_mark;
_marks;
textDecoder = new TextDecoder();
textEncoder = new TextEncoder();
/**
* @param data - The data to construct the IOBuffer with.
* If data is a number, it will be the new buffer's length
* If data is `undefined`, the buffer will be initialized with a default length of 8Kb
* If data is an ArrayBuffer, SharedArrayBuffer, an ArrayBufferView (Typed Array), an IOBuffer instance,
* or a Node.js Buffer, a view will be created over the underlying ArrayBuffer.
* @param options
*/
constructor(data = DEFAULT_BYTE_LENGTH, options = {}) {
let dataIsGiven = false;
if (typeof data === "number") {
data = new ArrayBuffer(data);
} else {
dataIsGiven = true;
this.lastWrittenByte = data.byteLength;
}
const offset = options.offset ? options.offset >>> 0 : 0;
const byteLength = data.byteLength - offset;
let dvOffset = offset;
if (ArrayBuffer.isView(data) || data instanceof IOBuffer) {
if (data.byteLength !== data.buffer.byteLength) {
dvOffset = data.byteOffset + offset;
}
data = data.buffer;
}
if (dataIsGiven) {
this.lastWrittenByte = byteLength;
} else {
this.lastWrittenByte = 0;
}
this.buffer = data;
this.length = byteLength;
this.byteLength = byteLength;
this.byteOffset = dvOffset;
this.offset = 0;
this.littleEndian = true;
this._data = new DataView(this.buffer, dvOffset, byteLength);
this._mark = 0;
this._marks = [];
}
/**
* Checks if the memory allocated to the buffer is sufficient to store more
* bytes after the offset.
* @param byteLength - The needed memory in bytes.
* @returns `true` if there is sufficient space and `false` otherwise.
*/
available(byteLength = 1) {
return this.offset + byteLength <= this.length;
}
/**
* Check if little-endian mode is used for reading and writing multi-byte
* values.
* @returns `true` if little-endian mode is used, `false` otherwise.
*/
isLittleEndian() {
return this.littleEndian;
}
/**
* Set little-endian mode for reading and writing multi-byte values.
*/
setLittleEndian() {
this.littleEndian = true;
return this;
}
/**
* Check if big-endian mode is used for reading and writing multi-byte values.
* @returns `true` if big-endian mode is used, `false` otherwise.
*/
isBigEndian() {
return !this.littleEndian;
}
/**
* Switches to big-endian mode for reading and writing multi-byte values.
*/
setBigEndian() {
this.littleEndian = false;
return this;
}
/**
* Move the pointer n bytes forward.
* @param n - Number of bytes to skip.
*/
skip(n = 1) {
this.offset += n;
return this;
}
/**
* Move the pointer to the given offset.
* @param offset
*/
seek(offset) {
this.offset = offset;
return this;
}
/**
* Store the current pointer offset.
* @see {@link IOBuffer#reset}
*/
mark() {
this._mark = this.offset;
return this;
}
/**
* Move the pointer back to the last pointer offset set by mark.
* @see {@link IOBuffer#mark}
*/
reset() {
this.offset = this._mark;
return this;
}
/**
* Push the current pointer offset to the mark stack.
* @see {@link IOBuffer#popMark}
*/
pushMark() {
this._marks.push(this.offset);
return this;
}
/**
* Pop the last pointer offset from the mark stack, and set the current
* pointer offset to the popped value.
* @see {@link IOBuffer#pushMark}
*/
popMark() {
const offset = this._marks.pop();
if (offset === void 0) {
throw new Error("Mark stack empty");
}
this.seek(offset);
return this;
}
/**
* Move the pointer offset back to 0.
*/
rewind() {
this.offset = 0;
return this;
}
/**
* Make sure the buffer has sufficient memory to write a given byteLength at
* the current pointer offset.
* If the buffer's memory is insufficient, this method will create a new
* buffer (a copy) with a length that is twice (byteLength + current offset).
* @param byteLength
*/
ensureAvailable(byteLength = 1) {
if (!this.available(byteLength)) {
const lengthNeeded = this.offset + byteLength;
const newLength = lengthNeeded * 2;
const newArray = new Uint8Array(newLength);
newArray.set(new Uint8Array(this.buffer));
this.buffer = newArray.buffer;
this.length = this.byteLength = newLength;
this._data = new DataView(this.buffer);
}
return this;
}
/**
* Read a byte and return false if the byte's value is 0, or true otherwise.
* Moves pointer forward by one byte.
*/
readBoolean() {
return this.readUint8() !== 0;
}
/**
* Read a signed 8-bit integer and move pointer forward by 1 byte.
*/
readInt8() {
return this._data.getInt8(this.offset++);
}
/**
* Read an unsigned 8-bit integer and move pointer forward by 1 byte.
*/
readUint8() {
return this._data.getUint8(this.offset++);
}
/**
* Alias for {@link IOBuffer#readUint8}.
*/
readByte() {
return this.readUint8();
}
/**
* Read `n` bytes and move pointer forward by `n` bytes.
*/
readBytes(n = 1) {
const bytes = new Uint8Array(n);
for (let i = 0; i < n; i++) {
bytes[i] = this.readByte();
}
return bytes;
}
/**
* Read a 16-bit signed integer and move pointer forward by 2 bytes.
*/
readInt16() {
const value = this._data.getInt16(this.offset, this.littleEndian);
this.offset += 2;
return value;
}
/**
* Read a 16-bit unsigned integer and move pointer forward by 2 bytes.
*/
readUint16() {
const value = this._data.getUint16(this.offset, this.littleEndian);
this.offset += 2;
return value;
}
/**
* Read a 32-bit signed integer and move pointer forward by 4 bytes.
*/
readInt32() {
const value = this._data.getInt32(this.offset, this.littleEndian);
this.offset += 4;
return value;
}
/**
* Read a 32-bit unsigned integer and move pointer forward by 4 bytes.
*/
readUint32() {
const value = this._data.getUint32(this.offset, this.littleEndian);
this.offset += 4;
return value;
}
/**
* Read a 32-bit floating number and move pointer forward by 4 bytes.
*/
readFloat32() {
const value = this._data.getFloat32(this.offset, this.littleEndian);
this.offset += 4;
return value;
}
/**
* Read a 64-bit floating number and move pointer forward by 8 bytes.
*/
readFloat64() {
const value = this._data.getFloat64(this.offset, this.littleEndian);
this.offset += 8;
return value;
}
/**
* Read a 1-byte ASCII character and move pointer forward by 1 byte.
*/
readChar() {
return String.fromCharCode(this.readInt8());
}
/**
* Read `n` 1-byte ASCII characters and move pointer forward by `n` bytes.
*/
readChars(n = 1) {
let result = "";
for (let i = 0; i < n; i++) {
result += this.readChar();
}
return result;
}
/**
* Read the next `n` bytes, return a UTF-8 decoded string and move pointer
* forward by `n` bytes.
*/
readUtf8(n = 1) {
return this.textDecoder.decode(this.readBytes(n));
}
/**
* Write 0xff if the passed value is truthy, 0x00 otherwise and move pointer
* forward by 1 byte.
*/
writeBoolean(value) {
this.writeUint8(value ? 255 : 0);
return this;
}
/**
* Write `value` as an 8-bit signed integer and move pointer forward by 1 byte.
*/
writeInt8(value) {
this.ensureAvailable(1);
this._data.setInt8(this.offset++, value);
this._updateLastWrittenByte();
return this;
}
/**
* Write `value` as an 8-bit unsigned integer and move pointer forward by 1
* byte.
*/
writeUint8(value) {
this.ensureAvailable(1);
this._data.setUint8(this.offset++, value);
this._updateLastWrittenByte();
return this;
}
/**
* An alias for {@link IOBuffer#writeUint8}.
*/
writeByte(value) {
return this.writeUint8(value);
}
/**
* Write all elements of `bytes` as uint8 values and move pointer forward by
* `bytes.length` bytes.
*/
writeBytes(bytes) {
this.ensureAvailable(bytes.length);
for (let i = 0; i < bytes.length; i++) {
this._data.setUint8(this.offset++, bytes[i]);
}
this._updateLastWrittenByte();
return this;
}
/**
* Write `value` as a 16-bit signed integer and move pointer forward by 2
* bytes.
*/
writeInt16(value) {
this.ensureAvailable(2);
this._data.setInt16(this.offset, value, this.littleEndian);
this.offset += 2;
this._updateLastWrittenByte();
return this;
}
/**
* Write `value` as a 16-bit unsigned integer and move pointer forward by 2
* bytes.
*/
writeUint16(value) {
this.ensureAvailable(2);
this._data.setUint16(this.offset, value, this.littleEndian);
this.offset += 2;
this._updateLastWrittenByte();
return this;
}
/**
* Write `value` as a 32-bit signed integer and move pointer forward by 4
* bytes.
*/
writeInt32(value) {
this.ensureAvailable(4);
this._data.setInt32(this.offset, value, this.littleEndian);
this.offset += 4;
this._updateLastWrittenByte();
return this;
}
/**
* Write `value` as a 32-bit unsigned integer and move pointer forward by 4
* bytes.
*/
writeUint32(value) {
this.ensureAvailable(4);
this._data.setUint32(this.offset, value, this.littleEndian);
this.offset += 4;
this._updateLastWrittenByte();
return this;
}
/**
* Write `value` as a 32-bit floating number and move pointer forward by 4
* bytes.
*/
writeFloat32(value) {
this.ensureAvailable(4);
this._data.setFloat32(this.offset, value, this.littleEndian);
this.offset += 4;
this._updateLastWrittenByte();
return this;
}
/**
* Write `value` as a 64-bit floating number and move pointer forward by 8
* bytes.
*/
writeFloat64(value) {
this.ensureAvailable(8);
this._data.setFloat64(this.offset, value, this.littleEndian);
this.offset += 8;
this._updateLastWrittenByte();
return this;
}
/**
* Write the charCode of `str`'s first character as an 8-bit unsigned integer
* and move pointer forward by 1 byte.
*/
writeChar(str) {
return this.writeUint8(str.charCodeAt(0));
}
/**
* Write the charCodes of all `str`'s characters as 8-bit unsigned integers
* and move pointer forward by `str.length` bytes.
*/
writeChars(str) {
for (let i = 0; i < str.length; i++) {
this.writeUint8(str.charCodeAt(i));
}
return this;
}
/**
* UTF-8 encode and write `str` to the current pointer offset and move pointer
* forward according to the encoded length.
*/
writeUtf8(str) {
const bytes = this.textEncoder.encode(str);
return this.writeBytes(bytes);
}
/**
* Export a Uint8Array view of the internal buffer.
* The view starts at the byte offset and its length
* is calculated to stop at the last written byte or the original length.
*/
toArray() {
return new Uint8Array(this.buffer, this.byteOffset, this.lastWrittenByte);
}
/**
* Update the last written byte offset
* @private
*/
_updateLastWrittenByte() {
if (this.offset > this.lastWrittenByte) {
this.lastWrittenByte = this.offset;
}
}
};
// dist/netcdfjs/read-type.js
var TYPES = {
BYTE: 1,
CHAR: 2,
SHORT: 3,
INT: 4,
FLOAT: 5,
DOUBLE: 6
};
function readType(buffer, type, size) {
switch (type) {
case TYPES.BYTE:
return buffer.readBytes(size);
case TYPES.CHAR:
return trimNull(buffer.readChars(size));
case TYPES.SHORT:
return readNumber(size, buffer.readInt16.bind(buffer));
case TYPES.INT:
return readNumber(size, buffer.readInt32.bind(buffer));
case TYPES.FLOAT:
return readNumber(size, buffer.readFloat32.bind(buffer));
case TYPES.DOUBLE:
return readNumber(size, buffer.readFloat64.bind(buffer));
default:
throw new Error(`NetCDF: non valid type ${type}`);
}
}
function num2str(type) {
switch (Number(type)) {
case TYPES.BYTE:
return "byte";
case TYPES.CHAR:
return "char";
case TYPES.SHORT:
return "short";
case TYPES.INT:
return "int";
case TYPES.FLOAT:
return "float";
case TYPES.DOUBLE:
return "double";
default:
return "undefined";
}
}
function num2bytes(type) {
switch (Number(type)) {
case TYPES.BYTE:
return 1;
case TYPES.CHAR:
return 1;
case TYPES.SHORT:
return 2;
case TYPES.INT:
return 4;
case TYPES.FLOAT:
return 4;
case TYPES.DOUBLE:
return 8;
default:
return -1;
}
}
function str2num(type) {
switch (String(type)) {
case "byte":
return TYPES.BYTE;
case "char":
return TYPES.CHAR;
case "short":
return TYPES.SHORT;
case "int":
return TYPES.INT;
case "float":
return TYPES.FLOAT;
case "double":
return TYPES.DOUBLE;
default:
return -1;
}
}
function readNumber(size, bufferReader) {
if (size !== 1) {
const numbers = new Array(size);
for (let i = 0; i < size; i++) {
numbers[i] = bufferReader();
}
return numbers;
}
return bufferReader();
}
function trimNull(value) {
if (value.charCodeAt(value.length - 1) === 0) {
return value.substring(0, value.length - 1);
}
return value;
}
// dist/netcdfjs/read-header.js
var ZERO = 0;
var NC_DIMENSION = 10;
var NC_VARIABLE = 11;
var NC_ATTRIBUTE = 12;
var NC_UNLIMITED = 0;
function readNetCDFHeader(buffer, version) {
const recordDimensionLength = buffer.readUint32();
const dimList = readDimensionsList(buffer);
const attributes = readAttributesList(buffer);
const variableList = readVariablesList(buffer, dimList.recordId, version);
const header = {
version,
recordDimension: {
length: recordDimensionLength,
id: dimList.recordId,
// id of the unlimited dimension
name: dimList.recordName,
// name of the unlimited dimension
recordStep: variableList.recordStep
},
dimensions: dimList.dimensions,
variables: variableList.variables,
attributes
};
return header;
}
function readDimensionsList(buffer) {
const dimList = buffer.readUint32();
if (dimList === ZERO) {
if (buffer.readUint32() !== ZERO) {
throw new Error("NetCDF: wrong empty tag for list of dimensions");
}
return {
recordId: 0,
recordName: "",
dimensions: []
};
}
if (dimList !== NC_DIMENSION) {
throw new Error("NetCDF: wrong tag for list of dimensions");
}
const dimensionSize = buffer.readUint32();
const dimensions = new Array(dimensionSize);
let recordId;
let recordName;
for (let dim = 0; dim < dimensionSize; dim++) {
const name = readName(buffer);
const size = buffer.readUint32();
if (size === NC_UNLIMITED) {
recordId = dim;
recordName = name;
}
dimensions[dim] = {
name,
size
};
}
return {
dimensions,
recordId,
recordName
};
}
function readAttributesList(buffer) {
const gAttList = buffer.readUint32();
if (gAttList === ZERO) {
if (buffer.readUint32() !== ZERO) {
throw new Error("NetCDF: wrong empty tag for list of attributes");
}
return [];
}
if (gAttList !== NC_ATTRIBUTE) {
throw new Error("NetCDF: wrong tag for list of attributes");
}
const attributeSize = buffer.readUint32();
const attributes = new Array(attributeSize);
for (let gAtt = 0; gAtt < attributeSize; gAtt++) {
const name = readName(buffer);
const type = buffer.readUint32();
if (type < 1 || type > 6) {
throw new Error(`NetCDF: non valid type ${type}`);
}
const size = buffer.readUint32();
const value = readType(buffer, type, size);
padding(buffer);
attributes[gAtt] = {
name,
type: num2str(type),
value
};
}
return attributes;
}
function readVariablesList(buffer, recordId, version) {
const varList = buffer.readUint32();
let recordStep = 0;
if (varList === ZERO) {
if (buffer.readUint32() !== ZERO) {
throw new Error("NetCDF: wrong empty tag for list of variables");
}
return {
recordStep,
variables: []
};
}
if (varList !== NC_VARIABLE) {
throw new Error("NetCDF: wrong tag for list of variables");
}
const variableSize = buffer.readUint32();
const variables = new Array(variableSize);
for (let v = 0; v < variableSize; v++) {
const name = readName(buffer);
const dimensionality = buffer.readUint32();
const dimensionsIds = new Array(dimensionality);
for (let dim = 0; dim < dimensionality; dim++) {
dimensionsIds[dim] = buffer.readUint32();
}
const attributes = readAttributesList(buffer);
const type = buffer.readUint32();
if (type < 1 && type > 6) {
throw new Error(`NetCDF: non valid type ${type}`);
}
const varSize = buffer.readUint32();
let offset = buffer.readUint32();
if (version === 2) {
if (offset > 0) {
throw new Error("NetCDF: offsets larger than 4GB not supported");
}
offset = buffer.readUint32();
}
let record = false;
if (typeof recordId !== "undefined" && dimensionsIds[0] === recordId) {
recordStep += varSize;
record = true;
}
variables[v] = {
name,
dimensions: dimensionsIds,
attributes,
type: num2str(type),
size: varSize,
offset,
record
};
}
return {
variables,
recordStep
};
}
function readName(buffer) {
const nameLength = buffer.readUint32();
const name = buffer.readChars(nameLength);
padding(buffer);
return name;
}
function padding(buffer) {
if (buffer.offset % 4 !== 0) {
buffer.skip(4 - buffer.offset % 4);
}
}
// dist/netcdfjs/read-data.js
function readNonRecord(buffer, variable) {
const type = str2num(variable.type);
const size = variable.size / num2bytes(type);
const data = new Array(size);
for (let i = 0; i < size; i++) {
data[i] = readType(buffer, type, 1);
}
return data;
}
function readRecord(buffer, variable, recordDimension) {
const type = str2num(variable.type);
const width = variable.size ? variable.size / num2bytes(type) : 1;
const size = recordDimension.length;
const data = new Array(size);
const step = recordDimension.recordStep;
for (let i = 0; i < size; i++) {
const currentOffset = buffer.offset;
data[i] = readType(buffer, type, width);
buffer.seek(currentOffset + step);
}
return data;
}
// dist/netcdfjs/netcdf-reader.js
var NetCDFReader = class {
header;
buffer;
constructor(data) {
const buffer = new IOBuffer(data);
buffer.setBigEndian();
const magic = buffer.readChars(3);
if (magic !== "CDF") {
throw new Error(`NetCDF: file should start with 'CDF', found ${magic}`);
}
const version = buffer.readByte();
if (version > 2) {
throw new Error(`NetCDF: unsupported version ${version}`);
}
this.header = readNetCDFHeader(buffer, version);
this.buffer = buffer;
}
/**
* @return {string} - Version for the NetCDF format
*/
get version() {
if (this.header.version === 1) {
return "classic format";
}
return "64-bit offset format";
}
/**
* Get metadata for the record dimension
*/
get recordDimension() {
return this.header.recordDimension;
}
/**
* Get list of dimensions (each with `name` and `size`)
*/
get dimensions() {
return this.header.dimensions;
}
/**
* Get list of global attributes with:
* * `name`: String with the name of the attribute
* * `type`: String with the type of the attribute
* * `value`: A number or string with the value of the attribute
*/
get attributes() {
return this.header.attributes;
}
/**
* Get list of variables
*/
get variables() {
return this.header.variables;
}
/**
* Check if an attribute exists
* @param attributeName - Name of the attribute to find
* @return
*/
attributeExists(attributeName) {
const attribute = this.attributes.find((val) => val.name === attributeName);
return attribute !== void 0;
}
/**
* Returns the value of an attribute
* @param attributeName
* @return Value of the attributeName or null
*/
getAttribute(attributeName) {
const attribute = this.attributes.find((val) => val.name === attributeName);
if (attribute)
return attribute.value;
return null;
}
/**
* Check if a dataVariable exists
* @param variableName - Name of the variable to find
* @return
*/
dataVariableExists(variableName) {
const variable = this.header.variables.find(function(val) {
return val.name === variableName;
});
return variable !== void 0;
}
/**
* Returns the value of a variable as a string
* @param variableName
* @return Value of the variable as a string or null
*/
getDataVariableAsString(variableName) {
const variable = this.getDataVariable(variableName);
if (variable)
return variable.join("");
return null;
}
/**
* Retrieves the data for a given variable
* @param variableName - Name of the variable to search or variable object
* @return List with the variable values
*/
getDataVariable(variableName) {
let variable;
if (typeof variableName === "string") {
variable = this.header.variables.find(function(val) {
return val.name === variableName;
});
} else {
variable = variableName;
}
if (variable === void 0) {
let errorOutput;
if (typeof variableName === "string") {
errorOutput = variableName;
} else if (typeof variableName === "object") {
errorOutput = JSON.stringify(variableName);
}
throw new Error(`NetCDF: variable not found: ${errorOutput}`);
}
this.buffer.seek(variable.offset);
if (variable.record) {
return readRecord(this.buffer, variable, this.header.recordDimension);
}
return readNonRecord(this.buffer, variable);
}
toString() {
const result = [];
result.push("DIMENSIONS");
for (const dimension of this.dimensions) {
result.push(` ${dimension.name.padEnd(30)} = size: ${dimension.size}`);
}
result.push("");
result.push("GLOBAL ATTRIBUTES");
for (const attribute of this.attributes) {
result.push(` ${attribute.name.padEnd(30)} = ${attribute.value}`);
}
const variables = JSON.parse(JSON.stringify(this.variables));
result.push("");
result.push("VARIABLES:");
for (const variable of variables) {
variable.value = this.getDataVariable(variable);
let stringify = JSON.stringify(variable.value);
if (stringify.length > 50)
stringify = stringify.substring(0, 50);
if (!isNaN(variable.value.length)) {
stringify += ` (length: ${variable.value.length})`;
}
result.push(` ${variable.name.padEnd(30)} = ${stringify}`);
}
return result.join("\n");
}
};
// dist/netcdf-loader.js
var VERSION = true ? "4.3.1" : "latest";
var NetCDFWorkerLoader = {
dataType: null,
batchType: null,
name: "NetCDF",
id: "mvt",
module: "mvt",
version: VERSION,
extensions: ["cdf", "nc"],
mimeTypes: [
"application/netcdf",
"application/x-netcdf"
// 'application/octet-stream'
],
category: "image",
options: {
netcdf: {
loadVariables: false
}
}
};
var NetCDFLoader = {
...NetCDFWorkerLoader,
parse: async (arrayBuffer, options) => parseNetCDF(arrayBuffer, options),
binary: true
};
function parseNetCDF(arrayBuffer, options) {
var _a;
const reader = new NetCDFReader(arrayBuffer);
const variables = {};
if ((_a = options == null ? void 0 : options.netcdf) == null ? void 0 : _a.loadData) {
for (const variable of reader.variables) {
variables[variable.name] = reader.getDataVariable(variable);
}
}
return {
loaderData: reader.header,
data: variables
};
}
//# sourceMappingURL=index.cjs.map