UNPKG

phpjs

Version:

php.js offers community built php functions in javascript

392 lines (352 loc) 12.9 kB
--- layout: page title: "JavaScript pack function" comments: true sharing: true footer: true alias: - /functions/view/pack:880 - /functions/view/pack - /functions/view/880 - /functions/pack:880 - /functions/880 --- <!-- Generated by Rakefile:build --> A JavaScript equivalent of PHP's pack {% codeblock misc/pack.js lang:js https://raw.github.com/kvz/phpjs/master/functions/misc/pack.js raw on github %} function pack (format) { // From: http://phpjs.org/functions // + original by: Tim de Koning (http://www.kingsquare.nl) // + parts by: Jonas Raoni Soares Silva (http://www.jsfromhell.com) // + bugfixed by: Tim de Koning (http://www.kingsquare.nl) // % note 1: Float encoding by: Jonas Raoni Soares Silva // % note 2: Home: http://www.kingsquare.nl/blog/12-12-2009/13507444 // % note 3: Feedback: phpjs-pack@kingsquare.nl // % note 4: 'machine dependent byte order and size' aren't // % note 4: applicable for JavaScript; pack works as on a 32bit, // % note 4: little endian machine // * example 1: pack('nvc*', 0x1234, 0x5678, 65, 66); // * returns 1: '4xVAB' var formatPointer = 0, argumentPointer = 1, result = '', argument = '', i = 0, r = [], instruction, quantifier, word, precisionBits, exponentBits, extraNullCount; // vars used by float encoding var bias, minExp, maxExp, minUnnormExp, status, exp, len, bin, signal, n, intPart, floatPart, lastBit, rounded, j, k, tmpResult; while (formatPointer < format.length) { instruction = format.charAt(formatPointer); quantifier = ''; formatPointer++; while ((formatPointer < format.length) && (format.charAt(formatPointer).match(/[\d\*]/) !== null)) { quantifier += format.charAt(formatPointer); formatPointer++; } if (quantifier === '') { quantifier = '1'; } // Now pack variables: 'quantifier' times 'instruction' switch (instruction) { case 'a': // NUL-padded string case 'A': // SPACE-padded string if (typeof arguments[argumentPointer] === 'undefined') { throw new Error('Warning: pack() Type ' + instruction + ': not enough arguments'); } else { argument = String(arguments[argumentPointer]); } if (quantifier === '*') { quantifier = argument.length; } for (i = 0; i < quantifier; i++) { if (typeof argument[i] === 'undefined') { if (instruction === 'a') { result += String.fromCharCode(0); } else { result += ' '; } } else { result += argument[i]; } } argumentPointer++; break; case 'h': // Hex string, low nibble first case 'H': // Hex string, high nibble first if (typeof arguments[argumentPointer] === 'undefined') { throw new Error('Warning: pack() Type ' + instruction + ': not enough arguments'); } else { argument = arguments[argumentPointer]; } if (quantifier === '*') { quantifier = argument.length; } if (quantifier > argument.length) { throw new Error('Warning: pack() Type ' + instruction + ': not enough characters in string'); } for (i = 0; i < quantifier; i += 2) { // Always get per 2 bytes... word = argument[i]; if (((i + 1) >= quantifier) || typeof argument[i + 1] === 'undefined') { word += '0'; } else { word += argument[i + 1]; } // The fastest way to reverse? if (instruction === 'h') { word = word[1] + word[0]; } result += String.fromCharCode(parseInt(word, 16)); } argumentPointer++; break; case 'c': // signed char case 'C': // unsigned char // c and C is the same in pack if (quantifier === '*') { quantifier = arguments.length - argumentPointer; } if (quantifier > (arguments.length - argumentPointer)) { throw new Error('Warning: pack() Type ' + instruction + ': too few arguments'); } for (i = 0; i < quantifier; i++) { result += String.fromCharCode(arguments[argumentPointer]); argumentPointer++; } break; case 's': // signed short (always 16 bit, machine byte order) case 'S': // unsigned short (always 16 bit, machine byte order) case 'v': // s and S is the same in pack if (quantifier === '*') { quantifier = arguments.length - argumentPointer; } if (quantifier > (arguments.length - argumentPointer)) { throw new Error('Warning: pack() Type ' + instruction + ': too few arguments'); } for (i = 0; i < quantifier; i++) { result += String.fromCharCode(arguments[argumentPointer] & 0xFF); result += String.fromCharCode(arguments[argumentPointer] >> 8 & 0xFF); argumentPointer++; } break; case 'n': // unsigned short (always 16 bit, big endian byte order) if (quantifier === '*') { quantifier = arguments.length - argumentPointer; } if (quantifier > (arguments.length - argumentPointer)) { throw new Error('Warning: pack() Type ' + instruction + ': too few arguments'); } for (i = 0; i < quantifier; i++) { result += String.fromCharCode(arguments[argumentPointer] >> 8 & 0xFF); result += String.fromCharCode(arguments[argumentPointer] & 0xFF); argumentPointer++; } break; case 'i': // signed integer (machine dependent size and byte order) case 'I': // unsigned integer (machine dependent size and byte order) case 'l': // signed long (always 32 bit, machine byte order) case 'L': // unsigned long (always 32 bit, machine byte order) case 'V': // unsigned long (always 32 bit, little endian byte order) if (quantifier === '*') { quantifier = arguments.length - argumentPointer; } if (quantifier > (arguments.length - argumentPointer)) { throw new Error('Warning: pack() Type ' + instruction + ': too few arguments'); } for (i = 0; i < quantifier; i++) { result += String.fromCharCode(arguments[argumentPointer] & 0xFF); result += String.fromCharCode(arguments[argumentPointer] >> 8 & 0xFF); result += String.fromCharCode(arguments[argumentPointer] >> 16 & 0xFF); result += String.fromCharCode(arguments[argumentPointer] >> 24 & 0xFF); argumentPointer++; } break; case 'N': // unsigned long (always 32 bit, big endian byte order) if (quantifier === '*') { quantifier = arguments.length - argumentPointer; } if (quantifier > (arguments.length - argumentPointer)) { throw new Error('Warning: pack() Type ' + instruction + ': too few arguments'); } for (i = 0; i < quantifier; i++) { result += String.fromCharCode(arguments[argumentPointer] >> 24 & 0xFF); result += String.fromCharCode(arguments[argumentPointer] >> 16 & 0xFF); result += String.fromCharCode(arguments[argumentPointer] >> 8 & 0xFF); result += String.fromCharCode(arguments[argumentPointer] & 0xFF); argumentPointer++; } break; case 'f': // float (machine dependent size and representation) case 'd': // double (machine dependent size and representation) // version based on IEEE754 precisionBits = 23; exponentBits = 8; if (instruction === 'd') { precisionBits = 52; exponentBits = 11; } if (quantifier === '*') { quantifier = arguments.length - argumentPointer; } if (quantifier > (arguments.length - argumentPointer)) { throw new Error('Warning: pack() Type ' + instruction + ': too few arguments'); } for (i = 0; i < quantifier; i++) { argument = arguments[argumentPointer]; bias = Math.pow(2, exponentBits - 1) - 1; minExp = -bias + 1; maxExp = bias; minUnnormExp = minExp - precisionBits; status = isNaN(n = parseFloat(argument)) || n === -Infinity || n === +Infinity ? n : 0; exp = 0; len = 2 * bias + 1 + precisionBits + 3; bin = new Array(len); signal = (n = status !== 0 ? 0 : n) < 0; n = Math.abs(n); intPart = Math.floor(n); floatPart = n - intPart; for (k = len; k;) { bin[--k] = 0; } for (k = bias + 2; intPart && k;) { bin[--k] = intPart % 2; intPart = Math.floor(intPart / 2); } for (k = bias + 1; floatPart > 0 && k; --floatPart) { (bin[++k] = ((floatPart *= 2) >= 1) - 0); } for (k = -1; ++k < len && !bin[k];) {} if (bin[(lastBit = precisionBits - 1 + (k = (exp = bias + 1 - k) >= minExp && exp <= maxExp ? k + 1 : bias + 1 - (exp = minExp - 1))) + 1]) { if (!(rounded = bin[lastBit])) { for (j = lastBit + 2; !rounded && j < len; rounded = bin[j++]) {} } for (j = lastBit + 1; rounded && --j >= 0; (bin[j] = !bin[j] - 0) && (rounded = 0)) {} } for (k = k - 2 < 0 ? -1 : k - 3; ++k < len && !bin[k];) {} if ((exp = bias + 1 - k) >= minExp && exp <= maxExp) { ++k; } else { if (exp < minExp) { if (exp !== bias + 1 - len && exp < minUnnormExp) { /*"encodeFloat::float underflow" */ } k = bias + 1 - (exp = minExp - 1); } } if (intPart || status !== 0) { exp = maxExp + 1; k = bias + 2; if (status === -Infinity) { signal = 1; } else if (isNaN(status)) { bin[k] = 1; } } n = Math.abs(exp + bias); tmpResult = ''; for (j = exponentBits + 1; --j;) { tmpResult = (n % 2) + tmpResult; n = n >>= 1; } n = 0; j = 0; k = (tmpResult = (signal ? '1' : '0') + tmpResult + bin.slice(k, k + precisionBits).join('')).length; r = []; for (; k;) { n += (1 << j) * tmpResult.charAt(--k); if (j === 7) { r[r.length] = String.fromCharCode(n); n = 0; } j = (j + 1) % 8; } r[r.length] = n ? String.fromCharCode(n) : ''; result += r.join(''); argumentPointer++; } break; case 'x': // NUL byte if (quantifier === '*') { throw new Error('Warning: pack(): Type x: \'*\' ignored'); } for (i = 0; i < quantifier; i++) { result += String.fromCharCode(0); } break; case 'X': // Back up one byte if (quantifier === '*') { throw new Error('Warning: pack(): Type X: \'*\' ignored'); } for (i = 0; i < quantifier; i++) { if (result.length === 0) { throw new Error('Warning: pack(): Type X:' + ' outside of string'); } else { result = result.substring(0, result.length - 1); } } break; case '@': // NUL-fill to absolute position if (quantifier === '*') { throw new Error('Warning: pack(): Type X: \'*\' ignored'); } if (quantifier > result.length) { extraNullCount = quantifier - result.length; for (i = 0; i < extraNullCount; i++) { result += String.fromCharCode(0); } } if (quantifier < result.length) { result = result.substring(0, quantifier); } break; default: throw new Error('Warning: pack() Type ' + instruction + ': unknown format code'); } } if (argumentPointer < arguments.length) { throw new Error('Warning: pack(): ' + (arguments.length - argumentPointer) + ' arguments unused'); } return result; } {% endcodeblock %} - [Raw function on GitHub](https://github.com/kvz/phpjs/blob/master/functions/misc/pack.js) Please note that php.js uses JavaScript objects as substitutes for PHP arrays, they are the closest match to this hashtable-like data structure. Please also note that php.js offers community built functions and goes by the [McDonald's Theory](https://medium.com/what-i-learned-building/9216e1c9da7d). We'll put online functions that are far from perfect, in the hopes to spark better contributions. Do you have one? Then please just: - [Edit on GitHub](https://github.com/kvz/phpjs/edit/master/functions/misc/pack.js) ### Example 1 This code {% codeblock lang:js example %} pack('nvc*', 0x1234, 0x5678, 65, 66); {% endcodeblock %} Should return {% codeblock lang:js returns %} '4xVAB' {% endcodeblock %} ### Other PHP functions in the misc extension {% render_partial _includes/custom/misc.html %}