From 4d82ef18a8bb18317be3e089f432f95b6e5dbd4a Mon Sep 17 00:00:00 2001 From: Piotr Szarmanski Date: Thu, 22 Sep 2022 11:16:44 +0200 Subject: Implement stream-read-byte --- src/cache.lisp | 2 +- src/eris-decode.lisp | 31 ++++++++++++++++++++++++------- tests/decode-tests.lisp | 43 +++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 66 insertions(+), 10 deletions(-) diff --git a/src/cache.lisp b/src/cache.lisp index ad6a0fa..d6bce9c 100644 --- a/src/cache.lisp +++ b/src/cache.lisp @@ -42,4 +42,4 @@ (lambda ,lambda-list (cacher ,cache ,call-list)))))) -(export cached-lambda) +(export 'cached-lambda) diff --git a/src/eris-decode.lisp b/src/eris-decode.lisp index b7575ab..43f8db0 100644 --- a/src/eris-decode.lisp +++ b/src/eris-decode.lisp @@ -186,7 +186,7 @@ fetched from a trusted party.") (setf (pos stream) new-pos (data buffer) (data (car (last root))) (pos buffer) (mod new-pos block-size)) - (if (= (- eof (mod eof block-size)) new-pos) + (if (< (- eof (mod eof block-size)) new-pos) (unpad-buffer buffer) (setf (eof buffer) block-size)))))) @@ -199,23 +199,25 @@ fetched from a trusted party.") (defun eris-decode (read-capability fetch-function &key (cache-capacity 2048)) - "With a given fetch-function, return a stream that decodes the read-capability. + "Using the FETCH-FUNCTION, return a stream that decodes the READ-CAPABILITY. Fetch-function must be a function with one argument, the reference octet, which returns a (simple-array (unsigned-byte 8)) containing the block. The block will be destructively modified, so you MUST provide a fresh array every time. If a hash-table is used, a (copy-seq) needs to be done on the return value of -gethash. " +gethash. + +The keyword argument CACHE-CAPACITY indicates the amount of blocks stored in the +cache." (with-slots (level block-size root-reference-pair) read-capability (let* ((get-block (cached-lambda (:cache-class 'lru-cache :capacity cache-capacity :table (make-hash-table :size (1+ cache-capacity) :test #'equalp)) (reference key &optional nonce) (let* ((block (funcall fetch-function reference))) + (unless block (error 'missing-block :reference reference)) (hash-check block reference) - (if block - (decrypt-block block key nonce) - (error 'missing-block :reference reference))))) + (decrypt-block block key nonce)))) (root (funcall get-block (reference root-reference-pair) (key root-reference-pair) (make-nonce level)))) ;; "Implementations MUST verify the key appearing in the read capability ;; if level of encoded content is larger than 0." @@ -282,10 +284,25 @@ the new position is beyond the end of file.." (read-to-seq seq buffer :start start :end (if end end (length seq)) :stream stream))) (defmethod stream-read-byte ((stream eris-decode-stream)) - nil) + (when (minusp (pos (buffer stream))) + ;; initializes the buffer + (reupdate-block stream (pos stream))) + (with-slots (position buffer block-size) stream + (with-slots (pos eof data) buffer + (cond + ((eql pos block-size) + (setf pos 0) + (advance-next-block stream) + (stream-read-byte stream)) + ((eql pos eof) + :eof) + (t (prog1 (aref data pos) + (incf pos) + (incf position))))))) (defmethod stream-element-type ((stream eris-decode-stream)) '(unsigned-byte 8)) (defun eris-file-length (stream) + "This is the equivalent of \"file-length\" for eris-decode-stream." (eof stream)) diff --git a/tests/decode-tests.lisp b/tests/decode-tests.lisp index 2cd359a..af3edb0 100644 --- a/tests/decode-tests.lisp +++ b/tests/decode-tests.lisp @@ -83,8 +83,6 @@ else do (replace decoded-array buf :start1 (* i s))))))) -(assert-bytes-read-4096 (make-octets 16383 :element 1) 1024 (4096 4096 4096 4095)) - (test simple-decoding-1kib (assert-array-decode (make-octets 1 :element 1) 1024) (assert-array-decode (make-octets 1023 :element 2) 1024) @@ -204,3 +202,44 @@ (assert-length (make-array 16384 :element-type '(unsigned-byte 8) :initial-element 2) 1024)) +(defmacro assert-read-byte (array block-size) + `(let* ((*table* (make-hash-table :test #'equalp)) + (array ,array) + (read-capability (eris-encode array ,block-size #'hashtable-encode)) + (decoded-array (make-array (length array) :element-type '(unsigned-byte 8) :fill-pointer 0)) + (stream (eris-decode read-capability #'hashtable-decode))) + (loop for i = (read-byte stream nil :eof) + until (eq i :eof) + do (vector-push i decoded-array)) + (is (equalp decoded-array array)))) + +(test check-read-byte + (assert-read-byte (make-octets 1 :element 2) 1024) + (assert-read-byte (make-octets 512 :element 2) 1024) + (assert-read-byte (make-octets 1023 :element 2) 1024) + (assert-read-byte (make-octets 1024 :element 2) 1024) + (assert-read-byte (make-octets 16383 :element 2) 1024) + (assert-read-byte (make-octets 16384 :element 2) 1024) + (assert-read-byte (make-octets 1024 :element 2) 32kib) + (assert-read-byte (make-octets 32767 :element 2) 32kib) + (assert-read-byte (make-octets 32768 :element 2) 32kib) + (assert-read-byte (make-octets 64000 :element 2) 32kib)) + +(defmacro assert-read-byte-error (array block-size) + `(let* ((*table* (make-hash-table :test #'equalp)) + (array ,array) + (read-capability (eris-encode array ,block-size #'hashtable-encode)) + (stream (eris-decode read-capability #'hashtable-decode))) + (signals end-of-file + (loop for i = (read-byte stream t) + for n = 0 then (incf n) + until (eql n (length array)))))) + +(test read-byte-eof + (assert-read-byte-error (make-octets 1 :element 2) 1024) + (assert-read-byte-error (make-octets 1024 :element 2) 1024) + (assert-read-byte-error (make-octets 16383 :element 2) 1024) + (assert-read-byte-error (make-octets 1024 :element 2) 32kib) + (assert-read-byte-error (make-octets 32767 :element 2) 32kib) + (assert-read-byte-error (make-octets 32768 :element 2) 32kib)) + -- cgit v1.2.3