aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--guix/utils.scm130
-rw-r--r--tests/utils.scm16
2 files changed, 146 insertions, 0 deletions
diff --git a/guix/utils.scm b/guix/utils.scm
index 2ffecbfab9..65e89a0e1b 100644
--- a/guix/utils.scm
+++ b/guix/utils.scm
@@ -22,6 +22,7 @@
#:use-module (srfi srfi-39)
#:use-module (srfi srfi-60)
#:use-module (rnrs bytevectors)
+ #:use-module (ice-9 vlist)
#:use-module (ice-9 format)
#:autoload (ice-9 popen) (open-pipe*)
#:autoload (ice-9 rdelim) (read-line)
@@ -32,6 +33,8 @@
bytevector->base32-string
bytevector->nix-base32-string
bytevector->base16-string
+ base32-string->bytevector
+ nix-base32-string->bytevector
sha256
%nixpkgs-directory
@@ -169,6 +172,133 @@ the previous application or INIT."
(make-bytevector->base32-string bytevector-quintet-fold-right
%nix-base32-chars))
+
+(define bytevector-quintet-set!
+ (let* ((setq! (lambda (bv offset start stop value)
+ (let ((v (bytevector-u8-ref bv offset))
+ (w (arithmetic-shift value start))
+ (m (bitwise-xor (1- (expt 2 stop))
+ (1- (expt 2 start)))))
+ (bytevector-u8-set! bv offset
+ (bitwise-merge m w v)))))
+ (set0! (lambda (bv offset value)
+ (setq! bv offset 3 8 value)))
+ (set1! (lambda (bv offset value)
+ (setq! bv offset 0 3 (bit-field value 2 5))
+ (or (= (+ 1 offset) (bytevector-length bv))
+ (setq! bv (+ 1 offset) 6 8 (bit-field value 0 2)))))
+ (set2! (lambda (bv offset value)
+ (setq! bv offset 1 6 value)))
+ (set3! (lambda (bv offset value)
+ (setq! bv offset 0 1 (bit-field value 4 5))
+ (or (= (+ 1 offset) (bytevector-length bv))
+ (setq! bv (+ 1 offset) 4 8 (bit-field value 0 4)))))
+ (set4! (lambda (bv offset value)
+ (setq! bv offset 0 4 (bit-field value 1 5))
+ (or (= (+ 1 offset) (bytevector-length bv))
+ (setq! bv (+ 1 offset) 7 8 (bit-field value 0 1)))))
+ (set5! (lambda (bv offset value)
+ (setq! bv offset 2 7 value)))
+ (set6! (lambda (bv offset value)
+ (setq! bv offset 0 2 (bit-field value 3 5))
+ (or (= (+ 1 offset) (bytevector-length bv))
+ (setq! bv (+ 1 offset) 5 8 (bit-field value 0 3)))))
+ (set7! (lambda (bv offset value)
+ (setq! bv offset 0 5 value)))
+ (sets (vector set0! set1! set2! set3! set4! set5! set6! set7!)))
+ (lambda (bv index value)
+ "Set the INDEXth quintet of BV to VALUE."
+ (let ((p (vector-ref sets (modulo index 8))))
+ (p bv (quotient (* index 5) 8) (logand value #x1f))))))
+
+(define bytevector-quintet-set-right!
+ (let* ((setq! (lambda (bv offset start stop value)
+ (let ((v (bytevector-u8-ref bv offset))
+ (w (arithmetic-shift value start))
+ (m (bitwise-xor (1- (expt 2 stop))
+ (1- (expt 2 start)))))
+ (bytevector-u8-set! bv offset
+ (bitwise-merge m w v)))))
+ (set0! (lambda (bv offset value)
+ (setq! bv offset 0 5 value)))
+ (set1! (lambda (bv offset value)
+ (setq! bv offset 5 8 (bit-field value 0 3))
+ (or (= (+ 1 offset) (bytevector-length bv))
+ (setq! bv (+ 1 offset) 0 2 (bit-field value 3 5)))))
+ (set2! (lambda (bv offset value)
+ (setq! bv offset 2 7 value)))
+ (set3! (lambda (bv offset value)
+ (setq! bv offset 7 8 (bit-field value 0 1))
+ (or (= (+ 1 offset) (bytevector-length bv))
+ (setq! bv (+ 1 offset) 0 4 (bit-field value 1 5)))))
+ (set4! (lambda (bv offset value)
+ (setq! bv offset 4 8 (bit-field value 0 4))
+ (or (= (+ 1 offset) (bytevector-length bv))
+ (setq! bv (+ 1 offset) 0 1 (bit-field value 4 5)))))
+ (set5! (lambda (bv offset value)
+ (setq! bv offset 1 6 value)))
+ (set6! (lambda (bv offset value)
+ (setq! bv offset 6 8 (bit-field value 0 2))
+ (or (= (+ 1 offset) (bytevector-length bv))
+ (setq! bv (+ 1 offset) 0 3 (bit-field value 2 5)))))
+ (set7! (lambda (bv offset value)
+ (setq! bv offset 3 8 value)))
+ (sets (vector set0! set1! set2! set3! set4! set5! set6! set7!)))
+ (lambda (bv index value)
+ "Set the INDEXth quintet of BV to VALUE, assuming quintets start from
+the least-significant bits."
+ (let ((p (vector-ref sets (modulo index 8))))
+ (p bv (quotient (* index 5) 8) (logand value #x1f))))))
+
+(define (base32-string-unfold f s)
+ "Given procedure F which, when applied to a character, returns the
+corresponding quintet, return the bytevector corresponding to string S."
+ (define len (string-length s))
+
+ (let ((bv (make-bytevector (quotient (* len 5) 8))))
+ (string-fold (lambda (chr index)
+ (bytevector-quintet-set! bv index (f chr))
+ (+ 1 index))
+ 0
+ s)
+ bv))
+
+(define (base32-string-unfold-right f s)
+ "Given procedure F which, when applied to a character, returns the
+corresponding quintet, return the bytevector corresponding to string S,
+starting from the right of S."
+ (define len (string-length s))
+
+ (let ((bv (make-bytevector (quotient (* len 5) 8))))
+ (string-fold-right (lambda (chr index)
+ (bytevector-quintet-set-right! bv index (f chr))
+ (+ 1 index))
+ 0
+ s)
+ bv))
+
+(define (make-base32-string->bytevector base32-string-unfold base32-chars)
+ (let ((char->value (let loop ((i 0)
+ (v vlist-null))
+ (if (= i (vector-length base32-chars))
+ v
+ (loop (+ 1 i)
+ (vhash-consv (vector-ref base32-chars i)
+ i v))))))
+ (lambda (s)
+ "Return the binary representation of base32 string S as a bytevector."
+ (base32-string-unfold (lambda (chr)
+ (or (and=> (vhash-assv chr char->value) cdr)
+ (error "invalid base32 character" chr)))
+ s))))
+
+(define base32-string->bytevector
+ (make-base32-string->bytevector base32-string-unfold %rfc4648-base32-chars))
+
+(define nix-base32-string->bytevector
+ (make-base32-string->bytevector base32-string-unfold-right %nix-base32-chars))
+
+
;;;
;;; Base 16.
diff --git a/tests/utils.scm b/tests/utils.scm
index eade84b5d4..edea11db72 100644
--- a/tests/utils.scm
+++ b/tests/utils.scm
@@ -46,6 +46,22 @@
"mzxw6ytb"
"mzxw6ytboi")))
+(test-assert "base32-string->bytevector"
+ (every (lambda (bv)
+ (equal? (base32-string->bytevector
+ (bytevector->base32-string bv))
+ bv))
+ ;; Examples from RFC 4648.
+ (map string->utf8 '("" "f" "fo" "foo" "foob" "fooba" "foobar"))))
+
+(test-assert "nix-base32-string->bytevector"
+ (every (lambda (bv)
+ (equal? (nix-base32-string->bytevector
+ (bytevector->nix-base32-string bv))
+ bv))
+ ;; Examples from RFC 4648.
+ (map string->utf8 '("" "f" "fo" "foo" "foob" "fooba" "foobar"))))
+
;; The following tests requires `nix-hash' in $PATH.
(test-skip (if (false-if-exception (system* "nix-hash" "--version"))
0