#include "core/jail/jfile.hpp" #include #include #include #include #include #include #include #include #include #include #include #ifndef _WIN32 #include #endif #define DEFAULT_FILENAME "data.jf2" #define DEFAULT_FOLDER "data/" #define CONFIG_FILENAME "config.txt" struct file_t { std::string path; uint32_t size; uint32_t offset; }; std::vector toc; /* El std::map me fa coses rares, vaig a usar un good old std::vector amb una estructura key,value propia i au, que sempre funciona */ struct keyvalue_t { std::string key, value; }; char* resource_filename = NULL; char* resource_folder = NULL; int file_source = SOURCE_FILE; char scratch[255]; static std::string config_folder; std::vector config; void file_setresourcefilename(const char* str) { if (resource_filename != NULL) free(resource_filename); resource_filename = (char*)malloc(strlen(str) + 1); strcpy(resource_filename, str); } void file_setresourcefolder(const char* str) { if (resource_folder != NULL) free(resource_folder); resource_folder = (char*)malloc(strlen(str) + 1); strcpy(resource_folder, str); } void file_setsource(const int src) { file_source = src % 2; // mod 2 so it always is a valid value, 0 (file) or 1 (folder) if (src == SOURCE_FOLDER && resource_folder == NULL) file_setresourcefolder(DEFAULT_FOLDER); } bool file_getdictionary() { if (resource_filename == NULL) file_setresourcefilename(DEFAULT_FILENAME); std::ifstream fi(resource_filename, std::ios::binary); if (!fi.is_open()) return false; char header[4]; fi.read(header, 4); uint32_t num_files, toc_offset; fi.read((char*)&num_files, 4); fi.read((char*)&toc_offset, 4); fi.seekg(toc_offset); for (uint32_t i = 0; i < num_files; ++i) { uint32_t file_offset, file_size; fi.read((char*)&file_offset, 4); fi.read((char*)&file_size, 4); uint8_t path_size; fi.read((char*)&path_size, 1); char file_name[256]; fi.read(file_name, path_size); file_name[path_size] = 0; std::string filename = file_name; toc.push_back({filename, file_size, file_offset}); } fi.close(); return true; } char* file_getfilenamewithfolder(const char* filename) { strcpy(scratch, resource_folder); strcat(scratch, filename); return scratch; } FILE* file_getfilepointer(const char* resourcename, int& filesize, const bool binary) { if (file_source == SOURCE_FILE and toc.size() == 0) { if (not file_getdictionary()) file_setsource(SOURCE_FOLDER); } FILE* f; if (file_source == SOURCE_FILE) { bool found = false; uint32_t count = 0; while (!found && count < toc.size()) { found = (std::string(resourcename) == toc[count].path); if (!found) count++; } if (!found) { perror("El recurs no s'ha trobat en l'arxiu de recursos"); exit(1); } filesize = toc[count].size; f = fopen(resource_filename, binary ? "rb" : "r"); if (not f) { perror("No s'ha pogut obrir l'arxiu de recursos"); exit(1); } fseek(f, toc[count].offset, SEEK_SET); } else { f = fopen(file_getfilenamewithfolder(resourcename), binary ? "rb" : "r"); fseek(f, 0, SEEK_END); filesize = ftell(f); fseek(f, 0, SEEK_SET); } return f; } char* file_getfilebuffer(const char* resourcename, int& filesize, const bool zero_terminate) { FILE* f = file_getfilepointer(resourcename, filesize, true); char* buffer = (char*)malloc(zero_terminate ? filesize : filesize + 1); fread(buffer, filesize, 1, f); if (zero_terminate) buffer[filesize] = 0; fclose(f); return buffer; } // Crea la carpeta del sistema donde guardar datos. // Acepta rutas con subdirectorios (ej: "jailgames/aee") y crea toda la jerarquía. void file_setconfigfolder(const char* foldername) { #ifdef _WIN32 config_folder = std::string(getenv("APPDATA")) + "/" + foldername; #elif __APPLE__ struct passwd* pw = getpwuid(getuid()); const char* homedir = pw->pw_dir; config_folder = std::string(homedir) + "/Library/Application Support/" + foldername; #elif __linux__ struct passwd* pw = getpwuid(getuid()); const char* homedir = pw->pw_dir; config_folder = std::string(homedir) + "/.config/" + foldername; #endif std::filesystem::create_directories(config_folder); } const char* file_getconfigfolder() { static std::string folder; folder = config_folder + "/"; return folder.c_str(); } void file_loadconfigvalues() { config.clear(); std::string config_file = config_folder + "/config.txt"; FILE* f = fopen(config_file.c_str(), "r"); if (!f) return; char line[1024]; while (fgets(line, sizeof(line), f)) { char* value = strchr(line, '='); if (value) { *value = '\0'; value++; value[strlen(value) - 1] = '\0'; config.push_back({line, value}); } } fclose(f); } void file_saveconfigvalues() { std::string config_file = config_folder + "/config.txt"; FILE* f = fopen(config_file.c_str(), "w"); if (f) { for (auto pair : config) { fprintf(f, "%s=%s\n", pair.key.c_str(), pair.value.c_str()); } fclose(f); } } const char* file_getconfigvalue(const char* key) { if (config.empty()) file_loadconfigvalues(); for (auto pair : config) { if (pair.key == std::string(key)) { strcpy(scratch, pair.value.c_str()); return scratch; } } return NULL; } void file_setconfigvalue(const char* key, const char* value) { if (config.empty()) file_loadconfigvalues(); for (auto& pair : config) { if (pair.key == std::string(key)) { pair.value = value; file_saveconfigvalues(); return; } } config.push_back({key, value}); file_saveconfigvalues(); return; }