# All files / node_modules/netcdfjs/src header.js

9.75% Statements 8/82
0% Branches 0/15
0% Functions 0/4
10.25% Lines 8/78

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228

    18x
    18x

    18x
    18x
    18x
    18x

    18x

    18x
     'use strict';

    const utils = require('./utils');
    const types = require('./types');

    // Grammar constants
    const ZERO = 0;
    const NC_DIMENSION = 10;
    const NC_VARIABLE = 11;
    const NC_ATTRIBUTE = 12;

    /**
     * Read the header of the file
     * @ignore
     * @param {IOBuffer} buffer - Buffer for the file data
     * @param {number} version - Version of the file
     * @return {object} - Object with the fields:
     *  * `recordDimension`: Number with the length of record dimension
     *  * `dimensions`: List of dimensions
     *  * `globalAttributes`: List of global attributes
     *  * `variables`: List of variables
     */
    function header(buffer, version) {
      // Length of record dimension
      // sum of the varSize's of all the record variables.
      var header = { recordDimension: { length: buffer.readUint32() } };

      // Version
      header.version = version;

      // List of dimensions
      var dimList = dimensionsList(buffer);
      header.recordDimension.id = dimList.recordId; // id of the unlimited dimension
      header.recordDimension.name = dimList.recordName; // name of the unlimited dimension
      header.dimensions = dimList.dimensions;

      // List of global attributes
      header.globalAttributes = attributesList(buffer);

      // List of variables
      var variables = variablesList(buffer, dimList.recordId, version);
      header.variables = variables.variables;
      header.recordDimension.recordStep = variables.recordStep;

      return header;
    }

    const NC_UNLIMITED = 0;

    /**
     * List of dimensions
     * @ignore
     * @param {IOBuffer} buffer - Buffer for the file data
     * @return {object} - Ojbect containing the following properties:
     *  * `dimensions` that is an array of dimension object:
      *  * `name`: String with the name of the dimension
      *  * `size`: Number with the size of the dimension dimensions: dimensions
     *  * `recordId`: the id of the dimension that has unlimited size or undefined,
     *  * `recordName`: name of the dimension that has unlimited size
     */
    function dimensionsList(buffer) {
      var recordId, recordName;
      const dimList = buffer.readUint32();
      if (dimList === ZERO) {
        utils.notNetcdf((buffer.readUint32() !== ZERO), 'wrong empty tag for list of dimensions');
        return [];
      } else {
        utils.notNetcdf((dimList !== NC_DIMENSION), 'wrong tag for list of dimensions');

        // Length of dimensions
        const dimensionSize = buffer.readUint32();
        var dimensions = new Array(dimensionSize);
        for (var dim = 0; dim < dimensionSize; dim++) {
          // Read name
          var name = utils.readName(buffer);

          // Read dimension size
          const size = buffer.readUint32();
    I      if (size === NC_UNLIMITED) { // in netcdf 3 one field can be of size unlimmited
            recordId = dim;
            recordName = name;
          }

          dimensions[dim] = {
            name: name,
            size: size
          };
        }
      }
      return {
        dimensions: dimensions,
        recordId: recordId,
        recordName: recordName
      };
    }

    /**
     * List of attributes
     * @ignore
     * @param {IOBuffer} buffer - Buffer for the file data
     * @return {Array<object>} - List of 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
     */
    function attributesList(buffer) {
      const gAttList = buffer.readUint32();
      if (gAttList === ZERO) {
        utils.notNetcdf((buffer.readUint32() !== ZERO), 'wrong empty tag for list of attributes');
        return [];
      } else {
        utils.notNetcdf((gAttList !== NC_ATTRIBUTE), 'wrong tag for list of attributes');

        // Length of attributes
        const attributeSize = buffer.readUint32();
        var attributes = new Array(attributeSize);
        for (var gAtt = 0; gAtt < attributeSize; gAtt++) {
          // Read name
          var name = utils.readName(buffer);

          // Read type
          var type = buffer.readUint32();
          utils.notNetcdf(((type < 1) || (type > 6)), `non valid type ${type}`);

          // Read attribute
          var size = buffer.readUint32();
          var value = types.readType(buffer, type, size);

          // Apply padding
          utils.padding(buffer);

          attributes[gAtt] = {
            name: name,
            type: types.num2str(type),
            value: value
          };
        }
      }
      return attributes;
    }

    /**
     * List of variables
     * @ignore
     * @param {IOBuffer} buffer - Buffer for the file data
     * @param {number} recordId - Id of the unlimited dimension (also called record dimension)
     *                            This value may be undefined if there is no unlimited dimension
     * @param {number} version - Version of the file
     * @return {object} - Number of recordStep and list of variables with:
     *  * `name`: String with the name of the variable
     *  * `dimensions`: Array with the dimension IDs of the variable
     *  * `attributes`: Array with the attributes of the variable
     *  * `type`: String with the type of the variable
     *  * `size`: Number with the size of the variable
     *  * `offset`: Number with the offset where of the variable begins
     *  * `record`: True if is a record variable, false otherwise (unlimited size)
     */

    function variablesList(buffer, recordId, version) {
      const varList = buffer.readUint32();
      var recordStep = 0;
      if (varList === ZERO) {
        utils.notNetcdf((buffer.readUint32() !== ZERO), 'wrong empty tag for list of variables');
        return [];
      } else {
        utils.notNetcdf((varList !== NC_VARIABLE), 'wrong tag for list of variables');

        // Length of variables
        const variableSize = buffer.readUint32();
        var variables = new Array(variableSize);
        for (var v = 0; v < variableSize; v++) {
          // Read name
          var name = utils.readName(buffer);

          // Read dimensionality of the variable
          const dimensionality = buffer.readUint32();

          // Index into the list of dimensions
          var dimensionsIds = new Array(dimensionality);
          for (var dim = 0; dim < dimensionality; dim++) {
            dimensionsIds[dim] = buffer.readUint32();
          }

          // Read variables size
          var attributes = attributesList(buffer);

          // Read type
          var type = buffer.readUint32();
          utils.notNetcdf(((type < 1) && (type > 6)), `non valid type ${type}`);

          // Read variable size
          // The 32-bit varSize field is not large enough to contain the size of variables that require
          // more than 2^32 - 4 bytes, so 2^32 - 1 is used in the varSize field for such variables.
          const varSize = buffer.readUint32();

          // Read offset
          var offset = buffer.readUint32();
    I      if (version === 2) {
            utils.notNetcdf((offset > 0), 'offsets larger than 4GB not supported');
            offset = buffer.readUint32();
          }

          let record = false;
          // Count amount of record variables
    I      if ((typeof recordId !== 'undefined') && (dimensionsIds[0] === recordId)) {
            recordStep += varSize;
            record = true;
          }
          variables[v] = {
            name: name,
            dimensions: dimensionsIds,
            attributes,
            type: types.num2str(type),
            size: varSize,
            offset,
            record
          };
        }
      }

      return {
        variables: variables,
        recordStep: recordStep
      };
    }

    module.exports = header;