From ac4fee1977e1b3138b4845d9fb558d173739fce9 Mon Sep 17 00:00:00 2001 From: lifegpc Date: Thu, 30 Dec 2021 22:05:42 +0800 Subject: [PATCH] Update --- CMakeLists.txt | 4 +++ cstr_util.c | 10 ++++++++ cstr_util.h | 15 ++++++++++++ fileop.cpp | 62 +++++++++++++++++++++++++++++++++++++++++++---- fileop.h | 23 ++++++++++++++++++ linked_list.h | 51 ++++++++++++++++++++++++++++++++++++++ utils_config.h.in | 2 ++ 7 files changed, 162 insertions(+), 5 deletions(-) create mode 100644 linked_list.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 47d8828..694adb9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,6 +23,9 @@ if (WIN32) check_symbol_exists(_wcserror_s "string.h" HAVE__WCSERROR_S) check_symbol_exists(printf_s "stdio.h" HAVE_PRINTF_S) check_symbol_exists(sscanf_s "stdio.h" HAVE_SSCANF_S) +else() + check_symbol_exists(fseeko "stdio.h" HAVE_FSEEKO) + check_symbol_exists(fseeko64 "stdio.h" HAVE_FSEEKO64) endif() check_symbol_exists(strerror_r "string.h" HAVE_STRERROR_R) if (HAVE_STRERROR_R) @@ -60,6 +63,7 @@ set(SOURCE_FILE_HEADERS time_util.h encoding.h str_util.h + linked_list.h ) add_library(utils STATIC ${SOURCE_FILE} ${SOURCE_FILE_HEADERS}) diff --git a/cstr_util.c b/cstr_util.c index 2cd8779..3fc6edb 100644 --- a/cstr_util.c +++ b/cstr_util.c @@ -42,3 +42,13 @@ int cstr_tolowercase(const char* str, size_t input_len, char** output) { *output = tmp; return 1; } + +uint32_t cstr_read_uint32(const uint8_t* bytes, int big) { + if (!bytes) return 0; + return big ? (bytes[0] << 24) + (bytes[1] << 16) + (bytes[2] << 8) + bytes[3] : bytes[0] + (bytes[1] << 8) + (bytes[2] << 16) + (bytes[3] << 24); +} + +int32_t cstr_read_int32(const uint8_t* bytes, int big) { + if (!bytes) return 0; + return cstr_read_uint32(bytes, big); +} diff --git a/cstr_util.h b/cstr_util.h index a5d080b..bf7aa60 100644 --- a/cstr_util.h +++ b/cstr_util.h @@ -4,6 +4,7 @@ extern "C" { #endif #include +#include /** * @brief Copy string to another string * @param dest The pointer of output string @@ -26,6 +27,20 @@ int cstr_is_integer(const char* str, int allow_sign); * @return 1 if successed otherwise 0. */ int cstr_tolowercase(const char* str, size_t input_len, char** output); +/** + * @brief Convert bytes to uint32 + * @param bytes Bytes (at least 4 bytes) + * @param big 0 if little endian otherwise big endian + * @return result +*/ +uint32_t cstr_read_uint32(const uint8_t* bytes, int big); +/** + * @brief Convert bytes to int32 + * @param bytes Bytes (at least 4 bytes) + * @param big 0 if little endian otherwise big endian + * @return result +*/ +int32_t cstr_read_int32(const uint8_t* bytes, int big); #ifdef __cplusplus } #endif diff --git a/fileop.cpp b/fileop.cpp index a99ef08..9dbb362 100644 --- a/fileop.cpp +++ b/fileop.cpp @@ -81,6 +81,10 @@ HANDLE set_file_time_internal(wchar_t* fn) { return CreateFileW(fn, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); } +HANDLE get_file_size_internal(wchar_t* fn) { + return CreateFileW(fn, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); +} + template T fileop_internal(const char* fname, UINT codePage, T(*callback)(wchar_t* fn, Args... args), T failed, Args... args) { int wlen; @@ -371,16 +375,16 @@ bool fileop::mkdirs(std::string path, int mode, bool allow_exists) { std::list li; li.push_back(dn); do { - dn = dirname(dn) + sp; - if (dn.length() == 1) { + dn = dirname(dn); + if (dn.length() == 0) { if (li.size() > 0) { auto en = *(li.rbegin()); if (en == ("." + sp)) return false; } - dn = "." + sp; + dn = "."; } - if (!isdir(dn, exists)) return false; - if (!exists) li.push_back(dn); + if (!isdir(dn + sp, exists)) return false; + if (!exists) li.push_back(dn + sp); } while (!exists); auto it = li.rbegin(); for (; it != li.rend(); it++) { @@ -388,3 +392,51 @@ bool fileop::mkdirs(std::string path, int mode, bool allow_exists) { } return true; } + +bool fileop::get_file_size(std::string path, size_t& size) { + if (!exists(path)) return false; +#if _WIN32 + UINT cp[] = { CP_UTF8, CP_OEMCP, CP_ACP }; + int i; + HANDLE file; + for (i = 0; i < 3; i++) { + if ((file = fileop_internal(path.c_str(), cp[i], &get_file_size_internal, INVALID_HANDLE_VALUE)) != INVALID_HANDLE_VALUE) { + break; + } + } + if (file == INVALID_HANDLE_VALUE) { + file = CreateFileA(path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + if (file == INVALID_HANDLE_VALUE) return false; + } + LARGE_INTEGER si; + auto re = GetFileSizeEx(file, &si); + if (re) size = si.QuadPart; + CloseHandle(file); + return re ? true : false; +#else + struct stat stats; + if (stat(path.c_str(), &stats)) { + return false; + } + size = stats.st_size; + return true; +#endif +} + +int fileop::fseek(FILE* f, int64_t offset, int origin) { +#if _WIN32 + return ::_fseeki64(f, offset, origin); +#else +#if HAVE_FSEEKO64 + return ::fseek64(f, offset, origin); +#elif HAVE_FSEEKO + return ::fseeko(f, offset, origin); +#else + return ::fseek(f, offset, origin); +#endif +#endif +} + +bool fileop::mkdir_for_file(std::string path, int mode) { + return mkdirs(dirname(path), mode, true); +} diff --git a/fileop.h b/fileop.h index bc4e6ca..cec6f0f 100644 --- a/fileop.h +++ b/fileop.h @@ -2,6 +2,7 @@ #define _UTIL_FILEOP_H #include #include +#include #include namespace fileop { @@ -125,5 +126,27 @@ namespace fileop { * @return true if create successfully otherwise false */ bool mkdirs(std::string path, int mode, bool allow_exists = false); + /** + * @brief Retrieves the size of the specified file, in bytes. + * @param path The path of file. + * @param size Result. + * @return true if successed otherwise false + */ + bool get_file_size(std::string path, size_t& size); + /** + * @brief Moves the file pointer to a specified location. + * @param f File + * @param offset Number of bytes from origin. + * @param origin Initial position. + * @return 0 if successed otherwise a nonzero value + */ + int fseek(FILE* f, int64_t offset, int origin); + /** + * @brief Make sure file's directory is already exists, if not exists, try create it. + * @param path File's path + * @param mode Directory permission. (Linux only) + * @return true if file's directory is exists now. + */ + bool mkdir_for_file(std::string path, int mode); } #endif diff --git a/linked_list.h b/linked_list.h new file mode 100644 index 0000000..c89ee10 --- /dev/null +++ b/linked_list.h @@ -0,0 +1,51 @@ +#ifndef _UTIL_LINKED_LIST_H +#define _UTIL_LINKED_LIST_H +#include +#include +template +struct LinkedList { + T d; + struct LinkedList* prev; + struct LinkedList* next; +}; + +template +bool linked_list_append(struct LinkedList*& list, T* data = nullptr, struct LinkedList** tail = nullptr) { + bool have_list = list; + struct LinkedList* tmp = (struct LinkedList*)malloc(sizeof(LinkedList)); + if (!tmp) return false; + memset(tmp, 0, sizeof(LinkedList)); + if (data) tmp->d = T(*data); else tmp->d = T(); + if (!have_list) { + list = tmp; + } else { + struct LinkedList* t = list; + while (t->next) t = t->next; + t->next = tmp; + tmp->prev = t; + } + if (tail) *tail = tmp; + return true; +} + +template +bool linked_list_append(struct LinkedList*& list, struct LinkedList** tail) { + return linked_list_append(list, (T*)nullptr, tail); +} + +template +void linked_list_clear(struct LinkedList*& list, void(*free_func)(T) = nullptr) { + if (!list) return; + struct LinkedList* t = list; + struct LinkedList* tmp = nullptr; + if (free_func) free_func(t->d); + while (t->next) { + tmp = t; + t = t->next; + free(tmp); + if (free_func) free_func(t->d); + } + free(t); + list = nullptr; +} +#endif diff --git a/utils_config.h.in b/utils_config.h.in index 70a2a93..3a2f00c 100644 --- a/utils_config.h.in +++ b/utils_config.h.in @@ -8,3 +8,5 @@ #cmakedefine HAVE_STRERROR_R @HAVE_STRERROR_R@ #cmakedefine HAVE_GNU_STRERROR_R @HAVE_GNU_STRERROR_R@ #cmakedefine HAVE_SSCANF_S @HAVE_SSCANF_S@ +#cmakedefine HAVE_FSEEKO @HAVE_FSEEKO@ +#cmakedefine HAVE_FSEEKO64 @HAVE_FSEEKO64@