Can embed any file in a PNG/WebM/GIF/JPEG and upload it to a third-party host through 4chan
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

168 lines
4.2 KiB

import { BitstreamReader as br, BitstreamWriter as bw } from '@astronautlabs/bitstream';
export const revbyte = (n: number, len = 8) => {
let acc = 0;
let n2 = n;
let len2 = len;
while (len2) {
// can't use bitshifts or binray ops or else becomes negative
acc = (acc * 2) + (n2 & 1);
n2 >>= 1;
len2--;
}
return acc;
};
export class BitstreamReader {
private buffers: Uint8Array[] = [];
private bufferedLength = 0;
private _offsetIntoBuffer = 0;
private _bufferIndex = 0;
private _offset = 0;
/**
* Get the index of the buffer currently being read. This will always be zero unless retainBuffers=true
*/
get bufferIndex() {
return this._bufferIndex;
}
/**
* Get the current offset in bits, starting from the very first bit read by this reader (across all
* buffers added)
*/
get offset() {
return this._offset;
}
/**
* The number of bits that are currently available.
*/
get available() {
return this.bufferedLength - this.skippedLength;
}
private skippedLength = 0;
/**
* Read an unsigned integer of the given bit length synchronously. If there are not enough
* bits available, an error is thrown.
*
* @param length The number of bits to read
* @returns The unsigned integer that was read
*/
getBit(offset: number) {
const byte = this.buffers[0][offset >> 3];
return +!!(byte & (1 << (offset & 7)));
}
readSync(length: number): number {
let value = 0;
//console.log(this.buffers[0])
if (this._offset >> 3 > this.buffers[0].byteLength) {
throw "Out of data";
}
//const byte = this.buffers[0][this._offset >> 3];
for (let i = length - 1; i >= 0; --i) {
value = value * 2 + this.getBit(this._offset + i);
}
this._offset += length;
this.bufferedLength -= length;
return value;
}
/**
* Add a buffer onto the end of the bitstream.
* @param buffer The buffer to add to the bitstream
*/
addBuffer(buffer: Uint8Array) {
this.buffers.push(buffer);
this.bufferedLength += buffer.length * 8;
}
}
export type Writable = {
write: (chunk: Uint8Array) => void;
};
export class BitstreamWriter {
/**
* Create a new writer
* @param stream The writable stream to write to
* @param bufferSize The number of bytes to buffer before flushing onto the writable
*/
constructor(public stream: Writable, bufferSize = 1) {
bufferSize = 1;
this.buffer = new Uint8Array(bufferSize);
}
private pendingBits = 0;
private buffer: Uint8Array;
bufferoffset = 0;
private _offset = 0;
/**
* How many bits have been written via this writer in total
*/
get offset() {
return this._offset;
}
/**
* How many bits into the current byte is the write cursor.
* If this value is zero, then we are currently byte-aligned.
* A value of 7 means we are 1 bit away from the byte boundary.
*/
get byteOffset() {
return this.pendingBits;
}
/**
* Finish the current byte (assuming zeros for the remaining bits, if necessary)
* and flushes the output.
*/
end() {
//this.finishByte();
this.flush();
}
flush() {
this.stream.write(new Uint8Array(this.buffer));
this.bufferoffset = 0;
this.buffer.fill(0);
}
setBit(b: number) {
if (b)
debugger;
let byte = this.buffer[0];
byte |= b << (this._offset & 7);
this.buffer[0] = byte;
this._offset += 1;
if (++this.bufferoffset == this.buffer.length * 8) {
this.flush();
}
}
/**
* Write the given number to the bitstream with the given bitlength. If the number is too large for the
* number of bits specified, the lower-order bits are written and the higher-order bits are ignored.
* @param length The number of bits to write
* @param value The number to write
*/
write(length: number, value: number) {
while (length--) {
this.setBit(value & 1);
value >>= 1;
}
}
}