All files / app/lib pattern.js

80% Statements 52/65
58.82% Branches 30/51
84.61% Functions 11/13
79.68% Lines 51/64

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            120x 120x 112x   120x           118x 118x 118x 118x 118x 118x   118x 34x   118x     2x 2x               2x 2x 2x   2x 2x 2x     2x         10x   2x   2x   120x 106x   76x       120x   76x     86x     120x   120x         86x         76x       120x 92x 28x   28x       92x   18x             74x         120x 102x     18x   6x               12x                                   34x 50x 34x     34x    
// -*- js-indent-level: 2 -*-
// Constructing patterns
 
'use strict';
 
function set(values) {
  var s = {};
  for (var i in values) {
    s[values[i]] = 1;
  }
  return s;
}
 
// Construct a segment bound to a variable, e.g., from a segment like
// "Len:32/unsigned-big". `specifiers0` is an array.
function variable(name, size, specifiers0) {
  var specifiers = set(specifiers0);
  var segment = {name: name};
  segment.type = type_in(specifiers);
  specs(segment, segment.type, specifiers);
  segment.size = size_of(segment, segment.type, size, segment.unit);
  Iif (segment.type == 'string') {
      add_string_specifiers(segment, specifiers);
  } else if (segment.type == 'binary') {
    add_binary_specifiers(segment, specifiers);
  }
  return segment;
}
 
module.exports.variable = variable;
module.exports.rest = function() {
  return variable('_', true, ['binary']);
}
 
// Construct a segment with a literal value, e.g., from a segment like
// "206". `specifiers0` is an array.
 
function value(val, size, specifiers0) {
  var specifiers = set(specifiers0);
  var segment = {value: val};
  segment.type = type_in(specifiers);
  // TODO check type v. value ..
  specs(segment, segment.type, specifiers);
  segment.size = size_of(segment, segment.type, size, segment.unit);
  return segment;
}
 
module.exports.value = value;
 
// A string can appear as a literal, but it must appear without
// specifiers.
function string(val) {
  return {value: val, type: 'string', size: Buffer.from(val, 'utf8').byteLength, unit: 8};
}
module.exports.string = string;
 
var TYPES = {'integer': 1, 'binary': 1, 'float': 1, 'string': 1, 'left': 1, 'right': 1, 'zero': 1, 'space': 1, 'bcd': 1};
function type_in(specifiers) {
  for (var t in specifiers) {
    if (TYPES[t]) { return t; }
  }
  return 'integer';
}
 
function specs(segment, type, specifiers) {
  switch (type) {
  case 'integer':
    segment.signed = signed_in(specifiers);
    // fall through
  case 'float':
    segment.bigendian = endian_in(specifiers);
    // fall through
  default:
    segment.unit = unit_in(specifiers, segment.type);
  }
  return segment;
}
 
function endian_in(specifiers) {
  // default is big, but I have chosen true = bigendian
  return !specifiers['little'];
}
 
function signed_in(specifiers) {
  // this time I got it right; default is unsigned
  return specifiers['signed'];
}
 
function unit_in(specifiers, type) {
  for (var s in specifiers) {
    if (s.substr(0, 5) == 'unit:') {
      var unit = parseInt(s.substr(5));
      // TODO check sane for type
      return unit;
    }
  }
  // OK defaults then
  switch (type) {
  case 'binary':
    return 8;
  case 'string':
    return 8;
  case 'bcd':
    return 8;
  case 'integer':
  case 'float':
    return 1;
  }
}
 
function size_of(segment, type, size, unit) {
  if (size !== undefined && size !== '' && size !== null) {
    return size;
  }
  else {
    switch (type) {
    case 'integer':
      return 8;
    case 'string':
      return null;
    case 'bcd':
      return 8;
    case 'float':
      return 64;
    case 'binary':
      return null;
    }
  }
}
 
function add_string_specifiers(segment, specifiers) {
  for (var s in specifiers) {
    if (s == 'left' || s == 'right' || s == 'zero' || s == 'space' || s == 'binhex' || s == 'hexbin' || s == 'bcd' || s == 'binary' || s == 'z') {
      if (s == 'binary' && ((parseInt(segment.size)/8) % 1) != 0) {
        throw "Segmen size must be divisible to 8!";
      }
      segment[s] = 1;
    }
  }
  return segment;
}
 
function add_binary_specifiers(segment, specifiers) {
  for (var s in specifiers) {
    if (s == 'left' || s == 'right' || s == 'zero' || s == 'space' || s == 'binhex' || s == 'hexbin' || s == 'binary' || s == 'z') {
      segment[s] = 1;
    }
  }
  return segment;
}