PageRenderTime 42ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/_octopress/source/functions/pack/index.markdown

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