0.9.8.10
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
serialization-c.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007-2015 Hypertable, Inc.
3  *
4  * This file is part of Hypertable.
5  *
6  * Hypertable is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 3
9  * of the License, or any later version.
10  *
11  * Hypertable is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  * 02110-1301, USA.
20  */
21 
27 #ifndef HT_SERIALIZATION_C_H
28 #define HT_SERIALIZATION_C_H
29 
30 /* Check if stdint is included correctly */
31 #ifndef SIZE_MAX
32 # error Forgot to include "Common/Compat.h" _first_ in your *.cc or *.c?
33 #endif
34 
35 /* Selection of implementation */
36 #ifdef HT_SERIALIZATION_GENERIC
37 #undef HT_LITTLE_ENDIAN
38 #else
39 #include "endian-c.h"
40 #endif
41 
42 /* Overridable error handling helper macros */
43 #ifdef __cplusplus
44 # include "Common/Error.h"
45 # ifndef HT_THROW_INPUT_OVERRUN
46 # define HT_THROW_INPUT_OVERRUN(_r_, _l_) \
47  HT_THROWF(Error::SERIALIZATION_INPUT_OVERRUN, \
48  "Need %lu bytes but only %lu remain", (Lu)(_l_), (Lu)(_r_))
49 # endif
50 # ifndef HT_THROW_BAD_VSTR
51 # define HT_THROW_BAD_VSTR(_s_) \
52  HT_THROWF(Error::SERIALIZATION_BAD_VSTR, "Error decoding %s", _s_)
53 # endif
54 # ifndef HT_THROW_BAD_VINT
55 # define HT_THROW_BAD_VINT(_s_) \
56  HT_THROWF(Error::SERIALIZATION_BAD_VINT, "Error decoding %s", _s_)
57 # endif
58 # ifndef HT_THROW_UNPOSSIBLE
59 # define HT_THROW_UNPOSSIBLE(_s_) \
60  HT_THROWF(Error::UNPOSSIBLE, "%s", _s_)
61 # endif
62 #else
63 # include <cstdio>
64 # ifndef HT_THROW_INPUT_OVERRUN
65 # define HT_THROW_INPUT_OVERRUN(_s_) do { \
66  std::fprintf(stderr, "Error: %s (%s:%d): input overrun deocding %s", \
67  HT_FUNC, __FILE__, __LINE__, _s_); \
68  abort(); \
69  } while (0)
70 # endif
71 # ifndef HT_THROW_BAD_VSTR
72 # define HT_THROW_BAD_VSTR(_s_) do { \
73  std::fprintf(stderr, "Error: %s (%s:%d): malformed input decoding %s", \
74  HT_FUNC, __FILE__, __LINE__, _s_); \
75  abort(); \
76  } while (0)
77 # endif
78 # ifndef HT_THROW_BAD_VINT
79 # define HT_THROW_BAD_VINT(_s_) do { \
80  std::fprintf(stderr, "Error: %s (%s:%d): malformed input decoding %s", \
81  HT_FUNC, __FILE__, __LINE__, _s_); \
82  abort(); \
83  } while (0)
84 # endif
85 # ifndef HT_THROW_UNPOSSIBLE
86 # define HT_THROW_UNPOSSIBLE(_s_) do { \
87  std::fprintf(stderr, "Error: %s (%s:%d): unpossible!: %s", \
88  HT_FUNC, __FILE__, __LINE__, _s_); \
89  abort(); \
90  } while (0)
91 # endif
92 #endif
93 
94 #define HT_DECODE_NEED(_r_, _l_) do { \
95  if (_r_ < _l_) \
96  HT_THROW_INPUT_OVERRUN(_r_, _l_); \
97  _r_ -= _l_; \
98 } while (0)
99 
100 
101 /*
102  * Encode a boolean value
103  */
104 #define HT_ENCODE_BOOL(_op_, _v_) *(_op_)++ = (_v_) ? 1 : 0
105 
106 
107 /*
108  * Encode a 8-bit integer (byte)
109  */
110 #define HT_ENCODE_I8(_op_, _v_) *(_op_)++ = _v_
111 
112 /*
113  * Decode a 8-bit integer (a byte/character)
114  */
115 #define HT_DECODE_I8(_ip_, _r_, _v_) do { \
116  HT_DECODE_NEED(_r_, 1); \
117  _v_ = *(_ip_)++; \
118 } while (0)
119 
120 /*
121  * Encode a 16 bit integer in little endian format
122  */
123 #ifdef HT_LITTLE_ENDIAN
124 # define HT_ENCODE_I16(_op_, _v_) do { \
125  memcpy(_op_, &(_v_), 2); \
126  _op_ += 2; \
127  } while (0)
128 #else
129 # define HT_ENCODE_I16(_op_, _v_) do { \
130  *(_op_)++ = (uint8_t)(_v_); \
131  *(_op_)++ = (uint8_t)((_v_) >> 8); \
132  } while (0)
133 #endif
134 
135 /*
136  * Decoded a 16 bit integer encoded in little endian format
137  */
138 #ifdef HT_LITTLE_ENDIAN
139 # define HT_DECODE_I16(_ip_, _r_, _v_) do { \
140  HT_DECODE_NEED(_r_, 2); \
141  memcpy(&(_v_), _ip_, 2); \
142  _ip_ += 2; \
143  } while (0)
144 #else
145 # define HT_DECODE_I16(_ip_, _r_, _v_) do { \
146  HT_DECODE_NEED(_r_, 2); \
147  _v_ = *(_ip_)++; \
148  _v_ |= (*(_ip_)++ << 8); \
149  } while (0)
150 #endif
151 
152 
153 /*
154  * Enocde a 32-bit integer in little endian format
155  */
156 #ifdef HT_LITTLE_ENDIAN
157 # define HT_ENCODE_I32(_op_, _v_) do { \
158  memcpy(_op_, &(_v_), 4); \
159  _op_ += 4; \
160  } while (0)
161 #else
162 # define HT_ENCODE_I32(_op_, _v_) do { \
163  *(_op_)++ = (uint8_t)(_v_); \
164  *(_op_)++ = (uint8_t)((_v_) >> 8); \
165  *(_op_)++ = (uint8_t)((_v_) >> 16); \
166  *(_op_)++ = (uint8_t)((_v_) >> 24); \
167  } while (0)
168 #endif
169 
170 /*
171  * Decode a 32-bit integer encoded in little endian format
172  */
173 #ifdef HT_LITTLE_ENDIAN
174 # define HT_DECODE_I32(_ip_, _r_, _v_) do { \
175  HT_DECODE_NEED(_r_, 4); \
176  memcpy(&_v_, _ip_, 4); \
177  _ip_ += 4; \
178  } while (0)
179 #else
180 # define HT_DECODE_I32(_ip_, _r_, _v_) do { \
181  HT_DECODE_NEED(_r_, 4); \
182  _v_ = *(_ip_)++; \
183  _v_ |= (*(_ip_)++ << 8); \
184  _v_ |= (*(_ip_)++ << 16); \
185  _v_ |= (*(_ip_)++ << 24); \
186  } while (0)
187 #endif
188 
189 
190 /*
191  * Encode a 64-bit integer in little endian format
192  */
193 #ifdef HT_LITTLE_ENDIAN
194 # define HT_ENCODE_I64(_op_, _v_) do { \
195  memcpy(_op_, &(_v_), 8); \
196  _op_ += 8; \
197  } while (0)
198 #else
199 # define HT_ENCODE_I64(_op_, _v_) do { \
200  *(_op_)++ = (uint8_t)(_v_); \
201  *(_op_)++ = (uint8_t)((_v_) >> 8); \
202  *(_op_)++ = (uint8_t)((_v_) >> 16); \
203  *(_op_)++ = (uint8_t)((_v_) >> 24); \
204  *(_op_)++ = (uint8_t)((_v_) >> 32); \
205  *(_op_)++ = (uint8_t)((_v_) >> 40); \
206  *(_op_)++ = (uint8_t)((_v_) >> 48); \
207  *(_op_)++ = (uint8_t)((_v_) >> 56); \
208  } while (0)
209 #endif
210 
211 /*
212  * Decode a 64-bit integer encoded in little endian format
213  */
214 #ifdef HT_LITTLE_ENDIAN
215 # define HT_DECODE_I64(_ip_, _r_, _v_) do { \
216  HT_DECODE_NEED(_r_, 8); \
217  memcpy(&(_v_), _ip_, 8); \
218  _ip_ += 8; \
219  } while (0)
220 #else
221 # define HT_DECODE_I64(_ip_, _r_, _v_) do { \
222  HT_DECODE_NEED(_r_, 8); \
223  _v_ = *(_ip_)++; \
224  _v_ |= (*(_ip_)++ << 8); \
225  _v_ |= (*(_ip_)++ << 16); \
226  _v_ |= ((uint64_t)(*(_ip_)++) << 24); \
227  _v_ |= ((uint64_t)(*(_ip_)++) << 32); \
228  _v_ |= ((uint64_t)(*(_ip_)++) << 40); \
229  _v_ |= ((uint64_t)(*(_ip_)++) << 48); \
230  _v_ |= ((uint64_t)(*(_ip_)++) << 56); \
231  } while (0)
232 #endif
233 
234 
235 /* vint limits */
236 #define HT_MAX_V1B 0x7f
237 #define HT_MAX_V2B 0x3fff
238 #define HT_MAX_V3B 0x1fffff
239 #define HT_MAX_V4B 0xfffffff
240 #define HT_MAX_V5B 0x7ffffffffull
241 #define HT_MAX_V6B 0x3ffffffffffull
242 #define HT_MAX_V7B 0x1ffffffffffffull
243 #define HT_MAX_V8B 0xffffffffffffffull
244 #define HT_MAX_V9B 0x7fffffffffffffffull
245 
246 #define HT_MAX_LEN_VINT32 5
247 #define HT_MAX_LEN_VINT64 10
248 
249 /*
250  * vint encoded length of a 32-bit integer
251  */
252 #define HT_ENCODED_LEN_VI32(_v_) \
253  (_v_ <= HT_MAX_V1B ? 1 : \
254  (_v_ <= HT_MAX_V2B ? 2 : \
255  (_v_ <= HT_MAX_V3B ? 3 : \
256  (_v_ <= HT_MAX_V4B ? 4 : 5))))
257 
258 /*
259  * vint encoded length of a 64-bit integer
260  */
261 #define HT_ENCODED_LEN_VI64(_v_) \
262  (val <= HT_MAX_V1B ? 1 : \
263  (val <= HT_MAX_V2B ? 2 : \
264  (val <= HT_MAX_V3B ? 3 : \
265  (val <= HT_MAX_V4B ? 4 : \
266  (val <= HT_MAX_V5B ? 5 : \
267  (val <= HT_MAX_V6B ? 6 : \
268  (val <= HT_MAX_V7B ? 7 : \
269  (val <= HT_MAX_V8B ? 8 : \
270  (val <= HT_MAX_V9B ? 9 : 10)))))))))
271 
272 /* vint encode helpers */
273 #define HT_ENCODE_VINT0(_op_, _v_, _done_) \
274  if (_v_ <= HT_MAX_V1B) { \
275  *(_op_)++ = (uint8_t)((_v_) & 0x7f); \
276  _done_; \
277  }
278 
279 #define HT_ENCODE_VINT_(_op_, _v_, _done_) \
280  *(_op_)++ = (uint8_t)((_v_) | 0x80); \
281  _v_ >>= 7; \
282  HT_ENCODE_VINT0(_op_, _v_, _done_)
283 
284 #define HT_ENCODE_VINT4(_op_, _v_, _done_) \
285  HT_ENCODE_VINT_(_op_, _v_, _done_) \
286  HT_ENCODE_VINT_(_op_, _v_, _done_) \
287  HT_ENCODE_VINT_(_op_, _v_, _done_) \
288  HT_ENCODE_VINT_(_op_, _v_, _done_)
289 
290 /*
291  * Encode a 32-bit integer in vint format
292  *
293  * @param _op_ - output buffer pointer
294  * @param _v_ - value to encode
295  * @param _done_ - return or break
296  */
297 #define HT_ENCODE_VI32(_op_, _v_, _done_) do { \
298  uint32_t _evtmp32_ = _v_; /* make sure these var names are not the same */ \
299  HT_ENCODE_VINT0(_op_, _evtmp32_, _done_) \
300  HT_ENCODE_VINT4(_op_, _evtmp32_, _done_) \
301  HT_ENCODE_VINT_(_op_, _evtmp32_, _done_) \
302  HT_THROW_UNPOSSIBLE("reach here encoding vint32"); \
303 } while (0)
304 
305 /*
306  * Encode a 64-bit integer in vint format
307  *
308  * @param _op_ - output buffer pointer
309  * @param _v_ - value to encode
310  * @param _done_ - return or break
311  */
312 #define HT_ENCODE_VI64(_op_, _v_, _done_) do { \
313  uint64_t _evtmp64_ = _v_; /* ditto */ \
314  HT_ENCODE_VINT0(_op_, _evtmp64_, _done_) \
315  HT_ENCODE_VINT4(_op_, _evtmp64_, _done_) \
316  HT_ENCODE_VINT4(_op_, _evtmp64_, _done_) \
317  HT_ENCODE_VINT_(_op_, _evtmp64_, _done_) \
318  HT_ENCODE_VINT_(_op_, _evtmp64_, _done_) \
319  HT_THROW_UNPOSSIBLE("reach here encoding vint64"); \
320 } while (0)
321 
322 /* vint decode helpers */
323 #define HT_DECODE_VINT0(_type_, _v_, _ip_, _r_) \
324  uint32_t _shift_ = 0; \
325  HT_DECODE_NEED(_r_, 1); \
326  _v_ = (*(_ip_)++ & 0x7f);
327 
328 #define HT_DECODE_VINT_(_type_, _v_, _ip_, _r_, _done_) \
329  _shift_ += 7; \
330  if ((_ip_)[-1] & 0x80) { \
331  HT_DECODE_NEED(_r_, 1); \
332  _v_ |= ((_type_)(*(_ip_)++ & 0x7f) << _shift_); \
333  } else _done_;
334 
335 #define HT_DECODE_VINT4(_type_, _v_, _ip_, _r_, _done_) \
336  HT_DECODE_VINT_(_type_, _v_, _ip_, _r_, _done_) \
337  HT_DECODE_VINT_(_type_, _v_, _ip_, _r_, _done_) \
338  HT_DECODE_VINT_(_type_, _v_, _ip_, _r_, _done_) \
339  HT_DECODE_VINT_(_type_, _v_, _ip_, _r_, _done_)
340 
341 /*
342  * Decode a 32-bit integer encoded in vint format
343  *
344  * @param _ip_ - input buffer pointer
345  * @param _r_ - varable with remaining bytes
346  * @param _v_ - variable for result
347  * @param _done_ - return _v_ or break
348  */
349 #define HT_DECODE_VI32(_ip_, _r_, _v_, _done_) do { \
350  HT_DECODE_VINT0(uint32_t, _v_, _ip_, _r_) \
351  HT_DECODE_VINT4(uint32_t, _v_, _ip_, _r_, _done_) \
352  HT_DECODE_VINT_(uint32_t, _v_, _ip_, _r_, _done_) \
353  HT_THROW_BAD_VINT("vint32"); \
354 } while (0)
355 
356 /*
357  * Decode a 64-bit integer encoded in vint format
358  *
359  * @param _ip_ - input buffer pointer
360  * @param _r_ - varable with remaining bytes
361  * @param _v_ - variable for result
362  * @param _done_ - return _v_ or break
363  */
364 #define HT_DECODE_VI64(_ip_, _r_, _v_, _done_) do { \
365  HT_DECODE_VINT0(uint64_t, _v_, _ip_, _r_) \
366  HT_DECODE_VINT4(uint64_t, _v_, _ip_, _r_, _done_) \
367  HT_DECODE_VINT4(uint64_t, _v_, _ip_, _r_, _done_) \
368  HT_DECODE_VINT_(uint64_t, _v_, _ip_, _r_, _done_) \
369  HT_DECODE_VINT_(uint64_t, _v_, _ip_, _r_, _done_) \
370  HT_THROW_BAD_VINT("vint64"); \
371 } while (0)
372 
373 
374 /*
375  * Encode a buffer in bytes32 format (i32, data)
376  *
377  * @param _op_ - output buffer pointer
378  * @param _ip_ - input buffer pointer
379  * @param _len_ - input buffer length
380  */
381 #define HT_ENCODE_BYTES32(_op_, _ip_, _len_) do { \
382  HT_ENCODE_I32(_op_, _len_); \
383  memcpy(_op_, _ip_, _len_); \
384  _op_ += _len_; \
385 } while (0)
386 
387 /*
388  * Decode bytes32 (i32, data)
389  *
390  * @param _ip_ - input buffer pointer
391  * @param _r_ - varable with remaining bytes
392  * @param _out_ - variable for output
393  * @param _len_ - variable for result length
394  */
395 #define HT_DECODE_BYTES32(_ip_, _r_, _out_, _len_) do { \
396  uint32_t _tmp_; \
397  HT_DECODE_I32(_ip_, _r_, _tmp_); \
398  HT_DECODE_NEED(_r_, _tmp_); \
399  _out_ = (uint8_t *)(_ip_); \
400  _ip_ += _tmp_; \
401  _len_ = _tmp_; \
402 } while (0)
403 
404 /*
405  * Encode a string buffer in str16 format (i16, data, null)
406  *
407  * @param _op_ - output buffer pointer
408  * @param _s_ - input buffer pointer
409  * @param _len_ - input buffer length
410  */
411 #define HT_ENCODE_STR16(_op_, _s_, _len_) do { \
412  uint16_t _s16tmp_ = _len_; /* just to be cautious */ \
413  HT_ENCODE_I16(_op_, _s16tmp_); /* length */ \
414  if (_s16tmp_ > 0) { \
415  memcpy(_op_, _s_, _s16tmp_); /* data */ \
416  _op_ += len; \
417  } \
418  *(*bufp)++ = 0; /* null */ \
419 } while (0)
420 
421 /*
422  * Decode str16 (i16, data, null)
423  *
424  * @param _ip_ - input buffer pointer
425  * @param _r_ - varable with remaining bytes
426  * @param _s_ - variable for result
427  * @param _len_ - variable for result length
428  */
429 #define HT_DECODE_STR16(_ip_, _r_, _s_, _len_) do { \
430  HT_DECODE_I16(_ip_, _r_, _len_); \
431  _s_ = (char *)(_ip_); \
432  _r_ -= (size_t)(_len_) + 1; \
433  _ip_ += (size_t)(_len_) + 1; \
434 } while (0)
435 
436 
437 /*
438  * Encode in vstr format (vint, data, null)
439  *
440  * @param _op_ - output buffer pointer
441  * @param _s_ - input buffer pointer
442  * @param _len_ - input buffer length
443  */
444 #define HT_ENCODE_VSTR(_op_, _s_, _len_) do { \
445  size_t _vs64tmp_ = _len_; /* ditto */ \
446  HT_ENCODE_VI64(_op_, _vs64tmp_, break); \
447  if (_vs64tmp_) { \
448  memcpy((_op_), _s_, _vs64tmp_); \
449  (_op_) += _vs64tmp_; \
450  } \
451  *(_op_)++ = 0; \
452 } while (0)
453 
454 /*
455  * Decode a vstr (vint, data, null)
456  */
457 #define HT_DECODE_VSTR(_ip_, _r_, _out_, _len_) do { \
458  uint64_t _tmp_; \
459  HT_DECODE_VI64(_ip_, _r_, _tmp_, break); \
460  if (_tmp_ > (uint64_t)(SIZE_MAX)) \
461  HT_THROW_BAD_VSTR("long vstr on 32-bit platform"); \
462  _out_ = (char *)(_ip_); \
463  _len_ = _tmp_++; \
464  HT_DECODE_NEED(_r_, _tmp_); \
465  _ip_ += _tmp_; \
466  if ((_ip_)[-1]) /* should be null */ \
467  HT_THROW_BAD_VSTR("vstr"); \
468 } while (0)
469 
470 
471 #endif /* HT_SERIALIZATION_C_H */
Endian conversion macros.
Error codes, Exception handling, error logging.