; uri.ss ; ; Copyright (c) 2010 Higepon(Taro Minowa) ; ; ; Redistribution and use in source and binary forms, with or without ; modification, are permitted provided that the following conditions ; are met: ; ; 1. Redistributions of source code must retain the above copyright ; notice, this list of conditions and the following disclaimer. ; ; 2. Redistributions in binary form must reproduce the above copyright ; notice, this list of conditions and the following disclaimer in the ; documentation and/or other materials provided with the distribution. ; ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED ; TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR ; PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ; (library (uri) (export uri-encode uri-decode) (import (rnrs)) ;; This library is undocumented. APIs is subject to change without notice. ;; http://tips.lisp-users.org/scheme/ (define uri-unreserved-char-sv? (let ((unreserved-char-svs (map char->integer (string->list "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._‾")))) (lambda (sv) (and (memv sv unreserved-char-svs) #t)))) (define (uri-encode str) (let ((svs (bytevector->u8-list (string->utf8 str)))) (call-with-string-output-port (lambda (p) (for-each (lambda (sv) (cond ((uri-unreserved-char-sv? sv) (display (integer->char sv) (current-error-port)) (newline (current-error-port)) (display (integer->char sv) p)) (else (display "%" p) (when (< sv 16) (display "0" p)) (display (number->string sv 16) p)))) svs))))) (define (uri-decode str) (define digit->integer (lambda (c) (cond ((char<=? #\0 c #\9) (- (char->integer c) (char->integer #\0))) ((char<=? #\a c #\f) (+ 10 (- (char->integer c) (char->integer #\a)))) ((char<=? #\A c #\F) (+ 10 (- (char->integer c) (char->integer #\A)))) (else #f)))) (define percent-filter (lambda (in out err) (let loop ((c (peek-char in))) (and (not (eof-object? c)) (char=? c #\%) (let* ((cp (get-char in)) (c1 (get-char in)) (c2 (get-char in))) (cond ((eof-object? c1) (put-char err cp)) ((eof-object? c2) (put-char err cp) (put-char err c1)) (else (let ((i1 (digit->integer c1)) (i2 (digit->integer c2))) (cond ((and i1 i2) (put-u8 out (+ (* 16 (digit->integer c1)) (digit->integer c2))) (loop (peek-char in))) (else (put-char err cp) (put-char err c1) (put-char err c2))))))))))) (define filter (lambda (in out) (let loop ((c (peek-char in))) (when (not (eof-object? c)) (if (char=? c #\%) (put-string out (bytevector->string (call-with-bytevector-output-port (lambda (op) (percent-filter in op out))) (make-transcoder (utf-8-codec)))) (let ((c (get-char in))) (cond ((char=? c #\+) (put-char out #\space)) (else (put-char out c))))) (loop (peek-char in)))))) (call-with-port (open-string-input-port str) (lambda (in) (call-with-string-output-port (lambda (out) (filter in out)))))) )