;;; Ikarus Scheme -- A compiler for R6RS Scheme. ;;; Copyright (C) 2006,2007,2008 Abdulaziz Ghuloum ;;; ;;; This program is free software: you can redistribute it and/or modify ;;; it under the terms of the GNU General Public License version 3 as ;;; published by the Free Software Foundation. ;;; ;;; This program is distributed in the hope that it will be useful, but ;;; WITHOUT ANY WARRANTY; without even the implied warranty of ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;;; General Public License for more details. ;;; ;;; You should have received a copy of the GNU General Public License ;;; along with this program. If not, see . (library (ikarus bytevectors) (export make-bytevector bytevector-length bytevector-s8-ref bytevector-u8-ref bytevector-u8-set! bytevector-s8-set! bytevector-copy! u8-list->bytevector bytevector->u8-list bytevector-u16-native-ref bytevector-u16-native-set! bytevector-s16-native-ref bytevector-s16-native-set! bytevector-u32-native-ref bytevector-u32-native-set! bytevector-s32-native-ref bytevector-s32-native-set! bytevector-u64-native-ref bytevector-u64-native-set! bytevector-s64-native-ref bytevector-s64-native-set! bytevector-u16-ref bytevector-u16-set! bytevector-s16-ref bytevector-s16-set! bytevector-u32-ref bytevector-u32-set! bytevector-s32-ref bytevector-s32-set! bytevector-u64-ref bytevector-u64-set! bytevector-s64-ref bytevector-s64-set! bytevector-fill! bytevector-copy bytevector=? bytevector-uint-ref bytevector-sint-ref bytevector-uint-set! bytevector-sint-set! bytevector->uint-list bytevector->sint-list uint-list->bytevector sint-list->bytevector bytevector-ieee-double-native-ref bytevector-ieee-double-native-set! bytevector-ieee-single-native-ref bytevector-ieee-single-native-set! bytevector-ieee-double-ref bytevector-ieee-double-set! bytevector-ieee-single-ref bytevector-ieee-single-set! native-endianness) (import (except (ikarus) make-bytevector bytevector-length bytevector-s8-ref bytevector-u8-ref bytevector-u8-set! bytevector-s8-set! bytevector-copy! u8-list->bytevector bytevector->u8-list bytevector-u16-native-ref bytevector-u16-native-set! bytevector-s16-native-ref bytevector-s16-native-set! bytevector-u32-native-ref bytevector-u32-native-set! bytevector-s32-native-ref bytevector-s32-native-set! bytevector-u64-native-ref bytevector-u64-native-set! bytevector-s64-native-ref bytevector-s64-native-set! bytevector-u16-ref bytevector-u16-set! bytevector-s16-ref bytevector-s16-set! bytevector-u32-ref bytevector-u32-set! bytevector-s32-ref bytevector-s32-set! bytevector-u64-ref bytevector-u64-set! bytevector-s64-ref bytevector-s64-set! bytevector-fill! bytevector-copy bytevector=? bytevector-uint-ref bytevector-sint-ref bytevector-uint-set! bytevector-sint-set! bytevector->uint-list bytevector->sint-list uint-list->bytevector sint-list->bytevector bytevector-ieee-double-native-ref bytevector-ieee-double-native-set! bytevector-ieee-double-ref bytevector-ieee-double-set! bytevector-ieee-single-native-ref bytevector-ieee-single-native-set! bytevector-ieee-single-ref bytevector-ieee-single-set! native-endianness) (ikarus system $fx) (ikarus system $bignums) (ikarus system $pairs) (ikarus system $bytevectors)) (define (native-endianness) 'little) ;;; HARDCODED (define ($bytevector-fill x i j fill) (cond [($fx= i j) x] [else ($bytevector-set! x i fill) ($bytevector-fill x ($fxadd1 i) j fill)])) (define make-bytevector (case-lambda [(k) (if (and (fixnum? k) ($fx>= k 0)) ($make-bytevector k) (die 'make-bytevector "not a valid size" k))] [(k fill) (if (and (fixnum? fill) ($fx<= -128 fill) ($fx<= fill 255)) ($bytevector-fill (make-bytevector k) 0 k fill) (die 'make-bytevector "not a valid fill" fill))])) (define bytevector-fill! (lambda (x fill) (unless (bytevector? x) (die 'bytevector-fill! "not a bytevector" x)) (unless (and (fixnum? fill) ($fx<= -128 fill) ($fx<= fill 255)) (die 'bytevector-fill! "not a valid fill" fill)) ($bytevector-fill x 0 ($bytevector-length x) fill))) (define bytevector-length (lambda (x) (if (bytevector? x) ($bytevector-length x) (die 'bytevector-length "not a bytevector" x)))) (define bytevector-s8-ref (lambda (x i) (if (bytevector? x) (if (and (fixnum? i) ($fx<= 0 i) ($fx< i ($bytevector-length x))) ($bytevector-s8-ref x i) (die 'bytevector-s8-ref "invalid index" i x)) (die 'bytevector-s8-ref "not a bytevector" x)))) (define bytevector-u8-ref (lambda (x i) (if (bytevector? x) (if (and (fixnum? i) ($fx<= 0 i) ($fx< i ($bytevector-length x))) ($bytevector-u8-ref x i) (die 'bytevector-u8-ref "invalid index" i x)) (die 'bytevector-u8-ref "not a bytevector" x)))) (define bytevector-s8-set! (lambda (x i v) (if (bytevector? x) (if (and (fixnum? i) ($fx<= 0 i) ($fx< i ($bytevector-length x))) (if (and (fixnum? v) ($fx<= -128 v) ($fx<= v 127)) ($bytevector-set! x i v) (die 'bytevector-s8-set! "not a byte" v)) (die 'bytevector-s8-set! "invalid index" i x)) (die 'bytevector-s8-set! "not a bytevector" x)))) (define bytevector-u8-set! (lambda (x i v) (if (bytevector? x) (if (and (fixnum? i) ($fx<= 0 i) ($fx< i ($bytevector-length x))) (if (and (fixnum? v) ($fx<= 0 v) ($fx<= v 255)) ($bytevector-set! x i v) (die 'bytevector-u8-set! "not an octet" v)) (die 'bytevector-u8-set! "invalid index" i x)) (die 'bytevector-u8-set! "not a bytevector" x)))) (define bytevector-u16-native-ref ;;; HARDCODED (lambda (x i) (if (bytevector? x) (if (and (fixnum? i) ($fx<= 0 i) ($fx< i ($fxsub1 ($bytevector-length x))) ($fxzero? ($fxlogand i 1))) ($fxlogor ;;; little ($bytevector-u8-ref x i) ($fxsll ($bytevector-u8-ref x ($fxadd1 i)) 8)) (die 'bytevector-u16-native-ref "invalid index" i)) (die 'bytevector-u16-native-ref "not a bytevector" x)))) (define bytevector-u16-native-set! ;;; HARDCODED (lambda (x i n) (if (bytevector? x) (if (and (fixnum? n) ($fx<= 0 n) ($fx<= n #xFFFF)) (if (and (fixnum? i) ($fx<= 0 i) ($fx< i ($fxsub1 ($bytevector-length x))) ($fxzero? ($fxlogand i 1))) (begin ;;; little ($bytevector-set! x i n) ($bytevector-set! x ($fxadd1 i) ($fxsra n 8))) (die 'bytevector-u16-native-set! "invalid index" i)) (die 'bytevector-u16-native-set! "invalid value" n)) (die 'bytevector-u16-native-set! "not a bytevector" x)))) (define bytevector-s16-native-set! ;;; HARDCODED (lambda (x i n) (if (bytevector? x) (if (and (fixnum? n) ($fx<= #x-8000 n) ($fx<= n #x7FFF)) (if (and (fixnum? i) ($fx<= 0 i) ($fx< i ($fxsub1 ($bytevector-length x))) ($fxzero? ($fxlogand i 1))) (begin ;;; little ($bytevector-set! x i n) ($bytevector-set! x ($fxadd1 i) ($fxsra n 8))) (die 'bytevector-s16-native-set! "invalid index" i)) (die 'bytevector-s16-native-set! "invalid value" n)) (die 'bytevector-s16-native-set! "not a bytevector" x)))) (define bytevector-s16-native-ref ;;; HARDCODED (lambda (x i) (if (bytevector? x) (if (and (fixnum? i) ($fx<= 0 i) ($fx< i ($fxsub1 ($bytevector-length x))) ($fxzero? ($fxlogand i 1))) ($fxlogor ;;; little ($bytevector-u8-ref x i) ($fxsll ($bytevector-s8-ref x ($fxadd1 i)) 8)) (die 'bytevector-s16-native-ref "invalid index" i)) (die 'bytevector-s16-native-ref "not a bytevector" x)))) (define bytevector-u16-ref (lambda (x i end) (if (bytevector? x) (if (and (fixnum? i) ($fx<= 0 i) ($fx< i ($fxsub1 ($bytevector-length x)))) (case end [(big) ($fxlogor ($fxsll ($bytevector-u8-ref x i) 8) ($bytevector-u8-ref x ($fxadd1 i)))] [(little) ($fxlogor ($fxsll ($bytevector-u8-ref x (fxadd1 i)) 8) ($bytevector-u8-ref x i))] [else (die 'bytevector-u16-ref "invalid endianness" end)]) (die 'bytevector-u16-ref "invalid index" i)) (die 'bytevector-u16-ref "not a bytevector" x)))) (define bytevector-u32-ref (lambda (x i end) (if (bytevector? x) (if (and (fixnum? i) ($fx<= 0 i) ($fx< i ($fx- ($bytevector-length x) 3))) (case end [(big) (+ (sll ($bytevector-u8-ref x i) 24) ($fxlogor ($fxsll ($bytevector-u8-ref x ($fx+ i 1)) 16) ($fxlogor ($fxsll ($bytevector-u8-ref x ($fx+ i 2)) 8) ($bytevector-u8-ref x ($fx+ i 3)))))] [(little) (+ (sll ($bytevector-u8-ref x ($fx+ i 3)) 24) ($fxlogor ($fxsll ($bytevector-u8-ref x ($fx+ i 2)) 16) ($fxlogor ($fxsll ($bytevector-u8-ref x ($fx+ i 1)) 8) ($bytevector-u8-ref x i))))] [else (die 'bytevector-u32-ref "invalid endianness" end)]) (die 'bytevector-u32-ref "invalid index" i)) (die 'bytevector-u32-ref "not a bytevector" x)))) (define bytevector-u32-native-ref (lambda (x i) (if (bytevector? x) (if (and (fixnum? i) ($fx<= 0 i) ($fx= 0 ($fxlogand i 3)) ($fx< i ($fx- ($bytevector-length x) 3))) (+ (sll ($bytevector-u8-ref x ($fx+ i 3)) 24) ($fxlogor ($fxsll ($bytevector-u8-ref x ($fx+ i 2)) 16) ($fxlogor ($fxsll ($bytevector-u8-ref x ($fx+ i 1)) 8) ($bytevector-u8-ref x i)))) (die 'bytevector-u32-native-ref "invalid index" i)) (die 'bytevector-u32-native-ref "not a bytevector" x)))) (define bytevector-s32-ref (lambda (x i end) (if (bytevector? x) (if (and (fixnum? i) ($fx<= 0 i) ($fx< i ($fx- ($bytevector-length x) 3))) (case end [(big) (+ (sll ($bytevector-s8-ref x i) 24) ($fxlogor ($fxsll ($bytevector-u8-ref x ($fx+ i 1)) 16) ($fxlogor ($fxsll ($bytevector-u8-ref x ($fx+ i 2)) 8) ($bytevector-u8-ref x ($fx+ i 3)))))] [(little) (+ (sll ($bytevector-s8-ref x ($fx+ i 3)) 24) ($fxlogor ($fxsll ($bytevector-u8-ref x ($fx+ i 2)) 16) ($fxlogor ($fxsll ($bytevector-u8-ref x ($fx+ i 1)) 8) ($bytevector-u8-ref x i))))] [else (die 'bytevector-s32-ref "invalid endianness" end)]) (die 'bytevector-s32-ref "invalid index" i)) (die 'bytevector-s32-ref "not a bytevector" x)))) (define bytevector-s32-native-ref (lambda (x i) (if (bytevector? x) (if (and (fixnum? i) ($fx<= 0 i) ($fx= 0 ($fxlogand i 3)) ($fx< i ($fx- ($bytevector-length x) 3))) (+ (sll ($bytevector-s8-ref x ($fx+ i 3)) 24) ($fxlogor ($fxsll ($bytevector-u8-ref x ($fx+ i 2)) 16) ($fxlogor ($fxsll ($bytevector-u8-ref x ($fx+ i 1)) 8) ($bytevector-u8-ref x i)))) (die 'bytevector-s32-native-ref "invalid index" i)) (die 'bytevector-s32-native-ref "not a bytevector" x)))) (define bytevector-u16-set! (lambda (x i n end) (if (bytevector? x) (if (and (fixnum? n) ($fx<= 0 n) ($fx<= n #xFFFF)) (if (and (fixnum? i) ($fx<= 0 i) ($fx< i ($fxsub1 ($bytevector-length x)))) (case end [(big) ($bytevector-set! x i ($fxsra n 8)) ($bytevector-set! x ($fxadd1 i) n)] [(little) ($bytevector-set! x i n) ($bytevector-set! x ($fxadd1 i) (fxsra n 8))] [else (die 'bytevector-u16-ref "invalid endianness" end)]) (die 'bytevector-u16-set! "invalid index" i)) (die 'bytevector-u16-set! "invalid value" n)) (die 'bytevector-u16-set! "not a bytevector" x)))) (define bytevector-u32-set! (lambda (x i n end) (if (bytevector? x) (if (if (fixnum? n) ($fx>= n 0) (if (bignum? n) (<= 0 n #xFFFFFFFF) #f)) (if (and (fixnum? i) ($fx<= 0 i) ($fx< i ($fx- ($bytevector-length x) 3))) (case end [(big) (let ([b (sra n 16)]) ($bytevector-set! x i ($fxsra b 8)) ($bytevector-set! x ($fx+ i 1) b)) (let ([b (bitwise-and n #xFFFF)]) ($bytevector-set! x ($fx+ i 2) ($fxsra b 8)) ($bytevector-set! x ($fx+ i 3) b))] [(little) (let ([b (sra n 16)]) ($bytevector-set! x ($fx+ i 3) ($fxsra b 8)) ($bytevector-set! x ($fx+ i 2) b)) (let ([b (bitwise-and n #xFFFF)]) ($bytevector-set! x ($fx+ i 1) ($fxsra b 8)) ($bytevector-set! x i b))] [else (die 'bytevector-u32-ref "invalid endianness" end)]) (die 'bytevector-u32-set! "invalid index" i)) (die 'bytevector-u32-set! "invalid value" n)) (die 'bytevector-u32-set! "not a bytevector" x)))) (define bytevector-u32-native-set! (lambda (x i n) (if (bytevector? x) (if (if (fixnum? n) ($fx>= n 0) (if (bignum? n) (<= 0 n #xFFFFFFFF) #f)) (if (and (fixnum? i) ($fx<= 0 i) ($fx= 0 ($fxlogand i 3)) ($fx< i ($fx- ($bytevector-length x) 3))) (begin (let ([b (sra n 16)]) ($bytevector-set! x ($fx+ i 3) ($fxsra b 8)) ($bytevector-set! x ($fx+ i 2) b)) (let ([b (bitwise-and n #xFFFF)]) ($bytevector-set! x ($fx+ i 1) ($fxsra b 8)) ($bytevector-set! x i b))) (die 'bytevector-u32-native-set! "invalid index" i)) (die 'bytevector-u32-native-set! "invalid value" n)) (die 'bytevector-u32-native-set! "not a bytevector" x)))) (define bytevector-s32-native-set! (lambda (x i n) (if (bytevector? x) (if (if (fixnum? n) #t (if (bignum? n) (<= #x-80000000 n #x7FFFFFFF) #f)) (if (and (fixnum? i) ($fx<= 0 i) ($fx= 0 ($fxlogand i 3)) ($fx< i ($fx- ($bytevector-length x) 3))) (begin (let ([b (sra n 16)]) ($bytevector-set! x ($fx+ i 3) ($fxsra b 8)) ($bytevector-set! x ($fx+ i 2) b)) (let ([b (bitwise-and n #xFFFF)]) ($bytevector-set! x ($fx+ i 1) ($fxsra b 8)) ($bytevector-set! x i b))) (die 'bytevector-s32-native-set! "invalid index" i)) (die 'bytevector-s32-native-set! "invalid value" n)) (die 'bytevector-s32-native-set! "not a bytevector" x)))) (define bytevector-s32-set! (lambda (x i n end) (if (bytevector? x) (if (if (fixnum? n) #t (if (bignum? n) (<= #x-80000000 n #x7FFFFFFF) #f)) (if (and (fixnum? i) ($fx<= 0 i) ($fx< i ($fx- ($bytevector-length x) 3))) (case end [(big) (let ([b (sra n 16)]) ($bytevector-set! x i ($fxsra b 8)) ($bytevector-set! x ($fx+ i 1) b)) (let ([b (bitwise-and n #xFFFF)]) ($bytevector-set! x ($fx+ i 2) ($fxsra b 8)) ($bytevector-set! x ($fx+ i 3) b))] [(little) (let ([b (sra n 16)]) ($bytevector-set! x ($fx+ i 3) ($fxsra b 8)) ($bytevector-set! x ($fx+ i 2) b)) (let ([b (bitwise-and n #xFFFF)]) ($bytevector-set! x ($fx+ i 1) ($fxsra b 8)) ($bytevector-set! x i b))] [else (die 'bytevector-s32-ref "invalid endianness" end)]) (die 'bytevector-s32-set! "invalid index" i)) (die 'bytevector-s32-set! "invalid value" n)) (die 'bytevector-s32-set! "not a bytevector" x)))) (define bytevector-s16-ref (lambda (x i end) (if (bytevector? x) (if (and (fixnum? i) ($fx<= 0 i) ($fx< i ($fxsub1 ($bytevector-length x)))) (case end [(big) ($fxlogor ($fxsll ($bytevector-s8-ref x i) 8) ($bytevector-u8-ref x ($fxadd1 i)))] [(little) ($fxlogor ($fxsll ($bytevector-s8-ref x (fxadd1 i)) 8) ($bytevector-u8-ref x i))] [else (die 'bytevector-s16-ref "invalid endianness" end)]) (die 'bytevector-s16-ref "invalid index" i)) (die 'bytevector-s16-ref "not a bytevector" x)))) (define bytevector-s16-set! (lambda (x i n end) (if (bytevector? x) (if (and (fixnum? n) ($fx<= #x-8000 n) ($fx<= n #x7FFF)) (if (and (fixnum? i) ($fx<= 0 i) ($fx< i ($fxsub1 ($bytevector-length x)))) (case end [(big) ($bytevector-set! x i ($fxsra n 8)) ($bytevector-set! x ($fxadd1 i) n)] [(little) ($bytevector-set! x i n) ($bytevector-set! x ($fxadd1 i) (fxsra n 8))] [else (die 'bytevector-s16-ref "invalid endianness" end)]) (die 'bytevector-s16-set! "invalid index" i)) (die 'bytevector-s16-set! "invalid value" n)) (die 'bytevector-s16-set! "not a bytevector" x)))) (define bytevector->u8-list (lambda (x) (unless (bytevector? x) (die 'bytevector->u8-list "not a bytevector" x)) (let f ([x x] [i ($bytevector-length x)] [ac '()]) (cond [($fx= i 0) ac] [else (let ([i ($fxsub1 i)]) (f x i (cons ($bytevector-u8-ref x i) ac)))])))) (define u8-list->bytevector (letrec ([race (lambda (h t ls n) (if (pair? h) (let ([h ($cdr h)]) (if (pair? h) (if (not (eq? h t)) (race ($cdr h) ($cdr t) ls ($fx+ n 2)) (die 'u8-list->bytevector "circular list" ls)) (if (null? h) ($fx+ n 1) (die 'u8-list->bytevector "not a proper list" ls)))) (if (null? h) n (die 'u8-list->bytevector "not a proper list" ls))))] [fill (lambda (s i ls) (cond [(null? ls) s] [else (let ([c ($car ls)]) (unless (and (fixnum? c) ($fx<= 0 c) ($fx<= c 255)) (die 'u8-list->bytevector "not an octet" c)) ($bytevector-set! s i c) (fill s ($fxadd1 i) (cdr ls)))]))]) (lambda (ls) (let ([n (race ls ls ls 0)]) (let ([s ($make-bytevector n)]) (fill s 0 ls)))))) (define bytevector-copy (lambda (src) (unless (bytevector? src) (die 'bytevector-copy "not a bytevector" src)) (let ([n ($bytevector-length src)]) (let f ([src src] [dst ($make-bytevector n)] [i 0] [n n]) (cond [($fx= i n) dst] [else ($bytevector-set! dst i ($bytevector-u8-ref src i)) (f src dst ($fxadd1 i) n)]))))) (define bytevector=? (lambda (x y) (unless (bytevector? x) (die 'bytevector=? "not a bytevector" x)) (unless (bytevector? y) (die 'bytevector=? "not a bytevector" y)) (let ([n ($bytevector-length x)]) (and ($fx= n ($bytevector-length y)) (let f ([x x] [y y] [i 0] [n n]) (or ($fx= i n) (and ($fx= ($bytevector-u8-ref x i) ($bytevector-u8-ref y i)) (f x y ($fxadd1 i) n)))))))) (define bytevector-copy! (lambda (src src-start dst dst-start k) (cond [(or (not (fixnum? src-start)) ($fx< src-start 0)) (die 'bytevector-copy! "not a valid starting index" src-start)] [(or (not (fixnum? dst-start)) ($fx< dst-start 0)) (die 'bytevector-copy! "not a valid starting index" dst-start)] [(or (not (fixnum? k)) ($fx< k 0)) (die 'bytevector-copy! "not a valid length" k)] [(not (bytevector? src)) (die 'bytevector-copy! "not a bytevector" src)] [(not (bytevector? dst)) (die 'bytevector-copy! "not a bytevector" dst)] [(let ([n ($fx+ src-start k)]) (or ($fx< n 0) ($fx> n ($bytevector-length src)))) (die 'bytevector-copy! "out of range" src-start k)] [(let ([n ($fx+ dst-start k)]) (or ($fx< n 0) ($fx> n ($bytevector-length dst)))) (die 'bytevector-copy! "out of range" dst-start k)] [(eq? src dst) (cond [($fx< dst-start src-start) (let f ([src src] [si src-start] [di dst-start] [sj ($fx+ src-start k)]) (unless ($fx= si sj) ($bytevector-set! src di ($bytevector-u8-ref src si)) (f src ($fxadd1 si) ($fxadd1 di) sj)))] [($fx< src-start dst-start) (let f ([src src] [si ($fx+ src-start k)] [di ($fx+ dst-start k)] [sj src-start]) (unless ($fx= si sj) (let ([si ($fxsub1 si)] [di ($fxsub1 di)]) ($bytevector-set! src di ($bytevector-u8-ref src si)) (f src si di sj))))] [else (void)])] [else (let f ([src src] [si src-start] [dst dst] [di dst-start] [sj ($fx+ src-start k)]) (unless ($fx= si sj) ($bytevector-set! dst di ($bytevector-u8-ref src si)) (f src ($fxadd1 si) dst ($fxadd1 di) sj)))]))) (module (bytevector-uint-ref bytevector-sint-ref bytevector->uint-list bytevector->sint-list) (define (uref-big x ib il) ;; ib included, il excluded (cond [($fx= il ib) 0] [else (let ([b ($bytevector-u8-ref x ib)]) (cond [($fx= b 0) (uref-big x ($fxadd1 ib) il)] [else (case ($fx- il ib) [(1) b] [(2) ($fx+ ($fxsll b 8) ($bytevector-u8-ref x ($fxsub1 il)))] [(3) ($fx+ ($fxsll ($fx+ ($fxsll b 8) ($bytevector-u8-ref x ($fxadd1 ib))) 8) ($bytevector-u8-ref x ($fxsub1 il)))] [else (let ([im ($fxsra ($fx+ il ib) 1)]) (+ (uref-big x im il) (* (uref-big x ib im) (expt 256 ($fx- il im)))))])]))])) (define (uref-little x il ib) ;; il included, ib excluded (cond [($fx= il ib) 0] [else (let ([ib^ ($fxsub1 ib)]) (let ([b ($bytevector-u8-ref x ib^)]) (cond [($fx= b 0) (uref-little x il ib^)] [else (case ($fx- ib il) [(1) b] [(2) ($fx+ ($fxsll b 8) ($bytevector-u8-ref x il))] [(3) ($fx+ ($fxsll ($fx+ ($fxsll b 8) ($bytevector-u8-ref x ($fxadd1 il))) 8) ($bytevector-u8-ref x il))] [else (let ([im ($fxsra ($fx+ il ib) 1)]) (+ (uref-little x il im) (* (uref-little x im ib) (expt 256 ($fx- im il)))))])])))])) (define (sref-big x ib il) ;; ib included, il excluded (cond [($fx= il ib) -1] [else (let ([b ($bytevector-u8-ref x ib)]) (cond [($fx= b 0) (uref-big x ($fxadd1 ib) il)] [($fx= b 255) (sref-big-neg x ($fxadd1 ib) il)] [($fx< b 128) (uref-big x ib il)] [else (- (uref-big x ib il) (expt 256 ($fx- il ib)))]))])) (define (sref-big-neg x ib il) ;; ib included, il excluded (cond [($fx= il ib) -1] [else (let ([b ($bytevector-u8-ref x ib)]) (cond [($fx= b 255) (sref-big-neg x ($fxadd1 ib) il)] [else (- (uref-big x ib il) (expt 256 ($fx- il ib)))]))])) (define (sref-little x il ib) ;; il included, ib excluded (cond [($fx= il ib) -1] [else (let ([ib^ ($fxsub1 ib)]) (let ([b ($bytevector-u8-ref x ib^)]) (cond [($fx= b 0) (uref-little x il ib^)] [($fx= b 255) (sref-little-neg x il ib^)] [($fx< b 128) (uref-little x il ib)] [else (- (uref-little x il ib) (expt 256 ($fx- ib il)))])))])) (define (sref-little-neg x il ib) ;; il included, ib excluded (cond [($fx= il ib) -1] [else (let ([ib^ ($fxsub1 ib)]) (let ([b ($bytevector-u8-ref x ib^)]) (cond [($fx= b 255) (sref-little-neg x il ib^)] [else (- (uref-little x il ib) (expt 256 ($fx- ib il)))])))])) (define bytevector-sint-ref (lambda (x k endianness size) (define who 'bytevector-sint-ref) (unless (bytevector? x) (die who "not a bytevector" x)) (unless (and (fixnum? k) ($fx>= k 0)) (die who "invalid index" k)) (unless (and (fixnum? size) ($fx>= size 1)) (die who "invalid size" size)) (let ([n ($bytevector-length x)]) (unless ($fx< k n) (die who "index is out of range" k)) (let ([end ($fx+ k size)]) (unless (and ($fx>= end 0) ($fx<= end n)) (die who "out of range" k size)) (case endianness [(little) (sref-little x k end)] [(big) (sref-big x k end)] [else (die who "invalid endianness" endianness)]))))) (define bytevector-uint-ref (lambda (x k endianness size) (define who 'bytevector-uint-ref) (unless (bytevector? x) (die who "not a bytevector" x)) (unless (and (fixnum? k) ($fx>= k 0)) (die who "invalid index" k)) (unless (and (fixnum? size) ($fx>= size 1)) (die who "invalid size" size)) (let ([n ($bytevector-length x)]) (unless ($fx< k n) (die who "index is out of range" k)) (let ([end ($fx+ k size)]) (unless (and ($fx>= end 0) ($fx<= end n)) (die who "out of range" k size)) (case endianness [(little) (uref-little x k end)] [(big) (uref-big x k end)] [else (die who "invalid endianness" endianness)]))))) (define (bytevector->some-list x k n ls proc who) (cond [($fx= n 0) ls] [else (let ([i ($fx- n k)]) (cond [($fx>= i 0) (bytevector->some-list x k i (cons (proc x i n) ls) proc who)] [else (die who "invalid size" k)]))])) (define bytevector->uint-list (lambda (x endianness size) (define who 'bytevector->uint-list) (unless (bytevector? x) (die who "not a bytevector" x)) (unless (and (fixnum? size) ($fx>= size 1)) (die who "invalid size" size)) (case endianness [(little) (bytevector->some-list x size ($bytevector-length x) '() uref-little 'bytevector->uint-list)] [(big) (bytevector->some-list x size ($bytevector-length x) '() uref-big 'bytevector->uint-list)] [else (die who "invalid endianness" endianness)]))) (define bytevector->sint-list (lambda (x endianness size) (define who 'bytevector->sint-list) (unless (bytevector? x) (die who "not a bytevector" x)) (unless (and (fixnum? size) ($fx>= size 1)) (die who "invalid size" size)) (case endianness [(little) (bytevector->some-list x size ($bytevector-length x) '() sref-little 'bytevector->sint-list)] [(big) (bytevector->some-list x size ($bytevector-length x) '() sref-big 'bytevector->sint-list)] [else (die who "invalid endianness" endianness)])))) (define (bytevector-uint-set! bv i0 n endianness size) (define who 'bytevector-uint-set!) (bytevector-uint-set!/who bv i0 n endianness size who)) (define (bytevector-uint-set!/who bv i0 n endianness size who) (unless (bytevector? bv) (die who "not a bytevector" bv)) (unless (or (fixnum? n) (bignum? n)) (die who "not an exact number" n)) (unless (>= n 0) (die who "number must be positive" n)) (let ([bvsize ($bytevector-length bv)]) (unless (and (fixnum? i0) ($fx>= i0 0) ($fx< i0 bvsize)) (die who "invalid index" i0)) (unless (and (fixnum? size) ($fx> size 0) ($fx<= i0 ($fx- bvsize size))) (die who "invalid size" size))) (let ([nsize (bitwise-length n)]) (when (< (* size 8) nsize) (die who (format "number does not fit in ~a byte~a" size (if (= size 1) "" "s")) n))) (case endianness [(little) (let f ([bv bv] [i0 i0] [i1 (fx+ i0 size)] [n n]) (unless ($fx= i0 i1) ($bytevector-set! bv i0 (bitwise-and n 255)) (f bv ($fx+ i0 1) i1 (sra n 8))))] [(big) (let f ([bv bv] [i0 i0] [i1 (fx+ i0 size)] [n n]) (unless ($fx= i0 i1) (let ([i1 ($fx- i1 1)]) ($bytevector-set! bv i1 (bitwise-and n 255)) (f bv i0 i1 (sra n 8)))))] [else (die who "invalid endianness" endianness)])) (define (bytevector-sint-set! bv i0 n endianness size) (define who 'bytevector-sint-set!) (bytevector-sint-set!/who bv i0 n endianness size who)) (define (bytevector-sint-set!/who bv i0 n endianness size who) (unless (bytevector? bv) (die who "not a bytevector" bv)) (unless (or (fixnum? n) (bignum? n)) (die who "not an exact number" n)) (let ([bvsize ($bytevector-length bv)]) (unless (and (fixnum? i0) ($fx>= i0 0) ($fx< i0 bvsize)) (die who "invalid index" i0)) (unless (and (fixnum? size) ($fx> size 0) ($fx<= i0 ($fx- bvsize size))) (die who "invalid size" size))) (let ([nsize (+ (bitwise-length n) 1)]) (when (< (* size 8) nsize) (die who "number does not fit" n))) (case endianness [(little) (let f ([bv bv] [i0 i0] [i1 (fx+ i0 size)] [n n]) (unless ($fx= i0 i1) ($bytevector-set! bv i0 (bitwise-and n 255)) (f bv ($fx+ i0 1) i1 (sra n 8))))] [(big) (let f ([bv bv] [i0 i0] [i1 (fx+ i0 size)] [n n]) (unless ($fx= i0 i1) (let ([i1 ($fx- i1 1)]) ($bytevector-set! bv i1 (bitwise-and n 255)) (f bv i0 i1 (sra n 8)))))] [else (die who "invalid endianness" endianness)])) (module (uint-list->bytevector sint-list->bytevector) (define (make-xint-list->bytevector who bv-set!) (define (race h t ls idx endianness size) (if (pair? h) (let ([h ($cdr h)] [a ($car h)]) (if (pair? h) (if (not (eq? h t)) (let ([bv (race ($cdr h) ($cdr t) ls ($fx+ idx ($fx+ size size)) endianness size)]) (bv-set! bv idx a endianness size who) (bv-set! bv ($fx+ idx size) ($car h) endianness size who) bv) (die who "circular list" ls)) (if (null? h) (let ([bv (make-bytevector ($fx+ idx size))]) (bv-set! bv idx a endianness size who) bv) (die who "not a proper list" ls)))) (if (null? h) (make-bytevector idx) (die who "not a proper list" ls)))) (lambda (ls endianness size) (if (and (fixnum? size) (fx> size 0)) (race ls ls ls 0 endianness size) (die who "size must be a positive integer" size)))) (define uint-list->bytevector (make-xint-list->bytevector 'uint-list->bytevector bytevector-uint-set!/who)) (define sint-list->bytevector (make-xint-list->bytevector 'sint-list->bytevector bytevector-sint-set!/who))) (define (bytevector-ieee-double-native-ref bv i) (if (bytevector? bv) (if (and (fixnum? i) ($fx>= i 0) ($fxzero? ($fxlogand i 7)) ($fx< i ($bytevector-length bv))) ($bytevector-ieee-double-native-ref bv i) (die 'bytevector-ieee-double-native-ref "invalid index" i)) (die 'bytevector-ieee-double-native-ref "not a bytevector" bv))) (define (bytevector-ieee-single-native-ref bv i) (if (bytevector? bv) (if (and (fixnum? i) ($fx>= i 0) ($fxzero? ($fxlogand i 3)) ($fx< i ($bytevector-length bv))) ($bytevector-ieee-single-native-ref bv i) (die 'bytevector-ieee-single-native-ref "invalid index" i)) (die 'bytevector-ieee-single-native-ref "not a bytevector" bv))) (define (bytevector-ieee-double-native-set! bv i x) (if (bytevector? bv) (if (and (fixnum? i) ($fx>= i 0) ($fxzero? ($fxlogand i 7)) ($fx< i ($bytevector-length bv))) (if (flonum? x) ($bytevector-ieee-double-native-set! bv i x) (die 'bytevector-ieee-double-native-set! "not a flonum" x)) (die 'bytevector-ieee-double-native-set! "invalid index" i)) (die 'bytevector-ieee-double-native-set! "not a bytevector" bv))) (define (bytevector-ieee-single-native-set! bv i x) (if (bytevector? bv) (if (and (fixnum? i) ($fx>= i 0) ($fxzero? ($fxlogand i 3)) ($fx< i ($bytevector-length bv))) (if (flonum? x) ($bytevector-ieee-single-native-set! bv i x) (die 'bytevector-ieee-single-native-set! "not a flonum" x)) (die 'bytevector-ieee-single-native-set! "invalid index" i)) (die 'bytevector-ieee-single-native-set! "not a bytevector" bv))) (define ($bytevector-ieee-double-ref/big x i) (import (ikarus system $flonums)) (let ([y ($make-flonum)]) ($flonum-set! y 0 ($bytevector-u8-ref x i)) ($flonum-set! y 1 ($bytevector-u8-ref x ($fx+ i 1))) ($flonum-set! y 2 ($bytevector-u8-ref x ($fx+ i 2))) ($flonum-set! y 3 ($bytevector-u8-ref x ($fx+ i 3))) ($flonum-set! y 4 ($bytevector-u8-ref x ($fx+ i 4))) ($flonum-set! y 5 ($bytevector-u8-ref x ($fx+ i 5))) ($flonum-set! y 6 ($bytevector-u8-ref x ($fx+ i 6))) ($flonum-set! y 7 ($bytevector-u8-ref x ($fx+ i 7))) y)) (define ($bytevector-ieee-double-set!/big x i y) (import (ikarus system $flonums)) ($bytevector-set! x i ($flonum-u8-ref y 0)) ($bytevector-set! x ($fx+ i 1) ($flonum-u8-ref y 1)) ($bytevector-set! x ($fx+ i 2) ($flonum-u8-ref y 2)) ($bytevector-set! x ($fx+ i 3) ($flonum-u8-ref y 3)) ($bytevector-set! x ($fx+ i 4) ($flonum-u8-ref y 4)) ($bytevector-set! x ($fx+ i 5) ($flonum-u8-ref y 5)) ($bytevector-set! x ($fx+ i 6) ($flonum-u8-ref y 6)) ($bytevector-set! x ($fx+ i 7) ($flonum-u8-ref y 7))) (define ($bytevector-ieee-double-ref/little x i) (import (ikarus system $flonums)) (let ([y ($make-flonum)]) ($flonum-set! y 7 ($bytevector-u8-ref x i)) ($flonum-set! y 6 ($bytevector-u8-ref x ($fx+ i 1))) ($flonum-set! y 5 ($bytevector-u8-ref x ($fx+ i 2))) ($flonum-set! y 4 ($bytevector-u8-ref x ($fx+ i 3))) ($flonum-set! y 3 ($bytevector-u8-ref x ($fx+ i 4))) ($flonum-set! y 2 ($bytevector-u8-ref x ($fx+ i 5))) ($flonum-set! y 1 ($bytevector-u8-ref x ($fx+ i 6))) ($flonum-set! y 0 ($bytevector-u8-ref x ($fx+ i 7))) y)) (define ($bytevector-ieee-double-set!/little x i y) (import (ikarus system $flonums)) ($bytevector-set! x i ($flonum-u8-ref y 7)) ($bytevector-set! x ($fx+ i 1) ($flonum-u8-ref y 6)) ($bytevector-set! x ($fx+ i 2) ($flonum-u8-ref y 5)) ($bytevector-set! x ($fx+ i 3) ($flonum-u8-ref y 4)) ($bytevector-set! x ($fx+ i 4) ($flonum-u8-ref y 3)) ($bytevector-set! x ($fx+ i 5) ($flonum-u8-ref y 2)) ($bytevector-set! x ($fx+ i 6) ($flonum-u8-ref y 1)) ($bytevector-set! x ($fx+ i 7) ($flonum-u8-ref y 0))) (define ($bytevector-ieee-single-ref/little x i) (let ([bv (make-bytevector 4)]) ($bytevector-set! bv 0 ($bytevector-u8-ref x i)) ($bytevector-set! bv 1 ($bytevector-u8-ref x ($fx+ i 1))) ($bytevector-set! bv 2 ($bytevector-u8-ref x ($fx+ i 2))) ($bytevector-set! bv 3 ($bytevector-u8-ref x ($fx+ i 3))) ($bytevector-ieee-single-native-ref bv 0))) (define ($bytevector-ieee-single-ref/big x i) (let ([bv (make-bytevector 4)]) ($bytevector-set! bv 3 ($bytevector-u8-ref x i)) ($bytevector-set! bv 2 ($bytevector-u8-ref x ($fx+ i 1))) ($bytevector-set! bv 1 ($bytevector-u8-ref x ($fx+ i 2))) ($bytevector-set! bv 0 ($bytevector-u8-ref x ($fx+ i 3))) ($bytevector-ieee-single-native-ref bv 0))) (define ($bytevector-ieee-single-set!/little x i v) (let ([bv (make-bytevector 4)]) ($bytevector-ieee-single-native-set! bv 0 v) ($bytevector-set! x i ($bytevector-u8-ref bv 0)) ($bytevector-set! x ($fx+ i 1) ($bytevector-u8-ref bv 1)) ($bytevector-set! x ($fx+ i 2) ($bytevector-u8-ref bv 2)) ($bytevector-set! x ($fx+ i 3) ($bytevector-u8-ref bv 3)))) (define ($bytevector-ieee-single-set!/big x i v) (let ([bv (make-bytevector 4)]) ($bytevector-ieee-single-native-set! bv 0 v) ($bytevector-set! x i ($bytevector-u8-ref bv 3)) ($bytevector-set! x ($fx+ i 1) ($bytevector-u8-ref bv 2)) ($bytevector-set! x ($fx+ i 2) ($bytevector-u8-ref bv 1)) ($bytevector-set! x ($fx+ i 3) ($bytevector-u8-ref bv 0)))) (define (bytevector-ieee-double-ref bv i endianness) (define who 'bytevector-ieee-double-ref) (if (bytevector? bv) (if (and (fixnum? i) ($fx>= i 0)) (let ([len ($bytevector-length bv)]) (if (and ($fxzero? ($fxlogand i 7)) ($fx< i len)) (case endianness [(little) ($bytevector-ieee-double-native-ref bv i)] [(big) ($bytevector-ieee-double-nonnative-ref bv i)] [else (die who "invalid endianness" endianness)]) (if ($fx<= i ($fx- len 8)) (case endianness [(little) ($bytevector-ieee-double-ref/little bv i)] [(big) ($bytevector-ieee-double-ref/big bv i)] [else (die who "invalid endianness" endianness)]) (die who "invalid index" i)))) (die who "invalid index" i)) (die who "not a bytevector" bv))) (define (bytevector-ieee-single-ref bv i endianness) (define who 'bytevector-ieee-single-ref) (if (bytevector? bv) (if (and (fixnum? i) ($fx>= i 0)) (let ([len ($bytevector-length bv)]) (if (and ($fxzero? ($fxlogand i 3)) ($fx< i len)) (case endianness [(little) ($bytevector-ieee-single-native-ref bv i)] [(big) ($bytevector-ieee-single-nonnative-ref bv i)] [else (die who "invalid endianness" endianness)]) (if ($fx<= i ($fx- len 4)) (case endianness [(little) ($bytevector-ieee-single-ref/little bv i)] [(big) ($bytevector-ieee-single-ref/big bv i)] [else (die who "invalid endianness" endianness)]) (die who "invalid index" i)))) (die who "invalid index" i)) (die who "not a bytevector" bv))) (define (bytevector-ieee-double-set! bv i x endianness) (define who 'bytevector-ieee-double-set!) (if (bytevector? bv) (if (flonum? x) (if (and (fixnum? i) ($fx>= i 0)) (let ([len ($bytevector-length bv)]) (if (and ($fxzero? ($fxlogand i 7)) ($fx< i len)) (case endianness [(little) ($bytevector-ieee-double-native-set! bv i x)] [(big) ($bytevector-ieee-double-nonnative-set! bv i x)] [else (die who "invalid endianness" endianness)]) (if ($fx<= i ($fx- len 8)) (case endianness [(little) ($bytevector-ieee-double-set!/little bv i x)] [(big) ($bytevector-ieee-double-set!/big bv i x)] [else (die who "invalid endianness" endianness)]) (die who "invalid index" i)))) (die who "invalid index" i)) (die who "not a flonum" x)) (die who "not a bytevector" bv))) (define (bytevector-ieee-single-set! bv i x endianness) (define who 'bytevector-ieee-single-set!) (if (bytevector? bv) (if (flonum? x) (if (and (fixnum? i) ($fx>= i 0)) (let ([len ($bytevector-length bv)]) (if (and ($fxzero? ($fxlogand i 3)) ($fx< i len)) (case endianness [(little) ($bytevector-ieee-single-native-set! bv i x)] [(big) ($bytevector-ieee-single-nonnative-set! bv i x)] [else (die who "invalid endianness" endianness)]) (if ($fx<= i ($fx- len 4)) (case endianness [(little) ($bytevector-ieee-single-set!/little bv i x)] [(big) ($bytevector-ieee-single-set!/big bv i x)] [else (die who "invalid endianness" endianness)]) (die who "invalid index" i)))) (die who "invalid index" i)) (die who "not a flonum" x)) (die who "not a bytevector" bv))) (define ($bytevector-ref/64/aligned bv i who decoder endianness) (if (bytevector? bv) (if (and (fixnum? i) ($fx>= i 0) ($fxzero? ($fxlogand i 7)) ($fx< i ($bytevector-length bv))) (case endianness [(little big) (decoder bv i endianness 8)] [else (die who "invalid endianness" endianness)]) (die who "invalid index" i)) (die who "not a bytevector" bv))) (define ($bytevector-ref/64 bv i who decoder endianness) (if (bytevector? bv) (if (and (fixnum? i) ($fx>= i 0) ($fx< i ($fx- ($bytevector-length bv) 7))) (case endianness [(little big) (decoder bv i endianness 8)] [else (die who "invalid endianness" endianness)]) (die who "invalid index" i)) (die who "not a bytevector" bv))) (define (bytevector-u64-native-ref bv i) ($bytevector-ref/64/aligned bv i 'bytevector-u64-native-ref bytevector-uint-ref 'little)) (define (bytevector-s64-native-ref bv i) ($bytevector-ref/64/aligned bv i 'bytevector-s64-native-ref bytevector-sint-ref 'little)) (define (bytevector-u64-ref bv i endianness) ($bytevector-ref/64 bv i 'bytevector-u64-ref bytevector-uint-ref endianness)) (define (bytevector-s64-ref bv i endianness) ($bytevector-ref/64 bv i 'bytevector-s64-ref bytevector-sint-ref endianness)) (define ($bytevector-set/64/align bv i n lo hi who setter endianness) (if (bytevector? bv) (if (and (fixnum? i) ($fx>= i 0) ($fxzero? ($fxlogand i 7)) ($fx< i ($bytevector-length bv))) (case endianness [(little big) (unless (or (fixnum? n) (bignum? n)) (die who "number is not an exact number" n)) (unless (and (<= lo n) (< n hi)) (die who "number out of range" n)) (setter bv i n endianness 8)] [else (die who "invalid endianness" endianness)]) (die who "invalid index" i)) (die who "not a bytevector" bv))) (define ($bytevector-set/64 bv i n lo hi who setter endianness) (if (bytevector? bv) (if (and (fixnum? i) ($fx>= i 0) ($fx< i ($fx- ($bytevector-length bv) 7))) (case endianness [(little big) (unless (or (fixnum? n) (bignum? n)) (die who "number is not exact number" n)) (unless (and (<= lo n) (< n hi)) (die who "number out of range" n)) (setter bv i n endianness 8)] [else (die who "invalid endianness" endianness)]) (die who "invalid index" i)) (die who "not a bytevector" bv))) (define (bytevector-u64-native-set! bv i n) ($bytevector-set/64/align bv i n 0 (expt 2 64) 'bytevector-u64-native-set! bytevector-uint-set! 'little)) (define (bytevector-s64-native-set! bv i n) ($bytevector-set/64/align bv i n (- (expt 2 63)) (expt 2 63) 'bytevector-s64-native-set! bytevector-sint-set! 'little)) (define (bytevector-u64-set! bv i n endianness) ($bytevector-set/64 bv i n 0 (expt 2 64) 'bytevector-u64-set! bytevector-uint-set! endianness)) (define (bytevector-s64-set! bv i n endianness) ($bytevector-set/64 bv i n (- (expt 2 63)) (expt 2 63) 'bytevector-s64-set! bytevector-sint-set! endianness)) ) (library (ikarus system bytevectors) (export $bytevector-u8-ref $bytevector-length $make-bytevector) (import (ikarus)) (define $bytevector-u8-ref bytevector-u8-ref) (define $bytevector-length bytevector-length) (define $make-bytevector make-bytevector))