private/bitbang.ss
;; Copyright 2000-2005 Ryan Culpepper
;; Released under the terms of the modified BSD license (see the file
;; COPYRIGHT for terms).

(module bitbang mzscheme
  (provide write-int16
           read-int16
           
           write-int32
           read-int32

           write-limbytes
           read-limbytes
           
           write-astring
           
           write-limstring
           read-limstring
           
           write-tbytes
           read-tbytes
           
           write-tstring
           read-tstring
           )
  
  
  ;; All output functions should write to ports: this way we can send
  ;; data directly through a connection, or we can print it out to a string
  ;; and then send the string.  The port shall be the first argument.
  
  ;; In the backend documentation, "string" meand C-style string, which
  ;; I assume means ASCII/Latin-1 string.
  ;; This question will need revisiting.
  
;; WRITING FUNCTIONS

;; Integer functions expect UNSIGNED values.  User is responsible for
;; doing whatever necessary to deal with negative numbers.

;; NOTE: The write functions do not report errors such as providing a number
;; to write-intN that is longer than N bits.  The function should silently
;; take the N least significant bits, but no guarantees...

  ;; write-int16 : port integer -> (void)
  ;; Writes a 16-bit integer, network byte order
  (define (write-int16 port val)
    (write-bytes (integer->integer-bytes val 2 #f #t) port))
  
  ;; write-int32 : port integer -> (void)
  ;; Writes a 32-bit integer, network byte order
  (define (write-int32 port val)
    (write-bytes (integer->integer-bytes val 4 #f #t) port))

  ;; write-astring : port string -> (void)
  ;; Writes an ASCII string.
  (define (write-astring port val)
    (write-bytes (string->bytes/latin-1 val)))
  
  ;; write-limstring : port size string -> (void)
  ;; Writes a string of length size, null padded on the end if necessary
  (define (write-limstring port size val)
    (write-limbytes port size (string->bytes/latin-1 val)))
  
  (define (write-limbytes port size val)
    (cond [(<= (bytes-length val) size)
           (write-bytes val port)
           (write-bytes (make-bytes (- size (bytes-length val)) 0) port)]
          [else
           (write-bytes (subbytes val 0 size) port)]))
  
  ;; write-tstring : port string -> (void)
  ;; Writes a null-terminated string to the port
  (define (write-tstring port val)
    (write-tbytes port (string->bytes/latin-1 val)))
  
  (define (write-tbytes port val)
    (write-bytes val port)
    (write-byte 0 port))
  
;  ;; write-bytestring : port string -> (void)
;  ;; Writes a stream of bytes (chars) as given in the string
;  ;; Does no null-padding, no null-ending
;  (define (write-bytestring port bytestring)
;    (display bytestring port))
  
  ;; READING
  
  ;; read-int16 : port -> integer
  (define (read-int16 port)
    (integer-bytes->integer (read-bytes 2 port) #f #t))
  
  ;; read-int32 : port -> integer
  (define (read-int32 port)
    (integer-bytes->integer (read-bytes 4 port) #f #t))

  ;; read-limstring : port size -> [string of length size]
  ;; Reads size bytes from the port and sticks them in a string
  (define (read-limstring port size)
    (bytes->string/latin-1 (read-limbytes port size)))
  
  (define (read-limbytes port size)
    (read-bytes size port))

  ;; read-tstring : port -> string
  ;; Reads a null-terminated string from the port
  (define (read-tstring port)
    (bytes->string/latin-1 (read-tbytes port)))
  
  (define (read-tbytes port)
    (let [(buffer (open-output-bytes))]
      (let loop ()
        (let ([next (read-byte port)])
          (unless (zero? next)
            (write-byte next buffer)
            (loop))))
      (get-output-bytes buffer)))
  
  )