diff --git a/source/manage_hiscore_table.cpp b/source/manage_hiscore_table.cpp index 834db19..43c8ef8 100644 --- a/source/manage_hiscore_table.cpp +++ b/source/manage_hiscore_table.cpp @@ -3,6 +3,7 @@ #include // Para SDL_ReadIO, SDL_WriteIO, SDL_CloseIO, SDL_GetError, SDL_IOFromFile, SDL_LogError, SDL_LogCategory, SDL_LogInfo #include // Para __sort_fn, sort +#include // Para array #include // Para identity #include // Para distance #include // Para __find_if_fn, find_if @@ -109,117 +110,41 @@ auto ManageHiScoreTable::loadFromFile(const std::string& file_path) -> bool { return false; } - Table temp_table; // Tabla temporal para no corromper la actual si hay errores - bool success = true; - - // Validación 1: Verificar magic number "CCAE" - char magic[4]; - if (SDL_ReadIO(file, magic, 4) != 4 || magic[0] != 'C' || magic[1] != 'C' || magic[2] != 'A' || magic[3] != 'E') { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Invalid magic number in %s - file may be corrupted or old format", getFileName(file_path).c_str()); + // Validar header (magic number + version + table size) + if (!validateMagicNumber(file, file_path)) { SDL_CloseIO(file); clear(); return false; } - // Validación 2: Verificar versión del formato - int version = 0; - if (SDL_ReadIO(file, &version, sizeof(int)) != sizeof(int)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Cannot read version in %s", getFileName(file_path).c_str()); + if (!validateVersion(file, file_path)) { SDL_CloseIO(file); clear(); return false; } - if (version != FILE_VERSION) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Unsupported file version %d in %s (expected %d)", version, getFileName(file_path).c_str(), FILE_VERSION); - SDL_CloseIO(file); - clear(); - return false; - } - - // Validación 3: Leer y validar tamaño de la tabla int table_size = 0; - if (SDL_ReadIO(file, &table_size, sizeof(int)) != sizeof(int)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Cannot read table size in %s", getFileName(file_path).c_str()); + if (!readTableSize(file, file_path, table_size)) { SDL_CloseIO(file); clear(); return false; } - if (table_size < 0 || table_size > MAX_TABLE_SIZE) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Invalid table size %d in %s (expected 0-%d)", table_size, getFileName(file_path).c_str(), MAX_TABLE_SIZE); - SDL_CloseIO(file); - clear(); - return false; - } - - // Leer cada entrada con validaciones + // Leer todas las entradas + Table temp_table; + bool success = true; for (int i = 0; i < table_size; ++i) { HiScoreEntry entry; - - // Validación 4: Leer y validar puntuación - if (SDL_ReadIO(file, &entry.score, sizeof(int)) != sizeof(int)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Cannot read score for entry %d in %s", i, getFileName(file_path).c_str()); + if (!readEntry(file, file_path, i, entry)) { success = false; break; } - - if (entry.score < 0 || entry.score > MAX_SCORE) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Invalid score %d for entry %d in %s", entry.score, i, getFileName(file_path).c_str()); - success = false; - break; - } - - // Validación 5: Leer y validar tamaño del nombre - int name_size = 0; - if (SDL_ReadIO(file, &name_size, sizeof(int)) != sizeof(int)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Cannot read name size for entry %d in %s", i, getFileName(file_path).c_str()); - success = false; - break; - } - - if (name_size < 0 || name_size > MAX_NAME_SIZE) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Invalid name size %d for entry %d in %s", name_size, i, getFileName(file_path).c_str()); - success = false; - break; - } - - // Leer el nombre - std::vector name_buffer(name_size + 1); - if (SDL_ReadIO(file, name_buffer.data(), name_size) != static_cast(name_size)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Cannot read name for entry %d in %s", i, getFileName(file_path).c_str()); - success = false; - break; - } - name_buffer[name_size] = '\0'; - entry.name = std::string(name_buffer.data()); - - // Validación 6: Leer one_credit_complete - int occ_value = 0; - if (SDL_ReadIO(file, &occ_value, sizeof(int)) != sizeof(int)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Cannot read one_credit_complete for entry %d in %s", i, getFileName(file_path).c_str()); - success = false; - break; - } - entry.one_credit_complete = (occ_value != 0); - temp_table.push_back(entry); } - // Validación 7: Verificar checksum + // Verificar checksum if (success) { - unsigned int stored_checksum = 0; - if (SDL_ReadIO(file, &stored_checksum, sizeof(unsigned int)) != sizeof(unsigned int)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Cannot read checksum in %s", getFileName(file_path).c_str()); - success = false; - } else { - unsigned int calculated_checksum = calculateChecksum(temp_table); - if (stored_checksum != calculated_checksum) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Checksum mismatch in %s (stored: 0x%08X, calculated: 0x%08X) - file is corrupted", - getFileName(file_path).c_str(), stored_checksum, calculated_checksum); - success = false; - } - } + success = verifyChecksum(file, file_path, temp_table); } SDL_CloseIO(file); @@ -236,6 +161,104 @@ auto ManageHiScoreTable::loadFromFile(const std::string& file_path) -> bool { return success; } +// Métodos auxiliares privados para loadFromFile + +auto ManageHiScoreTable::validateMagicNumber(SDL_IOStream* file, const std::string& file_path) -> bool { + std::array magic; + if (SDL_ReadIO(file, magic.data(), 4) != 4 || magic[0] != 'C' || magic[1] != 'C' || magic[2] != 'A' || magic[3] != 'E') { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Invalid magic number in %s - file may be corrupted or old format", getFileName(file_path).c_str()); + return false; + } + return true; +} + +auto ManageHiScoreTable::validateVersion(SDL_IOStream* file, const std::string& file_path) -> bool { + int version = 0; + if (SDL_ReadIO(file, &version, sizeof(int)) != sizeof(int)) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Cannot read version in %s", getFileName(file_path).c_str()); + return false; + } + + if (version != FILE_VERSION) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Unsupported file version %d in %s (expected %d)", version, getFileName(file_path).c_str(), FILE_VERSION); + return false; + } + return true; +} + +auto ManageHiScoreTable::readTableSize(SDL_IOStream* file, const std::string& file_path, int& table_size) -> bool { + if (SDL_ReadIO(file, &table_size, sizeof(int)) != sizeof(int)) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Cannot read table size in %s", getFileName(file_path).c_str()); + return false; + } + + if (table_size < 0 || table_size > MAX_TABLE_SIZE) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Invalid table size %d in %s (expected 0-%d)", table_size, getFileName(file_path).c_str(), MAX_TABLE_SIZE); + return false; + } + return true; +} + +auto ManageHiScoreTable::readEntry(SDL_IOStream* file, const std::string& file_path, int index, HiScoreEntry& entry) -> bool { + // Leer y validar puntuación + if (SDL_ReadIO(file, &entry.score, sizeof(int)) != sizeof(int)) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Cannot read score for entry %d in %s", index, getFileName(file_path).c_str()); + return false; + } + + if (entry.score < 0 || entry.score > MAX_SCORE) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Invalid score %d for entry %d in %s", entry.score, index, getFileName(file_path).c_str()); + return false; + } + + // Leer y validar tamaño del nombre + int name_size = 0; + if (SDL_ReadIO(file, &name_size, sizeof(int)) != sizeof(int)) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Cannot read name size for entry %d in %s", index, getFileName(file_path).c_str()); + return false; + } + + if (name_size < 0 || name_size > MAX_NAME_SIZE) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Invalid name size %d for entry %d in %s", name_size, index, getFileName(file_path).c_str()); + return false; + } + + // Leer el nombre + std::vector name_buffer(name_size + 1); + if (SDL_ReadIO(file, name_buffer.data(), name_size) != static_cast(name_size)) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Cannot read name for entry %d in %s", index, getFileName(file_path).c_str()); + return false; + } + name_buffer[name_size] = '\0'; + entry.name = std::string(name_buffer.data()); + + // Leer one_credit_complete + int occ_value = 0; + if (SDL_ReadIO(file, &occ_value, sizeof(int)) != sizeof(int)) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Cannot read one_credit_complete for entry %d in %s", index, getFileName(file_path).c_str()); + return false; + } + entry.one_credit_complete = (occ_value != 0); + + return true; +} + +auto ManageHiScoreTable::verifyChecksum(SDL_IOStream* file, const std::string& file_path, const Table& temp_table) -> bool { + unsigned int stored_checksum = 0; + if (SDL_ReadIO(file, &stored_checksum, sizeof(unsigned int)) != sizeof(unsigned int)) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Cannot read checksum in %s", getFileName(file_path).c_str()); + return false; + } + + unsigned int calculated_checksum = calculateChecksum(temp_table); + if (stored_checksum != calculated_checksum) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Checksum mismatch in %s (stored: 0x%08X, calculated: 0x%08X) - file is corrupted", + getFileName(file_path).c_str(), stored_checksum, calculated_checksum); + return false; + } + return true; +} + // Calcula checksum de la tabla auto ManageHiScoreTable::calculateChecksum(const Table& table) -> unsigned int { unsigned int checksum = 0x12345678; // Magic seed @@ -250,7 +273,7 @@ auto ManageHiScoreTable::calculateChecksum(const Table& table) -> unsigned int { } // Checksum de one_credit_complete - checksum = ((checksum << 5) + checksum) + (entry.one_credit_complete ? 1u : 0u); + checksum = ((checksum << 5) + checksum) + (entry.one_credit_complete ? 1U : 0U); } return checksum; @@ -263,8 +286,8 @@ auto ManageHiScoreTable::saveToFile(const std::string& file_path) -> bool { if (file != nullptr) { // Escribe magic number "CCAE" - const char magic[4] = {'C', 'C', 'A', 'E'}; - SDL_WriteIO(file, magic, 4); + constexpr std::array MAGIC = {'C', 'C', 'A', 'E'}; + SDL_WriteIO(file, MAGIC.data(), 4); // Escribe versión del formato int version = FILE_VERSION; diff --git a/source/manage_hiscore_table.hpp b/source/manage_hiscore_table.hpp index ff63cf1..2e99643 100644 --- a/source/manage_hiscore_table.hpp +++ b/source/manage_hiscore_table.hpp @@ -1,5 +1,7 @@ #pragma once +#include // Para SDL_IOStream + #include // Para std::string #include // Para std::vector @@ -45,6 +47,13 @@ class ManageHiScoreTable { Table& table_; // Referencia a la tabla con los records // --- Métodos privados --- - void sort(); // Ordena la tabla + void sort(); // Ordena la tabla static auto calculateChecksum(const Table& table) -> unsigned int; // Calcula checksum de la tabla + + // Métodos auxiliares para loadFromFile + auto validateMagicNumber(SDL_IOStream* file, const std::string& file_path) -> bool; + auto validateVersion(SDL_IOStream* file, const std::string& file_path) -> bool; + auto readTableSize(SDL_IOStream* file, const std::string& file_path, int& table_size) -> bool; + auto readEntry(SDL_IOStream* file, const std::string& file_path, int index, HiScoreEntry& entry) -> bool; + auto verifyChecksum(SDL_IOStream* file, const std::string& file_path, const Table& temp_table) -> bool; }; \ No newline at end of file diff --git a/source/resource_loader.cpp b/source/resource_loader.cpp index 8e7df94..dc5594d 100644 --- a/source/resource_loader.cpp +++ b/source/resource_loader.cpp @@ -39,7 +39,7 @@ auto ResourceLoader::initialize(const std::string& pack_file, bool enable_fallba } delete resource_pack_; resource_pack_ = nullptr; - std::cerr << "Failed to load resource pack: " << pack_file << std::endl; + std::cerr << "Failed to load resource pack: " << pack_file << '\n'; } if (fallback_to_files_) { diff --git a/source/resource_loader.hpp b/source/resource_loader.hpp index e13185d..2446470 100644 --- a/source/resource_loader.hpp +++ b/source/resource_loader.hpp @@ -34,6 +34,6 @@ class ResourceLoader { [[nodiscard]] auto getAvailableResources() const -> std::vector; private: - auto loadFromFile(const std::string& filename) -> std::vector; + static auto loadFromFile(const std::string& filename) -> std::vector; static auto getDataPath(const std::string& filename) -> std::string; };