diff --git a/README.md b/README.md index c11e6c4a..2d492492 100644 --- a/README.md +++ b/README.md @@ -151,6 +151,8 @@ Parse bytes as an array. `options` is an object; following options are available Use number for statically sized arrays. - `readUntil` - (either `length` or `readUntil` is required) If `'eof'`, then this parser reads until the end of `Buffer` object. If function it reads until the function returns true. +- `$parent` - (Optional) An array with selected properties from the parental scope. References can be + accessed inside functions using `this.$parent[...]`. ```javascript var parser = new Parser() @@ -193,9 +195,11 @@ Combining `choice` with `array` is useful for parsing a typical - `tag` - (Required) The value used to determine which parser to use from the `choices` Can be a string pointing to another field or a function. -- `choices` - (Required) An object which key is an integer and value is the parser which is executed +- `choices` - (Required) An object which key is an integer/string and value is the parser which is executed when `tag` equals the key value. - `defaultChoice` - (Optional) In case of the tag value doesn't match any of `choices` use this parser. +- `$parent` - (Optional) An array with selected properties from the parental scope. References can be +accessed inside functions using `this.$parent[...]`. ```javascript var parser1 = ...; @@ -221,7 +225,7 @@ Nest a parser in this position. Parse result of the nested parser is stored in t - `type` - (Required) A `Parser` object. ### skip(length) -Skip parsing for `length` bytes. +Skip parsing of bytes. `length` can be either a number, a string or a function. ### endianess(endianess) Define what endianess to use in this parser. `endianess` can be either `'little'` or `'big'`. @@ -254,7 +258,7 @@ These are common options that can be specified in all parsers. ```javascript var parser = new Parser() .array('ipv4', { - type: uint8, + type: 'uint8', length: '4', formatter: function(arr) { return arr.join('.'); } }); diff --git a/lib/binary_parser.js b/lib/binary_parser.js index 978e9484..faacc8be 100644 --- a/lib/binary_parser.js +++ b/lib/binary_parser.js @@ -148,9 +148,6 @@ Parser.prototype.choice = function(varName, options) { throw new Error('Choices option of array is not defined.'); } Object.keys(options.choices).forEach(function(key) { - if (isNaN(parseInt(key, 10))) { - throw new Error('Key of choices must be a number.'); - } if (!options.choices[key]) { throw new Error('Choice Case ' + key + ' of ' + varName + ' is not valid.'); } @@ -485,7 +482,17 @@ Parser.prototype.generateArray = function(ctx) { ctx.pushCode('var {0} = buffer.read{1}(offset);', item, NAME_MAP[type]); ctx.pushCode('offset += {0};', PRIMITIVE_TYPES[NAME_MAP[type]]); } else if (type instanceof Parser) { - ctx.pushCode('var {0} = {};', item); + if (!this.options.$parent) { + ctx.pushCode('var {0} = {};', item); + } else { + ctx.pushCode('var {0} = { "$parent": {1} };', item, + '[' + this.options.$parent.map(function(prop){ return '"' + prop + '"'; }).toString() + + '].reduce(function($parent, key){\ + $parent[key] = ' + ctx.generateVariable() + '[key];\ + return $parent;\ + }, {})' + ); + } ctx.pushScope(item); type.generate(ctx); @@ -519,12 +526,22 @@ Parser.prototype.generateChoiceCase = function(ctx, varName, type) { Parser.prototype.generateChoice = function(ctx) { var tag = ctx.generateOption(this.options.tag); - ctx.pushCode('{0} = {};', ctx.generateVariable(this.varName)); + if (!this.options.$parent) { + ctx.pushCode('{0} = {};', ctx.generateVariable(this.varName)); + } else { + ctx.pushCode('{0} = { "$parent": {1} };', ctx.generateVariable(this.varName), + '[' + this.options.$parent.map(function(prop){ return '"' + prop + '"'; }).toString() + + '].reduce(function($parent, key){\ + $parent[key] = ' + ctx.generateVariable() + '[key];\ + return $parent;\ + }, {})' + ); + } ctx.pushCode('switch({0}) {', tag); Object.keys(this.options.choices).forEach(function(tag) { var type = this.options.choices[tag]; - ctx.pushCode('case {0}:', tag); + ctx.pushCode('case ' + (isNaN(tag) ? '"{0}"' : '{0}') + ':', tag); this.generateChoiceCase(ctx, this.varName, type); ctx.pushCode('break;'); }, this);