Advertisement
adrian_fuchs

nbtParser.js

May 14th, 2021
648
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. var nbtParser = {};
  2. global.nbtParser = nbtParser
  3. var pako = require('./pako')
  4.  
  5. var TAG_End = 0;
  6. var TAG_Byte = 1;
  7. var TAG_Short = 2;
  8. var TAG_Int = 3;
  9. var TAG_Long = 4;
  10. var TAG_Float = 5;
  11. var TAG_Double = 6;
  12. var TAG_Byte_Array = 7;
  13. var TAG_String = 8;
  14. var TAG_List = 9;
  15. var TAG_Compound = 10;
  16. var TAG_Int_Array = 11;
  17. var TAG_Long_Array = 12;
  18.  
  19. var TYPE_SUFFIXES = {
  20.     1: 'b',
  21.     4: 'L',
  22.     5: 'F',
  23.     6: 'D'
  24. };
  25.  
  26. function NBTParser () {
  27.     this._reset();
  28. }
  29.  
  30. nbtParser.NBTParser = NBTParser;
  31.  
  32. NBTParser.prototype.parse = function (deflatedBuf, options) {
  33.     this._reset();
  34.     if (!options) options = {};
  35.     var buf = pako.inflate(deflatedBuf);
  36.     if (options.mode === 'arrayBuffer') return buf;
  37.     this.bufView = new DataView(buf.buffer);
  38.     var parsed = this._parse();
  39.     if (options.mode === 'tags') return parsed;
  40.     if (options.mode === 'snbt') {
  41.         if (options.indentation) this.snbt.indentation = options.indentation;
  42.         return this._getSnbt(parsed);
  43.     }
  44.     return this._removeTags(parsed, options);
  45. };
  46.  
  47. NBTParser.prototype._reset = function () {
  48.     this.i = 0;
  49.     this.skipNextName = false;
  50.     this.bufView = null;
  51.     this.textDecoder = new TextDecoder('utf-8');
  52.     this.snbt = {
  53.         indentation: '  ',
  54.         level: 0
  55.     };
  56. };
  57.  
  58. NBTParser.prototype._parse = function () {
  59.     var tag = this._getUint8();
  60.     return this._parseTag(tag);
  61. };
  62.  
  63. NBTParser.prototype._parseTag = function (tag) {
  64.     if (tag === 0) return this._getTagEnd();
  65.     if (tag === 1) return this._getTagByte();
  66.     if (tag === 2) return this._getTagShort();
  67.     if (tag === 3) return this._getTagInt();
  68.     if (tag === 4) return this._getTagLong();
  69.     if (tag === 5) return this._getTagFloat();
  70.     if (tag === 6) return this._getTagDouble();
  71.     if (tag === 7) return this._getTagByteArray();
  72.     if (tag === 8) return this._getTagString();
  73.     if (tag === 9) return this._getTagList();
  74.     if (tag === 10) return this._getTagCompound();
  75.     if (tag === 11) return this._getTagIntArray();
  76.     if (tag === 12) return this._getTagLongArray();
  77.     throw new Error('Unknown tag: ' + tag);
  78. };
  79.  
  80. NBTParser.prototype._getName = function () {
  81.     if (this.skipNextName) {
  82.         this.skipNextName = false;
  83.         return null;
  84.     }
  85.     var nameLen = this._getUint16();
  86.     var nameBuf = this.bufView.buffer.slice(this.i, this.i + nameLen);
  87.     var name = this.textDecoder.decode(nameBuf) || null;
  88.     this.i += nameLen;
  89.     return name;
  90. };
  91.  
  92. NBTParser.prototype._getTagEnd = function () {
  93.     return {
  94.         tag: TAG_End
  95.     };
  96. };
  97.  
  98. NBTParser.prototype._getTagByte = function () {
  99.     var name = this._getName();
  100.     var value = this._getInt8();
  101.     return {
  102.         tag: TAG_Byte,
  103.         name,
  104.         value
  105.     };
  106. };
  107.  
  108. NBTParser.prototype._getTagShort = function () {
  109.     var name = this._getName();
  110.     var value = this._getInt16();
  111.     return {
  112.         tag: TAG_Short,
  113.         name,
  114.         value
  115.     };
  116. };
  117.  
  118. NBTParser.prototype._getTagInt = function () {
  119.     var name = this._getName();
  120.     var value = this._getInt32();
  121.     return {
  122.         tag: TAG_Int,
  123.         name,
  124.         value
  125.     };
  126. };
  127.  
  128. NBTParser.prototype._getTagLong = function () {
  129.     var name = this._getName();
  130.     var value = this._getBigInt64();
  131.     return {
  132.         tag: TAG_Long,
  133.         name,
  134.         value
  135.     };
  136. };
  137.  
  138. NBTParser.prototype._getTagFloat = function () {
  139.     var name = this._getName();
  140.     var value = this._getFloat32();
  141.     return {
  142.         tag: TAG_Float,
  143.         name,
  144.         value
  145.     };
  146. };
  147.  
  148. NBTParser.prototype._getTagDouble = function () {
  149.     var name = this._getName();
  150.     var value = this._getFloat64();
  151.     return {
  152.         tag: TAG_Double,
  153.         name,
  154.         value
  155.     };
  156. };
  157.  
  158. NBTParser.prototype._getTagByteArray = function () {
  159.     var name = this._getName();
  160.     var size = this._getInt32();
  161.     var value = [];
  162.  
  163.     for(var j = 0; j < size; j++) {
  164.         value.push(this._getInt8());
  165.     }
  166.  
  167.     return {
  168.         tag: TAG_Byte_Array,
  169.         name,
  170.         value
  171.     };
  172. };
  173.  
  174. NBTParser.prototype._getTagString = function () {
  175.     var name = this._getName();
  176.     var size = this._getUint16();
  177.     var strBuf = this.bufView.buffer.slice(this.i, this.i + size);
  178.     var value = this.textDecoder.decode(strBuf) || null;
  179.     this.i += size;
  180.  
  181.     return {
  182.         tag: TAG_String,
  183.         name,
  184.         value
  185.     };
  186. };
  187.  
  188. NBTParser.prototype._getTagList = function () {
  189.     var name = this._getName();
  190.     var payloadTag = this._getUint8();
  191.     var size = this._getUint32();
  192.     var value = [];
  193.  
  194.     for (var j = 0; j < size; j++) {
  195.         this.skipNextName = true;
  196.         var next = this._parseTag(payloadTag);
  197.         value.push(next);
  198.     }
  199.  
  200.     return {
  201.         tag: TAG_List,
  202.         name,
  203.         value
  204.     };
  205. };
  206.  
  207. NBTParser.prototype._getTagCompound = function () {
  208.     var name = this._getName();
  209.  
  210.     var value = {};
  211.     while (true) {
  212.         var next = this._parse();
  213.         if (next.tag === TAG_End) {
  214.             return {
  215.                 tag: TAG_Compound,
  216.                 name,
  217.                 value: value
  218.             };
  219.         }
  220.         if (!next.name) throw new Error('Missing name in compound tag');
  221.         value[next.name] = next;
  222.     }
  223. };
  224.  
  225. NBTParser.prototype._getTagIntArray = function () {
  226.     var name = this._getName();
  227.     var size = this._getInt32();
  228.     var value = [];
  229.  
  230.     for(var j = 0; j < size; j++) {
  231.         value.push(this._getInt32());
  232.     }
  233.  
  234.     return {
  235.         tag: TAG_Int_Array,
  236.         name,
  237.         value
  238.     };
  239. };
  240.  
  241. NBTParser.prototype._getTagLongArray = function () {
  242.     var name = this._getName();
  243.     var size = this._getInt32();
  244.     var value = [];
  245.  
  246.     for(var j = 0; j < size; j++) {
  247.         value.push(this._getBigInt64());
  248.     }
  249.  
  250.     return {
  251.         tag: TAG_Long_Array,
  252.         name,
  253.         value
  254.     };
  255. };
  256.  
  257. NBTParser.prototype._getUint8 = function () {
  258.     var value = this.bufView.getUint8(this.i);
  259.     this.i += 1;
  260.     return value;
  261. };
  262.  
  263. NBTParser.prototype._getUint16 = function () {
  264.     var value = this.bufView.getUint16(this.i);
  265.     this.i += 2;
  266.     return value;
  267. };
  268.  
  269. NBTParser.prototype._getUint32 = function () {
  270.     var value = this.bufView.getUint32(this.i);
  271.     this.i += 4;
  272.     return value;
  273. };
  274.  
  275. NBTParser.prototype._getInt8 = function () {
  276.     var value = this.bufView.getInt8(this.i);
  277.     this.i += 1;
  278.     return value;
  279. };
  280.  
  281. NBTParser.prototype._getInt16 = function () {
  282.     var value = this.bufView.getInt16(this.i);
  283.     this.i += 2;
  284.     return value;
  285. };
  286.  
  287. NBTParser.prototype._getInt32 = function () {
  288.     var value = this.bufView.getInt32(this.i);
  289.     this.i += 4;
  290.     return value;
  291. };
  292.  
  293. NBTParser.prototype._getBigInt64 = function () {
  294.     var value = this.bufView.getBigInt64(this.i);
  295.     this.i += 8;
  296.     return value;
  297. };
  298.  
  299. NBTParser.prototype._getFloat32 = function () {
  300.     var value = this.bufView.getFloat32(this.i);
  301.     this.i += 4;
  302.     return value;
  303. };
  304.  
  305. NBTParser.prototype._getFloat64 = function () {
  306.     var value = this.bufView.getFloat64(this.i);
  307.     this.i += 8;
  308.     return value;
  309. };
  310.  
  311. NBTParser.prototype._removeTags = function (parsed) {
  312.     if (!parsed) return;
  313.     if (parsed.tag === TAG_Compound) {
  314.         var entries = Object.entries(parsed.value);
  315.         var compound = {};
  316.         entries.forEach(([key, value]) => {
  317.             compound[key] = this._removeTags(value);
  318.         })
  319.         return compound;
  320.     }
  321.     if (parsed.tag === TAG_List) {
  322.         return parsed.value.map(val => this._removeTags(val));
  323.     }
  324.     return parsed.value;
  325. };
  326.  
  327. NBTParser.prototype._getSnbt = function (parsed) {
  328.     if (!parsed) return '';
  329.  
  330.     if (parsed.tag === TAG_Byte_Array) {
  331.         var str = '';
  332.         if (!parsed.name) str += this._indent();
  333.         var values = parsed.value;
  334.         str += '[B;';
  335.         if (values.length) str += ' ' + values.join(', ');
  336.         str += ']';
  337.         return str;
  338.     }
  339.  
  340.     if (parsed.tag === TAG_String) {
  341.         return '"' + parsed.value + '"';
  342.     }
  343.  
  344.     if (parsed.tag === TAG_List) {
  345.         var str = '';
  346.         if (!parsed.name) str += this._indent();
  347.         if (parsed.value.length === 0) return str += '[]';
  348.         str += '[\n';
  349.         this.snbt.level++;
  350.         var i = 0;
  351.         for (var i = 0; i < parsed.value.length; i++) {
  352.             if (i === parsed.value.length) {
  353.                 str += this._getSnbt(parsed.value[i]) + '\n';
  354.             } else {
  355.                 str += this._getSnbt(parsed.value[i]) + ',\n';
  356.             }
  357.         }
  358.         this.snbt.level--;
  359.         str += this._indent() + ']';
  360.         return str;
  361.     }
  362.  
  363.     if (parsed.tag === TAG_Compound) {
  364.         var str = '';
  365.         if (!parsed.name) str += this._indent();
  366.         if (Object.keys(parsed.value).length === 0) return str += '{}';
  367.         str += '{\n';
  368.         var entries = Object.entries(parsed.value);
  369.         this.snbt.level++;
  370.         var i = 0;
  371.         entries.forEach(([ key, value ]) => {
  372.             i++;
  373.             str += this._indent() + key + ': ';
  374.             if (i === entries.length) {
  375.                 str += this._getSnbt(value) + '\n';
  376.             } else {
  377.                 str += this._getSnbt(value) + ',\n';
  378.             }
  379.         });
  380.         this.snbt.level--;
  381.         str += this._indent() + '}';
  382.         return str;
  383.     }
  384.  
  385.     if (parsed.tag === TAG_Int_Array) {
  386.         var str = '';
  387.         if (!parsed.name) str += this._indent();
  388.         var values = parsed.value;
  389.         str += '[I;';
  390.         if (values.length) str += ' ' + values.join(', ');
  391.         str += ']';
  392.         return str;
  393.     }
  394.  
  395.     if (parsed.tag === TAG_Long_Array) {
  396.         var str = '';
  397.         if (!parsed.name) str += this._indent();
  398.         var values = parsed.value;
  399.         str += '[L;';
  400.         if (values.length) str += ' ' + values.map(v => v + 'L').join(', ');
  401.         str += ']';
  402.         return str;
  403.     }
  404.  
  405.     var tagSuffix = TYPE_SUFFIXES[parsed.tag] || '';
  406.     return '' + parsed.value + tagSuffix;
  407. };
  408.  
  409. NBTParser.prototype._indent = function () {
  410.     return Array(this.snbt.level).fill(this.snbt.indentation || ' ').join('');
  411. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement