LCOV - code coverage report
Current view: top level - source/ps - ModInstaller.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 1 57 1.8 %
Date: 2023-01-19 00:18:29 Functions: 2 6 33.3 %

          Line data    Source code
       1             : /* Copyright (C) 2022 Wildfire Games.
       2             :  * This file is part of 0 A.D.
       3             :  *
       4             :  * 0 A.D. is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * 0 A.D. is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #include "precompiled.h"
      19             : 
      20             : #include "ModInstaller.h"
      21             : 
      22             : #include "lib/file/vfs/vfs_util.h"
      23             : #include "lib/file/file_system.h"
      24             : #include "lib/sysdep/os.h"
      25             : #include "ps/CLogger.h"
      26             : #include "ps/Filesystem.h"
      27             : #include "ps/XML/Xeromyces.h"
      28             : #include "scriptinterface/ScriptInterface.h"
      29             : #include "scriptinterface/JSON.h"
      30             : 
      31             : #if !OS_WIN
      32             : #include "lib/os_path.h"
      33             : #endif
      34             : 
      35             : #include <fstream>
      36             : #if OS_WIN
      37             : #include <filesystem>
      38             : #endif
      39             : 
      40           0 : CModInstaller::CModInstaller(const OsPath& modsdir, const OsPath& tempdir) :
      41           0 :     m_ModsDir(modsdir), m_TempDir(tempdir / "_modscache"), m_CacheDir("cache/")
      42             : {
      43           0 :     m_VFS = CreateVfs();
      44           0 :     CreateDirectories(m_TempDir, 0700);
      45           0 : }
      46             : 
      47           0 : CModInstaller::~CModInstaller()
      48             : {
      49           0 :     m_VFS.reset();
      50           0 :     DeleteDirectory(m_TempDir);
      51           0 : }
      52             : 
      53           0 : CModInstaller::ModInstallationResult CModInstaller::Install(
      54             :     const OsPath& mod,
      55             :     const std::shared_ptr<ScriptContext>& scriptContext,
      56             :     bool keepFile)
      57             : {
      58           0 :     const OsPath modTemp = m_TempDir / mod.Basename() / mod.Filename().ChangeExtension(L".zip");
      59           0 :     CreateDirectories(modTemp.Parent(), 0700);
      60             : 
      61           0 :     if (keepFile)
      62             :     {
      63           0 :         if (CopyFile(mod, modTemp, true) != INFO::OK)
      64             :         {
      65           0 :             LOGERROR("Failed to copy '%s' to '%s'", mod.string8().c_str(), modTemp.string8().c_str());
      66           0 :             return FAIL_ON_MOD_COPY;
      67             :         }
      68             :     }
      69           0 :     else if (RenameFile(mod, modTemp) != INFO::OK)
      70             :     {
      71           0 :         LOGERROR("Failed to rename '%s' into '%s'", mod.string8().c_str(), modTemp.string8().c_str());
      72           0 :         return FAIL_ON_MOD_MOVE;
      73             :     }
      74             : 
      75             :     // Load the mod to VFS
      76           0 :     if (m_VFS->Mount(m_CacheDir, m_TempDir / "") != INFO::OK)
      77           0 :         return FAIL_ON_VFS_MOUNT;
      78           0 :     CVFSFile modinfo;
      79           0 :     PSRETURN modinfo_status = modinfo.Load(m_VFS, m_CacheDir / modTemp.Basename() / "mod.json", false);
      80           0 :     m_VFS->Clear();
      81           0 :     if (modinfo_status != PSRETURN_OK)
      82           0 :         return FAIL_ON_MOD_LOAD;
      83             : 
      84             :     // Extract the name of the mod
      85           0 :     CStr modName;
      86             :     {
      87           0 :         ScriptInterface scriptInterface("Engine", "ModInstaller", scriptContext);
      88           0 :         ScriptRequest rq(scriptInterface);
      89             : 
      90           0 :         JS::RootedValue json_val(rq.cx);
      91           0 :         if (!Script::ParseJSON(rq, modinfo.GetAsString(), &json_val))
      92           0 :             return FAIL_ON_PARSE_JSON;
      93           0 :         JS::RootedObject json_obj(rq.cx, json_val.toObjectOrNull());
      94           0 :         JS::RootedValue name_val(rq.cx);
      95           0 :         if (!JS_GetProperty(rq.cx, json_obj, "name", &name_val))
      96           0 :             return FAIL_ON_EXTRACT_NAME;
      97           0 :         Script::FromJSVal(rq, name_val, modName);
      98           0 :         if (modName.empty())
      99           0 :             return FAIL_ON_EXTRACT_NAME;
     100             :     }
     101             : 
     102           0 :     const OsPath modDir = m_ModsDir / modName;
     103           0 :     const OsPath modPath = modDir / (modName + ".zip");
     104             : 
     105             :     // Create a directory with the following structure:
     106             :     //   mod-name/
     107             :     //     mod-name.zip
     108             :     //     mod.json
     109           0 :     CreateDirectories(modDir, 0700);
     110           0 :     if (RenameFile(modTemp, modPath) != INFO::OK)
     111             :     {
     112           0 :         LOGERROR("Failed to rename '%s' into '%s'", modTemp.string8().c_str(), modPath.string8().c_str());
     113           0 :         return FAIL_ON_MOD_MOVE;
     114             :     }
     115             : 
     116           0 :     DeleteDirectory(modTemp.Parent());
     117             : 
     118             : #if OS_WIN
     119             :     const std::filesystem::path modJsonPath = (modDir / L"mod.json").fileSystemPath();
     120             : #else
     121           0 :     const std::string modJsonPath = OsString(modDir / L"mod.json");
     122             : #endif
     123           0 :     std::ofstream mod_json(modJsonPath);
     124           0 :     if (mod_json.good())
     125             :     {
     126           0 :         mod_json << modinfo.GetAsString();
     127           0 :         mod_json.close();
     128             :     }
     129             :     else
     130           0 :         return FAIL_ON_JSON_WRITE;
     131             : 
     132           0 :     m_InstalledMods.emplace_back(modName);
     133             : 
     134           0 :     return SUCCESS;
     135             : }
     136             : 
     137           0 : const std::vector<CStr>& CModInstaller::GetInstalledMods() const
     138             : {
     139           0 :     return m_InstalledMods;
     140           3 : }

Generated by: LCOV version 1.13