diff --git a/lib/binary_parser.ts b/lib/binary_parser.ts index d347ee8a..22edb6a0 100644 --- a/lib/binary_parser.ts +++ b/lib/binary_parser.ts @@ -1038,6 +1038,30 @@ export class Parser { return ctx; } + private nextNotBit() { + // Used to test if next type is a bitN or not + if (this.next) { + if (this.next.type === "nest") { + // For now consider a nest as a bit + if (this.next.options && this.next.options.type instanceof Parser) { + // Something in the nest + if (this.next.options.type.next) { + return this.next.options.type.next.type !== "bit"; + } + return false; + } else { + // Nest is empty. For now assume this means bit is not next. However what if something comes after the nest? + return true; + } + } else { + return this.next.type !== "bit"; + } + } else { + // Nothing else so next can't be bits + return true; + } + } + private generateBit(ctx: Context) { // TODO find better method to handle nested bit fields const parser = JSON.parse(JSON.stringify(this)); @@ -1047,10 +1071,7 @@ export class Parser { parser.varName = ctx.generateVariable(parser.varName); ctx.bitFields.push(parser); - if ( - !this.next || - (this.next && ["bit", "nest"].indexOf(this.next.type) < 0) - ) { + if (!this.next || this.nextNotBit()) { const val = ctx.generateTmpVariable(); ctx.pushCode(`var ${val} = 0;`); diff --git a/test/composite_parser.ts b/test/composite_parser.ts index 333c7684..34058af9 100644 --- a/test/composite_parser.ts +++ b/test/composite_parser.ts @@ -982,6 +982,56 @@ function compositeParserTests( }, }); }); + + it("standalone bit fields should work", () => { + const parser = Parser.start().bit6("one").bit8("two"); + const buffer = factory([0xa8, 0x78]); + const result = parser.parse(buffer); + deepStrictEqual(result.one, 0xa8 >> 2); + deepStrictEqual(result.two, 0x78 >> 2); + }); + + it("bit to nested bit should work", () => { + const parser = Parser.start() + .bit6("one") + .nest("nested", { + type: new Parser().bit8("two").uint8("three"), + }); + const buffer = factory([0xa8, 0x78, 0x45]); + const result = parser.parse(buffer); + deepStrictEqual(result.one, 0xa8 >> 2); + deepStrictEqual(result.nested.two, 0x78 >> 2); + // switching to uint8 should start at next byte (skipping two bits here) + deepStrictEqual(result.nested.three, 0x45); + }); + + it("bit before nest should work", () => { + const parser = Parser.start() + .useContextVars() + .bit8("items") + .nest("data", { + type: Parser.start() + .uint8("length") + .string("message", { length: "length" }) + .array("value", { + type: "uint8", + length: "$parent.items", + }), + }); + + const buffer = factory([ + 0x2, 0xc, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77, 0x6f, 0x72, + 0x6c, 0x64, 0x01, 0x02, 0x02, 0x02, + ]); + deepStrictEqual(parser.parse(buffer), { + items: 2, + data: { + length: 12, + message: "hello, world", + value: [0x01, 0x02], + }, + }); + }); }); describe("Constructors", () => {