lib/core: remove uses of Byte for Text
[nit.git] / lib / msgpack / read.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Low-level read MessagePack format from `Reader` streams
16 module read
17
18 import serialization
19 private import binary
20
21 import ext
22
23 redef class Reader
24
25 # Read the next MessagePack object and return it as a simple Nit object
26 #
27 # The return value is composed of:
28 # * the simple types `null`, `Bool`, `Int`, `Float`, `String` and `Bytes`,
29 # * collections of simple Nit objects `Array[nullable Serializable]`
30 # and `Map[nullable Serializable, nullable Serializable]`,
31 # * and `MsgPackExt` for custom MessagePack *ext* data.
32 #
33 # This method reads plain MessagePack data, as written by `MsgPackSerializer`
34 # when `plain_msgpack == true`. To deserialize full Nit objects from
35 # MessagePack with metadata use `Reader::deserialize_msgpack`.
36 fun read_msgpack: nullable Serializable
37 do
38 if last_error != null then return 0
39
40 var typ = read_byte
41 if typ < 0 then
42 # Error, return default `null`
43 return null
44
45 else if typ & 0b1000_0000 == 0 or typ & 0b1110_0000 == 0b1110_0000 then
46 # fixint
47 var bytes = new Bytes.with_capacity(1)
48 bytes.add typ
49 return bytes.to_i(signed=true)
50
51 else if typ & 0b1111_0000 == 0b1000_0000 then
52 # fixmap
53 var len = typ & 0b0000_1111
54 return read_msgpack_map_data(len.to_i)
55
56 else if typ & 0b1111_0000 == 0b1001_0000 then
57 # fixarray
58 var len = typ & 0b0000_1111
59 return read_msgpack_array_data(len.to_i)
60
61 else if typ & 0b1110_0000 == 0b1010_0000 then
62 # fixstr
63 var len = typ & 0b0001_1111
64 return read_bytes(len.to_i).to_s
65
66 else if typ == 0xC0 then
67 return null
68 else if typ == 0xC2 then
69 return false
70 else if typ == 0xC3 then
71 return true
72
73 else if typ >= 0xCC and typ <= 0xCF then
74 # uint8, 16, 32 and 64
75 var len = 1 << (typ - 0xCC)
76 return read_bytes(len).to_i
77
78 else if typ >= 0xD0 and typ <= 0xD3 then
79 # int8, 16, 32 and 64
80 var len = 1 << (typ - 0xD0)
81 return read_bytes(len).to_i(true)
82
83 else if typ == 0xCA then
84 return read_float
85 else if typ == 0xCB then
86 return read_double
87
88 else if typ >= 0xD9 and typ <= 0xDB then
89 # str8, 16 and 32
90 var len_ln = 1 << (typ - 0xD9)
91 var bf = read_bytes(len_ln)
92 var len = bf.to_i
93 if len < 0 then return null
94 var rd_buf = read_bytes(len)
95 if rd_buf.length != len then
96 # Bad formatted message.
97 return null
98 end
99 return rd_buf.to_s
100
101 else if typ >= 0xC4 and typ <= 0xC6 then
102 # bin8, 16 or 32
103 var len_ln = 1 << (typ - 0xC4)
104 var bf = read_bytes(len_ln)
105 var len = bf.to_i
106 if len < 0 then return null
107 var rd_buf = read_bytes(len)
108 if rd_buf.length != len then
109 # Bad formatted message.
110 return null
111 end
112 return rd_buf
113
114 else if typ == 0xDC or typ == 0xDD then
115 # array16 and array32
116 var len_ln = 2 << (typ - 0xDC)
117 var lenbuf = read_bytes(len_ln)
118 return read_msgpack_array_data(lenbuf.to_i)
119
120 else if typ == 0xDE or typ == 0xDF then
121 # map16 and map32
122 var len_ln = 2 << (typ - 0xDE)
123 var lenbuf = read_bytes(len_ln)
124 return read_msgpack_map_data(lenbuf.to_i)
125
126 else if typ == 0xD4 then
127 # fixext1
128 return read_msgpack_fixext_data(1)
129 else if typ == 0xD5 then
130 # fixext2
131 return read_msgpack_fixext_data(2)
132 else if typ == 0xD6 then
133 # fixext4
134 return read_msgpack_fixext_data(4)
135 else if typ == 0xD7 then
136 # fixext8
137 return read_msgpack_fixext_data(8)
138 else if typ == 0xD8 then
139 # fixext16
140 return read_msgpack_fixext_data(16)
141
142 else if typ == 0xC7 then
143 # ext1
144 return read_msgpack_ext_data(1)
145 else if typ == 0xC8 then
146 # ext2
147 return read_msgpack_ext_data(2)
148 else if typ == 0xC9 then
149 # ext4
150 return read_msgpack_ext_data(4)
151 end
152
153 print_error "MessagePack Warning: Found no match for typ {typ.to_base(16)} / 0b{typ.to_base(2)}"
154 return null
155 end
156
157 # Read the content of a map, `len` keys and values
158 private fun read_msgpack_map_data(len: Int): Map[nullable Serializable, nullable Serializable]
159 do
160 var map = new Map[nullable Serializable, nullable Serializable]
161 for i in [0..len.to_i[ do map[read_msgpack] = read_msgpack
162 return map
163 end
164
165 # Read the content of an array of `len` items
166 private fun read_msgpack_array_data(len: Int): Array[nullable Serializable]
167 do
168 return [for i in [0..len[ do read_msgpack]
169 end
170
171 # Read the content of a *fixext* of `len` bytes
172 #
173 # ~~~
174 # var reader = new BytesReader(b"\xC7\x03\x0A\x0B\x0C\x0D")
175 # var ext = reader.read_msgpack
176 # assert ext isa MsgPackExt
177 # assert ext.typ == 0x0a
178 # assert ext.data == b"\x0B\x0C\x0D"
179 # ~~~
180 private fun read_msgpack_fixext_data(len: Int): MsgPackExt
181 do
182 var exttyp = read_byte
183 if exttyp < 0 then exttyp = 0
184 var data = read_bytes(len)
185 return new MsgPackExt(exttyp, data)
186 end
187
188 # Read the content of a dynamic *ext* including the length on `len_len` bytes
189 private fun read_msgpack_ext_data(len_len: Int): MsgPackExt
190 do
191 var len = read_bytes(len_len).to_i
192 return read_msgpack_fixext_data(len)
193 end
194 end