Last active
November 5, 2024 23:34
-
-
Save freehuntx/8b554edcc6238105286b73e6f8388761 to your computer and use it in GitHub Desktop.
Buffer Serialization tools
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class DataViewStream { | |
_grow = false | |
_byteOffset = 0 | |
_view = null | |
_textDecoder = new TextDecoder() | |
_textEncoder = new TextEncoder() | |
get byteOffset() { return this._byteOffset } | |
get byteLength() { return this._view.byteLength } | |
get bytesLeft() { return this._view.byteLength - this._offset } | |
get buffer() { return this._view.buffer } | |
constructor(buffer=null, grow=false) { | |
this._grow = grow | |
this._view = new DataView(buffer || new ArrayBuffer(0)) | |
for (const name of Object.getOwnPropertyNames(DataView.prototype)) { | |
const match = name.match(/^([gs]et)([^\d]+)(\d+)$/) | |
if (!match) continue | |
const variant = match[1] | |
const type = match[2] | |
const bits = match[3] | |
const bytes = bits / 8 | |
this[name] = function(...args) { | |
return this._view[name](this._byteOffset, ...args) | |
} | |
if (variant === 'get') { | |
this[`read${type}${bits}`] = function(...args) { | |
const res = this._view[name](this._byteOffset, ...args) | |
this._byteOffset += bytes | |
return res | |
} | |
} else { | |
this[`write${type}${bits}`] = function(...args) { | |
this.expectBytes(bits/8) | |
const res = this._view[name](this._byteOffset, ...args) | |
this._byteOffset += bytes | |
return res | |
} | |
} | |
} | |
} | |
setCanGrow(grow) { | |
this._grow = grow | |
} | |
seek(byteOffset) { | |
this._byteOffset = byteOffset | |
} | |
appendBytes(num) { | |
if (!this._grow) throw new Error('Cannot grow') | |
const oldBuffer = new Uint8Array(this._view.buffer) | |
const newBuffer = new Uint8Array(new ArrayBuffer(oldBuffer.length + num)) | |
newBuffer.set(oldBuffer) | |
this._view = new DataView(newBuffer.buffer) | |
} | |
expectBytes(byteCount) { | |
if (!this._grow) return | |
const missingBytes = (this.bytesLeft - byteCount) * -1 | |
if (missingBytes > 0) { | |
this.appendBytes(missingBytes) | |
} | |
} | |
// Buffer | |
getBuffer(len=-1) { | |
if (len === -1) len = this._view.byteLength - this._byteOffset | |
const byteOffset = this._view.byteOffset + this._byteOffset | |
return this._view.buffer.slice(byteOffset, byteOffset + len) | |
} | |
readBuffer(len=-1) { | |
const buffer = this.getBuffer(len) | |
this._byteOffset += buffer.byteLength | |
return buffer | |
} | |
setBuffer(buffer) { | |
this.expectBytes(buffer.byteLength) | |
const bytes = new Uint8Array(buffer) | |
for (let i=0; i<bytes.length; i++) { | |
this._view.setUint8(this._byteOffset + i, bytes[i]) | |
} | |
} | |
writeBuffer(buffer) { | |
this.setBuffer(buffer) | |
this._byteOffset += buffer.byteLength | |
} | |
// Prefixed String | |
getPString(byteLen=4) { | |
const byteOffset = this._byteOffset | |
let len = -1 | |
if (byteLen === 1) len = this.readInt8() | |
else if (byteLen === 2) len = this.readInt16() | |
else if (byteLen === 4) len = this.readInt32() | |
const string = len > 0 ? this.readString(len) : '' | |
this.seek(byteOffset) | |
return string | |
} | |
readPString(byteLen=4) { | |
const string = this.getPString(byteLen) | |
this._byteOffset += byteLen + string.length | |
return string | |
} | |
setPString(string, byteLen=4) { | |
const byteOffset = this._byteOffset | |
this.writePString(string, byteLen) | |
this.seek(byteOffset) | |
} | |
writePString(string, byteLen=4) { | |
if (byteLen === 1) this.writeInt8(string.length || -1) | |
else if (byteLen === 2) this.writeInt16(string.length || -1) | |
else if (byteLen === 4) this.writeInt32(string.length || -1) | |
if (string.length > 0) this.writeString(string) | |
} | |
// String | |
getString(len) { | |
return this._textDecoder.decode(this.getBuffer(len)) | |
} | |
readString(len) { | |
const string = this.getString(len) | |
this._byteOffset += len | |
return string | |
} | |
setString(string) { | |
this.setBuffer(this._textEncoder.encode(string).buffer) | |
} | |
writeString(string) { | |
this.writeBuffer(this._textEncoder.encode(string).buffer) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment