1 ! Copyright (C) 2019 John Benediktsson
2 ! See http://factorcode.org/license.txt for BSD license
4 USING: accessors arrays assocs base64 byte-arrays calendar
5 calendar.format calendar.parser combinators endian io
6 io.encodings.binary io.encodings.string io.encodings.utf8
7 io.streams.byte-array io.streams.string kernel math math.bitwise
8 math.floats.half present sequences strings urls ;
16 SINGLETON: +cbor-undefined+
18 SINGLETON: +cbor-break+
20 SINGLETON: +cbor-indefinite+
22 TUPLE: cbor-tagged tag item ;
24 TUPLE: cbor-simple value ;
28 : read-unsigned ( info -- n )
35 { 31 [ +cbor-indefinite+ ] }
39 : read-bytestring ( info -- byte-array )
40 read-unsigned dup +cbor-indefinite+ = [
41 drop [ read-cbor dup +cbor-break+ = not ] [ ] produce nip concat
46 : read-textstring ( info -- string )
47 read-bytestring utf8 decode ;
49 : read-array ( info -- array )
50 read-unsigned dup +cbor-indefinite+ = [
51 drop [ read-cbor dup +cbor-break+ = not ] [ ] produce nip
53 [ read-cbor ] replicate
56 : read-map ( info -- alist )
57 read-unsigned dup +cbor-indefinite+ = [
58 drop [ read-cbor dup +cbor-break+ = not ]
59 [ read-cbor 2array ] produce nip
61 [ read-cbor read-cbor 2array ] replicate
64 : read-tagged ( info -- tagged )
65 read-unsigned read-cbor swap {
66 { 0 [ rfc3339>timestamp ] }
67 { 1 [ unix-time>timestamp ] }
72 [ swap cbor-tagged boa ]
75 : read-float ( info -- float )
76 dup 20 < [ cbor-simple boa ] [
81 { 23 [ +cbor-undefined+ ] }
82 { 24 [ read1 cbor-simple boa ] }
83 { 25 [ 2 read be> bits>half ] }
84 { 26 [ 4 read be> bits>float ] }
85 { 27 [ 8 read be> bits>double ] }
86 { 31 [ +cbor-break+ ] }
92 : read-cbor ( -- obj )
93 read1 [ 5 bits ] [ -5 shift 3 bits ] bi {
94 { 0 [ read-unsigned ] }
95 { 1 [ read-unsigned neg 1 - ] }
96 { 2 [ read-bytestring ] }
97 { 3 [ read-textstring ] }
100 { 6 [ read-tagged ] }
104 GENERIC: write-cbor ( obj -- )
108 M: f write-cbor drop 0xf4 write1 ;
110 M: t write-cbor drop 0xf5 write1 ;
112 M: +cbor-nil+ write-cbor drop 0xf6 write1 ;
114 M: +cbor-undefined+ write-cbor drop 0xf7 write1 ;
116 : write-integer ( n type -- )
118 { [ over 24 < ] [ bitor write1 ] }
119 { [ over 0xff <= ] [ 24 bitor write1 write1 ] }
120 { [ over 0xffff <= ] [ 25 bitor write1 2 >be write ] }
121 { [ over 0xffffffff <= ] [ 26 bitor write1 4 >be write ] }
122 { [ over 0xffffffffffffffff <= ] [ 27 bitor write1 8 >be write ] }
124 -5 shift 2 + 0xc0 bitor write1
125 dup bit-length 8 /mod zero? [ 1 + ] unless
130 M: integer write-cbor
131 dup 0 >= [ 0 write-integer ] [ neg 1 - 1 write-integer ] if ;
133 M: float write-cbor 0xfb write1 double>bits 8 >be write ;
135 M: byte-array write-cbor dup length 2 write-integer write ;
137 M: string write-cbor dup length 3 write-integer utf8 encode write ;
139 M: sequence write-cbor
140 dup length 4 write-integer [ write-cbor ] each ;
143 dup length 5 write-integer [ [ write-cbor ] bi@ ] assoc-each ;
145 M: timestamp write-cbor
146 0 6 write-integer timestamp>rfc3339 write-cbor ;
149 32 6 write-integer present write-cbor ;
151 M: cbor-tagged write-cbor
152 dup tag>> 6 write-integer item>> write-cbor ;
154 M: cbor-simple write-cbor
155 value>> 7 write-integer ;
159 GENERIC: cbor> ( seq -- obj )
162 [ read-cbor ] with-string-reader ;
165 binary [ read-cbor ] with-byte-reader ;
167 : >cbor ( obj -- bytes )
168 binary [ write-cbor ] with-byte-writer ;