All files decoder.js

100% Statements 52/52
100% Branches 22/22
100% Functions 4/4
100% Lines 45/45

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 7210x   1x 41x   10x   8x       22x   1x       1x 1x 1x 1x 1x   1x 1x 10x 6x 1x 1x   1x       8x 8x 8x 8x 15x 15x   8x 8x     8x 1x   7x 1x 1x   6x   1x 1x 1x   5x 5x 5x   2x 2x 2x   3x 3x   8x    
const decodeBase64 = (data) => Buffer.from(data.toString().replace(/\r|\n/g, ''), 'base64');
 
module.exports = (encoding, body) => {
  switch (encoding) {
    case 'base64':
      return decodeBase64(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 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;
  for (let i = 0; i < len; i++) {
    while (i < len && (decoded[j++] = body[i++]) !== EQUALS);
    if (i >= len) 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;
  }
  return decoded.slice(0, j);
}