2.7 KiB
@suaveplan/license — codec/bitpack
(no submodules)
Purpose
Bit-precise pack/unpack primitives used to serialise the 72-bit license
payload into 9 bytes. Plain DataView / typed-array slicing can only
write whole bytes, so we walk the buffer bit-by-bit. Two thin classes
hold the cursor: SimpleBitPacker writes MSB-first, SimpleBitUnpacker
reads MSB-first. Both round-trip identically to upstream's
@suaveplan/license bitpacker.
Features
packUint(value, bits)— writes an unsigned integer in[0, 2^bits)usingbitsbits; raisesLicenseError(LICENSE.PAYLOAD_OUT_OF_RANGE)when the value exceeds the declared width or is negative.unpackUint(bits)— reads the nextbits-wide unsigned integer; raisesLicenseError(LICENSE.MALFORMED)when the read would underflow the buffer.getBytes()/getBitCount()/getBitPosition()introspection helpers used by the spec-conformance tests.
Usage: Basic
import {
SimpleBitPacker,
SimpleBitUnpacker,
} from "@suaveplan/license/codec/bitpack/bitpack";
const p = new SimpleBitPacker();
p.packUint(2, 3); // 3-bit version
p.packUint(17, 5); // 5-bit signingKeyId
const bytes = p.getBytes();
const u = new SimpleBitUnpacker(bytes);
const version = u.unpackUint(3); // 2
const keyId = u.unpackUint(5); // 17
Usage: Advanced
Round-tripping a full 72-bit payload:
import { FIELD_BITS } from "@suaveplan/license/constants/constants";
import {
SimpleBitPacker,
SimpleBitUnpacker,
} from "@suaveplan/license/codec/bitpack/bitpack";
const p = new SimpleBitPacker();
for (const [_field, bits] of Object.entries(FIELD_BITS)) {
p.packUint(0, bits);
}
const bytes = p.getBytes(); // 9 bytes
const u = new SimpleBitUnpacker(bytes);
for (const [_field, bits] of Object.entries(FIELD_BITS)) {
u.unpackUint(bits); // === 0
}
API Reference
class SimpleBitPacker
packUint(value: number, bits: number): void— write an unsigned integer; throws on overflow / negative.getBytes(): Uint8Array— snapshot the packed bytes.getBitCount(): number— total bits written.
class SimpleBitUnpacker
constructor(buffer: Uint8Array)— wrap a byte buffer.unpackUint(bits: number): number— read the next integer; throwsMALFORMEDon underflow.getBitPosition(): number— current read cursor.
Implementation Notes
The packer grows its internal number[] buffer one byte at a time
because the upstream layout is small (9 bytes) and pre-sizing would
require knowing the total bit count in advance. The 1 << bits overflow
check is safe for the bit widths used by the license schema (≤19 bits);
for wider integers, callers should use a dedicated bigint bitpacker.