Fletcher's checksum


Write functions to compute various sizes of Fletcher's checksum.

 $ cat fc.scm 
 (use-modules 
   ((rnrs io ports) #:renamer (symbol-prefix-proc 'bio:)) 
   (rnrs bytevectors) 
   (ice-9 match)) 
 (include-from-path "srfi-78/srfi-78.scm") 

Return a function accepting a file descriptor and returning the n-byte integer read from the file descriptor, or various status values.

 (define (make-reader n) 
   (lambda (f) 
     (let ((bytes (bio:get-bytevector-n f n))) 
       (cond  
         ((eof-object? bytes) 
            '(eof . #f)) 
         ((< (bytevector-length bytes) n) 
            '(err . #f)) 
         (#t  
           (cons 'num (bytevector-uint-ref bytes 0 (endianness big) n))))))) 
  
  
 (define reader1 (make-reader 1)) 
 (check (reader1 (bio:open-bytevector-input-port #vu8())) => '(eof . #f)) 
 (let ((f (bio:open-bytevector-input-port #vu8(1)))) 
   (check (reader1 f) => '(num . 1)) 
   (check (reader1 f) => '(eof . #f))) 
 (let ((f (bio:open-bytevector-input-port #vu8(0 1 255)))) 
   (check (reader1 f) => '(num . 0)) 
   (check (reader1 f) => '(num . 1)) 
   (check (reader1 f) => '(num . 255)) 
   (check (reader1 f) => '(eof . #f))) 
  
 (define reader2 (make-reader 2)) 
 (let ((f (bio:open-bytevector-input-port #vu8(0 1)))) 
   (check (reader2 f) => '(num . 1)) 
   (check (reader2 f) => '(eof . #f))) 
 (let ((f (bio:open-bytevector-input-port #vu8(0 0 0 1 0 255 255 255)))) 
   (check (reader2 f) => '(num . 0)) 
   (check (reader2 f) => '(num . 1)) 
   (check (reader2 f) => '(num . 255)) 
   (check (reader2 f) => '(num . #xffff)) 
   (check (reader2 f) => '(eof . #f))) 
  
 (define reader4 (make-reader 4)) 
 (let ((f (bio:open-bytevector-input-port #vu8(0 0 0 1)))) 
   (check (reader4 f) => '(num . 1)) 
   (check (reader4 f) => '(eof . #f))) 
 (let ((f (bio:open-bytevector-input-port #vu8(0 0 0 0 0 0 0 1 0 0 0 255 255 255 255 255)))) 
   (check (reader4 f) => '(num . 0)) 
   (check (reader4 f) => '(num . 1)) 
   (check (reader4 f) => '(num . 255)) 
   (check (reader4 f) => '(num . #xffffffff)) 
   (check (reader4 f) => '(eof . #f))) 

Return a function accepting a file descriptor f and returning the 2n-byte Fletcher's checksum of the data read from f. The number of bytes read from f should be evenly divisible by n.

 (define (make-fcs n) 
  
   (let* ((reader (make-reader n)) 
          (bits (* n 8)) 
          (little-mask (logxor -1 (ash -1 bits))) 
          (big-mask (logior (ash little-mask bits) little-mask))) 
  
     (lambda (f) 
       (let loop ((in (reader f)) (cs1 0) (cs2 0)) 
         (match (car in) 
           ('eof (logand (+ (ash cs2 bits) (logand cs1 little-mask))  
                         big-mask)) 
           ('err (error "unexpected eof")) 
           ('num  
             (let ((cs1' (+ cs1 (cdr in)))) 
               (loop (reader f) cs1' (+ cs2 cs1'))))))))) 
  
  
 (define fcs1 (make-fcs 1)) 
  
 (check (fcs1 (bio:open-bytevector-input-port #vu8())) => 0) 
 (check (fcs1 (bio:open-bytevector-input-port #vu8(1))) => #x0101) 
 (check (fcs1 (bio:open-bytevector-input-port #vu8(255 1))) => #x0ff00) 
 (check (fcs1 (bio:open-bytevector-input-port #vu8(1 255))) => #x0100) 
  
  
 (define fcs2 (make-fcs 2)) 
  
 (check (fcs2 (bio:open-bytevector-input-port #vu8())) => 0) 
 (check (fcs2 (bio:open-bytevector-input-port #vu8(0 1))) => #x00010001) 
 (check (fcs2 (bio:open-bytevector-input-port #vu8(0 255 0 1))) => #x01ff0100) 
 (check (fcs2 (bio:open-bytevector-input-port #vu8(0 1 0 255))) => #x01010100) 
  
  
 (define fcs4 (make-fcs 4)) 
  
 (check (fcs4 (bio:open-bytevector-input-port #vu8())) => 0) 
 (check (fcs4 (bio:open-bytevector-input-port #vu8(0 0 0 1))) => #x0000000100000001) 
 (check (fcs4 (bio:open-bytevector-input-port #vu8(0 0 0 255 0 0 0 1))) => #x000001ff00000100) 
 (check (fcs4 (bio:open-bytevector-input-port #vu8(0 0 0 1 0 0 0 255))) => #x000010100000100) 
  
  
 $ guile fc.scm 
  
 (reader1 (bio:open-bytevector-input-port #vu8())) => (eof . #f) ; correct 
 (reader1 f) => (num . 1) ; correct 
 (reader1 f) => (eof . #f) ; correct 
 (reader1 f) => (num . 0) ; correct 
 (reader1 f) => (num . 1) ; correct 
 (reader1 f) => (num . 255) ; correct 
 (reader1 f) => (eof . #f) ; correct 
  
 (reader2 f) => (num . 1) ; correct 
 (reader2 f) => (eof . #f) ; correct 
 (reader2 f) => (num . 0) ; correct 
 (reader2 f) => (num . 1) ; correct 
 (reader2 f) => (num . 255) ; correct 
 (reader2 f) => (num . 65535) ; correct 
 (reader2 f) => (eof . #f) ; correct 
  
 (reader4 f) => (num . 1) ; correct 
 (reader4 f) => (eof . #f) ; correct 
 (reader4 f) => (num . 0) ; correct 
 (reader4 f) => (num . 1) ; correct 
 (reader4 f) => (num . 255) ; correct 
 (reader4 f) => (num . 4294967295) ; correct 
 (reader4 f) => (eof . #f) ; correct 
  
 (fcs1 (bio:open-bytevector-input-port #vu8())) => 0 ; correct 
 (fcs1 (bio:open-bytevector-input-port #vu8(1))) => 257 ; correct 
 (fcs1 (bio:open-bytevector-input-port #vu8(255 1))) => 65280 ; correct 
 (fcs1 (bio:open-bytevector-input-port #vu8(1 255))) => 256 ; correct 
  
 (fcs2 (bio:open-bytevector-input-port #vu8())) => 0 ; correct 
 (fcs2 (bio:open-bytevector-input-port #vu8(0 1))) => 65537 ; correct 
 (fcs2 (bio:open-bytevector-input-port #vu8(0 255 0 1))) => 33489152 ; correct 
 (fcs2 (bio:open-bytevector-input-port #vu8(0 1 0 255))) => 16843008 ; correct 
  
 (fcs4 (bio:open-bytevector-input-port #vu8())) => 0 ; correct 
 (fcs4 (bio:open-bytevector-input-port #vu8(0 0 0 1))) => 4294967297 ; correct 
 (fcs4 (bio:open-bytevector-input-port #vu8(0 0 0 255 0 0 0 1))) => 2194728288512 ; correct 
 (fcs4 (bio:open-bytevector-input-port #vu8(0 0 0 1 0 0 0 255))) => 1103806595328 ; correct 
  
 $