Skip to content

Commit f6c2dd6

Browse files
authored
Merge pull request #115 from keichi/buffer-readuntil
Implement readUntil option for buffer
2 parents 7dbf542 + e1b91ea commit f6c2dd6

File tree

4 files changed

+61
-20
lines changed

4 files changed

+61
-20
lines changed

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,14 +151,16 @@ the following keys:
151151
- `clone` - (Optional, defaults to `false`) By default,
152152
`buffer(name [,options])` returns a new buffer which references the same
153153
memory as the parser input, but offset and cropped by a certain range. If
154-
this option is true, input buffer will be cloned and a new buffer referncing
155-
another memory is returned.
154+
this option is true, input buffer will be cloned and a new buffer
155+
referencing a new memory region is returned.
156156
- `length ` - (either `length` or `readUntil` is required) Length of the
157157
buffer. Can be a number, string or a function. Use number for statically
158158
sized buffers, string to reference another variable and function to do some
159159
calculation.
160160
- `readUntil` - (either `length` or `readUntil` is required) If `"eof"`, then
161-
this parser will read till it reaches end of the `Buffer` object.
161+
this parser will read till it reaches end of the `Buffer` object. If it is a
162+
function, this parser will read the buffer is read until the function
163+
returns true.
162164

163165
### array(name, options)
164166
Parse bytes as an array. `options` is an object which can have the following

lib/binary_parser.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -911,7 +911,22 @@ export class Parser {
911911
private generateBuffer(ctx: Context) {
912912
const varName = ctx.generateVariable(this.varName);
913913

914-
if (this.options.readUntil === 'eof') {
914+
if (typeof this.options.readUntil === 'function') {
915+
const pred = this.options.readUntil;
916+
const start = ctx.generateTmpVariable();
917+
const cur = ctx.generateTmpVariable();
918+
919+
ctx.pushCode(`var ${start} = offset;`);
920+
ctx.pushCode(`var ${cur} = 0;`);
921+
ctx.pushCode(`while (offset < buffer.length) {`);
922+
ctx.pushCode(`${cur} = buffer.readUInt8(offset);`);
923+
ctx.pushCode(
924+
`if (${pred}.call(this, ${cur}, buffer.slice(offset))) break;`
925+
);
926+
ctx.pushCode(`offset += 1;`);
927+
ctx.pushCode(`}`);
928+
ctx.pushCode(`${varName} = buffer.slice(${start}, offset);`);
929+
} else if (this.options.readUntil === 'eof') {
915930
ctx.pushCode(`${varName} = buffer.slice(offset);`);
916931
} else {
917932
const len = ctx.generateOption(this.options.length);

test/composite_parser.js

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -906,22 +906,6 @@ describe('Composite parser', function() {
906906
});
907907
});
908908

909-
describe('Buffer parser', function() {
910-
//this is a test for testing a fix of a bug, that removed the last byte of the
911-
//buffer parser
912-
it('should return a buffer with same size', function() {
913-
var bufferParser = new Parser().buffer('buf', {
914-
readUntil: 'eof',
915-
formatter: function(buffer) {
916-
return buffer;
917-
},
918-
});
919-
920-
var buffer = Buffer.from('John\0Doe\0');
921-
assert.deepEqual(bufferParser.parse(buffer), { buf: buffer });
922-
});
923-
});
924-
925909
describe('Constructors', function() {
926910
it('should create a custom object type', function() {
927911
function Person() {

test/primitive_parser.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,5 +424,45 @@ describe('Primitive parser', function() {
424424
result.raw[0] = 0xff;
425425
assert.notDeepEqual(result.raw, buf);
426426
});
427+
428+
it('should parse until function returns true when readUntil is function', function() {
429+
var parser = new Parser()
430+
.endianess('big')
431+
.uint8('cmd')
432+
.buffer('data', {
433+
readUntil: function(item) {
434+
return item === 2;
435+
},
436+
});
437+
438+
var result = parser.parse(Buffer.from('aa', 'hex'));
439+
assert.deepEqual(result, { cmd: 0xaa, data: Buffer.from([]) });
440+
441+
var result = parser.parse(Buffer.from('aabbcc', 'hex'));
442+
assert.deepEqual(result, { cmd: 0xaa, data: Buffer.from('bbcc', 'hex') });
443+
444+
var result = parser.parse(Buffer.from('aa02bbcc', 'hex'));
445+
assert.deepEqual(result, { cmd: 0xaa, data: Buffer.from([]) });
446+
447+
var result = parser.parse(Buffer.from('aabbcc02', 'hex'));
448+
assert.deepEqual(result, { cmd: 0xaa, data: Buffer.from('bbcc', 'hex') });
449+
450+
var result = parser.parse(Buffer.from('aabbcc02dd', 'hex'));
451+
assert.deepEqual(result, { cmd: 0xaa, data: Buffer.from('bbcc', 'hex') });
452+
});
453+
454+
// this is a test for testing a fix of a bug, that removed the last byte
455+
// of the buffer parser
456+
it('should return a buffer with same size', function() {
457+
var bufferParser = new Parser().buffer('buf', {
458+
readUntil: 'eof',
459+
formatter: function(buffer) {
460+
return buffer;
461+
},
462+
});
463+
464+
var buffer = Buffer.from('John\0Doe\0');
465+
assert.deepEqual(bufferParser.parse(buffer), { buf: buffer });
466+
});
427467
});
428468
});

0 commit comments

Comments
 (0)