| #include <stdlib.h> |
| #include <string.h> |
| |
| static bool is_big_endian(void) |
| { |
| union |
| { |
| uint32_t i; |
| char c[4]; |
| } bint = {0x01020304}; |
| |
| return bint.c[0] == 1; |
| } |
| |
| /* Decode an unsigned int LEB128 at buf into r, returning the nr of bytes read. |
| */ |
| inline size_t decode_uint_leb(const uint8_t* buf, const uint8_t* buf_end, uint64_t* r) |
| { |
| const uint8_t* p = buf; |
| uint8_t shift = 0; |
| uint64_t result = 0; |
| uint8_t byte; |
| |
| do |
| { |
| if (p >= buf_end) |
| { |
| return 0; |
| } |
| byte = *p++; |
| result |= ((uint64_t)(byte & 0x7f)) << shift; |
| shift += 7; |
| } while ((byte & 0x80) != 0); |
| *r = result; |
| return p - buf; |
| } |
| |
| /* Decodes a string |
| */ |
| inline uint64_t decode_string(uint64_t str_len, |
| const uint8_t* buf, |
| const uint8_t* buf_end, |
| char* char_buf) |
| { |
| // Return zero bytes read on buffer overflow |
| if (buf_end < buf + str_len) |
| { |
| return 0; |
| } |
| const uint8_t* p = buf; |
| for (int i = 0; i < str_len; i++) |
| { |
| char_buf[i] = *p++; |
| } |
| // Add the null terminator |
| char_buf[str_len] = '\0'; |
| return str_len; |
| } |
| |
| /* Decodes a float (4 bytes) |
| */ |
| inline size_t decode_float(const uint8_t* buf, const uint8_t* buf_end, float* r) |
| { |
| // Return zero bytes read on buffer overflow |
| if (buf_end - buf < (unsigned)sizeof(float)) |
| { |
| return 0; |
| } |
| if (is_big_endian()) |
| { |
| uint8_t inverted[4] = {buf[3], buf[2], buf[1], buf[0]}; |
| memcpy(r, inverted, sizeof(float)); |
| } |
| else |
| { |
| memcpy(r, buf, sizeof(float)); |
| } |
| return sizeof(float); |
| } |
| |
| /* Decodes a single byte |
| */ |
| inline size_t decode_uint_8(const uint8_t* buf, const uint8_t* buf_end, uint8_t* r) |
| { |
| // Return zero bytes read on buffer overflow |
| if (buf_end - buf < (unsigned)sizeof(uint8_t)) |
| { |
| return 0; |
| } |
| memcpy(r, buf, sizeof(uint8_t)); |
| return sizeof(uint8_t); |
| } |
| |
| /* Decodes a 32 bit unsigned integer. |
| */ |
| inline size_t decode_uint_32(const uint8_t* buf, const uint8_t* buf_end, uint32_t* r) |
| { |
| // Return zero bytes read on buffer overflow |
| if (buf_end - buf < (unsigned)sizeof(uint32_t)) |
| { |
| return 0; |
| } |
| if (is_big_endian()) |
| { |
| uint8_t inverted[4] = {buf[3], buf[2], buf[1], buf[0]}; |
| memcpy(r, inverted, sizeof(uint32_t)); |
| } |
| else |
| { |
| memcpy(r, buf, sizeof(uint32_t)); |
| } |
| return sizeof(uint32_t); |
| } |