Files
RedScarfEngine/utilities/src/file_utils.c
T
everyonecancode bbccf7f0ba Add wrap dependency for vulkan headers
Don't expect the vulkan headers to be present on the development system. Instead, download the using meson wrap.

Signed-off-by: Piotr Krygier <piotrkrygier@everyonecancode.xyz>
2026-06-12 14:11:42 +02:00

202 lines
5.2 KiB
C

#include "file_utils.h"
#define CGLTF_IMPLEMENTATION
#include "cgltf.h"
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SDL3/SDL_log.h"
#include "commons.h"
#include "errors_common.h"
#ifdef __linux__
#include <limits.h>
#include <unistd.h>
#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;
}