Skip to content

Commit 4443726

Browse files
committed
Fixes encoding array readUntil function and add encodeUntil option
1 parent dd75c74 commit 4443726

File tree

4 files changed

+170
-6
lines changed

4 files changed

+170
-6
lines changed

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,12 @@ keys:
208208
a function. Use number for statically sized arrays.
209209
- `readUntil` - (either `length`, `lengthInBytes`, or `readUntil` is required)
210210
If `"eof"`, then this parser reads until the end of `Buffer` object. If
211-
function it reads until the function returns true.
211+
function it reads until the function returns true. **<u>Note</u>**: When encoding,
212+
the `buffer` second parameter of `readUntil` function is the buffer already encoded
213+
before this array. So no *read-ahead* is possible.
214+
- `encodeUntil` - a function (item, object), only used when encoding, that replaces
215+
the `readUntil` function when present and allow limit the number of encoded items
216+
by returning true based on *item* values or other *object* properies.
212217

213218
```javascript
214219
var parser = new Parser()

lib/binary_parser.js

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -898,7 +898,6 @@ Parser.prototype.generate_encodeArray = function(ctx) {
898898
var item = ctx.generateTmpVariable();
899899
var itemCounter = ctx.generateTmpVariable();
900900
var maxItems = ctx.generateTmpVariable();
901-
var maxOffset = ctx.generateTmpVariable();
902901
var isHash = typeof this.options.key === "string";
903902

904903
if (isHash) {
@@ -928,7 +927,10 @@ Parser.prototype.generate_encodeArray = function(ctx) {
928927
);
929928

930929
ctx.pushCode("var {0} = 0;", itemCounter);
931-
if (typeof this.options.readUntil === "function") {
930+
if (
931+
typeof this.options.encodeUntil === "function" ||
932+
this.options.readUntil
933+
) {
932934
ctx.pushCode("do {");
933935
} else {
934936
ctx.pushCode("for ( ; {0} < {1}; ) {", itemCounter, maxItems);
@@ -958,9 +960,19 @@ Parser.prototype.generate_encodeArray = function(ctx) {
958960

959961
ctx.pushCode("}"); // End of 'do {' or 'for(...) {'
960962

961-
if (typeof this.options.readUntil === "function") {
963+
if (typeof this.options.encodeUntil === "function") {
962964
ctx.pushCode(
963-
" while (!({0}).call(this, {1}, {2}.toBuffer()));",
965+
" while ({0} < {1} && !({2}).call(this, {3}, vars));",
966+
itemCounter,
967+
maxItems,
968+
this.options.encodeUntil,
969+
item
970+
);
971+
} else if (typeof this.options.readUntil === "function") {
972+
ctx.pushCode(
973+
" while ({0} < {1} && !({2}).call(this, {3}, {4}.toBuffer()));",
974+
itemCounter,
975+
maxItems,
964976
this.options.readUntil,
965977
item,
966978
savSmartBuffer

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "binary-parser-encoder",
3-
"version": "1.3.2",
3+
"version": "1.4.0",
44
"description": "Blazing-fast binary parser builder",
55
"main": "lib/binary_parser.js",
66
"devDependencies": {

test/zz_encoder_bugs.js

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
var assert = require("assert");
2+
var Parser = require("../lib/binary_parser").Parser;
3+
4+
describe("Specific bugs testing", function() {
5+
describe("Array encoder with readUntil", function() {
6+
it("should limit to array length even if readUntil is never true", function() {
7+
var parser = Parser.start()
8+
.uint16("len")
9+
.array("payloads", {
10+
type: new Parser().uint8("cmd").array("params", {
11+
type: new Parser().uint8("param"),
12+
readUntil: function(item, buffer) {
13+
return buffer.length == 2; // Stop when 2 bytes left in parsed buffer
14+
}
15+
}),
16+
lengthInBytes: function() {
17+
return this.len - 4;
18+
}
19+
})
20+
.uint16("crc");
21+
22+
var buffer = Buffer.from("0008AAB1B2B3FFFF", "hex");
23+
var decoded = parser.parse(buffer);
24+
25+
assert.deepEqual(decoded, {
26+
len: 8,
27+
payloads: [
28+
{
29+
cmd: 170,
30+
params: [
31+
{
32+
param: 177
33+
},
34+
{
35+
param: 178
36+
},
37+
{
38+
param: 179
39+
}
40+
]
41+
}
42+
],
43+
crc: 65535
44+
});
45+
46+
var encoded;
47+
// Although readUntil is never true here, the encoding will be good
48+
assert.doesNotThrow(function() {
49+
encoded = parser.encode(decoded);
50+
});
51+
assert.deepEqual(encoded, buffer);
52+
});
53+
54+
it("is not the reverse of parsing when readUntil gives false information", function() {
55+
var parser = Parser.start()
56+
.uint16("len")
57+
.array("payloads", {
58+
type: new Parser().uint8("cmd").array("params", {
59+
type: new Parser().uint8("param"),
60+
readUntil: function(item, buffer) {
61+
return buffer.length <= 2; // Stop when 2 bytes left in buffer
62+
}
63+
}),
64+
lengthInBytes: function() {
65+
return this.len - 4;
66+
}
67+
})
68+
.uint16("crc");
69+
70+
var buffer = Buffer.from("0008AAB1B2B3FFFF", "hex");
71+
var decoded = parser.parse(buffer);
72+
73+
assert.deepEqual(decoded, {
74+
len: 8,
75+
payloads: [
76+
{
77+
cmd: 170,
78+
params: [
79+
{
80+
param: 177
81+
},
82+
{
83+
param: 178
84+
},
85+
{
86+
param: 179
87+
}
88+
]
89+
}
90+
],
91+
crc: 0xffff
92+
});
93+
94+
var encoded = parser.encode(decoded);
95+
// Missing parms 178 and 179 as readUntil will be true at first run
96+
assert.deepEqual(encoded, Buffer.from("0008AAB1FFFF", "hex"));
97+
});
98+
99+
it("should ignore readUntil when encodeUntil is provided", function() {
100+
var parser = Parser.start()
101+
.uint16("len")
102+
.array("payloads", {
103+
type: new Parser().uint8("cmd").array("params", {
104+
type: new Parser().uint8("param"),
105+
readUntil: function(item, buffer) {
106+
return buffer.length == 2; // Stop when 2 bytes left in buffer
107+
},
108+
encodeUntil: function(item, obj) {
109+
return item.param === 178; // Stop encoding when value 178 is reached
110+
}
111+
}),
112+
lengthInBytes: function() {
113+
return this.len - 4;
114+
}
115+
})
116+
.uint16("crc");
117+
118+
var buffer = Buffer.from("0008AAB1B2B3FFFF", "hex");
119+
var decoded = parser.parse(buffer);
120+
121+
assert.deepEqual(decoded, {
122+
len: 8,
123+
payloads: [
124+
{
125+
cmd: 170,
126+
params: [
127+
{
128+
param: 177
129+
},
130+
{
131+
param: 178
132+
},
133+
{
134+
param: 179
135+
}
136+
]
137+
}
138+
],
139+
crc: 0xffff
140+
});
141+
142+
var encoded = parser.encode(decoded);
143+
// Missing parms 179 as encodeUntil stops at 178
144+
assert.deepEqual(encoded, Buffer.from("0008AAB1B2FFFF", "hex"));
145+
});
146+
});
147+
});

0 commit comments

Comments
 (0)