#lang scheme/base
(require "depend.ss"
)
(define (q-preserve? b)
(or (<= (char->integer #\A) b (char->integer #\Z))
(<= (char->integer #\a) b (char->integer #\z))
(<= (char->integer #\0) b (char->integer #\9))
(memq b (map char->integer '(#\! #\* #\+ #\- #\/ #\= #\_)))))
(define (q-convert? b)
(not (q-preserve? b)))
(define (integer->hex-string i)
(define (helper str)
(if (= (string-length str) 1)
(string-append "0" str)
str))
(helper (format "~x" i)))
(define (byte->q-bytes b)
(bytes->list (string->bytes/utf-8
(format "=~a" (integer->hex-string b)))))
(define p:q-encode-byte (choice (byte-when q-preserve?)
(seq v <- (byte-when q-convert?)
(return (byte->q-bytes v)))))
(define p:q-encode-bytes (seq bytes <- (zero-many p:q-encode-byte)
(return (list->bytes (flatten bytes)))))
(define q-encode (make-reader p:q-encode-bytes))
(define p:q-encoded (seq #"=" h1 <- hexdecimal h2 <- hexdecimal
(return (string->number (format "#x~a~a" h1 h2)))))
(define p:q-decode-byte (choice p:q-encoded any-byte))
(define p:q-decode-bytes (seq v <- (zero-many p:q-decode-byte)
(return (list->bytes v))))
(define q-decode (make-reader p:q-decode-bytes))
(provide/contract
(q-decode Reader/c)
(q-encode Reader/c))