Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,30 @@ Jump to `offset`, execute parser for `type` and rewind to previous offset.
start of the input buffer. Can be a string `[u]int{8, 16, 32, 64}{le, be}`
or an user defined Parser object.

### saveOffset(name [,options])
Save the current buffer offset as key `name`. This function is only useful when called after another function which would advance the internal buffer offset.

```javascript
var parser = new Parser()
// this call advances the buffer offset by
// a variable (i.e. unknown to us) number of bytes
.string('name', {
zeroTerminated: true
})
// this variable points to an absolute position
// in the buffer
.uint32('seekOffset')
// now, save the "current" offset in the stream
// as the variable "currentOffset"
.saveOffset('currentOffset')
// finally, use the saved offset to figure out
// how many bytes we need to skip
.skip(function() {
return this.seekOffset - this.currentOffset;
})
... // the parser would continue here
```

### skip(length)
Skip parsing for `length` bytes.

Expand Down
14 changes: 14 additions & 0 deletions lib/binary_parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type ComplexTypes =
| 'nest'
| 'skip'
| 'pointer'
| 'saveoffset'
| '';

type Endianess = 'be' | 'le';
Expand Down Expand Up @@ -151,6 +152,7 @@ const CAPITILIZED_TYPE_NAMES: { [key in Types]: string } = {
nest: 'Nest',
skip: 'Skip',
pointer: 'Pointer',
saveoffset: 'SaveOffset',
'': '',
};

Expand Down Expand Up @@ -539,6 +541,10 @@ export class Parser {
return this.setNextParser('pointer', varName, options);
}

saveoffset(varName: string, options?: ParserOptions) {
return this.setNextParser('saveoffset', varName, options);
}

endianess(endianess: 'little' | 'big') {
switch (endianess.toLowerCase()) {
case 'little':
Expand Down Expand Up @@ -762,6 +768,9 @@ export class Parser {
case 'pointer':
this.generatePointer(ctx);
break;
case 'saveoffset':
this.generateSaveOffset(ctx);
break;
}
this.generateAssert(ctx);
}
Expand Down Expand Up @@ -1108,4 +1117,9 @@ export class Parser {
// Restore offset
ctx.pushCode(`offset = ${tempVar};`);
}

private generateSaveOffset(ctx: Context) {
const varName = ctx.generateVariable(this.varName);
ctx.pushCode(`${varName} = offset`);
}
}
42 changes: 42 additions & 0 deletions test/composite_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -995,6 +995,48 @@ describe('Composite parser', function() {
});
});

describe('SaveOffset', () => {
it('should save the offset', () => {
const buff = Buffer.from([0x01, 0x00, 0x02]);
const parser = Parser.start()
.int8('a')
.int16('b')
.saveoffset('bytesRead');

assert.deepEqual(parser.parse(buff), {
a: 1,
b: 2,
bytesRead: 3,
});
});

it('should save the offset if not at end', () => {
const buff = Buffer.from([0x01, 0x00, 0x02]);
const parser = Parser.start()
.int8('a')
.saveoffset('bytesRead')
.int16('b');

assert.deepEqual(parser.parse(buff), {
a: 1,
b: 2,
bytesRead: 1,
});
});

it('should save the offset with a dynamic parser', () => {
const buff = Buffer.from([0x74, 0x65, 0x73, 0x74, 0x00]);
const parser = Parser.start()
.string('name', { zeroTerminated: true })
.saveoffset('bytesRead');

assert.deepEqual(parser.parse(buff), {
name: 'test',
bytesRead: 5,
});
});
});

describe('Utilities', function() {
it('should count size for fixed size structs', function() {
var parser = Parser.start()
Expand Down