-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
913f4ea
commit 938f75d
Showing
11 changed files
with
247 additions
and
42 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
; | ||
; Copyright (C) 2024 The Goldfish Scheme Authors | ||
; | ||
; Licensed under the Apache License, Version 2.0 (the "License"); | ||
; you may not use this file except in compliance with the License. | ||
; You may obtain a copy of the License at | ||
; | ||
; http://www.apache.org/licenses/LICENSE-2.0 | ||
; | ||
; Unless required by applicable law or agreed to in writing, software | ||
; distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
; WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
; License for the specific language governing permissions and limitations | ||
; under the License. | ||
; | ||
|
||
(define-library (liii base64) | ||
(import (liii base) | ||
(liii bitwise)) | ||
(export | ||
string-base64-encode bytevector-base64-encode base64-encode | ||
string-base64-decode bytevector-base64-decode base64-decode | ||
) | ||
(begin | ||
(define-constant BYTE2BASE64_BV | ||
(string->utf8 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")) | ||
|
||
(define-constant BASE64_PAD_BYTE | ||
(char->integer #\=)) | ||
|
||
(define bytevector-base64-encode | ||
(typed-lambda ((bv bytevector?)) | ||
(define (encode b1 b2 b3) | ||
(let* ((p1 b1) | ||
(p2 (if b2 b2 0)) | ||
(p3 (if b3 b3 0)) | ||
(combined (bitwise-ior (ash p1 16) (ash p2 8) p3)) | ||
(c1 (bitwise-and (ash combined -18) #x3F)) | ||
(c2 (bitwise-and (ash combined -12) #x3F)) | ||
(c3 (bitwise-and (ash combined -6) #x3F)) | ||
(c4 (bitwise-and combined #x3F))) | ||
(values | ||
(BYTE2BASE64_BV c1) | ||
(BYTE2BASE64_BV c2) | ||
(if b2 (BYTE2BASE64_BV c3) BASE64_PAD_BYTE) | ||
(if b3 (BYTE2BASE64_BV c4) BASE64_PAD_BYTE)))) | ||
|
||
(let* ((input-N (bytevector-length bv)) | ||
(output-N (* 4 (ceiling (/ input-N 3)))) | ||
(output (make-bytevector output-N))) | ||
(let loop ((i 0) (j 0)) | ||
(when (< i input-N) | ||
(let* ((b1 (bv i)) | ||
(b2 (if (< (+ i 1) input-N) (bv (+ i 1)) #f)) | ||
(b3 (if (< (+ i 2) input-N) (bv (+ i 2)) #f))) | ||
(receive (r1 r2 r3 r4) (encode b1 b2 b3) | ||
(bytevector-u8-set! output j r1) | ||
(bytevector-u8-set! output (+ j 1) r2) | ||
(bytevector-u8-set! output (+ j 2) r3) | ||
(bytevector-u8-set! output (+ j 3) r4) | ||
(loop (+ i 3) (+ j 4)))))) | ||
output))) | ||
|
||
(define string-base64-encode | ||
(typed-lambda ((str string?)) | ||
(utf8->string (bytevector-base64-encode (string->utf8 str))))) | ||
|
||
(define (base64-encode x) | ||
(cond ((string? x) | ||
(string-base64-encode x)) | ||
((bytevector? x) | ||
(bytevector-base64-encode x)) | ||
(else | ||
(type-error "input must be string or bytevector")))) | ||
|
||
(define-constant BASE64_TO_BYTE_V | ||
(let1 byte2base64-N (bytevector-length BYTE2BASE64_BV) | ||
(let loop ((i 0) (v (make-vector 256 -1))) | ||
(if (< i byte2base64-N) | ||
(begin | ||
(vector-set! v (BYTE2BASE64_BV i) i) | ||
(loop (+ i 1) v)) | ||
v)))) | ||
|
||
(define (bytevector-base64-decode bv) | ||
(define (decode c1 c2 c3 c4) | ||
(let* ((b1 (BASE64_TO_BYTE_V c1)) | ||
(b2 (BASE64_TO_BYTE_V c2)) | ||
(b3 (BASE64_TO_BYTE_V c3)) | ||
(b4 (BASE64_TO_BYTE_V c4))) | ||
(if (or (negative? b1) (negative? b2) | ||
(and (negative? b3) (!= c3 BASE64_PAD_BYTE)) | ||
(and (negative? b4) (!= c4 BASE64_PAD_BYTE))) | ||
(value-error "Invalid base64 input") | ||
(values | ||
(bitwise-ior (ash b1 2) (ash b2 -4)) | ||
(bitwise-and (bitwise-ior (ash b2 4) (ash b3 -2)) #xFF) | ||
(bitwise-and (bitwise-ior (ash b3 6) b4) #xFF) | ||
(if (negative? b3) 1 (if (negative? b4) 2 3)))))) | ||
|
||
(let* ((input-N (bytevector-length bv)) | ||
(output-N (* input-N 3/4)) | ||
(output (make-bytevector output-N))) | ||
|
||
(unless (zero? (modulo input-N 4)) | ||
(value-error "length of the input bytevector must be 4X")) | ||
|
||
(let loop ((i 0) (j 0)) | ||
(if (< i input-N) | ||
(receive (r1 r2 r3 cnt) | ||
(decode (bv i) (bv (+ i 1)) (bv (+ i 2)) (bv (+ i 3))) | ||
(bytevector-u8-set! output j r1) | ||
(when (>= cnt 2) | ||
(bytevector-u8-set! output (+ j 1) r2)) | ||
(when (>= cnt 3) | ||
(bytevector-u8-set! output (+ j 2) r3)) | ||
(loop (+ i 4) (+ j cnt))) | ||
(let ((final (make-bytevector j))) | ||
(vector-copy! final 0 output 0 j) | ||
final))))) | ||
|
||
(define string-base64-decode | ||
(typed-lambda ((str string?)) | ||
(utf8->string (bytevector-base64-decode (string->utf8 str))))) | ||
|
||
(define (base64-decode x) | ||
(cond ((string? x) | ||
(string-base64-decode x)) | ||
((bytevector? x) | ||
(bytevector-base64-decode x)) | ||
(else | ||
(type-error "input must be string or bytevector")))) | ||
|
||
) ; end of begin | ||
) ; end of define-library | ||
|
This file contains 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
This file contains 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
This file contains 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
This file contains 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
This file contains 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
This file contains 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
This file contains 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
Oops, something went wrong.