You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
481 lines
11 KiB
481 lines
11 KiB
// Copyright (c) 2008, Fair Oaks Labs, Inc. |
|
// All rights reserved. |
|
// |
|
// Redistribution and use in source and binary forms, with or without modification, are |
|
// permitted provided that the following conditions are met: |
|
// |
|
// * Redistributions of source code must retain the above copyright notice, this list |
|
// of conditions and the following disclaimer. |
|
// * Redistributions in binary form must reproduce the above copyright notice, this |
|
// list of conditions and the following disclaimer in the documentation and/or other |
|
// materials provided with the distribution. |
|
// * Neither the name of Fair Oaks Labs, Inc. nor the names of its contributors may be |
|
// used to endorse or promote products derived from this software without specific |
|
// prior written permission. |
|
// |
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY |
|
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
|
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL |
|
// THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
|
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF |
|
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
// Modified from original JSPack <cbond@positrace.com> |
|
exports.jspack = function (bigEndian) { |
|
this.bigEndian = bigEndian; |
|
} |
|
|
|
exports.jspack.prototype._DeArray = function (a, p, l) { |
|
return [a.slice(p, p + l)]; |
|
}; |
|
|
|
exports.jspack.prototype._EnArray = function (a, p, l, v) { |
|
for (var i = 0; i < l; ++i) { |
|
a[p + i] = v[i] ? v[i] : 0; |
|
} |
|
}; |
|
|
|
exports.jspack.prototype._DeChar = function (a, p) { |
|
return String.fromCharCode(a[p]); |
|
}; |
|
|
|
exports.jspack.prototype._EnChar = function (a, p, v) { |
|
a[p] = v.charCodeAt(0); |
|
}; |
|
|
|
exports.jspack.prototype._DeInt = function (a, p) { |
|
var lsb = bigEndian ? format.len - 1 : 0; |
|
var nsb = bigEndian ? -1 : 1; |
|
var stp = lsb + nsb * format.len, |
|
rv; |
|
var ret = 0; |
|
|
|
var i = lsb; |
|
var f = 1; |
|
while (i != stp) { |
|
rv += a[p + i] * f; |
|
i += nsb; |
|
f *= 256; |
|
} |
|
|
|
if (format.signed) { |
|
if ((rv & Math.pow(2, format.len * 8 - 1)) != 0) { |
|
rv -= Math.pow(2, format.len * 8); |
|
} |
|
} |
|
|
|
return rv; |
|
}; |
|
|
|
exports.jspack.prototype._EnInt = function (a, p, v) { |
|
var lsb = bigEndian ? format.len - 1 : 0; |
|
var nsb = bigEndian ? -1 : 1; |
|
var stp = lsb + nsb * format.len; |
|
|
|
v = v < format.min ? format.min : ((v > format.max) ? format.max : v); |
|
|
|
var i = lsb; |
|
while (i != stp) { |
|
a[p + i] = v & 0xff; |
|
i += nsb; |
|
v >>= 8; |
|
} |
|
}; |
|
|
|
exports.jspack.prototype._DeString = function (a, p, l) { |
|
var rv = new Array(1); |
|
|
|
for (i = 0; i < l; i++) { |
|
rv[i] = String.fromCharCode(a[p + i]); |
|
} |
|
|
|
return rv.join(''); |
|
}; |
|
|
|
exports.jspack.prototype._EnString = function (a, p, l, v) { |
|
for (var t, i = 0; i < l; ++i) { |
|
t = v.charCodeAt(i); |
|
if (!t) t = 0; |
|
|
|
a[p + i] = t; |
|
} |
|
}; |
|
|
|
exports.jspack.prototype._De754 = function (a, p) { |
|
var s, e, m, i, d, bits, bit, len, bias, max; |
|
|
|
bit = format.bit; |
|
len = format.len * 8 - format.bit - 1; |
|
max = (1 << len) - 1; |
|
bias = max >> 1; |
|
|
|
i = bigEndian ? 0 : format.len - 1; |
|
d = bigEndian ? 1 : -1;; |
|
s = a[p + i]; |
|
i = i + d; |
|
|
|
bits = -7; |
|
|
|
e = s & ((1 << -bits) - 1); |
|
s >>= -bits; |
|
|
|
for (bits += len; bits > 0; bits -= 8) { |
|
e = e * 256 + a[p + i]; |
|
i += d; |
|
} |
|
|
|
m = e & ((1 << -bits) - 1); |
|
e >>= -bits; |
|
|
|
for (bits += bit; bits > 0; bits -= 8) { |
|
m = m * 256 + a[p + i]; |
|
i += d; |
|
} |
|
|
|
switch (e) { |
|
case 0: |
|
// Zero, or denormalized number |
|
e = 1 - bias; |
|
break; |
|
|
|
case max: |
|
// NaN, or +/-Infinity |
|
return m ? NaN : ((s ? -1 : 1) * Infinity); |
|
|
|
default: |
|
// Normalized number |
|
m = m + Math.pow(2, bit); |
|
e = e - bias; |
|
break; |
|
} |
|
|
|
return (s ? -1 : 1) * m * Math.pow(2, e - bit); |
|
}; |
|
|
|
exports.jspack.prototype._En754 = function (a, p, v) { |
|
var s, e, m, i, d, c, bit, len, bias, max; |
|
|
|
bit = format.bit; |
|
len = format.len * 8 - format.bit - 1; |
|
max = (1 << len) - 1; |
|
bias = max >> 1; |
|
|
|
s = v < 0 ? 1 : 0; |
|
v = Math.abs(v); |
|
|
|
if (isNaN(v) || (v == Infinity)) { |
|
m = isNaN(v) ? 1 : 0; |
|
e = max; |
|
} else { |
|
e = Math.floor(Math.log(v) / Math.LN2); // Calculate log2 of the value |
|
c = Math.pow(2, -e); |
|
if (v * c < 1) { |
|
e--; |
|
c = c * 2; |
|
} |
|
|
|
// Round by adding 1/2 the significand's LSD |
|
if (e + bias >= 1) { |
|
v += format.rt / c; // Normalized: bit significand digits |
|
} else { |
|
v += format.rt * Math.pow(2, 1 - bias); // Denormalized: <= bit significand digits |
|
} |
|
if (v * c >= 2) { |
|
e++; |
|
c = c / 2; // Rounding can increment the exponent |
|
} |
|
|
|
if (e + bias >= max) { // overflow |
|
m = 0; |
|
e = max; |
|
} else if (e + bias >= 1) { // normalized |
|
m = (v * c - 1) * Math.pow(2, bit); // do not reorder this expression |
|
e = e + bias; |
|
} else { |
|
// Denormalized - also catches the '0' case, somewhat by chance |
|
m = v * Math.pow(2, bias - 1) * Math.pow(2, bit); |
|
e = 0; |
|
} |
|
} |
|
|
|
i = bigEndian ? format.len - 1 : 0; |
|
d = bigEndian ? -1 : 1;; |
|
|
|
while (bit >= 8) { |
|
a[p + i] = m & 0xff; |
|
i += d; |
|
m /= 256; |
|
bit -= 8; |
|
} |
|
|
|
e = (e << bit) | m; |
|
for (len += bit; len > 0; len -= 8) { |
|
a[p + i] = e & 0xff; |
|
i += d; |
|
e /= 256; |
|
} |
|
|
|
a[p + i - d] |= s * 128; |
|
}; |
|
|
|
// Unpack a series of n formatements of size s from array a at offset p with fxn |
|
exports.jspack.prototype._UnpackSeries = function (n, s, a, p) { |
|
var fxn = format.de; |
|
|
|
var ret = []; |
|
for (var i = 0; i < n; i++) { |
|
ret.push(fxn(a, p + i * s)); |
|
} |
|
|
|
return ret; |
|
}; |
|
|
|
// Pack a series of n formatements of size s from array v at offset i to array a at offset p with fxn |
|
exports.jspack.prototype._PackSeries = function (n, s, a, p, v, i) { |
|
var fxn = format.en; |
|
|
|
for (o = 0; o < n; o++) { |
|
fxn(a, p + o * s, v[i + o]); |
|
} |
|
}; |
|
|
|
// Unpack the octet array a, beginning at offset p, according to the fmt string |
|
exports.jspack.prototype.Unpack = function (fmt, a, p) { |
|
bigEndian = fmt.charAt(0) != '<'; |
|
|
|
if (p == undefined || p == null) p = 0; |
|
|
|
var re = new RegExp(this._sPattern, 'g'); |
|
|
|
var ret = []; |
|
|
|
for (var m; m = re.exec(fmt); /* */ ) { |
|
var n; |
|
if (m[1] == undefined || m[1] == '') n = 1; |
|
else n = parseInt(m[1]); |
|
|
|
var s = this._lenLut[m[2]]; |
|
|
|
if ((p + n * s) > a.length) return undefined; |
|
|
|
switch (m[2]) { |
|
case 'A': |
|
case 's': |
|
rv.push(this._formatLut[m[2]].de(a, p, n)); |
|
break; |
|
case 'c': |
|
case 'b': |
|
case 'B': |
|
case 'h': |
|
case 'H': |
|
case 'i': |
|
case 'I': |
|
case 'l': |
|
case 'L': |
|
case 'f': |
|
case 'd': |
|
format = this._formatLut[m[2]]; |
|
ret.push(this._UnpackSeries(n, s, a, p)); |
|
break; |
|
} |
|
|
|
p += n * s; |
|
} |
|
|
|
return Array.prototype.concat.apply([], ret); |
|
}; |
|
|
|
// Pack the supplied values into the octet array a, beginning at offset p, according to the fmt string |
|
exports.jspack.prototype.PackTo = function (fmt, a, p, values) { |
|
bigEndian = (fmt.charAt(0) != '<'); |
|
|
|
var re = new RegExp(this._sPattern, 'g'); |
|
|
|
for (var m, i = 0; m = re.exec(fmt); /* */ ) { |
|
var n; |
|
if (m[1] == undefined || m[1] == '') n = 1; |
|
else n = parseInt(m[1]); |
|
|
|
var s = this._lenLut[m[2]]; |
|
|
|
if ((p + n * s) > a.length) return false; |
|
|
|
switch (m[2]) { |
|
case 'A': |
|
case 's': |
|
if ((i + 1) > values.length) return false; |
|
|
|
this._formatLut[m[2]].en(a, p, n, values[i]); |
|
|
|
i += 1; |
|
break; |
|
|
|
case 'c': |
|
case 'b': |
|
case 'B': |
|
case 'h': |
|
case 'H': |
|
case 'i': |
|
case 'I': |
|
case 'l': |
|
case 'L': |
|
case 'f': |
|
case 'd': |
|
format = this._formatLut[m[2]]; |
|
|
|
if (i + n > values.length) return false; |
|
|
|
this._PackSeries(n, s, a, p, values, i); |
|
|
|
i += n; |
|
break; |
|
|
|
case 'x': |
|
for (var j = 0; j < n; j++) { |
|
a[p + j] = 0; |
|
} |
|
break; |
|
} |
|
|
|
p += n * s; |
|
} |
|
|
|
return a; |
|
}; |
|
|
|
// Pack the supplied values into a new octet array, according to the fmt string |
|
exports.jspack.prototype.Pack = function (fmt, values) { |
|
return this.PackTo(fmt, new Array(this.CalcLength(fmt)), 0, values); |
|
}; |
|
|
|
// Determine the number of bytes represented by the format string |
|
exports.jspack.prototype.CalcLength = function (fmt) { |
|
var re = new RegExp(this._sPattern, 'g'); |
|
var sz = 0; |
|
|
|
while (match = re.exec(fmt)) { |
|
var n; |
|
if (match[1] == undefined || match[1] == '') n = 1; |
|
else n = parseInt(match[1]); |
|
|
|
sz += n * this._lenLut[match[2]]; |
|
} |
|
|
|
return sz; |
|
}; |
|
|
|
// Regular expression for counting digits |
|
exports.jspack.prototype._sPattern = '(\\d+)?([AxcbBhHsfdiIlL])'; |
|
|
|
// Byte widths for associated formats |
|
exports.jspack.prototype._lenLut = { |
|
'A': 1, |
|
'x': 1, |
|
'c': 1, |
|
'b': 1, |
|
'B': 1, |
|
'h': 2, |
|
'H': 2, |
|
's': 1, |
|
'f': 4, |
|
'd': 8, |
|
'i': 4, |
|
'I': 4, |
|
'l': 4, |
|
'L': 4 |
|
}; |
|
|
|
exports.jspack.prototype._formatLut = { |
|
'A': { |
|
en: exports.jspack.prototype._EnArray, |
|
de: exports.jspack.prototype._DeArray |
|
}, |
|
's': { |
|
en: exports.jspack.prototype._EnString, |
|
de: exports.jspack.prototype._DeString |
|
}, |
|
'c': { |
|
en: exports.jspack.prototype._EnChar, |
|
de: exports.jspack.prototype._DeChar |
|
}, |
|
'b': { |
|
en: exports.jspack.prototype._EnInt, |
|
de: exports.jspack.prototype._DeInt, |
|
len: 1, |
|
signed: true, |
|
min: -Math.pow(2, 7), |
|
max: Math.pow(2, 7) - 1 |
|
}, |
|
'B': { |
|
en: exports.jspack.prototype._EnInt, |
|
de: exports.jspack.prototype._DeInt, |
|
len: 1, |
|
signed: false, |
|
min: 0, |
|
max: Math.pow(2, 8) - 1 |
|
}, |
|
'h': { |
|
en: exports.jspack.prototype._EnInt, |
|
de: exports.jspack.prototype._DeInt, |
|
len: 2, |
|
signed: true, |
|
min: -Math.pow(2, 15), |
|
max: Math.pow(2, 15) - 1 |
|
}, |
|
'H': { |
|
en: exports.jspack.prototype._EnInt, |
|
de: exports.jspack.prototype._DeInt, |
|
len: 2, |
|
signed: false, |
|
min: 0, |
|
max: Math.pow(2, 16) - 1 |
|
}, |
|
'i': { |
|
en: exports.jspack.prototype._EnInt, |
|
de: exports.jspack.prototype._DeInt, |
|
len: 4, |
|
signed: true, |
|
min: -Math.pow(2, 31), |
|
max: Math.pow(2, 31) - 1 |
|
}, |
|
'I': { |
|
en: exports.jspack.prototype._EnInt, |
|
de: exports.jspack.prototype._DeInt, |
|
len: 4, |
|
signed: false, |
|
min: 0, |
|
max: Math.pow(2, 32) - 1 |
|
}, |
|
'l': { |
|
en: exports.jspack.prototype._EnInt, |
|
de: exports.jspack.prototype._DeInt, |
|
len: 4, |
|
signed: true, |
|
min: -Math.pow(2, 31), |
|
max: Math.pow(2, 31) - 1 |
|
}, |
|
'L': { |
|
en: exports.jspack.prototype._EnInt, |
|
de: exports.jspack.prototype._DeInt, |
|
len: 4, |
|
signed: false, |
|
min: 0, |
|
max: Math.pow(2, 32) - 1 |
|
}, |
|
'f': { |
|
en: exports.jspack.prototype._En754, |
|
de: exports.jspack.prototype._De754, |
|
len: 4, |
|
bit: 23, |
|
rt: Math.pow(2, -24) - Math.pow(2, -77) |
|
}, |
|
'd': { |
|
en: exports.jspack.prototype._En754, |
|
de: exports.jspack.prototype._De754, |
|
len: 8, |
|
bit: 52, |
|
rt: 0 |
|
} |
|
};
|
|
|