;; -*- Mode: Irken -*- ;; https://en.wikipedia.org/wiki/Ascii85 ;; base85 is a 4->5 encoding ;; we implement this as two sets of codecs ... ;; ;; 1) a uint32 <=> char[4] codec ;; 2) a char[5] <=> uint32 codec ;; ;; ... which are chained together. ;; since there are several approaches to padding in the ;; various 'standards', this issue is left to the user. ;; [hint: use padding/unpadding generators] ;; Note: no support for the special meanings for the 'z' ;; and 'y' chars. ;; char * 4 -> uint32 (define (ch->u32 gen) (let ((v 0) (n 0)) (makegen emit (for ch gen (set! v (logior (<< v 8) (char->int ch))) (inc! n) (when (= n 4) (emit v) (set! v 0) (set! n 0)))))) ;; uint32 -> char * 4 (define (u32->ch gen) (makegen emit (define (put n) (emit (int->char (logand #xff n)))) (for val gen (put (>> val 24)) (put (>> val 16)) (put (>> val 8)) (put (>> val 0)) ))) ;; uint32 -> char * 5 (define (u32->b85 gen32) (let ((vals (list:nil))) (makegen emit (for val gen32 (for-range i 5 (PUSH vals (int->char (+ 33 (mod val 85)))) (set! val (/ val 85))) (for-each emit vals) (set! vals (list:nil)) )))) ;; char * 5 -> uint32 (define (b85->u32 gen) (let ((val 0) (n 0)) (makegen emit (for ch gen (set! val (+ (* val 85) (- (char->int ch) 33))) (inc! n) (when (= n 5) (emit val) (set! val 0) (set! n 0)) )))) (define (b85-enc gen) (u32->b85 (ch->u32 gen))) (define (b85-dec gen) (u32->ch (b85->u32 gen))) (define (string->b85 s) (let ((result (list:nil))) (for ch (b85-enc (string-generator s)) (PUSH result ch)) (list->string result))) (define (b85->string s) (let ((result (list:nil))) (for ch (b85-dec (string-generator s)) (PUSH result ch)) (list->string result)))