Skip to content

Instantly share code, notes, and snippets.

@bbb651
Created May 8, 2024 14:14
Show Gist options
  • Select an option

  • Save bbb651/cd29dc3e66606d714e852e957204c2dd to your computer and use it in GitHub Desktop.

Select an option

Save bbb651/cd29dc3e66606d714e852e957204c2dd to your computer and use it in GitHub Desktop.
Line by line translation of thisismypassword's Picotron pxu decoder from python to typescript
class CursorView {
private data: DataView
private cursor: number = 0
constructor(data: DataView) {
this.data = data;
}
getUint8() { return this.data.getUint8((this.cursor += 1) - 1); }
getUint16() { return this.data.getUint16((this.cursor += 2) - 2, true); }
getUint32() { return this.data.getUint32((this.cursor += 4) - 4, true); }
}
export function pxuDecode(encoded: Uint8Array): Uint8Array {
const view = new CursorView(new DataView(encoded.buffer));
const flags = view.getUint16();
if ((flags & ~0x840) !== 0x2003) {
throw new Error("Unknown flags");
}
const hasHeight = (flags & 0x40) !== 0;
const longSize = (flags & 0x800) !== 0;
const width = longSize ? view.getUint32() : view.getUint8();
const height = hasHeight ? (longSize ? view.getUint32() : view.getUint8()) : 1;
const size = width * height
const bits = view.getUint8();
if (bits !== 4) {
throw new Error("Unknown bits division");
}
const data: number[] = [];
const meanings: number[] = new Array(0xf).fill(null);
let nextRepeat = 0xe;
while (data.length < size) {
const byte = view.getUint8();
let value = byte & 0xf;
if (value === 0xf) {
value = view.getUint8();
if (nextRepeat >= 0) {
meanings[nextRepeat] = value;
}
} else {
if (value === nextRepeat) {
nextRepeat -= 1;
while (nextRepeat >= 0 && meanings[nextRepeat] != null) {
nextRepeat -= 1;
}
}
if (meanings[value] !== null) {
value = meanings[value]
} else {
meanings[value] = value;
}
}
let count = 1 + (byte >> 4);
if (count == 0x10) {
while (true) {
const c = view.getUint8();
count += c;
if (c != 0xff) {
break;
}
}
}
for (let i = 0; i < count; i++) {
data.push(value);
}
}
return Uint8Array.from(data);
}
@thisismypassport
Copy link

FYI, the code this was based on wasn't tested sufficiently well and was wrong for larger pxus
I've figured out the correct algorithm now (python version will end up in the shrinko repo soon)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment