aboutsummaryrefslogtreecommitdiff
path: root/gz.scm
diff options
context:
space:
mode:
Diffstat (limited to 'gz.scm')
-rw-r--r--gz.scm155
1 files changed, 155 insertions, 0 deletions
diff --git a/gz.scm b/gz.scm
new file mode 100644
index 0000000..789c25d
--- /dev/null
+++ b/gz.scm
@@ -0,0 +1,155 @@
+(import (scheme base)
+ (chibi bytevector)
+ ;; (srfi 1)
+ (srfi 33))
+
+(define FTEXT 0)
+(define FHCRC 1)
+(define FEXTRA 2)
+(define FNAME 3)
+(define FCOMMENT 4)
+
+(define (bit-description bit)
+ (cond ((= bit FTEXT) "File is probably text")
+ ((= bit FHCRC) "CRC16 Checksum is present")
+ ((= bit FEXTRA) "Extra Field is present")
+ ((= bit FNAME) "Filename is present")
+ ((= bit FCOMMENT) "A Comment is present")
+ (else "Unknown Bit")))
+
+(define (filter proc lst)
+ (cond ((null? lst) '())
+ ((proc (car lst)) (cons (car lst)
+ (filter proc (cdr lst))))
+ (else (filter proc (cdr lst)))))
+
+(define (parse-flags int)
+ (filter string?
+ (map (lambda (bit)
+ (if (bit-set? bit int)
+ (string-append (bit-description bit) "\n")
+ #f))
+ (list FTEXT FHCRC FEXTRA FNAME FCOMMENT))))
+
+(define (os-name i)
+ (case i
+ ((0) "Fat filesystem (MS-DOS, OS/2, NT/Win32)")
+ ((1) "Amiga")
+ ((2) "VMS (or OpenVMS)")
+ ((3) "Unix")
+ ((4) "VM/CMS")
+ ((5) "Atari TOS")
+ ((6) "HPFS fileesystem (OS/2, NT)")
+ ((7) "Macintosh")
+ ((8) "Z-System")
+ ((9) "CP/M")
+ ((10) "TOPS-20")
+ ((11) "NTFS filesystem (NT)")
+ ((12) "QDOS")
+ ((13) "Acorn RISCOS")
+ (else "unknown")))
+
+(define (bytevector-search bv el idx)
+ (cond ((>= idx (bytevector-length bv)) #f)
+ ((equal? el (bytevector-u8-ref bv idx)) idx)
+ (else (bytevector-search bv el (+ idx 1)))))
+
+(define make-segment vector)
+
+(define (get-segment bv addr)
+ (call/cc
+ (lambda (return)
+ (when (> 10 (bytevector-length bv))
+ (return (make-segment 0 (bytevector-length bv)
+ "Not a GZIP file")))
+
+ (let ()
+ (define ptr 0)
+
+ (define id1 (bytevector-u8-ref bv 0))
+ (define id2 (bytevector-u8-ref bv 1))
+ (define cm (bytevector-u8-ref bv 2))
+ (define flg (bytevector-u8-ref bv 3))
+ (define mtime (bytevector-u32-ref-le bv 4))
+ (define xfl (bytevector-u8-ref bv 8))
+ (define os (bytevector-u8-ref bv 9))
+
+ (cond ((= addr 0) (return (make-segment 0 1 "ID1 = 31")))
+ ((= addr 1) (return (make-segment 1 2 "ID2 = 139")))
+ ((= addr 2) (return (make-segment
+ 2 3
+ "CM (Compression Method)\nCM = 8 is deflate")))
+ ((= addr 3) (return (make-segment 3 4
+ (apply string-append (parse-flags (bytevector-u8-ref bv addr))))))
+ ((<= 4 addr 7) (return (make-segment
+ 4 8 (string-append "mtime="
+ (number->string mtime)))))
+ ((= addr 8) (return (make-segment 8 9 "XFL")))
+ ((= addr 9) (return (make-segment 9 10 (string-append "OS: " (os-name os)))))
+ (else 'continue))
+
+ (set! ptr (+ ptr 10))
+
+ (when (bit-set? FEXTRA flg)
+ (let ((xlen ((bytevector-u16-ref-le bv ptr))))
+ (when (<= addr ptr (+ 1 addr))
+ (return (make-segment ptr (+ 1 ptr) "XLEN")))
+ (set! ptr (+ ptr 2))
+ (when (< addr (+ ptr xlen))
+ (return (make-segment ptr (+ ptr xlen) "XLEN bytes of extra data")))
+ (set! ptr (+ ptr xlen 1))))
+
+
+ ;; utf8->string exists in R7RS,
+ ;; But we want latin1->string
+ (when (bit-set? FNAME flg)
+ (cond ((bytevector-search bv 0 ptr)
+ => (lambda (idx)
+ (let ((old ptr))
+ (set! ptr (+ idx 1))
+ (when (< addr ptr)
+ (return (make-segment old ptr "Filename"))))))
+ (else (return (make-segment ptr (bytevector-length bv)
+ "Unterminated Filename")))))
+
+ (when (bit-set? FCOMMENT flg)
+ (cond ((bytevector-search bv 0 ptr)
+ => (lambda (idx)
+ (let ((old ptr))
+ (set! ptr (+ idx 1))
+ (when (< addr ptr)
+ (return (make-segment old ptr "Comment"))))))
+ (else (return (make-segment ptr (bytevector-length bv)
+ "Unterminated Comment")))))
+
+ (when (bit-set? FHCRC flg)
+ (when (< addr (+ ptr 2))
+ (return
+ (make-segment ptr (+ ptr 2)
+ (string-append
+ "CRC16="
+ (number->string
+ (bytevector-u16-ref-le bv ptr))))))
+ (set! ptr (+ ptr 2)))
+
+ (cond ((>= 4 (- (bytevector-length bv) addr))
+ (return (make-segment (- (bytevector-length bv) 4)
+ (bytevector-length bv)
+ (string-append "ISIZE="
+ (number->string
+ (bytevector-u32-ref-le
+ bv (- (bytevector-length bv) 4)))))))
+ ((>= 4 (- (bytevector-length bv) addr 4))
+ (return (make-segment (- (bytevector-length bv) 8)
+ (- (bytevector-length bv) 4)
+ (string-append "CRC32="
+ (number->string
+ (bytevector-u32-ref-le
+ bv (- (bytevector-length bv) 8)))))))
+ ((<= ptr addr (+ ptr (bytevector-length bv) -8))
+ (return (make-segment ptr
+ (- (bytevector-length bv) 8)
+ "ZLIB compressed payload"))))
+
+ (return (make-segment -1 -1 "No Segment"))
+ ))))