Skip to content

Instantly share code, notes, and snippets.

@plexus
Created July 26, 2023 08:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save plexus/a6e9b38bd644149f7e08db7c75a6fbbc to your computer and use it in GitHub Desktop.
Save plexus/a6e9b38bd644149f7e08db7c75a6fbbc to your computer and use it in GitHub Desktop.
(module encode_decode
(:import
[fs :from "node:fs"]))
(def in (fs.readFileSync "/home/arne/tmp/screenshot_00.png"))
(def out (js:ArrayBuffer. (* 2 (count in))))
(def out-arr (js:Uint8Array. out))
(def [widx ridx] [0 0])
(defn write! [byte]
(assoc! out-arr widx byte)
(set! widx (inc widx)))
(defn read! []
(when (< ridx (count in))
(let [byte (get in ridx)]
(set! ridx (inc ridx))
byte)))
(while (< ridx (count in))
(let [x (read!)]
(if (and (< x 128)
(not (or (= x 13) (= x 10) (= x 92) (= x 34))))
;; fits in 7 bits, and is not a newline, carriage return, quote, or backslash
(write! x)
;; can't be encoded in a single UTF-8 byte, split two bytes over three
(let [y (read!)]
(if y
(do
;; 1110xxxx
(write! (bit-or (+ 128 64 32) (bit-shift-right x 4)))
;; 10xxxxyy
(write! (bit-or 128
(bit-and (+ 32 16 8 4)
(bit-shift-left x 2))
(bit-shift-right y 6)))
;; 10yyyyyy
(write! (bit-or 128 (bit-and (+ 32 16 8 4 2 1) y))))
(do
;; 1100xxxx
(write! (bit-or (+ 128 64) (bit-shift-right x 4)))
;; 1000xxxx
(write! (bit-or 128 (bit-and (+ 8 4 2 1) x)))))))))
(fs:writeFileSync "/tmp/out" (js:Uint8Array. (out.slice 0 widx)))
(fs:writeFileSync "/tmp/out.js" (str
"const x = \""
(.decode
(js:TextDecoder.)
(js:Uint8Array. (out.slice 0 widx))) "\""))
;; decode
(def in (fs.readFileSync "/tmp/out"))
(def out (js:ArrayBuffer. (count in)))
(def out-arr (js:Uint8Array. out))
(def [widx ridx] [0 0])
(while (< ridx (count in))
(let [x (read!)]
(cond (< x 128)
(write! x)
(< x (+ 128 64 32))
(let [y (read!)]
;; Final byte spread across two bytes
(write! (bit-or
(bit-shift-left x 4)
(bit-and (+ 1 2 4 8) y))))
:else
(let [y (read!)
z (read!)]
;; Two bytes spread across three
(write! (bit-or
(bit-shift-left x 4)
(bit-and (+ 1 2 4 8) (bit-shift-right y 2))))
(write! (bit-or
(bit-shift-left y 6)
(bit-and (+ 1 2 4 8 16 32) z)))))))
;; (fs:writeFileSync "/tmp/roundtrip"
;; )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment