mpack_core.c (17159B)
1 #include <string.h> 2 3 #include "mpack_core.h" 4 5 #define UNUSED(p) (void)p; 6 #define ADVANCE(buf, buflen) ((*buflen)--, (unsigned char)*((*buf)++)) 7 #define TLEN(val, range_start) ((mpack_uint32_t)(1 << (val - range_start))) 8 #ifndef MIN 9 # define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) 10 #endif 11 12 static int mpack_rpending(const char **b, size_t *nl, mpack_tokbuf_t *tb); 13 static int mpack_rvalue(mpack_token_type_t t, mpack_uint32_t l, 14 const char **b, size_t *bl, mpack_token_t *tok); 15 static int mpack_rblob(mpack_token_type_t t, mpack_uint32_t l, 16 const char **b, size_t *bl, mpack_token_t *tok); 17 static int mpack_wtoken(const mpack_token_t *tok, char **b, size_t *bl); 18 static int mpack_wpending(char **b, size_t *bl, mpack_tokbuf_t *tb); 19 static int mpack_wpint(char **b, size_t *bl, mpack_value_t v); 20 static int mpack_wnint(char **b, size_t *bl, mpack_value_t v); 21 static int mpack_wfloat(char **b, size_t *bl, const mpack_token_t *v); 22 static int mpack_wstr(char **buf, size_t *buflen, mpack_uint32_t len); 23 static int mpack_wbin(char **buf, size_t *buflen, mpack_uint32_t len); 24 static int mpack_wext(char **buf, size_t *buflen, int type, 25 mpack_uint32_t len); 26 static int mpack_warray(char **buf, size_t *buflen, mpack_uint32_t len); 27 static int mpack_wmap(char **buf, size_t *buflen, mpack_uint32_t len); 28 static int mpack_w1(char **b, size_t *bl, mpack_uint32_t v); 29 static int mpack_w2(char **b, size_t *bl, mpack_uint32_t v); 30 static int mpack_w4(char **b, size_t *bl, mpack_uint32_t v); 31 static mpack_value_t mpack_byte(unsigned char b); 32 static int mpack_value(mpack_token_type_t t, mpack_uint32_t l, 33 mpack_value_t v, mpack_token_t *tok); 34 static int mpack_blob(mpack_token_type_t t, mpack_uint32_t l, int et, 35 mpack_token_t *tok); 36 37 MPACK_API void mpack_tokbuf_init(mpack_tokbuf_t *tokbuf) 38 { 39 tokbuf->ppos = 0; 40 tokbuf->plen = 0; 41 tokbuf->passthrough = 0; 42 } 43 44 MPACK_API int mpack_read(mpack_tokbuf_t *tokbuf, const char **buf, 45 size_t *buflen, mpack_token_t *tok) 46 { 47 int status; 48 size_t initial_ppos, ptrlen, advanced; 49 const char *ptr, *ptr_save; 50 assert(*buf); 51 if (*buflen == 0) { 52 return MPACK_EOF; 53 } 54 55 if (tokbuf->passthrough) { 56 /* pass data from str/bin/ext directly as a MPACK_TOKEN_CHUNK, adjusting 57 * *buf and *buflen */ 58 tok->type = MPACK_TOKEN_CHUNK; 59 tok->data.chunk_ptr = *buf; 60 tok->length = MIN((mpack_uint32_t)*buflen, tokbuf->passthrough); 61 tokbuf->passthrough -= tok->length; 62 *buf += tok->length; 63 *buflen -= tok->length; 64 goto done; 65 } 66 67 initial_ppos = tokbuf->ppos; 68 69 if (tokbuf->plen) { 70 if (!mpack_rpending(buf, buflen, tokbuf)) { 71 return MPACK_EOF; 72 } 73 ptr = tokbuf->pending; 74 ptrlen = tokbuf->ppos; 75 } else { 76 ptr = *buf; 77 ptrlen = *buflen; 78 } 79 80 ptr_save = ptr; 81 82 if ((status = mpack_rtoken(&ptr, &ptrlen, tok))) { 83 if (status != MPACK_EOF) return MPACK_ERROR; 84 /* need more data */ 85 assert(!tokbuf->plen); 86 /* read the remainder of *buf to tokbuf->pending so it can be parsed 87 * later with more data. only required when tokbuf->plen == 0 or else 88 * it would have been done already. */ 89 tokbuf->plen = tok->length + 1; 90 assert(tokbuf->plen <= sizeof(tokbuf->pending)); 91 tokbuf->ppos = 0; 92 status = mpack_rpending(buf, buflen, tokbuf); 93 assert(!status); 94 return MPACK_EOF; 95 } 96 97 advanced = (size_t)(ptr - ptr_save) - initial_ppos; 98 tokbuf->plen = tokbuf->ppos = 0; 99 *buflen -= advanced; 100 *buf += advanced; 101 102 if (tok->type > MPACK_TOKEN_MAP) { 103 tokbuf->passthrough = tok->length; 104 } 105 106 done: 107 return MPACK_OK; 108 } 109 110 MPACK_API int mpack_write(mpack_tokbuf_t *tokbuf, char **buf, size_t *buflen, 111 const mpack_token_t *t) 112 { 113 int status; 114 char *ptr; 115 size_t ptrlen; 116 mpack_token_t tok = tokbuf->plen ? tokbuf->pending_tok : *t; 117 assert(*buf && *buflen); 118 119 if (tok.type == MPACK_TOKEN_CHUNK) { 120 size_t written, pending, count; 121 if (!tokbuf->plen) tokbuf->ppos = 0; 122 written = tokbuf->ppos; 123 pending = tok.length - written; 124 count = MIN(pending, *buflen); 125 memcpy(*buf, tok.data.chunk_ptr + written, count); 126 *buf += count; 127 *buflen -= count; 128 tokbuf->ppos += count; 129 tokbuf->plen = count == pending ? 0 : tok.length; 130 if (count == pending) { 131 return MPACK_OK; 132 } else { 133 tokbuf->pending_tok = tok; 134 return MPACK_EOF; 135 } 136 } 137 138 if (tokbuf->plen) return mpack_wpending(buf, buflen, tokbuf); 139 140 if (*buflen < MPACK_MAX_TOKEN_LEN) { 141 ptr = tokbuf->pending; 142 ptrlen = sizeof(tokbuf->pending); 143 } else { 144 ptr = *buf; 145 ptrlen = *buflen; 146 } 147 148 if ((status = mpack_wtoken(&tok, &ptr, &ptrlen))) return status; 149 150 if (*buflen < MPACK_MAX_TOKEN_LEN) { 151 size_t toklen = sizeof(tokbuf->pending) - ptrlen; 152 size_t write_cnt = MIN(toklen, *buflen); 153 memcpy(*buf, tokbuf->pending, write_cnt); 154 *buf += write_cnt; 155 *buflen -= write_cnt; 156 if (write_cnt < toklen) { 157 assert(!*buflen); 158 tokbuf->plen = toklen; 159 tokbuf->ppos = write_cnt; 160 tokbuf->pending_tok = tok; 161 return MPACK_EOF; 162 } 163 } else { 164 *buflen -= (size_t)(ptr - *buf); 165 *buf = ptr; 166 } 167 168 return MPACK_OK; 169 } 170 171 int mpack_rtoken(const char **buf, size_t *buflen, mpack_token_t *tok) 172 { 173 if (*buflen == 0) { 174 return MPACK_EOF; 175 } 176 unsigned char t = ADVANCE(buf, buflen); 177 if (t < 0x80) { 178 /* positive fixint */ 179 return mpack_value(MPACK_TOKEN_UINT, 1, mpack_byte(t), tok); 180 } else if (t < 0x90) { 181 /* fixmap */ 182 return mpack_blob(MPACK_TOKEN_MAP, t & 0xf, 0, tok); 183 } else if (t < 0xa0) { 184 /* fixarray */ 185 return mpack_blob(MPACK_TOKEN_ARRAY, t & 0xf, 0, tok); 186 } else if (t < 0xc0) { 187 /* fixstr */ 188 return mpack_blob(MPACK_TOKEN_STR, t & 0x1f, 0, tok); 189 } else if (t < 0xe0) { 190 switch (t) { 191 case 0xc0: /* nil */ 192 return mpack_value(MPACK_TOKEN_NIL, 0, mpack_byte(0), tok); 193 case 0xc2: /* false */ 194 return mpack_value(MPACK_TOKEN_BOOLEAN, 1, mpack_byte(0), tok); 195 case 0xc3: /* true */ 196 return mpack_value(MPACK_TOKEN_BOOLEAN, 1, mpack_byte(1), tok); 197 case 0xc4: /* bin 8 */ 198 case 0xc5: /* bin 16 */ 199 case 0xc6: /* bin 32 */ 200 return mpack_rblob(MPACK_TOKEN_BIN, TLEN(t, 0xc4), buf, buflen, tok); 201 case 0xc7: /* ext 8 */ 202 case 0xc8: /* ext 16 */ 203 case 0xc9: /* ext 32 */ 204 return mpack_rblob(MPACK_TOKEN_EXT, TLEN(t, 0xc7), buf, buflen, tok); 205 case 0xca: /* float 32 */ 206 case 0xcb: /* float 64 */ 207 return mpack_rvalue(MPACK_TOKEN_FLOAT, TLEN(t, 0xc8), buf, buflen, tok); 208 case 0xcc: /* uint 8 */ 209 case 0xcd: /* uint 16 */ 210 case 0xce: /* uint 32 */ 211 case 0xcf: /* uint 64 */ 212 return mpack_rvalue(MPACK_TOKEN_UINT, TLEN(t, 0xcc), buf, buflen, tok); 213 case 0xd0: /* int 8 */ 214 case 0xd1: /* int 16 */ 215 case 0xd2: /* int 32 */ 216 case 0xd3: /* int 64 */ 217 return mpack_rvalue(MPACK_TOKEN_SINT, TLEN(t, 0xd0), buf, buflen, tok); 218 case 0xd4: /* fixext 1 */ 219 case 0xd5: /* fixext 2 */ 220 case 0xd6: /* fixext 4 */ 221 case 0xd7: /* fixext 8 */ 222 case 0xd8: /* fixext 16 */ 223 if (*buflen == 0) { 224 /* require only one extra byte for the type code */ 225 tok->length = 1; 226 return MPACK_EOF; 227 } 228 tok->length = TLEN(t, 0xd4); 229 tok->type = MPACK_TOKEN_EXT; 230 tok->data.ext_type = ADVANCE(buf, buflen); 231 return MPACK_OK; 232 case 0xd9: /* str 8 */ 233 case 0xda: /* str 16 */ 234 case 0xdb: /* str 32 */ 235 return mpack_rblob(MPACK_TOKEN_STR, TLEN(t, 0xd9), buf, buflen, tok); 236 case 0xdc: /* array 16 */ 237 case 0xdd: /* array 32 */ 238 return mpack_rblob(MPACK_TOKEN_ARRAY, TLEN(t, 0xdb), buf, buflen, tok); 239 case 0xde: /* map 16 */ 240 case 0xdf: /* map 32 */ 241 return mpack_rblob(MPACK_TOKEN_MAP, TLEN(t, 0xdd), buf, buflen, tok); 242 default: 243 return MPACK_ERROR; 244 } 245 } else { 246 /* negative fixint */ 247 return mpack_value(MPACK_TOKEN_SINT, 1, mpack_byte(t), tok); 248 } 249 } 250 251 static int mpack_rpending(const char **buf, size_t *buflen, 252 mpack_tokbuf_t *state) 253 { 254 size_t count; 255 assert(state->ppos < state->plen); 256 count = MIN(state->plen - state->ppos, *buflen); 257 memcpy(state->pending + state->ppos, *buf, count); 258 state->ppos += count; 259 if (state->ppos < state->plen) { 260 /* consume buffer since no token will be parsed yet. */ 261 *buf += *buflen; 262 *buflen = 0; 263 return 0; 264 } 265 return 1; 266 } 267 268 static int mpack_rvalue(mpack_token_type_t type, mpack_uint32_t remaining, 269 const char **buf, size_t *buflen, mpack_token_t *tok) 270 { 271 if (*buflen < remaining) { 272 tok->length = remaining; 273 return MPACK_EOF; 274 } 275 276 mpack_value(type, remaining, mpack_byte(0), tok); 277 278 while (remaining) { 279 mpack_uint32_t byte = ADVANCE(buf, buflen), byte_idx, byte_shift; 280 byte_idx = (mpack_uint32_t)--remaining; 281 byte_shift = (byte_idx % 4) * 8; 282 tok->data.value.lo |= byte << byte_shift; 283 if (remaining == 4) { 284 /* unpacked the first half of a 8-byte value, shift what was parsed to the 285 * "hi" field and reset "lo" for the trailing 4 bytes. */ 286 tok->data.value.hi = tok->data.value.lo; 287 tok->data.value.lo = 0; 288 } 289 } 290 291 if (type == MPACK_TOKEN_SINT) { 292 mpack_uint32_t hi = tok->data.value.hi; 293 mpack_uint32_t lo = tok->data.value.lo; 294 mpack_uint32_t msb = (tok->length == 8 && hi >> 31) || 295 (tok->length == 4 && lo >> 31) || 296 (tok->length == 2 && lo >> 15) || 297 (tok->length == 1 && lo >> 7); 298 if (!msb) { 299 tok->type = MPACK_TOKEN_UINT; 300 } 301 } 302 303 return MPACK_OK; 304 } 305 306 static int mpack_rblob(mpack_token_type_t type, mpack_uint32_t tlen, 307 const char **buf, size_t *buflen, mpack_token_t *tok) 308 { 309 mpack_token_t l; 310 mpack_uint32_t required = tlen + (type == MPACK_TOKEN_EXT ? 1 : 0); 311 312 if (*buflen < required) { 313 tok->length = required; 314 return MPACK_EOF; 315 } 316 317 l.data.value.lo = 0; 318 mpack_rvalue(MPACK_TOKEN_UINT, tlen, buf, buflen, &l); 319 tok->type = type; 320 tok->length = l.data.value.lo; 321 322 if (type == MPACK_TOKEN_EXT) { 323 tok->data.ext_type = ADVANCE(buf, buflen); 324 } 325 326 return MPACK_OK; 327 } 328 329 static int mpack_wtoken(const mpack_token_t *tok, char **buf, 330 size_t *buflen) 331 { 332 switch (tok->type) { 333 case MPACK_TOKEN_NIL: 334 return mpack_w1(buf, buflen, 0xc0); 335 case MPACK_TOKEN_BOOLEAN: 336 return mpack_w1(buf, buflen, tok->data.value.lo ? 0xc3 : 0xc2); 337 case MPACK_TOKEN_UINT: 338 return mpack_wpint(buf, buflen, tok->data.value); 339 case MPACK_TOKEN_SINT: 340 return mpack_wnint(buf, buflen, tok->data.value); 341 case MPACK_TOKEN_FLOAT: 342 return mpack_wfloat(buf, buflen, tok); 343 case MPACK_TOKEN_BIN: 344 return mpack_wbin(buf, buflen, tok->length); 345 case MPACK_TOKEN_STR: 346 return mpack_wstr(buf, buflen, tok->length); 347 case MPACK_TOKEN_EXT: 348 return mpack_wext(buf, buflen, tok->data.ext_type, tok->length); 349 case MPACK_TOKEN_ARRAY: 350 return mpack_warray(buf, buflen, tok->length); 351 case MPACK_TOKEN_MAP: 352 return mpack_wmap(buf, buflen, tok->length); 353 default: 354 return MPACK_ERROR; 355 } 356 } 357 358 static int mpack_wpending(char **buf, size_t *buflen, mpack_tokbuf_t *state) 359 { 360 size_t count; 361 assert(state->ppos < state->plen); 362 count = MIN(state->plen - state->ppos, *buflen); 363 memcpy(*buf, state->pending + state->ppos, count); 364 state->ppos += count; 365 *buf += count; 366 *buflen -= count; 367 if (state->ppos == state->plen) { 368 state->plen = 0; 369 return MPACK_OK; 370 } 371 return MPACK_EOF; 372 } 373 374 static int mpack_wpint(char **buf, size_t *buflen, mpack_value_t val) 375 { 376 mpack_uint32_t hi = val.hi; 377 mpack_uint32_t lo = val.lo; 378 379 if (hi) { 380 /* uint 64 */ 381 return mpack_w1(buf, buflen, 0xcf) || 382 mpack_w4(buf, buflen, hi) || 383 mpack_w4(buf, buflen, lo); 384 } else if (lo > 0xffff) { 385 /* uint 32 */ 386 return mpack_w1(buf, buflen, 0xce) || 387 mpack_w4(buf, buflen, lo); 388 } else if (lo > 0xff) { 389 /* uint 16 */ 390 return mpack_w1(buf, buflen, 0xcd) || 391 mpack_w2(buf, buflen, lo); 392 } else if (lo > 0x7f) { 393 /* uint 8 */ 394 return mpack_w1(buf, buflen, 0xcc) || 395 mpack_w1(buf, buflen, lo); 396 } else { 397 return mpack_w1(buf, buflen, lo); 398 } 399 } 400 401 static int mpack_wnint(char **buf, size_t *buflen, mpack_value_t val) 402 { 403 mpack_uint32_t hi = val.hi; 404 mpack_uint32_t lo = val.lo; 405 406 if (lo < 0x80000000) { 407 /* int 64 */ 408 return mpack_w1(buf, buflen, 0xd3) || 409 mpack_w4(buf, buflen, hi) || 410 mpack_w4(buf, buflen, lo); 411 } else if (lo < 0xffff7fff) { 412 /* int 32 */ 413 return mpack_w1(buf, buflen, 0xd2) || 414 mpack_w4(buf, buflen, lo); 415 } else if (lo < 0xffffff7f) { 416 /* int 16 */ 417 return mpack_w1(buf, buflen, 0xd1) || 418 mpack_w2(buf, buflen, lo); 419 } else if (lo < 0xffffffe0) { 420 /* int 8 */ 421 return mpack_w1(buf, buflen, 0xd0) || 422 mpack_w1(buf, buflen, lo); 423 } else { 424 /* negative fixint */ 425 return mpack_w1(buf, buflen, (mpack_uint32_t)(0x100 + lo)); 426 } 427 } 428 429 static int mpack_wfloat(char **buf, size_t *buflen, 430 const mpack_token_t *tok) 431 { 432 if (tok->length == 4) { 433 return mpack_w1(buf, buflen, 0xca) || 434 mpack_w4(buf, buflen, tok->data.value.lo); 435 } else if (tok->length == 8) { 436 return mpack_w1(buf, buflen, 0xcb) || 437 mpack_w4(buf, buflen, tok->data.value.hi) || 438 mpack_w4(buf, buflen, tok->data.value.lo); 439 } else { 440 return MPACK_ERROR; 441 } 442 } 443 444 static int mpack_wstr(char **buf, size_t *buflen, mpack_uint32_t len) 445 { 446 if (len < 0x20) { 447 return mpack_w1(buf, buflen, 0xa0 | len); 448 } else if (len < 0x100) { 449 return mpack_w1(buf, buflen, 0xd9) || 450 mpack_w1(buf, buflen, len); 451 } else if (len < 0x10000) { 452 return mpack_w1(buf, buflen, 0xda) || 453 mpack_w2(buf, buflen, len); 454 } else { 455 return mpack_w1(buf, buflen, 0xdb) || 456 mpack_w4(buf, buflen, len); 457 } 458 } 459 460 static int mpack_wbin(char **buf, size_t *buflen, mpack_uint32_t len) 461 { 462 if (len < 0x100) { 463 return mpack_w1(buf, buflen, 0xc4) || 464 mpack_w1(buf, buflen, len); 465 } else if (len < 0x10000) { 466 return mpack_w1(buf, buflen, 0xc5) || 467 mpack_w2(buf, buflen, len); 468 } else { 469 return mpack_w1(buf, buflen, 0xc6) || 470 mpack_w4(buf, buflen, len); 471 } 472 } 473 474 static int mpack_wext(char **buf, size_t *buflen, int type, 475 mpack_uint32_t len) 476 { 477 mpack_uint32_t t; 478 assert(type >= 0 && type < 0x80); 479 t = (mpack_uint32_t)type; 480 switch (len) { 481 case 1: mpack_w1(buf, buflen, 0xd4); return mpack_w1(buf, buflen, t); 482 case 2: mpack_w1(buf, buflen, 0xd5); return mpack_w1(buf, buflen, t); 483 case 4: mpack_w1(buf, buflen, 0xd6); return mpack_w1(buf, buflen, t); 484 case 8: mpack_w1(buf, buflen, 0xd7); return mpack_w1(buf, buflen, t); 485 case 16: mpack_w1(buf, buflen, 0xd8); return mpack_w1(buf, buflen, t); 486 default: 487 if (len < 0x100) { 488 return mpack_w1(buf, buflen, 0xc7) || 489 mpack_w1(buf, buflen, len) || 490 mpack_w1(buf, buflen, t); 491 } else if (len < 0x10000) { 492 return mpack_w1(buf, buflen, 0xc8) || 493 mpack_w2(buf, buflen, len) || 494 mpack_w1(buf, buflen, t); 495 } else { 496 return mpack_w1(buf, buflen, 0xc9) || 497 mpack_w4(buf, buflen, len) || 498 mpack_w1(buf, buflen, t); 499 } 500 } 501 } 502 503 static int mpack_warray(char **buf, size_t *buflen, mpack_uint32_t len) 504 { 505 if (len < 0x10) { 506 return mpack_w1(buf, buflen, 0x90 | len); 507 } else if (len < 0x10000) { 508 return mpack_w1(buf, buflen, 0xdc) || 509 mpack_w2(buf, buflen, len); 510 } else { 511 return mpack_w1(buf, buflen, 0xdd) || 512 mpack_w4(buf, buflen, len); 513 } 514 } 515 516 static int mpack_wmap(char **buf, size_t *buflen, mpack_uint32_t len) 517 { 518 if (len < 0x10) { 519 return mpack_w1(buf, buflen, 0x80 | len); 520 } else if (len < 0x10000) { 521 return mpack_w1(buf, buflen, 0xde) || 522 mpack_w2(buf, buflen, len); 523 } else { 524 return mpack_w1(buf, buflen, 0xdf) || 525 mpack_w4(buf, buflen, len); 526 } 527 } 528 529 static int mpack_w1(char **b, size_t *bl, mpack_uint32_t v) 530 { 531 (*bl)--; 532 *(*b)++ = (char)(v & 0xff); 533 return MPACK_OK; 534 } 535 536 static int mpack_w2(char **b, size_t *bl, mpack_uint32_t v) 537 { 538 *bl -= 2; 539 *(*b)++ = (char)((v >> 8) & 0xff); 540 *(*b)++ = (char)(v & 0xff); 541 return MPACK_OK; 542 } 543 544 static int mpack_w4(char **b, size_t *bl, mpack_uint32_t v) 545 { 546 *bl -= 4; 547 *(*b)++ = (char)((v >> 24) & 0xff); 548 *(*b)++ = (char)((v >> 16) & 0xff); 549 *(*b)++ = (char)((v >> 8) & 0xff); 550 *(*b)++ = (char)(v & 0xff); 551 return MPACK_OK; 552 } 553 554 static int mpack_value(mpack_token_type_t type, mpack_uint32_t length, 555 mpack_value_t value, mpack_token_t *tok) 556 { 557 tok->type = type; 558 tok->length = length; 559 tok->data.value = value; 560 return MPACK_OK; 561 } 562 563 static int mpack_blob(mpack_token_type_t type, mpack_uint32_t length, 564 int ext_type, mpack_token_t *tok) 565 { 566 tok->type = type; 567 tok->length = length; 568 tok->data.ext_type = ext_type; 569 return MPACK_OK; 570 } 571 572 static mpack_value_t mpack_byte(unsigned char byte) 573 { 574 mpack_value_t rv; 575 rv.lo = byte; 576 rv.hi = 0; 577 return rv; 578 }