@minecraft/creator-tools
Version:
Minecraft Creator Tools command line and libraries.
349 lines (345 loc) • 14 kB
JavaScript
"use strict";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
const NbtBinaryTag_1 = require("./NbtBinaryTag");
const Utilities_1 = require("./../core/Utilities");
const Log_1 = require("../core/Log");
class NbtBinary {
constructor() {
this.roots = null;
}
get singleRoot() {
if (this.roots === null) {
return null;
}
if (this.roots.length === 0) {
return null;
}
if (this.roots.length !== 1) {
this._pushError("Unexpectedly did not find a single root (" + this.roots.length + ")");
}
return this.roots[0];
}
_pushError(message, contextIn) {
this.isInErrorState = true;
if (this.errorMessages === undefined) {
this.errorMessages = [];
}
let contextOut = undefined;
if (contextIn) {
contextOut = this.context ? this.context + "-" + contextIn : contextIn;
}
else {
contextOut = this.context;
}
Log_1.default.error(message + (contextOut ? " " + contextOut : ""));
this.errorMessages.push({
message: message,
context: contextOut,
});
}
_getSignedByte(num) {
const buffer = new ArrayBuffer(1);
const bytes = new Uint8Array(buffer);
bytes[0] = num;
const view = new DataView(buffer);
return view.getInt8(0);
}
_getFloat(num1, num2, num3, num4, littleEndian) {
const buffer = new ArrayBuffer(4);
const bytes = new Uint8Array(buffer);
bytes[0] = num1;
bytes[1] = num2;
bytes[2] = num3;
bytes[3] = num4;
const view = new DataView(buffer);
return view.getFloat32(0, littleEndian);
}
_getSignedLong(num1, num2, num3, num4, num5, num6, num7, num8, littleEndian) {
const buffer = new ArrayBuffer(8);
const bytes = new Uint8Array(buffer);
bytes[0] = num1;
bytes[1] = num2;
bytes[2] = num3;
bytes[3] = num4;
bytes[4] = num5;
bytes[5] = num6;
bytes[6] = num7;
bytes[7] = num8;
const view = new DataView(buffer);
return view.getBigInt64(0, littleEndian);
}
_getSignedDouble(num1, num2, num3, num4, num5, num6, num7, num8, littleEndian) {
const buffer = new ArrayBuffer(8);
const bytes = new Uint8Array(buffer);
bytes[0] = num1;
bytes[1] = num2;
bytes[2] = num3;
bytes[3] = num4;
bytes[4] = num5;
bytes[5] = num6;
bytes[6] = num7;
bytes[7] = num8;
const view = new DataView(buffer);
return view.getFloat64(0, littleEndian);
}
_getVarInt(data, index) {
let bytesRead = 0;
let result = 0;
let currentByte = 0;
do {
currentByte = data[index];
const currentByteVal = currentByte & 0b01111111;
result |= currentByteVal << (7 * bytesRead);
bytesRead++;
if (bytesRead > 5) {
throw new Error("VarInt is unexpectedly large");
}
} while ((currentByte & 0b10000000) !== 0);
return {
value: result,
bytesRead: bytesRead,
};
}
_getSignedShort(num1, num2, littleEndian) {
const buffer = new ArrayBuffer(2);
const bytes = new Uint8Array(buffer);
bytes[0] = num1;
bytes[1] = num2;
const view = new DataView(buffer);
return view.getInt16(0, littleEndian);
}
_getUnsignedShort(num1, num2, littleEndian) {
const buffer = new ArrayBuffer(2);
const bytes = new Uint8Array(buffer);
bytes[0] = num1;
bytes[1] = num2;
const view = new DataView(buffer);
return view.getUint16(0, littleEndian);
}
_getSignedInteger(num1, num2, num3, num4, littleEndian) {
const buffer = new ArrayBuffer(4);
const bytes = new Uint8Array(buffer);
bytes[0] = num1;
bytes[1] = num2;
bytes[2] = num3;
bytes[3] = num4;
const view = new DataView(buffer);
const val = view.getInt32(0, littleEndian);
return val;
}
_getUnsignedInteger(num1, num2, num3, num4, littleEndian) {
const buffer = new ArrayBuffer(4);
const bytes = new Uint8Array(buffer);
bytes[0] = num1;
bytes[1] = num2;
bytes[2] = num3;
bytes[3] = num4;
const view = new DataView(buffer);
return view.getUint32(0, littleEndian);
}
getJsonString() {
return JSON.stringify(this.getJson());
}
getJson() {
if (this.roots === null) {
return {};
}
if (this.roots.length === 1) {
return this.roots[0].getJson();
}
throw new Error("Unexpected multiple roots.");
}
toBinary() {
if (this.roots === undefined || this.roots === null) {
return undefined;
}
let byteSize = 0;
for (let i = 0; i < this.roots.length; i++) {
byteSize += this.roots[i].getByteSize();
}
const ab = new ArrayBuffer(byteSize);
const bytes = new Uint8Array(ab);
let bytesWrittenAll = 0;
for (let i = 0; i < this.roots.length; i++) {
bytesWrittenAll += this.roots[i].writeBytes(bytes, bytesWrittenAll, true);
}
Log_1.default.assert(bytesWrittenAll === byteSize, "Unexpectedly did not write full NBT.");
return bytes;
}
ensureSingleRoot() {
if (this.roots) {
if (this.roots.length !== 1) {
throw new Error("Unexpected root count.");
}
return this.roots[0];
}
this.roots = [];
this.roots.push(new NbtBinaryTag_1.default(NbtBinaryTag_1.NbtTagType.compound, "", false));
return this.roots[0];
}
fromBinary(data, littleEndian, isVarint, skipBytes, stringsAreASCII, processAsList) {
const tagStack = [];
const listCountStack = [];
const listTypeStack = [];
this.roots = [];
let i = 0;
if (skipBytes !== undefined) {
i = skipBytes;
}
if (!stringsAreASCII) {
stringsAreASCII = false;
}
while (i < data.length) {
let tagType = NbtBinaryTag_1.NbtTagType.unknown;
let name = "";
let isListChild = false;
if (tagStack.length === 0 || tagStack[tagStack.length - 1].type !== NbtBinaryTag_1.NbtTagType.list) {
tagType = data[i++];
if (tagType > 13 && tagType !== 99) {
this._pushError("Unexpected NBT tag type: " + tagType);
}
if (tagType !== NbtBinaryTag_1.NbtTagType.end) {
let nameLength = 0;
if (isVarint) {
const result = this._getVarInt(data, i);
nameLength = result.value;
i += result.bytesRead;
}
else {
nameLength = data[i++];
nameLength += data[i++] * 256;
}
for (let j = 0; j < nameLength; j++) {
name += String.fromCharCode(data[i++]);
}
}
else if (tagStack.length === 0) {
break;
}
} // we're in list sub tag parsing mode
else {
tagType = listTypeStack[tagStack.length - 1];
isListChild = true;
}
const activeTag = new NbtBinaryTag_1.default(tagType, name, isListChild);
if (tagStack.length === 0) {
this.roots.push(activeTag);
} // if (activeTag.type !== NbtTagType.end)
else {
const parentTag = tagStack[tagStack.length - 1];
if (parentTag.type === NbtBinaryTag_1.NbtTagType.list &&
(parentTag.childTagType === undefined || parentTag.childTagType === NbtBinaryTag_1.NbtTagType.unknown)) {
parentTag.childTagType = activeTag.type;
}
parentTag.childrenWithEnd.push(activeTag);
}
if (tagStack.length > 0 && tagStack[tagStack.length - 1].type === NbtBinaryTag_1.NbtTagType.list) {
listCountStack[tagStack.length - 1]--;
if (listCountStack[tagStack.length - 1] === 0) {
tagStack.pop();
}
}
if (activeTag.type === NbtBinaryTag_1.NbtTagType.compound) {
tagStack.push(activeTag);
}
else if (activeTag.type === NbtBinaryTag_1.NbtTagType.end) {
tagStack.pop();
if (tagStack.length === 0 && !processAsList) {
break;
}
}
else if (activeTag.type === NbtBinaryTag_1.NbtTagType.byte) {
activeTag.value = this._getSignedByte(data[i++]);
}
else if (activeTag.type === NbtBinaryTag_1.NbtTagType.byteArray) {
const arrayLength = this._getSignedInteger(data[i++], data[i++], data[i++], data[i++], littleEndian);
const numberArray = [];
for (let j = 0; j < arrayLength; j++) {
numberArray.push(this._getSignedByte(data[i++]));
}
activeTag.value = numberArray;
}
else if (activeTag.type === NbtBinaryTag_1.NbtTagType.list) {
activeTag.type = NbtBinaryTag_1.NbtTagType.list;
tagStack.push(activeTag);
listTypeStack[tagStack.length - 1] = data[i++];
listCountStack[tagStack.length - 1] = this._getSignedInteger(data[i++], data[i++], data[i++], data[i++], littleEndian);
}
else if (activeTag.type === NbtBinaryTag_1.NbtTagType.intArray) {
const arrayLength = this._getSignedInteger(data[i++], data[i++], data[i++], data[i++], littleEndian);
const numberArray = [];
for (let j = 0; j < arrayLength; j++) {
numberArray.push(this._getSignedInteger(data[i++], data[i++], data[i++], data[i++], littleEndian));
}
activeTag.value = numberArray;
}
else if (activeTag.type === NbtBinaryTag_1.NbtTagType.longArray) {
const arrayLength = this._getSignedInteger(data[i++], data[i++], data[i++], data[i++], littleEndian);
const numberArray = [];
for (let j = 0; j < arrayLength; j++) {
numberArray.push(this._getSignedLong(data[i++], data[i++], data[i++], data[i++], data[i++], data[i++], data[i++], data[i++], littleEndian));
}
activeTag.value = numberArray;
}
else if (activeTag.type === NbtBinaryTag_1.NbtTagType.short) {
activeTag.value = this._getSignedShort(data[i++], data[i++], littleEndian);
}
else if (activeTag.type === NbtBinaryTag_1.NbtTagType.int) {
activeTag.value = this._getSignedInteger(data[i++], data[i++], data[i++], data[i++], littleEndian);
}
else if (activeTag.type === NbtBinaryTag_1.NbtTagType.float) {
activeTag.value = this._getFloat(data[i++], data[i++], data[i++], data[i++], littleEndian);
}
else if (activeTag.type === NbtBinaryTag_1.NbtTagType.double) {
activeTag.value = this._getSignedDouble(data[i++], data[i++], data[i++], data[i++], data[i++], data[i++], data[i++], data[i++], littleEndian);
}
else if (activeTag.type === NbtBinaryTag_1.NbtTagType.long) {
activeTag.value = this._getSignedLong(data[i++], data[i++], data[i++], data[i++], data[i++], data[i++], data[i++], data[i++], littleEndian);
}
else if (activeTag.type === NbtBinaryTag_1.NbtTagType.string) {
let stringLength = 0;
if (isVarint) {
const result = this._getVarInt(data, i);
stringLength = result.value;
i += result.bytesRead;
}
else {
stringLength = this._getUnsignedShort(data[i++], data[i++], littleEndian);
}
const view = new DataView(data.buffer);
let str;
if (stringsAreASCII) {
str = Utilities_1.default.readStringASCIIBuffer(data, i, stringLength);
}
else {
str = Utilities_1.default.getString(view, i, stringLength, "UTF8");
}
if (str === undefined) {
throw new Error("Unexpectedly could not read a string.");
}
activeTag.value = str;
i += stringLength;
Log_1.default.assert(i <= data.length, "NBTFB");
/*
let valueString = "";
for (let j=0; j<stringLength; j++)
{
valueString += String.fromCharCode(data[i++]);
}
activeTag.value = valueString;*/
}
else {
Log_1.default.unexpectedError("Unsupported NBT tag type '" + activeTag.type + "'");
}
}
let bytesRead = i;
if (skipBytes !== undefined) {
bytesRead -= skipBytes;
}
return bytesRead;
}
}
exports.default = NbtBinary;
//# sourceMappingURL=../maps/minecraft/NbtBinary.js.map