From: Branimir Ri\v{c}ko Date: Sat, 1 Jun 2024 22:38:06 +0000 (+0200) Subject: Stop reading json files twice X-Git-Tag: upstream/1.3.296~8 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1108bba6c97174d172d45470a7470a3d6a564647;p=platform%2Fupstream%2FVulkan-Loader.git Stop reading json files twice Split out the JSON file opening and reading logic into a Windows and Posix function to allow only reading the contents of a file once. --- diff --git a/loader/cJSON.c b/loader/cJSON.c index b07d9518..dd875853 100644 --- a/loader/cJSON.c +++ b/loader/cJSON.c @@ -40,6 +40,11 @@ #include "loader.h" #include "log.h" +#if COMMON_UNIX_PLATFORMS +#include +#include +#endif + static void *cJSON_malloc(const VkAllocationCallbacks *pAllocator, size_t size) { return loader_calloc(pAllocator, size, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); } @@ -951,65 +956,105 @@ cJSON *loader_cJSON_GetObjectItem(cJSON *object, const char *string) { return c; } -VkResult loader_get_json(const struct loader_instance *inst, const char *filename, cJSON **json) { - FILE *file = NULL; - char *json_buf = NULL; - size_t len; +#ifdef _WIN32 +static VkResult loader_read_entire_file(const struct loader_instance *inst, const char *filename, char **out_buff) { + HANDLE file_handle = INVALID_HANDLE_VALUE; + DWORD len = 0, read_len = 0; VkResult res = VK_SUCCESS; + BOOL read_ok = false; - assert(json != NULL); - - *json = NULL; - -#if defined(_WIN32) int filename_utf16_size = MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0); if (filename_utf16_size > 0) { wchar_t *filename_utf16 = (wchar_t *)loader_stack_alloc(filename_utf16_size * sizeof(wchar_t)); if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, filename_utf16, filename_utf16_size) == filename_utf16_size) { - errno_t wfopen_error = _wfopen_s(&file, filename_utf16, L"rb"); - if (0 != wfopen_error) { - loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_get_json: Failed to open JSON file %s", filename); - } + file_handle = + CreateFileW(filename_utf16, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); } } -#elif COMMON_UNIX_PLATFORMS - file = fopen(filename, "rb"); -#else -#warning fopen not available on this platform -#endif - - if (!file) { + if (INVALID_HANDLE_VALUE == file_handle) { loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_get_json: Failed to open JSON file %s", filename); res = VK_ERROR_INITIALIZATION_FAILED; goto out; } - // NOTE: We can't just use fseek(file, 0, SEEK_END) because that isn't guaranteed to be supported on all systems - size_t fread_ret_count = 0; - do { - char buffer[256]; - fread_ret_count = fread(buffer, 1, 256, file); - } while (fread_ret_count == 256 && !feof(file)); - len = ftell(file); - fseek(file, 0, SEEK_SET); - json_buf = (char *)loader_instance_heap_calloc(inst, len + 1, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); - if (json_buf == NULL) { - loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, - "loader_get_json: Failed to allocate space for JSON file %s buffer of length %lu", filename, len); + len = GetFileSize(file_handle, NULL); + if (INVALID_FILE_SIZE == len) { + loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_get_json: Failed to read file size of JSON file %s", filename); + res = VK_ERROR_INITIALIZATION_FAILED; + goto out; + } + *out_buff = (char *)loader_instance_heap_calloc(inst, len + 1, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (NULL == *out_buff) { + loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_get_json: Failed to allocate memory to read JSON file %s", filename); res = VK_ERROR_OUT_OF_HOST_MEMORY; goto out; } - if (fread(json_buf, sizeof(char), len, file) != len) { - loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_get_json: Failed to read JSON file %s.", filename); + read_ok = ReadFile(file_handle, *out_buff, len, &read_len, NULL); + if (len != read_len || false == read_ok) { + loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_get_json: Failed to read entire JSON file %s", filename); res = VK_ERROR_INITIALIZATION_FAILED; goto out; } - json_buf[len] = '\0'; + (*out_buff)[len] = '\0'; - // Can't be a valid json if the string is of length zero - if (len == 0) { +out: + if (INVALID_HANDLE_VALUE != file_handle) { + CloseHandle(file_handle); + } + return res; +} +#elif COMMON_UNIX_PLATFORMS +static VkResult loader_read_entire_file(const struct loader_instance *inst, const char *filename, char **out_buff) { + FILE *file = NULL; + struct stat stats = {0}; + VkResult res = VK_SUCCESS; + + file = fopen(filename, "rb"); + if (NULL == file) { + loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_get_json: Failed to open JSON file %s", filename); + res = VK_ERROR_INITIALIZATION_FAILED; + goto out; + } + if (-1 == fstat(fileno(file), &stats)) { + loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_get_json: Failed to read file size of JSON file %s", filename); + res = VK_ERROR_INITIALIZATION_FAILED; + goto out; + } + *out_buff = (char *)loader_instance_heap_calloc(inst, stats.st_size + 1, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (NULL == *out_buff) { + loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_get_json: Failed to allocate memory to read JSON file %s", filename); + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } + if (stats.st_size != (long int)fread(*out_buff, sizeof(char), stats.st_size, file)) { + loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_get_json: Failed to read entire JSON file %s", filename); res = VK_ERROR_INITIALIZATION_FAILED; goto out; } + (*out_buff)[stats.st_size] = '\0'; + +out: + if (NULL != file) { + fclose(file); + } + return res; +} +#else +#warning fopen not available on this platform +VkResult loader_read_entire_file(const struct loader_instance *inst, const char *filename, char **out_buff) { + return VK_ERROR_INITIALIZATION_FAILED; +} +#endif + +VkResult loader_get_json(const struct loader_instance *inst, const char *filename, cJSON **json) { + char *json_buf = NULL; + VkResult res = VK_SUCCESS; + + assert(json != NULL); + + *json = NULL; + res = loader_read_entire_file(inst, filename, &json_buf); + if (VK_SUCCESS != res) goto out; + // Parse text from file bool out_of_memory = false; *json = cJSON_Parse(inst ? &inst->alloc_callbacks : NULL, json_buf, &out_of_memory); @@ -1025,9 +1070,6 @@ VkResult loader_get_json(const struct loader_instance *inst, const char *filenam out: loader_instance_heap_free(inst, json_buf); - if (NULL != file) { - fclose(file); - } if (res != VK_SUCCESS && *json != NULL) { loader_cJSON_Delete(*json); *json = NULL;