PageRenderTime 45ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/_workbench/misc/unpack.js

http://github.com/kvz/phpjs
JavaScript | 358 lines | 293 code | 45 blank | 20 comment | 66 complexity | 7b524a1e09512ba514c44601f3a380d6 MD5 | raw file
  1. function unpack(format, data) {
  2. // http://kevin.vanzonneveld.net
  3. // + original by: Tim de Koning (http://www.kingsquare.nl)
  4. // + parts by: Jonas Raoni Soares Silva
  5. // + http://www.jsfromhell.com
  6. // + bugfixed by: marcuswestin
  7. // % note 1: Float decoding by: Jonas Raoni Soares Silva
  8. // % note 2: Home: http://www.kingsquare.nl/blog/22-12-2009/13650536
  9. // % note 3: Feedback: phpjs-unpack@kingsquare.nl
  10. // % note 4: 'machine dependant byte order and size' aren't
  11. // % note 5: applicable for JavaScript unpack works as on a 32bit,
  12. // % note 6: little endian machine
  13. // * example 1: unpack('f2test', 'abcddbca');
  14. // * returns 1: { 'test1': 1.6777999408082E+22.
  15. // * returns 2: 'test2': 2.6100787562286E+20 }
  16. var formatPointer = 0, dataPointer = 0, result = {}, instruction = '',
  17. quantifier = '', label = '', currentData = '', i = 0, j = 0,
  18. word = '', precisionBits = 0, exponentBits = 0, dataByteLength = 0;
  19. // Used by float decoding
  20. var b = [], bias, signal, exponent, significand, divisor, curByte,
  21. byteValue, startBit = 0, mask, currentResult;
  22. var readBits = function(start, length, byteArray){
  23. var offsetLeft, offsetRight, curByte, lastByte, diff, sum;
  24. function shl(a, b){
  25. for(++b; --b;) {
  26. a = ((a %= 0x7fffffff + 1) & 0x40000000) === 0x40000000 ?
  27. a * 2 :
  28. (a - 0x40000000) * 2 + 0x7fffffff + 1;
  29. }
  30. return a;
  31. }
  32. if(start < 0 || length <= 0) {
  33. return 0;
  34. }
  35. offsetRight = start % 8;
  36. curByte = byteArray.length - (start >> 3) - 1;
  37. lastByte = byteArray.length + (-(start + length) >> 3);
  38. diff = curByte - lastByte;
  39. sum = (
  40. (byteArray[ curByte ] >> offsetRight) &
  41. ((1 << (diff ? 8 - offsetRight : length)) - 1)
  42. ) + (
  43. diff && (offsetLeft = (start + length) % 8) ?
  44. (byteArray[ lastByte++ ] & ((1 << offsetLeft) - 1)) <<
  45. (diff-- << 3) - offsetRight :
  46. 0
  47. );
  48. for(; diff;) {
  49. sum += shl(byteArray[ lastByte++ ], (diff-- << 3) - offsetRight);
  50. }
  51. return sum;
  52. };
  53. while (formatPointer < format.length) {
  54. instruction = format[formatPointer];
  55. // Start reading 'quantifier'
  56. quantifier = '';
  57. formatPointer++;
  58. while ((formatPointer < format.length) &&
  59. (format[formatPointer].match(/[\d\*]/) !== null)) {
  60. quantifier += format[formatPointer];
  61. formatPointer++;
  62. }
  63. if (quantifier === '') {
  64. quantifier = '1';
  65. }
  66. // Start reading label
  67. label = '';
  68. while ((formatPointer < format.length) &&
  69. (format[formatPointer] !== '/')) {
  70. label += format[formatPointer];
  71. formatPointer++;
  72. }
  73. if (format[formatPointer] === '/') {
  74. formatPointer++;
  75. }
  76. // Process given instruction
  77. switch (instruction) {
  78. case 'a': // NUL-padded string
  79. case 'A': // SPACE-padded string
  80. if (quantifier === '*') {
  81. quantifier = data.length - dataPointer;
  82. } else {
  83. quantifier = parseInt(quantifier, 10);
  84. }
  85. currentData = data.substr(dataPointer, quantifier);
  86. dataPointer += quantifier;
  87. if (instruction === 'a') {
  88. currentResult = currentData.replace(/\0+$/, '');
  89. } else {
  90. currentResult = currentData.replace(/ +$/, '');
  91. }
  92. result[label] = currentResult;
  93. break;
  94. case 'h': // Hex string, low nibble first
  95. case 'H': // Hex string, high nibble first
  96. if (quantifier === '*') {
  97. quantifier = data.length - dataPointer;
  98. } else {
  99. quantifier = parseInt(quantifier, 10);
  100. }
  101. currentData = data.substr(dataPointer, quantifier);
  102. dataPointer += quantifier;
  103. if (quantifier>currentData.length) {
  104. throw new Error('Warning: unpack(): Type ' + instruction +
  105. ': not enough input, need ' + quantifier);
  106. }
  107. currentResult = '';
  108. for(i=0;i<currentData.length;i++) {
  109. word = currentData.charCodeAt(i).toString(16);
  110. if (instruction === 'h') {
  111. word = word[1]+word[0];
  112. }
  113. currentResult += word;
  114. }
  115. result[label] = currentResult;
  116. break;
  117. case 'c': // signed char
  118. case 'C': // unsigned c
  119. if (quantifier === '*') {
  120. quantifier = data.length - dataPointer;
  121. } else {
  122. quantifier = parseInt(quantifier, 10);
  123. }
  124. currentData = data.substr(dataPointer, quantifier);
  125. dataPointer += quantifier;
  126. for (i=0;i<currentData.length;i++) {
  127. currentResult = currentData.charCodeAt(i);
  128. if ((instruction === 'c') && (currentResult >= 128)) {
  129. currentResult -= 256;
  130. }
  131. result[label+(quantifier>1?
  132. (i+1):
  133. '')] = currentResult;
  134. }
  135. break;
  136. case 'S': // unsigned short (always 16 bit, machine byte order)
  137. case 's': // signed short (always 16 bit, machine byte order)
  138. case 'v': // unsigned short (always 16 bit, little endian byte order)
  139. if (quantifier === '*') {
  140. quantifier = (data.length - dataPointer) / 2;
  141. } else {
  142. quantifier = parseInt(quantifier, 10);
  143. }
  144. currentData = data.substr(dataPointer, quantifier * 2);
  145. dataPointer += quantifier * 2;
  146. for (i=0;i<currentData.length;i+=2) {
  147. // sum per word;
  148. currentResult = (currentData.charCodeAt(i+1) & 0xFF) << 8 +
  149. (currentData.charCodeAt(i) & 0xFF);
  150. if ((instruction === 's') && (currentResult >= 32768)) {
  151. currentResult -= 65536;
  152. }
  153. result[label+(quantifier>1?
  154. ((i/2)+1):
  155. '')] = currentResult;
  156. }
  157. break;
  158. case 'n': // unsigned short (always 16 bit, big endian byte order)
  159. if (quantifier === '*') {
  160. quantifier = (data.length - dataPointer) / 2;
  161. } else {
  162. quantifier = parseInt(quantifier, 10);
  163. }
  164. currentData = data.substr(dataPointer, quantifier * 2);
  165. dataPointer += quantifier * 2;
  166. for (i=0;i<currentData.length;i+=2) {
  167. // sum per word;
  168. currentResult = ((currentData.charCodeAt(i) & 0xFF) << 8) +
  169. (currentData.charCodeAt(i+1) & 0xFF);
  170. result[label+(quantifier>1?
  171. ((i/2)+1):
  172. '')] = currentResult;
  173. }
  174. break;
  175. case 'i': // signed integer (machine dependent size and byte order)
  176. case 'I': // unsigned integer (machine dependent size & byte order)
  177. case 'l': // signed long (always 32 bit, machine byte order)
  178. case 'L': // unsigned long (always 32 bit, machine byte order)
  179. case 'V': // unsigned long (always 32 bit, little endian byte order)
  180. if (quantifier === '*') {
  181. quantifier = (data.length - dataPointer) / 4;
  182. } else {
  183. quantifier = parseInt(quantifier, 10);
  184. }
  185. currentData = data.substr(dataPointer, quantifier * 4);
  186. dataPointer += quantifier * 4;
  187. for (i=0;i<currentData.length;i+=4) {
  188. currentResult =
  189. ((currentData.charCodeAt(i+3) & 0xFF) << 24) +
  190. ((currentData.charCodeAt(i+2) & 0xFF) << 16) +
  191. ((currentData.charCodeAt(i+1) & 0xFF) << 8) +
  192. ((currentData.charCodeAt(i) & 0xFF));
  193. result[label+(quantifier>1?
  194. ((i/4)+1):
  195. '')] = currentResult;
  196. }
  197. break;
  198. case 'N': // unsigned long (always 32 bit, little endian byte order)
  199. if (quantifier === '*') {
  200. quantifier = (data.length - dataPointer) / 4;
  201. } else {
  202. quantifier = parseInt(quantifier, 10);
  203. }
  204. currentData = data.substr(dataPointer, quantifier * 4);
  205. dataPointer += quantifier * 4;
  206. for (i=0;i<currentData.length;i+=4) {
  207. currentResult =
  208. ((currentData.charCodeAt(i) & 0xFF) << 24) +
  209. ((currentData.charCodeAt(i+1) & 0xFF) << 16) +
  210. ((currentData.charCodeAt(i+2) & 0xFF) << 8) +
  211. ((currentData.charCodeAt(i+3) & 0xFF));
  212. result[label+(quantifier>1?
  213. ((i/4)+1):
  214. '')] = currentResult;
  215. }
  216. break;
  217. case 'f':
  218. case 'd':
  219. exponentBits = 8;
  220. dataByteLength = 4;
  221. if (instruction === 'd') {
  222. exponentBits = 11;
  223. dataByteLength = 8;
  224. }
  225. if (quantifier === '*') {
  226. quantifier = (data.length - dataPointer) / dataByteLength;
  227. } else {
  228. quantifier = parseInt(quantifier, 10);
  229. }
  230. currentData = data.substr(dataPointer,
  231. quantifier * dataByteLength);
  232. dataPointer += quantifier * dataByteLength;
  233. for (i=0;i<currentData.length;i+=dataByteLength) {
  234. data = currentData.substr(i, dataByteLength);
  235. b = [];
  236. for(j = data.length-1; j >= 0 ; --j) {
  237. b.push(data.charCodeAt(j));
  238. }
  239. precisionBits = (instruction === 'f')?23:52;
  240. bias = Math.pow(2, exponentBits - 1) - 1;
  241. signal = readBits(precisionBits + exponentBits, 1, b);
  242. exponent = readBits(precisionBits, exponentBits, b);
  243. significand = 0;
  244. divisor = 2;
  245. curByte = b.length + (-precisionBits >> 3) - 1;
  246. startBit = 0;
  247. do {
  248. byteValue = b[ ++curByte ];
  249. startBit = precisionBits % 8 || 8;
  250. mask = 1 << startBit;
  251. for(; (mask >>= 1);) {
  252. if (byteValue & mask) {
  253. significand += 1 / divisor;
  254. }
  255. divisor *= 2;
  256. }
  257. } while ((precisionBits -= startBit));
  258. if (exponent === (bias << 1) + 1) {
  259. if (significand) {
  260. currentResult = NaN;
  261. } else {
  262. if (signal) {
  263. currentResult = -Infinity;
  264. } else {
  265. currentResult = +Infinity;
  266. }
  267. }
  268. } else {
  269. if ((1 + signal * -2) * (exponent || significand)) {
  270. if (!exponent) {
  271. currentResult = Math.pow(2, -bias + 1) *
  272. significand;
  273. } else {
  274. currentResult = Math.pow(2,
  275. exponent - bias) *
  276. (1 + significand);
  277. }
  278. } else {
  279. currentResult = 0;
  280. }
  281. }
  282. result[label+(quantifier>1?
  283. ((i/4)+1):
  284. '')] = currentResult;
  285. }
  286. break;
  287. case 'x': // NUL byte
  288. case 'X': // Back up one byte
  289. case '@': // NUL byte
  290. if (quantifier === '*') {
  291. quantifier = data.length - dataPointer;
  292. } else {
  293. quantifier = parseInt(quantifier, 10);
  294. }
  295. if (quantifier > 0) {
  296. if (instruction === 'X') {
  297. dataPointer -= quantifier;
  298. } else {
  299. if (instruction === 'x') {
  300. dataPointer += quantifier;
  301. } else {
  302. dataPointer = quantifier;
  303. }
  304. }
  305. }
  306. break;
  307. default:
  308. throw new Error('Warning: unpack() Type ' + instruction +
  309. ': unknown format code');
  310. }
  311. }
  312. return result;
  313. }