From ca05acd361b03c6a7b80887df24486efe215eaf7 Mon Sep 17 00:00:00 2001 From: Offroaders123 <65947371+Offroaders123@users.noreply.github.com> Date: Mon, 12 Dec 2022 11:30:29 -0800 Subject: [PATCH] End of Buffer Error Been chewing on this for the last few days for some reason. I think the error message wasn't quite what I wanted it to be, so I wasn't ready to commit it to the repo just yet. I like this error message now, as it's more clear what happened, but also not overly-verbose, which is what I didn't like about the error messages I had made so far. This essentially checks if the `NBTReader`'s reading `#byteOffset` is longer than the source `Uint8Array`'s length, which would mean that it can't read any more data, since it's read up to the end of the buffer. This puts a little roadblock before showing any confusing `DataView` errors, which aren't as apparent as to what went wrong. These should help make things more visible to the user, if something is wrong with the data, or if they are reading in the wrong format. I'm gonna do some more testing after getting this initial version for these errors up, and maybe moving the error back a little bit, to where the `#byteOffset` is incremented to a value higher than the buffer length. This would make the error show up sooner while reading the data, as it would make the error-prone next read exclusive, rather than inclusive. In other words, instead of throwing the error when it tries to read at an il-formatted offset, it will throw when the offset is set to that il-formatted length. I just keep flip-flopping on how the errors should be (I seem to do this a lot with the JSDoc annotations too), so I have to commit something now, or else I'll just keep working on this derpy little fix forever, for some reason, aaah! XD --- src/read.ts | 32 ++++++++++++++++++++++++++++++-- test/index.js | 2 +- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/read.ts b/src/read.ts index a20fc39..9664e07 100644 --- a/src/read.ts +++ b/src/read.ts @@ -158,7 +158,6 @@ export class NBTReader { const remaining = this.#data.byteLength - this.#byteOffset; throw new Error(`Encountered unexpected End tag at byte offset ${this.#byteOffset}, ${remaining} unread bytes remaining`); } - case TAG.BYTE: return new Byte(this.#readByte()); case TAG.SHORT: return new Short(this.#readShort()); case TAG.INT: return new Int(this.#readInt()); @@ -171,7 +170,6 @@ export class NBTReader { case TAG.COMPOUND: return this.#readCompound(); case TAG.INT_ARRAY: return this.#readIntArray(); case TAG.LONG_ARRAY: return this.#readLongArray(); - default: throw new Error(`Encountered unsupported tag type ${type} at byte offset ${this.#byteOffset}`); } } @@ -181,48 +179,72 @@ export class NBTReader { } #readUnsignedByte() { + if (this.#byteOffset + 1 > this.#data.byteLength){ + throw new Error("Ran out of bytes to read, unexpectedly reached the end of the buffer"); + } const value = this.#view.getUint8(this.#byteOffset); this.#byteOffset += 1; return value; } #readByte() { + if (this.#byteOffset + 1 > this.#data.byteLength){ + throw new Error("Ran out of bytes to read, unexpectedly reached the end of the buffer"); + } const value = this.#view.getInt8(this.#byteOffset); this.#byteOffset += 1; return value; } #readUnsignedShort() { + if (this.#byteOffset + 2 > this.#data.byteLength){ + throw new Error("Ran out of bytes to read, unexpectedly reached the end of the buffer"); + } const value = this.#view.getUint16(this.#byteOffset,this.#littleEndian); this.#byteOffset += 2; return value; } #readShort() { + if (this.#byteOffset + 2 > this.#data.byteLength){ + throw new Error("Ran out of bytes to read, unexpectedly reached the end of the buffer"); + } const value = this.#view.getInt16(this.#byteOffset,this.#littleEndian); this.#byteOffset += 2; return value; } #readInt() { + if (this.#byteOffset + 4 > this.#data.byteLength){ + throw new Error("Ran out of bytes to read, unexpectedly reached the end of the buffer"); + } const value = this.#view.getInt32(this.#byteOffset,this.#littleEndian); this.#byteOffset += 4; return value; } #readLong() { + if (this.#byteOffset + 8 > this.#data.byteLength){ + throw new Error("Ran out of bytes to read, unexpectedly reached the end of the buffer"); + } const value = this.#view.getBigInt64(this.#byteOffset,this.#littleEndian); this.#byteOffset += 8; return value; } #readFloat() { + if (this.#byteOffset + 4 > this.#data.byteLength){ + throw new Error("Ran out of bytes to read, unexpectedly reached the end of the buffer"); + } const value = this.#view.getFloat32(this.#byteOffset,this.#littleEndian); this.#byteOffset += 4; return value; } #readDouble() { + if (this.#byteOffset + 8 > this.#data.byteLength){ + throw new Error("Ran out of bytes to read, unexpectedly reached the end of the buffer"); + } const value = this.#view.getFloat64(this.#byteOffset,this.#littleEndian); this.#byteOffset += 8; return value; @@ -230,6 +252,9 @@ export class NBTReader { #readByteArray() { const byteLength = this.#readInt(); + if (this.#byteOffset + byteLength > this.#data.byteLength){ + throw new Error("Ran out of bytes to read, unexpectedly reached the end of the buffer"); + } const value = new Int8Array(this.#data.subarray(this.#byteOffset,this.#byteOffset + byteLength)); this.#byteOffset += byteLength; return value; @@ -237,6 +262,9 @@ export class NBTReader { #readString() { const length = this.#readUnsignedShort(); + if (this.#byteOffset + length > this.#data.byteLength){ + throw new Error("Ran out of bytes to read, unexpectedly reached the end of the buffer"); + } const value = decoder.decode(this.#data.subarray(this.#byteOffset,this.#byteOffset + length)); this.#byteOffset += length; return value; diff --git a/test/index.js b/test/index.js index 1c6fe4b..5d7dbc5 100644 --- a/test/index.js +++ b/test/index.js @@ -10,7 +10,7 @@ const result = await NBT.read(data); console.log(result,"\n"); const result2 = await NBT.write(result,{ bedrockLevel: null }) -.then(buffer => NBT.read(buffer,{ endian: "big", isNamed: false })); +.then(buffer => NBT.read(buffer,{ endian: "big" })); console.log(result2,"\n"); const recompile = Buffer.from(await NBT.write(result2));