PageRenderTime 245ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 1ms

/files/phpjs/0.1/misc/pack.js

https://gitlab.com/Mirros/jsdelivr
JavaScript | 346 lines | 277 code | 30 blank | 39 comment | 85 complexity | 3bfadd30a62999b8fdfbb6ac80c59535 MD5 | raw file
  1. function pack (format) {
  2. // http://kevin.vanzonneveld.net
  3. // + original by: Tim de Koning (http://www.kingsquare.nl)
  4. // + parts by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
  5. // + bugfixed by: Tim de Koning (http://www.kingsquare.nl)
  6. // % note 1: Float encoding by: Jonas Raoni Soares Silva
  7. // % note 2: Home: http://www.kingsquare.nl/blog/12-12-2009/13507444
  8. // % note 3: Feedback: phpjs-pack@kingsquare.nl
  9. // % note 4: 'machine dependent byte order and size' aren't
  10. // % note 4: applicable for JavaScript; pack works as on a 32bit,
  11. // % note 4: little endian machine
  12. // * example 1: pack('nvc*', 0x1234, 0x5678, 65, 66);
  13. // * returns 1: '4xVAB'
  14. var formatPointer = 0,
  15. argumentPointer = 1,
  16. result = '',
  17. argument = '',
  18. i = 0,
  19. r = [],
  20. instruction, quantifier, word, precisionBits, exponentBits, extraNullCount;
  21. // vars used by float encoding
  22. var bias, minExp, maxExp, minUnnormExp, status, exp, len, bin, signal, n, intPart, floatPart, lastBit, rounded, j, k, tmpResult;
  23. while (formatPointer < format.length) {
  24. instruction = format.charAt(formatPointer);
  25. quantifier = '';
  26. formatPointer++;
  27. while ((formatPointer < format.length) && (format.charAt(formatPointer).match(/[\d\*]/) !== null)) {
  28. quantifier += format.charAt(formatPointer);
  29. formatPointer++;
  30. }
  31. if (quantifier === '') {
  32. quantifier = '1';
  33. }
  34. // Now pack variables: 'quantifier' times 'instruction'
  35. switch (instruction) {
  36. case 'a':
  37. // NUL-padded string
  38. case 'A':
  39. // SPACE-padded string
  40. if (typeof arguments[argumentPointer] === 'undefined') {
  41. throw new Error('Warning: pack() Type ' + instruction + ': not enough arguments');
  42. } else {
  43. argument = String(arguments[argumentPointer]);
  44. }
  45. if (quantifier === '*') {
  46. quantifier = argument.length;
  47. }
  48. for (i = 0; i < quantifier; i++) {
  49. if (typeof argument[i] === 'undefined') {
  50. if (instruction === 'a') {
  51. result += String.fromCharCode(0);
  52. } else {
  53. result += ' ';
  54. }
  55. } else {
  56. result += argument[i];
  57. }
  58. }
  59. argumentPointer++;
  60. break;
  61. case 'h':
  62. // Hex string, low nibble first
  63. case 'H':
  64. // Hex string, high nibble first
  65. if (typeof arguments[argumentPointer] === 'undefined') {
  66. throw new Error('Warning: pack() Type ' + instruction + ': not enough arguments');
  67. } else {
  68. argument = arguments[argumentPointer];
  69. }
  70. if (quantifier === '*') {
  71. quantifier = argument.length;
  72. }
  73. if (quantifier > argument.length) {
  74. throw new Error('Warning: pack() Type ' + instruction + ': not enough characters in string');
  75. }
  76. for (i = 0; i < quantifier; i += 2) {
  77. // Always get per 2 bytes...
  78. word = argument[i];
  79. if (((i + 1) >= quantifier) || typeof argument[i + 1] === 'undefined') {
  80. word += '0';
  81. } else {
  82. word += argument[i + 1];
  83. }
  84. // The fastest way to reverse?
  85. if (instruction === 'h') {
  86. word = word[1] + word[0];
  87. }
  88. result += String.fromCharCode(parseInt(word, 16));
  89. }
  90. argumentPointer++;
  91. break;
  92. case 'c':
  93. // signed char
  94. case 'C':
  95. // unsigned char
  96. // c and C is the same in pack
  97. if (quantifier === '*') {
  98. quantifier = arguments.length - argumentPointer;
  99. }
  100. if (quantifier > (arguments.length - argumentPointer)) {
  101. throw new Error('Warning: pack() Type ' + instruction + ': too few arguments');
  102. }
  103. for (i = 0; i < quantifier; i++) {
  104. result += String.fromCharCode(arguments[argumentPointer]);
  105. argumentPointer++;
  106. }
  107. break;
  108. case 's':
  109. // signed short (always 16 bit, machine byte order)
  110. case 'S':
  111. // unsigned short (always 16 bit, machine byte order)
  112. case 'v':
  113. // s and S is the same in pack
  114. if (quantifier === '*') {
  115. quantifier = arguments.length - argumentPointer;
  116. }
  117. if (quantifier > (arguments.length - argumentPointer)) {
  118. throw new Error('Warning: pack() Type ' + instruction + ': too few arguments');
  119. }
  120. for (i = 0; i < quantifier; i++) {
  121. result += String.fromCharCode(arguments[argumentPointer] & 0xFF);
  122. result += String.fromCharCode(arguments[argumentPointer] >> 8 & 0xFF);
  123. argumentPointer++;
  124. }
  125. break;
  126. case 'n':
  127. // unsigned short (always 16 bit, big endian byte order)
  128. if (quantifier === '*') {
  129. quantifier = arguments.length - argumentPointer;
  130. }
  131. if (quantifier > (arguments.length - argumentPointer)) {
  132. throw new Error('Warning: pack() Type ' + instruction + ': too few arguments');
  133. }
  134. for (i = 0; i < quantifier; i++) {
  135. result += String.fromCharCode(arguments[argumentPointer] >> 8 & 0xFF);
  136. result += String.fromCharCode(arguments[argumentPointer] & 0xFF);
  137. argumentPointer++;
  138. }
  139. break;
  140. case 'i':
  141. // signed integer (machine dependent size and byte order)
  142. case 'I':
  143. // unsigned integer (machine dependent size and byte order)
  144. case 'l':
  145. // signed long (always 32 bit, machine byte order)
  146. case 'L':
  147. // unsigned long (always 32 bit, machine byte order)
  148. case 'V':
  149. // unsigned long (always 32 bit, little endian byte order)
  150. if (quantifier === '*') {
  151. quantifier = arguments.length - argumentPointer;
  152. }
  153. if (quantifier > (arguments.length - argumentPointer)) {
  154. throw new Error('Warning: pack() Type ' + instruction + ': too few arguments');
  155. }
  156. for (i = 0; i < quantifier; i++) {
  157. result += String.fromCharCode(arguments[argumentPointer] & 0xFF);
  158. result += String.fromCharCode(arguments[argumentPointer] >> 8 & 0xFF);
  159. result += String.fromCharCode(arguments[argumentPointer] >> 16 & 0xFF);
  160. result += String.fromCharCode(arguments[argumentPointer] >> 24 & 0xFF);
  161. argumentPointer++;
  162. }
  163. break;
  164. case 'N':
  165. // unsigned long (always 32 bit, big endian byte order)
  166. if (quantifier === '*') {
  167. quantifier = arguments.length - argumentPointer;
  168. }
  169. if (quantifier > (arguments.length - argumentPointer)) {
  170. throw new Error('Warning: pack() Type ' + instruction + ': too few arguments');
  171. }
  172. for (i = 0; i < quantifier; i++) {
  173. result += String.fromCharCode(arguments[argumentPointer] >> 24 & 0xFF);
  174. result += String.fromCharCode(arguments[argumentPointer] >> 16 & 0xFF);
  175. result += String.fromCharCode(arguments[argumentPointer] >> 8 & 0xFF);
  176. result += String.fromCharCode(arguments[argumentPointer] & 0xFF);
  177. argumentPointer++;
  178. }
  179. break;
  180. case 'f':
  181. // float (machine dependent size and representation)
  182. case 'd':
  183. // double (machine dependent size and representation)
  184. // version based on IEEE754
  185. precisionBits = 23;
  186. exponentBits = 8;
  187. if (instruction === 'd') {
  188. precisionBits = 52;
  189. exponentBits = 11;
  190. }
  191. if (quantifier === '*') {
  192. quantifier = arguments.length - argumentPointer;
  193. }
  194. if (quantifier > (arguments.length - argumentPointer)) {
  195. throw new Error('Warning: pack() Type ' + instruction + ': too few arguments');
  196. }
  197. for (i = 0; i < quantifier; i++) {
  198. argument = arguments[argumentPointer];
  199. bias = Math.pow(2, exponentBits - 1) - 1;
  200. minExp = -bias + 1;
  201. maxExp = bias;
  202. minUnnormExp = minExp - precisionBits;
  203. status = isNaN(n = parseFloat(argument)) || n === -Infinity || n === +Infinity ? n : 0;
  204. exp = 0;
  205. len = 2 * bias + 1 + precisionBits + 3;
  206. bin = new Array(len);
  207. signal = (n = status !== 0 ? 0 : n) < 0;
  208. n = Math.abs(n);
  209. intPart = Math.floor(n);
  210. floatPart = n - intPart;
  211. for (k = len; k;) {
  212. bin[--k] = 0;
  213. }
  214. for (k = bias + 2; intPart && k;) {
  215. bin[--k] = intPart % 2;
  216. intPart = Math.floor(intPart / 2);
  217. }
  218. for (k = bias + 1; floatPart > 0 && k; --floatPart) {
  219. (bin[++k] = ((floatPart *= 2) >= 1) - 0);
  220. }
  221. for (k = -1; ++k < len && !bin[k];) {}
  222. if (bin[(lastBit = precisionBits - 1 + (k = (exp = bias + 1 - k) >= minExp && exp <= maxExp ? k + 1 : bias + 1 - (exp = minExp - 1))) + 1]) {
  223. if (!(rounded = bin[lastBit])) {
  224. for (j = lastBit + 2; !rounded && j < len; rounded = bin[j++]) {}
  225. }
  226. for (j = lastBit + 1; rounded && --j >= 0;
  227. (bin[j] = !bin[j] - 0) && (rounded = 0)) {}
  228. }
  229. for (k = k - 2 < 0 ? -1 : k - 3; ++k < len && !bin[k];) {}
  230. if ((exp = bias + 1 - k) >= minExp && exp <= maxExp) {
  231. ++k;
  232. } else {
  233. if (exp < minExp) {
  234. if (exp !== bias + 1 - len && exp < minUnnormExp) { /*"encodeFloat::float underflow" */
  235. }
  236. k = bias + 1 - (exp = minExp - 1);
  237. }
  238. }
  239. if (intPart || status !== 0) {
  240. exp = maxExp + 1;
  241. k = bias + 2;
  242. if (status === -Infinity) {
  243. signal = 1;
  244. } else if (isNaN(status)) {
  245. bin[k] = 1;
  246. }
  247. }
  248. n = Math.abs(exp + bias);
  249. tmpResult = '';
  250. for (j = exponentBits + 1; --j;) {
  251. tmpResult = (n % 2) + tmpResult;
  252. n = n >>= 1;
  253. }
  254. n = 0;
  255. j = 0;
  256. k = (tmpResult = (signal ? '1' : '0') + tmpResult + bin.slice(k, k + precisionBits).join('')).length;
  257. r = [];
  258. for (; k;) {
  259. n += (1 << j) * tmpResult.charAt(--k);
  260. if (j === 7) {
  261. r[r.length] = String.fromCharCode(n);
  262. n = 0;
  263. }
  264. j = (j + 1) % 8;
  265. }
  266. r[r.length] = n ? String.fromCharCode(n) : '';
  267. result += r.join('');
  268. argumentPointer++;
  269. }
  270. break;
  271. case 'x':
  272. // NUL byte
  273. if (quantifier === '*') {
  274. throw new Error('Warning: pack(): Type x: \'*\' ignored');
  275. }
  276. for (i = 0; i < quantifier; i++) {
  277. result += String.fromCharCode(0);
  278. }
  279. break;
  280. case 'X':
  281. // Back up one byte
  282. if (quantifier === '*') {
  283. throw new Error('Warning: pack(): Type X: \'*\' ignored');
  284. }
  285. for (i = 0; i < quantifier; i++) {
  286. if (result.length === 0) {
  287. throw new Error('Warning: pack(): Type X:' + ' outside of string');
  288. } else {
  289. result = result.substring(0, result.length - 1);
  290. }
  291. }
  292. break;
  293. case '@':
  294. // NUL-fill to absolute position
  295. if (quantifier === '*') {
  296. throw new Error('Warning: pack(): Type X: \'*\' ignored');
  297. }
  298. if (quantifier > result.length) {
  299. extraNullCount = quantifier - result.length;
  300. for (i = 0; i < extraNullCount; i++) {
  301. result += String.fromCharCode(0);
  302. }
  303. }
  304. if (quantifier < result.length) {
  305. result = result.substring(0, quantifier);
  306. }
  307. break;
  308. default:
  309. throw new Error('Warning: pack() Type ' + instruction + ': unknown format code');
  310. }
  311. }
  312. if (argumentPointer < arguments.length) {
  313. throw new Error('Warning: pack(): ' + (arguments.length - argumentPointer) + ' arguments unused');
  314. }
  315. return result;
  316. }