2025-02-26 13:24:16 +01:00
|
|
|
|
|
|
|
|
#include "iron_file.h"
|
|
|
|
|
#include <iron_system.h>
|
2025-03-09 17:02:12 +01:00
|
|
|
#ifdef IRON_ANDROID
|
2025-03-11 22:33:21 +01:00
|
|
|
#include <backends/android_system.h>
|
2025-02-26 13:24:16 +01:00
|
|
|
#endif
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
2025-03-09 17:02:12 +01:00
|
|
|
#ifdef IRON_WINDOWS
|
2025-02-26 13:24:16 +01:00
|
|
|
#include <malloc.h>
|
|
|
|
|
#include <memory.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
static bool memory_close_callback(iron_file_reader_t *reader) {
|
2025-02-26 13:24:16 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
static size_t memory_read_callback(iron_file_reader_t *reader, void *data, size_t size) {
|
2025-02-26 13:24:16 +01:00
|
|
|
size_t read_size = reader->size - reader->offset < size ? reader->size - reader->offset : size;
|
|
|
|
|
memcpy(data, (uint8_t *)reader->data + reader->offset, read_size);
|
|
|
|
|
reader->offset += read_size;
|
|
|
|
|
return read_size;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
static size_t memory_pos_callback(iron_file_reader_t *reader) {
|
2025-02-26 13:24:16 +01:00
|
|
|
return reader->offset;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
static bool memory_seek_callback(iron_file_reader_t *reader, size_t pos) {
|
2025-02-26 13:24:16 +01:00
|
|
|
reader->offset = pos;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
bool iron_file_reader_from_memory(iron_file_reader_t *reader, void *data, size_t size) {
|
|
|
|
|
memset(reader, 0, sizeof(iron_file_reader_t));
|
2025-02-26 13:24:16 +01:00
|
|
|
reader->data = data;
|
|
|
|
|
reader->size = size;
|
|
|
|
|
reader->read = memory_read_callback;
|
|
|
|
|
reader->pos = memory_pos_callback;
|
|
|
|
|
reader->seek = memory_seek_callback;
|
|
|
|
|
reader->close = memory_close_callback;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
#ifdef IRON_IOS
|
2025-08-05 21:20:38 +02:00
|
|
|
const char *iron_get_resource_path(void);
|
2025-02-26 13:24:16 +01:00
|
|
|
#endif
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
#ifdef IRON_MACOS
|
2025-08-05 21:20:38 +02:00
|
|
|
const char *iron_get_resource_path(void);
|
2025-02-26 13:24:16 +01:00
|
|
|
#endif
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
#ifdef IRON_WINDOWS
|
2025-03-07 11:30:51 +01:00
|
|
|
#include <backends/windows_mini.h>
|
2025-02-26 13:24:16 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static char *fileslocation = NULL;
|
2025-03-09 17:02:12 +01:00
|
|
|
static bool (*file_reader_callback)(iron_file_reader_t *reader, const char *filename, int type) = NULL;
|
|
|
|
|
#ifdef IRON_WINDOWS
|
2025-02-26 13:24:16 +01:00
|
|
|
static wchar_t wfilepath[1001];
|
|
|
|
|
#endif
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
void iron_internal_set_files_location(char *dir) {
|
2025-02-26 13:24:16 +01:00
|
|
|
fileslocation = dir;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
char *iron_internal_get_files_location(void) {
|
2025-02-26 13:24:16 +01:00
|
|
|
return fileslocation;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
bool iron_internal_file_reader_callback(iron_file_reader_t *reader, const char *filename, int type) {
|
2025-02-26 13:24:16 +01:00
|
|
|
return file_reader_callback ? file_reader_callback(reader, filename, type) : false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
#ifdef IRON_WINDOWS
|
|
|
|
|
static size_t iron_libc_file_reader_read(iron_file_reader_t *reader, void *data, size_t size) {
|
2025-02-26 13:24:16 +01:00
|
|
|
DWORD readBytes = 0;
|
|
|
|
|
if (ReadFile(reader->data, data, (DWORD)size, &readBytes, NULL)) {
|
|
|
|
|
return (size_t)readBytes;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
static bool iron_libc_file_reader_seek(iron_file_reader_t *reader, size_t pos) {
|
2025-02-26 13:24:16 +01:00
|
|
|
// TODO: make this 64-bit compliant
|
|
|
|
|
SetFilePointer(reader->data, (LONG)pos, NULL, FILE_BEGIN);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
static bool iron_libc_file_reader_close(iron_file_reader_t *reader) {
|
2025-02-26 13:24:16 +01:00
|
|
|
CloseHandle(reader->data);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
static size_t iron_libc_file_reader_pos(iron_file_reader_t *reader) {
|
2025-02-26 13:24:16 +01:00
|
|
|
// TODO: make this 64-bit compliant
|
|
|
|
|
return (size_t)SetFilePointer(reader->data, 0, NULL, FILE_CURRENT);
|
|
|
|
|
}
|
|
|
|
|
#else
|
2025-03-09 17:02:12 +01:00
|
|
|
static size_t iron_libc_file_reader_read(iron_file_reader_t *reader, void *data, size_t size) {
|
2025-02-26 13:24:16 +01:00
|
|
|
return fread(data, 1, size, (FILE *)reader->data);
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
static bool iron_libc_file_reader_seek(iron_file_reader_t *reader, size_t pos) {
|
2025-02-26 13:24:16 +01:00
|
|
|
fseek((FILE *)reader->data, pos, SEEK_SET);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
static bool iron_libc_file_reader_close(iron_file_reader_t *reader) {
|
2025-02-26 13:24:16 +01:00
|
|
|
if (reader->data != NULL) {
|
|
|
|
|
fclose((FILE *)reader->data);
|
|
|
|
|
reader->data = NULL;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
static size_t iron_libc_file_reader_pos(iron_file_reader_t *reader) {
|
2025-02-26 13:24:16 +01:00
|
|
|
return ftell((FILE *)reader->data);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
bool iron_internal_file_reader_open(iron_file_reader_t *reader, const char *filename, int type) {
|
2025-02-26 13:24:16 +01:00
|
|
|
char filepath[1001];
|
2025-03-09 17:02:12 +01:00
|
|
|
#ifdef IRON_IOS
|
2025-08-05 21:20:38 +02:00
|
|
|
strcpy(filepath, type == IRON_FILE_TYPE_SAVE ? iron_internal_save_path() : iron_get_resource_path());
|
2025-03-09 17:02:12 +01:00
|
|
|
if (type != IRON_FILE_TYPE_SAVE) {
|
2025-02-26 13:24:16 +01:00
|
|
|
strcat(filepath, "/");
|
2025-03-09 17:02:12 +01:00
|
|
|
strcat(filepath, IRON_OUTDIR);
|
2025-02-26 13:24:16 +01:00
|
|
|
strcat(filepath, "/");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
strcat(filepath, filename);
|
|
|
|
|
#endif
|
2025-03-09 17:02:12 +01:00
|
|
|
#ifdef IRON_MACOS
|
2025-08-05 21:20:38 +02:00
|
|
|
strcpy(filepath, type == IRON_FILE_TYPE_SAVE ? iron_internal_save_path() : iron_get_resource_path());
|
2025-03-09 17:02:12 +01:00
|
|
|
if (type != IRON_FILE_TYPE_SAVE) {
|
2025-02-26 13:24:16 +01:00
|
|
|
strcat(filepath, "/");
|
2025-03-09 17:02:12 +01:00
|
|
|
strcat(filepath, IRON_OUTDIR);
|
2025-02-26 13:24:16 +01:00
|
|
|
strcat(filepath, "/");
|
|
|
|
|
}
|
|
|
|
|
strcat(filepath, filename);
|
|
|
|
|
#endif
|
2025-03-09 17:02:12 +01:00
|
|
|
#ifdef IRON_WINDOWS
|
|
|
|
|
if (type == IRON_FILE_TYPE_SAVE) {
|
|
|
|
|
strcpy(filepath, iron_internal_save_path());
|
2025-02-26 13:24:16 +01:00
|
|
|
strcat(filepath, filename);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
strcpy(filepath, filename);
|
|
|
|
|
}
|
|
|
|
|
size_t filepathlength = strlen(filepath);
|
|
|
|
|
for (size_t i = 0; i < filepathlength; ++i)
|
|
|
|
|
if (filepath[i] == '/')
|
|
|
|
|
filepath[i] = '\\';
|
|
|
|
|
#endif
|
2025-03-09 17:02:12 +01:00
|
|
|
#if defined(IRON_LINUX) || defined(IRON_ANDROID)
|
|
|
|
|
if (type == IRON_FILE_TYPE_SAVE) {
|
|
|
|
|
strcpy(filepath, iron_internal_save_path());
|
2025-02-26 13:24:16 +01:00
|
|
|
strcat(filepath, filename);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
strcpy(filepath, filename);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2025-03-09 17:02:12 +01:00
|
|
|
#ifdef IRON_WASM
|
2025-02-26 13:24:16 +01:00
|
|
|
strcpy(filepath, filename);
|
|
|
|
|
#endif
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
#ifdef IRON_WINDOWS
|
2025-02-26 13:24:16 +01:00
|
|
|
// Drive letter or network
|
|
|
|
|
bool isAbsolute = (filename[1] == ':' && filename[2] == '\\') || (filename[0] == '\\' && filename[1] == '\\');
|
|
|
|
|
#else
|
|
|
|
|
bool isAbsolute = filename[0] == '/';
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (isAbsolute) {
|
|
|
|
|
strcpy(filepath, filename);
|
|
|
|
|
}
|
2025-03-09 17:02:12 +01:00
|
|
|
else if (fileslocation != NULL && type != IRON_FILE_TYPE_SAVE) {
|
2025-02-26 13:24:16 +01:00
|
|
|
strcpy(filepath, fileslocation);
|
|
|
|
|
strcat(filepath, "/");
|
|
|
|
|
strcat(filepath, filename);
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
#ifdef IRON_WINDOWS
|
2025-02-26 13:24:16 +01:00
|
|
|
MultiByteToWideChar(CP_UTF8, 0, filepath, -1, wfilepath, 1000);
|
|
|
|
|
reader->data = CreateFileW(wfilepath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
|
if (reader->data == INVALID_HANDLE_VALUE) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
reader->data = fopen(filepath, "rb");
|
|
|
|
|
if (reader->data == NULL) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
#ifdef IRON_WINDOWS
|
2025-02-26 13:24:16 +01:00
|
|
|
// TODO: make this 64-bit compliant
|
|
|
|
|
reader->size = (size_t)GetFileSize(reader->data, NULL);
|
|
|
|
|
#else
|
|
|
|
|
fseek((FILE *)reader->data, 0, SEEK_END);
|
|
|
|
|
reader->size = ftell((FILE *)reader->data);
|
|
|
|
|
fseek((FILE *)reader->data, 0, SEEK_SET);
|
|
|
|
|
#endif
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
reader->read = iron_libc_file_reader_read;
|
|
|
|
|
reader->seek = iron_libc_file_reader_seek;
|
|
|
|
|
reader->close = iron_libc_file_reader_close;
|
|
|
|
|
reader->pos = iron_libc_file_reader_pos;
|
2025-02-26 13:24:16 +01:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
#if !defined(IRON_ANDROID)
|
|
|
|
|
bool iron_file_reader_open(iron_file_reader_t *reader, const char *filename, int type) {
|
2025-02-26 13:24:16 +01:00
|
|
|
memset(reader, 0, sizeof(*reader));
|
2025-03-09 17:02:12 +01:00
|
|
|
return iron_internal_file_reader_callback(reader, filename, type) ||
|
|
|
|
|
iron_internal_file_reader_open(reader, filename, type);
|
2025-02-26 13:24:16 +01:00
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
void iron_file_reader_set_callback(bool (*callback)(iron_file_reader_t *reader, const char *filename, int type)) {
|
2025-02-26 13:24:16 +01:00
|
|
|
file_reader_callback = callback;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
size_t iron_file_reader_read(iron_file_reader_t *reader, void *data, size_t size) {
|
2025-02-26 13:24:16 +01:00
|
|
|
return reader->read(reader, data, size);
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
bool iron_file_reader_seek(iron_file_reader_t *reader, size_t pos) {
|
2025-02-26 13:24:16 +01:00
|
|
|
return reader->seek(reader, pos);
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
bool iron_file_reader_close(iron_file_reader_t *reader) {
|
2025-02-26 13:24:16 +01:00
|
|
|
return reader->close(reader);
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
size_t iron_file_reader_pos(iron_file_reader_t *reader) {
|
2025-02-26 13:24:16 +01:00
|
|
|
return reader->pos(reader);
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
size_t iron_file_reader_size(iron_file_reader_t *reader) {
|
2025-02-26 13:24:16 +01:00
|
|
|
return reader->size;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
float iron_read_f32le(uint8_t *data) {
|
2025-02-26 13:24:16 +01:00
|
|
|
return *(float *)data;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
uint64_t iron_read_u64le(uint8_t *data) {
|
2025-02-26 13:24:16 +01:00
|
|
|
return *(uint64_t *)data;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
int64_t iron_read_s64le(uint8_t *data) {
|
2025-02-26 13:24:16 +01:00
|
|
|
return *(int64_t *)data;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
uint32_t iron_read_u32le(uint8_t *data) {
|
2025-02-26 13:24:16 +01:00
|
|
|
return *(uint32_t *)data;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
int32_t iron_read_s32le(uint8_t *data) {
|
2025-02-26 13:24:16 +01:00
|
|
|
return *(int32_t *)data;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
uint16_t iron_read_u16le(uint8_t *data) {
|
2025-02-26 13:24:16 +01:00
|
|
|
return *(uint16_t *)data;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
int16_t iron_read_s16le(uint8_t *data) {
|
2025-02-26 13:24:16 +01:00
|
|
|
return *(int16_t *)data;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
uint8_t iron_read_u8(uint8_t *data) {
|
2025-02-26 13:24:16 +01:00
|
|
|
return *data;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
int8_t iron_read_s8(uint8_t *data) {
|
2025-02-26 13:24:16 +01:00
|
|
|
return *(int8_t *)data;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
bool iron_file_writer_open(iron_file_writer_t *writer, const char *filepath) {
|
2025-02-26 13:24:16 +01:00
|
|
|
writer->file = NULL;
|
|
|
|
|
|
|
|
|
|
char path[1001];
|
2025-03-09 17:02:12 +01:00
|
|
|
strcpy(path, iron_internal_save_path());
|
2025-02-26 13:24:16 +01:00
|
|
|
strcat(path, filepath);
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
#ifdef IRON_WINDOWS
|
2025-02-26 13:24:16 +01:00
|
|
|
wchar_t wpath[MAX_PATH];
|
|
|
|
|
MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, MAX_PATH);
|
|
|
|
|
writer->file = CreateFileW(wpath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
|
#else
|
|
|
|
|
writer->file = fopen(path, "wb");
|
|
|
|
|
#endif
|
|
|
|
|
if (writer->file == NULL) {
|
2025-03-09 17:02:12 +01:00
|
|
|
iron_log("Could not open file %s.", filepath);
|
2025-02-26 13:24:16 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
void iron_file_writer_close(iron_file_writer_t *writer) {
|
2025-02-26 13:24:16 +01:00
|
|
|
if (writer->file != NULL) {
|
2025-03-09 17:02:12 +01:00
|
|
|
#ifdef IRON_WINDOWS
|
2025-02-26 13:24:16 +01:00
|
|
|
CloseHandle(writer->file);
|
|
|
|
|
#else
|
|
|
|
|
fclose((FILE *)writer->file);
|
|
|
|
|
#endif
|
|
|
|
|
writer->file = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-09 17:02:12 +01:00
|
|
|
void iron_file_writer_write(iron_file_writer_t *writer, void *data, int size) {
|
|
|
|
|
#ifdef IRON_WINDOWS
|
2025-02-26 13:24:16 +01:00
|
|
|
DWORD written = 0;
|
|
|
|
|
WriteFile(writer->file, data, (DWORD)size, &written, NULL);
|
|
|
|
|
#else
|
|
|
|
|
fwrite(data, 1, size, (FILE *)writer->file);
|
|
|
|
|
#endif
|
|
|
|
|
}
|