mhtml-stream 0.0.1 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/bundle/mhtml.cjs.min.js +1 -0
- package/bundle/mhtml.esm.min.js +1 -0
- package/bundle/mhtml.iife.min.js +1 -0
- package/dist/headers.d.ts +62 -0
- package/dist/headers.js +55 -0
- package/dist/index.d.ts +12 -68
- package/dist/index.js +11 -116
- package/dist/utils.d.ts +0 -4
- package/dist/utils.js +2 -24
- package/package.json +127 -27
- package/dist/base64.d.ts +0 -8
- package/dist/base64.js +0 -77
- package/dist/index.cjs.min.js +0 -1
- package/dist/index.iife.min.js +0 -1
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@ MHTML Stream
|
|
|
2
2
|
============
|
|
3
3
|
[](https://github.com/erikbrinkman/mhtml-stream/actions/workflows/node.js.yml)
|
|
4
4
|
[](https://erikbrinkman.github.io/mhtml-stream/)
|
|
5
|
+
[](https://www.npmjs.com/package/mhtml-stream)
|
|
6
|
+
[](LICENSE)
|
|
5
7
|
|
|
6
8
|
Zero-dependency library for parsing MHTML data as streams using modern WHATWG
|
|
7
9
|
streams and async iterators. Because it relies on modern cross javascript
|
|
@@ -25,3 +27,11 @@ for await (const { headers, content } of parseMhtml(...)) {
|
|
|
25
27
|
// for how to parse each individual included file.
|
|
26
28
|
}
|
|
27
29
|
```
|
|
30
|
+
|
|
31
|
+
Notes
|
|
32
|
+
-----
|
|
33
|
+
|
|
34
|
+
- As far as I can tell, header folding behavior is not well defined when it
|
|
35
|
+
comes to whether whitespace should be added when unfolding. This currently
|
|
36
|
+
uses the first whitespace character to indicate folding, and preservers any
|
|
37
|
+
others.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var j=Object.create;var h=Object.defineProperty;var Q=Object.getOwnPropertyDescriptor;var W=Object.getOwnPropertyNames;var N=Object.getPrototypeOf,J=Object.prototype.hasOwnProperty;var R=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports),V=(t,e)=>{for(var r in e)h(t,r,{get:e[r],enumerable:!0})},x=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of W(e))!J.call(t,o)&&o!==r&&h(t,o,{get:()=>e[o],enumerable:!(n=Q(e,o))||n.enumerable});return t};var U=(t,e,r)=>(r=t!=null?j(N(t)):{},x(e||!t||!t.__esModule?h(r,"default",{value:t,enumerable:!0}):r,t)),_=t=>x(h({},"__esModule",{value:!0}),t);var w=R(g=>{"use strict";g.byteLength=G;g.toByteArray=X;g.fromByteArray=ee;var c=[],d=[],z=typeof Uint8Array<"u"?Uint8Array:Array,b="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";for(f=0,F=b.length;f<F;++f)c[f]=b[f],d[b.charCodeAt(f)]=f;var f,F;d["-".charCodeAt(0)]=62;d["_".charCodeAt(0)]=63;function B(t){var e=t.length;if(e%4>0)throw new Error("Invalid string. Length must be a multiple of 4");var r=t.indexOf("=");r===-1&&(r=e);var n=r===e?0:4-r%4;return[r,n]}function G(t){var e=B(t),r=e[0],n=e[1];return(r+n)*3/4-n}function K(t,e,r){return(e+r)*3/4-r}function X(t){var e,r=B(t),n=r[0],o=r[1],a=new z(K(t,n,o)),s=0,i=o>0?n-4:n,l;for(l=0;l<i;l+=4)e=d[t.charCodeAt(l)]<<18|d[t.charCodeAt(l+1)]<<12|d[t.charCodeAt(l+2)]<<6|d[t.charCodeAt(l+3)],a[s++]=e>>16&255,a[s++]=e>>8&255,a[s++]=e&255;return o===2&&(e=d[t.charCodeAt(l)]<<2|d[t.charCodeAt(l+1)]>>4,a[s++]=e&255),o===1&&(e=d[t.charCodeAt(l)]<<10|d[t.charCodeAt(l+1)]<<4|d[t.charCodeAt(l+2)]>>2,a[s++]=e>>8&255,a[s++]=e&255),a}function Y(t){return c[t>>18&63]+c[t>>12&63]+c[t>>6&63]+c[t&63]}function Z(t,e,r){for(var n,o=[],a=e;a<r;a+=3)n=(t[a]<<16&16711680)+(t[a+1]<<8&65280)+(t[a+2]&255),o.push(Y(n));return o.join("")}function ee(t){for(var e,r=t.length,n=r%3,o=[],a=16383,s=0,i=r-n;s<i;s+=a)o.push(Z(t,s,s+a>i?i:s+a));return n===1?(e=t[r-1],o.push(c[e>>2]+c[e<<4&63]+"==")):n===2&&(e=(t[r-2]<<8)+t[r-1],o.push(c[e>>10]+c[e>>4&63]+c[e<<2&63]+"=")),o.join("")}});var fe={};V(fe,{parseMhtml:()=>ce});module.exports=_(fe);var q=U(w());var p=class{#e=new Map;[Symbol.iterator](){return this.entries()}append(e,r){let n=this.#e.get(e);n===void 0?this.#e.set(e,[r]):n.push(r)}*entries(e=", "){for(let[r,n]of this.#e.entries())yield[r,n.join(e)]}*entriesAll(){for(let[e,r]of this.#e.entries())for(let n of r)yield[e,n]}get(e,r=", "){let n=this.#e.get(e);return n===void 0?null:n.join(r)}getAll(e){return this.#e.get(e)??[]}has(e){return this.#e.has(e)}keys(){return this.#e.keys()}*values(e=", "){for(let r of this.#e.values())yield r.join(e)}*valuesAll(){for(let e of this.#e.values())yield*e}};var C=U(w());function te(t){return ArrayBuffer.isView(t)?new Uint8Array(t.buffer,t.byteOffset,t.byteLength):new Uint8Array(t)}function v(t,e){if(t.length!==e.length)return!1;if(t.byteOffset%4===e.byteOffset%4){let r=(4-t.byteOffset%4)%4,n=Math.floor((t.byteLength-r)/4),o=r+n*4,a=new Uint32Array(t.buffer,t.byteOffset+r,n),s=new Uint32Array(e.buffer,e.byteOffset+r,n);for(let i=0;i<r;++i)if(t[i]!==e[i])return!1;for(let i=0;i<n;++i)if(a[i]!==s[i])return!1;for(let i=o;i<t.length;++i)if(t[i]!==e[i])return!1;return!0}else{for(let r of t.keys())if(t[r]!==e[r])return!1;return!0}}function re(t,e){return t.findIndex((r,n)=>{if(r!==e[0]||n+e.length>t.length)return!1;for(let o=1;o<e.length;++o)if(t[n+o]!==e[o])return!1;return!0})}async function*k(t,e){let r=new Uint8Array(0);for await(let n of t){let o=te(n);r=r.length?E([r,o]):o;let a;for(;(a=re(r,e))!==-1;)yield r.subarray(0,a),r=r.subarray(a+e.length)}yield r}function E(t){let e=t.reduce((o,a)=>o+a.length,0),r=new Uint8Array(e),n=0;for(let o of t)r.set(o,n),n+=o.length;return r}async function M(t){let e=[];for await(let r of t)e.push(r);return E(e)}var ne=new Uint8Array([10]);async function*L(t,e=ne){for await(let r of t){let n=new Uint8Array(r.length+e.length),o=!1,a=0;for(let s=0;s<r.length;++s){let i=r[s];if(i>=128)throw new Error(`got non-ascii character when decoding quoted printable: ${r}`);if(i!==61)n[a++]=i;else{let l=r[++s];if(l===void 0)o=!0;else{let u=r[++s];if(u===void 0)throw new Error("quoted printable escape (=) was not followed by two bytes");let y=parseInt(String.fromCharCode(l),16);y*=16,y+=parseInt(String.fromCharCode(u),16),n[a++]=y}}}o||(n.set(e,a),a+=e.length),yield n.subarray(0,a)}}var oe=new TextDecoder;async function*O(t){for await(let e of t)yield(0,C.toByteArray)(oe.decode(e))}async function*m(t){for await(let e of t)yield e}function H(){throw new Error("binary transfer-encoding is explicitly not supported and trying to add an implementation will likely result in unexpected results, but if you want to ignore anyway, set binary to `decode8bit`")}var $=new TextEncoder,D=new TextDecoder;function ae(t){let e=new Uint8Array(t.length),r=0;for(let n=0;n<t.length;++n){let o=t.charCodeAt(n),a;if(o>=128)throw new Error(`got non-ascii character when decoding q-quoted word: "${t}"`);o===95?a=32:o===61?(a=parseInt(t[++n],16),a*=16,a+=parseInt(t[++n],16)):a=o,e[r++]=a}return e.subarray(0,r)}var se=/^=\?([^?\s]+)\?([BQ])\?([^?\s]+)\?=$/;function T(t){let e=se.exec(t);if(e){let[,r,n,o]=e,a;if(n==="Q")a=ae(o);else if(n==="B")a=(0,q.toByteArray)(o);else throw new Error(`unknown encoding for header value encoding: ${n}`);return new TextDecoder(r).decode(a)}else return t}async function ie(t){let e=new p,r="",n="";for(;;){let{done:o,value:a}=await t.next();if(o)throw new Error("didn't find an empty line to signify the end of header parsing");let s=D.decode(a);if(/^\s/.test(s))n+=T(s.substr(1));else if(r&&e.append(r,n),s){let i=s.indexOf(": ");if(i===-1)throw new Error(`header line didn't have key-value delimiter: "${s}"`);r=s.slice(0,i),n=T(s.slice(i+2))}else return e}}var le=new Map([["7bit",m],["base64",O],["quoted-printable",L],["8bit",m],["binary",H]]);function de(t){let e=t.get("Content-Type");if(e===null)throw new Error(`first headers didn't contain a content type: ${JSON.stringify(Object.fromEntries(t))}`);let r,n=!1;for(let s of e.split(/;\s*/))s.startsWith("multipart/")?n=!0:s.startsWith("boundary=")&&(r=s.slice(9),r.startsWith('"')&&r.endsWith('"')&&(r=r.slice(1,-1)));if(!n||r===void 0)throw new Error("first content type header didn't contain 'multipart/...' and a boundary string");let o=$.encode(`--${r}`),a=$.encode(`--${r}--`);return[o,a]}async function*ce(t,{decoderOverrides:e=new Map}={}){let r=new Map([...le.entries(),...e.entries()]),n=new Uint8Array([13,10]),o=k(t,n),a=null,s=!0;for(;s;){let i=await ie(o),[l,u]=a??(a=de(i)),y=i.get("Content-Transfer-Encoding")??"7bit",I=r.get(y);if(I===void 0)throw new Error(`unhandled encoding type: ${y}`);let P=await M(I({[Symbol.asyncIterator](){return{async next(){let{done:S,value:A}=await o.next();if(S)throw new Error(`stream didn't end with the appropriate termination boundary: ${D.decode(u)}`);return v(A,l)?{done:!0,value:void 0}:v(A,u)?(s=!1,{done:!0,value:void 0}):{value:A}}}}}));yield{headers:i,content:P}}}0&&(module.exports={parseMhtml});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var S=Object.create;var I=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var Q=Object.getOwnPropertyNames;var W=Object.getPrototypeOf,N=Object.prototype.hasOwnProperty;var J=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var R=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of Q(e))!N.call(t,o)&&o!==r&&I(t,o,{get:()=>e[o],enumerable:!(n=j(e,o))||n.enumerable});return t};var x=(t,e,r)=>(r=t!=null?S(W(t)):{},R(e||!t||!t.__esModule?I(r,"default",{value:t,enumerable:!0}):r,t));var b=J(h=>{"use strict";h.byteLength=_;h.toByteArray=G;h.fromByteArray=Y;var c=[],d=[],V=typeof Uint8Array<"u"?Uint8Array:Array,A="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";for(f=0,U=A.length;f<U;++f)c[f]=A[f],d[A.charCodeAt(f)]=f;var f,U;d["-".charCodeAt(0)]=62;d["_".charCodeAt(0)]=63;function F(t){var e=t.length;if(e%4>0)throw new Error("Invalid string. Length must be a multiple of 4");var r=t.indexOf("=");r===-1&&(r=e);var n=r===e?0:4-r%4;return[r,n]}function _(t){var e=F(t),r=e[0],n=e[1];return(r+n)*3/4-n}function z(t,e,r){return(e+r)*3/4-r}function G(t){var e,r=F(t),n=r[0],o=r[1],a=new V(z(t,n,o)),s=0,i=o>0?n-4:n,l;for(l=0;l<i;l+=4)e=d[t.charCodeAt(l)]<<18|d[t.charCodeAt(l+1)]<<12|d[t.charCodeAt(l+2)]<<6|d[t.charCodeAt(l+3)],a[s++]=e>>16&255,a[s++]=e>>8&255,a[s++]=e&255;return o===2&&(e=d[t.charCodeAt(l)]<<2|d[t.charCodeAt(l+1)]>>4,a[s++]=e&255),o===1&&(e=d[t.charCodeAt(l)]<<10|d[t.charCodeAt(l+1)]<<4|d[t.charCodeAt(l+2)]>>2,a[s++]=e>>8&255,a[s++]=e&255),a}function K(t){return c[t>>18&63]+c[t>>12&63]+c[t>>6&63]+c[t&63]}function X(t,e,r){for(var n,o=[],a=e;a<r;a+=3)n=(t[a]<<16&16711680)+(t[a+1]<<8&65280)+(t[a+2]&255),o.push(K(n));return o.join("")}function Y(t){for(var e,r=t.length,n=r%3,o=[],a=16383,s=0,i=r-n;s<i;s+=a)o.push(X(t,s,s+a>i?i:s+a));return n===1?(e=t[r-1],o.push(c[e>>2]+c[e<<4&63]+"==")):n===2&&(e=(t[r-2]<<8)+t[r-1],o.push(c[e>>10]+c[e>>4&63]+c[e<<2&63]+"=")),o.join("")}});var T=x(b());var g=class{#e=new Map;[Symbol.iterator](){return this.entries()}append(e,r){let n=this.#e.get(e);n===void 0?this.#e.set(e,[r]):n.push(r)}*entries(e=", "){for(let[r,n]of this.#e.entries())yield[r,n.join(e)]}*entriesAll(){for(let[e,r]of this.#e.entries())for(let n of r)yield[e,n]}get(e,r=", "){let n=this.#e.get(e);return n===void 0?null:n.join(r)}getAll(e){return this.#e.get(e)??[]}has(e){return this.#e.has(e)}keys(){return this.#e.keys()}*values(e=", "){for(let r of this.#e.values())yield r.join(e)}*valuesAll(){for(let e of this.#e.values())yield*e}};var B=x(b());function Z(t){return ArrayBuffer.isView(t)?new Uint8Array(t.buffer,t.byteOffset,t.byteLength):new Uint8Array(t)}function w(t,e){if(t.length!==e.length)return!1;if(t.byteOffset%4===e.byteOffset%4){let r=(4-t.byteOffset%4)%4,n=Math.floor((t.byteLength-r)/4),o=r+n*4,a=new Uint32Array(t.buffer,t.byteOffset+r,n),s=new Uint32Array(e.buffer,e.byteOffset+r,n);for(let i=0;i<r;++i)if(t[i]!==e[i])return!1;for(let i=0;i<n;++i)if(a[i]!==s[i])return!1;for(let i=o;i<t.length;++i)if(t[i]!==e[i])return!1;return!0}else{for(let r of t.keys())if(t[r]!==e[r])return!1;return!0}}function ee(t,e){return t.findIndex((r,n)=>{if(r!==e[0]||n+e.length>t.length)return!1;for(let o=1;o<e.length;++o)if(t[n+o]!==e[o])return!1;return!0})}async function*C(t,e){let r=new Uint8Array(0);for await(let n of t){let o=Z(n);r=r.length?k([r,o]):o;let a;for(;(a=ee(r,e))!==-1;)yield r.subarray(0,a),r=r.subarray(a+e.length)}yield r}function k(t){let e=t.reduce((o,a)=>o+a.length,0),r=new Uint8Array(e),n=0;for(let o of t)r.set(o,n),n+=o.length;return r}async function E(t){let e=[];for await(let r of t)e.push(r);return k(e)}var te=new Uint8Array([10]);async function*M(t,e=te){for await(let r of t){let n=new Uint8Array(r.length+e.length),o=!1,a=0;for(let s=0;s<r.length;++s){let i=r[s];if(i>=128)throw new Error(`got non-ascii character when decoding quoted printable: ${r}`);if(i!==61)n[a++]=i;else{let l=r[++s];if(l===void 0)o=!0;else{let u=r[++s];if(u===void 0)throw new Error("quoted printable escape (=) was not followed by two bytes");let y=parseInt(String.fromCharCode(l),16);y*=16,y+=parseInt(String.fromCharCode(u),16),n[a++]=y}}}o||(n.set(e,a),a+=e.length),yield n.subarray(0,a)}}var re=new TextDecoder;async function*L(t){for await(let e of t)yield(0,B.toByteArray)(re.decode(e))}async function*v(t){for await(let e of t)yield e}function O(){throw new Error("binary transfer-encoding is explicitly not supported and trying to add an implementation will likely result in unexpected results, but if you want to ignore anyway, set binary to `decode8bit`")}var H=new TextEncoder,q=new TextDecoder;function ne(t){let e=new Uint8Array(t.length),r=0;for(let n=0;n<t.length;++n){let o=t.charCodeAt(n),a;if(o>=128)throw new Error(`got non-ascii character when decoding q-quoted word: "${t}"`);o===95?a=32:o===61?(a=parseInt(t[++n],16),a*=16,a+=parseInt(t[++n],16)):a=o,e[r++]=a}return e.subarray(0,r)}var oe=/^=\?([^?\s]+)\?([BQ])\?([^?\s]+)\?=$/;function $(t){let e=oe.exec(t);if(e){let[,r,n,o]=e,a;if(n==="Q")a=ne(o);else if(n==="B")a=(0,T.toByteArray)(o);else throw new Error(`unknown encoding for header value encoding: ${n}`);return new TextDecoder(r).decode(a)}else return t}async function ae(t){let e=new g,r="",n="";for(;;){let{done:o,value:a}=await t.next();if(o)throw new Error("didn't find an empty line to signify the end of header parsing");let s=q.decode(a);if(/^\s/.test(s))n+=$(s.substr(1));else if(r&&e.append(r,n),s){let i=s.indexOf(": ");if(i===-1)throw new Error(`header line didn't have key-value delimiter: "${s}"`);r=s.slice(0,i),n=$(s.slice(i+2))}else return e}}var se=new Map([["7bit",v],["base64",L],["quoted-printable",M],["8bit",v],["binary",O]]);function ie(t){let e=t.get("Content-Type");if(e===null)throw new Error(`first headers didn't contain a content type: ${JSON.stringify(Object.fromEntries(t))}`);let r,n=!1;for(let s of e.split(/;\s*/))s.startsWith("multipart/")?n=!0:s.startsWith("boundary=")&&(r=s.slice(9),r.startsWith('"')&&r.endsWith('"')&&(r=r.slice(1,-1)));if(!n||r===void 0)throw new Error("first content type header didn't contain 'multipart/...' and a boundary string");let o=H.encode(`--${r}`),a=H.encode(`--${r}--`);return[o,a]}async function*ge(t,{decoderOverrides:e=new Map}={}){let r=new Map([...se.entries(),...e.entries()]),n=new Uint8Array([13,10]),o=C(t,n),a=null,s=!0;for(;s;){let i=await ae(o),[l,u]=a??(a=ie(i)),y=i.get("Content-Transfer-Encoding")??"7bit",m=r.get(y);if(m===void 0)throw new Error(`unhandled encoding type: ${y}`);let D=await E(m({[Symbol.asyncIterator](){return{async next(){let{done:P,value:p}=await o.next();if(P)throw new Error(`stream didn't end with the appropriate termination boundary: ${q.decode(u)}`);return w(p,l)?{done:!0,value:void 0}:w(p,u)?(s=!1,{done:!0,value:void 0}):{value:p}}}}}));yield{headers:i,content:D}}}export{ge as parseMhtml};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var mhtml=(()=>{var j=Object.create;var h=Object.defineProperty;var Q=Object.getOwnPropertyDescriptor;var W=Object.getOwnPropertyNames;var N=Object.getPrototypeOf,J=Object.prototype.hasOwnProperty;var R=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports),V=(t,e)=>{for(var r in e)h(t,r,{get:e[r],enumerable:!0})},x=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of W(e))!J.call(t,o)&&o!==r&&h(t,o,{get:()=>e[o],enumerable:!(n=Q(e,o))||n.enumerable});return t};var U=(t,e,r)=>(r=t!=null?j(N(t)):{},x(e||!t||!t.__esModule?h(r,"default",{value:t,enumerable:!0}):r,t)),_=t=>x(h({},"__esModule",{value:!0}),t);var w=R(g=>{"use strict";g.byteLength=G;g.toByteArray=X;g.fromByteArray=ee;var c=[],d=[],z=typeof Uint8Array<"u"?Uint8Array:Array,b="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";for(f=0,F=b.length;f<F;++f)c[f]=b[f],d[b.charCodeAt(f)]=f;var f,F;d["-".charCodeAt(0)]=62;d["_".charCodeAt(0)]=63;function B(t){var e=t.length;if(e%4>0)throw new Error("Invalid string. Length must be a multiple of 4");var r=t.indexOf("=");r===-1&&(r=e);var n=r===e?0:4-r%4;return[r,n]}function G(t){var e=B(t),r=e[0],n=e[1];return(r+n)*3/4-n}function K(t,e,r){return(e+r)*3/4-r}function X(t){var e,r=B(t),n=r[0],o=r[1],a=new z(K(t,n,o)),s=0,i=o>0?n-4:n,l;for(l=0;l<i;l+=4)e=d[t.charCodeAt(l)]<<18|d[t.charCodeAt(l+1)]<<12|d[t.charCodeAt(l+2)]<<6|d[t.charCodeAt(l+3)],a[s++]=e>>16&255,a[s++]=e>>8&255,a[s++]=e&255;return o===2&&(e=d[t.charCodeAt(l)]<<2|d[t.charCodeAt(l+1)]>>4,a[s++]=e&255),o===1&&(e=d[t.charCodeAt(l)]<<10|d[t.charCodeAt(l+1)]<<4|d[t.charCodeAt(l+2)]>>2,a[s++]=e>>8&255,a[s++]=e&255),a}function Y(t){return c[t>>18&63]+c[t>>12&63]+c[t>>6&63]+c[t&63]}function Z(t,e,r){for(var n,o=[],a=e;a<r;a+=3)n=(t[a]<<16&16711680)+(t[a+1]<<8&65280)+(t[a+2]&255),o.push(Y(n));return o.join("")}function ee(t){for(var e,r=t.length,n=r%3,o=[],a=16383,s=0,i=r-n;s<i;s+=a)o.push(Z(t,s,s+a>i?i:s+a));return n===1?(e=t[r-1],o.push(c[e>>2]+c[e<<4&63]+"==")):n===2&&(e=(t[r-2]<<8)+t[r-1],o.push(c[e>>10]+c[e>>4&63]+c[e<<2&63]+"=")),o.join("")}});var fe={};V(fe,{parseMhtml:()=>ce});var q=U(w());var p=class{#e=new Map;[Symbol.iterator](){return this.entries()}append(e,r){let n=this.#e.get(e);n===void 0?this.#e.set(e,[r]):n.push(r)}*entries(e=", "){for(let[r,n]of this.#e.entries())yield[r,n.join(e)]}*entriesAll(){for(let[e,r]of this.#e.entries())for(let n of r)yield[e,n]}get(e,r=", "){let n=this.#e.get(e);return n===void 0?null:n.join(r)}getAll(e){return this.#e.get(e)??[]}has(e){return this.#e.has(e)}keys(){return this.#e.keys()}*values(e=", "){for(let r of this.#e.values())yield r.join(e)}*valuesAll(){for(let e of this.#e.values())yield*e}};var C=U(w());function te(t){return ArrayBuffer.isView(t)?new Uint8Array(t.buffer,t.byteOffset,t.byteLength):new Uint8Array(t)}function v(t,e){if(t.length!==e.length)return!1;if(t.byteOffset%4===e.byteOffset%4){let r=(4-t.byteOffset%4)%4,n=Math.floor((t.byteLength-r)/4),o=r+n*4,a=new Uint32Array(t.buffer,t.byteOffset+r,n),s=new Uint32Array(e.buffer,e.byteOffset+r,n);for(let i=0;i<r;++i)if(t[i]!==e[i])return!1;for(let i=0;i<n;++i)if(a[i]!==s[i])return!1;for(let i=o;i<t.length;++i)if(t[i]!==e[i])return!1;return!0}else{for(let r of t.keys())if(t[r]!==e[r])return!1;return!0}}function re(t,e){return t.findIndex((r,n)=>{if(r!==e[0]||n+e.length>t.length)return!1;for(let o=1;o<e.length;++o)if(t[n+o]!==e[o])return!1;return!0})}async function*k(t,e){let r=new Uint8Array(0);for await(let n of t){let o=te(n);r=r.length?E([r,o]):o;let a;for(;(a=re(r,e))!==-1;)yield r.subarray(0,a),r=r.subarray(a+e.length)}yield r}function E(t){let e=t.reduce((o,a)=>o+a.length,0),r=new Uint8Array(e),n=0;for(let o of t)r.set(o,n),n+=o.length;return r}async function M(t){let e=[];for await(let r of t)e.push(r);return E(e)}var ne=new Uint8Array([10]);async function*L(t,e=ne){for await(let r of t){let n=new Uint8Array(r.length+e.length),o=!1,a=0;for(let s=0;s<r.length;++s){let i=r[s];if(i>=128)throw new Error(`got non-ascii character when decoding quoted printable: ${r}`);if(i!==61)n[a++]=i;else{let l=r[++s];if(l===void 0)o=!0;else{let u=r[++s];if(u===void 0)throw new Error("quoted printable escape (=) was not followed by two bytes");let y=parseInt(String.fromCharCode(l),16);y*=16,y+=parseInt(String.fromCharCode(u),16),n[a++]=y}}}o||(n.set(e,a),a+=e.length),yield n.subarray(0,a)}}var oe=new TextDecoder;async function*O(t){for await(let e of t)yield(0,C.toByteArray)(oe.decode(e))}async function*m(t){for await(let e of t)yield e}function H(){throw new Error("binary transfer-encoding is explicitly not supported and trying to add an implementation will likely result in unexpected results, but if you want to ignore anyway, set binary to `decode8bit`")}var $=new TextEncoder,D=new TextDecoder;function ae(t){let e=new Uint8Array(t.length),r=0;for(let n=0;n<t.length;++n){let o=t.charCodeAt(n),a;if(o>=128)throw new Error(`got non-ascii character when decoding q-quoted word: "${t}"`);o===95?a=32:o===61?(a=parseInt(t[++n],16),a*=16,a+=parseInt(t[++n],16)):a=o,e[r++]=a}return e.subarray(0,r)}var se=/^=\?([^?\s]+)\?([BQ])\?([^?\s]+)\?=$/;function T(t){let e=se.exec(t);if(e){let[,r,n,o]=e,a;if(n==="Q")a=ae(o);else if(n==="B")a=(0,q.toByteArray)(o);else throw new Error(`unknown encoding for header value encoding: ${n}`);return new TextDecoder(r).decode(a)}else return t}async function ie(t){let e=new p,r="",n="";for(;;){let{done:o,value:a}=await t.next();if(o)throw new Error("didn't find an empty line to signify the end of header parsing");let s=D.decode(a);if(/^\s/.test(s))n+=T(s.substr(1));else if(r&&e.append(r,n),s){let i=s.indexOf(": ");if(i===-1)throw new Error(`header line didn't have key-value delimiter: "${s}"`);r=s.slice(0,i),n=T(s.slice(i+2))}else return e}}var le=new Map([["7bit",m],["base64",O],["quoted-printable",L],["8bit",m],["binary",H]]);function de(t){let e=t.get("Content-Type");if(e===null)throw new Error(`first headers didn't contain a content type: ${JSON.stringify(Object.fromEntries(t))}`);let r,n=!1;for(let s of e.split(/;\s*/))s.startsWith("multipart/")?n=!0:s.startsWith("boundary=")&&(r=s.slice(9),r.startsWith('"')&&r.endsWith('"')&&(r=r.slice(1,-1)));if(!n||r===void 0)throw new Error("first content type header didn't contain 'multipart/...' and a boundary string");let o=$.encode(`--${r}`),a=$.encode(`--${r}--`);return[o,a]}async function*ce(t,{decoderOverrides:e=new Map}={}){let r=new Map([...le.entries(),...e.entries()]),n=new Uint8Array([13,10]),o=k(t,n),a=null,s=!0;for(;s;){let i=await ie(o),[l,u]=a??(a=de(i)),y=i.get("Content-Transfer-Encoding")??"7bit",I=r.get(y);if(I===void 0)throw new Error(`unhandled encoding type: ${y}`);let P=await M(I({[Symbol.asyncIterator](){return{async next(){let{done:S,value:A}=await o.next();if(S)throw new Error(`stream didn't end with the appropriate termination boundary: ${D.decode(u)}`);return v(A,l)?{done:!0,value:void 0}:v(A,u)?(s=!1,{done:!0,value:void 0}):{value:A}}}}}));yield{headers:i,content:P}}}return _(fe);})();
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* class for storing headers parse from MHTML
|
|
3
|
+
*
|
|
4
|
+
* Tries to somewhat mimic the behavior of the fetch-api Headers object, with
|
|
5
|
+
* some differences, notably that it does no validation.
|
|
6
|
+
*/
|
|
7
|
+
export interface MhtmlHeaders extends Iterable<[string, string]> {
|
|
8
|
+
/**
|
|
9
|
+
* add a key-value pair
|
|
10
|
+
*
|
|
11
|
+
* If key is already present it will be appended.
|
|
12
|
+
*/
|
|
13
|
+
append(key: string, value: string): void;
|
|
14
|
+
/**
|
|
15
|
+
* iterate over all key-value pairs
|
|
16
|
+
*
|
|
17
|
+
* Multiple values for the same key will be joined in the order they were
|
|
18
|
+
* added by `delim`.
|
|
19
|
+
*/
|
|
20
|
+
entries(delim?: string): IterableIterator<[string, string]>;
|
|
21
|
+
/**
|
|
22
|
+
* iterate over all key-value pairs
|
|
23
|
+
*
|
|
24
|
+
* Multiple values for the same key will get iterated in the order they were
|
|
25
|
+
* added.
|
|
26
|
+
*/
|
|
27
|
+
entriesAll(): IterableIterator<[string, string]>;
|
|
28
|
+
/**
|
|
29
|
+
* get the value for a key
|
|
30
|
+
*
|
|
31
|
+
* If the key is missing, null will be returned, if multiple values for the
|
|
32
|
+
* key are present, they will be joined be `delim`.
|
|
33
|
+
*/
|
|
34
|
+
get(key: string, delim?: string): string | null;
|
|
35
|
+
/** get all values for a key */
|
|
36
|
+
getAll(key: string): string[];
|
|
37
|
+
/** whether key has any values associated with it */
|
|
38
|
+
has(key: string): boolean;
|
|
39
|
+
/** all keys with at least one value */
|
|
40
|
+
keys(): Iterable<string>;
|
|
41
|
+
/**
|
|
42
|
+
* iterate over all values
|
|
43
|
+
*
|
|
44
|
+
* If a key has multiple values they will be joined by `delim`.
|
|
45
|
+
*/
|
|
46
|
+
values(delim?: string): IterableIterator<string>;
|
|
47
|
+
/** iterate over all values added */
|
|
48
|
+
valuesAll(): IterableIterator<string>;
|
|
49
|
+
}
|
|
50
|
+
export declare class Headers implements MhtmlHeaders {
|
|
51
|
+
#private;
|
|
52
|
+
[Symbol.iterator](): Iterator<[string, string]>;
|
|
53
|
+
append(key: string, value: string): void;
|
|
54
|
+
entries(delim?: string): IterableIterator<[string, string]>;
|
|
55
|
+
entriesAll(): IterableIterator<[string, string]>;
|
|
56
|
+
get(key: string, delim?: string): string | null;
|
|
57
|
+
getAll(key: string): string[];
|
|
58
|
+
has(key: string): boolean;
|
|
59
|
+
keys(): Iterable<string>;
|
|
60
|
+
values(delim?: string): IterableIterator<string>;
|
|
61
|
+
valuesAll(): IterableIterator<string>;
|
|
62
|
+
}
|
package/dist/headers.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export class Headers {
|
|
2
|
+
#raw = new Map();
|
|
3
|
+
[Symbol.iterator]() {
|
|
4
|
+
return this.entries();
|
|
5
|
+
}
|
|
6
|
+
append(key, value) {
|
|
7
|
+
const list = this.#raw.get(key);
|
|
8
|
+
if (list === undefined) {
|
|
9
|
+
this.#raw.set(key, [value]);
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
list.push(value);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
*entries(delim = ", ") {
|
|
16
|
+
for (const [key, values] of this.#raw.entries()) {
|
|
17
|
+
yield [key, values.join(delim)];
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
*entriesAll() {
|
|
21
|
+
for (const [key, values] of this.#raw.entries()) {
|
|
22
|
+
for (const val of values) {
|
|
23
|
+
yield [key, val];
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
get(key, delim = ", ") {
|
|
28
|
+
const vals = this.#raw.get(key);
|
|
29
|
+
if (vals === undefined) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
return vals.join(delim);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
getAll(key) {
|
|
37
|
+
return this.#raw.get(key) ?? [];
|
|
38
|
+
}
|
|
39
|
+
has(key) {
|
|
40
|
+
return this.#raw.has(key);
|
|
41
|
+
}
|
|
42
|
+
keys() {
|
|
43
|
+
return this.#raw.keys();
|
|
44
|
+
}
|
|
45
|
+
*values(delim = ", ") {
|
|
46
|
+
for (const vals of this.#raw.values()) {
|
|
47
|
+
yield vals.join(delim);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
*valuesAll() {
|
|
51
|
+
for (const vals of this.#raw.values()) {
|
|
52
|
+
yield* vals;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,81 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* Tries to somewhat mimic the behavior of the fetch-api Headers object, with
|
|
5
|
-
* some differences, notably that it does no validation.
|
|
6
|
-
*/
|
|
7
|
-
export declare class MhtmlHeaders {
|
|
8
|
-
#private;
|
|
9
|
-
[Symbol.iterator](): Iterator<[string, string]>;
|
|
10
|
-
/**
|
|
11
|
-
* add a key-value pair
|
|
12
|
-
*
|
|
13
|
-
* If key is already present it will be appended.
|
|
14
|
-
*/
|
|
15
|
-
append(key: string, value: string): void;
|
|
16
|
-
/**
|
|
17
|
-
* iterate over all key-value pairs
|
|
18
|
-
*
|
|
19
|
-
* Multiple values for the same key will be joined in the order they were
|
|
20
|
-
* added by `delim`.
|
|
21
|
-
*/
|
|
22
|
-
entries(delim?: string): IterableIterator<[string, string]>;
|
|
23
|
-
/**
|
|
24
|
-
* iterate over all key-value pairs
|
|
25
|
-
*
|
|
26
|
-
* Multiple values for the same key will get iterated in the order they were
|
|
27
|
-
* added.
|
|
28
|
-
*/
|
|
29
|
-
entriesAll(): IterableIterator<[string, string]>;
|
|
30
|
-
/**
|
|
31
|
-
* get the value for a key
|
|
32
|
-
*
|
|
33
|
-
* If the key is missing, null will be returned, if multiple values for the
|
|
34
|
-
* key are present, they will be joined be `delim`.
|
|
35
|
-
*/
|
|
36
|
-
get(key: string, delim?: string): string | null;
|
|
37
|
-
/**
|
|
38
|
-
* get all values for a key
|
|
39
|
-
*/
|
|
40
|
-
getAll(key: string): string[];
|
|
41
|
-
/**
|
|
42
|
-
* whether key has any values associated with it
|
|
43
|
-
*/
|
|
44
|
-
has(key: string): boolean;
|
|
45
|
-
/**
|
|
46
|
-
* all keys with at least one value
|
|
47
|
-
*/
|
|
48
|
-
keys(): Iterable<string>;
|
|
49
|
-
/**
|
|
50
|
-
* iterate over all values
|
|
51
|
-
*
|
|
52
|
-
* If a key has multiple values they will be joined by `delim`.
|
|
53
|
-
*/
|
|
54
|
-
values(delim?: string): IterableIterator<string>;
|
|
55
|
-
/**
|
|
56
|
-
* iterate over all values added
|
|
57
|
-
*/
|
|
58
|
-
valuesAll(): IterableIterator<string>;
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* a file that was encoded in MHTML format
|
|
62
|
-
*/
|
|
1
|
+
import { MhtmlHeaders } from "./headers";
|
|
2
|
+
export type { MhtmlHeaders };
|
|
3
|
+
/** a file that was encoded in MHTML format */
|
|
63
4
|
export interface MhtmlFile {
|
|
5
|
+
/** the files's headers */
|
|
64
6
|
headers: MhtmlHeaders;
|
|
7
|
+
/** the file's content */
|
|
65
8
|
content: Uint8Array;
|
|
66
9
|
}
|
|
67
|
-
/**
|
|
68
|
-
* The decoder of any Content-Transfer-Encoding
|
|
69
|
-
*/
|
|
10
|
+
/** The decoder of any Content-Transfer-Encoding */
|
|
70
11
|
export interface Decoder {
|
|
71
12
|
(lines: AsyncIterable<Uint8Array>): AsyncIterable<Uint8Array>;
|
|
72
13
|
}
|
|
14
|
+
/** options for mhtml parsing */
|
|
15
|
+
export interface ParseOptions {
|
|
16
|
+
/** custom decoders for other Content-Transfer-Encodings */
|
|
17
|
+
decoderOverrides?: Map<string, Decoder>;
|
|
18
|
+
}
|
|
73
19
|
/**
|
|
74
20
|
* parse a readable stream into an async iterator of MHTML files
|
|
75
21
|
*
|
|
76
22
|
* decoderOverrides can be used to overwrite default encoders or specify your
|
|
77
23
|
* own if a Content-Transfer-Encoding isn't handled properly
|
|
78
24
|
*/
|
|
79
|
-
export declare function parseMhtml(stream:
|
|
80
|
-
decoderOverrides?: Map<string, Decoder>;
|
|
81
|
-
}): AsyncIterableIterator<MhtmlFile>;
|
|
25
|
+
export declare function parseMhtml(stream: AsyncIterable<ArrayBuffer>, { decoderOverrides }?: ParseOptions): AsyncIterableIterator<MhtmlFile>;
|
package/dist/index.js
CHANGED
|
@@ -1,113 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { toByteArray } from "base64-js";
|
|
2
|
+
import { Headers } from "./headers";
|
|
3
|
+
import { bytesEqual, collect, decodeBase64, decodeBinary, decodeIdentity, decodeQuotedPrintable, splitStream, } from "./utils";
|
|
3
4
|
// NOTE we use this for ascii because it's faster than manual, but may cause
|
|
4
5
|
// unexpected errors if the assumption is violated
|
|
5
6
|
const encoder = new TextEncoder();
|
|
6
7
|
const decoder = new TextDecoder();
|
|
7
|
-
/**
|
|
8
|
-
* class for storing headers parse from MHTML
|
|
9
|
-
*
|
|
10
|
-
* Tries to somewhat mimic the behavior of the fetch-api Headers object, with
|
|
11
|
-
* some differences, notably that it does no validation.
|
|
12
|
-
*/
|
|
13
|
-
export class MhtmlHeaders {
|
|
14
|
-
#raw = new Map();
|
|
15
|
-
[Symbol.iterator]() {
|
|
16
|
-
return this.entries();
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* add a key-value pair
|
|
20
|
-
*
|
|
21
|
-
* If key is already present it will be appended.
|
|
22
|
-
*/
|
|
23
|
-
append(key, value) {
|
|
24
|
-
const list = this.#raw.get(key);
|
|
25
|
-
if (list === undefined) {
|
|
26
|
-
this.#raw.set(key, [value]);
|
|
27
|
-
}
|
|
28
|
-
else {
|
|
29
|
-
list.push(value);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* iterate over all key-value pairs
|
|
34
|
-
*
|
|
35
|
-
* Multiple values for the same key will be joined in the order they were
|
|
36
|
-
* added by `delim`.
|
|
37
|
-
*/
|
|
38
|
-
*entries(delim = ", ") {
|
|
39
|
-
for (const [key, values] of this.#raw.entries()) {
|
|
40
|
-
yield [key, values.join(delim)];
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* iterate over all key-value pairs
|
|
45
|
-
*
|
|
46
|
-
* Multiple values for the same key will get iterated in the order they were
|
|
47
|
-
* added.
|
|
48
|
-
*/
|
|
49
|
-
*entriesAll() {
|
|
50
|
-
for (const [key, values] of this.#raw.entries()) {
|
|
51
|
-
for (const val of values) {
|
|
52
|
-
yield [key, val];
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* get the value for a key
|
|
58
|
-
*
|
|
59
|
-
* If the key is missing, null will be returned, if multiple values for the
|
|
60
|
-
* key are present, they will be joined be `delim`.
|
|
61
|
-
*/
|
|
62
|
-
get(key, delim = ", ") {
|
|
63
|
-
const vals = this.#raw.get(key);
|
|
64
|
-
if (vals === undefined) {
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
|
-
else {
|
|
68
|
-
return vals.join(delim);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* get all values for a key
|
|
73
|
-
*/
|
|
74
|
-
getAll(key) {
|
|
75
|
-
return this.#raw.get(key) ?? [];
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* whether key has any values associated with it
|
|
79
|
-
*/
|
|
80
|
-
has(key) {
|
|
81
|
-
return this.#raw.has(key);
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* all keys with at least one value
|
|
85
|
-
*/
|
|
86
|
-
keys() {
|
|
87
|
-
return this.#raw.keys();
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* iterate over all values
|
|
91
|
-
*
|
|
92
|
-
* If a key has multiple values they will be joined by `delim`.
|
|
93
|
-
*/
|
|
94
|
-
*values(delim = ", ") {
|
|
95
|
-
for (const vals of this.#raw.values()) {
|
|
96
|
-
yield vals.join(delim);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* iterate over all values added
|
|
101
|
-
*/
|
|
102
|
-
*valuesAll() {
|
|
103
|
-
for (const vals of this.#raw.values()) {
|
|
104
|
-
yield* vals;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* decode a q-encoded token
|
|
110
|
-
*/
|
|
8
|
+
/** decode a q-encoded token */
|
|
111
9
|
function decodeQEncoding(text) {
|
|
112
10
|
const res = new Uint8Array(text.length);
|
|
113
11
|
let destInd = 0;
|
|
@@ -136,9 +34,7 @@ function decodeQEncoding(text) {
|
|
|
136
34
|
return res.subarray(0, destInd);
|
|
137
35
|
}
|
|
138
36
|
const encodeFormat = /^=\?([^?\s]+)\?([BQ])\?([^?\s]+)\?=$/;
|
|
139
|
-
/**
|
|
140
|
-
* decode a header line that may have an extra encoding in it
|
|
141
|
-
*/
|
|
37
|
+
/** decode a header line that may have an extra encoding in it */
|
|
142
38
|
function decodeLine(line) {
|
|
143
39
|
// TODO this might make more sense as a function as part of a regex replaceAll
|
|
144
40
|
const match = encodeFormat.exec(line);
|
|
@@ -150,7 +46,7 @@ function decodeLine(line) {
|
|
|
150
46
|
buff = decodeQEncoding(text);
|
|
151
47
|
}
|
|
152
48
|
else if (encoding === "B") {
|
|
153
|
-
buff =
|
|
49
|
+
buff = toByteArray(text);
|
|
154
50
|
}
|
|
155
51
|
else {
|
|
156
52
|
// NOTE should be impossible
|
|
@@ -170,7 +66,7 @@ function decodeLine(line) {
|
|
|
170
66
|
* keys instead of storing multiple
|
|
171
67
|
*/
|
|
172
68
|
async function parseHeaders(iter) {
|
|
173
|
-
const headers = new
|
|
69
|
+
const headers = new Headers();
|
|
174
70
|
let key = "";
|
|
175
71
|
let val = "";
|
|
176
72
|
for (;;) {
|
|
@@ -181,8 +77,7 @@ async function parseHeaders(iter) {
|
|
|
181
77
|
const line = decoder.decode(value);
|
|
182
78
|
if (/^\s/.test(line)) {
|
|
183
79
|
// header folded
|
|
184
|
-
val +=
|
|
185
|
-
val += decodeLine(line.trimStart());
|
|
80
|
+
val += decodeLine(line.substr(1));
|
|
186
81
|
}
|
|
187
82
|
else {
|
|
188
83
|
if (key) {
|
|
@@ -222,7 +117,7 @@ function getBoundary(headers) {
|
|
|
222
117
|
}
|
|
223
118
|
let bound = undefined;
|
|
224
119
|
let multipart = false;
|
|
225
|
-
for (const field of contentType.split(
|
|
120
|
+
for (const field of contentType.split(/;\s*/)) {
|
|
226
121
|
if (field.startsWith("multipart/")) {
|
|
227
122
|
multipart = true;
|
|
228
123
|
}
|
|
@@ -247,14 +142,14 @@ function getBoundary(headers) {
|
|
|
247
142
|
* decoderOverrides can be used to overwrite default encoders or specify your
|
|
248
143
|
* own if a Content-Transfer-Encoding isn't handled properly
|
|
249
144
|
*/
|
|
250
|
-
export async function* parseMhtml(stream, { decoderOverrides = new Map()
|
|
145
|
+
export async function* parseMhtml(stream, { decoderOverrides = new Map() } = {}) {
|
|
251
146
|
// initial setup
|
|
252
147
|
const decoders = new Map([
|
|
253
148
|
...defaultDecoders.entries(),
|
|
254
149
|
...decoderOverrides.entries(),
|
|
255
150
|
]);
|
|
256
151
|
const crlf = new Uint8Array([13, 10]);
|
|
257
|
-
const lines = splitStream(
|
|
152
|
+
const lines = splitStream(stream, crlf);
|
|
258
153
|
let bound = null;
|
|
259
154
|
let cont = true;
|
|
260
155
|
while (cont) {
|
package/dist/utils.d.ts
CHANGED
|
@@ -9,10 +9,6 @@ export declare function toBytes(buff: ArrayBuffer): Uint8Array;
|
|
|
9
9
|
* Compare two byte arrays for equality
|
|
10
10
|
*/
|
|
11
11
|
export declare function bytesEqual(left: Uint8Array, right: Uint8Array): boolean;
|
|
12
|
-
/**
|
|
13
|
-
* convert readable stream to async iterator
|
|
14
|
-
*/
|
|
15
|
-
export declare function asIterable<T extends ArrayBuffer>(stream: ReadableStream<T>): AsyncIterable<T>;
|
|
16
12
|
/**
|
|
17
13
|
* Find index of one byte array in another
|
|
18
14
|
*/
|
package/dist/utils.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*
|
|
8
8
|
* @packageDocumentation
|
|
9
9
|
*/
|
|
10
|
-
import {
|
|
10
|
+
import { toByteArray } from "base64-js";
|
|
11
11
|
/**
|
|
12
12
|
* create a Uint8Array from a buffer
|
|
13
13
|
*
|
|
@@ -63,28 +63,6 @@ export function bytesEqual(left, right) {
|
|
|
63
63
|
return true;
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
|
-
/**
|
|
67
|
-
* convert readable stream to async iterator
|
|
68
|
-
*/
|
|
69
|
-
export function asIterable(stream) {
|
|
70
|
-
return {
|
|
71
|
-
[Symbol.asyncIterator]() {
|
|
72
|
-
const reader = stream.getReader();
|
|
73
|
-
return {
|
|
74
|
-
// NOTE this complexity is for typescript
|
|
75
|
-
async next() {
|
|
76
|
-
const res = await reader.read();
|
|
77
|
-
if (res.done) {
|
|
78
|
-
return { done: true, value: undefined };
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
return { done: false, value: res.value };
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
};
|
|
85
|
-
},
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
66
|
/**
|
|
89
67
|
* Find index of one byte array in another
|
|
90
68
|
*/
|
|
@@ -199,7 +177,7 @@ const decoder = new TextDecoder();
|
|
|
199
177
|
*/
|
|
200
178
|
export async function* decodeBase64(lines) {
|
|
201
179
|
for await (const bytes of lines) {
|
|
202
|
-
yield
|
|
180
|
+
yield toByteArray(decoder.decode(bytes));
|
|
203
181
|
}
|
|
204
182
|
}
|
|
205
183
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mhtml-stream",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "Zero dependency stream MHTML parser",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mhtml",
|
|
@@ -12,41 +12,141 @@
|
|
|
12
12
|
},
|
|
13
13
|
"author": "Erik Brinkman <erik.brinkman@gmail.com>",
|
|
14
14
|
"license": "MIT",
|
|
15
|
-
"module": "dist/index.js",
|
|
16
15
|
"types": "dist/index.d.ts",
|
|
17
|
-
"
|
|
18
|
-
"
|
|
16
|
+
"module": "bundle/mhtml.esm.min.js",
|
|
17
|
+
"main": "bundle/mhtml.cjs.min.js",
|
|
18
|
+
"unpkg": "bundle/mhtml.iife.min.js",
|
|
19
19
|
"files": [
|
|
20
|
+
"/bundle/*.js",
|
|
20
21
|
"/dist/**/*.js",
|
|
21
22
|
"/dist/**/*.d.ts"
|
|
22
23
|
],
|
|
23
24
|
"type": "module",
|
|
24
25
|
"scripts": {
|
|
25
|
-
"fmt": "prettier --write 'src/*.ts' '*.json'",
|
|
26
|
-
"lint": "tsc && eslint 'src/*.ts'",
|
|
26
|
+
"fmt": "prettier --write 'src/*.ts' '*.json' bundle.mjs",
|
|
27
|
+
"lint": "tsc && eslint --cache 'src/*.ts' && typedoc --emit none",
|
|
27
28
|
"test": "jest --coverage",
|
|
28
29
|
"doc": "typedoc",
|
|
29
|
-
"build": "tsc -p tsconfig.build.json &&
|
|
30
|
-
"
|
|
30
|
+
"build": "tsc -p tsconfig.build.json && node bundle.mjs",
|
|
31
|
+
"prepack": "yarn lint && yarn test && yarn build"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"base64-js": "^1.5.1"
|
|
31
35
|
},
|
|
32
36
|
"devDependencies": {
|
|
33
|
-
"@
|
|
34
|
-
"
|
|
35
|
-
"@babel/
|
|
36
|
-
"@
|
|
37
|
-
"@
|
|
38
|
-
"@types/
|
|
39
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
40
|
-
"@typescript-eslint/parser": "^5.
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
37
|
+
"@babel/core": "^7.18.5",
|
|
38
|
+
"@babel/preset-env": "^7.18.2",
|
|
39
|
+
"@babel/preset-typescript": "^7.17.12",
|
|
40
|
+
"@types/base64-js": "^1.3.0",
|
|
41
|
+
"@types/jest": "^28.1.3",
|
|
42
|
+
"@types/node": "^18.0.0",
|
|
43
|
+
"@typescript-eslint/eslint-plugin": "^5.29.0",
|
|
44
|
+
"@typescript-eslint/parser": "^5.29.0",
|
|
45
|
+
"@yarnpkg/esbuild-plugin-pnp": "^3.0.0-rc.9",
|
|
46
|
+
"babel-jest": "^28.1.1",
|
|
47
|
+
"chalk": "5.0.1",
|
|
48
|
+
"esbuild": "^0.14.47",
|
|
49
|
+
"eslint": "^8.18.0",
|
|
50
|
+
"eslint-config-prettier": "^8.5.0",
|
|
51
|
+
"eslint-plugin-jest": "^26.5.3",
|
|
45
52
|
"eslint-plugin-spellcheck": "^0.0.19",
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"prettier
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
+
"eslint-plugin-tsdoc": "^0.2.16",
|
|
54
|
+
"jest": "^28.1.1",
|
|
55
|
+
"prettier": "^2.7.1",
|
|
56
|
+
"prettier-plugin-organize-imports": "^3.0.0",
|
|
57
|
+
"typedoc": "^0.22.17",
|
|
58
|
+
"typescript": "^4.6.4"
|
|
59
|
+
},
|
|
60
|
+
"resolutions": {
|
|
61
|
+
"minimist": "1.2.6"
|
|
62
|
+
},
|
|
63
|
+
"prettier": {
|
|
64
|
+
"plugins": [
|
|
65
|
+
"prettier-plugin-organize-imports"
|
|
66
|
+
]
|
|
67
|
+
},
|
|
68
|
+
"jest": {
|
|
69
|
+
"testEnvironment": "node"
|
|
70
|
+
},
|
|
71
|
+
"babel": {
|
|
72
|
+
"presets": [
|
|
73
|
+
[
|
|
74
|
+
"@babel/preset-env",
|
|
75
|
+
{
|
|
76
|
+
"targets": {
|
|
77
|
+
"node": "current"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
],
|
|
81
|
+
"@babel/preset-typescript"
|
|
82
|
+
]
|
|
83
|
+
},
|
|
84
|
+
"eslintConfig": {
|
|
85
|
+
"root": true,
|
|
86
|
+
"parser": "@typescript-eslint/parser",
|
|
87
|
+
"plugins": [
|
|
88
|
+
"@typescript-eslint",
|
|
89
|
+
"jest",
|
|
90
|
+
"spellcheck",
|
|
91
|
+
"eslint-plugin-tsdoc"
|
|
92
|
+
],
|
|
93
|
+
"extends": [
|
|
94
|
+
"eslint:recommended",
|
|
95
|
+
"plugin:@typescript-eslint/recommended",
|
|
96
|
+
"plugin:jest/recommended",
|
|
97
|
+
"prettier"
|
|
98
|
+
],
|
|
99
|
+
"env": {
|
|
100
|
+
"node": true
|
|
101
|
+
},
|
|
102
|
+
"rules": {
|
|
103
|
+
"@typescript-eslint/no-inferrable-types": "off",
|
|
104
|
+
"@typescript-eslint/no-non-null-assertion": "off",
|
|
105
|
+
"@typescript-eslint/no-unused-vars": [
|
|
106
|
+
"error",
|
|
107
|
+
{
|
|
108
|
+
"varsIgnorePattern": "^_+$"
|
|
109
|
+
}
|
|
110
|
+
],
|
|
111
|
+
"prefer-const": [
|
|
112
|
+
"error",
|
|
113
|
+
{
|
|
114
|
+
"destructuring": "all"
|
|
115
|
+
}
|
|
116
|
+
],
|
|
117
|
+
"no-warning-comments": [
|
|
118
|
+
"error",
|
|
119
|
+
{
|
|
120
|
+
"terms": [
|
|
121
|
+
"fixme"
|
|
122
|
+
],
|
|
123
|
+
"location": "anywhere"
|
|
124
|
+
}
|
|
125
|
+
],
|
|
126
|
+
"spellcheck/spell-checker": [
|
|
127
|
+
"error",
|
|
128
|
+
{
|
|
129
|
+
"identifiers": false,
|
|
130
|
+
"skipIfMatch": [
|
|
131
|
+
"[^\\s]{20,}"
|
|
132
|
+
],
|
|
133
|
+
"skipWords": [
|
|
134
|
+
"0x7fffffff",
|
|
135
|
+
"Chr",
|
|
136
|
+
"Dvalue",
|
|
137
|
+
"Hola",
|
|
138
|
+
"Mhtml",
|
|
139
|
+
"Today’s",
|
|
140
|
+
"Uint",
|
|
141
|
+
"Yorker",
|
|
142
|
+
"ascii",
|
|
143
|
+
"delim",
|
|
144
|
+
"multipart",
|
|
145
|
+
"versa"
|
|
146
|
+
]
|
|
147
|
+
}
|
|
148
|
+
]
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
"packageManager": "yarn@3.2.0"
|
|
152
|
+
}
|
package/dist/base64.d.ts
DELETED
package/dist/base64.js
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
/*\
|
|
2
|
-
|*|
|
|
3
|
-
|*| Base64 / binary data / UTF-8 strings utilities
|
|
4
|
-
|*|
|
|
5
|
-
|*| https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding
|
|
6
|
-
|*|
|
|
7
|
-
\*/
|
|
8
|
-
/* Array of bytes to Base64 string decoding */
|
|
9
|
-
function b64ToUint6(nChr) {
|
|
10
|
-
return nChr > 64 && nChr < 91
|
|
11
|
-
? nChr - 65
|
|
12
|
-
: nChr > 96 && nChr < 123
|
|
13
|
-
? nChr - 71
|
|
14
|
-
: nChr > 47 && nChr < 58
|
|
15
|
-
? nChr + 4
|
|
16
|
-
: nChr === 43
|
|
17
|
-
? 62
|
|
18
|
-
: nChr === 47
|
|
19
|
-
? 63
|
|
20
|
-
: /* istanbul ignore next */
|
|
21
|
-
0;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* decode base 64 string as bytes
|
|
25
|
-
*/
|
|
26
|
-
export function decodeBase64(sBase64, nBlocksSize) {
|
|
27
|
-
const sB64Enc = sBase64.replace(/[^A-Za-z0-9+/]/g, "");
|
|
28
|
-
const nInLen = sB64Enc.length;
|
|
29
|
-
const nOutLen = nBlocksSize
|
|
30
|
-
? Math.ceil(((nInLen * 3 + 1) >> 2) / nBlocksSize) * nBlocksSize
|
|
31
|
-
: (nInLen * 3 + 1) >> 2;
|
|
32
|
-
const taBytes = new Uint8Array(nOutLen);
|
|
33
|
-
for (let nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) {
|
|
34
|
-
const nMod4 = nInIdx & 3;
|
|
35
|
-
nUint24 |= b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << (6 * (3 - nMod4));
|
|
36
|
-
if (nMod4 === 3 || nInLen - nInIdx === 1) {
|
|
37
|
-
for (let nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) {
|
|
38
|
-
taBytes[nOutIdx] = (nUint24 >>> ((16 >>> nMod3) & 24)) & 255;
|
|
39
|
-
}
|
|
40
|
-
nUint24 = 0;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
return taBytes;
|
|
44
|
-
}
|
|
45
|
-
/* Base64 string to array encoding */
|
|
46
|
-
function uint6ToB64(nUint6) {
|
|
47
|
-
return nUint6 < 26
|
|
48
|
-
? nUint6 + 65
|
|
49
|
-
: nUint6 < 52
|
|
50
|
-
? nUint6 + 71
|
|
51
|
-
: nUint6 < 62
|
|
52
|
-
? nUint6 - 4
|
|
53
|
-
: nUint6 === 62
|
|
54
|
-
? 43
|
|
55
|
-
: nUint6 === 63
|
|
56
|
-
? 47
|
|
57
|
-
: /* istanbul ignore next */
|
|
58
|
-
65;
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* encode bytes as base64 string
|
|
62
|
-
*/
|
|
63
|
-
export function encodeBase64(aBytes) {
|
|
64
|
-
const nLen = aBytes.length;
|
|
65
|
-
let nMod3 = 2;
|
|
66
|
-
let sB64Enc = "";
|
|
67
|
-
for (let nUint24 = 0, nIdx = 0; nIdx < nLen; nIdx++) {
|
|
68
|
-
nMod3 = nIdx % 3;
|
|
69
|
-
nUint24 |= aBytes[nIdx] << ((16 >>> nMod3) & 24);
|
|
70
|
-
if (nMod3 === 2 || aBytes.length - nIdx === 1) {
|
|
71
|
-
sB64Enc += String.fromCodePoint(uint6ToB64((nUint24 >>> 18) & 63), uint6ToB64((nUint24 >>> 12) & 63), uint6ToB64((nUint24 >>> 6) & 63), uint6ToB64(nUint24 & 63));
|
|
72
|
-
nUint24 = 0;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return (sB64Enc.substr(0, sB64Enc.length - 2 + nMod3) +
|
|
76
|
-
(nMod3 === 2 ? "" : nMod3 === 1 ? "=" : "=="));
|
|
77
|
-
}
|
package/dist/index.cjs.min.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
var y=Object.defineProperty;var S=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var k=Object.prototype.hasOwnProperty;var q=e=>y(e,"__esModule",{value:!0});var D=(e,t)=>{for(var r in t)y(e,r,{get:t[r],enumerable:!0})},L=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of $(t))!k.call(e,o)&&(r||o!=="default")&&y(e,o,{get:()=>t[o],enumerable:!(n=S(t,o))||n.enumerable});return e};var P=(e=>(t,r)=>e&&e.get(t)||(r=L(q({}),t,1),e&&e.set(t,r),r))(typeof WeakMap!="undefined"?new WeakMap:0);var K={};D(K,{MhtmlHeaders:()=>h,parseMhtml:()=>G});function Q(e){return e>64&&e<91?e-65:e>96&&e<123?e-71:e>47&&e<58?e+4:e===43?62:e===47?63:0}function f(e,t){let r=e.replace(/[^A-Za-z0-9+/]/g,""),n=r.length,o=t?Math.ceil((n*3+1>>2)/t)*t:n*3+1>>2,s=new Uint8Array(o);for(let a=0,i=0,d=0;d<n;d++){let l=d&3;if(a|=Q(r.charCodeAt(d))<<6*(3-l),l===3||n-d===1){for(let c=0;c<3&&i<o;c++,i++)s[i]=a>>>(16>>>c&24)&255;a=0}}return s}function j(e){return ArrayBuffer.isView(e)?new Uint8Array(e.buffer,e.byteOffset,e.byteLength):new Uint8Array(e)}function g(e,t){if(e.length!==t.length)return!1;if(e.byteOffset%4===t.byteOffset%4){let r=(4-e.byteOffset%4)%4,n=Math.floor((e.byteLength-r)/4),o=r+n*4,s=new Uint32Array(e.buffer,e.byteOffset+r,n),a=new Uint32Array(t.buffer,t.byteOffset+r,n);for(let i=0;i<r;++i)if(e[i]!==t[i])return!1;for(let i=0;i<n;++i)if(s[i]!==a[i])return!1;for(let i=o;i<e.length;++i)if(e[i]!==t[i])return!1;return!0}else{for(let r of e.keys())if(e[r]!==t[r])return!1;return!0}}function A(e){return{[Symbol.asyncIterator](){let t=e.getReader();return{async next(){let r=await t.read();return r.done?{done:!0,value:void 0}:{done:!1,value:r.value}}}}}}function H(e,t){return e.findIndex((r,n)=>{if(r!==t[0]||n+t.length>e.length)return!1;for(let o=1;o<t.length;++o)if(e[n+o]!==t[o])return!1;return!0})}async function*p(e,t){let r=new Uint8Array(0);for await(let n of e){let o=j(n);r=r.length?I([r,o]):o;let s;for(;(s=H(r,t))!==-1;)yield r.subarray(0,s),r=r.subarray(s+t.length)}yield r}function I(e){let t=e.reduce((o,s)=>o+s.length,0),r=new Uint8Array(t),n=0;for(let o of e)r.set(o,n),n+=o.length;return r}async function m(e){let t=[];for await(let r of e)t.push(r);return I(t)}var R=new Uint8Array([10]);async function*U(e,t=R){for await(let r of e){let n=new Uint8Array(r.length+t.length),o=!1,s=0;for(let a=0;a<r.length;++a){let i=r[a];if(i>=128)throw new Error(`got non-ascii character when decoding quoted printable: ${r}`);if(i!==61)n[s++]=i;else{let d=r[++a];if(d===void 0)o=!0;else{let l=r[++a];if(l===void 0)throw new Error("quoted printable escape (=) was not followed by two bytes");let c=parseInt(String.fromCharCode(d),16);c*=16,c+=parseInt(String.fromCharCode(l),16),n[s++]=c}}}o||(n.set(t,s),s+=t.length),yield n.subarray(0,s)}}var W=new TextDecoder;async function*x(e){for await(let t of e)yield f(W.decode(t))}async function*b(e){for await(let t of e)yield t}function v(){throw new Error("binary transfer-encoding is explicitly not supported and trying to add an implementation will likely result in unexpected results, but if you want to ignore anyway, set binary to `decode8bit`")}var E=new TextEncoder,M=new TextDecoder,h=class{#e=new Map;[Symbol.iterator](){return this.entries()}append(t,r){let n=this.#e.get(t);n===void 0?this.#e.set(t,[r]):n.push(r)}*entries(t=", "){for(let[r,n]of this.#e.entries())yield[r,n.join(t)]}*entriesAll(){for(let[t,r]of this.#e.entries())for(let n of r)yield[t,n]}get(t,r=", "){let n=this.#e.get(t);return n===void 0?null:n.join(r)}getAll(t){return this.#e.get(t)??[]}has(t){return this.#e.has(t)}keys(){return this.#e.keys()}*values(t=", "){for(let r of this.#e.values())yield r.join(t)}*valuesAll(){for(let t of this.#e.values())yield*t}};function F(e){let t=new Uint8Array(e.length),r=0;for(let n=0;n<e.length;++n){let o=e.charCodeAt(n),s;if(o>=128)throw new Error(`got non-ascii character when decoding q-quoted word: "${e}"`);o===95?s=32:o===61?(s=parseInt(e[++n],16),s*=16,s+=parseInt(e[++n],16)):s=o,t[r++]=s}return t.subarray(0,r)}var N=/^=\?([^?\s]+)\?([BQ])\?([^?\s]+)\?=$/;function B(e){let t=N.exec(e);if(t){let[,r,n,o]=t,s;if(n==="Q")s=F(o);else if(n==="B")s=f(o);else throw new Error(`unknown encoding for header value encoding: ${n}`);return new TextDecoder(r).decode(s)}else return e}async function J(e){let t=new h,r="",n="";for(;;){let{done:o,value:s}=await e.next();if(o)throw new Error("didn't find an empty line to signify the end of header parsing");let a=M.decode(s);if(/^\s/.test(a))n+=" ",n+=B(a.trimStart());else if(r&&t.append(r,n),a){let i=a.indexOf(": ");if(i===-1)throw new Error(`header line didn't have key-value delimiter: "${a}"`);r=a.slice(0,i),n=B(a.slice(i+2))}else return t}}var V=new Map([["7bit",b],["base64",x],["quoted-printable",U],["8bit",b],["binary",v]]);function Z(e){let t=e.get("Content-Type");if(t===null)throw new Error(`first headers didn't contain a content type: ${JSON.stringify(Object.fromEntries(e))}`);let r,n=!1;for(let a of t.split("; "))a.startsWith("multipart/")?n=!0:a.startsWith("boundary=")&&(r=a.slice(9),r.startsWith('"')&&r.endsWith('"')&&(r=r.slice(1,-1)));if(!n||r===void 0)throw new Error("first content type header didn't contain 'multipart/...' and a boundary string");let o=E.encode(`--${r}`),s=E.encode(`--${r}--`);return[o,s]}async function*G(e,{decoderOverrides:t=new Map}={}){let r=new Map([...V.entries(),...t.entries()]),n=new Uint8Array([13,10]),o=p(A(e),n),s=null,a=!0;for(;a;){let i=await J(o),[d,l]=s??(s=Z(i)),c=i.get("Content-Transfer-Encoding")??"7bit",w=r.get(c);if(w===void 0)throw new Error(`unhandled encoding type: ${c}`);let O=await m(w({[Symbol.asyncIterator](){return{async next(){let{done:T,value:u}=await o.next();if(T)throw new Error(`stream didn't end with the appropriate termination boundary: ${M.decode(l)}`);return g(u,d)?{done:!0,value:void 0}:g(u,l)?(a=!1,{done:!0,value:void 0}):{value:u}}}}}));yield{headers:i,content:O}}}module.exports=P(K);
|
package/dist/index.iife.min.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
var mhtmlStream=(()=>{var y=Object.defineProperty;var S=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var k=Object.prototype.hasOwnProperty;var q=e=>y(e,"__esModule",{value:!0});var D=(e,t)=>{for(var r in t)y(e,r,{get:t[r],enumerable:!0})},L=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of $(t))!k.call(e,o)&&(r||o!=="default")&&y(e,o,{get:()=>t[o],enumerable:!(n=S(t,o))||n.enumerable});return e};var P=(e=>(t,r)=>e&&e.get(t)||(r=L(q({}),t,1),e&&e.set(t,r),r))(typeof WeakMap!="undefined"?new WeakMap:0);var K={};D(K,{MhtmlHeaders:()=>h,parseMhtml:()=>G});function Q(e){return e>64&&e<91?e-65:e>96&&e<123?e-71:e>47&&e<58?e+4:e===43?62:e===47?63:0}function f(e,t){let r=e.replace(/[^A-Za-z0-9+/]/g,""),n=r.length,o=t?Math.ceil((n*3+1>>2)/t)*t:n*3+1>>2,s=new Uint8Array(o);for(let a=0,i=0,d=0;d<n;d++){let l=d&3;if(a|=Q(r.charCodeAt(d))<<6*(3-l),l===3||n-d===1){for(let c=0;c<3&&i<o;c++,i++)s[i]=a>>>(16>>>c&24)&255;a=0}}return s}function j(e){return ArrayBuffer.isView(e)?new Uint8Array(e.buffer,e.byteOffset,e.byteLength):new Uint8Array(e)}function g(e,t){if(e.length!==t.length)return!1;if(e.byteOffset%4===t.byteOffset%4){let r=(4-e.byteOffset%4)%4,n=Math.floor((e.byteLength-r)/4),o=r+n*4,s=new Uint32Array(e.buffer,e.byteOffset+r,n),a=new Uint32Array(t.buffer,t.byteOffset+r,n);for(let i=0;i<r;++i)if(e[i]!==t[i])return!1;for(let i=0;i<n;++i)if(s[i]!==a[i])return!1;for(let i=o;i<e.length;++i)if(e[i]!==t[i])return!1;return!0}else{for(let r of e.keys())if(e[r]!==t[r])return!1;return!0}}function A(e){return{[Symbol.asyncIterator](){let t=e.getReader();return{async next(){let r=await t.read();return r.done?{done:!0,value:void 0}:{done:!1,value:r.value}}}}}}function H(e,t){return e.findIndex((r,n)=>{if(r!==t[0]||n+t.length>e.length)return!1;for(let o=1;o<t.length;++o)if(e[n+o]!==t[o])return!1;return!0})}async function*p(e,t){let r=new Uint8Array(0);for await(let n of e){let o=j(n);r=r.length?I([r,o]):o;let s;for(;(s=H(r,t))!==-1;)yield r.subarray(0,s),r=r.subarray(s+t.length)}yield r}function I(e){let t=e.reduce((o,s)=>o+s.length,0),r=new Uint8Array(t),n=0;for(let o of e)r.set(o,n),n+=o.length;return r}async function m(e){let t=[];for await(let r of e)t.push(r);return I(t)}var R=new Uint8Array([10]);async function*U(e,t=R){for await(let r of e){let n=new Uint8Array(r.length+t.length),o=!1,s=0;for(let a=0;a<r.length;++a){let i=r[a];if(i>=128)throw new Error(`got non-ascii character when decoding quoted printable: ${r}`);if(i!==61)n[s++]=i;else{let d=r[++a];if(d===void 0)o=!0;else{let l=r[++a];if(l===void 0)throw new Error("quoted printable escape (=) was not followed by two bytes");let c=parseInt(String.fromCharCode(d),16);c*=16,c+=parseInt(String.fromCharCode(l),16),n[s++]=c}}}o||(n.set(t,s),s+=t.length),yield n.subarray(0,s)}}var W=new TextDecoder;async function*x(e){for await(let t of e)yield f(W.decode(t))}async function*b(e){for await(let t of e)yield t}function v(){throw new Error("binary transfer-encoding is explicitly not supported and trying to add an implementation will likely result in unexpected results, but if you want to ignore anyway, set binary to `decode8bit`")}var E=new TextEncoder,M=new TextDecoder,h=class{#e=new Map;[Symbol.iterator](){return this.entries()}append(t,r){let n=this.#e.get(t);n===void 0?this.#e.set(t,[r]):n.push(r)}*entries(t=", "){for(let[r,n]of this.#e.entries())yield[r,n.join(t)]}*entriesAll(){for(let[t,r]of this.#e.entries())for(let n of r)yield[t,n]}get(t,r=", "){let n=this.#e.get(t);return n===void 0?null:n.join(r)}getAll(t){return this.#e.get(t)??[]}has(t){return this.#e.has(t)}keys(){return this.#e.keys()}*values(t=", "){for(let r of this.#e.values())yield r.join(t)}*valuesAll(){for(let t of this.#e.values())yield*t}};function F(e){let t=new Uint8Array(e.length),r=0;for(let n=0;n<e.length;++n){let o=e.charCodeAt(n),s;if(o>=128)throw new Error(`got non-ascii character when decoding q-quoted word: "${e}"`);o===95?s=32:o===61?(s=parseInt(e[++n],16),s*=16,s+=parseInt(e[++n],16)):s=o,t[r++]=s}return t.subarray(0,r)}var N=/^=\?([^?\s]+)\?([BQ])\?([^?\s]+)\?=$/;function B(e){let t=N.exec(e);if(t){let[,r,n,o]=t,s;if(n==="Q")s=F(o);else if(n==="B")s=f(o);else throw new Error(`unknown encoding for header value encoding: ${n}`);return new TextDecoder(r).decode(s)}else return e}async function J(e){let t=new h,r="",n="";for(;;){let{done:o,value:s}=await e.next();if(o)throw new Error("didn't find an empty line to signify the end of header parsing");let a=M.decode(s);if(/^\s/.test(a))n+=" ",n+=B(a.trimStart());else if(r&&t.append(r,n),a){let i=a.indexOf(": ");if(i===-1)throw new Error(`header line didn't have key-value delimiter: "${a}"`);r=a.slice(0,i),n=B(a.slice(i+2))}else return t}}var V=new Map([["7bit",b],["base64",x],["quoted-printable",U],["8bit",b],["binary",v]]);function Z(e){let t=e.get("Content-Type");if(t===null)throw new Error(`first headers didn't contain a content type: ${JSON.stringify(Object.fromEntries(e))}`);let r,n=!1;for(let a of t.split("; "))a.startsWith("multipart/")?n=!0:a.startsWith("boundary=")&&(r=a.slice(9),r.startsWith('"')&&r.endsWith('"')&&(r=r.slice(1,-1)));if(!n||r===void 0)throw new Error("first content type header didn't contain 'multipart/...' and a boundary string");let o=E.encode(`--${r}`),s=E.encode(`--${r}--`);return[o,s]}async function*G(e,{decoderOverrides:t=new Map}={}){let r=new Map([...V.entries(),...t.entries()]),n=new Uint8Array([13,10]),o=p(A(e),n),s=null,a=!0;for(;a;){let i=await J(o),[d,l]=s??(s=Z(i)),c=i.get("Content-Transfer-Encoding")??"7bit",w=r.get(c);if(w===void 0)throw new Error(`unhandled encoding type: ${c}`);let O=await m(w({[Symbol.asyncIterator](){return{async next(){let{done:T,value:u}=await o.next();if(T)throw new Error(`stream didn't end with the appropriate termination boundary: ${M.decode(l)}`);return g(u,d)?{done:!0,value:void 0}:g(u,l)?(a=!1,{done:!0,value:void 0}):{value:u}}}}}));yield{headers:i,content:O}}}return P(K);})();
|