UNPKG

fast-mhtml-maa

Version:
90 lines (83 loc) 2.47 kB
const { decode } = require('64'); const BufferBuilder = require('buffer-builder'); module.exports = (encoding, body) => { switch (encoding) { case 'base64': return decode(clean(body)); case 'quoted-printable': return convertQuotedPrintable(body); case '8bit': case '7bit': case 'binary': return body; default: throw new Error(`Unknown encoding ${encoding}body: ${body}`); } }; const clean = (body) => { const buffBuild = new BufferBuilder(); let start = 0; for (let i = 0; i < body.length; i++) { for (;i < body.length && body[i] !== CR && body[i] !== LF; i++); const end = i; for (;i < body.length && (body[i] === CR || body[i] === LF); i++); buffBuild.appendBuffer(body.slice(start, end)); start = i; } return buffBuild.get(); }; const EQUALS = '='.charCodeAt(0); const CR = '\r'.charCodeAt(0); const LF = '\n'.charCodeAt(0); const D = 'D'.charCodeAt(0); const THREE = '3'.charCodeAt(0); const translate = (() => { let str = 'switch (c) {\n'; for (let i = 0; i <= 9; i++) str += `\tcase ${'0'.charCodeAt(0) + i}: return ${i};\n`; for (let i = 0xA; i <= 0xF; i++) str += `\tcase ${'A'.charCodeAt(0) + i - 0xA}: return ${i};\n`; str += 'default: return -1;\n'; str += '};\n'; /* eslint-disable no-new-func */ return Function('c', str); })(); function convertQuotedPrintable(body) { const len = body.length; const decoded = Buffer.alloc(len); // at most this big let j = 0; const runTo = len - 3; for (let i = 0; i < runTo; i++) { while (i < runTo && (decoded[j++] = body[i++]) !== EQUALS); if (i >= runTo) break; // We are dealing with a '=xx' sequence. const upper = body[i]; const lower = body[++i]; // fast path for =3D if (upper === THREE && lower === D) { continue; } if (upper === CR && lower === LF) { j--; continue; } if (upper === LF) { // windows chrome does invalid encoding with \n and not \r\n i--; j--; continue; } const upperTranslated = translate(upper); const lowerTranslated = translate(lower); if ((upperTranslated | lowerTranslated) & 128) { // invalid seq decoded[j++] = upper; decoded[j++] = lower; continue; } const shifted = upperTranslated << 4; decoded[j - 1] = shifted | lowerTranslated; } for (let i = runTo; i < len; i++) { decoded[j++] = body[i]; } return decoded.slice(0, j); }