208 lines
5.8 KiB
C++
208 lines
5.8 KiB
C++
#include "utils/Utils.h"
|
|
#include <cstring>
|
|
#include <iterator>
|
|
#include <vector>
|
|
#include <iostream>
|
|
#include <algorithm>
|
|
#include <fstream>
|
|
#include <zip.h>
|
|
#include <cstdlib>
|
|
#include <filesystem>
|
|
#include <string>
|
|
#include <cctype>
|
|
#include <SDL.h>
|
|
|
|
#ifdef __ANDROID__
|
|
#include <android/log.h>
|
|
#endif
|
|
|
|
namespace ZL
|
|
{
|
|
std::string readTextFile(const std::string &filename) {
|
|
#ifdef __ANDROID__
|
|
SDL_RWops* file = SDL_RWFromFile(filename.c_str(), "rb");
|
|
if (!file) {
|
|
#ifdef DEBUG
|
|
__android_log_print(ANDROID_LOG_ERROR, "Utils",
|
|
"Failed to open: %s", filename.c_str());
|
|
#endif
|
|
return "";
|
|
}
|
|
|
|
Sint64 size = SDL_RWsize(file);
|
|
if (size <= 0) {
|
|
SDL_RWclose(file);
|
|
return "";
|
|
}
|
|
|
|
std::string content(size, '\0');
|
|
if (SDL_RWread(file, &content[0], size, 1) != 1) {
|
|
SDL_RWclose(file);
|
|
return "";
|
|
}
|
|
|
|
SDL_RWclose(file);
|
|
return content;
|
|
#else
|
|
std::ifstream f(filename);
|
|
if (!f.is_open()) {
|
|
return "";
|
|
}
|
|
return std::string((std::istreambuf_iterator<char>(f)),
|
|
std::istreambuf_iterator<char>());
|
|
#endif
|
|
}
|
|
|
|
std::vector<char> readFile(const std::string &filename) {
|
|
#ifdef __ANDROID__
|
|
SDL_RWops* file = SDL_RWFromFile(filename.c_str(), "rb");
|
|
if (!file) {
|
|
return {};
|
|
}
|
|
|
|
Sint64 size = SDL_RWsize(file);
|
|
if (size <= 0) {
|
|
SDL_RWclose(file);
|
|
return {};
|
|
}
|
|
|
|
std::vector<char> data(size);
|
|
if (SDL_RWread(file, data.data(), size, 1) != 1) {
|
|
SDL_RWclose(file);
|
|
return {};
|
|
}
|
|
|
|
SDL_RWclose(file);
|
|
return data;
|
|
#else
|
|
std::ifstream file(filename, std::ios::binary | std::ios::ate);
|
|
if (!file) {
|
|
return {};
|
|
}
|
|
|
|
std::streamsize size = file.tellg();
|
|
if (size <= 0) {
|
|
return {};
|
|
}
|
|
|
|
file.seekg(0, std::ios::beg);
|
|
std::vector<char> buffer(size);
|
|
|
|
if (!file.read(buffer.data(), size)) {
|
|
return {};
|
|
}
|
|
|
|
return buffer;
|
|
#endif
|
|
}
|
|
|
|
std::vector<char> readFileFromZIP(const std::string& filename, const std::string& zipfilename) {
|
|
#ifdef EMSCRIPTEN
|
|
int zipErr = 0;
|
|
zip_t* archive = zip_open(zipfilename.c_str(), ZIP_RDONLY, &zipErr);
|
|
if (!archive) {
|
|
std::cout << "Failed to open ZIP: " << zipfilename << " (error code " << zipErr << ")" << std::endl;
|
|
throw std::runtime_error("Failed to open ZIP: " + zipfilename);
|
|
}
|
|
|
|
std::string cleanFilename = filename;
|
|
if (cleanFilename.rfind("./", 0) == 0) cleanFilename = cleanFilename.substr(2);
|
|
|
|
zip_stat_t fileStat;
|
|
zip_stat_init(&fileStat);
|
|
if (zip_stat(archive, cleanFilename.c_str(), 0, &fileStat) != 0 || !(fileStat.valid & ZIP_STAT_SIZE)) {
|
|
zip_close(archive);
|
|
std::cout << "Failed to stat file in ZIP: " << cleanFilename << " in " << zipfilename << std::endl;
|
|
throw std::runtime_error("Can't stat file in ZIP: " + cleanFilename);
|
|
}
|
|
|
|
zip_file_t* zipFile = zip_fopen(archive, cleanFilename.c_str(), 0);
|
|
if (!zipFile) {
|
|
zip_close(archive);
|
|
std::cout << "Failed to open file in ZIP: " << cleanFilename << std::endl;
|
|
throw std::runtime_error("Can't open file in ZIP: " + cleanFilename);
|
|
}
|
|
|
|
std::vector<char> fileData(static_cast<size_t>(fileStat.size));
|
|
zip_int64_t bytesRead = zip_fread(zipFile, fileData.data(), fileStat.size);
|
|
|
|
// Обязательно закрываем всё перед проверкой результата или throw
|
|
zip_fclose(zipFile);
|
|
zip_close(archive);
|
|
|
|
if (bytesRead < 0 || static_cast<zip_uint64_t>(bytesRead) != fileStat.size) {
|
|
std::cout << "Failed to read file from ZIP: " << cleanFilename << " (bytes read: " << bytesRead << ", expected: " << fileStat.size << ")" << std::endl;
|
|
throw std::runtime_error("Error reading data from ZIP: " + cleanFilename);
|
|
}
|
|
|
|
return fileData;
|
|
#else
|
|
|
|
if (zipfilename.empty()) {
|
|
std::cerr << "readFileFromZIP: zipfilename empty" << std::endl;
|
|
return {};
|
|
}
|
|
|
|
int zipErr = 0;
|
|
zip_t* archive = zip_open(zipfilename.c_str(), ZIP_RDONLY, &zipErr);
|
|
if (!archive) {
|
|
std::cerr << "readFileFromZIP: zip_open failed for: " << zipfilename
|
|
<< " (error code " << zipErr << ")" << std::endl;
|
|
return {};
|
|
}
|
|
|
|
std::string cleanFilename = filename;
|
|
if (cleanFilename.rfind("./", 0) == 0) {
|
|
cleanFilename = cleanFilename.substr(2);
|
|
}
|
|
|
|
zip_stat_t fileStat;
|
|
if (zip_stat(archive, cleanFilename.c_str(), 0, &fileStat) != 0) {
|
|
std::cerr << "readFileFromZIP: file not found in ZIP: " << cleanFilename
|
|
<< " in " << zipfilename << std::endl;
|
|
zip_close(archive);
|
|
return {};
|
|
}
|
|
|
|
zip_file_t* zipFile = zip_fopen(archive, cleanFilename.c_str(), 0);
|
|
if (!zipFile) {
|
|
std::cerr << "readFileFromZIP: zip_fopen failed for " << cleanFilename << std::endl;
|
|
zip_close(archive);
|
|
return {};
|
|
}
|
|
|
|
std::vector<char> fileData;
|
|
fileData.resize(static_cast<size_t>(fileStat.size));
|
|
|
|
zip_int64_t readBytes = zip_fread(zipFile, fileData.data(), static_cast<zip_uint64_t>(fileData.size()));
|
|
if (readBytes < 0) {
|
|
std::cerr << "readFileFromZIP: zip_fread failed for " << cleanFilename << std::endl;
|
|
zip_fclose(zipFile);
|
|
zip_close(archive);
|
|
return {};
|
|
}
|
|
|
|
zip_fclose(zipFile);
|
|
zip_close(archive);
|
|
|
|
return fileData;
|
|
#endif
|
|
}
|
|
|
|
bool findString(const char* in, char* list)
|
|
{
|
|
size_t thisLength = strlen(in);
|
|
while (*list != 0)
|
|
{
|
|
size_t length = strcspn(list, " ");
|
|
|
|
if (thisLength == length)
|
|
if (!strncmp(in, list, length))
|
|
return true;
|
|
|
|
list += length;
|
|
list += 1;
|
|
}
|
|
return false;
|
|
}
|
|
}; |