UNPKG

@minecraft/creator-tools

Version:

Minecraft Creator Tools command line and libraries.

325 lines (322 loc) 14.3 kB
"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const NbtBinaryTag_1 = __importStar(require("./NbtBinaryTag")); const Utilities_1 = __importDefault(require("./../core/Utilities")); const Log_1 = __importDefault(require("../core/Log")); const DataUtilities_1 = __importDefault(require("../core/DataUtilities")); class NbtBinary { roots = null; context; isInErrorState; errorMessages; static MAX_ARRAY_LENGTH = 10_000_000; static MAX_STRING_LENGTH = 1_000_000; 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, }); } _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, }; } 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; } if (nameLength < 0 || nameLength > NbtBinary.MAX_STRING_LENGTH) { this._pushError("Invalid NBT name length: " + nameLength); return 0; } for (let j = 0; j < nameLength; j++) { if (i >= data.length) { this._pushError("Unexpected end of data while reading NBT name"); return 0; } 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 = DataUtilities_1.default.getSignedByte(data[i++]); } else if (activeTag.type === NbtBinaryTag_1.NbtTagType.byteArray) { const arrayLength = DataUtilities_1.default.getSignedInteger(data[i++], data[i++], data[i++], data[i++], littleEndian); if (arrayLength < 0 || arrayLength > NbtBinary.MAX_ARRAY_LENGTH || i + arrayLength > data.length) { this._pushError("Invalid NBT byteArray length: " + arrayLength); return 0; } const numberArray = []; for (let j = 0; j < arrayLength; j++) { numberArray.push(DataUtilities_1.default.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] = DataUtilities_1.default.getSignedInteger(data[i++], data[i++], data[i++], data[i++], littleEndian); } else if (activeTag.type === NbtBinaryTag_1.NbtTagType.intArray) { const arrayLength = DataUtilities_1.default.getSignedInteger(data[i++], data[i++], data[i++], data[i++], littleEndian); if (arrayLength < 0 || arrayLength > NbtBinary.MAX_ARRAY_LENGTH || i + arrayLength * 4 > data.length) { this._pushError("Invalid NBT intArray length: " + arrayLength); return 0; } const numberArray = []; for (let j = 0; j < arrayLength; j++) { numberArray.push(DataUtilities_1.default.getSignedInteger(data[i++], data[i++], data[i++], data[i++], littleEndian)); } activeTag.value = numberArray; } else if (activeTag.type === NbtBinaryTag_1.NbtTagType.longArray) { const arrayLength = DataUtilities_1.default.getSignedInteger(data[i++], data[i++], data[i++], data[i++], littleEndian); if (arrayLength < 0 || arrayLength > NbtBinary.MAX_ARRAY_LENGTH || i + arrayLength * 8 > data.length) { this._pushError("Invalid NBT longArray length: " + arrayLength); return 0; } const numberArray = []; for (let j = 0; j < arrayLength; j++) { numberArray.push(DataUtilities_1.default.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 = DataUtilities_1.default.getSignedShort(data[i++], data[i++], littleEndian); } else if (activeTag.type === NbtBinaryTag_1.NbtTagType.int) { activeTag.value = DataUtilities_1.default.getSignedInteger(data[i++], data[i++], data[i++], data[i++], littleEndian); } else if (activeTag.type === NbtBinaryTag_1.NbtTagType.float) { activeTag.value = DataUtilities_1.default.getFloat(data[i++], data[i++], data[i++], data[i++], littleEndian); } else if (activeTag.type === NbtBinaryTag_1.NbtTagType.double) { activeTag.value = DataUtilities_1.default.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 = DataUtilities_1.default.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 = DataUtilities_1.default.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;