bye
parent
1b8557373b
commit
3c27002620
@ -1,205 +0,0 @@
|
||||
#lang racket/base
|
||||
(require "private/racket.rkt")
|
||||
(require racket/generic racket/private/generic-methods)
|
||||
(provide (all-defined-out))
|
||||
|
||||
;; helper class
|
||||
(define-subclass object% (PortWrapper _port)
|
||||
(unless (port? _port)
|
||||
(raise-argument-error 'PortWrapper:constructor "port" _port))
|
||||
(define/public (pos [where #f])
|
||||
(when where (file-position _port where))
|
||||
(file-position _port))
|
||||
(define/public (dump) (void)))
|
||||
|
||||
(test-module
|
||||
(check-not-exn (λ () (make-object PortWrapper (open-input-bytes #"Foo"))))
|
||||
(check-not-exn (λ () (make-object PortWrapper (open-output-bytes))))
|
||||
(check-exn exn:fail? (λ () (make-object PortWrapper -42))))
|
||||
|
||||
|
||||
|
||||
#| approximates
|
||||
https://github.com/mbutterick/restructure/blob/master/src/EncodeStream.coffee
|
||||
|#
|
||||
|
||||
;; basically just a wrapper for a Racket output port
|
||||
(define EncodeStream
|
||||
(class* PortWrapper (dumpable<%>)
|
||||
(init-field [[maybe-output-port maybe-output-port] (open-output-bytes)])
|
||||
|
||||
(unless (output-port? maybe-output-port)
|
||||
(raise-argument-error 'EncodeStream:constructor "output port" maybe-output-port))
|
||||
|
||||
(super-make-object maybe-output-port)
|
||||
(inherit-field _port)
|
||||
|
||||
(define/override-final (dump) (get-output-bytes _port))
|
||||
|
||||
(define/public-final (write val)
|
||||
(unless (bytes? val)
|
||||
(raise-argument-error 'EncodeStream:write "bytes" val))
|
||||
(write-bytes val _port)
|
||||
(void))
|
||||
|
||||
(define/public-final (writeBuffer buffer)
|
||||
(write buffer))
|
||||
|
||||
(define/public-final (writeUInt8 int)
|
||||
(write (bytes int)))
|
||||
|
||||
(define/public (writeString string [encoding 'ascii])
|
||||
;; todo: handle encodings correctly.
|
||||
;; right now just utf8 and ascii are correct
|
||||
(caseq encoding
|
||||
[(utf16le ucs2 utf8 ascii) (writeBuffer (string->bytes/utf-8 string))
|
||||
(when (eq? encoding 'utf16le)
|
||||
(error 'swap-bytes-unimplemented))]
|
||||
[else (error 'unsupported-string-encoding)]))
|
||||
|
||||
(define/public (fill val len)
|
||||
(write (make-bytes len val)))))
|
||||
|
||||
(define-class-predicates EncodeStream)
|
||||
|
||||
(test-module
|
||||
(define es (+EncodeStream))
|
||||
(check-true (EncodeStream? es))
|
||||
(send es write #"AB")
|
||||
(check-equal? (· es pos) 2)
|
||||
(send es write #"C")
|
||||
(check-equal? (· es pos) 3)
|
||||
(send es write #"D")
|
||||
(check-equal? (· es pos) 4)
|
||||
(check-exn exn:fail? (λ () (send es write -42)))
|
||||
(check-exn exn:fail? (λ () (send es write 1)))
|
||||
(define op (open-output-bytes))
|
||||
(define es2 (+EncodeStream op))
|
||||
(send es2 write #"FOOBAR")
|
||||
(check-equal? (dump es2) #"FOOBAR")
|
||||
(check-equal? (dump es2) #"FOOBAR") ; dump can repeat
|
||||
(check-equal? (get-output-bytes op) #"FOOBAR")
|
||||
(define es3 (+EncodeStream))
|
||||
(send es3 fill 0 10)
|
||||
(check-equal? (dump es3) (make-bytes 10 0)))
|
||||
|
||||
|
||||
#| approximates
|
||||
https://github.com/mbutterick/restructure/blob/master/src/DecodeStream.coffee
|
||||
|#
|
||||
|
||||
;; basically just a wrapper for a Racket port
|
||||
;; but needs to start with a buffer so length can be found
|
||||
|
||||
(require "sizes.rkt")
|
||||
(define-macro (define-reader ID)
|
||||
#'(define/public (ID)
|
||||
(define bs (*ref type-sizes (string->symbol (string-downcase (string-replace (symbol->string 'ID) "read" "")))))
|
||||
(readBuffer bs)))
|
||||
|
||||
(define countable<%>
|
||||
(interface* ()
|
||||
([(generic-property gen:countable)
|
||||
(generic-method-table gen:countable
|
||||
(define (length o) (get-field length_ o)))])))
|
||||
|
||||
|
||||
|
||||
(define DecodeStreamT
|
||||
(class* PortWrapper
|
||||
(codable<%> dumpable<%> countable<%> posable<%>)
|
||||
(init-field [buffer #""])
|
||||
(unless (bytes? buffer) ; corresponds to a Node Buffer, not a restructure BufferT object
|
||||
(raise-argument-error 'DecodeStream:constructor "bytes" buffer))
|
||||
(super-make-object (open-input-bytes buffer))
|
||||
(inherit-field _port)
|
||||
|
||||
(field [_pos 0]
|
||||
[length_ (length buffer)])
|
||||
|
||||
(define/override (pos [where #f])
|
||||
(when where
|
||||
(set! _pos (super pos where)))
|
||||
_pos)
|
||||
|
||||
(define/public (count-nonzero-chars)
|
||||
;; helper function for String
|
||||
;; counts nonzero chars from current position
|
||||
(length (car (regexp-match-peek "[^\u0]*" _port))))
|
||||
|
||||
(public [-length length])
|
||||
(define (-length) length_)
|
||||
|
||||
(define/public (readString length__ [encoding 'ascii])
|
||||
(define proc (caseq encoding
|
||||
[(utf16le) (error 'bah)]
|
||||
[(ucs2) (error 'bleh)]
|
||||
[(utf8) bytes->string/utf-8]
|
||||
[(ascii) bytes->string/latin-1]
|
||||
[else identity]))
|
||||
(define start (pos))
|
||||
(define stop (+ start length__))
|
||||
(proc (subbytes buffer start (pos stop))))
|
||||
|
||||
(define/public-final (readBuffer count)
|
||||
(unless (index? count)
|
||||
(raise-argument-error 'DecodeStream:read "positive integer" count))
|
||||
(define bytes-remaining (- length_ (pos)))
|
||||
(when (> count bytes-remaining)
|
||||
(raise-argument-error 'DecodeStream:read (format "byte count not more than bytes remaining = ~a" bytes-remaining) count))
|
||||
(increment-field! _pos this count) ; don't use `pos` method here because `read-bytes` will increment the port position
|
||||
(define bs (read-bytes count _port))
|
||||
(unless (= _pos (file-position _port)) (raise-result-error 'DecodeStream "positions askew" (list _pos (file-position _port))))
|
||||
bs)
|
||||
|
||||
(define/public (read count) (readBuffer count))
|
||||
|
||||
(define/public (readUInt8) (bytes-ref (readBuffer 1) 0))
|
||||
(define/public (readUInt16BE) (+ (arithmetic-shift (readUInt8) 8) (readUInt8)))
|
||||
(define/public (readInt16BE) (unsigned->signed (readUInt16BE) 16))
|
||||
(define/public (readUInt16LE) (+ (readUInt8) (arithmetic-shift (readUInt8) 8)))
|
||||
(define/public (readUInt24BE) (+ (arithmetic-shift (readUInt16BE) 8) (readUInt8)))
|
||||
(define/public (readUInt24LE) (+ (readUInt16LE) (arithmetic-shift (readUInt8) 16)))
|
||||
(define/public (readInt24BE) (unsigned->signed (readUInt24BE) 24))
|
||||
(define/public (readInt24LE) (unsigned->signed (readUInt24LE) 24))
|
||||
|
||||
(define/override-final (dump)
|
||||
(define current-position (port-position _port))
|
||||
(set-port-position! _port 0)
|
||||
(define bs (port->bytes _port))
|
||||
(set-port-position! _port current-position)
|
||||
bs)))
|
||||
|
||||
|
||||
(define-subclass DecodeStreamT (DecodeStream))
|
||||
|
||||
(test-module
|
||||
(define ds (+DecodeStream #"ABCD"))
|
||||
(check-true (DecodeStream? ds))
|
||||
(check-equal? (length ds) 4)
|
||||
(check-equal? (dump ds) #"ABCD")
|
||||
(check-equal? (dump ds) #"ABCD") ; dump can repeat
|
||||
(check-equal? (send ds readUInt16BE) 16706)
|
||||
(check-equal? (dump ds) #"ABCD")
|
||||
(check-equal? (· ds pos) 2)
|
||||
(check-equal? (send ds readUInt8) 67)
|
||||
(check-equal? (· ds pos) 3)
|
||||
(check-equal? (send ds readUInt8) 68)
|
||||
(check-equal? (· ds pos) 4)
|
||||
(check-exn exn:fail? (λ () (send ds read -42)))
|
||||
(check-exn exn:fail? (λ () (send ds read 1))))
|
||||
|
||||
|
||||
|
||||
(test-module
|
||||
(define-subclass xenomorph-base% (Dummy)
|
||||
(define/augment (decode stream parent) "foo")
|
||||
(define/augment (encode stream val parent) "bar")
|
||||
(define/augment (size) 42))
|
||||
|
||||
(define d (+Dummy))
|
||||
(check-true (Dummy? d))
|
||||
(check-exn exn:fail:contract? (λ () (decode d 42)))
|
||||
(check-not-exn (λ () (decode d #"foo")))
|
||||
(check-exn exn:fail:contract? (λ () (encode d 42 21)))
|
||||
(check-not-exn (λ () (encode d 42 (open-output-bytes) ))))
|
Loading…
Reference in New Issue