Created
July 19, 2020 00:57
-
-
Save junderw/f59264aede3dc5df4bc393f926dbad35 to your computer and use it in GitHub Desktop.
A CBOR encoder in TypeScript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class CBOREncoder { | |
private entryCount: number = 0; | |
private data: Uint8Array = Uint8Array.from([]); | |
pushBool(key: string, value: boolean): void { | |
this.entryCount++; | |
this.pushTextInternal(key); | |
this.pushBoolInternal(value); | |
} | |
pushText(key: string, value: string): void { | |
this.entryCount++; | |
this.pushTextInternal(key); | |
this.pushTextInternal(value); | |
} | |
pushBytes(key: string, value: Uint8Array): void { | |
this.entryCount++; | |
this.pushTextInternal(key); | |
this.pushBytesInternal(value); | |
} | |
serialise(): Uint8Array { | |
const size = this.data.length + 1; | |
if (size > 0xffff) throw new Error('Metadata too large.'); | |
if (this.entryCount > 0x1f) throw new Error('Too many map entries.'); | |
const ret = appendBytes( | |
Uint8Array.from([0xa0 + this.entryCount]), | |
this.data, | |
Uint8Array.from([0, 0]), | |
); | |
ret[size] = size >> 8; | |
ret[size + 1] = size & 0xff; | |
return ret; | |
} | |
private appendBytes(...bufs: Uint8Array[]): void { | |
this.data = appendBytes(this.data, ...bufs); | |
} | |
private pushBoolInternal(value: boolean): void { | |
this.appendBytes(Uint8Array.from([value ? 0xf5 : 0xf4])); | |
} | |
private pushBytesInternal(value: Uint8Array): void { | |
const len = value.length; | |
if (len < 24) { | |
this.appendBytes(Uint8Array.from([0x40 + len]), value); | |
} else if (len <= 256) { | |
this.appendBytes(Uint8Array.from([0x58, len]), value); | |
} else { | |
throw new Error('Byte string too large.'); | |
} | |
} | |
private pushTextInternal(value: string): void { | |
const valueBuf = new TextEncoder().encode(value); | |
const len = valueBuf.length; | |
if (len < 24) { | |
this.appendBytes(Uint8Array.from([0x60 + len]), valueBuf); | |
} else if (len <= 256) { | |
this.appendBytes(Uint8Array.from([0x78, len]), valueBuf); | |
} else { | |
throw new Error('Text string too large.'); | |
} | |
} | |
} | |
function appendBytes(main: Uint8Array, ...bufs: Uint8Array[]): Uint8Array { | |
const bufsLen = bufs.reduce((total, buf) => total + buf.length, 0); | |
let skipLen = main.length; | |
const ret = new Uint8Array(bufsLen + skipLen); | |
ret.set(main); | |
bufs.forEach(buf => { | |
ret.set(buf, skipLen); | |
skipLen += buf.length; | |
}); | |
return ret; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment