// // Copyright 2012 MultiMC Contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #include #include #include #include #include #include #include #include #include #include "Mod.h" #include #include Mod::Mod( const QFileInfo& file ) { repath(file); } void Mod::repath ( const QFileInfo& file ) { m_file = file; m_name = file.completeBaseName(); m_id = file.fileName(); m_type = Mod::MOD_UNKNOWN; if (m_file.isDir()) m_type = MOD_FOLDER; else if (m_file.isFile()) { QString ext = m_file.suffix().toLower(); if (ext == "zip" || ext == "jar") m_type = MOD_ZIPFILE; else m_type = MOD_SINGLEFILE; } if(m_type == MOD_ZIPFILE) { QuaZip zip(m_file.filePath()); if(!zip.open(QuaZip::mdUnzip)) return; QuaZipFile file(&zip); for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) { QString name = zip.getCurrentFileName(); if(name == "mcmod.info") { if(!file.open(QIODevice::ReadOnly)) { zip.close(); return; } ReadMCModInfo(file.readAll()); file.close(); zip.close(); return; } else if(name == "forgeversion.properties") { if(!file.open(QIODevice::ReadOnly)) { 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); } } } // NEW format // https://github.com/MinecraftForge/FML/wiki/FML-mod-information-file/6f62b37cea040daf350dc253eae6326dd9c822c3 // OLD format: // https://github.com/MinecraftForge/FML/wiki/FML-mod-information-file/5bf6a2d05145ec79387acc0d45c958642fb049fc void Mod::ReadMCModInfo(QByteArray contents) { auto getInfoFromArray = [&]( QJsonArray arr ) -> void { if(!arr.at(0).isObject()) return; auto firstObj = arr.at(0).toObject(); m_id = firstObj.value("modid").toString(); 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()) { getInfoFromArray(jsonDoc.array()); } else if(jsonDoc.isObject()) { auto val = jsonDoc.object().value("modinfoversion"); int version = val.toDouble(); if(version != 2) { qDebug() << "BAD stuff happened to mod json:"; qDebug() << contents; return; } auto arrVal = jsonDoc.object().value("modlist"); if(arrVal.isArray()) { getInfoFromArray(arrVal.toArray()); } } } void Mod::ReadForgeInfo(QByteArray contents) { // Read the data m_name = "Minecraft Forge"; m_id = "Forge"; INIFile ini; if(!ini.loadFile(contents)) return; QString major = ini.get("forge.major.number","0").toString(); QString minor = ini.get("forge.minor.number","0").toString(); QString revision = ini.get("forge.revision.number","0").toString(); QString build = ini.get("forge.build.number","0").toString(); m_version = major + "." + minor + "." + revision + "." + build; } bool Mod::replace ( Mod& with ) { if(!destroy()) return false; bool success = false; auto t = with.type(); if(t == MOD_ZIPFILE || t == MOD_SINGLEFILE) { success = QFile::copy(with.m_file.filePath(), m_file.path()); } if(t == MOD_FOLDER) { success = copyPath(with.m_file.filePath(), m_file.path()); } if(success) { m_id = with.m_id; m_mcversion = with.m_mcversion; m_type = with.m_type; m_name = with.m_name; m_version = with.m_version; } return success; } bool Mod::destroy() { if(m_type == MOD_FOLDER) { QDir d(m_file.filePath()); if(d.removeRecursively()) { m_type = MOD_UNKNOWN; return true; } return false; } else if (m_type == MOD_SINGLEFILE || m_type == MOD_ZIPFILE) { QFile f(m_file.filePath()); if(f.remove()) { m_type = MOD_UNKNOWN; return true; } return false; } return true; } QString Mod::version() const { switch(type()) { case MOD_ZIPFILE: return m_version; case MOD_FOLDER: return "Folder"; case MOD_SINGLEFILE: return "File"; default: return "VOID"; } }