#include "loader.h"
#include "log.h"
+#if COMMON_UNIX_PLATFORMS
+#include <fcntl.h>
+#include <sys/stat.h>
+#endif
+
static void *cJSON_malloc(const VkAllocationCallbacks *pAllocator, size_t size) {
return loader_calloc(pAllocator, size, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
}
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);
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;