Skip to content

Instantly share code, notes, and snippets.

@uWynell
Last active January 8, 2021 19:19
Show Gist options
  • Save uWynell/17b40eea4557ac686d3cbf9932f9eb46 to your computer and use it in GitHub Desktop.
Save uWynell/17b40eea4557ac686d3cbf9932f9eb46 to your computer and use it in GitHub Desktop.
Classes for convenient work with binary data
class BinaryWriter {
constructor(buffer = [], offset = 0, littleEndian = true) {
this.view = new DataView(new ArrayBuffer(8));
this._buffer = [];
this.littleEndian = false;
if (Array.isArray(buffer)) {
this._buffer = buffer;
}
else if (buffer instanceof ArrayBuffer) {
this._buffer = Array.from(new Uint8Array(buffer));
}
else if (buffer instanceof DataView ||
buffer instanceof Writer ||
buffer instanceof Uint8Array) {
this._buffer = Array.from(new Uint8Array(buffer.buffer));
}
else {
throw new Error('Buffer type is neither Array, nor Uint8Array, nor ArrayBuffer, nor DataView, nor Writer');
}
if (!offset || isNaN(offset))
this.offset = 0;
else
this.offset = offset;
this.view = new DataView(new ArrayBuffer(8));
this.littleEndian = littleEndian;
}
skip(offset = 1) {
this.offset += offset;
return this;
}
move(offset = 1) {
for (let i = 0; i < offset; i++) {
const byte = this.view.getUint8(i);
this._buffer[this.offset] = byte;
this.skip();
}
return this;
}
writeUint8(val) {
this.view.setUint8(0, val);
this.move();
return this;
}
writeInt8(val) {
this.view.setInt8(0, val);
this.move();
return this;
}
writeUint16(val) {
this.view.setUint16(0, val, this.littleEndian);
this.move(2);
return this;
}
writeInt16(val) {
this.view.setInt16(0, val, this.littleEndian);
this.move(2);
return this;
}
writeUint32(val) {
this.view.setUint32(0, val, this.littleEndian);
this.move(4);
return this;
}
writeInt32(val) {
this.view.setInt32(0, val, this.littleEndian);
this.move(4);
return this;
}
writeBigUint64(val) {
this.view.setBigUint64(0, BigInt(val), this.littleEndian);
this.move(8);
return this;
}
writeBigInt64(val) {
this.view.setBigInt64(0, BigInt(val), this.littleEndian);
this.move(8);
return this;
}
writeFloat32(val) {
this.view.setFloat32(0, val, this.littleEndian);
this.move(4);
return this;
}
writeFloat64(val) {
this.view.setFloat64(0, val, this.littleEndian);
this.move(8);
return this;
}
writeString(val) {
for (let i = 0; i < val.length; i++) {
const charCode = val.charCodeAt(i);
this.writeUint16(charCode);
}
this.writeUint16(0);
}
get buffer() {
return new Uint8Array(this._buffer).buffer;
}
get byteLength() {
return this._buffer.length;
}
}
class BinaryReader {
constructor(data, offset = 0, littleEndian = true) {
this.offset = 0;
this.littleEndian = true;
if (data instanceof DataView || data instanceof BinaryWriter) {
this.buffer = data.buffer;
}
else if (data instanceof ArrayBuffer) {
this.buffer = data;
}
else {
throw new Error('Given data is neither DataView, nor ArrayBuffer, nor Writer');
}
if (!offset || isNaN(offset))
this.offset = 0;
else
this.offset = offset;
this.littleEndian = Boolean(littleEndian);
}
skip(offset = 1) {
this.offset += offset;
return this;
}
skipString() {
while (true) {
const char = this.readUint16();
if (char === 0)
break;
}
return this;
}
readUint8() {
const result = this.view.getUint8(this.offset);
this.skip();
return result;
}
readInt8() {
const result = this.view.getInt8(this.offset);
this.skip();
return result;
}
readUint16() {
const result = this.view.getUint16(this.offset, this.littleEndian);
this.skip(2);
return result;
}
readInt16() {
const result = this.view.getInt16(this.offset, this.littleEndian);
this.skip(2);
return result;
}
readUint32() {
const result = this.view.getUint32(this.offset, this.littleEndian);
this.skip(4);
return result;
}
readInt32() {
const result = this.view.getInt32(this.offset, this.littleEndian);
this.skip(4);
return result;
}
readBigUint64() {
const result = this.view.getBigUint64(this.offset, this.littleEndian);
this.skip(8);
return result;
}
readBigInt64() {
const result = this.view.getBigInt64(this.offset, this.littleEndian);
this.skip(8);
return result;
}
readFloat32() {
const result = this.view.getFloat32(this.offset, this.littleEndian);
this.skip(4);
return result;
}
readFloat64() {
const result = this.view.getFloat64(this.offset, this.littleEndian);
this.skip(8);
return result;
}
readString() {
let result = '';
while (true) {
const charCode = this.readUint16();
if (charCode === 0)
break;
result += String.fromCharCode(charCode);
}
return result;
}
get buffer() {
return this.view.buffer;
}
set buffer(val) {
this.view = new DataView(val);
}
get byteLength() {
return this.view.byteLength;
}
}
window.BinaryReader = BinaryReader;
window.BinaryWriter = BinaryWriter;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment