diff --git a/core/include/retroforge/identification/ConsoleIdentifier.hpp b/core/include/retroforge/identification/ConsoleIdentifier.hpp new file mode 100644 index 0000000..68f7c72 --- /dev/null +++ b/core/include/retroforge/identification/ConsoleIdentifier.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include "retroforge/identification/IConsoleDetector.hpp" +#include "retroforge/io/BinaryFileReader.hpp" + +#include + +namespace retroforge::identification { + +class ConsoleIdentifier { + public: + void register_detector(std::unique_ptr detector); + Console identify(retroforge::io::BinaryFileReader &leitor) const; + + private: + static constexpr size_t TAMANHO_CABECALHO = 32; + std::vector> detectores_; +}; + +} // namespace retroforge::identification diff --git a/core/include/retroforge/identification/IConsoleDetector.hpp b/core/include/retroforge/identification/IConsoleDetector.hpp new file mode 100644 index 0000000..333d6e1 --- /dev/null +++ b/core/include/retroforge/identification/IConsoleDetector.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include "retroforge/models/Console.hpp" + +#include +#include + +namespace retroforge::identification { + +using retroforge::models::Console; + +class IConsoleDetector { + public: + virtual ~IConsoleDetector() = default; + virtual bool matches(const std::vector &cabecalho) const = 0; + virtual Console console() const = 0; +}; + +} // namespace retroforge::identification diff --git a/core/include/retroforge/identification/detectors/GameCubeDetector.hpp b/core/include/retroforge/identification/detectors/GameCubeDetector.hpp new file mode 100644 index 0000000..71da349 --- /dev/null +++ b/core/include/retroforge/identification/detectors/GameCubeDetector.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "retroforge/identification/IConsoleDetector.hpp" + +namespace retroforge::identification::detectors { + +class GameCubeDetector : public IConsoleDetector { + public: + bool matches(const std::vector &cabecalho) const override; + Console console() const override { return Console::GameCube; } +}; + +} // namespace retroforge::identification::detectors diff --git a/core/include/retroforge/identification/detectors/Ps1Detector.hpp b/core/include/retroforge/identification/detectors/Ps1Detector.hpp new file mode 100644 index 0000000..0c25ee6 --- /dev/null +++ b/core/include/retroforge/identification/detectors/Ps1Detector.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "retroforge/identification/IConsoleDetector.hpp" + +namespace retroforge::identification::detectors { + +class Ps1Detector : public IConsoleDetector { + public: + bool matches(const std::vector &cabecalho) const override; + Console console() const override { return Console::PS1; } +}; + +} // namespace retroforge::identification::detectors diff --git a/core/include/retroforge/io/BinaryFileReader.hpp b/core/include/retroforge/io/BinaryFileReader.hpp index 0248c54..1351f35 100644 --- a/core/include/retroforge/io/BinaryFileReader.hpp +++ b/core/include/retroforge/io/BinaryFileReader.hpp @@ -5,21 +5,21 @@ #include #include -namespace retroforge ::io { +namespace retroforge::io { class BinaryFileReader { public: - explicit BinaryFileReader(const std ::string &caminho); + explicit BinaryFileReader(const std::string &caminho); - std::vector read_at(std ::streamoff offset, size_t quantidade); + std::vector read_at(std::streamoff offset, size_t quantidade); std::vector read_next_chunk(size_t tamanho_maximo); bool eof() const; - std ::uintmax_t tamanho_total() const { return tamanho_total_; } + std::uintmax_t tamanho_total() const { return tamanho_total_; } private: std::ifstream arquivo_; std::uintmax_t tamanho_total_; }; -} // namespace retroforge::io \ No newline at end of file +} // namespace retroforge::io diff --git a/core/include/retroforge/models/Console.hpp b/core/include/retroforge/models/Console.hpp new file mode 100644 index 0000000..c64c74a --- /dev/null +++ b/core/include/retroforge/models/Console.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace retroforge::models { + +enum class Console { PS1, PS2, PSP, GameCube, Dreamcast, MegaDrive, SNES, Desconhecido }; +} // namespace retroforge::models diff --git a/core/include/retroforge/process/ExternalProcessHandle.hpp b/core/include/retroforge/process/ExternalProcessHandle.hpp index fc689c0..cf6c383 100644 --- a/core/include/retroforge/process/ExternalProcessHandle.hpp +++ b/core/include/retroforge/process/ExternalProcessHandle.hpp @@ -22,4 +22,4 @@ class ExternalProcessHandle { std::unique_ptr handle_; }; -} // namespace retroforge::process \ No newline at end of file +} // namespace retroforge::process diff --git a/core/src/identification/ConsoleIdentifier.cpp b/core/src/identification/ConsoleIdentifier.cpp new file mode 100644 index 0000000..f1a4fd0 --- /dev/null +++ b/core/src/identification/ConsoleIdentifier.cpp @@ -0,0 +1,21 @@ +#include "retroforge/identification/ConsoleIdentifier.hpp" + +namespace retroforge::identification { + +void ConsoleIdentifier::register_detector(std::unique_ptr detector) { + detectores_.push_back(std::move(detector)); +} + +Console ConsoleIdentifier::identify(retroforge::io::BinaryFileReader &leitor) const { + auto cabecalho = leitor.read_at(0, TAMANHO_CABECALHO); + + for (const auto &detector : detectores_) { + if (detector->matches(cabecalho)) { + return detector->console(); + } + } + + return Console::Desconhecido; +} + +} // namespace retroforge::identification diff --git a/core/src/identification/detectors/GameCubeDetector.cpp b/core/src/identification/detectors/GameCubeDetector.cpp new file mode 100644 index 0000000..cf687c9 --- /dev/null +++ b/core/src/identification/detectors/GameCubeDetector.cpp @@ -0,0 +1,21 @@ +#include "retroforge/identification/detectors/GameCubeDetector.hpp" + +namespace retroforge::identification::detectors { + +bool GameCubeDetector::matches(const std::vector &cabecalho) const { + constexpr size_t OFFSET_ASSINATURA = 0x1C; + constexpr uint32_t MAGIC_GAMECUBE = 0xC2339F3D; + + if (cabecalho.size() < OFFSET_ASSINATURA + 4) { + return false; + } + + uint32_t valor = (static_cast(cabecalho[OFFSET_ASSINATURA]) << 24) | + (static_cast(cabecalho[OFFSET_ASSINATURA + 1]) << 16) | + (static_cast(cabecalho[OFFSET_ASSINATURA + 2]) << 8) | + (static_cast(cabecalho[OFFSET_ASSINATURA + 3])); + + return valor == MAGIC_GAMECUBE; +} + +} // namespace retroforge::identification::detectors diff --git a/core/src/identification/detectors/Ps1Detector.cpp b/core/src/identification/detectors/Ps1Detector.cpp new file mode 100644 index 0000000..b9d7cb2 --- /dev/null +++ b/core/src/identification/detectors/Ps1Detector.cpp @@ -0,0 +1,22 @@ +#include "retroforge/identification/detectors/Ps1Detector.hpp" +#include +#include + +namespace retroforge::identification::detectors { + +bool Ps1Detector::matches(const std::vector &cabecalho) const { + if (cabecalho.empty()) { + return false; + } + + std::string conteudo(cabecalho.begin(), cabecalho.end()); + + std::transform(conteudo.begin(), conteudo.end(), conteudo.begin(), ::toupper); + + bool temFile = conteudo.find("FILE") != std::string::npos; + bool temMode2 = conteudo.find("MODE2/2352") != std::string::npos; + + return temFile && temMode2; +} + +} // namespace retroforge::identification::detectors diff --git a/core/src/io/BinaryFileReader.cpp b/core/src/io/BinaryFileReader.cpp index b9dc63b..a2f256d 100644 --- a/core/src/io/BinaryFileReader.cpp +++ b/core/src/io/BinaryFileReader.cpp @@ -40,4 +40,4 @@ std::vector BinaryFileReader::read_next_chunk(size_t tamanho_maximo) { bool BinaryFileReader::eof() const { return arquivo_.eof(); } -} // namespace retroforge::io \ No newline at end of file +} // namespace retroforge::io diff --git a/core/src/process/ExternalProcessHandle.cpp b/core/src/process/ExternalProcessHandle.cpp index cc15137..1e399c9 100644 --- a/core/src/process/ExternalProcessHandle.cpp +++ b/core/src/process/ExternalProcessHandle.cpp @@ -26,4 +26,4 @@ bool ExternalProcessHandle::read_line(std::string &linha_destino) { return true; } -} // namespace retroforge::process \ No newline at end of file +} // namespace retroforge::process