| // -*- 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); |
| 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'}; |
| } |
| module.exports.string = string; |
| |
| var TYPES = {'integer': 1, 'binary': 1, 'float': 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 'integer': |
| case 'float': |
| return 1; |
| } |
| } |
| |
| function size_of(segment, type, size, unit) { |
| if (size !== undefined && size !== '') { |
| return size; |
| } |
| else { |
| switch (type) { |
| case 'integer': |
| return 8; |
| case 'float': |
| return 64; |
| case 'binary': |
| return true; |
| } |
| } |
| } |