| 374 | #define EOS 0x3fffffff |
| 375 | |
| 376 | int64_t |
| 377 | huffman_decode(char *dst_start, const uint8_t *src, uint32_t src_len) |
| 378 | { |
| 379 | char *dst_end = dst_start; |
| 380 | uint8_t shift = 7; |
| 381 | Node *current = HUFFMAN_TREE_ROOT; |
| 382 | int nbits = 0; |
| 383 | uint32_t curr_bits = 0; |
| 384 | |
| 385 | while (src_len) { |
| 386 | if (nbits > 0) { |
| 387 | curr_bits <<= 1; |
| 388 | } |
| 389 | if (*src & (1 << shift)) { |
| 390 | curr_bits |= 1; |
| 391 | current = current->right; |
| 392 | } else { |
| 393 | current = current->left; |
| 394 | } |
| 395 | ++nbits; |
| 396 | |
| 397 | if (current->leaf_node == true) { |
| 398 | if (curr_bits == EOS) { |
| 399 | return -1; |
| 400 | } |
| 401 | nbits = 0; |
| 402 | curr_bits = 0; |
| 403 | *dst_end = current->ascii_code; |
| 404 | ++dst_end; |
| 405 | current = HUFFMAN_TREE_ROOT; |
| 406 | } |
| 407 | |
| 408 | if (shift) { |
| 409 | --shift; |
| 410 | } else { |
| 411 | shift = 7; |
| 412 | ++src; |
| 413 | --src_len; |
| 414 | } |
| 415 | |
| 416 | if (nbits > MAX_HUFFMAN_CODE_LEN) { |
| 417 | return -1; |
| 418 | } |
| 419 | } |
| 420 | |
| 421 | if (nbits > 7) { |
| 422 | return -1; |
| 423 | } |
| 424 | |
| 425 | // Padding bits must be a prefix of EOS |
| 426 | uint8_t mask = (1 << nbits) - 1; |
| 427 | if ((mask & curr_bits) != mask) { |
| 428 | return -1; |
| 429 | } |
| 430 | |
| 431 | return dst_end - dst_start; |
| 432 | } |
| 433 |
no outgoing calls