Skip to content

Commit

Permalink
Add lengthInBytes option to array() (#19)
Browse files Browse the repository at this point in the history
Add lengthInBytes option to array()
  • Loading branch information
nhjm449 authored and keichi committed Aug 22, 2017
1 parent b33404b commit 2ba7504
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 5 deletions.
29 changes: 25 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,11 @@ Parse bytes as an array. `options` is an object; following options are available

- `type` - (Required) Type of the array element. Can be a string or an user defined Parser object.
If it's a string, you have to choose from [u]int{8, 16, 32}{le, be}.
- `length` - (either `length` or `readUntil` is required) Length of the array. Can be a number, string or a function.
- `length` - (either `length`, `lengthInBytes`, or `readUntil` is required) Length of the array. Can be a number, string or a function.
Use number for statically sized arrays.
- `readUntil` - (either `length` or `readUntil` is required) If `'eof'`, then this parser
- `lengthInBytes` - (either `length`, `lengthInBytes`, or `readUntil` is required) Length of the array expressed in bytes. Can be a number, string or a function.
Use number for statically sized arrays.
- `readUntil` - (either `length`, `lengthInBytes`, 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.

```javascript
Expand All @@ -173,14 +175,33 @@ var parser = new Parser()
length: function() { return this.dataLength - 1; } // other fields are available through this
});

// Dynamically sized array (with stop-check on parsed item)
// Statically sized array
.array('data4', {
type: 'int32',
lengthInBytes: 16
})

// Dynamically sized array (reference another variable)
.uint8('dataLengthInBytes')
.array('data5', {
type: 'int32',
lengthInBytes: 'dataLengthInBytes'
})

// Dynamically sized array (with some calculation)
.array('data6', {
type: 'int32',
lengthInBytes: function() { return this.dataLengthInBytes - 4; } // other fields are available through this
})

// Dynamically sized array (with stop-check on parsed item)
.array('data7', {
type: 'int32',
readUntil: function(item, buffer) { return item === 42 } // stop when specific item is parsed. buffer can be used to perform a read-ahead.
});

// Use user defined parser object
.array('data5', {
.array('data8', {
type: userDefinedParser,
length: 'dataLength'
});
Expand Down
5 changes: 4 additions & 1 deletion lib/binary_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ Parser.prototype.buffer = function(varName, options) {
};

Parser.prototype.array = function(varName, options) {
if (!options.readUntil && !options.length) {
if (!options.readUntil && !options.length && !options.lengthInBytes) {
throw new Error('Length option of array is not defined.');
}
if (!options.type) {
Expand Down Expand Up @@ -524,6 +524,7 @@ Parser.prototype.generateBuffer = function(ctx) {

Parser.prototype.generateArray = function(ctx) {
var length = ctx.generateOption(this.options.length);
var lengthInBytes = ctx.generateOption(this.options.lengthInBytes);
var type = this.options.type;
var counter = ctx.generateTmpVariable();
var lhs = ctx.generateVariable(this.varName);
Expand All @@ -540,6 +541,8 @@ Parser.prototype.generateArray = function(ctx) {
ctx.pushCode('do {');
} else if (this.options.readUntil === 'eof') {
ctx.pushCode('for (var {0} = 0; offset < buffer.length; {0}++) {', counter);
} else if (lengthInBytes !== undefined) {
ctx.pushCode('for (var {0} = offset; offset - {0} < {1}; ) {', counter, lengthInBytes);
} else {
ctx.pushCode('for (var {0} = 0; {0} < {1}; {0}++) {', counter, length);
}
Expand Down
79 changes: 79 additions & 0 deletions test/composite_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,21 @@ describe('Composite parser', function(){
message: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
});
});
it('should parse array of primitive types with lengthInBytes', function(){
var parser =
Parser.start()
.uint8('length')
.array('message', {
lengthInBytes: 'length',
type: 'uint8'
});

var buffer = new Buffer([12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
assert.deepEqual(parser.parse(buffer), {
length: 12,
message: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
});
});
it('should parse array of user defined types', function(){
var elementParser = new Parser()
.uint8('key')
Expand All @@ -41,6 +56,70 @@ describe('Composite parser', function(){
]
});
});
it('should parse array of user defined types with lengthInBytes', function(){
var elementParser = new Parser()
.uint8('key')
.int16le('value');

var parser =
Parser.start()
.uint16le('length')
.array('message', {
lengthInBytes: 'length',
type: elementParser
});

var buffer = new Buffer([0x06, 0x00, 0xca, 0xd2, 0x04, 0xbe, 0xd3, 0x04]);
assert.deepEqual(parser.parse(buffer), {
length: 0x06,
message: [
{key: 0xca, value: 1234},
{key: 0xbe, value: 1235}
]
});
});
it('should parse array of user defined types with lengthInBytes literal', function(){
var elementParser = new Parser()
.uint8('key')
.int16le('value');

var parser =
Parser.start()
.array('message', {
lengthInBytes: 0x06,
type: elementParser
});

var buffer = new Buffer([0xca, 0xd2, 0x04, 0xbe, 0xd3, 0x04]);
assert.deepEqual(parser.parse(buffer), {
message: [
{key: 0xca, value: 1234},
{key: 0xbe, value: 1235}
]
});
});
it('should parse array of user defined types with lengthInBytes function', function(){
var elementParser = new Parser()
.uint8('key')
.int16le('value');

var parser =
Parser.start()
.uint16le('length')
.array('message', {
lengthInBytes: function() { return this.length; },
type: elementParser
});

var buffer = new Buffer([0x06, 0x00, 0xca, 0xd2, 0x04, 0xbe, 0xd3, 0x04]);
assert.deepEqual(parser.parse(buffer), {
length: 0x06,
message: [
{key: 0xca, value: 1234},
{key: 0xbe, value: 1235}
]
});
});
it('should parse array of arrays', function(){
var rowParser =
Parser.start()
Expand Down

0 comments on commit 2ba7504

Please sign in to comment.