#include "iron_file.h" #include #ifdef IRON_ANDROID #include #endif #include #include #include #ifdef IRON_WINDOWS #include #include #endif static bool memory_close_callback(iron_file_reader_t *reader) { return true; } static size_t memory_read_callback(iron_file_reader_t *reader, void *data, size_t size) { 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; } static size_t memory_pos_callback(iron_file_reader_t *reader) { return reader->offset; } static bool memory_seek_callback(iron_file_reader_t *reader, size_t pos) { reader->offset = pos; return true; } bool iron_file_reader_from_memory(iron_file_reader_t *reader, void *data, size_t size) { memset(reader, 0, sizeof(iron_file_reader_t)); 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; } #ifdef IRON_IOS const char *iphonegetresourcepath(void); #endif #ifdef IRON_MACOS const char *macgetresourcepath(void); #endif #ifdef IRON_WINDOWS #include #endif static char *fileslocation = NULL; static bool (*file_reader_callback)(iron_file_reader_t *reader, const char *filename, int type) = NULL; #ifdef IRON_WINDOWS static wchar_t wfilepath[1001]; #endif void iron_internal_set_files_location(char *dir) { fileslocation = dir; } char *iron_internal_get_files_location(void) { return fileslocation; } bool iron_internal_file_reader_callback(iron_file_reader_t *reader, const char *filename, int type) { return file_reader_callback ? file_reader_callback(reader, filename, type) : false; } #ifdef IRON_WINDOWS static size_t iron_libc_file_reader_read(iron_file_reader_t *reader, void *data, size_t size) { DWORD readBytes = 0; if (ReadFile(reader->data, data, (DWORD)size, &readBytes, NULL)) { return (size_t)readBytes; } else { return 0; } } static bool iron_libc_file_reader_seek(iron_file_reader_t *reader, size_t pos) { // TODO: make this 64-bit compliant SetFilePointer(reader->data, (LONG)pos, NULL, FILE_BEGIN); return true; } static bool iron_libc_file_reader_close(iron_file_reader_t *reader) { CloseHandle(reader->data); return true; } static size_t iron_libc_file_reader_pos(iron_file_reader_t *reader) { // TODO: make this 64-bit compliant return (size_t)SetFilePointer(reader->data, 0, NULL, FILE_CURRENT); } #else static size_t iron_libc_file_reader_read(iron_file_reader_t *reader, void *data, size_t size) { return fread(data, 1, size, (FILE *)reader->data); } static bool iron_libc_file_reader_seek(iron_file_reader_t *reader, size_t pos) { fseek((FILE *)reader->data, pos, SEEK_SET); return true; } static bool iron_libc_file_reader_close(iron_file_reader_t *reader) { if (reader->data != NULL) { fclose((FILE *)reader->data); reader->data = NULL; } return true; } static size_t iron_libc_file_reader_pos(iron_file_reader_t *reader) { return ftell((FILE *)reader->data); } #endif bool iron_internal_file_reader_open(iron_file_reader_t *reader, const char *filename, int type) { char filepath[1001]; #ifdef IRON_IOS strcpy(filepath, type == IRON_FILE_TYPE_SAVE ? iron_internal_save_path() : iphonegetresourcepath()); if (type != IRON_FILE_TYPE_SAVE) { strcat(filepath, "/"); strcat(filepath, IRON_OUTDIR); strcat(filepath, "/"); } strcat(filepath, filename); #endif #ifdef IRON_MACOS strcpy(filepath, type == IRON_FILE_TYPE_SAVE ? iron_internal_save_path() : macgetresourcepath()); if (type != IRON_FILE_TYPE_SAVE) { strcat(filepath, "/"); strcat(filepath, IRON_OUTDIR); strcat(filepath, "/"); } strcat(filepath, filename); #endif #ifdef IRON_WINDOWS if (type == IRON_FILE_TYPE_SAVE) { strcpy(filepath, iron_internal_save_path()); 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 #if defined(IRON_LINUX) || defined(IRON_ANDROID) if (type == IRON_FILE_TYPE_SAVE) { strcpy(filepath, iron_internal_save_path()); strcat(filepath, filename); } else { strcpy(filepath, filename); } #endif #ifdef IRON_WASM strcpy(filepath, filename); #endif #ifdef IRON_WINDOWS // 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); } else if (fileslocation != NULL && type != IRON_FILE_TYPE_SAVE) { strcpy(filepath, fileslocation); strcat(filepath, "/"); strcat(filepath, filename); } #ifdef IRON_WINDOWS 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 #ifdef IRON_WINDOWS // 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 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; return true; } #if !defined(IRON_ANDROID) bool iron_file_reader_open(iron_file_reader_t *reader, const char *filename, int type) { memset(reader, 0, sizeof(*reader)); return iron_internal_file_reader_callback(reader, filename, type) || iron_internal_file_reader_open(reader, filename, type); } #endif void iron_file_reader_set_callback(bool (*callback)(iron_file_reader_t *reader, const char *filename, int type)) { file_reader_callback = callback; } size_t iron_file_reader_read(iron_file_reader_t *reader, void *data, size_t size) { return reader->read(reader, data, size); } bool iron_file_reader_seek(iron_file_reader_t *reader, size_t pos) { return reader->seek(reader, pos); } bool iron_file_reader_close(iron_file_reader_t *reader) { return reader->close(reader); } size_t iron_file_reader_pos(iron_file_reader_t *reader) { return reader->pos(reader); } size_t iron_file_reader_size(iron_file_reader_t *reader) { return reader->size; } float iron_read_f32le(uint8_t *data) { return *(float *)data; } uint64_t iron_read_u64le(uint8_t *data) { return *(uint64_t *)data; } int64_t iron_read_s64le(uint8_t *data) { return *(int64_t *)data; } uint32_t iron_read_u32le(uint8_t *data) { return *(uint32_t *)data; } int32_t iron_read_s32le(uint8_t *data) { return *(int32_t *)data; } uint16_t iron_read_u16le(uint8_t *data) { return *(uint16_t *)data; } int16_t iron_read_s16le(uint8_t *data) { return *(int16_t *)data; } uint8_t iron_read_u8(uint8_t *data) { return *data; } int8_t iron_read_s8(uint8_t *data) { return *(int8_t *)data; } bool iron_file_writer_open(iron_file_writer_t *writer, const char *filepath) { writer->file = NULL; char path[1001]; strcpy(path, iron_internal_save_path()); strcat(path, filepath); #ifdef IRON_WINDOWS 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) { iron_log("Could not open file %s.", filepath); return false; } return true; } void iron_file_writer_close(iron_file_writer_t *writer) { if (writer->file != NULL) { #ifdef IRON_WINDOWS CloseHandle(writer->file); #else fclose((FILE *)writer->file); #endif writer->file = NULL; } } void iron_file_writer_write(iron_file_writer_t *writer, void *data, int size) { #ifdef IRON_WINDOWS DWORD written = 0; WriteFile(writer->file, data, (DWORD)size, &written, NULL); #else fwrite(data, 1, size, (FILE *)writer->file); #endif }