1 var undefined = (void 0); // Paranoia
3 // Beyond this value, index getters/setters (i.e. array[0], array[1]) are so slow to
4 // create, and consume so much memory, that the browser appears frozen.
5 var MAX_ARRAY_LENGTH
= 1e5
;
7 // Approximations of internal ECMAScript conversion functions
8 var ECMAScript
= (function() {
9 // Stash a copy in case other scripts modify these
10 var opts
= Object
.prototype.toString
,
11 ophop
= Object
.prototype.hasOwnProperty
;
14 // Class returns internal [[Class]] property, used to avoid cross-frame instanceof issues:
15 Class: function(v
) { return opts
.call(v
).replace(/^\[object *|\]$/g, ''); },
16 HasProperty: function(o
, p
) { return p
in o
; },
17 HasOwnProperty: function(o
, p
) { return ophop
.call(o
, p
); },
18 IsCallable: function(o
) { return typeof o
=== 'function'; },
19 ToInt32: function(v
) { return v
>> 0; },
20 ToUint32: function(v
) { return v
>>> 0; }
24 // Snapshot intrinsics
33 // ES5: lock down object properties
34 function configureProperties(obj
) {
35 if (getOwnPropNames
&& defineProp
) {
36 var props
= getOwnPropNames(obj
), i
;
37 for (i
= 0; i
< props
.length
; i
+= 1) {
38 defineProp(obj
, props
[i
], {
48 // emulate ES5 getter/setter API using legacy APIs
49 // http://blogs.msdn.com/b/ie/archive/2010/09/07/transitioning-existing-code-to-the-es5-getter-setter-apis.aspx
50 // (second clause tests for Object.defineProperty() in IE<9 that only supports extending DOM prototypes, but
51 // note that IE<9 does not support __defineGetter__ or __defineSetter__ so it just renders the method harmless)
53 if (Object
.defineProperty
&& (function() {
55 Object
.defineProperty({}, 'x', {});
61 defineProp
= Object
.defineProperty
;
63 defineProp = function(o
, p
, desc
) {
64 if (!o
=== Object(o
)) throw new TypeError("Object.defineProperty called on non-object");
65 if (ECMAScript
.HasProperty(desc
, 'get') && Object
.prototype.__defineGetter__
) { Object
.prototype.__defineGetter__
.call(o
, p
, desc
.get); }
66 if (ECMAScript
.HasProperty(desc
, 'set') && Object
.prototype.__defineSetter__
) { Object
.prototype.__defineSetter__
.call(o
, p
, desc
.set); }
67 if (ECMAScript
.HasProperty(desc
, 'value')) { o
[p
] = desc
.value
; }
72 var getOwnPropNames
= Object
.getOwnPropertyNames
|| function (o
) {
73 if (o
!== Object(o
)) throw new TypeError("Object.getOwnPropertyNames called on non-object");
76 if (ECMAScript
.HasOwnProperty(o
, p
)) {
83 // ES5: Make obj[index] an alias for obj._getter(index)/obj._setter(index, value)
84 // for index in 0 ... obj.length
85 function makeArrayAccessors(obj
) {
86 if (!defineProp
) { return; }
88 if (obj
.length
> MAX_ARRAY_LENGTH
) throw new RangeError("Array too large for polyfill");
90 function makeArrayAccessor(index
) {
91 defineProp(obj
, index
, {
92 'get': function() { return obj
._getter(index
); },
93 'set': function(v
) { obj
._setter(index
, v
); },
100 for (i
= 0; i
< obj
.length
; i
+= 1) {
101 makeArrayAccessor(i
);
105 // Internal conversion functions:
106 // pack<Type>() - take a number (interpreted as Type), output a byte array
107 // unpack<Type>() - take a byte array, output a Type-like number
109 function as_signed(value
, bits
) { var s
= 32 - bits
; return (value
<< s
) >> s
; }
110 function as_unsigned(value
, bits
) { var s
= 32 - bits
; return (value
<< s
) >>> s
; }
112 function packI8(n
) { return [n
& 0xff]; }
113 function unpackI8(bytes
) { return as_signed(bytes
[0], 8); }
115 function packU8(n
) { return [n
& 0xff]; }
116 function unpackU8(bytes
) { return as_unsigned(bytes
[0], 8); }
118 function packU8Clamped(n
) { n
= round(Number(n
)); return [n
< 0 ? 0 : n
> 0xff ? 0xff : n
& 0xff]; }
120 function packI16(n
) { return [(n
>> 8) & 0xff, n
& 0xff]; }
121 function unpackI16(bytes
) { return as_signed(bytes
[0] << 8 | bytes
[1], 16); }
123 function packU16(n
) { return [(n
>> 8) & 0xff, n
& 0xff]; }
124 function unpackU16(bytes
) { return as_unsigned(bytes
[0] << 8 | bytes
[1], 16); }
126 function packI32(n
) { return [(n
>> 24) & 0xff, (n
>> 16) & 0xff, (n
>> 8) & 0xff, n
& 0xff]; }
127 function unpackI32(bytes
) { return as_signed(bytes
[0] << 24 | bytes
[1] << 16 | bytes
[2] << 8 | bytes
[3], 32); }
129 function packU32(n
) { return [(n
>> 24) & 0xff, (n
>> 16) & 0xff, (n
>> 8) & 0xff, n
& 0xff]; }
130 function unpackU32(bytes
) { return as_unsigned(bytes
[0] << 24 | bytes
[1] << 16 | bytes
[2] << 8 | bytes
[3], 32); }
132 function packIEEE754(v
, ebits
, fbits
) {
134 var bias
= (1 << (ebits
- 1)) - 1,
138 function roundToEven(n
) {
139 var w
= floor(n
), f
= n
- w
;
144 return w
% 2 ? w
+ 1 : w
;
147 // Compute sign, exponent, fraction
150 // http://dev.w3.org/2006/webapi/WebIDL/#es-type-mapping
151 e
= (1 << ebits
) - 1; f
= pow(2, fbits
- 1); s
= 0;
152 } else if (v
=== Infinity
|| v
=== -Infinity
) {
153 e
= (1 << ebits
) - 1; f
= 0; s
= (v
< 0) ? 1 : 0;
154 } else if (v
=== 0) {
155 e
= 0; f
= 0; s
= (1 / v
=== -Infinity
) ? 1 : 0;
160 if (v
>= pow(2, 1 - bias
)) {
161 e
= min(floor(log(v
) / LN2
), 1023);
162 f
= roundToEven(v
/ pow(2, e
) * pow(2, fbits
));
163 if (f
/ pow(2, fbits
) >= 2) {
169 e
= (1 << ebits
) - 1;
174 f
= f
- pow(2, fbits
);
179 f
= roundToEven(v
/ pow(2, 1 - bias
- fbits
));
183 // Pack sign, exponent, fraction
185 for (i
= fbits
; i
; i
-= 1) { bits
.push(f
% 2 ? 1 : 0); f
= floor(f
/ 2); }
186 for (i
= ebits
; i
; i
-= 1) { bits
.push(e
% 2 ? 1 : 0); e
= floor(e
/ 2); }
187 bits
.push(s
? 1 : 0);
194 bytes
.push(parseInt(str
.substring(0, 8), 2));
195 str
= str
.substring(8);
200 function unpackIEEE754(bytes
, ebits
, fbits
) {
203 var bits
= [], i
, j
, b
, str
,
206 for (i
= bytes
.length
; i
; i
-= 1) {
208 for (j
= 8; j
; j
-= 1) {
209 bits
.push(b
% 2 ? 1 : 0); b
= b
>> 1;
215 // Unpack sign, exponent, fraction
216 bias
= (1 << (ebits
- 1)) - 1;
217 s
= parseInt(str
.substring(0, 1), 2) ? -1 : 1;
218 e
= parseInt(str
.substring(1, 1 + ebits
), 2);
219 f
= parseInt(str
.substring(1 + ebits
), 2);
222 if (e
=== (1 << ebits
) - 1) {
223 return f
!== 0 ? NaN
: s
* Infinity
;
226 return s
* pow(2, e
- bias
) * (1 + f
/ pow(2, fbits
));
227 } else if (f
!== 0) {
229 return s
* pow(2, -(bias
- 1)) * (f
/ pow(2, fbits
));
231 return s
< 0 ? -0 : 0;
235 function unpackF64(b
) { return unpackIEEE754(b
, 11, 52); }
236 function packF64(v
) { return packIEEE754(v
, 11, 52); }
237 function unpackF32(b
) { return unpackIEEE754(b
, 8, 23); }
238 function packF32(v
) { return packIEEE754(v
, 8, 23); }
242 // 3 The ArrayBuffer Type
248 var ArrayBuffer
= function ArrayBuffer(length
) {
249 length
= ECMAScript
.ToInt32(length
);
250 if (length
< 0) throw new RangeError('ArrayBuffer size is not a small enough positive integer');
252 this.byteLength
= length
;
254 this._bytes
.length
= length
;
257 for (i
= 0; i
< this.byteLength
; i
+= 1) {
261 configureProperties(this);
264 exports
.ArrayBuffer
= exports
.ArrayBuffer
|| ArrayBuffer
;
267 // 4 The ArrayBufferView Type
270 // NOTE: this constructor is not exported
272 var ArrayBufferView
= function ArrayBufferView() {
273 //this.buffer = null;
274 //this.byteOffset = 0;
275 //this.byteLength = 0;
279 // 5 The Typed Array View Types
282 function makeConstructor(bytesPerElement
, pack
, unpack
) {
283 // Each TypedArray type requires a distinct constructor instance with
284 // identical logic, which this produces.
287 ctor = function(buffer
, byteOffset
, length
) {
288 var array
, sequence
, i
, s
;
290 if (!arguments
.length
|| typeof arguments
[0] === 'number') {
291 // Constructor(unsigned long length)
292 this.length
= ECMAScript
.ToInt32(arguments
[0]);
293 if (length
< 0) throw new RangeError('ArrayBufferView size is not a small enough positive integer');
295 this.byteLength
= this.length
* this.BYTES_PER_ELEMENT
;
296 this.buffer
= new ArrayBuffer(this.byteLength
);
298 } else if (typeof arguments
[0] === 'object' && arguments
[0].constructor === ctor
) {
299 // Constructor(TypedArray array)
300 array
= arguments
[0];
302 this.length
= array
.length
;
303 this.byteLength
= this.length
* this.BYTES_PER_ELEMENT
;
304 this.buffer
= new ArrayBuffer(this.byteLength
);
307 for (i
= 0; i
< this.length
; i
+= 1) {
308 this._setter(i
, array
._getter(i
));
310 } else if (typeof arguments
[0] === 'object' &&
311 !(arguments
[0] instanceof ArrayBuffer
|| ECMAScript
.Class(arguments
[0]) === 'ArrayBuffer')) {
312 // Constructor(sequence<type> array)
313 sequence
= arguments
[0];
315 this.length
= ECMAScript
.ToUint32(sequence
.length
);
316 this.byteLength
= this.length
* this.BYTES_PER_ELEMENT
;
317 this.buffer
= new ArrayBuffer(this.byteLength
);
320 for (i
= 0; i
< this.length
; i
+= 1) {
322 this._setter(i
, Number(s
));
324 } else if (typeof arguments
[0] === 'object' &&
325 (arguments
[0] instanceof ArrayBuffer
|| ECMAScript
.Class(arguments
[0]) === 'ArrayBuffer')) {
326 // Constructor(ArrayBuffer buffer,
327 // optional unsigned long byteOffset, optional unsigned long length)
328 this.buffer
= buffer
;
330 this.byteOffset
= ECMAScript
.ToUint32(byteOffset
);
331 if (this.byteOffset
> this.buffer
.byteLength
) {
332 throw new RangeError("byteOffset out of range");
335 if (this.byteOffset
% this.BYTES_PER_ELEMENT
) {
336 // The given byteOffset must be a multiple of the element
337 // size of the specific type, otherwise an exception is raised.
338 throw new RangeError("ArrayBuffer length minus the byteOffset is not a multiple of the element size.");
341 if (arguments
.length
< 3) {
342 this.byteLength
= this.buffer
.byteLength
- this.byteOffset
;
344 if (this.byteLength
% this.BYTES_PER_ELEMENT
) {
345 throw new RangeError("length of buffer minus byteOffset not a multiple of the element size");
347 this.length
= this.byteLength
/ this.BYTES_PER_ELEMENT
;
349 this.length
= ECMAScript
.ToUint32(length
);
350 this.byteLength
= this.length
* this.BYTES_PER_ELEMENT
;
353 if ((this.byteOffset
+ this.byteLength
) > this.buffer
.byteLength
) {
354 throw new RangeError("byteOffset and length reference an area beyond the end of the buffer");
357 throw new TypeError("Unexpected argument type(s)");
360 this.constructor = ctor
;
362 configureProperties(this);
363 makeArrayAccessors(this);
366 ctor
.prototype = new ArrayBufferView();
367 ctor
.prototype.BYTES_PER_ELEMENT
= bytesPerElement
;
368 ctor
.prototype._pack
= pack
;
369 ctor
.prototype._unpack
= unpack
;
370 ctor
.BYTES_PER_ELEMENT
= bytesPerElement
;
372 // getter type (unsigned long index);
373 ctor
.prototype._getter = function(index
) {
374 if (arguments
.length
< 1) throw new SyntaxError("Not enough arguments");
376 index
= ECMAScript
.ToUint32(index
);
377 if (index
>= this.length
) {
381 var bytes
= [], i
, o
;
382 for (i
= 0, o
= this.byteOffset
+ index
* this.BYTES_PER_ELEMENT
;
383 i
< this.BYTES_PER_ELEMENT
;
385 bytes
.push(this.buffer
._bytes
[o
]);
387 return this._unpack(bytes
);
390 // NONSTANDARD: convenience alias for getter: type get(unsigned long index);
391 ctor
.prototype.get = ctor
.prototype._getter
;
393 // setter void (unsigned long index, type value);
394 ctor
.prototype._setter = function(index
, value
) {
395 if (arguments
.length
< 2) throw new SyntaxError("Not enough arguments");
397 index
= ECMAScript
.ToUint32(index
);
398 if (index
>= this.length
) {
402 var bytes
= this._pack(value
), i
, o
;
403 for (i
= 0, o
= this.byteOffset
+ index
* this.BYTES_PER_ELEMENT
;
404 i
< this.BYTES_PER_ELEMENT
;
406 this.buffer
._bytes
[o
] = bytes
[i
];
410 // void set(TypedArray array, optional unsigned long offset);
411 // void set(sequence<type> array, optional unsigned long offset);
412 ctor
.prototype.set = function(index
, value
) {
413 if (arguments
.length
< 1) throw new SyntaxError("Not enough arguments");
414 var array
, sequence
, offset
, len
,
416 byteOffset
, byteLength
, tmp
;
418 if (typeof arguments
[0] === 'object' && arguments
[0].constructor === this.constructor) {
419 // void set(TypedArray array, optional unsigned long offset);
420 array
= arguments
[0];
421 offset
= ECMAScript
.ToUint32(arguments
[1]);
423 if (offset
+ array
.length
> this.length
) {
424 throw new RangeError("Offset plus length of array is out of range");
427 byteOffset
= this.byteOffset
+ offset
* this.BYTES_PER_ELEMENT
;
428 byteLength
= array
.length
* this.BYTES_PER_ELEMENT
;
430 if (array
.buffer
=== this.buffer
) {
432 for (i
= 0, s
= array
.byteOffset
; i
< byteLength
; i
+= 1, s
+= 1) {
433 tmp
[i
] = array
.buffer
._bytes
[s
];
435 for (i
= 0, d
= byteOffset
; i
< byteLength
; i
+= 1, d
+= 1) {
436 this.buffer
._bytes
[d
] = tmp
[i
];
439 for (i
= 0, s
= array
.byteOffset
, d
= byteOffset
;
440 i
< byteLength
; i
+= 1, s
+= 1, d
+= 1) {
441 this.buffer
._bytes
[d
] = array
.buffer
._bytes
[s
];
444 } else if (typeof arguments
[0] === 'object' && typeof arguments
[0].length
!== 'undefined') {
445 // void set(sequence<type> array, optional unsigned long offset);
446 sequence
= arguments
[0];
447 len
= ECMAScript
.ToUint32(sequence
.length
);
448 offset
= ECMAScript
.ToUint32(arguments
[1]);
450 if (offset
+ len
> this.length
) {
451 throw new RangeError("Offset plus length of array is out of range");
454 for (i
= 0; i
< len
; i
+= 1) {
456 this._setter(offset
+ i
, Number(s
));
459 throw new TypeError("Unexpected argument type(s)");
463 // TypedArray subarray(long begin, optional long end);
464 ctor
.prototype.subarray = function(start
, end
) {
465 function clamp(v
, min
, max
) { return v
< min
? min
: v
> max
? max
: v
; }
467 start
= ECMAScript
.ToInt32(start
);
468 end
= ECMAScript
.ToInt32(end
);
470 if (arguments
.length
< 1) { start
= 0; }
471 if (arguments
.length
< 2) { end
= this.length
; }
473 if (start
< 0) { start
= this.length
+ start
; }
474 if (end
< 0) { end
= this.length
+ end
; }
476 start
= clamp(start
, 0, this.length
);
477 end
= clamp(end
, 0, this.length
);
479 var len
= end
- start
;
484 return new this.constructor(
485 this.buffer
, this.byteOffset
+ start
* this.BYTES_PER_ELEMENT
, len
);
491 var Int8Array
= makeConstructor(1, packI8
, unpackI8
);
492 var Uint8Array
= makeConstructor(1, packU8
, unpackU8
);
493 var Uint8ClampedArray
= makeConstructor(1, packU8Clamped
, unpackU8
);
494 var Int16Array
= makeConstructor(2, packI16
, unpackI16
);
495 var Uint16Array
= makeConstructor(2, packU16
, unpackU16
);
496 var Int32Array
= makeConstructor(4, packI32
, unpackI32
);
497 var Uint32Array
= makeConstructor(4, packU32
, unpackU32
);
498 var Float32Array
= makeConstructor(4, packF32
, unpackF32
);
499 var Float64Array
= makeConstructor(8, packF64
, unpackF64
);
501 exports
.Int8Array
= exports
.Int8Array
|| Int8Array
;
502 exports
.Uint8Array
= exports
.Uint8Array
|| Uint8Array
;
503 exports
.Uint8ClampedArray
= exports
.Uint8ClampedArray
|| Uint8ClampedArray
;
504 exports
.Int16Array
= exports
.Int16Array
|| Int16Array
;
505 exports
.Uint16Array
= exports
.Uint16Array
|| Uint16Array
;
506 exports
.Int32Array
= exports
.Int32Array
|| Int32Array
;
507 exports
.Uint32Array
= exports
.Uint32Array
|| Uint32Array
;
508 exports
.Float32Array
= exports
.Float32Array
|| Float32Array
;
509 exports
.Float64Array
= exports
.Float64Array
|| Float64Array
;
513 // 6 The DataView View Type
517 function r(array
, index
) {
518 return ECMAScript
.IsCallable(array
.get) ? array
.get(index
) : array
[index
];
521 var IS_BIG_ENDIAN
= (function() {
522 var u16array
= new(exports
.Uint16Array
)([0x1234]),
523 u8array
= new(exports
.Uint8Array
)(u16array
.buffer
);
524 return r(u8array
, 0) === 0x12;
527 // Constructor(ArrayBuffer buffer,
528 // optional unsigned long byteOffset,
529 // optional unsigned long byteLength)
531 var DataView
= function DataView(buffer
, byteOffset
, byteLength
) {
532 if (arguments
.length
=== 0) {
533 buffer
= new exports
.ArrayBuffer(0);
534 } else if (!(buffer
instanceof exports
.ArrayBuffer
|| ECMAScript
.Class(buffer
) === 'ArrayBuffer')) {
535 throw new TypeError("TypeError");
538 this.buffer
= buffer
|| new exports
.ArrayBuffer(0);
540 this.byteOffset
= ECMAScript
.ToUint32(byteOffset
);
541 if (this.byteOffset
> this.buffer
.byteLength
) {
542 throw new RangeError("byteOffset out of range");
545 if (arguments
.length
< 3) {
546 this.byteLength
= this.buffer
.byteLength
- this.byteOffset
;
548 this.byteLength
= ECMAScript
.ToUint32(byteLength
);
551 if ((this.byteOffset
+ this.byteLength
) > this.buffer
.byteLength
) {
552 throw new RangeError("byteOffset and length reference an area beyond the end of the buffer");
555 configureProperties(this);
558 function makeGetter(arrayType
) {
559 return function(byteOffset
, littleEndian
) {
561 byteOffset
= ECMAScript
.ToUint32(byteOffset
);
563 if (byteOffset
+ arrayType
.BYTES_PER_ELEMENT
> this.byteLength
) {
564 throw new RangeError("Array index out of range");
566 byteOffset
+= this.byteOffset
;
568 var uint8Array
= new exports
.Uint8Array(this.buffer
, byteOffset
, arrayType
.BYTES_PER_ELEMENT
),
570 for (i
= 0; i
< arrayType
.BYTES_PER_ELEMENT
; i
+= 1) {
571 bytes
.push(r(uint8Array
, i
));
574 if (Boolean(littleEndian
) === Boolean(IS_BIG_ENDIAN
)) {
578 return r(new arrayType(new exports
.Uint8Array(bytes
).buffer
), 0);
582 DataView
.prototype.getUint8
= makeGetter(exports
.Uint8Array
);
583 DataView
.prototype.getInt8
= makeGetter(exports
.Int8Array
);
584 DataView
.prototype.getUint16
= makeGetter(exports
.Uint16Array
);
585 DataView
.prototype.getInt16
= makeGetter(exports
.Int16Array
);
586 DataView
.prototype.getUint32
= makeGetter(exports
.Uint32Array
);
587 DataView
.prototype.getInt32
= makeGetter(exports
.Int32Array
);
588 DataView
.prototype.getFloat32
= makeGetter(exports
.Float32Array
);
589 DataView
.prototype.getFloat64
= makeGetter(exports
.Float64Array
);
591 function makeSetter(arrayType
) {
592 return function(byteOffset
, value
, littleEndian
) {
594 byteOffset
= ECMAScript
.ToUint32(byteOffset
);
595 if (byteOffset
+ arrayType
.BYTES_PER_ELEMENT
> this.byteLength
) {
596 throw new RangeError("Array index out of range");
600 var typeArray
= new arrayType([value
]),
601 byteArray
= new exports
.Uint8Array(typeArray
.buffer
),
602 bytes
= [], i
, byteView
;
604 for (i
= 0; i
< arrayType
.BYTES_PER_ELEMENT
; i
+= 1) {
605 bytes
.push(r(byteArray
, i
));
609 if (Boolean(littleEndian
) === Boolean(IS_BIG_ENDIAN
)) {
614 byteView
= new exports
.Uint8Array(this.buffer
, byteOffset
, arrayType
.BYTES_PER_ELEMENT
);
619 DataView
.prototype.setUint8
= makeSetter(exports
.Uint8Array
);
620 DataView
.prototype.setInt8
= makeSetter(exports
.Int8Array
);
621 DataView
.prototype.setUint16
= makeSetter(exports
.Uint16Array
);
622 DataView
.prototype.setInt16
= makeSetter(exports
.Int16Array
);
623 DataView
.prototype.setUint32
= makeSetter(exports
.Uint32Array
);
624 DataView
.prototype.setInt32
= makeSetter(exports
.Int32Array
);
625 DataView
.prototype.setFloat32
= makeSetter(exports
.Float32Array
);
626 DataView
.prototype.setFloat64
= makeSetter(exports
.Float64Array
);
628 exports
.DataView
= exports
.DataView
|| DataView
;