mirror of
https://github.com/fergalmoran/dss.git
synced 2026-01-04 16:04:35 +00:00
763 lines
21 KiB
JavaScript
763 lines
21 KiB
JavaScript
//
|
|
// jDataView by Vjeux <vjeuxx@gmail.com> - Jan 2010
|
|
// Continued by RReverser <me@rreverser.com> - Feb 2013
|
|
//
|
|
// A unique way to work with a binary file in the browser
|
|
// http://github.com/jDataView/jDataView
|
|
// http://jDataView.github.io/
|
|
|
|
(function (global) {
|
|
|
|
'use strict';
|
|
|
|
var compatibility = {
|
|
// NodeJS Buffer in v0.5.5 and newer
|
|
NodeBuffer: 'Buffer' in global && 'readInt16LE' in Buffer.prototype,
|
|
DataView: 'DataView' in global && (
|
|
'getFloat64' in DataView.prototype || // Chrome
|
|
'getFloat64' in new DataView(new ArrayBuffer(1)) // Node
|
|
),
|
|
ArrayBuffer: 'ArrayBuffer' in global,
|
|
PixelData: 'CanvasPixelArray' in global && 'ImageData' in global && 'document' in global
|
|
};
|
|
|
|
// we don't want to bother with old Buffer implementation
|
|
if (compatibility.NodeBuffer) {
|
|
(function (buffer) {
|
|
try {
|
|
buffer.writeFloatLE(Infinity, 0);
|
|
} catch (e) {
|
|
compatibility.NodeBuffer = false;
|
|
}
|
|
})(new Buffer(4));
|
|
}
|
|
|
|
if (compatibility.PixelData) {
|
|
var createPixelData = function (byteLength, buffer) {
|
|
var data = createPixelData.context2d.createImageData((byteLength + 3) / 4, 1).data;
|
|
data.byteLength = byteLength;
|
|
if (buffer !== undefined) {
|
|
for (var i = 0; i < byteLength; i++) {
|
|
data[i] = buffer[i];
|
|
}
|
|
}
|
|
return data;
|
|
};
|
|
createPixelData.context2d = document.createElement('canvas').getContext('2d');
|
|
}
|
|
|
|
var dataTypes = {
|
|
'Int8': 1,
|
|
'Int16': 2,
|
|
'Int32': 4,
|
|
'Uint8': 1,
|
|
'Uint16': 2,
|
|
'Uint32': 4,
|
|
'Float32': 4,
|
|
'Float64': 8
|
|
};
|
|
|
|
var nodeNaming = {
|
|
'Int8': 'Int8',
|
|
'Int16': 'Int16',
|
|
'Int32': 'Int32',
|
|
'Uint8': 'UInt8',
|
|
'Uint16': 'UInt16',
|
|
'Uint32': 'UInt32',
|
|
'Float32': 'Float',
|
|
'Float64': 'Double'
|
|
};
|
|
|
|
function arrayFrom(arrayLike, forceCopy) {
|
|
return (!forceCopy && (arrayLike instanceof Array)) ? arrayLike : Array.prototype.slice.call(arrayLike);
|
|
}
|
|
|
|
function defined(value, defaultValue) {
|
|
return value !== undefined ? value : defaultValue;
|
|
}
|
|
|
|
function jDataView(buffer, byteOffset, byteLength, littleEndian) {
|
|
/* jshint validthis:true */
|
|
|
|
if (buffer instanceof jDataView) {
|
|
var result = buffer.slice(byteOffset, byteOffset + byteLength);
|
|
result._littleEndian = defined(littleEndian, result._littleEndian);
|
|
return result;
|
|
}
|
|
|
|
if (!(this instanceof jDataView)) {
|
|
return new jDataView(buffer, byteOffset, byteLength, littleEndian);
|
|
}
|
|
|
|
this.buffer = buffer = jDataView.wrapBuffer(buffer);
|
|
|
|
// Check parameters and existing functionnalities
|
|
this._isArrayBuffer = compatibility.ArrayBuffer && buffer instanceof ArrayBuffer;
|
|
this._isPixelData = compatibility.PixelData && buffer instanceof CanvasPixelArray;
|
|
this._isDataView = compatibility.DataView && this._isArrayBuffer;
|
|
this._isNodeBuffer = compatibility.NodeBuffer && buffer instanceof Buffer;
|
|
|
|
// Handle Type Errors
|
|
if (!this._isNodeBuffer && !this._isArrayBuffer && !this._isPixelData && !(buffer instanceof Array)) {
|
|
throw new TypeError('jDataView buffer has an incompatible type');
|
|
}
|
|
|
|
// Default Values
|
|
this._littleEndian = !!littleEndian;
|
|
|
|
var bufferLength = 'byteLength' in buffer ? buffer.byteLength : buffer.length;
|
|
this.byteOffset = byteOffset = defined(byteOffset, 0);
|
|
this.byteLength = byteLength = defined(byteLength, bufferLength - byteOffset);
|
|
|
|
if (!this._isDataView) {
|
|
this._checkBounds(byteOffset, byteLength, bufferLength);
|
|
} else {
|
|
this._view = new DataView(buffer, byteOffset, byteLength);
|
|
}
|
|
|
|
// Create uniform methods (action wrappers) for the following data types
|
|
|
|
this._engineAction =
|
|
this._isDataView
|
|
? this._dataViewAction
|
|
: this._isNodeBuffer
|
|
? this._nodeBufferAction
|
|
: this._isArrayBuffer
|
|
? this._arrayBufferAction
|
|
: this._arrayAction;
|
|
}
|
|
|
|
function getCharCodes(string) {
|
|
if (compatibility.NodeBuffer) {
|
|
return new Buffer(string, 'binary');
|
|
}
|
|
|
|
var Type = compatibility.ArrayBuffer ? Uint8Array : Array,
|
|
codes = new Type(string.length);
|
|
|
|
for (var i = 0, length = string.length; i < length; i++) {
|
|
codes[i] = string.charCodeAt(i) & 0xff;
|
|
}
|
|
return codes;
|
|
}
|
|
|
|
// mostly internal function for wrapping any supported input (String or Array-like) to best suitable buffer format
|
|
jDataView.wrapBuffer = function (buffer) {
|
|
switch (typeof buffer) {
|
|
case 'number':
|
|
if (compatibility.NodeBuffer) {
|
|
buffer = new Buffer(buffer);
|
|
buffer.fill(0);
|
|
} else
|
|
if (compatibility.ArrayBuffer) {
|
|
buffer = new Uint8Array(buffer).buffer;
|
|
} else
|
|
if (compatibility.PixelData) {
|
|
buffer = createPixelData(buffer);
|
|
} else {
|
|
buffer = new Array(buffer);
|
|
for (var i = 0; i < buffer.length; i++) {
|
|
buffer[i] = 0;
|
|
}
|
|
}
|
|
return buffer;
|
|
|
|
case 'string':
|
|
buffer = getCharCodes(buffer);
|
|
/* falls through */
|
|
default:
|
|
if ('length' in buffer && !((compatibility.NodeBuffer && buffer instanceof Buffer) || (compatibility.ArrayBuffer && buffer instanceof ArrayBuffer) || (compatibility.PixelData && buffer instanceof CanvasPixelArray))) {
|
|
if (compatibility.NodeBuffer) {
|
|
buffer = new Buffer(buffer);
|
|
} else
|
|
if (compatibility.ArrayBuffer) {
|
|
if (!(buffer instanceof ArrayBuffer)) {
|
|
buffer = new Uint8Array(buffer).buffer;
|
|
// bug in Node.js <= 0.8:
|
|
if (!(buffer instanceof ArrayBuffer)) {
|
|
buffer = new Uint8Array(arrayFrom(buffer, true)).buffer;
|
|
}
|
|
}
|
|
} else
|
|
if (compatibility.PixelData) {
|
|
buffer = createPixelData(buffer.length, buffer);
|
|
} else {
|
|
buffer = arrayFrom(buffer);
|
|
}
|
|
}
|
|
return buffer;
|
|
}
|
|
};
|
|
|
|
function pow2(n) {
|
|
return (n >= 0 && n < 31) ? (1 << n) : (pow2[n] || (pow2[n] = Math.pow(2, n)));
|
|
}
|
|
|
|
// left for backward compatibility
|
|
jDataView.createBuffer = function () {
|
|
return jDataView.wrapBuffer(arguments);
|
|
};
|
|
|
|
function Uint64(lo, hi) {
|
|
this.lo = lo;
|
|
this.hi = hi;
|
|
}
|
|
|
|
jDataView.Uint64 = Uint64;
|
|
|
|
Uint64.prototype = {
|
|
valueOf: function () {
|
|
return this.lo + pow2(32) * this.hi;
|
|
},
|
|
|
|
toString: function () {
|
|
return Number.prototype.toString.apply(this.valueOf(), arguments);
|
|
}
|
|
};
|
|
|
|
Uint64.fromNumber = function (number) {
|
|
var hi = Math.floor(number / pow2(32)),
|
|
lo = number - hi * pow2(32);
|
|
|
|
return new Uint64(lo, hi);
|
|
};
|
|
|
|
function Int64(lo, hi) {
|
|
Uint64.apply(this, arguments);
|
|
}
|
|
|
|
jDataView.Int64 = Int64;
|
|
|
|
Int64.prototype = 'create' in Object ? Object.create(Uint64.prototype) : new Uint64();
|
|
|
|
Int64.prototype.valueOf = function () {
|
|
if (this.hi < pow2(31)) {
|
|
return Uint64.prototype.valueOf.apply(this, arguments);
|
|
}
|
|
return -((pow2(32) - this.lo) + pow2(32) * (pow2(32) - 1 - this.hi));
|
|
};
|
|
|
|
Int64.fromNumber = function (number) {
|
|
var lo, hi;
|
|
if (number >= 0) {
|
|
var unsigned = Uint64.fromNumber(number);
|
|
lo = unsigned.lo;
|
|
hi = unsigned.hi;
|
|
} else {
|
|
hi = Math.floor(number / pow2(32));
|
|
lo = number - hi * pow2(32);
|
|
hi += pow2(32);
|
|
}
|
|
return new Int64(lo, hi);
|
|
};
|
|
|
|
jDataView.prototype = {
|
|
_offset: 0,
|
|
_bitOffset: 0,
|
|
|
|
compatibility: compatibility,
|
|
|
|
_checkBounds: function (byteOffset, byteLength, maxLength) {
|
|
// Do additional checks to simulate DataView
|
|
if (typeof byteOffset !== 'number') {
|
|
throw new TypeError('Offset is not a number.');
|
|
}
|
|
if (typeof byteLength !== 'number') {
|
|
throw new TypeError('Size is not a number.');
|
|
}
|
|
if (byteLength < 0) {
|
|
throw new RangeError('Length is negative.');
|
|
}
|
|
if (byteOffset < 0 || byteOffset + byteLength > defined(maxLength, this.byteLength)) {
|
|
throw new RangeError('Offsets are out of bounds.');
|
|
}
|
|
},
|
|
|
|
_action: function (type, isReadAction, byteOffset, littleEndian, value) {
|
|
return this._engineAction(
|
|
type,
|
|
isReadAction,
|
|
defined(byteOffset, this._offset),
|
|
defined(littleEndian, this._littleEndian),
|
|
value
|
|
);
|
|
},
|
|
|
|
_dataViewAction: function (type, isReadAction, byteOffset, littleEndian, value) {
|
|
// Move the internal offset forward
|
|
this._offset = byteOffset + dataTypes[type];
|
|
return isReadAction ? this._view['get' + type](byteOffset, littleEndian) : this._view['set' + type](byteOffset, value, littleEndian);
|
|
},
|
|
|
|
_nodeBufferAction: function (type, isReadAction, byteOffset, littleEndian, value) {
|
|
// Move the internal offset forward
|
|
this._offset = byteOffset + dataTypes[type];
|
|
var nodeName = nodeNaming[type] + ((type === 'Int8' || type === 'Uint8') ? '' : littleEndian ? 'LE' : 'BE');
|
|
byteOffset += this.byteOffset;
|
|
return isReadAction ? this.buffer['read' + nodeName](byteOffset) : this.buffer['write' + nodeName](value, byteOffset);
|
|
},
|
|
|
|
_arrayBufferAction: function (type, isReadAction, byteOffset, littleEndian, value) {
|
|
var size = dataTypes[type], TypedArray = global[type + 'Array'], typedArray;
|
|
|
|
littleEndian = defined(littleEndian, this._littleEndian);
|
|
|
|
// ArrayBuffer: we use a typed array of size 1 from original buffer if alignment is good and from slice when it's not
|
|
if (size === 1 || ((this.byteOffset + byteOffset) % size === 0 && littleEndian)) {
|
|
typedArray = new TypedArray(this.buffer, this.byteOffset + byteOffset, 1);
|
|
this._offset = byteOffset + size;
|
|
return isReadAction ? typedArray[0] : (typedArray[0] = value);
|
|
} else {
|
|
var bytes = new Uint8Array(isReadAction ? this.getBytes(size, byteOffset, littleEndian, true) : size);
|
|
typedArray = new TypedArray(bytes.buffer, 0, 1);
|
|
|
|
if (isReadAction) {
|
|
return typedArray[0];
|
|
} else {
|
|
typedArray[0] = value;
|
|
this._setBytes(byteOffset, bytes, littleEndian);
|
|
}
|
|
}
|
|
},
|
|
|
|
_arrayAction: function (type, isReadAction, byteOffset, littleEndian, value) {
|
|
return isReadAction ? this['_get' + type](byteOffset, littleEndian) : this['_set' + type](byteOffset, value, littleEndian);
|
|
},
|
|
|
|
// Helpers
|
|
|
|
_getBytes: function (length, byteOffset, littleEndian) {
|
|
littleEndian = defined(littleEndian, this._littleEndian);
|
|
byteOffset = defined(byteOffset, this._offset);
|
|
length = defined(length, this.byteLength - byteOffset);
|
|
|
|
this._checkBounds(byteOffset, length);
|
|
|
|
byteOffset += this.byteOffset;
|
|
|
|
this._offset = byteOffset - this.byteOffset + length;
|
|
|
|
var result = this._isArrayBuffer
|
|
? new Uint8Array(this.buffer, byteOffset, length)
|
|
: (this.buffer.slice || Array.prototype.slice).call(this.buffer, byteOffset, byteOffset + length);
|
|
|
|
return littleEndian || length <= 1 ? result : arrayFrom(result).reverse();
|
|
},
|
|
|
|
// wrapper for external calls (do not return inner buffer directly to prevent it's modifying)
|
|
getBytes: function (length, byteOffset, littleEndian, toArray) {
|
|
var result = this._getBytes(length, byteOffset, defined(littleEndian, true));
|
|
return toArray ? arrayFrom(result) : result;
|
|
},
|
|
|
|
_setBytes: function (byteOffset, bytes, littleEndian) {
|
|
var length = bytes.length;
|
|
|
|
// needed for Opera
|
|
if (length === 0) {
|
|
return;
|
|
}
|
|
|
|
littleEndian = defined(littleEndian, this._littleEndian);
|
|
byteOffset = defined(byteOffset, this._offset);
|
|
|
|
this._checkBounds(byteOffset, length);
|
|
|
|
if (!littleEndian && length > 1) {
|
|
bytes = arrayFrom(bytes, true).reverse();
|
|
}
|
|
|
|
byteOffset += this.byteOffset;
|
|
|
|
if (this._isArrayBuffer) {
|
|
new Uint8Array(this.buffer, byteOffset, length).set(bytes);
|
|
}
|
|
else {
|
|
if (this._isNodeBuffer) {
|
|
new Buffer(bytes).copy(this.buffer, byteOffset);
|
|
} else {
|
|
for (var i = 0; i < length; i++) {
|
|
this.buffer[byteOffset + i] = bytes[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
this._offset = byteOffset - this.byteOffset + length;
|
|
},
|
|
|
|
setBytes: function (byteOffset, bytes, littleEndian) {
|
|
this._setBytes(byteOffset, bytes, defined(littleEndian, true));
|
|
},
|
|
|
|
getString: function (byteLength, byteOffset, encoding) {
|
|
if (this._isNodeBuffer) {
|
|
byteOffset = defined(byteOffset, this._offset);
|
|
byteLength = defined(byteLength, this.byteLength - byteOffset);
|
|
|
|
this._checkBounds(byteOffset, byteLength);
|
|
|
|
this._offset = byteOffset + byteLength;
|
|
return this.buffer.toString(encoding || 'binary', this.byteOffset + byteOffset, this.byteOffset + this._offset);
|
|
}
|
|
var bytes = this._getBytes(byteLength, byteOffset, true), string = '';
|
|
byteLength = bytes.length;
|
|
for (var i = 0; i < byteLength; i++) {
|
|
string += String.fromCharCode(bytes[i]);
|
|
}
|
|
if (encoding === 'utf8') {
|
|
string = decodeURIComponent(escape(string));
|
|
}
|
|
return string;
|
|
},
|
|
|
|
setString: function (byteOffset, subString, encoding) {
|
|
if (this._isNodeBuffer) {
|
|
byteOffset = defined(byteOffset, this._offset);
|
|
this._checkBounds(byteOffset, subString.length);
|
|
this._offset = byteOffset + this.buffer.write(subString, this.byteOffset + byteOffset, encoding || 'binary');
|
|
return;
|
|
}
|
|
if (encoding === 'utf8') {
|
|
subString = unescape(encodeURIComponent(subString));
|
|
}
|
|
this._setBytes(byteOffset, getCharCodes(subString), true);
|
|
},
|
|
|
|
getChar: function (byteOffset) {
|
|
return this.getString(1, byteOffset);
|
|
},
|
|
|
|
setChar: function (byteOffset, character) {
|
|
this.setString(byteOffset, character);
|
|
},
|
|
|
|
tell: function () {
|
|
return this._offset;
|
|
},
|
|
|
|
seek: function (byteOffset) {
|
|
this._checkBounds(byteOffset, 0);
|
|
/* jshint boss: true */
|
|
return this._offset = byteOffset;
|
|
},
|
|
|
|
skip: function (byteLength) {
|
|
return this.seek(this._offset + byteLength);
|
|
},
|
|
|
|
slice: function (start, end, forceCopy) {
|
|
function normalizeOffset(offset, byteLength) {
|
|
return offset < 0 ? offset + byteLength : offset;
|
|
}
|
|
|
|
start = normalizeOffset(start, this.byteLength);
|
|
end = normalizeOffset(defined(end, this.byteLength), this.byteLength);
|
|
|
|
return forceCopy
|
|
? new jDataView(this.getBytes(end - start, start, true, true), undefined, undefined, this._littleEndian)
|
|
: new jDataView(this.buffer, this.byteOffset + start, end - start, this._littleEndian);
|
|
},
|
|
|
|
alignBy: function (byteCount) {
|
|
this._bitOffset = 0;
|
|
if (defined(byteCount, 1) !== 1) {
|
|
return this.skip(byteCount - (this._offset % byteCount || byteCount));
|
|
} else {
|
|
return this._offset;
|
|
}
|
|
},
|
|
|
|
// Compatibility functions
|
|
|
|
_getFloat64: function (byteOffset, littleEndian) {
|
|
var b = this._getBytes(8, byteOffset, littleEndian),
|
|
|
|
sign = 1 - (2 * (b[7] >> 7)),
|
|
exponent = ((((b[7] << 1) & 0xff) << 3) | (b[6] >> 4)) - ((1 << 10) - 1),
|
|
|
|
// Binary operators such as | and << operate on 32 bit values, using + and Math.pow(2) instead
|
|
mantissa = ((b[6] & 0x0f) * pow2(48)) + (b[5] * pow2(40)) + (b[4] * pow2(32)) +
|
|
(b[3] * pow2(24)) + (b[2] * pow2(16)) + (b[1] * pow2(8)) + b[0];
|
|
|
|
if (exponent === 1024) {
|
|
if (mantissa !== 0) {
|
|
return NaN;
|
|
} else {
|
|
return sign * Infinity;
|
|
}
|
|
}
|
|
|
|
if (exponent === -1023) { // Denormalized
|
|
return sign * mantissa * pow2(-1022 - 52);
|
|
}
|
|
|
|
return sign * (1 + mantissa * pow2(-52)) * pow2(exponent);
|
|
},
|
|
|
|
_getFloat32: function (byteOffset, littleEndian) {
|
|
var b = this._getBytes(4, byteOffset, littleEndian),
|
|
|
|
sign = 1 - (2 * (b[3] >> 7)),
|
|
exponent = (((b[3] << 1) & 0xff) | (b[2] >> 7)) - 127,
|
|
mantissa = ((b[2] & 0x7f) << 16) | (b[1] << 8) | b[0];
|
|
|
|
if (exponent === 128) {
|
|
if (mantissa !== 0) {
|
|
return NaN;
|
|
} else {
|
|
return sign * Infinity;
|
|
}
|
|
}
|
|
|
|
if (exponent === -127) { // Denormalized
|
|
return sign * mantissa * pow2(-126 - 23);
|
|
}
|
|
|
|
return sign * (1 + mantissa * pow2(-23)) * pow2(exponent);
|
|
},
|
|
|
|
_get64: function (Type, byteOffset, littleEndian) {
|
|
littleEndian = defined(littleEndian, this._littleEndian);
|
|
byteOffset = defined(byteOffset, this._offset);
|
|
|
|
var parts = littleEndian ? [0, 4] : [4, 0];
|
|
|
|
for (var i = 0; i < 2; i++) {
|
|
parts[i] = this.getUint32(byteOffset + parts[i], littleEndian);
|
|
}
|
|
|
|
this._offset = byteOffset + 8;
|
|
|
|
return new Type(parts[0], parts[1]);
|
|
},
|
|
|
|
getInt64: function (byteOffset, littleEndian) {
|
|
return this._get64(Int64, byteOffset, littleEndian);
|
|
},
|
|
|
|
getUint64: function (byteOffset, littleEndian) {
|
|
return this._get64(Uint64, byteOffset, littleEndian);
|
|
},
|
|
|
|
_getInt32: function (byteOffset, littleEndian) {
|
|
var b = this._getBytes(4, byteOffset, littleEndian);
|
|
return (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0];
|
|
},
|
|
|
|
_getUint32: function (byteOffset, littleEndian) {
|
|
return this._getInt32(byteOffset, littleEndian) >>> 0;
|
|
},
|
|
|
|
_getInt16: function (byteOffset, littleEndian) {
|
|
return (this._getUint16(byteOffset, littleEndian) << 16) >> 16;
|
|
},
|
|
|
|
_getUint16: function (byteOffset, littleEndian) {
|
|
var b = this._getBytes(2, byteOffset, littleEndian);
|
|
return (b[1] << 8) | b[0];
|
|
},
|
|
|
|
_getInt8: function (byteOffset) {
|
|
return (this._getUint8(byteOffset) << 24) >> 24;
|
|
},
|
|
|
|
_getUint8: function (byteOffset) {
|
|
return this._getBytes(1, byteOffset)[0];
|
|
},
|
|
|
|
_getBitRangeData: function (bitLength, byteOffset) {
|
|
var startBit = (defined(byteOffset, this._offset) << 3) + this._bitOffset,
|
|
endBit = startBit + bitLength,
|
|
start = startBit >>> 3,
|
|
end = (endBit + 7) >>> 3,
|
|
b = this._getBytes(end - start, start, true),
|
|
wideValue = 0;
|
|
|
|
/* jshint boss: true */
|
|
if (this._bitOffset = endBit & 7) {
|
|
this._bitOffset -= 8;
|
|
}
|
|
|
|
for (var i = 0, length = b.length; i < length; i++) {
|
|
wideValue = (wideValue << 8) | b[i];
|
|
}
|
|
|
|
return {
|
|
start: start,
|
|
bytes: b,
|
|
wideValue: wideValue
|
|
};
|
|
},
|
|
|
|
getSigned: function (bitLength, byteOffset) {
|
|
var shift = 32 - bitLength;
|
|
return (this.getUnsigned(bitLength, byteOffset) << shift) >> shift;
|
|
},
|
|
|
|
getUnsigned: function (bitLength, byteOffset) {
|
|
var value = this._getBitRangeData(bitLength, byteOffset).wideValue >>> -this._bitOffset;
|
|
return bitLength < 32 ? (value & ~(-1 << bitLength)) : value;
|
|
},
|
|
|
|
_setBinaryFloat: function (byteOffset, value, mantSize, expSize, littleEndian) {
|
|
var signBit = value < 0 ? 1 : 0,
|
|
exponent,
|
|
mantissa,
|
|
eMax = ~(-1 << (expSize - 1)),
|
|
eMin = 1 - eMax;
|
|
|
|
if (value < 0) {
|
|
value = -value;
|
|
}
|
|
|
|
if (value === 0) {
|
|
exponent = 0;
|
|
mantissa = 0;
|
|
} else if (isNaN(value)) {
|
|
exponent = 2 * eMax + 1;
|
|
mantissa = 1;
|
|
} else if (value === Infinity) {
|
|
exponent = 2 * eMax + 1;
|
|
mantissa = 0;
|
|
} else {
|
|
exponent = Math.floor(Math.log(value) / Math.LN2);
|
|
if (exponent >= eMin && exponent <= eMax) {
|
|
mantissa = Math.floor((value * pow2(-exponent) - 1) * pow2(mantSize));
|
|
exponent += eMax;
|
|
} else {
|
|
mantissa = Math.floor(value / pow2(eMin - mantSize));
|
|
exponent = 0;
|
|
}
|
|
}
|
|
|
|
var b = [];
|
|
while (mantSize >= 8) {
|
|
b.push(mantissa % 256);
|
|
mantissa = Math.floor(mantissa / 256);
|
|
mantSize -= 8;
|
|
}
|
|
exponent = (exponent << mantSize) | mantissa;
|
|
expSize += mantSize;
|
|
while (expSize >= 8) {
|
|
b.push(exponent & 0xff);
|
|
exponent >>>= 8;
|
|
expSize -= 8;
|
|
}
|
|
b.push((signBit << expSize) | exponent);
|
|
|
|
this._setBytes(byteOffset, b, littleEndian);
|
|
},
|
|
|
|
_setFloat32: function (byteOffset, value, littleEndian) {
|
|
this._setBinaryFloat(byteOffset, value, 23, 8, littleEndian);
|
|
},
|
|
|
|
_setFloat64: function (byteOffset, value, littleEndian) {
|
|
this._setBinaryFloat(byteOffset, value, 52, 11, littleEndian);
|
|
},
|
|
|
|
_set64: function (Type, byteOffset, value, littleEndian) {
|
|
if (!(value instanceof Type)) {
|
|
value = Type.fromNumber(value);
|
|
}
|
|
|
|
littleEndian = defined(littleEndian, this._littleEndian);
|
|
byteOffset = defined(byteOffset, this._offset);
|
|
|
|
var parts = littleEndian ? {lo: 0, hi: 4} : {lo: 4, hi: 0};
|
|
|
|
for (var partName in parts) {
|
|
this.setUint32(byteOffset + parts[partName], value[partName], littleEndian);
|
|
}
|
|
|
|
this._offset = byteOffset + 8;
|
|
},
|
|
|
|
setInt64: function (byteOffset, value, littleEndian) {
|
|
this._set64(Int64, byteOffset, value, littleEndian);
|
|
},
|
|
|
|
setUint64: function (byteOffset, value, littleEndian) {
|
|
this._set64(Uint64, byteOffset, value, littleEndian);
|
|
},
|
|
|
|
_setUint32: function (byteOffset, value, littleEndian) {
|
|
this._setBytes(byteOffset, [
|
|
value & 0xff,
|
|
(value >>> 8) & 0xff,
|
|
(value >>> 16) & 0xff,
|
|
value >>> 24
|
|
], littleEndian);
|
|
},
|
|
|
|
_setUint16: function (byteOffset, value, littleEndian) {
|
|
this._setBytes(byteOffset, [
|
|
value & 0xff,
|
|
(value >>> 8) & 0xff
|
|
], littleEndian);
|
|
},
|
|
|
|
_setUint8: function (byteOffset, value) {
|
|
this._setBytes(byteOffset, [value & 0xff]);
|
|
},
|
|
|
|
setUnsigned: function (byteOffset, value, bitLength) {
|
|
var data = this._getBitRangeData(bitLength, byteOffset),
|
|
wideValue = data.wideValue,
|
|
b = data.bytes;
|
|
|
|
wideValue &= ~(~(-1 << bitLength) << -this._bitOffset); // clearing bit range before binary "or"
|
|
wideValue |= (bitLength < 32 ? (value & ~(-1 << bitLength)) : value) << -this._bitOffset; // setting bits
|
|
|
|
for (var i = b.length - 1; i >= 0; i--) {
|
|
b[i] = wideValue & 0xff;
|
|
wideValue >>>= 8;
|
|
}
|
|
|
|
this._setBytes(data.start, b, true);
|
|
}
|
|
};
|
|
|
|
var proto = jDataView.prototype;
|
|
|
|
for (var type in dataTypes) {
|
|
(function (type) {
|
|
proto['get' + type] = function (byteOffset, littleEndian) {
|
|
return this._action(type, true, byteOffset, littleEndian);
|
|
};
|
|
proto['set' + type] = function (byteOffset, value, littleEndian) {
|
|
this._action(type, false, byteOffset, littleEndian, value);
|
|
};
|
|
})(type);
|
|
}
|
|
|
|
proto._setInt32 = proto._setUint32;
|
|
proto._setInt16 = proto._setUint16;
|
|
proto._setInt8 = proto._setUint8;
|
|
proto.setSigned = proto.setUnsigned;
|
|
|
|
for (var method in proto) {
|
|
if (method.slice(0, 3) === 'set') {
|
|
(function (type) {
|
|
proto['write' + type] = function () {
|
|
Array.prototype.unshift.call(arguments, undefined);
|
|
this['set' + type].apply(this, arguments);
|
|
};
|
|
})(method.slice(3));
|
|
}
|
|
}
|
|
|
|
if (typeof module !== 'undefined' && typeof module.exports === 'object') {
|
|
module.exports = jDataView;
|
|
} else
|
|
if (typeof define === 'function' && define.amd) {
|
|
define([], function () { return jDataView });
|
|
} else {
|
|
var oldGlobal = global.jDataView;
|
|
(global.jDataView = jDataView).noConflict = function () {
|
|
global.jDataView = oldGlobal;
|
|
return this;
|
|
};
|
|
}
|
|
|
|
})((function () { /* jshint strict: false */ return this })()); |