binary.js (3274B)
1 'use strict'; 2 3 /*eslint-disable no-bitwise*/ 4 5 var NodeBuffer; 6 7 try { 8 // A trick for browserified version, to not include `Buffer` shim 9 var _require = require; 10 NodeBuffer = _require('buffer').Buffer; 11 } catch (__) {} 12 13 var Type = require('../type'); 14 15 16 // [ 64, 65, 66 ] -> [ padding, CR, LF ] 17 var BASE64_MAP = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\r'; 18 19 20 function resolveYamlBinary(data) { 21 if (data === null) return false; 22 23 var code, idx, bitlen = 0, max = data.length, map = BASE64_MAP; 24 25 // Convert one by one. 26 for (idx = 0; idx < max; idx++) { 27 code = map.indexOf(data.charAt(idx)); 28 29 // Skip CR/LF 30 if (code > 64) continue; 31 32 // Fail on illegal characters 33 if (code < 0) return false; 34 35 bitlen += 6; 36 } 37 38 // If there are any bits left, source was corrupted 39 return (bitlen % 8) === 0; 40 } 41 42 function constructYamlBinary(data) { 43 var idx, tailbits, 44 input = data.replace(/[\r\n=]/g, ''), // remove CR/LF & padding to simplify scan 45 max = input.length, 46 map = BASE64_MAP, 47 bits = 0, 48 result = []; 49 50 // Collect by 6*4 bits (3 bytes) 51 52 for (idx = 0; idx < max; idx++) { 53 if ((idx % 4 === 0) && idx) { 54 result.push((bits >> 16) & 0xFF); 55 result.push((bits >> 8) & 0xFF); 56 result.push(bits & 0xFF); 57 } 58 59 bits = (bits << 6) | map.indexOf(input.charAt(idx)); 60 } 61 62 // Dump tail 63 64 tailbits = (max % 4) * 6; 65 66 if (tailbits === 0) { 67 result.push((bits >> 16) & 0xFF); 68 result.push((bits >> 8) & 0xFF); 69 result.push(bits & 0xFF); 70 } else if (tailbits === 18) { 71 result.push((bits >> 10) & 0xFF); 72 result.push((bits >> 2) & 0xFF); 73 } else if (tailbits === 12) { 74 result.push((bits >> 4) & 0xFF); 75 } 76 77 // Wrap into Buffer for NodeJS and leave Array for browser 78 if (NodeBuffer) { 79 // Support node 6.+ Buffer API when available 80 return NodeBuffer.from ? NodeBuffer.from(result) : new NodeBuffer(result); 81 } 82 83 return result; 84 } 85 86 function representYamlBinary(object /*, style*/) { 87 var result = '', bits = 0, idx, tail, 88 max = object.length, 89 map = BASE64_MAP; 90 91 // Convert every three bytes to 4 ASCII characters. 92 93 for (idx = 0; idx < max; idx++) { 94 if ((idx % 3 === 0) && idx) { 95 result += map[(bits >> 18) & 0x3F]; 96 result += map[(bits >> 12) & 0x3F]; 97 result += map[(bits >> 6) & 0x3F]; 98 result += map[bits & 0x3F]; 99 } 100 101 bits = (bits << 8) + object[idx]; 102 } 103 104 // Dump tail 105 106 tail = max % 3; 107 108 if (tail === 0) { 109 result += map[(bits >> 18) & 0x3F]; 110 result += map[(bits >> 12) & 0x3F]; 111 result += map[(bits >> 6) & 0x3F]; 112 result += map[bits & 0x3F]; 113 } else if (tail === 2) { 114 result += map[(bits >> 10) & 0x3F]; 115 result += map[(bits >> 4) & 0x3F]; 116 result += map[(bits << 2) & 0x3F]; 117 result += map[64]; 118 } else if (tail === 1) { 119 result += map[(bits >> 2) & 0x3F]; 120 result += map[(bits << 4) & 0x3F]; 121 result += map[64]; 122 result += map[64]; 123 } 124 125 return result; 126 } 127 128 function isBinary(object) { 129 return NodeBuffer && NodeBuffer.isBuffer(object); 130 } 131 132 module.exports = new Type('tag:yaml.org,2002:binary', { 133 kind: 'scalar', 134 resolve: resolveYamlBinary, 135 construct: constructYamlBinary, 136 predicate: isBinary, 137 represent: representYamlBinary 138 });