1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
|
/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
#ifndef _ARCHIVE_SCANNER_H
#define _ARCHIVE_SCANNER_H
#include <string>
#include <vector>
#include <list>
#include <map>
#include "System/Info.h"
class IArchive;
class IFileFilter;
class LuaTable;
/*
* This class searches through a given directory and its sub-directories looking
* for archive files.
* When it finds one, it figures out what kind of archive it is (i.e. if it is a
* map or a mod currently). This information is cached, so that only modified
* archives are actually opened. The information can then be retreived by the
* mod and map selectors.
*
* The archive namespace is global, so it is not allowed to have an archive with
* the same name in more than one folder.
*/
namespace modtype
{
static const int primary = 1;
static const int hidden = 0;
static const int map = 3;
}
class CArchiveScanner
{
public:
class ArchiveData
{
public:
ArchiveData() {};
ArchiveData(const LuaTable& archiveTable, bool fromCache);
/*
* These methods are only here for convenience and compile time checks.
* These are all the properties used engine internally.
* With these methods, we prevent spreading key strings through the
* code, which could provoke runtime bugs when edited wrong.
* There may well be other info-times supplied by the archive.
*/
std::string GetName() const { return GetInfoValueString("name_pure"); } /// ex: Original Total Annihilation
std::string GetNameVersioned() const { return GetInfoValueString("name"); } /// ex: Original Total Annihilation v2.3
std::string GetShortName() const { return GetInfoValueString("shortName"); } /// ex: OTA
std::string GetVersion() const { return GetInfoValueString("version"); } /// ex: v2.3
std::string GetMutator() const { return GetInfoValueString("mutator"); } /// ex: deployment
std::string GetGame() const { return GetInfoValueString("game"); } /// ex: Total Annihilation
std::string GetShortGame() const { return GetInfoValueString("shortGame"); } /// ex: TA
std::string GetDescription() const { return GetInfoValueString("description"); } /// ex: Little units blowing up other little units
std::string GetMapFile() const { return GetInfoValueString("mapFile"); } /// in case its a map, store location of smf/sm3 file
int GetModType() const { return GetInfoValueInteger("modType"); } /// 1=primary, 0=hidden, 3=map
const std::map<std::string, InfoItem>& GetInfo() const { return info; }
std::vector<InfoItem> GetInfoItems() const;
const std::vector<std::string>& GetDependencies() const { return dependencies; }
std::vector<std::string>& GetDependencies() { return dependencies; }
const std::vector<std::string>& GetReplaces() const { return replaces; }
std::vector<std::string>& GetReplaces() { return replaces; }
void SetInfoItemValueString(const std::string& key, const std::string& value);
void SetInfoItemValueInteger(const std::string& key, int value);
void SetInfoItemValueFloat(const std::string& key, float value);
void SetInfoItemValueBool(const std::string& key, bool value);
bool IsValid(std::string& error) const;
bool IsEmpty() const { return info.empty(); }
static bool IsReservedKey(const std::string& keyLower);
static std::string GetKeyDescription(const std::string& keyLower);
private:
InfoValueType GetInfoValueType(const std::string& key) const;
std::string GetInfoValueString(const std::string& key) const;
int GetInfoValueInteger(const std::string& key) const;
float GetInfoValueFloat(const std::string& key) const;
bool GetInfoValueBool(const std::string& key) const;
InfoItem* GetInfoItem(const std::string& key);
const InfoItem* GetInfoItem(const std::string& key) const;
InfoItem& EnsureInfoItem(const std::string& key);
std::map<std::string, InfoItem> info;
std::vector<std::string> dependencies; /// Archives we depend on
std::vector<std::string> replaces; /// This archive obsoletes these archives
};
CArchiveScanner();
~CArchiveScanner();
public:
const std::string& GetFilepath() const;
std::vector<std::string> GetMaps() const;
std::vector<ArchiveData> GetPrimaryMods() const;
std::vector<ArchiveData> GetAllMods() const;
std::vector<ArchiveData> GetAllArchives() const;
std::vector<std::string> GetAllArchivesUsedBy(const std::string& root, int depth = 0) const;
public:
/// checksum of the given archive (without dependencies)
unsigned int GetSingleArchiveChecksum(const std::string& name);
/// Calculate checksum of the given archive and all its dependencies
unsigned int GetArchiveCompleteChecksum(const std::string& name);
/// like GetArchiveCompleteChecksum, throws exception if mismatch
void CheckArchive(const std::string& name, unsigned checksum);
void ScanArchive(const std::string& fullName, bool checksum = false);
void ScanAllDirs();
std::string ArchiveFromName(const std::string& s) const;
std::string NameFromArchive(const std::string& s) const;
std::string GetArchivePath(const std::string& name) const;
std::string MapNameToMapFile(const std::string& name) const;
ArchiveData GetArchiveData(const std::string& name) const;
ArchiveData GetArchiveDataByArchive(const std::string& archive) const;
private:
struct ArchiveInfo
{
ArchiveInfo()
: modified(0)
, checksum(0)
, updated(false)
{}
std::string path;
std::string origName; ///< Could be useful to have the non-lowercased name around
std::string replaced; ///< If not empty, use that archive instead
ArchiveData archiveData;
unsigned int modified;
unsigned int checksum;
bool updated;
};
struct BrokenArchive
{
BrokenArchive()
: modified(0)
, updated(false)
{}
std::string path;
unsigned int modified;
bool updated;
std::string problem;
};
private:
void ScanDirs(const std::vector<std::string>& dirs, bool checksum = false);
void ScanDir(const std::string& curPath, std::list<std::string>* foundArchives);
/// scan mapinfo / modinfo lua files
bool ScanArchiveLua(IArchive* ar, const std::string& fileName, ArchiveInfo& ai, std::string& err);
/**
* scan archive for map file
* @return file name if found, empty string if not
*/
std::string SearchMapFile(const IArchive* ar, std::string& error);
void ReadCacheData(const std::string& filename);
void WriteCacheData(const std::string& filename);
IFileFilter* CreateIgnoreFilter(IArchive* ar);
/**
* Get CRC of the data in the specified archive.
* Returns 0 if file could not be opened.
*/
unsigned int GetCRC(const std::string& filename);
void ComputeChecksumForArchive(const std::string& filePath);
bool CheckCachedData(const std::string& fullName, unsigned* modified, bool doChecksum);
/**
* Returns a value > 0 if the file is rated as a meta-file.
* First class means, it is essential for the archive, and will be read by
* pretty much every software that scans through archives.
* Second class means, it is not essential for the archive, but it may be
* read by certain tools that generate spezialized indices while scanning
* through archives.
* Examples:
* "objects3d/ddm.s3o" -> 0
* "ModInfo.lua" -> 1
* "maps/dsd.smf" -> 1
* "LuaAI.lua" -> 2
* "sides/arm.bmp" -> 2
* @param filePath file path, relative to archive-root
* @return 0 if the file is not a meta-file,
* 1 if the file is a first class meta-file,
* 2 if the file is a second class meta-file
*/
static unsigned char GetMetaFileClass(const std::string& filePath);
static bool CheckCompression(const IArchive* ar,const std::string& fullName, std::string& error);
private:
std::map<std::string, ArchiveInfo> archiveInfos;
std::map<std::string, BrokenArchive> brokenArchives;
bool isDirty;
std::string cachefile;
};
extern CArchiveScanner* archiveScanner;
#endif // _ARCHIVE_SCANNER_H
|