1 #include <cassert>
2 #include <cstdint>
3 #include <cstring>
4 #include <functional>
5 #include <string>
6 
7 #include "msgpack.h"
8 
9 namespace msgpack {
10 
internal_error()11 [[noreturn]] void internal_error() {
12   printf("internal error\n");
13   exit(1);
14 }
15 
type_name(type ty)16 const char *type_name(type ty) {
17   switch (ty) {
18 #define X(NAME, WIDTH, PAYLOAD, LOWER, UPPER)                                  \
19   case NAME:                                                                   \
20     return #NAME;
21 #include "msgpack.def"
22 #undef X
23   }
24   internal_error();
25 }
26 
bytes_used_fixed(msgpack::type ty)27 unsigned bytes_used_fixed(msgpack::type ty) {
28   using namespace msgpack;
29   switch (ty) {
30 #define X(NAME, WIDTH, PAYLOAD, LOWER, UPPER)                                  \
31   case NAME:                                                                   \
32     return WIDTH;
33 #include "msgpack.def"
34 #undef X
35   }
36   internal_error();
37 }
38 
parse_type(unsigned char x)39 msgpack::type parse_type(unsigned char x) {
40 
41 #define X(NAME, WIDTH, PAYLOAD, LOWER, UPPER)                                  \
42   if (x >= LOWER && x <= UPPER) {                                              \
43     return NAME;                                                               \
44   } else
45 #include "msgpack.def"
46 #undef X
47   { internal_error(); }
48 }
49 
bitcast(T x)50 template <typename T, typename R> R bitcast(T x) {
51   static_assert(sizeof(T) == sizeof(R), "");
52   R tmp;
53   memcpy(&tmp, &x, sizeof(T));
54   return tmp;
55 }
56 template int64_t bitcast<uint64_t, int64_t>(uint64_t);
57 } // namespace msgpack
58 
59 // Helper functions for reading additional payload from the header
60 // Depending on the type, this can be a number of bytes, elements,
61 // key-value pairs or an embedded integer.
62 // Each takes a pointer to the start of the header and returns a uint64_t
63 
64 namespace {
65 namespace payload {
read_zero(const unsigned char *)66 uint64_t read_zero(const unsigned char *) { return 0; }
67 
68 // Read the first byte and zero/sign extend it
read_embedded_u8(const unsigned char * start)69 uint64_t read_embedded_u8(const unsigned char *start) { return start[0]; }
read_embedded_s8(const unsigned char * start)70 uint64_t read_embedded_s8(const unsigned char *start) {
71   int64_t res = msgpack::bitcast<uint8_t, int8_t>(start[0]);
72   return msgpack::bitcast<int64_t, uint64_t>(res);
73 }
74 
75 // Read a masked part of the first byte
read_via_mask_0x1(const unsigned char * start)76 uint64_t read_via_mask_0x1(const unsigned char *start) { return *start & 0x1u; }
read_via_mask_0xf(const unsigned char * start)77 uint64_t read_via_mask_0xf(const unsigned char *start) { return *start & 0xfu; }
read_via_mask_0x1f(const unsigned char * start)78 uint64_t read_via_mask_0x1f(const unsigned char *start) {
79   return *start & 0x1fu;
80 }
81 
82 // Read 1/2/4/8 bytes immediately following the type byte and zero/sign extend
83 // Big endian format.
read_size_field_u8(const unsigned char * from)84 uint64_t read_size_field_u8(const unsigned char *from) {
85   from++;
86   return from[0];
87 }
88 
89 // TODO: detect whether host is little endian or not, and whether the intrinsic
90 // is available. And probably use the builtin to test the diy
91 const bool use_bswap = false;
92 
read_size_field_u16(const unsigned char * from)93 uint64_t read_size_field_u16(const unsigned char *from) {
94   from++;
95   if (use_bswap) {
96     uint16_t b;
97     memcpy(&b, from, 2);
98     return __builtin_bswap16(b);
99   } else {
100     return (from[0] << 8u) | from[1];
101   }
102 }
read_size_field_u32(const unsigned char * from)103 uint64_t read_size_field_u32(const unsigned char *from) {
104   from++;
105   if (use_bswap) {
106     uint32_t b;
107     memcpy(&b, from, 4);
108     return __builtin_bswap32(b);
109   } else {
110     return (from[0] << 24u) | (from[1] << 16u) | (from[2] << 8u) |
111            (from[3] << 0u);
112   }
113 }
read_size_field_u64(const unsigned char * from)114 uint64_t read_size_field_u64(const unsigned char *from) {
115   from++;
116   if (use_bswap) {
117     uint64_t b;
118     memcpy(&b, from, 8);
119     return __builtin_bswap64(b);
120   } else {
121     return ((uint64_t)from[0] << 56u) | ((uint64_t)from[1] << 48u) |
122            ((uint64_t)from[2] << 40u) | ((uint64_t)from[3] << 32u) |
123            (from[4] << 24u) | (from[5] << 16u) | (from[6] << 8u) |
124            (from[7] << 0u);
125   }
126 }
127 
read_size_field_s8(const unsigned char * from)128 uint64_t read_size_field_s8(const unsigned char *from) {
129   uint8_t u = read_size_field_u8(from);
130   int64_t res = msgpack::bitcast<uint8_t, int8_t>(u);
131   return msgpack::bitcast<int64_t, uint64_t>(res);
132 }
read_size_field_s16(const unsigned char * from)133 uint64_t read_size_field_s16(const unsigned char *from) {
134   uint16_t u = read_size_field_u16(from);
135   int64_t res = msgpack::bitcast<uint16_t, int16_t>(u);
136   return msgpack::bitcast<int64_t, uint64_t>(res);
137 }
read_size_field_s32(const unsigned char * from)138 uint64_t read_size_field_s32(const unsigned char *from) {
139   uint32_t u = read_size_field_u32(from);
140   int64_t res = msgpack::bitcast<uint32_t, int32_t>(u);
141   return msgpack::bitcast<int64_t, uint64_t>(res);
142 }
read_size_field_s64(const unsigned char * from)143 uint64_t read_size_field_s64(const unsigned char *from) {
144   uint64_t u = read_size_field_u64(from);
145   int64_t res = msgpack::bitcast<uint64_t, int64_t>(u);
146   return msgpack::bitcast<int64_t, uint64_t>(res);
147 }
148 } // namespace payload
149 } // namespace
150 
151 namespace msgpack {
152 
payload_info(msgpack::type ty)153 payload_info_t payload_info(msgpack::type ty) {
154   using namespace msgpack;
155   switch (ty) {
156 #define X(NAME, WIDTH, PAYLOAD, LOWER, UPPER)                                  \
157   case NAME:                                                                   \
158     return payload::PAYLOAD;
159 #include "msgpack.def"
160 #undef X
161   }
162   internal_error();
163 }
164 
165 } // namespace msgpack
166 
skip_next_message(const unsigned char * start,const unsigned char * end)167 const unsigned char *msgpack::skip_next_message(const unsigned char *start,
168                                                 const unsigned char *end) {
169   class f : public functors_defaults<f> {};
170   return handle_msgpack({start, end}, f());
171 }
172 
173 namespace msgpack {
message_is_string(byte_range bytes,const char * needle)174 bool message_is_string(byte_range bytes, const char *needle) {
175   bool matched = false;
176   size_t needleN = strlen(needle);
177 
178   foronly_string(bytes, [=, &matched](size_t N, const unsigned char *str) {
179     if (N == needleN) {
180       if (memcmp(needle, str, N) == 0) {
181         matched = true;
182       }
183     }
184   });
185   return matched;
186 }
187 
dump(byte_range bytes)188 void dump(byte_range bytes) {
189   struct inner : functors_defaults<inner> {
190     inner(unsigned indent) : indent(indent) {}
191     const unsigned by = 2;
192     unsigned indent = 0;
193 
194     void handle_string(size_t N, const unsigned char *bytes) {
195       char *tmp = (char *)malloc(N + 1);
196       memcpy(tmp, bytes, N);
197       tmp[N] = '\0';
198       printf("\"%s\"", tmp);
199       free(tmp);
200     }
201 
202     void handle_signed(int64_t x) { printf("%ld", x); }
203     void handle_unsigned(uint64_t x) { printf("%lu", x); }
204 
205     const unsigned char *handle_array(uint64_t N, byte_range bytes) {
206       printf("\n%*s[\n", indent, "");
207       indent += by;
208 
209       for (uint64_t i = 0; i < N; i++) {
210         indent += by;
211         printf("%*s", indent, "");
212         const unsigned char *next = handle_msgpack<inner>(bytes, {indent});
213         printf(",\n");
214         indent -= by;
215         bytes.start = next;
216         if (!next) {
217           break;
218         }
219       }
220       indent -= by;
221       printf("%*s]", indent, "");
222 
223       return bytes.start;
224     }
225 
226     const unsigned char *handle_map(uint64_t N, byte_range bytes) {
227       printf("\n%*s{\n", indent, "");
228       indent += by;
229 
230       for (uint64_t i = 0; i < 2 * N; i += 2) {
231         const unsigned char *start_key = bytes.start;
232         printf("%*s", indent, "");
233         const unsigned char *end_key =
234             handle_msgpack<inner>({start_key, bytes.end}, {indent});
235         if (!end_key) {
236           break;
237         }
238 
239         printf(" : ");
240 
241         const unsigned char *start_value = end_key;
242         const unsigned char *end_value =
243             handle_msgpack<inner>({start_value, bytes.end}, {indent});
244 
245         if (!end_value) {
246           break;
247         }
248 
249         printf(",\n");
250         bytes.start = end_value;
251       }
252 
253       indent -= by;
254       printf("%*s}", indent, "");
255 
256       return bytes.start;
257     }
258   };
259 
260   handle_msgpack<inner>(bytes, {0});
261   printf("\n");
262 }
263 
264 } // namespace msgpack
265