Read mod files to get versions... and stuff.

This commit is contained in:
Petr Mrázek 2013-08-27 22:32:41 +02:00
parent a266e5d0cc
commit fcd05ca2f6
4 changed files with 116 additions and 142 deletions

View File

@ -16,7 +16,7 @@
#pragma once #pragma once
#include <QString> #include <QString>
#include <QVariant> #include <QVariant>
#include <QIODevice>
#include "libsettings_config.h" #include "libsettings_config.h"
@ -26,6 +26,7 @@ class LIBSETTINGS_EXPORT INIFile : public QMap<QString, QVariant>
public: public:
explicit INIFile(); explicit INIFile();
bool loadFile(QByteArray file);
bool loadFile(QString fileName); bool loadFile(QString fileName);
bool saveFile(QString fileName); bool saveFile(QString fileName);

View File

@ -60,10 +60,16 @@ bool INIFile::saveFile(QString fileName)
bool INIFile::loadFile(QString fileName) bool INIFile::loadFile(QString fileName)
{ {
// TODO Handle errors.
QFile file(fileName); QFile file(fileName);
file.open(QIODevice::ReadOnly); if(!file.open(QIODevice::ReadOnly))
QTextStream in(&file); return false;
bool success = loadFile(file.readAll());
file.close();
return success;
}
bool INIFile::loadFile( QByteArray file )
{
QTextStream in(file);
in.setCodec("UTF-8"); in.setCodec("UTF-8");
QStringList lines = in.readAll().split('\n'); QStringList lines = in.readAll().split('\n');

View File

@ -14,9 +14,20 @@
// limitations under the License. // limitations under the License.
// //
#include <QDir>
#include <QString>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonValue>
#include <QDebug>
#include <quazip.h>
#include <quazipfile.h>
#include "Mod.h" #include "Mod.h"
#include <pathutils.h> #include <pathutils.h>
#include <QDir> #include <inifile.h>
Mod::Mod( const QFileInfo& file ) Mod::Mod( const QFileInfo& file )
{ {
@ -40,164 +51,117 @@ void Mod::repath ( const QFileInfo& file )
else else
m_type = MOD_SINGLEFILE; m_type = MOD_SINGLEFILE;
} }
if(m_type == MOD_ZIPFILE)
{
QuaZip zip(m_file.filePath());
if(!zip.open(QuaZip::mdUnzip))
return;
/* QuaZipFile file(&zip);
switch (modType) for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile())
{ {
case MOD_ZIPFILE: QString name = zip.getCurrentFileName();
if(name == "mcmod.info")
{ {
wxFFileInputStream fileIn(modFile.GetFullPath()); if(!file.open(QIODevice::ReadOnly))
wxZipInputStream zipIn(fileIn);
std::auto_ptr<wxZipEntry> entry;
bool is_forge = false;
while(true)
{ {
entry.reset(zipIn.GetNextEntry()); zip.close();
if (entry.get() == nullptr) return;
break; }
if(entry->GetInternalName().EndsWith("mcmod.info")) ReadMCModInfo(file.readAll());
break; file.close();
if(entry->GetInternalName().EndsWith("forgeversion.properties")) zip.close();
return;
}
else if(name == "forgeversion.properties")
{ {
is_forge = true; if(!file.open(QIODevice::ReadOnly))
break; {
zip.close();
return;
}
ReadForgeInfo(file.readAll());
file.close();
zip.close();
return;
}
}
zip.close();
}
else if(m_type == MOD_FOLDER)
{
QFileInfo mcmod_info(PathCombine(m_file.filePath(), "mcmod.info"));
if (mcmod_info.isFile())
{
QFile mcmod(mcmod_info.filePath());
if(!mcmod.open(QIODevice::ReadOnly))
return;
auto data = mcmod.readAll();
if(data.isEmpty() || data.isNull())
return;
ReadMCModInfo(data);
}
} }
} }
if (entry.get() != nullptr) // NEW format
{ // https://github.com/MinecraftForge/FML/wiki/FML-mod-information-file/6f62b37cea040daf350dc253eae6326dd9c822c3
// Read the info file into text
wxString infoFileData;
wxStringOutputStream stringOut(&infoFileData);
zipIn.Read(stringOut);
if(!is_forge)
ReadModInfoData(infoFileData);
else
ReadForgeInfoData(infoFileData);
}
}
break;
case MOD_FOLDER: // OLD format:
// https://github.com/MinecraftForge/FML/wiki/FML-mod-information-file/5bf6a2d05145ec79387acc0d45c958642fb049fc
void Mod::ReadMCModInfo(QByteArray contents)
{ {
wxString infoFile = Path::Combine(modFile, "mcmod.info"); auto getInfoFromArray = [&]( QJsonArray arr ) -> void
if (!wxFileExists(infoFile))
{ {
infoFile = wxEmptyString; if(!arr.at(0).isObject())
return;
wxDir modDir(modFile.GetFullPath()); auto firstObj = arr.at(0).toObject();
m_id = firstObj.value("modid").toString();
if (!modDir.IsOpened()) m_name = firstObj.value("name").toString();
m_version = firstObj.value("version").toString();
return;
};
QJsonParseError jsonError;
QJsonDocument jsonDoc = QJsonDocument::fromJson(contents, &jsonError);
// this is the very old format that had just the array
if(jsonDoc.isArray())
{ {
wxLogError(_("Can't fine mod info file. Failed to open mod folder.")); getInfoFromArray(jsonDoc.array());
break;
} }
else if(jsonDoc.isObject())
wxString currentFile;
if (modDir.GetFirst(&currentFile))
{ {
do auto val = jsonDoc.object().value("modinfoversion");
int version = val.toDouble();
if(version != 2)
{ {
if (currentFile.EndsWith("mcmod.info")) qDebug() << "BAD stuff happened to mod json:";
{ qDebug() << contents;
infoFile = Path::Combine(modFile.GetFullPath(), currentFile); return;
break; }
auto arrVal = jsonDoc.object().value("modlist");
if(arrVal.isArray())
{
getInfoFromArray(arrVal.toArray());
} }
} while (modDir.GetNext(&currentFile));
} }
} }
if (infoFile != wxEmptyString && wxFileExists(infoFile)) void Mod::ReadForgeInfo(QByteArray contents)
{ {
wxString infoStr;
wxFFileInputStream fileIn(infoFile);
wxStringOutputStream strOut(&infoStr);
fileIn.Read(strOut);
ReadModInfoData(infoStr);
}
}
break;
}
*/
}
/*
void ReadModInfoData(QString info)
{
using namespace boost::property_tree;
// Read the data // Read the data
ptree ptRoot; m_name = "Minecraft Forge";
m_id = "Forge";
INIFile ini;
if(!ini.loadFile(contents))
return;
std::stringstream stringIn(cStr(info)); QString major = ini.get("forge.major.number","0").toString();
try QString minor = ini.get("forge.minor.number","0").toString();
{ QString revision = ini.get("forge.revision.number","0").toString();
read_json(stringIn, ptRoot); QString build = ini.get("forge.build.number","0").toString();
ptree pt = ptRoot.get_child(ptRoot.count("modlist") == 1 ? "modlist" : "").begin()->second; m_version = major + "." + minor + "." + revision + "." + build;
modID = wxStr(pt.get<std::string>("modid"));
modName = wxStr(pt.get<std::string>("name"));
modVersion = wxStr(pt.get<std::string>("version"));
} }
catch (json_parser_error e)
{
// Silently fail...
}
catch (ptree_error e)
{
// Silently fail...
}
}
*/
// FIXME: abstraction violated.
/*
void Mod::ReadForgeInfoData(QString infoFileData)
{
using namespace boost::property_tree;
// Read the data
ptree ptRoot;
modName = "Minecraft Forge";
modID = "Forge";
std::stringstream stringIn(cStr(infoFileData));
try
{
read_ini(stringIn, ptRoot);
wxString major, minor, revision, build;
// BUG: boost property tree is bad. won't let us get a key with dots in it
// Likely cause = treating the dots as path separators.
for (auto iter = ptRoot.begin(); iter != ptRoot.end(); iter++)
{
auto &item = *iter;
std::string key = item.first;
std::string value = item.second.get_value<std::string>();
if(key == "forge.major.number")
major = value;
if(key == "forge.minor.number")
minor = value;
if(key == "forge.revision.number")
revision = value;
if(key == "forge.build.number")
build = value;
}
modVersion.Empty();
modVersion << major << "." << minor << "." << revision << "." << build;
}
catch (json_parser_error e)
{
std::cerr << e.what();
}
catch (ptree_error e)
{
std::cerr << e.what();
}
}
*/
bool Mod::replace ( Mod& with ) bool Mod::replace ( Mod& with )
{ {

View File

@ -56,6 +56,9 @@ public:
{ {
return filename() == other.filename() && id() == other.id() && version() == other.version() && type() == other.type(); return filename() == other.filename() && id() == other.id() && version() == other.version() && type() == other.type();
} }
private:
void ReadMCModInfo(QByteArray contents);
void ReadForgeInfo(QByteArray contents);
protected: protected:
//FIXME: what do do with those? HMM... //FIXME: what do do with those? HMM...