UNPKG

@minecraft/creator-tools

Version:

Minecraft Creator Tools command line and libraries.

349 lines (345 loc) 14 kB
"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