mc-anvil
Version:
A Typescript library for reading Minecraft Anvil format files and Minecraft NBT format files in the browser.
194 lines • 7.57 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NBTParser = exports.baseName = exports.parent = exports.findChildTagAtPath = exports.findCompoundListChildren = exports.findChildTagIndex = exports.findChildTag = exports.parseCompoundListIndex = exports.LIST_INDEX = void 0;
const util_1 = require("../util");
const pako_1 = require("pako");
const types_1 = require("./types");
exports.LIST_INDEX = /^[\[][0-9]+[\]]$/;
function parseCompoundListIndex(value) {
if (value.match(exports.LIST_INDEX) !== null)
return +value.slice(1, value.length - 1);
return +value;
}
exports.parseCompoundListIndex = parseCompoundListIndex;
function findChildTag(tag, f) {
if (tag.type === types_1.TagType.COMPOUND)
return tag.data.find(f);
}
exports.findChildTag = findChildTag;
function findChildTagIndex(tag, f) {
if (tag.type === types_1.TagType.COMPOUND)
return tag.data.findIndex(f);
}
exports.findChildTagIndex = findChildTagIndex;
function findCompoundListChildren(tag, f) {
if (tag.type === types_1.TagType.LIST && tag.data.subType === types_1.TagType.COMPOUND)
return tag.data.data.map(x => x.find(f));
}
exports.findCompoundListChildren = findCompoundListChildren;
function findChildTagAtPath(path, tag) {
const p = path.split('/');
for (let i = 0; i < p.length; ++i) {
if (!tag || !tag.type)
return;
if (tag.type === types_1.TagType.COMPOUND)
tag = findChildTag(tag, x => x.name === p[i]);
else if (tag.type === types_1.TagType.LIST && tag.data.subType === types_1.TagType.COMPOUND) {
const data = tag.data.data[parseCompoundListIndex(p[i])];
tag = data ? { type: types_1.TagType.COMPOUND, name: "", data } : undefined;
}
}
return tag;
}
exports.findChildTagAtPath = findChildTagAtPath;
function parent(path) {
const p = path.split("/");
return p.slice(0, p.length - 1).join("/");
}
exports.parent = parent;
function baseName(path) {
const p = path.split("/");
return p[p.length - 1];
}
exports.baseName = baseName;
function tryInflate(buffer) {
try {
const b = pako_1.inflate(new Uint8Array(buffer));
if (!b)
throw new Error("not compressed");
return b.buffer;
}
catch (e) {
return buffer;
}
}
class NBTParser extends util_1.ResizableBinaryWriter {
constructor(data, verbose) {
super(tryInflate(data));
this.tagReaders = new Map([
[types_1.TagType.END, () => null],
[types_1.TagType.BYTE, this.getByte.bind(this)],
[types_1.TagType.BYTE_ARRAY, this.getByteArrayTag.bind(this)],
[types_1.TagType.SHORT, this.getShort.bind(this)],
[types_1.TagType.INT, this.getInt.bind(this)],
[types_1.TagType.INT_ARRAY, this.getIntArrayTag.bind(this)],
[types_1.TagType.LONG, this.getInt64.bind(this)],
[types_1.TagType.LONG_ARRAY, this.getLongArrayTag.bind(this)],
[types_1.TagType.FLOAT, this.getFloat.bind(this)],
[types_1.TagType.DOUBLE, this.getDouble.bind(this)],
[types_1.TagType.STRING, this.getStringTag.bind(this)],
[types_1.TagType.COMPOUND, this.getCompoundTag.bind(this)],
[types_1.TagType.LIST, this.getListTag.bind(this)]
]);
this.tagWriters = new Map([
[types_1.TagType.END, () => { }],
[types_1.TagType.BYTE, this.setByte.bind(this)],
[types_1.TagType.BYTE_ARRAY, this.setByteArrayTag.bind(this)],
[types_1.TagType.SHORT, this.setShort.bind(this)],
[types_1.TagType.INT, this.setInt.bind(this)],
[types_1.TagType.INT_ARRAY, this.setIntArrayTag.bind(this)],
[types_1.TagType.LONG, this.setInt64LE.bind(this)],
[types_1.TagType.LONG_ARRAY, this.setLongArrayTag.bind(this)],
[types_1.TagType.FLOAT, this.setFloat.bind(this)],
[types_1.TagType.DOUBLE, this.setDouble.bind(this)],
[types_1.TagType.STRING, this.setStringTag.bind(this)],
[types_1.TagType.COMPOUND, this.setCompoundTag.bind(this)],
[types_1.TagType.LIST, this.setListTag.bind(this)]
]);
this.verbose = verbose;
}
getNumberArrayTag(reader) {
const data = [];
const length = this.getInt();
for (let i = 0; i < length; ++i)
data.push(reader());
return data;
}
setNumberArrayTag(value, writer) {
this.setInt(value.length);
value.forEach(writer);
}
getByteArrayTag() {
return this.getNumberArrayTag(this.getByte.bind(this));
}
setByteArrayTag(value) {
this.setNumberArrayTag(value, this.setByte.bind(this));
}
getIntArrayTag() {
return this.getNumberArrayTag(this.getInt.bind(this));
}
setIntArrayTag(value) {
this.setNumberArrayTag(value, this.setInt.bind(this));
}
getLongArrayTag() {
const length = this.getInt();
const r = this.view.buffer.slice(this.position, this.position + length * 8);
this.position += length * 8;
return r;
}
setLongArrayTag(value) {
this.setInt(value.byteLength / 8);
this.setArrayBuffer(value);
}
getStringTag() {
const length = this.getUShort();
return this.getFixedLengthString(length);
}
setStringTag(value) {
this.setUShort(value.length);
this.setFixedLengthString(value);
}
getListTag() {
const subType = this.getByte();
const length = this.getInt();
const reader = this.tagReaders.get(subType);
const data = [];
if (reader === undefined)
throw new Error(`Invalid NBT tag ID ${subType} for list tag`);
for (let i = 0; i < length; ++i)
data.push(reader());
return { subType, data };
}
setListTag(value) {
const writer = this.tagWriters.get(value.subType);
if (writer === undefined)
throw new Error(`Invalid NBT tag ID ${value.subType} for list tag`);
this.setByte(value.subType);
this.setInt(value.data.length);
value.data.forEach(writer);
}
getCompoundTag() {
const tags = [];
do {
tags.push(this.getTag());
} while (tags[tags.length - 1].type !== types_1.TagType.END);
return tags;
}
setCompoundTag(value) {
var _a;
value.forEach(this.setTag.bind(this));
if (((_a = value[value.length - 1]) === null || _a === void 0 ? void 0 : _a.type) !== types_1.TagType.END)
this.setTag({ type: types_1.TagType.END, name: "", data: null });
}
getTag() {
const type = this.getByte();
const nameLength = type !== types_1.TagType.END ? this.getUShort() : 0;
const name = this.getFixedLengthString(nameLength);
const reader = this.tagReaders.get(type);
if (reader === undefined)
throw new Error(`Invalid NBT tag ID ${type}`);
return { type, name, data: reader() };
}
setTag(value) {
const writer = this.tagWriters.get(value.type);
if (writer === undefined)
throw new Error(`Invalid NBT tag ID ${value.type}`);
this.setByte(value.type);
if (value.type !== types_1.TagType.END)
this.setUShort(value.name.length);
this.setFixedLengthString(value.name);
writer(value.data);
}
}
exports.NBTParser = NBTParser;
//# sourceMappingURL=nbt.js.map