Files
dilemmaker/source/japi/file.cpp
Raimon Zamora 9eae2aa785 - [FIX] uint a unsigned int per als compiladors quisquillosos
- [FIX] return true en funcions inacabades, per als mateixos de dalt
2025-11-18 08:47:22 +01:00

276 lines
6.7 KiB
C++

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include "file.h"
#include <sys/stat.h>
#include <unistd.h>
#include <iostream>
#include <fstream>
#include <filesystem>
#include <string>
#include <vector>
#ifndef _WIN32
#include <pwd.h>
#endif
#define DEFAULT_FILENAME "data.jf2"
#define DEFAULT_FOLDER "data/"
#define CONFIG_FILENAME "config.txt"
namespace file
{
struct file_t
{
std::string path;
uint32_t size;
uint32_t offset;
};
std::vector<file_t> 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<keyvalue_t> config;
void setResourceFilename(const char *str) {
if (resource_filename != NULL) free(resource_filename);
resource_filename = (char*)malloc(strlen(str)+1);
strcpy(resource_filename, str);
}
void setResourceFolder(const char *str) {
if (resource_folder != NULL) free(resource_folder);
resource_folder = (char*)malloc(strlen(str)+1);
strcpy(resource_folder, str);
}
void 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) setResourceFolder(DEFAULT_FOLDER);
}
bool getDictionary() {
if (resource_filename == NULL) 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 (unsigned int 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[path_size+1];
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 *getFilenameWithFolder(const char* filename) {
strcpy(scratch, resource_folder);
strcat(scratch, filename);
return scratch;
}
FILE *getFilePointer(const char *resourcename, int& filesize, const bool binary) {
if (file_source==SOURCE_FILE and toc.size()==0) {
if (not getDictionary()) 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(getFilenameWithFolder(resourcename), binary?"rb":"r");
fseek(f, 0, SEEK_END);
filesize = ftell(f);
fseek(f, 0, SEEK_SET);
}
return f;
}
char *getFileBuffer(const char *resourcename, int& filesize, const bool zero_terminate) {
FILE *f = getFilePointer(resourcename, filesize, true);
char* buffer = (char*)malloc(zero_terminate?filesize+1:filesize);
fread(buffer, filesize, 1, f);
if (zero_terminate) buffer[filesize]=0;
fclose(f);
return buffer;
}
// Crea la carpeta del sistema donde guardar datos
void 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) + "/." + foldername;
#endif
struct stat st = {0};
if (stat(config_folder.c_str(), &st) == -1)
{
#ifdef _WIN32
int ret = mkdir(config_folder.c_str());
#else
int ret = mkdir(config_folder.c_str(), S_IRWXU);
#endif
if (ret == -1)
{
printf("ERROR CREATING CONFIG FOLDER.");
exit(EXIT_FAILURE);
}
}
}
const char *getConfigFolder() {
std::string folder = config_folder + "/";
return folder.c_str();
}
void 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 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* getConfigValueString(const char *key) {
if (config.empty()) loadConfigValues();
for (auto pair : config) {
if (pair.key == std::string(key)) {
strcpy(scratch, pair.value.c_str());
return scratch;
}
}
return NULL;
}
const int getConfigValueInteger(const char *key, const int default_value)
{
const char* value = getConfigValueString(key);
if (!value) return default_value;
return atoi(value);
}
const float getConfigValueFloat(const char *key, const float default_value)
{
const char* value = getConfigValueString(key);
if (!value) return default_value;
return atof(value);
}
const bool getConfigValueBool(const char *key, const bool default_value)
{
const char* value = getConfigValueString(key);
if (!value) return default_value;
return strcmp(value, "true")==0?true:false;
}
void setConfigValueString(const char* key, const char* value) {
if (config.empty()) loadConfigValues();
for (auto &pair : config) {
if (pair.key == std::string(key)) {
pair.value = value;
saveConfigValues();
return;
}
}
config.push_back({key, value});
saveConfigValues();
return;
}
void setConfigValueInteger(const char* key, const int value)
{
char tmp[256];
sprintf(tmp, "%i", value);
setConfigValueString(key, tmp);
}
void setConfigValueFloat(const char* key, const float value)
{
char tmp[256];
sprintf(tmp, "%.2f", value);
setConfigValueString(key, tmp);
}
void setConfigValueBool(const char* key, const bool value)
{
setConfigValueString(key, value?"true":"false");
}
}