-
Notifications
You must be signed in to change notification settings - Fork 138
/
cl-messagepack.lisp
264 lines (238 loc) · 9.09 KB
/
cl-messagepack.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
;;;; cl-messagepack.lisp
(in-package #:messagepack)
(declaim (optimize (debug 3)))
(eval-when (:compile-toplevel :load-toplevel :execute)
(defun mkstr (&rest args)
(format nil "~{~a~}" args))
(defun mksymb (&rest args)
(intern (apply #'mkstr args))))
(defmacro signed-unsigned-convertors (size)
(let ((speed (if (< size 32) 3 0)))
`(progn
(defun ,(mksymb 'sb size '-> 'ub size) (sb)
(declare (optimize (debug 0) (safety 0) (speed ,speed))
(type (integer ,(- (expt 2 (1- size))) ,(1- (expt 2 (1- size)))) sb))
(if (< sb 0)
(ldb (byte ,size 0) sb)
sb))
(defun ,(mksymb 'ub size '-> 'sb size) (sb)
(declare (optimize (debug 0) (safety 0) (speed ,speed))
(type (mod ,(expt 2 size)) sb))
(if (logbitp (1- ,size) sb)
(- (1+ (logxor (1- (expt 2 ,size)) sb)))
sb)))))
(signed-unsigned-convertors 8)
(signed-unsigned-convertors 16)
(signed-unsigned-convertors 32)
(signed-unsigned-convertors 64)
(defun write-hex (data)
(let (line)
(loop
for i from 0 to (1- (length data))
do (push (elt data i) line)
when (= (length line) 16)
do
(format t "~{~2,'0x ~}~%" (nreverse line))
(setf line nil))
(when line
(format t "~{~2,'0x ~}~%" (nreverse line)))))
(defun encode (data)
(flexi-streams:with-output-to-sequence (stream)
(encode-stream data stream)))
(defun make-hash (data)
(let ((result (make-hash-table)))
(dolist (kv data)
(cond ((consp (cdr kv))
(setf (gethash (first kv) result) (second kv)))
(t
(setf (gethash (car kv) result) (cdr kv)))))
result))
(defun is-byte-array (data-type)
(and (vectorp data-type)
(equal '(unsigned-byte 8) (array-element-type data-type))))
(defun encode-stream (data stream)
(cond ((floatp data) (encode-float data stream))
((numberp data) (encode-integer data stream))
((null data) (write-byte #xc0 stream))
((eq data t) (write-byte #xc3 stream))
((stringp data)
(encode-string data stream))
((is-byte-array data)
(encode-raw-bytes data stream))
((or (consp data) (vectorp data))
(encode-array data stream))
((hash-table-p data)
(encode-hash data stream))
((symbolp data)
(encode-string (symbol-name data) stream))
(t (error "Cannot encode data."))))
(defun encode-string (data stream)
(encode-raw-bytes (babel:string-to-octets data) stream))
#+sbcl (defun sbcl-encode-float (data stream)
(cond ((equal (type-of data) 'single-float)
(write-byte #xca stream)
(store-big-endian (sb-kernel:single-float-bits data) stream 4))
((equal (type-of data) 'double-float)
(write-byte #xcb stream)
(store-big-endian (sb-kernel:double-float-high-bits data) stream 4)
(store-big-endian (sb-kernel:double-float-low-bits data) stream 4)))
t)
(defun encode-float (data stream)
(or #+sbcl (sbcl-encode-float data stream)
#-(or sbcl) (error "No floating point support yet.")))
(defun encode-each (data stream &optional (encoder #'encode-stream))
(cond ((hash-table-p data)
(maphash (lambda (key value)
(funcall encoder key stream)
(funcall encoder value stream))
data))
((or (vectorp data) (consp data))
(mapc (lambda (subdata)
(funcall encoder subdata stream))
(coerce data 'list)))
(t (error "Not sequence or hash table."))))
(defun encode-sequence (data stream
short-prefix short-length
typecode-16 typecode-32
&optional (encoder #'encode-stream))
(let ((len (if (hash-table-p data)
(hash-table-count data)
(length data))))
(cond ((<= 0 len short-length)
(write-byte (+ short-prefix len) stream)
(encode-each data stream encoder))
((<= 0 len 65535)
(write-byte typecode-16 stream)
(store-big-endian len stream 2)
(encode-each data stream encoder))
((<= 0 len (1- (expt 2 32)))
(write-byte typecode-32 stream)
(store-big-endian len stream 4)
(encode-each data stream encoder)))))
(defun encode-hash (data stream)
(encode-sequence data stream #x80 15 #xdc #xdd))
(defun encode-array (data stream)
(encode-sequence data stream #x90 15 #xdc #xdd))
(defun encode-raw-bytes (data stream)
(encode-sequence data stream #xa0 31 #xda #xdb #'write-byte))
(defun encode-integer (data stream)
(cond ((<= 0 data 127) (write-byte data stream))
((<= -32 data -1) (write-byte (sb8->ub8 data) stream))
((<= 0 data 255)
(write-byte #xcc stream)
(write-byte data stream))
((<= 0 data 65535)
(write-byte #xcd stream)
(store-big-endian data stream 2))
((<= 0 data (1- (expt 2 32)))
(write-byte #xce stream)
(store-big-endian data stream 4))
((<= 0 data (1- (expt 2 64)))
(write-byte #xcf stream)
(store-big-endian data stream 8))
((<= -128 data 127)
(write-byte #xd0 stream)
(write-byte (sb8->ub8 data) stream))
((<= -32768 data 32767)
(write-byte #xd1 stream)
(write-byte (sb16->ub16 data) stream))
((<= (- (expt 2 31)) data (1- (expt 2 31)))
(write-byte #xd2 stream)
(write-byte (sb32->ub32 data) stream))
((<= (- (expt 2 63)) data (1- (expt 2 63)))
(write-byte #xd3 stream)
(write-byte (sb64->ub64 data) stream))
(t (error "Integer too large or too small."))))
(defun store-big-endian (number stream byte-count)
(let (byte-list)
(loop
while (> number 0)
do
(push (rem number 256)
byte-list)
(setf number (ash number -8)))
(loop
while (< (length byte-list) byte-count)
do (push 0 byte-list))
(when (> (length byte-list) byte-count)
(error "Number too large."))
(write-sequence byte-list stream)))
(defun decode (byte-array)
(flexi-streams:with-input-from-sequence (stream byte-array)
(decode-stream stream)))
(defun decode-stream (stream)
(let ((byte (read-byte stream)))
(cond ((= 0 (ldb (byte 1 7) byte))
byte)
((= 7 (ldb (byte 3 5) byte))
(ub8->sb8 byte))
((= #xcc byte)
(read-byte stream))
((= #xcd byte)
(load-big-endian stream 2))
((= #xce byte)
(load-big-endian stream 4))
((= #xcf byte)
(load-big-endian stream 8))
((= #xd0 byte)
(ub8->sb8 (read-byte stream)))
((= #xd1 byte)
(ub16->sb16 (load-big-endian stream 2)))
((= #xd2 byte)
(ub32->sb32 (load-big-endian stream 4)))
((= #xd3 byte)
(ub64->sb64 (load-big-endian stream 8)))
((= #xc0 byte)
nil)
((= #xc3 byte)
t)
((= #xc2 byte)
nil)
((= #xca byte)
(or #+sbcl (sb-kernel:make-single-float (load-big-endian stream 4))
#-(or sbcl) (error "No floating point support yet.")))
((= #xcb byte)
(or #+sbcl (sb-kernel:make-double-float (load-big-endian stream 4)
(load-big-endian stream 4))
#-(or sbcl) (error "No floating point support yet.")))
((= 5 (ldb (byte 3 5) byte))
(decode-raw-sequence (ldb (byte 5 0) byte) stream))
((= #xda byte)
(decode-raw-sequence (load-big-endian stream 2) stream))
((= #xdb byte)
(decode-raw-sequence (load-big-endian stream 4) stream))
((= 9 (ldb (byte 4 4) byte))
(decode-array (- byte #x90) stream))
((= #xdc byte)
(decode-array (load-big-endian stream 2) stream))
((= #xdd byte)
(decode-array (load-big-endian stream 4) stream))
((= 8 (ldb (byte 4 4) byte))
(decode-map (- byte #x80) stream))
((= #xde byte)
(decode-map (load-big-endian stream 2) stream))
((= #xdf byte)
(decode-map (load-big-endian stream 4) stream)))))
(defun decode-map (length stream)
(let ((hash-table (make-hash-table :test #'equal)))
(loop repeat length
do (let ((key (decode-stream stream))
(value (decode-stream stream)))
(setf (gethash key hash-table) value)))
hash-table))
(defun decode-array (length stream)
(let ((array (make-array length)))
(dotimes (i length)
(setf (aref array i) (decode-stream stream)))
array))
(defun decode-raw-sequence (length stream)
(let ((seq (make-array length :element-type '(mod 256))))
(read-sequence seq stream)
(babel:octets-to-string seq)))
(defun load-big-endian (stream byte-count)
(let ((result 0))
(loop
repeat byte-count
do (setf result (+ (ash result 8)
(read-byte stream))))
result))