]>
Commit | Line | Data |
---|---|---|
4ef946dd | 1 | /* |
c1830d26 TB |
2 | * Copyright (C) 2012 Tobias Brunner |
3 | * Hochschule fuer Technik Rapperswil | |
4 | * | |
4ef946dd | 5 | * Copyright (C) 2010 Martin Willi |
0f82a470 | 6 | * Copyright (C) 2010 revosec AG |
4ef946dd MW |
7 | * |
8 | * This program is free software; you can redistribute it and/or modify it | |
9 | * under the terms of the GNU General Public License as published by the | |
10 | * Free Software Foundation; either version 2 of the License, or (at your | |
11 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, but | |
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
15 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
16 | * for more details. | |
17 | */ | |
18 | ||
7e432eff | 19 | #include "bio_reader.h" |
4ef946dd | 20 | |
f05b4272 | 21 | #include <utils/debug.h> |
4ef946dd | 22 | |
7e432eff | 23 | typedef struct private_bio_reader_t private_bio_reader_t; |
4ef946dd MW |
24 | |
25 | /** | |
7e432eff | 26 | * Private data of an bio_reader_t object. |
4ef946dd | 27 | */ |
7e432eff | 28 | struct private_bio_reader_t { |
4ef946dd MW |
29 | |
30 | /** | |
7e432eff | 31 | * Public bio_reader_t interface. |
4ef946dd | 32 | */ |
7e432eff | 33 | bio_reader_t public; |
4ef946dd MW |
34 | |
35 | /** | |
36 | * Remaining data to process | |
37 | */ | |
38 | chunk_t buf; | |
39 | }; | |
40 | ||
7e432eff AS |
41 | METHOD(bio_reader_t, remaining, u_int32_t, |
42 | private_bio_reader_t *this) | |
4ef946dd MW |
43 | { |
44 | return this->buf.len; | |
45 | } | |
46 | ||
7e432eff AS |
47 | METHOD(bio_reader_t, peek, chunk_t, |
48 | private_bio_reader_t *this) | |
3ddd164e MW |
49 | { |
50 | return this->buf; | |
51 | } | |
52 | ||
c1830d26 TB |
53 | /** |
54 | * A version of chunk_skip() that supports skipping from the end (i.e. simply | |
55 | * reducing the size) | |
56 | */ | |
57 | static inline chunk_t chunk_skip_end(chunk_t chunk, size_t bytes, bool from_end) | |
58 | { | |
59 | if (chunk.len > bytes) | |
60 | { | |
61 | if (!from_end) | |
62 | { | |
63 | chunk.ptr += bytes; | |
64 | } | |
65 | chunk.len -= bytes; | |
66 | return chunk; | |
67 | } | |
68 | return chunk_empty; | |
69 | } | |
70 | ||
71 | /** | |
72 | * Returns a pointer to the data to read, optionally from the end | |
73 | */ | |
74 | static inline u_char *get_ptr_end(private_bio_reader_t *this, u_int32_t len, | |
75 | bool from_end) | |
76 | { | |
77 | return from_end ? this->buf.ptr + (this->buf.len - len) : this->buf.ptr; | |
78 | } | |
79 | ||
80 | /** | |
81 | * Read an u_int8_t from the buffer, optionally from the end of the buffer | |
82 | */ | |
83 | static bool read_uint8_internal(private_bio_reader_t *this, u_int8_t *res, | |
84 | bool from_end) | |
4ef946dd MW |
85 | { |
86 | if (this->buf.len < 1) | |
87 | { | |
7e432eff | 88 | DBG1(DBG_LIB, "%d bytes insufficient to parse u_int8 data", |
58d73d38 | 89 | this->buf.len); |
4ef946dd MW |
90 | return FALSE; |
91 | } | |
c1830d26 TB |
92 | *res = *get_ptr_end(this, 1, from_end); |
93 | this->buf = chunk_skip_end(this->buf, 1, from_end); | |
4ef946dd MW |
94 | return TRUE; |
95 | } | |
96 | ||
c1830d26 TB |
97 | /** |
98 | * Read an u_int16_t from the buffer, optionally from the end | |
99 | */ | |
100 | static bool read_uint16_internal(private_bio_reader_t *this, u_int16_t *res, | |
101 | bool from_end) | |
4ef946dd MW |
102 | { |
103 | if (this->buf.len < 2) | |
104 | { | |
7e432eff | 105 | DBG1(DBG_LIB, "%d bytes insufficient to parse u_int16 data", |
58d73d38 | 106 | this->buf.len); |
4ef946dd MW |
107 | return FALSE; |
108 | } | |
c1830d26 TB |
109 | *res = untoh16(get_ptr_end(this, 2, from_end)); |
110 | this->buf = chunk_skip_end(this->buf, 2, from_end); | |
4ef946dd MW |
111 | return TRUE; |
112 | } | |
113 | ||
c1830d26 TB |
114 | /** |
115 | * Read an u_int32_t (only 24-bit) from the buffer, optionally from the end | |
116 | */ | |
117 | static bool read_uint24_internal(private_bio_reader_t *this, u_int32_t *res, | |
118 | bool from_end) | |
4ef946dd MW |
119 | { |
120 | if (this->buf.len < 3) | |
121 | { | |
7e432eff | 122 | DBG1(DBG_LIB, "%d bytes insufficient to parse u_int24 data", |
58d73d38 | 123 | this->buf.len); |
4ef946dd MW |
124 | return FALSE; |
125 | } | |
c1830d26 TB |
126 | *res = untoh32(get_ptr_end(this, 3, from_end)) >> 8; |
127 | this->buf = chunk_skip_end(this->buf, 3, from_end); | |
4ef946dd MW |
128 | return TRUE; |
129 | } | |
130 | ||
c1830d26 TB |
131 | /** |
132 | * Read an u_int32_t from the buffer, optionally from the end | |
133 | */ | |
134 | static bool read_uint32_internal(private_bio_reader_t *this, u_int32_t *res, | |
135 | bool from_end) | |
4ef946dd MW |
136 | { |
137 | if (this->buf.len < 4) | |
138 | { | |
7e432eff | 139 | DBG1(DBG_LIB, "%d bytes insufficient to parse u_int32 data", |
58d73d38 | 140 | this->buf.len); |
4ef946dd MW |
141 | return FALSE; |
142 | } | |
c1830d26 TB |
143 | *res = untoh32(get_ptr_end(this, 4, from_end)); |
144 | this->buf = chunk_skip_end(this->buf, 4, from_end); | |
4ef946dd MW |
145 | return TRUE; |
146 | } | |
147 | ||
c1830d26 TB |
148 | /** |
149 | * Read an u_int64_t from the buffer, optionally from the end | |
150 | */ | |
151 | static bool read_uint64_internal(private_bio_reader_t *this, u_int64_t *res, | |
152 | bool from_end) | |
fbeb9454 AS |
153 | { |
154 | if (this->buf.len < 8) | |
155 | { | |
156 | DBG1(DBG_LIB, "%d bytes insufficient to parse u_int64 data", | |
157 | this->buf.len); | |
158 | return FALSE; | |
159 | } | |
c1830d26 TB |
160 | *res = untoh64(get_ptr_end(this, 8, from_end)); |
161 | this->buf = chunk_skip_end(this->buf, 8, from_end); | |
fbeb9454 AS |
162 | return TRUE; |
163 | } | |
164 | ||
c1830d26 TB |
165 | /** |
166 | * Read a chunk of data from the buffer, optionally from the end | |
167 | */ | |
168 | static bool read_data_internal(private_bio_reader_t *this, u_int32_t len, | |
169 | chunk_t *res, bool from_end) | |
4ef946dd MW |
170 | { |
171 | if (this->buf.len < len) | |
172 | { | |
7e432eff | 173 | DBG1(DBG_LIB, "%d bytes insufficient to parse %d bytes of data", |
4ef946dd MW |
174 | this->buf.len, len); |
175 | return FALSE; | |
176 | } | |
c1830d26 TB |
177 | *res = chunk_create(get_ptr_end(this, len, from_end), len); |
178 | this->buf = chunk_skip_end(this->buf, len, from_end); | |
4ef946dd MW |
179 | return TRUE; |
180 | } | |
181 | ||
c1830d26 TB |
182 | METHOD(bio_reader_t, read_uint8, bool, |
183 | private_bio_reader_t *this, u_int8_t *res) | |
184 | { | |
185 | return read_uint8_internal(this, res, FALSE); | |
186 | } | |
187 | ||
188 | METHOD(bio_reader_t, read_uint16, bool, | |
189 | private_bio_reader_t *this, u_int16_t *res) | |
190 | { | |
191 | return read_uint16_internal(this, res, FALSE); | |
192 | } | |
193 | ||
194 | METHOD(bio_reader_t, read_uint24, bool, | |
195 | private_bio_reader_t *this, u_int32_t *res) | |
196 | { | |
197 | return read_uint24_internal(this, res, FALSE); | |
198 | } | |
199 | ||
200 | METHOD(bio_reader_t, read_uint32, bool, | |
201 | private_bio_reader_t *this, u_int32_t *res) | |
202 | { | |
203 | return read_uint32_internal(this, res, FALSE); | |
204 | } | |
205 | ||
206 | METHOD(bio_reader_t, read_uint64, bool, | |
207 | private_bio_reader_t *this, u_int64_t *res) | |
208 | { | |
209 | return read_uint64_internal(this, res, FALSE); | |
210 | } | |
211 | ||
212 | METHOD(bio_reader_t, read_data, bool, | |
213 | private_bio_reader_t *this, u_int32_t len, chunk_t *res) | |
214 | { | |
215 | return read_data_internal(this, len, res, FALSE); | |
216 | } | |
217 | ||
218 | METHOD(bio_reader_t, read_uint8_end, bool, | |
219 | private_bio_reader_t *this, u_int8_t *res) | |
220 | { | |
221 | return read_uint8_internal(this, res, TRUE); | |
222 | } | |
223 | ||
224 | METHOD(bio_reader_t, read_uint16_end, bool, | |
225 | private_bio_reader_t *this, u_int16_t *res) | |
226 | { | |
227 | return read_uint16_internal(this, res, TRUE); | |
228 | } | |
229 | ||
230 | METHOD(bio_reader_t, read_uint24_end, bool, | |
231 | private_bio_reader_t *this, u_int32_t *res) | |
232 | { | |
233 | return read_uint24_internal(this, res, TRUE); | |
234 | } | |
235 | ||
236 | METHOD(bio_reader_t, read_uint32_end, bool, | |
237 | private_bio_reader_t *this, u_int32_t *res) | |
238 | { | |
239 | return read_uint32_internal(this, res, TRUE); | |
240 | } | |
241 | ||
242 | METHOD(bio_reader_t, read_uint64_end, bool, | |
243 | private_bio_reader_t *this, u_int64_t *res) | |
244 | { | |
245 | return read_uint64_internal(this, res, TRUE); | |
246 | } | |
247 | ||
248 | METHOD(bio_reader_t, read_data_end, bool, | |
249 | private_bio_reader_t *this, u_int32_t len, chunk_t *res) | |
250 | { | |
251 | return read_data_internal(this, len, res, TRUE); | |
252 | } | |
253 | ||
7e432eff AS |
254 | METHOD(bio_reader_t, read_data8, bool, |
255 | private_bio_reader_t *this, chunk_t *res) | |
4ef946dd MW |
256 | { |
257 | u_int8_t len; | |
258 | ||
259 | if (!read_uint8(this, &len)) | |
260 | { | |
261 | return FALSE; | |
262 | } | |
263 | return read_data(this, len, res); | |
264 | } | |
265 | ||
7e432eff AS |
266 | METHOD(bio_reader_t, read_data16, bool, |
267 | private_bio_reader_t *this, chunk_t *res) | |
4ef946dd MW |
268 | { |
269 | u_int16_t len; | |
270 | ||
271 | if (!read_uint16(this, &len)) | |
272 | { | |
273 | return FALSE; | |
274 | } | |
275 | return read_data(this, len, res); | |
276 | } | |
277 | ||
7e432eff AS |
278 | METHOD(bio_reader_t, read_data24, bool, |
279 | private_bio_reader_t *this, chunk_t *res) | |
4ef946dd MW |
280 | { |
281 | u_int32_t len; | |
282 | ||
283 | if (!read_uint24(this, &len)) | |
284 | { | |
285 | return FALSE; | |
286 | } | |
287 | return read_data(this, len, res); | |
288 | } | |
289 | ||
7e432eff AS |
290 | METHOD(bio_reader_t, read_data32, bool, |
291 | private_bio_reader_t *this, chunk_t *res) | |
4ef946dd MW |
292 | { |
293 | u_int32_t len; | |
294 | ||
295 | if (!read_uint32(this, &len)) | |
296 | { | |
297 | return FALSE; | |
298 | } | |
299 | return read_data(this, len, res); | |
300 | } | |
301 | ||
7e432eff AS |
302 | METHOD(bio_reader_t, destroy, void, |
303 | private_bio_reader_t *this) | |
4ef946dd MW |
304 | { |
305 | free(this); | |
306 | } | |
307 | ||
308 | /** | |
309 | * See header | |
310 | */ | |
7e432eff | 311 | bio_reader_t *bio_reader_create(chunk_t data) |
4ef946dd | 312 | { |
7e432eff | 313 | private_bio_reader_t *this; |
4ef946dd MW |
314 | |
315 | INIT(this, | |
316 | .public = { | |
317 | .remaining = _remaining, | |
3ddd164e | 318 | .peek = _peek, |
4ef946dd MW |
319 | .read_uint8 = _read_uint8, |
320 | .read_uint16 = _read_uint16, | |
321 | .read_uint24 = _read_uint24, | |
322 | .read_uint32 = _read_uint32, | |
fbeb9454 | 323 | .read_uint64 = _read_uint64, |
4ef946dd | 324 | .read_data = _read_data, |
c1830d26 TB |
325 | .read_uint8_end = _read_uint8_end, |
326 | .read_uint16_end = _read_uint16_end, | |
327 | .read_uint24_end = _read_uint24_end, | |
328 | .read_uint32_end = _read_uint32_end, | |
329 | .read_uint64_end = _read_uint64_end, | |
330 | .read_data_end = _read_data_end, | |
4ef946dd MW |
331 | .read_data8 = _read_data8, |
332 | .read_data16 = _read_data16, | |
333 | .read_data24 = _read_data24, | |
334 | .read_data32 = _read_data32, | |
335 | .destroy = _destroy, | |
336 | }, | |
337 | .buf = data, | |
338 | ); | |
339 | ||
340 | return &this->public; | |
341 | } |