#include "file_utils.h" #define CGLTF_IMPLEMENTATION #include "cgltf.h" #include #include #include #include #include #include "SDL3/SDL_log.h" #include "commons.h" #include "errors_common.h" #ifdef __linux__ #include #include #endif /* ifndef __linux */ static rse_err_t get_curr_path(char* path) { char* last_sep = NULL; char* tmp_path = NULL; size_t path_length = 0U; ssize_t binary_path_length = 0U; size_t directory_path_length = 0U; if (NULL == path) { SDL_LogCritical(SDL_LOG_CATEGORY_GPU, "Failed to get path. Provided pointer is NULL"); return RSE_ERROR_NULL_POINTER; } path_length = strlen(path); if (path_length > MAX_PATH_LENGTH) { SDL_LogCritical(SDL_LOG_CATEGORY_GPU, "Max path length cannot be 0"); return RSE_ERROR_INVALID_PARAM; } rse_memset(path, '\0', path_length); rse_malloc(tmp_path, MAX_PATH_LENGTH); #ifdef __linux__ binary_path_length = readlink("/proc/self/exe", tmp_path, MAX_PATH_LENGTH - 1); if (binary_path_length == -1) { SDL_LogCritical(SDL_LOG_CATEGORY_GPU, "Failed to read current binary path"); return RSE_ERROR_NULL_POINTER; } tmp_path[binary_path_length] = '\0'; #endif /* ifdef __linux__ */ last_sep = strrchr(tmp_path, '/') + 1; if (NULL == last_sep) { SDL_LogCritical(SDL_LOG_CATEGORY_GPU, "Failed to get last separator in path"); return RSE_ERROR_INTERNAL_ERROR; } directory_path_length = last_sep - tmp_path; if (directory_path_length > MAX_PATH_LENGTH) { SDL_LogCritical(SDL_LOG_CATEGORY_GPU, "Provided path buffer is too small"); return RSE_ERROR_INTERNAL_ERROR; } strncpy(path, tmp_path, directory_path_length); free(tmp_path); return RSE_ERROR_NO_ERROR; } rse_err_t file_append_full_path(char* file_path, size_t max_buffer_size) { rse_err_t ret = RSE_ERROR_NO_ERROR; size_t curr_path_length = 0U; size_t file_path_length = 0U; char curr_path[MAX_PATH_LENGTH] = {0}; char temp_path[MAX_PATH_LENGTH] = {0}; file_path_length = strlen(file_path); if (file_path_length > max_buffer_size) { SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "Provided max_buffer_size is smaller than the file path itself"); return RSE_ERROR_INVALID_PARAM; } if ((ret = get_curr_path(curr_path)) != RSE_ERROR_NO_ERROR) { return ret; } curr_path_length = strlen(curr_path); if ((curr_path_length + file_path_length) > max_buffer_size) { SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "Provided max_buffer_size is to small to hold concatenated file path. %ld vs %ld", (curr_path_length + file_path_length), max_buffer_size); } strncpy(temp_path, file_path, MAX_PATH_LENGTH); memset(file_path, 0, max_buffer_size); strncat(file_path, curr_path, max_buffer_size); strncat(file_path, temp_path, max_buffer_size); return ret; } rse_err_t file_read_bytes(const char* file_name, size_t* bytes_count, unsigned char* buffer) { rse_err_t ret = RSE_ERROR_NO_ERROR; FILE* file = NULL; char real_path[MAX_PATH_LENGTH] = {0}; strncpy(real_path, file_name, MAX_PATH_LENGTH); if ((ret = file_append_full_path(real_path, MAX_PATH_LENGTH)) != RSE_ERROR_NO_ERROR) { return ret; } file = fopen(real_path, "rb"); if (file == NULL) { SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "Failed to open file for read: %s", real_path); ret = RSE_ERROR_INTERNAL_ERROR; return ret; } fseek(file, 0, SEEK_END); *bytes_count = ftell(file); fseek(file, 0, SEEK_SET); if (buffer == NULL) { goto file_close; } fread(buffer, *bytes_count, 1, file); if (ferror(file) != 0) { perror("Error reading file"); ret = RSE_ERROR_INTERNAL_ERROR; } file_close: fclose(file); return ret; } rse_err_t file_write(const char* file_name, size_t bytes_count, char* buffer) { FILE* file = NULL; char real_path[MAX_PATH_LENGTH] = {0}; rse_err_t ret = RSE_ERROR_NO_ERROR; strncpy(real_path, file_name, MAX_PATH_LENGTH); if ((ret = file_append_full_path(real_path, MAX_PATH_LENGTH)) != RSE_ERROR_NO_ERROR) { return ret; } file = fopen(real_path, "wb"); if (file == NULL) { SDL_LogCritical(SDL_LOG_CATEGORY_GPU, "Failed to open file for write: %s", file_name); return RSE_ERROR_INTERNAL_ERROR; } fwrite(buffer, bytes_count, 1, file); fclose(file); return ret; } rse_err_t file_load_gltf(const char* file_name, cgltf_data** data) { char real_path[MAX_PATH_LENGTH] = {0}; rse_err_t ret = RSE_ERROR_NO_ERROR; cgltf_options options = {0}; strncpy(real_path, file_name, MAX_PATH_LENGTH); if ((ret = file_append_full_path(real_path, MAX_PATH_LENGTH)) != RSE_ERROR_NO_ERROR) { return ret; } if (cgltf_parse_file(&options, real_path, data) != cgltf_result_success) { SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "Failed to parse GLTF data"); return RSE_ERROR_INTERNAL_ERROR; } return ret; }