Created
May 8, 2024 14:14
-
-
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
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 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); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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)