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 11 [[noreturn]] void internal_error() { 12 printf("internal error\n"); 13 exit(1); 14 } 15 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 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 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 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 { 66 uint64_t read_zero(const unsigned char *) { return 0; } 67 68 // Read the first byte and zero/sign extend it 69 uint64_t read_embedded_u8(const unsigned char *start) { return start[0]; } 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 76 uint64_t read_via_mask_0x1(const unsigned char *start) { return *start & 0x1u; } 77 uint64_t read_via_mask_0xf(const unsigned char *start) { return *start & 0xfu; } 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. 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 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 } 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 } 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 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 } 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 } 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 } 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 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 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 { 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 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