Skip to content
Open
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
2 changes: 1 addition & 1 deletion src/encoder.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Encode a binary buffer
//
// definition: array of type parser functions
// objcet: object to encode to buffer
// object: object to encode to buffer
// options:
// - `bigEndian`: default endianness of encoder (default: `true`)
function encode(definition, object, { bigEndian = true } = {}) {
Expand Down
35 changes: 19 additions & 16 deletions src/types/binary.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,43 +25,46 @@ function binary(name,
reverseTransform = value => value,
} = {}
) {
let instanceSize = size;

function parse(buffer, parseTree, { bigEndian }) {
let offset = 0;
instanceSize = size;

// determine size to copy to result buffer
if (sizePrefixed) {
const { parse: prefixParser } = uint('prefix', { size: sizePrefixLength, bigEndian: sizePrefixBigEndian });
const result = prefixParser(buffer, {}, { bigEndian });

size = result.value;
instanceSize = result.value;
offset = result.size;
}
if (sizeField) {
size = sizeFieldTransform(parseTree[sizeField]);
instanceSize = sizeFieldTransform(parseTree[sizeField]);
}
if (size === undefined) {
size = buffer.length;
if (instanceSize === undefined) {
instanceSize = buffer.length;
}

// just copy data to result
const result = new Buffer(size);
const result = new Buffer(instanceSize);

buffer.copy(result, 0, offset, size + offset);
buffer.copy(result, 0, offset, instanceSize + offset);

// return result
return {
value: transform(result),
size: size + offset,
size: instanceSize + offset,
};
}

function prepareEncode(object, parseTree, { bigEndian }) {
if (size === undefined) {
size = object.length;
instanceSize = object.length;
}

if (sizeField) {
parseTree[sizeField] = sizeFieldReverseTransform(size);
parseTree[sizeField] = sizeFieldReverseTransform(instanceSize);
}
}

Expand All @@ -74,21 +77,21 @@ function binary(name,
const result = prefixEncoder(transformed.length, { bigEndian });

bufferItems.unshift(result);
size = transformed.length + sizePrefixLength;
instanceSize = transformed.length + sizePrefixLength;
}
if (size === undefined) {
size = transformed.length;
if (instanceSize === undefined) {
instanceSize = transformed.length;
}

// build buffer
let data = Buffer.concat(bufferItems);

if (data.length < size) {
if (data.length < instanceSize) {
// if the buffer was shorter than anticipated, pad with zeroes
data = Buffer.concat([data, Buffer.alloc(size - data.length)]);
} else if (data.length > size) {
data = Buffer.concat([data, Buffer.alloc(instanceSize - data.length)]);
} else if (data.length > instanceSize) {
// if the buffer was longer just cut it off
data = data.slice(0, size);
data = data.slice(0, instanceSize);
}

return data;
Expand Down
33 changes: 32 additions & 1 deletion src/types/loop.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,21 @@ const { uint } = require('./uint');

// Loop over a sub-struct
//
// Each iteration of the loop accesses its own context, which is initially
// empty apart from '_index', '_repetitions' and '_context'.
//
// struct: the structure that repeats
// repetitionsPrefixed: this loop is prefixed with a repetition count
// repetitionsPrefixLength: size of the prefix
// repetitionsBigEndian: override endianness of size prefix
// repetitions: how often the sub-struct repeats, defaults to Infinity
// repetitionsField: field in the parse tree that defines the repetition count
// contextField: field in the parse tree that is passed to each loop iteration
// as '_context', along with '_index' and '_repetitions'.
// contextFieldTransform: passed two params, an object from the loop state
// and the current loop index
// contextFieldReverseTransform: passed two params, an object from the loop state
// and the current loop index
//
// returns: parser function that returns array of parsed items
function loop(name,
Expand All @@ -18,6 +27,8 @@ function loop(name,
repetitionsPrefixed = false,
repetitionsPrefixLength = 0,
repetitionsBigEndian,
contextField,
contextFieldTransform = (value, idx) => value,
}
) {
function parse(buffer, parseTree, { bigEndian: inheritBigEndian }) {
Expand All @@ -44,10 +55,15 @@ function loop(name,

// run the loop for the defined sub-struct
const result = [];
const ctx = parseTree[contextField];

for (let i = 0; i < repetitions; i += 1) {
const data = buffer.slice(offset, buffer.length);
const loopResult = {};
const loopResult = {
'_index': i,
'_repetitions': repetitions,
'_context' : contextFieldTransform(ctx, i),
};
let parserOffset = 0;

// loop over items in the sub struct
Expand All @@ -59,6 +75,10 @@ function loop(name,
parserOffset += r.size;
}

delete loopResult['_index'];
delete loopResult['_repetitions'];
delete loopResult['_context'];

result.push(loopResult);
offset += parserOffset;

Expand All @@ -83,6 +103,10 @@ function loop(name,
if (repetitionsField) {
parseTree[repetitionsField] = repetitions;
}

if(contextField) {
object['_context'] = parseTree[contextField];
}
}

function encode(object, { bigEndian }) {
Expand All @@ -98,7 +122,13 @@ function loop(name,
parts.push(result);
}

let i = 0;

for (const loopObject of object) {
loopObject['_index'] = i;
loopObject['_repetitions'] = repetitions;
loopObject['_context'] = contextFieldTransform(object['_context'], i);

for (const { prepareEncode: itemPrepareEncode, name: itemName } of struct) {
const data = loopObject[itemName];

Expand All @@ -111,6 +141,7 @@ function loop(name,

parts.push(result);
}
i += 1;
}

return Buffer.concat(parts);
Expand Down
22 changes: 22 additions & 0 deletions test/binary.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,25 @@ test('bcd_4byte', (t) => {

t.is(compareTemplate(template(definition), { bcd: null }), true);
});

test("binary_reuse_with_undefined_size", (t) => {
const definition = [binary("bin")];
const buffer = Buffer.from("0d0a", "hex");
const buffer2 = Buffer.from("0a0b0c0d", "hex");
const parsed = parse(definition, buffer);
const parsed2 = parse(definition, buffer2);
const encoded = encode(definition, parsed);
const encoded2 = encode(definition, parsed2);

t.is(parsed.bin.length, 2);
t.is(parsed.bin[0], 0x0d);
t.is(parsed.bin[1], 0x0a);
t.is(encoded.compare(buffer), 0);

t.is(parsed2.bin.length, 4);
t.is(parsed2.bin[0], 0x0a);
t.is(parsed2.bin[1], 0x0b);
t.is(parsed2.bin[2], 0x0c);
t.is(parsed2.bin[3], 0x0d);
t.is(encoded2.compare(buffer2), 0);
});
Loading