mdx-m3-viewer
Version:
A browser WebGL model viewer. Mainly focused on models of the games Warcraft 3 and Starcraft 2.
624 lines • 22.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const bytesof_1 = require("./bytesof");
const searches_1 = require("./searches");
const typecast_1 = require("./typecast");
const utf8_1 = require("./utf8");
// Memory for all of the xxxToUint type casts.
const uint8 = new Uint8Array(8);
/**
* A binary stream.
*/
class BinaryStream {
constructor(buffer, byteOffset, byteLength) {
this.index = 0;
const bytes = (0, bytesof_1.bytesOf)(buffer);
// For browsers not supporting the spec.
// Once upon a time I reported this issue on the Firefox tracker.
// Seems like Safari needs an issue report too.
byteOffset = byteOffset || 0;
byteLength = byteLength || bytes.length;
this.buffer = buffer;
this.uint8array = bytes.subarray(byteOffset, byteOffset + byteLength);
this.byteLength = byteLength;
this.remaining = byteLength;
}
/**
* Create a subreader of this reader, at its position, with the given byte length.
*/
substream(byteLength) {
if (this.remaining < byteLength) {
throw new Error(`ByteStream: substream: want ${byteLength} bytes but have ${this.remaining}`);
}
const index = this.index;
this.index += byteLength;
return new BinaryStream(this.uint8array.subarray(index, index + byteLength));
}
/**
* Skip a number of bytes.
*/
skip(bytes) {
if (this.remaining < bytes) {
throw new Error(`ByteStream: skip: premature end - want ${bytes} bytes but have ${this.remaining}`);
}
this.index += bytes;
this.remaining -= bytes;
}
/**
* Set the reader's index.
*/
seek(index) {
this.index = index;
this.remaining = this.byteLength - index;
}
/**
* Read a UTF8 string with the given number of bytes.
*
* The entire size will be read, however the string returned is NULL terminated in its memory block.
*
* For example, the MDX format has many strings that have a constant maximum size, where any bytes after the string are NULLs.
* Such strings will be loaded correctly given the maximum size.
*/
read(bytes) {
if (this.remaining < bytes) {
throw new Error(`ByteStream: read: premature end - want ${bytes} bytes but have ${this.remaining}`);
}
const uint8array = this.uint8array;
const start = this.index;
let end = (0, searches_1.boundIndexOf)(uint8array, 0, start, bytes);
if (end === -1) {
end = start + bytes;
}
this.index += bytes;
this.remaining -= bytes;
return (0, utf8_1.decodeUtf8)(uint8array.subarray(start, end));
}
/**
* Read a UTF8 NULL terminated string.
*/
readNull() {
if (this.remaining < 1) {
throw new Error(`ByteStream: readNull: premature end - want at least 1 byte but have 0`);
}
const uint8array = this.uint8array;
const start = this.index;
let end = uint8array.indexOf(0, start);
if (end === -1) {
end = uint8array.length - 1;
}
const bytes = end - start + 1;
this.index += bytes;
this.remaining -= bytes;
return (0, utf8_1.decodeUtf8)(uint8array.subarray(start, end));
}
/**
* Read a binary string with the given number of bytes.
*/
readBinary(bytes) {
if (this.remaining < bytes) {
throw new Error(`ByteStream: readBinary: premature end - want ${bytes} bytes but have ${this.remaining}`);
}
const uint8array = this.uint8array;
const index = this.index;
let data = '';
for (let i = 0; i < bytes; i++) {
data += String.fromCharCode(uint8array[index + i]);
}
this.index += bytes;
this.remaining -= bytes;
return data;
}
/**
* Read a 8 bit signed integer.
*/
readInt8() {
if (this.remaining < 1) {
throw new Error(`ByteStream: readInt8: premature end - want 1 byte but have ${this.remaining}`);
}
const index = this.index;
const uint8array = this.uint8array;
const data = (0, typecast_1.uint8ToInt8)(uint8array[index]);
this.index += 1;
this.remaining -= 1;
return data;
}
/**
* Read a 16 bit signed integer.
*/
readInt16() {
if (this.remaining < 2) {
throw new Error(`ByteStream: readInt16: premature end - want 2 bytes but have ${this.remaining}`);
}
const index = this.index;
const uint8array = this.uint8array;
const data = (0, typecast_1.uint8ToInt16)(uint8array[index], uint8array[index + 1]);
this.index += 2;
this.remaining -= 2;
return data;
}
/**
* Read a 32 bit signed integer.
*/
readInt32() {
if (this.remaining < 4) {
throw new Error(`ByteStream: readInt32: premature end - want 4 bytes but have ${this.remaining}`);
}
const index = this.index;
const uint8array = this.uint8array;
const data = (0, typecast_1.uint8ToInt32)(uint8array[index], uint8array[index + 1], uint8array[index + 2], uint8array[index + 3]);
this.index += 4;
this.remaining -= 4;
return data;
}
/**
* Read a 8 bit unsigned integer.
*/
readUint8() {
if (this.remaining < 1) {
throw new Error(`ByteStream: readUint8: premature end - want 1 byte but have ${this.remaining}`);
}
const data = this.uint8array[this.index];
this.index += 1;
this.remaining -= 1;
return data;
}
/**
* Read a 16 bit unsigned integer.
*/
readUint16() {
if (this.remaining < 2) {
throw new Error(`ByteStream: readUint16: premature end - want 2 bytes but have ${this.remaining}`);
}
const index = this.index;
const uint8array = this.uint8array;
const data = (0, typecast_1.uint8ToUint16)(uint8array[index], uint8array[index + 1]);
this.index += 2;
this.remaining -= 2;
return data;
}
/**
* Read a 32 bit unsigned integer.
*/
readUint32() {
if (this.remaining < 4) {
throw new Error(`ByteStream: readUint32: premature end - want 4 bytes but have ${this.remaining}`);
}
const index = this.index;
const uint8array = this.uint8array;
const data = (0, typecast_1.uint8ToUint32)(uint8array[index], uint8array[index + 1], uint8array[index + 2], uint8array[index + 3]);
this.index += 4;
this.remaining -= 4;
return data;
}
/**
* Read a 32 bit float.
*/
readFloat32() {
if (this.remaining < 4) {
throw new Error(`ByteStream: readFloat32: premature end - want 4 bytes but have ${this.remaining}`);
}
const index = this.index;
const uint8array = this.uint8array;
const data = (0, typecast_1.uint8ToFloat32)(uint8array[index], uint8array[index + 1], uint8array[index + 2], uint8array[index + 3]);
this.index += 4;
this.remaining -= 4;
return data;
}
/**
* Read a 64 bit float.
*/
readFloat64() {
if (this.remaining < 8) {
throw new Error(`ByteStream: readFloat64: premature end - want 8 bytes but have ${this.remaining}`);
}
const index = this.index;
const uint8array = this.uint8array;
const data = (0, typecast_1.uint8ToFloat64)(uint8array[index], uint8array[index + 1], uint8array[index + 2], uint8array[index + 3], uint8array[index + 4], uint8array[index + 5], uint8array[index + 6], uint8array[index + 7]);
this.index += 8;
this.remaining -= 8;
return data;
}
/**
* Read an array of 8 bit signed integers.
*/
readInt8Array(view) {
if (!ArrayBuffer.isView(view)) {
view = new Int8Array(view);
}
if (this.remaining < view.byteLength) {
throw new Error(`ByteStream: readInt8Array: premature end - want ${view.byteLength} bytes but have ${this.remaining}`);
}
const index = this.index;
const uint8array = this.uint8array;
for (let i = 0, l = view.length; i < l; i++) {
view[i] = (0, typecast_1.uint8ToInt8)(uint8array[index + i]);
}
this.index += view.byteLength;
this.remaining -= view.byteLength;
return view;
}
/**
* Read an array of 16 bit signed integers.
*/
readInt16Array(view) {
if (!ArrayBuffer.isView(view)) {
view = new Int16Array(view);
}
if (this.remaining < view.byteLength) {
throw new Error(`ByteStream: readInt16Array: premature end - want ${view.byteLength} bytes but have ${this.remaining}`);
}
const index = this.index;
const uint8array = this.uint8array;
for (let i = 0, l = view.length; i < l; i++) {
const offset = index + i * 2;
view[i] = (0, typecast_1.uint8ToInt16)(uint8array[offset], uint8array[offset + 1]);
}
this.index += view.byteLength;
this.remaining -= view.byteLength;
return view;
}
/**
* Read an array of 32 bit signed integers.
*/
readInt32Array(view) {
if (!ArrayBuffer.isView(view)) {
view = new Int32Array(view);
}
if (this.remaining < view.byteLength) {
throw new Error(`ByteStream: readInt32Array: premature end - want ${view.byteLength} bytes but have ${this.remaining}`);
}
const index = this.index;
const uint8array = this.uint8array;
for (let i = 0, l = view.length; i < l; i++) {
const offset = index + i * 4;
view[i] = (0, typecast_1.uint8ToInt32)(uint8array[offset], uint8array[offset + 1], uint8array[offset + 2], uint8array[offset + 3]);
}
this.index += view.byteLength;
this.remaining -= view.byteLength;
return view;
}
/**
* Read an array of 8 bit unsigned integers.
*/
readUint8Array(view) {
if (!ArrayBuffer.isView(view)) {
view = new Uint8Array(view);
}
if (this.remaining < view.byteLength) {
throw new Error(`ByteStream: readUint8Array: premature end - want ${view.byteLength} bytes but have ${this.remaining}`);
}
const index = this.index;
const uint8array = this.uint8array;
for (let i = 0, l = view.length; i < l; i++) {
view[i] = uint8array[index + i];
}
this.index += view.byteLength;
this.remaining -= view.byteLength;
return view;
}
/**
* Read an array of 16 bit unsigned integers.
*/
readUint16Array(view) {
if (!ArrayBuffer.isView(view)) {
view = new Uint16Array(view);
}
if (this.remaining < view.byteLength) {
throw new Error(`ByteStream: readUint16Array: premature end - want ${view.byteLength} bytes but have ${this.remaining}`);
}
const index = this.index;
const uint8array = this.uint8array;
for (let i = 0, l = view.length; i < l; i++) {
const offset = index + i * 2;
view[i] = (0, typecast_1.uint8ToUint16)(uint8array[offset], uint8array[offset + 1]);
}
this.index += view.byteLength;
this.remaining -= view.byteLength;
return view;
}
/**
* Read an array of 32 bit unsigned integers.
*/
readUint32Array(view) {
if (!ArrayBuffer.isView(view)) {
view = new Uint32Array(view);
}
if (this.remaining < view.byteLength) {
throw new Error(`ByteStream: readUint32Array: premature end - want ${view.byteLength} bytes but have ${this.remaining}`);
}
const index = this.index;
const uint8array = this.uint8array;
for (let i = 0, l = view.length; i < l; i++) {
const offset = index + i * 4;
view[i] = (0, typecast_1.uint8ToUint32)(uint8array[offset], uint8array[offset + 1], uint8array[offset + 2], uint8array[offset + 3]);
}
this.index += view.byteLength;
this.remaining -= view.byteLength;
return view;
}
/**
* Read an array of 32 bit floats.
*/
readFloat32Array(view) {
if (!ArrayBuffer.isView(view)) {
view = new Float32Array(view);
}
if (this.remaining < view.byteLength) {
throw new Error(`ByteStream: readFloat32Array: premature end - want ${view.byteLength} bytes but have ${this.remaining}`);
}
const index = this.index;
const uint8array = this.uint8array;
for (let i = 0, l = view.length; i < l; i++) {
const offset = index + i * 4;
view[i] = (0, typecast_1.uint8ToFloat32)(uint8array[offset], uint8array[offset + 1], uint8array[offset + 2], uint8array[offset + 3]);
}
this.index += view.byteLength;
this.remaining -= view.byteLength;
return view;
}
/**
* Read an array of 64 bit floats.
*/
readFloat64Array(view) {
if (!ArrayBuffer.isView(view)) {
view = new Float64Array(view);
}
if (this.remaining < view.byteLength) {
throw new Error(`ByteStream: readFloat64Array: premature end - want ${view.byteLength} bytes but have ${this.remaining}`);
}
const index = this.index;
const uint8array = this.uint8array;
for (let i = 0, l = view.length; i < l; i++) {
const offset = index + i * 8;
view[i] = (0, typecast_1.uint8ToFloat64)(uint8array[offset], uint8array[offset + 1], uint8array[offset + 2], uint8array[offset + 3], uint8array[offset + 4], uint8array[offset + 5], uint8array[offset + 6], uint8array[offset + 7]);
}
this.index += view.byteLength;
this.remaining -= view.byteLength;
return view;
}
/**
* Write a UTF8 string.
*
* Returns the number of bytes that were written,
*/
write(utf8) {
const bytes = (0, utf8_1.encodeUtf8)(utf8);
this.writeUint8Array(bytes);
return bytes.length;
}
/**
* Write a UTF8 string as a NULL terminated string.
*
* Returns the number of bytes that were written, including the terminating NULL.
*/
writeNull(utf8) {
const bytes = this.write(utf8);
this.index++;
this.remaining--;
return bytes + 1;
}
/**
* Write a binary string.
*/
writeBinary(value) {
const index = this.index;
const uint8array = this.uint8array;
const count = value.length;
for (let i = 0; i < count; i++) {
uint8array[index + i] = value.charCodeAt(i);
}
this.index += count;
}
/**
* Write a 8 bit signed integer.
*/
writeInt8(value) {
this.uint8array[this.index] = (0, typecast_1.int8ToUint8)(value);
this.index += 1;
}
/**
* Write a 16 bit signed integer.
*/
writeInt16(value) {
const index = this.index;
const uint8array = this.uint8array;
(0, typecast_1.int16ToUint8)(uint8, value);
uint8array[index] = uint8[0];
uint8array[index + 1] = uint8[1];
this.index += 2;
}
/**
* Write a 32 bit signed integer.
*/
writeInt32(value) {
const index = this.index;
const uint8array = this.uint8array;
(0, typecast_1.int32ToUint8)(uint8, value);
uint8array[index] = uint8[0];
uint8array[index + 1] = uint8[1];
uint8array[index + 2] = uint8[2];
uint8array[index + 3] = uint8[3];
this.index += 4;
}
/**
* Write a 8 bit unsigned integer.
*/
writeUint8(value) {
this.uint8array[this.index] = value;
this.index += 1;
}
/**
* Write a 16 bit unsigned integer.
*/
writeUint16(value) {
const index = this.index;
const uint8array = this.uint8array;
(0, typecast_1.uint16ToUint8)(uint8, value);
uint8array[index] = uint8[0];
uint8array[index + 1] = uint8[1];
this.index += 2;
}
/**
* Write a 32 bit unsigned integer.
*/
writeUint32(value) {
const index = this.index;
const uint8array = this.uint8array;
(0, typecast_1.uint32ToUint8)(uint8, value);
uint8array[index] = uint8[0];
uint8array[index + 1] = uint8[1];
uint8array[index + 2] = uint8[2];
uint8array[index + 3] = uint8[3];
this.index += 4;
}
/**
* Write a 32 bit float.
*/
writeFloat32(value) {
const index = this.index;
const uint8array = this.uint8array;
(0, typecast_1.float32ToUint8)(uint8, value);
uint8array[index] = uint8[0];
uint8array[index + 1] = uint8[1];
uint8array[index + 2] = uint8[2];
uint8array[index + 3] = uint8[3];
this.index += 4;
}
/**
* Write a 64 bit float.
*/
writeFloat64(value) {
const index = this.index;
const uint8array = this.uint8array;
(0, typecast_1.float64ToUint8)(uint8, value);
uint8array[index] = uint8[0];
uint8array[index + 1] = uint8[1];
uint8array[index + 2] = uint8[2];
uint8array[index + 3] = uint8[3];
uint8array[index + 4] = uint8[4];
uint8array[index + 5] = uint8[5];
uint8array[index + 6] = uint8[6];
uint8array[index + 7] = uint8[7];
this.index += 8;
}
/**
* Write an array of 8 bit signed integers.
*/
writeInt8Array(view) {
const index = this.index;
const uint8array = this.uint8array;
for (let i = 0, l = view.length; i < l; i++) {
uint8array[index + i] = (0, typecast_1.int8ToUint8)(view[i]);
}
this.index += view.byteLength;
}
/**
* Write an array of 16 bit signed integers.
*/
writeInt16Array(view) {
const index = this.index;
const uint8array = this.uint8array;
for (let i = 0, l = view.length; i < l; i++) {
const offset = index + i * 2;
(0, typecast_1.int16ToUint8)(uint8, view[i]);
uint8array[offset] = uint8[0];
uint8array[offset + 1] = uint8[1];
}
this.index += view.byteLength;
}
/**
* Write an array of 32 bit signed integers.
*/
writeInt32Array(view) {
const index = this.index;
const uint8array = this.uint8array;
for (let i = 0, l = view.length; i < l; i++) {
const offset = index + i * 4;
(0, typecast_1.int32ToUint8)(uint8, view[i]);
uint8array[offset] = uint8[0];
uint8array[offset + 1] = uint8[1];
uint8array[offset + 2] = uint8[2];
uint8array[offset + 3] = uint8[3];
}
this.index += view.byteLength;
}
/**
* Write an array of 8 bit unsigned integers.
*/
writeUint8Array(view) {
const index = this.index;
const uint8array = this.uint8array;
for (let i = 0, l = view.length; i < l; i++) {
uint8array[index + i] = view[i];
}
this.index += view.byteLength;
}
/**
* Write an array of 16 bit unsigned integers.
*/
writeUint16Array(view) {
const index = this.index;
const uint8array = this.uint8array;
for (let i = 0, l = view.length; i < l; i++) {
const offset = index + i * 2;
(0, typecast_1.uint16ToUint8)(uint8, view[i]);
uint8array[offset] = uint8[0];
uint8array[offset + 1] = uint8[1];
}
this.index += view.byteLength;
}
/**
* Write an array of 32 bit unsigned integers.
*/
writeUint32Array(view) {
const index = this.index;
const uint8array = this.uint8array;
for (let i = 0, l = view.length; i < l; i++) {
const offset = index + i * 4;
(0, typecast_1.uint32ToUint8)(uint8, view[i]);
uint8array[offset] = uint8[0];
uint8array[offset + 1] = uint8[1];
uint8array[offset + 2] = uint8[2];
uint8array[offset + 3] = uint8[3];
}
this.index += view.byteLength;
}
/**
* Write an array of 32 bit floats.
*/
writeFloat32Array(view) {
const index = this.index;
const uint8array = this.uint8array;
for (let i = 0, l = view.length; i < l; i++) {
const offset = index + i * 4;
(0, typecast_1.float32ToUint8)(uint8, view[i]);
uint8array[offset] = uint8[0];
uint8array[offset + 1] = uint8[1];
uint8array[offset + 2] = uint8[2];
uint8array[offset + 3] = uint8[3];
}
this.index += view.byteLength;
}
/**
* Write an array of 64 bit floats.
*/
writeFloat64Array(view) {
const index = this.index;
const uint8array = this.uint8array;
for (let i = 0, l = view.length; i < l; i++) {
const offset = index + i * 8;
(0, typecast_1.float64ToUint8)(uint8, view[i]);
uint8array[offset] = uint8[0];
uint8array[offset + 1] = uint8[1];
uint8array[offset + 2] = uint8[2];
uint8array[offset + 3] = uint8[3];
uint8array[offset + 4] = uint8[4];
uint8array[offset + 5] = uint8[5];
uint8array[offset + 6] = uint8[6];
uint8array[offset + 7] = uint8[7];
}
this.index += view.byteLength;
}
}
exports.default = BinaryStream;
//# sourceMappingURL=binarystream.js.map