BFR 2 (Big Fucking Restructureixon) (dos)
Este es el primer commit de la reestructuració. En caso de pánico, tornar al commit anterior. - [FIX] Llevada basura varia (pos no en queda...) - [NEW] mogut el codi font a ./source/ - [NEW] lagueirtofile nou per a compilar en windows y linux, release i debug. mac res, que no se ni si funciona lagueirto. - [NEW] WARNING!!! make ja no funciona. Mantinc encara el Makefile per a referència.
This commit is contained in:
384
source/jfile.cpp
Normal file
384
source/jfile.cpp
Normal file
@@ -0,0 +1,384 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include "jfile.h"
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
|
||||
#include <algorithm>
|
||||
#include <dirent.h> // Para opendir/readdir en SOURCE_FOLDER
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <pwd.h>
|
||||
#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<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 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 = (char*)malloc(path_size+1);
|
||||
fi.read( file_name, path_size );
|
||||
file_name[path_size] = 0;
|
||||
std::string filename = file_name;
|
||||
free(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;
|
||||
}
|
||||
|
||||
FILE *file_getfilepointerex(const char *filename, int& filesize, const bool binary) {
|
||||
|
||||
FILE *f;
|
||||
f = fopen(filename, binary?"rb":"r");
|
||||
fseek(f, 0, SEEK_END);
|
||||
filesize = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
return f;
|
||||
}
|
||||
|
||||
char *file_getfilebufferex(const char *filename, int& filesize, const bool zero_terminate) {
|
||||
FILE *f = file_getfilepointerex(filename, 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
|
||||
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) + "/." + foldername;
|
||||
config_folder = std::string(homedir) + "/.config/jailgames/" + foldername;
|
||||
|
||||
{
|
||||
// Intenta crear ".config", per si no existeix
|
||||
std::string config_base_folder = std::string(homedir) + "/.config";
|
||||
int ret = mkdir(config_base_folder.c_str(), S_IRWXU);
|
||||
if (ret == -1 && errno != EEXIST)
|
||||
{
|
||||
printf("ERROR CREATING CONFIG BASE FOLDER.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
{
|
||||
// Intenta crear ".config/jailgames", per si no existeix
|
||||
std::string config_base_folder = std::string(homedir) + "/.config/jailgames";
|
||||
int ret = mkdir(config_base_folder.c_str(), S_IRWXU);
|
||||
if (ret == -1 && errno != EEXIST)
|
||||
{
|
||||
printf("ERROR CREATING CONFIG BASE FOLDER.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
#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 *file_getconfigfolder() {
|
||||
static std::string 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;
|
||||
}
|
||||
|
||||
bool file_createFolder(const char* name) {
|
||||
char tmp[256];
|
||||
strcpy(tmp, "./");
|
||||
strcat(tmp, name);
|
||||
#ifdef _WIN32
|
||||
return mkdir(tmp)==0;
|
||||
#else
|
||||
return mkdir(tmp, 0755)==0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool has_extension(const std::string &name, const char *ext)
|
||||
{
|
||||
if (!ext) return true; // sin filtro
|
||||
|
||||
std::string e = ext;
|
||||
std::string suffix = "." + e;
|
||||
|
||||
if (name.size() < suffix.size())
|
||||
return false;
|
||||
|
||||
return (name.compare(name.size() - suffix.size(), suffix.size(), suffix) == 0);
|
||||
}
|
||||
|
||||
std::vector<std::string> file_listdir(const char *folder, const char *extension)
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
std::string base(folder);
|
||||
|
||||
// Normalizar: quitar "/" final si existe
|
||||
if (!base.empty() && base.back() == '/')
|
||||
base.pop_back();
|
||||
|
||||
// -------------------------------
|
||||
// 1. MODO: ARCHIVOS SUELTOS
|
||||
// -------------------------------
|
||||
if (file_source == SOURCE_FOLDER)
|
||||
{
|
||||
std::string fullpath = std::string(resource_folder) + base;
|
||||
|
||||
DIR *dir = opendir(fullpath.c_str());
|
||||
if (!dir)
|
||||
return result;
|
||||
|
||||
struct dirent *entry;
|
||||
while ((entry = readdir(dir)) != nullptr)
|
||||
{
|
||||
std::string name = entry->d_name;
|
||||
|
||||
// Ignorar "." y ".."
|
||||
if (name == "." || name == "..")
|
||||
continue;
|
||||
|
||||
// Ignorar subdirectorios
|
||||
std::string full = fullpath + "/" + name;
|
||||
DIR *test = opendir(full.c_str());
|
||||
if (test)
|
||||
{
|
||||
closedir(test);
|
||||
continue; // es un directorio
|
||||
}
|
||||
|
||||
// Filtrar por extensión
|
||||
if (!has_extension(name, extension))
|
||||
continue;
|
||||
|
||||
result.push_back(name);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
return result;
|
||||
}
|
||||
|
||||
// -------------------------------
|
||||
// 2. MODO: ARCHIVO CONTENEDOR
|
||||
// -------------------------------
|
||||
if (file_source == SOURCE_FILE)
|
||||
{
|
||||
std::string prefix = base + "/";
|
||||
|
||||
for (auto &f : toc)
|
||||
{
|
||||
const std::string &path = f.path;
|
||||
|
||||
// Debe empezar por "folder/"
|
||||
if (path.compare(0, prefix.size(), prefix) != 0)
|
||||
continue;
|
||||
|
||||
// Extraer la parte después de "folder/"
|
||||
std::string rest = path.substr(prefix.size());
|
||||
|
||||
// Ignorar subdirectorios
|
||||
if (rest.find('/') != std::string::npos)
|
||||
continue;
|
||||
|
||||
// Filtrar por extensión
|
||||
if (!has_extension(rest, extension))
|
||||
continue;
|
||||
|
||||
result.push_back(rest);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
Reference in New Issue
Block a user