modern-netcdf
Version:
Modern NetCDF file reader and utilities
127 lines (121 loc) • 4.13 kB
JavaScript
const { readType, num2str } = require('./types');
const { notNetcdf, padding, readName } = require('./utils');
// Constants
const ZERO = 0;
const NC_DIMENSION = 10;
const NC_VARIABLE = 11;
const NC_ATTRIBUTE = 12;
const NC_UNLIMITED = 0;
function dimensionsList(buffer) {
const result = {};
let recordId, recordName;
const dimList = buffer.readUint32();
let dimensions;
if (dimList === ZERO) {
notNetcdf(buffer.readUint32() !== ZERO, 'wrong empty tag for list of dimensions');
return [];
} else {
notNetcdf(dimList !== NC_DIMENSION, 'wrong tag for list of dimensions');
const dimensionSize = buffer.readUint32();
dimensions = new Array(dimensionSize);
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 };
}
}
if (recordId !== undefined) result.recordId = recordId;
if (recordName !== undefined) result.recordName = recordName;
result.dimensions = dimensions;
return result;
}
function attributesList(buffer) {
const gAttList = buffer.readUint32();
let attributes;
if (gAttList === ZERO) {
notNetcdf(buffer.readUint32() !== ZERO, 'wrong empty tag for list of attributes');
return [];
} else {
notNetcdf(gAttList !== NC_ATTRIBUTE, 'wrong tag for list of attributes');
const attributeSize = buffer.readUint32();
attributes = new Array(attributeSize);
for (let gAtt = 0; gAtt < attributeSize; gAtt++) {
const name = readName(buffer);
const type = buffer.readUint32();
notNetcdf(type < 1 || type > 6, `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 variablesList(buffer, recordId, version) {
const varList = buffer.readUint32();
let recordStep = 0;
let variables;
if (varList === ZERO) {
notNetcdf(buffer.readUint32() !== ZERO, 'wrong empty tag for list of variables');
return [];
} else {
notNetcdf(varList !== NC_VARIABLE, 'wrong tag for list of variables');
const variableSize = buffer.readUint32();
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 d = 0; d < dimensionality; d++) {
dimensionsIds[d] = buffer.readUint32();
}
const attributes = attributesList(buffer);
const type = buffer.readUint32();
notNetcdf(type < 1 || type > 6, `non valid type ${type}`);
const varSize = buffer.readUint32();
let offset = buffer.readUint32();
if (version === 2) {
notNetcdf(offset > 0, '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 header(buffer, version) {
const header = { version };
const recordDimension = { length: buffer.readUint32() };
const dimList = dimensionsList(buffer);
if (!Array.isArray(dimList)) {
recordDimension.id = dimList.recordId;
recordDimension.name = dimList.recordName;
header.dimensions = dimList.dimensions;
}
header.globalAttributes = attributesList(buffer);
const varsInfo = variablesList(buffer, recordDimension?.id, version);
if (!Array.isArray(varsInfo)) {
header.variables = varsInfo.variables;
recordDimension.recordStep = varsInfo.recordStep;
}
header.recordDimension = recordDimension;
return header;
}
module.exports = { header };