diff --git a/CMakeLists.txt b/CMakeLists.txt index dbc977d..5ab2008 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,3 +80,6 @@ if (Iconv_FOUND) target_link_libraries(utils Iconv::Iconv) endif() endif() +if (NOT MSVC) + target_link_libraries(utils m) +endif() diff --git a/cstr_util.c b/cstr_util.c index 0c2d424..4fbe105 100644 --- a/cstr_util.c +++ b/cstr_util.c @@ -2,6 +2,7 @@ #include "utils_config.h" #include +#include #include #include #include @@ -10,6 +11,44 @@ #define printf printf_s #endif +typedef enum float_format { + undetected_endian, + ieee_big_endian, + ieee_little_endian, + unknown_endian, +} float_format_type; + +static float_format_type double_format = undetected_endian; +static float_format_type float_format = undetected_endian; + +void detect_double_format() { + if (sizeof(double) != 8) double_format = unknown_endian; + else { + double x = 9006104071833999.0; + if (!memcmp(&x, "C?\xff\x01\x02\x03\t\x8f", 8)) { + double_format = ieee_big_endian; + } else if (!memcmp(&x, "\x8f\t\x03\x02\x01\xff?C", 8)) { + double_format = ieee_little_endian; + } else { + double_format = unknown_endian; + } + } +} + +void detect_float_format() { + if (sizeof(float) != 4) float_format = unknown_endian; + else { + float x = 213213216.0; + if (!memcmp(&x, "MKV\x02", 4)) { + float_format = ieee_big_endian; + } else if (!memcmp(&x, "\x02VKM", 4)) { + float_format = ieee_little_endian; + } else { + float_format = unknown_endian; + } + } +} + int cstr_util_copy_str(char** dest, const char* str) { if (!dest || !str) return 1; size_t le = strlen(str); @@ -121,3 +160,120 @@ int cstr_read_str(char* buf, char** dest, size_t* pos, size_t buf_len) { *dest = ntmp ? ntmp : tmp; return 0; } + +float cstr_read_float(const uint8_t* p, int big) { + if (float_format == undetected_endian) detect_float_format(); + if (float_format == unknown_endian) { + unsigned char sign; + int e; + unsigned int f; + float x; + int incr = 1; + if (!big) { + p += 3; + incr = -1; + } + sign = (*p >> 7) & 1; + e = (*p & 0x7F) << 1; + p += incr; + e |= (*p >> 7) & 1; + f = (*p & 0x7F) << 16; + p += incr; + f |= *p << 8; + p += incr; + f |= *p; + if (e == 255) { + if (f == 0) return sign ? -INFINITY : INFINITY; + else return NAN; + } + x = (float)f / 8388608.0; + if (e == 0) { + e = -126; + } else { + x += 1.0; + e -= 127; + } + x = ldexpf(x, e); + if (sign) x = -x; + return x; + } else { + float x; + if ((float_format == ieee_little_endian && big) || (float_format == ieee_big_endian && !big)) { + char buf[4]; + char* d = &(buf[3]); + int i; + for (i = 0; i < 4; i++) { + *d-- = *p++; + } + memcpy(&x, buf, 4); + } else { + memcpy(&x, p, 4); + } + return x; + } +} + +double cstr_read_double(const uint8_t* p, int big) { + if (double_format == undetected_endian) detect_double_format(); + if (double_format == unknown_endian) { + unsigned char sign; + int e; + unsigned int fhi, flo; + double x; + int incr = 1; + if (!big) { + p += 7; + incr = -1; + } + sign = (*p >> 7) & 1; + e = (*p & 0x7F) << 4; + p += incr; + e |= (*p >> 4) & 0xF; + fhi = (*p & 0xF) << 24; + p += incr; + fhi |= *p << 16; + p += incr; + fhi |= *p << 8; + p += incr; + fhi |= *p; + p += incr; + flo = *p << 16; + p += incr; + flo |= *p << 8; + p += incr; + flo |= *p; + if (e == 2047) { + if (flo == 0 && fhi == 0) { + return sign ? -INFINITY : INFINITY; + } else { + float a = NAN; + return a; + } + } + x = (double)fhi + (double)flo / 16777216.0; + x /= 268435456.0; + if (e == 0) + e = -1022; + else { + x += 1.0; + e -= 1023; + } + x = ldexp(x, e); + if (sign) x = -x; + return x; + } else { + double x; + if ((double_format == ieee_little_endian && big) || (double_format == ieee_big_endian && !big)) { + char buf[8]; + char* d = &(buf[7]); + int i; + for (i = 0; i < 8; i++) { + *d-- = *p++; + } + memcpy(&x, buf, 8); + } else { + memcpy(&x, p, 8); + } + return x; + } +} diff --git a/cstr_util.h b/cstr_util.h index 109a548..e988571 100644 --- a/cstr_util.h +++ b/cstr_util.h @@ -84,6 +84,20 @@ int16_t cstr_read_int16(const uint8_t* bytes, int big); * @return 0 if successed otherwise 1 */ int cstr_read_str(char* buf, char** dest, size_t* pos, size_t buf_len); +/** + * @brief Convert bytes to float + * @param bytes Bytes (at least 4 bytes) + * @param big 0 if little endian otherwise big endian + * @return result +*/ +float cstr_read_float(const uint8_t* bytes, int big); +/** + * @brief Convert bytes to double + * @param bytes Bytes (at least 8 bytes) + * @param big 0 if little endian otherwise big endian + * @return result +*/ +double cstr_read_double(const uint8_t* bytes, int big); #ifdef __cplusplus } #endif diff --git a/dict.h b/dict.h index c5d1fcf..e7148fd 100644 --- a/dict.h +++ b/dict.h @@ -31,6 +31,12 @@ struct dict_entry* dict_get(struct Dict* d, K key) { return &re->d; } template +V dict_get_value(struct Dict* d, K key) { + struct dict_entry* re = dict_get(d, key); + if (!re) return nullptr; + return re->value; +} +template bool dict_heve_key_internal(struct dict_entry origin, K key) { return key == origin.key; } diff --git a/file_reader.c b/file_reader.c index 95f1bbc..ed39d63 100644 --- a/file_reader.c +++ b/file_reader.c @@ -94,6 +94,46 @@ int file_reader_read_char(file_reader_file* f, char* re) { return 0; } +int file_reader_read_double(file_reader_file* f, double* re) { + if (!f) return 1; + int64_t offset = f->tell(f->f); + double r = 0; + int origin = SEEK_SET; + if (offset == -1) { + origin = SEEK_CUR; + } + size_t c; + uint8_t buf[8]; + if ((c = f->read(f->f, 8, buf)) < 8) { + if (origin == SEEK_CUR) offset = -c; + f->seek(f->f, offset, origin); + return 1; + } + r = cstr_read_double(buf, f->endian); + if (re) *re = r; + return 0; +} + +int file_reader_read_float(file_reader_file* f, float* re) { + if (!f) return 1; + int64_t offset = f->tell(f->f); + float r = 0; + int origin = SEEK_SET; + if (offset == -1) { + origin = SEEK_CUR; + } + size_t c; + uint8_t buf[4]; + if ((c = f->read(f->f, 4, buf)) < 4) { + if (origin == SEEK_CUR) offset = -c; + f->seek(f->f, offset, origin); + return 1; + } + r = cstr_read_float(buf, f->endian); + if (re) *re = r; + return 0; +} + int file_reader_read_uint8(file_reader_file* f, uint8_t* re) { return file_reader_read_char(f, (char*)re); } @@ -118,6 +158,10 @@ int file_reader_read_int16(file_reader_file* f, int16_t* re) { return 0; } +int file_reader_read_uint16(file_reader_file* f, uint16_t* re) { + return file_reader_read_int16(f, (int16_t*)re); +} + int file_reader_read_int32(file_reader_file* f, int32_t* re) { if (!f) return 1; int64_t offset = f->tell(f->f); diff --git a/file_reader.h b/file_reader.h index f28dddb..895471f 100644 --- a/file_reader.h +++ b/file_reader.h @@ -54,6 +54,20 @@ int64_t file_reader_tell(file_reader_file* f); * @return 0 if successed otherwise 1 */ int file_reader_read_char(file_reader_file* f, char* re); +/** + * @brief Read double from reader + * @param f reader + * @param re result + * @return 0 if successed otherwise 1 +*/ +int file_reader_read_double(file_reader_file* f, double* re); +/** + * @brief Read float from reader + * @param f reader + * @param re result + * @return 0 if successed otherwise 1 +*/ +int file_reader_read_float(file_reader_file* f, float* re); /** * @brief Read uint8 from reader * @param f reader @@ -68,6 +82,13 @@ int file_reader_read_uint8(file_reader_file* f, uint8_t* re); * @return 0 if successed otherwise 1 */ int file_reader_read_int16(file_reader_file* f, int16_t* re); +/** + * @brief Read uint16 from reader + * @param f reader + * @param re result + * @return 0 if successed otherwise 1 +*/ +int file_reader_read_uint16(file_reader_file* f, uint16_t* re); /** * @brief Read int32 from reader * @param f reader