From e67b6e058a71d7f9942192e060d252e7c6b63504 Mon Sep 17 00:00:00 2001 From: Ibrahim Ansari Date: Tue, 16 Apr 2024 00:35:42 +0530 Subject: [PATCH 1/4] refactor: remove Bvffer polyfill Any Buffer polyfill should be bundled by consumers instead, so we don't unnecessarily increase bundle sizes if they already have a Buffer impl. --- lib/bvffer.js | 104 ----------------------------------------- lib/tags/byte_array.js | 2 +- lib/tags/compound.js | 2 +- lib/tags/int.js | 2 +- lib/tags/short.js | 2 +- nbt.js | 3 +- types/lib/bvffer.d.ts | 30 ------------ 7 files changed, 5 insertions(+), 140 deletions(-) delete mode 100644 lib/bvffer.js delete mode 100644 types/lib/bvffer.d.ts diff --git a/lib/bvffer.js b/lib/bvffer.js deleted file mode 100644 index a89ee51..0000000 --- a/lib/bvffer.js +++ /dev/null @@ -1,104 +0,0 @@ -'use strict'; - -const defaultPoolSize = 64 * 1024; -if (Buffer.poolSize < defaultPoolSize) { - Buffer.poolSize = defaultPoolSize; -} - -class Bvffer { - constructor(buffByteLength) { - /** - * Buffer store data - */ - this.buffer = Buffer.allocUnsafe(buffByteLength); - /** - * data length in buffer - */ - this.dataByteLength = 0; - } - - get dataLength() { - return this.dataByteLength; - } - - get buff() { - return this.buffer; - } - - /** - * write buffer data to buffer - * @param {Buffer} value data to write - */ - writeBuffer(value) { - this.writeUInt16BE(value.length); - - value.copy(this.buffer, this.dataByteLength); - this.dataByteLength += value.length; - } - - /** - * @param {number} value value - */ - writeUInt8(value) { - this.buff[this.dataByteLength] = value; - this.dataByteLength += 1; - } - - /** - * @param {number} value value - */ - writeInt8(value) { - this.buff[this.dataByteLength] = value; - this.dataByteLength += 1; - } - - /** - * @param {number} value value - */ - writeUInt16BE(value) { - this.buffer.writeUInt16BE(value, this.dataByteLength); - this.dataByteLength += 2; - } - - /** - * @param {number} value value - */ - writeInt16BE(value) { - this.buffer.writeInt16BE(value, this.dataByteLength); - this.dataByteLength += 2; - } - - /** - * @param {number} value value - */ - writeUInt32BE(value) { - this.buffer.writeUInt32BE(value, this.dataByteLength); - this.dataByteLength += 4; - } - - /** - * @param {number} value value - */ - writeInt32BE(value) { - this.buffer.writeInt32BE(value, this.dataByteLength); - this.dataByteLength += 4; - } - - /** - * @param {number} value value - */ - writeDoubleBE(value) { - this.buffer.writeDoubleBE(value, this.dataByteLength); - this.dataByteLength += 8; - } - - /** - * @param {number} value value - */ - writeFloatBE(value) { - this.buffer.writeFloatBE(value, this.dataByteLength); - this.dataByteLength += 4; - } -} - -exports.Bvffer = Bvffer; diff --git a/lib/tags/byte_array.js b/lib/tags/byte_array.js index 066d2dc..2115a36 100644 --- a/lib/tags/byte_array.js +++ b/lib/tags/byte_array.js @@ -44,7 +44,7 @@ class TAGByteArray extends BaseTag { /** * Write body to buffer - * @param {Bvffer} buff The buffer to write to + * @param {Buffer} buff The buffer to write to * @param {number} offset The offset to start writing from */ writeBuffer(buff) { diff --git a/lib/tags/compound.js b/lib/tags/compound.js index b1b2d4b..26f2434 100644 --- a/lib/tags/compound.js +++ b/lib/tags/compound.js @@ -100,7 +100,7 @@ class TAGCompound extends BaseTag { /** * Write body to buffer - * @param {Bvffer} buff The buffer to write to + * @param {Buffer} buff The buffer to write to * @param {number} offset The offset to start writing to */ writeBuffer(buff) { diff --git a/lib/tags/int.js b/lib/tags/int.js index 069122b..9c417d4 100644 --- a/lib/tags/int.js +++ b/lib/tags/int.js @@ -27,7 +27,7 @@ class TAGInt extends BaseTag { /** * Write body to buffer - * @param {Bvffer} buff The buffer to write to + * @param {Buffer} buff The buffer to write to */ writeBuffer(buff) { buff.writeInt32BE(this.value); diff --git a/lib/tags/short.js b/lib/tags/short.js index e6da2fe..40c037c 100644 --- a/lib/tags/short.js +++ b/lib/tags/short.js @@ -27,7 +27,7 @@ class TAGShort extends BaseTag { /** * Write body to buffer - * @param {Bvffer} buff The buffer to write to + * @param {Buffer} buff The buffer to write to */ writeBuffer(buff) { buff.writeInt16BE(this.value); diff --git a/nbt.js b/nbt.js index 2c21c7c..f02ec43 100644 --- a/nbt.js +++ b/nbt.js @@ -4,7 +4,6 @@ const fs = require('fs'); const zlib = require('zlib'); const Tag = require('./lib/base_tag'); -const { Bvffer } = require('./lib/bvffer'); /** * The NBT class @@ -73,7 +72,7 @@ class NBT { * @return {Buffer} The buffer */ writeToBuffer() { - const buff = new Bvffer(this.calcBufferLength()); + const buff = new Buffer(this.calcBufferLength()); for (const key in this.root) { if (!this.root.hasOwnProperty(key)) continue; diff --git a/types/lib/bvffer.d.ts b/types/lib/bvffer.d.ts deleted file mode 100644 index e9370bb..0000000 --- a/types/lib/bvffer.d.ts +++ /dev/null @@ -1,30 +0,0 @@ -/** - * The Bvffer class - */ -declare class Bvffer { - constructor(buffByteLength: number); - - get dataLength(): number; - - get buff(): Buffer; - - writeBuffer(value): void; - - writeUInt8(value): void; - - writeInt8(value): void; - - writeUInt16BE(value): void; - - writeInt16BE(value): void; - - writeUInt32BE(value): void; - - writeInt32BE(value): void; - - writeFloatBE(value): void; - - writeDoubleBE(value): void; -} - -export = Bvffer; From 269a1c5715bad910533f8ef8261d38a7212db2fe Mon Sep 17 00:00:00 2001 From: Ibrahim Ansari Date: Tue, 16 Apr 2024 00:48:16 +0530 Subject: [PATCH 2/4] refactor: replace long with native JS BigInt This can be polyfilled on any JS platforms missing BigInt support. --- README.md | 5 ++--- lib/base_tag.js | 6 ++---- lib/tags/long.js | 23 +++++++++-------------- package.json | 4 ---- test/archive.js | 11 +++++++++-- test/bigtest_archive.js | 11 +++++++++-- types/lib/tags/long.d.ts | 5 ++--- 7 files changed, 33 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 12db110..394bb3a 100644 --- a/README.md +++ b/README.md @@ -112,8 +112,7 @@ No extra method. ### TAGLong -The value's type is long long ([bignum](https://github.com/justmoon/node-bignum) -in js). +The value's type is long (bigint in js). No extra method. @@ -125,7 +124,7 @@ No extra method. ### TAGDouble -The value's type is double (nbumer in js). +The value's type is double (number in js). No extra method. diff --git a/lib/base_tag.js b/lib/base_tag.js index 33d85b7..5864903 100644 --- a/lib/base_tag.js +++ b/lib/base_tag.js @@ -1,7 +1,5 @@ 'use strict'; -const Long = require('long'); - const TAG_TYPE_OFFSET = 1; let _tagIds; @@ -194,8 +192,8 @@ class BaseTag { return val; } - if (val instanceof Long) { - return val; + if (typeof val === 'bigint') { + return val.toString(); } if (this.type === 'TAG_Int_Array' || this.type === 'TAG_Byte_Array') { diff --git a/lib/tags/long.js b/lib/tags/long.js index f90f7eb..cafd70e 100644 --- a/lib/tags/long.js +++ b/lib/tags/long.js @@ -1,11 +1,10 @@ 'use strict'; const BaseTag = require('../base_tag'); -const Long = require('long'); const LONG_BOUND = { - MIN: Long.fromString('-9223372036854775808'), - MAX: Long.fromString('9223372036854775807'), + MIN: BigInt('-9223372036854775808'), + MAX: BigInt('9223372036854775807'), }; class TAGLong extends BaseTag { @@ -15,16 +14,12 @@ class TAGLong extends BaseTag { } _readBodyFromBuffer(buff, offset) { - const sliced = buff.slice(offset, offset + 8); - this.value = Long.fromBytesBE(sliced, true); + this.value = buff.readBigInt64BE(offset); return 8; } writeBuffer(buff) { - const bytes = this.value.toBytesBE(); - for (let i = 0; i < 8; i++) { - buff.writeUInt8(bytes[i]); - } + buff.writeBigInt64BE(this.value); } toJSON() { @@ -34,18 +29,18 @@ class TAGLong extends BaseTag { setValue(value) { let temp = -1; if (typeof value === 'string') { - temp = new Long(value); - } else if (value instanceof Long) { - temp = Long.fromString(value.toString()); + temp = BigInt(value); + } else if (typeof value === 'bigint') { + temp = value; } else if (typeof value === 'number' && !isNaN(value)) { - temp = Long.fromNumber(value); + temp = BigInt(value); } if (temp === -1) { throw new Error('Wrong type to set TAG_Long\'s value.'); } - if (temp.lessThan(LONG_BOUND.MIN) || temp.greaterThan(LONG_BOUND.MAX)) { + if (temp < LONG_BOUND.MIN || temp > LONG_BOUND.MAX) { throw new RangeError( 'Value of TAG_Long should between -9223372036854775808 and ' + '9223372036854775807'); diff --git a/package.json b/package.json index 29b0d59..148abdf 100644 --- a/package.json +++ b/package.json @@ -21,12 +21,8 @@ "url": "https://github.com/XadillaX/mcnbt/issues" }, "homepage": "https://github.com/XadillaX/mcnbt", - "dependencies": { - "long": "^4.0.0" - }, "types": "types/nbt.d.ts", "devDependencies": { - "@types/long": "^4.0.1", "@types/node": "^17.0.18", "eslint": "^8.9.0", "eslint-config-egg": "^11.0.0", diff --git a/test/archive.js b/test/archive.js index 8b76224..f11ee26 100644 --- a/test/archive.js +++ b/test/archive.js @@ -3,11 +3,18 @@ const fs = require('fs'); const util = require('util'); -const Long = require('long'); const should = require('should'); const NBT = require('../nbt'); +function tryBigInt(value) { + try { + return BigInt(value); + } catch (e) { + return BigInt(0); + } +} + describe('Real archive test', function() { const archive = new NBT(); let stdData = fs.readFileSync(__dirname + '/files/level.dat.json', { @@ -58,7 +65,7 @@ describe('Real archive test', function() { } else if (typeof result === 'string') { if (result === '') { node.getType().should.match(/^TAG_String/); - } else if (Long.fromString(result).toString() === result) { + } else if (tryBigInt(result).toString() === result) { node.getType().should.match(/^TAG_(Long|String)$/); } else { node.getType().should.match(/^TAG_String$/); diff --git a/test/bigtest_archive.js b/test/bigtest_archive.js index c2c6ba6..3cd838f 100644 --- a/test/bigtest_archive.js +++ b/test/bigtest_archive.js @@ -3,11 +3,18 @@ const fs = require('fs'); const util = require('util'); -const Long = require('long'); const should = require('should'); const NBT = require('../nbt'); +function tryBigInt(value) { + try { + return BigInt(value); + } catch (e) { + return BigInt(0); + } +} + describe('Real bugtest archive test', function() { const archive = new NBT(); const stdData = require('./files/bigtest.nbt.json'); @@ -57,7 +64,7 @@ describe('Real bugtest archive test', function() { } else if (typeof result === 'object' && !util.isArray(result)) { node.getType().should.be.eql('TAG_Compound'); } else if (typeof result === 'string') { - if (Long.fromString(result).toString() === result) { + if (tryBigInt(result).toString() === result) { node.getType().should.match(/^TAG_(String|Long)$/); } else { node.getType().should.be.eql('TAG_String'); diff --git a/types/lib/tags/long.d.ts b/types/lib/tags/long.d.ts index 09fdca6..bcfb8c4 100644 --- a/types/lib/tags/long.d.ts +++ b/types/lib/tags/long.d.ts @@ -1,9 +1,8 @@ import BaseTag from '../base_tag.d'; -import Long from 'long'; declare class TAGLong extends BaseTag { - getValue(): Long; - setValue(value: string | Long | number): void; + getValue(): bigint; + setValue(value: string | bigint | number): void; } export = TAGLong; From fe5837c7565413600a7cef53bd5c4fdbdf9dcdf5 Mon Sep 17 00:00:00 2001 From: Ibrahim Ansari Date: Sun, 5 May 2024 15:08:19 +0530 Subject: [PATCH 3/4] refactor: make loadFromBuffer callback optional This removes unnecessary callbacks for synchronous consumers. Since it is optional, existing code will continue to work fine. --- README.md | 2 +- nbt.js | 11 ++++++++--- types/nbt.d.ts | 4 ++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 394bb3a..2704f82 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ const NBT = require('mcnbt'); There're several function for you to parse an NBT structure after you instantiating an object: -+ `loadFromBuffer(buff, callback)` ++ `loadFromBuffer(buff, callback?)`: callback is optional + `loadFromZlibCompressedBuffer(buff, callback)` + `loadFromFile(filename, callback)` + `loadFromZlibCompressedFile(filename, callback)` diff --git a/nbt.js b/nbt.js index f02ec43..a0d8e6e 100644 --- a/nbt.js +++ b/nbt.js @@ -17,9 +17,10 @@ class NBT { /** * Load from buffer * @param {Buffer} buff The buffer to load from - * @param {(err?: Error) => void} callback The callback to call when done + * @param {(err?: Error) => void} [callback] The callback to call when done */ loadFromBuffer(buff, callback) { + let err; try { this._buff = buff; let offset = 0; @@ -32,10 +33,14 @@ class NBT { offset += len; } } catch (e) { - return callback(e); + err = e; } - callback(); + if (callback) { + callback(err); + } else { + throw err; + } } /** diff --git a/types/nbt.d.ts b/types/nbt.d.ts index 8ee6cd1..4bd2da2 100644 --- a/types/nbt.d.ts +++ b/types/nbt.d.ts @@ -9,9 +9,9 @@ declare class NBT { /** * Load from buffer * @param {Buffer} buff The buffer to load from - * @param {(err?: Error) => void} callback The callback to call when done + * @param {(err?: Error) => void} [callback] The callback to call when done */ - loadFromBuffer(buff: Buffer, callback: (err?: Error) => void): void; + loadFromBuffer(buff: Buffer, callback?: (err?: Error) => void): void; _buff: Buffer; /** * Load from compressed buffer From 3bc44434cf7204f00e4cf18e6d5747f9959c36ca Mon Sep 17 00:00:00 2001 From: Ibrahim Ansari Date: Mon, 29 Apr 2024 20:03:01 +0530 Subject: [PATCH 4/4] refactor: make fs/zlib optional for browsers This allows users to shrink bundle sizes by marking them as externals. I would prefer to do away with these entirely to shrink the library, but I've only opted to do this much for now. --- nbt.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nbt.js b/nbt.js index a0d8e6e..fa219af 100644 --- a/nbt.js +++ b/nbt.js @@ -1,7 +1,9 @@ 'use strict'; -const fs = require('fs'); -const zlib = require('zlib'); +let fs; +try { fs = require('fs'); } catch (e) { /* Not running on Node.js */ } +let zlib; +try { zlib = require('zlib'); } catch (e) { /* Not running on Node.js */ } const Tag = require('./lib/base_tag');