2017-03-26 16:38:55 +00:00
|
|
|
#ifndef INCLUDED_GAMELOADER_H
|
|
|
|
#define INCLUDED_GAMELOADER_H
|
|
|
|
|
|
|
|
#include "Util/NewConfig.h"
|
|
|
|
#include "Pkgs/unzip.h"
|
|
|
|
#include "Game.h"
|
|
|
|
#include "ROMSet.h"
|
|
|
|
#include <map>
|
|
|
|
#include <set>
|
|
|
|
|
|
|
|
class GameLoader
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
// Describes a file node in the game XML
|
|
|
|
struct File
|
|
|
|
{
|
|
|
|
typedef std::shared_ptr<File> ptr_t;
|
|
|
|
uint32_t offset;
|
|
|
|
std::string filename;
|
|
|
|
uint32_t crc32;
|
|
|
|
bool has_crc32;
|
|
|
|
static ptr_t Create(const GameLoader &loader, const Util::Config::Node &file_node);
|
|
|
|
bool Matches(const std::string &filename, uint32_t crc32) const;
|
2017-04-03 01:03:38 +00:00
|
|
|
bool operator==(const File &rhs) const;
|
2017-03-26 16:38:55 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// Describes a region node in the game XML
|
|
|
|
struct Region
|
|
|
|
{
|
|
|
|
typedef std::shared_ptr<Region> ptr_t;
|
|
|
|
std::string region_name;
|
|
|
|
size_t stride;
|
|
|
|
size_t chunk_size;
|
|
|
|
bool byte_swap;
|
2017-03-27 02:02:22 +00:00
|
|
|
std::vector<File::ptr_t> files;
|
2017-03-26 16:38:55 +00:00
|
|
|
static ptr_t Create(const GameLoader &loader, const Util::Config::Node ®ion_node);
|
2017-04-03 01:03:38 +00:00
|
|
|
bool AttribsMatch(const ptr_t &other) const;
|
|
|
|
bool FindFileIndexByOffset(size_t *idx, uint32_t offset) const;
|
2017-03-26 16:38:55 +00:00
|
|
|
};
|
|
|
|
|
2017-04-08 18:30:29 +00:00
|
|
|
// Game information from XML
|
|
|
|
std::map<std::string, Game> m_game_info_by_game;
|
|
|
|
|
|
|
|
// ROM patches by game and by region. Cannot place into Region because child
|
|
|
|
// sets do not inherit parent patches, which may complicate merging.
|
|
|
|
typedef std::map<std::string, std::vector<ROM::BigEndianPatch>> PatchesByRegion_t;
|
|
|
|
std::map<std::string, PatchesByRegion_t> m_patches_by_game;
|
2017-03-26 16:38:55 +00:00
|
|
|
|
|
|
|
// Parsed XML
|
|
|
|
typedef std::map<std::string, Region::ptr_t> RegionsByName_t;
|
2017-04-03 01:03:38 +00:00
|
|
|
std::map<std::string, RegionsByName_t> m_regions_by_game; // all games as defined in XML
|
|
|
|
std::map<std::string, RegionsByName_t> m_regions_by_merged_game; // only child sets merged w/ parents
|
2017-03-26 16:38:55 +00:00
|
|
|
std::string m_xml_filename;
|
|
|
|
|
2017-04-08 18:30:29 +00:00
|
|
|
// Single compressed file inside of a zip archive
|
2017-03-27 02:02:22 +00:00
|
|
|
struct ZippedFile
|
|
|
|
{
|
2017-04-03 01:03:38 +00:00
|
|
|
unzFile zf = nullptr;
|
|
|
|
std::string zipfilename; // zip archive
|
|
|
|
std::string filename; // file inside the zip archive
|
|
|
|
size_t uncompressed_size = 0;
|
|
|
|
uint32_t crc32 = 0;
|
2017-03-27 02:02:22 +00:00
|
|
|
};
|
|
|
|
|
2017-04-08 18:30:29 +00:00
|
|
|
// Multiple zip archives
|
2017-03-27 02:02:22 +00:00
|
|
|
struct ZipArchive
|
|
|
|
{
|
2017-04-03 01:03:38 +00:00
|
|
|
std::vector<std::string> zipfilenames;
|
|
|
|
std::vector<unzFile> zfs;
|
2017-03-27 02:02:22 +00:00
|
|
|
std::map<uint32_t, ZippedFile> files_by_crc;
|
|
|
|
|
|
|
|
~ZipArchive()
|
|
|
|
{
|
2017-04-03 01:03:38 +00:00
|
|
|
for (auto &zf: zfs)
|
|
|
|
{
|
2017-03-27 02:02:22 +00:00
|
|
|
unzClose(zf);
|
2017-04-03 01:03:38 +00:00
|
|
|
}
|
2017-03-27 02:02:22 +00:00
|
|
|
}
|
|
|
|
};
|
2017-03-26 16:38:55 +00:00
|
|
|
|
2017-03-27 02:02:22 +00:00
|
|
|
bool LoadZipArchive(ZipArchive *zip, const std::string &zipfilename) const;
|
|
|
|
const ZippedFile *LookupFile(const File::ptr_t &file, const ZipArchive &zip) const;
|
2017-04-03 01:03:38 +00:00
|
|
|
bool FileExistsInZipArchive(const File::ptr_t &file, const ZipArchive &zip) const;
|
|
|
|
bool LoadZippedFile(std::shared_ptr<uint8_t> *buffer, size_t *file_size, const GameLoader::File::ptr_t &file, const ZipArchive &zip) const;
|
2017-03-26 16:38:55 +00:00
|
|
|
static bool MissingAttrib(const GameLoader &loader, const Util::Config::Node &node, const std::string &attribute);
|
2017-04-03 01:03:38 +00:00
|
|
|
bool LoadGamesFromXML(const Util::Config::Node &xml);
|
|
|
|
bool MergeChildrenWithParents();
|
|
|
|
void LogROMDefinition(const std::string &game_name, const RegionsByName_t ®ions_by_name) const;
|
2017-03-26 16:38:55 +00:00
|
|
|
bool ParseXML(const Util::Config::Node &xml);
|
2017-03-31 05:23:04 +00:00
|
|
|
bool LoadDefinitionXML(const std::string &filename);
|
2017-04-03 01:03:38 +00:00
|
|
|
static void FindEquivalentFiles(std::set<File::ptr_t> *equivalent_files, const std::set<File::ptr_t> &a, const std::set<File::ptr_t> &b);
|
|
|
|
void IdentifyGamesInZipArchive(
|
|
|
|
std::set<std::string> *complete_games,
|
|
|
|
std::map<std::string, std::set<File::ptr_t>> *files_missing_by_game,
|
|
|
|
const ZipArchive &zip,
|
|
|
|
const std::map<std::string, RegionsByName_t> ®ions_by_game) const;
|
2017-03-27 02:02:22 +00:00
|
|
|
bool ComputeRegionSize(uint32_t *region_size, const Region::ptr_t ®ion, const ZipArchive &zip) const;
|
2017-04-03 01:03:38 +00:00
|
|
|
void ChooseGameInZipArchive(std::string *chosen_game, bool *missing_parent_roms, const ZipArchive &zip, const std::string &zipfilename) const;
|
|
|
|
bool LoadRegion(ROM *buffer, const GameLoader::Region::ptr_t ®ion, const ZipArchive &zip) const;
|
|
|
|
bool LoadROMs(ROMSet *rom_set, const std::string &game_name, const ZipArchive &zip) const;
|
2017-04-01 05:08:50 +00:00
|
|
|
std::string ChooseGame(const std::set<std::string> &games_found, const std::string &zipfilename) const;
|
|
|
|
static bool CompareFilesByName(const File::ptr_t &a,const File::ptr_t &b);
|
2017-03-26 16:38:55 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
GameLoader(const std::string &xml_file);
|
2017-04-03 01:03:38 +00:00
|
|
|
bool Load(Game *game, ROMSet *rom_set, const std::string &zipfilename) const;
|
2017-03-26 16:38:55 +00:00
|
|
|
const std::map<std::string, Game> &GetGames() const
|
|
|
|
{
|
|
|
|
return m_game_info_by_game;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif // INCLUDED_GAMELOADER_H
|