gmll
Version:
A generic launcher core for building custom launchers
104 lines (103 loc) • 3.98 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.readDat = exports.readNBT = exports.tagTypes = void 0;
/**
* An NBT reader implement in JS.
*/
const gfsl_1 = require("gfsl");
const config_1 = require("./config");
var tagTypes;
(function (tagTypes) {
tagTypes[tagTypes["TAG_End"] = 0] = "TAG_End";
tagTypes[tagTypes["TAG_Byte"] = 1] = "TAG_Byte";
tagTypes[tagTypes["TAG_Short"] = 2] = "TAG_Short";
tagTypes[tagTypes["TAG_Int"] = 3] = "TAG_Int";
tagTypes[tagTypes["TAG_Long"] = 4] = "TAG_Long";
tagTypes[tagTypes["TAG_Float"] = 5] = "TAG_Float";
tagTypes[tagTypes["TAG_Double"] = 6] = "TAG_Double";
tagTypes[tagTypes["TAG_Byte_Array"] = 7] = "TAG_Byte_Array";
tagTypes[tagTypes["TAG_String"] = 8] = "TAG_String";
tagTypes[tagTypes["TAG_List"] = 9] = "TAG_List";
tagTypes[tagTypes["TAG_Compound"] = 10] = "TAG_Compound";
tagTypes[tagTypes["TAG_Int_Array"] = 11] = "TAG_Int_Array";
tagTypes[tagTypes["TAG_Long_Array"] = 12] = "TAG_Long_Array";
})(tagTypes = exports.tagTypes || (exports.tagTypes = {}));
function readNBT(raw, typed) {
//Skips the initial compound tag header
let i = 3;
//Parse a section of the raw buffer
function parse(size) {
const buf = raw.slice(i, Math.min(i + size, raw.length));
i += size;
return buf;
}
function getString() {
return parse(parse(2).readUInt16BE()).toString();
}
function arrType(index) {
const size = parse(4).readUInt32BE();
const arr = [];
for (let i3 = 0; i3 < size; i3++) {
arr.push(decode(index));
}
return typed ? { tag: tagTypes[index], list: arr } : arr;
}
function decode(c) {
switch (c) {
case 0:
return; //end-flag
case 1:
return parse(1).readInt8(); //byte
case 2:
return parse(2).readInt16BE(); //short
case 3:
return parse(4).readInt32BE(); //int
case 4:
return Number(parse(8).readBigInt64BE()); //long
case 5:
return parse(4).readFloatBE(); //float
case 6:
return parse(8).readDoubleBE(); //double
case 7:
return arrType(1); //byte array
case 8:
return getString(); //string
case 9:
return arrType(parse(1).readInt8()); //list
case 11:
return arrType(3); //int array
case 12:
return arrType(4); //long int array
case 10:
//Compound tag flag
const t = {};
while ((c = raw[i++]) != 0) {
t[getString()] = typed
? { tag: tagTypes[c], value: decode(c) }
: decode(c);
}
return t;
default:
//Unknown flag. Due to how dat files are encoded. The decoder cannot continue if it hits an unknown flag
(0, config_1.emit)("debug.error", "Unknown type", [String.fromCharCode(c), c], " at ", i, raw[i]);
(0, config_1.emit)("debug.error", [raw.slice(3, i + 10).toString()]);
throw "UNKNOWN TYPE";
}
}
const c = raw[i];
return (typed ? { tag: tagTypes[c], value: decode(c) } : decode(c));
}
exports.readNBT = readNBT;
async function readDat(path, typed) {
if (!path.sysPath().toLocaleLowerCase().endsWith(".dat"))
(0, config_1.emit)("debug.warn", "Potentially unsupported file extention detected!");
const p = gfsl_1.Dir.tmpdir().getDir("gmll", path.getHash()).mkdir();
//We need to decompress the dat file
await path.unzip(p);
const file = p.ls()[0];
//We'll be working with a buffer here
const raw = file.readRaw();
p.rm();
return readNBT(raw, typed);
}
exports.readDat = readDat;
;