binary_parser.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. /**
  2. * Binary Parser.
  3. * Jonas Raoni Soares Silva
  4. * http://jsfromhell.com/classes/binary-parser [v1.0]
  5. */
  6. var chr = String.fromCharCode;
  7. var maxBits = [];
  8. for (var i = 0; i < 64; i++) {
  9. maxBits[i] = Math.pow(2, i);
  10. }
  11. function BinaryParser (bigEndian, allowExceptions) {
  12. if(!(this instanceof BinaryParser)) return new BinaryParser(bigEndian, allowExceptions);
  13. this.bigEndian = bigEndian;
  14. this.allowExceptions = allowExceptions;
  15. };
  16. BinaryParser.warn = function warn (msg) {
  17. if (this.allowExceptions) {
  18. throw new Error(msg);
  19. }
  20. return 1;
  21. };
  22. BinaryParser.decodeFloat = function decodeFloat (data, precisionBits, exponentBits) {
  23. var b = new this.Buffer(this.bigEndian, data);
  24. b.checkBuffer(precisionBits + exponentBits + 1);
  25. var bias = maxBits[exponentBits - 1] - 1
  26. , signal = b.readBits(precisionBits + exponentBits, 1)
  27. , exponent = b.readBits(precisionBits, exponentBits)
  28. , significand = 0
  29. , divisor = 2
  30. , curByte = b.buffer.length + (-precisionBits >> 3) - 1;
  31. do {
  32. for (var byteValue = b.buffer[ ++curByte ], startBit = precisionBits % 8 || 8, mask = 1 << startBit; mask >>= 1; ( byteValue & mask ) && ( significand += 1 / divisor ), divisor *= 2 );
  33. } while (precisionBits -= startBit);
  34. return exponent == ( bias << 1 ) + 1 ? significand ? NaN : signal ? -Infinity : +Infinity : ( 1 + signal * -2 ) * ( exponent || significand ? !exponent ? Math.pow( 2, -bias + 1 ) * significand : Math.pow( 2, exponent - bias ) * ( 1 + significand ) : 0 );
  35. };
  36. BinaryParser.decodeInt = function decodeInt (data, bits, signed, forceBigEndian) {
  37. var b = new this.Buffer(this.bigEndian || forceBigEndian, data)
  38. , x = b.readBits(0, bits)
  39. , max = maxBits[bits]; //max = Math.pow( 2, bits );
  40. return signed && x >= max / 2
  41. ? x - max
  42. : x;
  43. };
  44. BinaryParser.encodeFloat = function encodeFloat (data, precisionBits, exponentBits) {
  45. var bias = maxBits[exponentBits - 1] - 1
  46. , minExp = -bias + 1
  47. , maxExp = bias
  48. , minUnnormExp = minExp - precisionBits
  49. , n = parseFloat(data)
  50. , status = isNaN(n) || n == -Infinity || n == +Infinity ? n : 0
  51. , exp = 0
  52. , len = 2 * bias + 1 + precisionBits + 3
  53. , bin = new Array(len)
  54. , signal = (n = status !== 0 ? 0 : n) < 0
  55. , intPart = Math.floor(n = Math.abs(n))
  56. , floatPart = n - intPart
  57. , lastBit
  58. , rounded
  59. , result
  60. , i
  61. , j;
  62. for (i = len; i; bin[--i] = 0);
  63. for (i = bias + 2; intPart && i; bin[--i] = intPart % 2, intPart = Math.floor(intPart / 2));
  64. for (i = bias + 1; floatPart > 0 && i; (bin[++i] = ((floatPart *= 2) >= 1) - 0 ) && --floatPart);
  65. for (i = -1; ++i < len && !bin[i];);
  66. if (bin[(lastBit = precisionBits - 1 + (i = (exp = bias + 1 - i) >= minExp && exp <= maxExp ? i + 1 : bias + 1 - (exp = minExp - 1))) + 1]) {
  67. if (!(rounded = bin[lastBit])) {
  68. for (j = lastBit + 2; !rounded && j < len; rounded = bin[j++]);
  69. }
  70. for (j = lastBit + 1; rounded && --j >= 0; (bin[j] = !bin[j] - 0) && (rounded = 0));
  71. }
  72. for (i = i - 2 < 0 ? -1 : i - 3; ++i < len && !bin[i];);
  73. if ((exp = bias + 1 - i) >= minExp && exp <= maxExp) {
  74. ++i;
  75. } else if (exp < minExp) {
  76. exp != bias + 1 - len && exp < minUnnormExp && this.warn("encodeFloat::float underflow");
  77. i = bias + 1 - (exp = minExp - 1);
  78. }
  79. if (intPart || status !== 0) {
  80. this.warn(intPart ? "encodeFloat::float overflow" : "encodeFloat::" + status);
  81. exp = maxExp + 1;
  82. i = bias + 2;
  83. if (status == -Infinity) {
  84. signal = 1;
  85. } else if (isNaN(status)) {
  86. bin[i] = 1;
  87. }
  88. }
  89. for (n = Math.abs(exp + bias), j = exponentBits + 1, result = ""; --j; result = (n % 2) + result, n = n >>= 1);
  90. for (n = 0, j = 0, i = (result = (signal ? "1" : "0") + result + bin.slice(i, i + precisionBits).join("")).length, r = []; i; j = (j + 1) % 8) {
  91. n += (1 << j) * result.charAt(--i);
  92. if (j == 7) {
  93. r[r.length] = String.fromCharCode(n);
  94. n = 0;
  95. }
  96. }
  97. r[r.length] = n
  98. ? String.fromCharCode(n)
  99. : "";
  100. return (this.bigEndian ? r.reverse() : r).join("");
  101. };
  102. BinaryParser.encodeInt = function encodeInt (data, bits, signed, forceBigEndian) {
  103. var max = maxBits[bits];
  104. if (data >= max || data < -(max / 2)) {
  105. this.warn("encodeInt::overflow");
  106. data = 0;
  107. }
  108. if (data < 0) {
  109. data += max;
  110. }
  111. for (var r = []; data; r[r.length] = String.fromCharCode(data % 256), data = Math.floor(data / 256));
  112. for (bits = -(-bits >> 3) - r.length; bits--; r[r.length] = "\0");
  113. return ((this.bigEndian || forceBigEndian) ? r.reverse() : r).join("");
  114. };
  115. BinaryParser.toSmall = function( data ){ return this.decodeInt( data, 8, true ); };
  116. BinaryParser.fromSmall = function( data ){ return this.encodeInt( data, 8, true ); };
  117. BinaryParser.toByte = function( data ){ return this.decodeInt( data, 8, false ); };
  118. BinaryParser.fromByte = function( data ){ return this.encodeInt( data, 8, false ); };
  119. BinaryParser.toShort = function( data ){ return this.decodeInt( data, 16, true ); };
  120. BinaryParser.fromShort = function( data ){ return this.encodeInt( data, 16, true ); };
  121. BinaryParser.toWord = function( data ){ return this.decodeInt( data, 16, false ); };
  122. BinaryParser.fromWord = function( data ){ return this.encodeInt( data, 16, false ); };
  123. BinaryParser.toInt = function( data ){ return this.decodeInt( data, 32, true ); };
  124. BinaryParser.fromInt = function( data ){ return this.encodeInt( data, 32, true ); };
  125. BinaryParser.toLong = function( data ){ return this.decodeInt( data, 64, true ); };
  126. BinaryParser.fromLong = function( data ){ return this.encodeInt( data, 64, true ); };
  127. BinaryParser.toDWord = function( data ){ return this.decodeInt( data, 32, false ); };
  128. BinaryParser.fromDWord = function( data ){ return this.encodeInt( data, 32, false ); };
  129. BinaryParser.toQWord = function( data ){ return this.decodeInt( data, 64, true ); };
  130. BinaryParser.fromQWord = function( data ){ return this.encodeInt( data, 64, true ); };
  131. BinaryParser.toFloat = function( data ){ return this.decodeFloat( data, 23, 8 ); };
  132. BinaryParser.fromFloat = function( data ){ return this.encodeFloat( data, 23, 8 ); };
  133. BinaryParser.toDouble = function( data ){ return this.decodeFloat( data, 52, 11 ); };
  134. BinaryParser.fromDouble = function( data ){ return this.encodeFloat( data, 52, 11 ); };
  135. // Factor out the encode so it can be shared by add_header and push_int32
  136. BinaryParser.encode_int32 = function encode_int32 (number, asArray) {
  137. var a, b, c, d, unsigned;
  138. unsigned = (number < 0) ? (number + 0x100000000) : number;
  139. a = Math.floor(unsigned / 0xffffff);
  140. unsigned &= 0xffffff;
  141. b = Math.floor(unsigned / 0xffff);
  142. unsigned &= 0xffff;
  143. c = Math.floor(unsigned / 0xff);
  144. unsigned &= 0xff;
  145. d = Math.floor(unsigned);
  146. return asArray ? [chr(a), chr(b), chr(c), chr(d)] : chr(a) + chr(b) + chr(c) + chr(d);
  147. };
  148. BinaryParser.encode_int64 = function encode_int64 (number) {
  149. var a, b, c, d, e, f, g, h, unsigned;
  150. unsigned = (number < 0) ? (number + 0x10000000000000000) : number;
  151. a = Math.floor(unsigned / 0xffffffffffffff);
  152. unsigned &= 0xffffffffffffff;
  153. b = Math.floor(unsigned / 0xffffffffffff);
  154. unsigned &= 0xffffffffffff;
  155. c = Math.floor(unsigned / 0xffffffffff);
  156. unsigned &= 0xffffffffff;
  157. d = Math.floor(unsigned / 0xffffffff);
  158. unsigned &= 0xffffffff;
  159. e = Math.floor(unsigned / 0xffffff);
  160. unsigned &= 0xffffff;
  161. f = Math.floor(unsigned / 0xffff);
  162. unsigned &= 0xffff;
  163. g = Math.floor(unsigned / 0xff);
  164. unsigned &= 0xff;
  165. h = Math.floor(unsigned);
  166. return chr(a) + chr(b) + chr(c) + chr(d) + chr(e) + chr(f) + chr(g) + chr(h);
  167. };
  168. /**
  169. * UTF8 methods
  170. */
  171. // Take a raw binary string and return a utf8 string
  172. BinaryParser.decode_utf8 = function decode_utf8 (binaryStr) {
  173. var len = binaryStr.length
  174. , decoded = ''
  175. , i = 0
  176. , c = 0
  177. , c1 = 0
  178. , c2 = 0
  179. , c3;
  180. while (i < len) {
  181. c = binaryStr.charCodeAt(i);
  182. if (c < 128) {
  183. decoded += String.fromCharCode(c);
  184. i++;
  185. } else if ((c > 191) && (c < 224)) {
  186. c2 = binaryStr.charCodeAt(i+1);
  187. decoded += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
  188. i += 2;
  189. } else {
  190. c2 = binaryStr.charCodeAt(i+1);
  191. c3 = binaryStr.charCodeAt(i+2);
  192. decoded += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
  193. i += 3;
  194. }
  195. }
  196. return decoded;
  197. };
  198. // Encode a cstring
  199. BinaryParser.encode_cstring = function encode_cstring (s) {
  200. return unescape(encodeURIComponent(s)) + BinaryParser.fromByte(0);
  201. };
  202. // Take a utf8 string and return a binary string
  203. BinaryParser.encode_utf8 = function encode_utf8 (s) {
  204. var a = ""
  205. , c;
  206. for (var n = 0, len = s.length; n < len; n++) {
  207. c = s.charCodeAt(n);
  208. if (c < 128) {
  209. a += String.fromCharCode(c);
  210. } else if ((c > 127) && (c < 2048)) {
  211. a += String.fromCharCode((c>>6) | 192) ;
  212. a += String.fromCharCode((c&63) | 128);
  213. } else {
  214. a += String.fromCharCode((c>>12) | 224);
  215. a += String.fromCharCode(((c>>6) & 63) | 128);
  216. a += String.fromCharCode((c&63) | 128);
  217. }
  218. }
  219. return a;
  220. };
  221. BinaryParser.hprint = function hprint (s) {
  222. var number;
  223. for (var i = 0, len = s.length; i < len; i++) {
  224. if (s.charCodeAt(i) < 32) {
  225. number = s.charCodeAt(i) <= 15
  226. ? "0" + s.charCodeAt(i).toString(16)
  227. : s.charCodeAt(i).toString(16);
  228. process.stdout.write(number + " ")
  229. } else {
  230. number = s.charCodeAt(i) <= 15
  231. ? "0" + s.charCodeAt(i).toString(16)
  232. : s.charCodeAt(i).toString(16);
  233. process.stdout.write(number + " ")
  234. }
  235. }
  236. process.stdout.write("\n\n");
  237. };
  238. BinaryParser.ilprint = function hprint (s) {
  239. var number;
  240. for (var i = 0, len = s.length; i < len; i++) {
  241. if (s.charCodeAt(i) < 32) {
  242. number = s.charCodeAt(i) <= 15
  243. ? "0" + s.charCodeAt(i).toString(10)
  244. : s.charCodeAt(i).toString(10);
  245. require('util').debug(number+' : ');
  246. } else {
  247. number = s.charCodeAt(i) <= 15
  248. ? "0" + s.charCodeAt(i).toString(10)
  249. : s.charCodeAt(i).toString(10);
  250. require('util').debug(number+' : '+ s.charAt(i));
  251. }
  252. }
  253. };
  254. BinaryParser.hlprint = function hprint (s) {
  255. var number;
  256. for (var i = 0, len = s.length; i < len; i++) {
  257. if (s.charCodeAt(i) < 32) {
  258. number = s.charCodeAt(i) <= 15
  259. ? "0" + s.charCodeAt(i).toString(16)
  260. : s.charCodeAt(i).toString(16);
  261. require('util').debug(number+' : ');
  262. } else {
  263. number = s.charCodeAt(i) <= 15
  264. ? "0" + s.charCodeAt(i).toString(16)
  265. : s.charCodeAt(i).toString(16);
  266. require('util').debug(number+' : '+ s.charAt(i));
  267. }
  268. }
  269. };
  270. /**
  271. * BinaryParser buffer constructor.
  272. */
  273. function BinaryParserBuffer (bigEndian, buffer) {
  274. this.bigEndian = bigEndian || 0;
  275. this.buffer = [];
  276. this.setBuffer(buffer);
  277. };
  278. BinaryParserBuffer.prototype.setBuffer = function setBuffer (data) {
  279. var l, i, b;
  280. if (data) {
  281. i = l = data.length;
  282. b = this.buffer = new Array(l);
  283. for (; i; b[l - i] = data.charCodeAt(--i));
  284. this.bigEndian && b.reverse();
  285. }
  286. };
  287. BinaryParserBuffer.prototype.hasNeededBits = function hasNeededBits (neededBits) {
  288. return this.buffer.length >= -(-neededBits >> 3);
  289. };
  290. BinaryParserBuffer.prototype.checkBuffer = function checkBuffer (neededBits) {
  291. if (!this.hasNeededBits(neededBits)) {
  292. throw new Error("checkBuffer::missing bytes");
  293. }
  294. };
  295. BinaryParserBuffer.prototype.readBits = function readBits (start, length) {
  296. //shl fix: Henri Torgemane ~1996 (compressed by Jonas Raoni)
  297. function shl (a, b) {
  298. for (; b--; a = ((a %= 0x7fffffff + 1) & 0x40000000) == 0x40000000 ? a * 2 : (a - 0x40000000) * 2 + 0x7fffffff + 1);
  299. return a;
  300. }
  301. if (start < 0 || length <= 0) {
  302. return 0;
  303. }
  304. this.checkBuffer(start + length);
  305. var offsetLeft
  306. , offsetRight = start % 8
  307. , curByte = this.buffer.length - ( start >> 3 ) - 1
  308. , lastByte = this.buffer.length + ( -( start + length ) >> 3 )
  309. , diff = curByte - lastByte
  310. , sum = ((this.buffer[ curByte ] >> offsetRight) & ((1 << (diff ? 8 - offsetRight : length)) - 1)) + (diff && (offsetLeft = (start + length) % 8) ? (this.buffer[lastByte++] & ((1 << offsetLeft) - 1)) << (diff-- << 3) - offsetRight : 0);
  311. for(; diff; sum += shl(this.buffer[lastByte++], (diff-- << 3) - offsetRight));
  312. return sum;
  313. };
  314. /**
  315. * Expose.
  316. */
  317. BinaryParser.Buffer = BinaryParserBuffer;
  318. exports.BinaryParser = BinaryParser;