binpat
Version:
Parse binary data using declarative patterns.
1 lines • 3.2 kB
JavaScript
const t=Symbol.for("binpat.array");function e(t,n,r){if("function"==typeof n)return n(t,r);if(Array.isArray(n))return n.map(n=>e(t,n,r));if("object"==typeof n){const o={...r,parent:r,data:{}};return Object.entries(n).forEach(([n,r])=>{const i=e(t,r,o);n.startsWith("...")?o.data={...o.data,...i}:n.startsWith("//")||(o.data[n]=i)}),r.offset=o.offset,o.data}return n}export default class n{#t;endian="big";constructor(t,e){this.#t=t,this.endian="little"===e?.endian?"little":"big"}exec(t){const n={endian:this.endian,offset:0,data:{}};return e(new DataView(t),this.#t,n)}}function r(e){return n=>{function r(t,r){const o=n??"little"===r.endian,i=t[`get${e.name.slice(0,-5)}`](r.offset,o);return r.offset+=e.BYTES_PER_ELEMENT,i}return r[t]=e,r}}export const u8=r(Uint8Array);export const u16=r(Uint16Array);export const u32=r(Uint32Array);export const u64=r(BigUint64Array);export const i8=r(Int8Array);export const i16=r(Int16Array);export const i32=r(Int32Array);export const i64=r(BigInt64Array);export const f16=r(Float16Array);export const f32=r(Float32Array);export const f64=r(Float64Array);export function bool(){return function(t,e){const n=!!t.getUint8(e.offset);return e.offset+=1,n}}export function string(t,e="utf-8"){return function(n,r){const o="function"==typeof t?t(r):t,i=new Uint8Array(n.buffer.slice(r.offset,r.offset+o));return r.offset+=o,new TextDecoder(e).decode(i)}}export function array(n,r){return function(o,i){const f="function"==typeof r?r(i):r,s=n[t];if(s){const t=f*s.BYTES_PER_ELEMENT,e=new s(o.buffer.slice(i.offset,i.offset+t));return i.offset+=t,e}return Array.from({length:f}).map(()=>e(o,n,i))}}export function bitfield(t,e={}){return function(n,r){const o=e.endian||r.endian,i=e.first||("big"===o?"MSb":"LSb"),f=Object.entries(t).map(([t,e])=>[t,"number"==typeof e?{type:"u",size:e}:e]),s=f.reduce((t,[,e])=>t+e.size,0),u=Math.ceil(s/8),c=8*u-s;c&&f.push([omit(),{type:"u",size:c}]),"LSb"===i&&f.reverse();const a=new Uint8Array(n.buffer.slice(r.offset,r.offset+u));"little"===o&&a.reverse(),r.offset+=u;let p=[...a].map(t=>t.toString(2).padStart(8,"0")).join("");const l=Object.fromEntries(f.map(([t,e])=>{const n=Number.parseInt(p.slice(0,e.size),2);if(p=p.slice(e.size),t.startsWith("//"))return null;let r=n;return"i"===e.type&&(r=n<1<<e.size-1?n:n-(1<<e.size)),"bool"===e.type&&(r=!!n),[t,r]}).filter(t=>null!==t));return Object.fromEntries(Object.keys(t).filter(t=>!t.startsWith("//")).map(t=>[t,l[t]]))}}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,n,r){return function(o,i){const f=t(i)?n:r;if(void 0!==f)return e(o,f,i)}}export function convert(t,n){return function(r,o){const i=e(r,t,o);return n(i,o)}}export function seek(t){return function(e,n){n.offset="function"==typeof t?t(n):t}}export function peek(t,n){return function(r,o){const i=o.offset;o.offset="function"==typeof t?t(o):t;const f=e(r,n,o);return o.offset=i,f}}export function skip(t){return function(e,n){n.offset+=t}}function o(){return Math.random().toString(16).slice(2)}export function omit(t){return`//${o()}`}export function spread(t){return`...${o()}`}