Browse code
Add binary parsing library, rework .asd
Showing 2 changed files
1 | 1 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,80 @@ |
1 |
+(uiop:define-package :fwoar.bin-parser |
|
2 |
+ (:use :cl) |
|
3 |
+ (:mix :fw.lu :alexandria :serapeum)) |
|
4 |
+ |
|
5 |
+(in-package :fwoar.bin-parser) |
|
6 |
+ |
|
7 |
+(defun read-bytes (n s) |
|
8 |
+ (with (seq (make-array n :element-type 'octet)) |
|
9 |
+ (values seq |
|
10 |
+ (read-sequence seq s)))) |
|
11 |
+ |
|
12 |
+(defun calculate-sizes (desc) |
|
13 |
+ (reduce #'+ desc |
|
14 |
+ :key #'cadr |
|
15 |
+ :initial-value 0)) |
|
16 |
+ |
|
17 |
+(defun le->int (bytes) |
|
18 |
+ (cadr |
|
19 |
+ (reduce (op (destructuring-bind (count val) _1 |
|
20 |
+ (list (1+ count) |
|
21 |
+ (+ val |
|
22 |
+ (ash _2 |
|
23 |
+ (* count 8)))))) |
|
24 |
+ bytes |
|
25 |
+ :initial-value (list 0 0)))) |
|
26 |
+ |
|
27 |
+(defun get-extractable-bytes (desc &optional (bindings ())) |
|
28 |
+ (loop for ((name size . other) . rest) on (resolve-sizes desc bindings) |
|
29 |
+ until (symbolp size) |
|
30 |
+ collect (list* name size other) into extractable |
|
31 |
+ finally (return (values extractable |
|
32 |
+ (append (unsplice |
|
33 |
+ (when (symbolp size) |
|
34 |
+ (list* name size other))) |
|
35 |
+ rest))))) |
|
36 |
+ |
|
37 |
+(defun resolve-sizes (desc extant-bindings) |
|
38 |
+ (declare (optimize (debug 3))) |
|
39 |
+ (loop with bindings = (copy-seq extant-bindings) |
|
40 |
+ for (name size . rest) in desc |
|
41 |
+ for resolved = (when (symbolp size) |
|
42 |
+ (cdr (assoc size bindings))) |
|
43 |
+ when resolved do (push (cons name resolved) |
|
44 |
+ bindings) |
|
45 |
+ if resolved collect (list* name resolved rest) into new-desc |
|
46 |
+ else collect (list* name size rest) into new-desc |
|
47 |
+ finally (return (values new-desc |
|
48 |
+ (remove-duplicates (append (mapcar (op (apply #'cons (subseq _ 0 2))) |
|
49 |
+ new-desc) |
|
50 |
+ bindings) |
|
51 |
+ :key 'car |
|
52 |
+ :from-end t))))) |
|
53 |
+ |
|
54 |
+(defun extract-bytes (desc bytes) |
|
55 |
+ (loop |
|
56 |
+ with cur-idx = 0 |
|
57 |
+ for (name size . rest) in desc |
|
58 |
+ for next-seq = (subseq bytes cur-idx |
|
59 |
+ (+ cur-idx size)) |
|
60 |
+ collect (cons name (if rest |
|
61 |
+ (funcall (car rest) next-seq) |
|
62 |
+ next-seq)) |
|
63 |
+ do (incf cur-idx size))) |
|
64 |
+ |
|
65 |
+(defun parse-struct (desc s) |
|
66 |
+ (let* ((struct-size (calculate-sizes desc)) |
|
67 |
+ (bytes (read-bytes struct-size s))) |
|
68 |
+ (extract-bytes desc bytes))) |
|
69 |
+ |
|
70 |
+(defun make-zipfile-stream (fn) |
|
71 |
+ (open fn :element-type '(unsigned-byte 8))) |
|
72 |
+ |
|
73 |
+ |
|
74 |
+(defun extract (raw-desc s &optional bindings) |
|
75 |
+ (multiple-value-bind (desc remainder) (get-extractable-bytes raw-desc bindings) |
|
76 |
+ (let ((next-segment (parse-struct desc s))) |
|
77 |
+ (if remainder |
|
78 |
+ (append next-segment |
|
79 |
+ (extract remainder s (append next-segment bindings))) |
|
80 |
+ next-segment)))) |
... | ... |
@@ -1,5 +1,16 @@ |
1 | 1 |
;;;; fwoar.lisputils.asd |
2 | 2 |
(in-package :asdf-user) |
3 |
+ |
|
4 |
+(defsystem #:fwoar.lisputils/string-utils |
|
5 |
+ :description "A binary parser" |
|
6 |
+ :author "fiddlerwoaroof <fiddlerwoaroof@gmail.com" |
|
7 |
+ :license "MIT" |
|
8 |
+ :depends-on (#:should-test) |
|
9 |
+ :components ((:file "string-utils/package") |
|
10 |
+ (:file "string-utils/string-utils" :depends-on ("string-utils/package")) |
|
11 |
+ #-lispworks |
|
12 |
+ (:file "string-utils/test" :depends-on ("string-utils/string-utils")))) |
|
13 |
+ |
|
3 | 14 |
(asdf:defsystem #:fwoar.lisputils |
4 | 15 |
:description "Some utilities common to other libraries I'm writing" |
5 | 16 |
:author "fiddlerwoaroof <fiddlerwoaroof@gmail.com" |
... | ... |
@@ -13,6 +24,7 @@ |
13 | 24 |
#:serapeum |
14 | 25 |
#:cl-containers |
15 | 26 |
#:iterate |
27 |
+ #:fwoar.lisputils/string-utils |
|
16 | 28 |
#-lispworks #:plump |
17 | 29 |
#:positional-lambda |
18 | 30 |
#-lispworks #:should-test) |
... | ... |
@@ -24,13 +36,17 @@ |
24 | 36 |
(:file "clos-helpers") |
25 | 37 |
(:file "counter") |
26 | 38 |
(:file "vector-utils") |
27 |
- (:file "string-utils/package") |
|
28 |
- (:file "string-utils/string-utils") |
|
29 | 39 |
#-lispworks |
30 | 40 |
(:file "non-lispworks") |
31 | 41 |
#-lispworks |
32 |
- (:file "string-utils/test") |
|
33 |
- #-lispworks |
|
34 | 42 |
(:file "patmatch") |
35 | 43 |
(:file "glambda"))) |
36 | 44 |
|
45 |
+(defsystem #:fwoar.lisputils/bin-parser |
|
46 |
+ :description "A binary parser" |
|
47 |
+ :author "fiddlerwoaroof <fiddlerwoaroof@gmail.com" |
|
48 |
+ :license "MIT" |
|
49 |
+ :depends-on (:fwoar.lisputils |
|
50 |
+ :alexandria |
|
51 |
+ :serapeum) |
|
52 |
+ :components ((:file "bin-parser"))) |