UNPKG

binpat

Version:

Parse binary data using declarative patterns.

1 lines 4 kB
const BINPAT_TYPE=Symbol("type"),BINPAT_ARRAY=Symbol("array");function exec(t,e,r){if("function"==typeof e&&BINPAT_TYPE in e)return e(t,r);if(Array.isArray(e))return e.map((e=>exec(t,e,r)));if("object"==typeof e){const n={...r,parent:r,data:{}};return Object.entries(e).forEach((([e,r])=>{const i=exec(t,r,n);e.startsWith("__BINPAT_SPREAD_")?n.data={...n.data,...i}:e.startsWith("__BINPAT_OMIT_")||(n.data[e]=i)})),r.offset=n.offset,n.data}return e}export default class Binpat{#t;endian="big";constructor(t,e){this.#t=t,this.endian="little"===e?.endian?"little":"big"}exec(t){const e={endian:this.endian,offset:0,data:{}};return exec(new DataView(t),this.#t,e)}}function createPrimitiveHandler(t,e,r,n){return i=>{function o(t,n){const o=i??"little"===n.endian,a=t[r](n.offset,o);return n.offset+=e,a}return o[BINPAT_TYPE]=t,o[BINPAT_ARRAY]=n,o}}export const u8=createPrimitiveHandler("u8",1,"getUint8",Uint8Array);export const u16=createPrimitiveHandler("u16",2,"getUint16",Uint16Array);export const u32=createPrimitiveHandler("u32",4,"getUint32",Uint32Array);export const u64=createPrimitiveHandler("u64",8,"getBigUint64",BigUint64Array);export const i8=createPrimitiveHandler("i8",1,"getInt8",Int8Array);export const i16=createPrimitiveHandler("i16",2,"getInt16",Int16Array);export const i32=createPrimitiveHandler("i32",4,"getInt32",Int32Array);export const i64=createPrimitiveHandler("i64",8,"getBigInt64",BigInt64Array);export const f16=createPrimitiveHandler("f16",2,"getFloat16",Float16Array);export const f32=createPrimitiveHandler("f32",4,"getFloat32",Float32Array);export const f64=createPrimitiveHandler("f64",8,"getFloat64",Float64Array);export function bool(){function t(t,e){const r=!!t.getUint8(e.offset);return e.offset+=1,r}return t[BINPAT_TYPE]="bool",t}export function string(t,e="utf-8"){function r(r,n){const i="function"==typeof t?t(n):t,o=new Uint8Array(r.buffer.slice(n.offset,n.offset+i));return n.offset+=i,new TextDecoder(e).decode(o)}return r[BINPAT_TYPE]="string",r}export function array(t,e){function r(r,n){const i="function"==typeof e?e(n):e;return(t[BINPAT_ARRAY]||Array).from({length:i}).map((()=>exec(r,t,n)))}return r[BINPAT_TYPE]="array",r}export function bitfield(t,e={}){function r(r,n){const i=e.endian||n.endian,o=e.first||("big"===i?"MSb":"LSb");let a=Object.entries(t).map((([t,e])=>[t,"number"==typeof e?{type:"u",size:e}:e]));const f=a.reduce(((t,[,e])=>t+e.size),0),c=Math.ceil(f/8),s=8*c-f;s&&a.push([omit(),{type:"u",size:s}]),"LSb"===o&&a.reverse();let u=new Uint8Array(r.buffer.slice(n.offset,n.offset+c));"little"===i&&u.reverse(),n.offset+=c;let l=[...u].map((t=>t.toString(2).padStart(8,"0"))).join("");const p=Object.fromEntries(a.map((([t,e])=>{const r=Number.parseInt(l.slice(0,e.size),2);if(l=l.slice(e.size),t.startsWith("__BINPAT_OMIT_"))return null;let n=r;return"i"===e.type&&(n=r<1<<e.size-1?r:r-(1<<e.size)),"bool"===e.type&&(n=!!r),[t,n]})).filter((t=>null!==t)));return Object.fromEntries(Object.keys(t).filter((t=>!t.startsWith("__BINPAT_OMIT_"))).map((t=>[t,p[t]])))}return r[BINPAT_TYPE]="bitfield",r}bitfield.u=function(t){return{type:"u",size:t}},bitfield.i=function(t){return{type:"i",size:t}},bitfield.bool=function(){return{type:"bool",size:1}};export function ternary(t,e,r){function n(n,i){const o=t(i)?e:r;if(void 0!==o)return exec(n,o,i)}return n[BINPAT_TYPE]="ternary",n}export function convert(t,e){function r(r,n){const i=exec(r,t,n);return e(i,n)}return r[BINPAT_TYPE]="convert",r}export function seek(t){function e(e,r){r.offset="function"==typeof t?t(r):t}return e[BINPAT_TYPE]="seek",e}export function peek(t,e){function r(r,n){const i=n.offset;n.offset="function"==typeof t?t(n):t;const o=exec(r,e,n);return n.offset=i,o}return r[BINPAT_TYPE]="peek",r}export function skip(t){function e(e,r){r.offset+=t}return e[BINPAT_TYPE]="skip",e}function random(){return Math.random().toString(16).slice(2)}export function omit(t){return`__BINPAT_OMIT_${random()}__`}export function spread(){return`__BINPAT_SPREAD_${random()}__`}