1 /*
2 * This file is part of the Colobot: Gold Edition source code
3 * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
4 * http://epsitec.ch; http://colobot.info; http://github.com/colobot
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see http://gnu.org/licenses
18 */
19
20
21 #include "app/pathman.h"
22
23 #include "common/config.h"
24
25 #include "app/app.h"
26
27
28 #include "common/logger.h"
29
30 #include "common/resources/resourcemanager.h"
31
32 #include "common/system/system.h"
33 #ifdef PLATFORM_WINDOWS
34 #include "common/system/system_windows.h"
35 #endif
36
37 #include <boost/algorithm/string.hpp>
38 #include <boost/filesystem.hpp>
39
CPathManager(CSystemUtils * systemUtils)40 CPathManager::CPathManager(CSystemUtils* systemUtils)
41 : m_dataPath(systemUtils->GetDataPath())
42 , m_langPath(systemUtils->GetLangPath())
43 , m_savePath(systemUtils->GetSaveDir())
44 , m_modSearchDirs{}
45 {
46 }
47
~CPathManager()48 CPathManager::~CPathManager()
49 {
50 }
51
SetDataPath(const std::string & dataPath)52 void CPathManager::SetDataPath(const std::string &dataPath)
53 {
54 m_dataPath = dataPath;
55 }
56
SetLangPath(const std::string & langPath)57 void CPathManager::SetLangPath(const std::string &langPath)
58 {
59 m_langPath = langPath;
60 }
61
SetSavePath(const std::string & savePath)62 void CPathManager::SetSavePath(const std::string &savePath)
63 {
64 m_savePath = savePath;
65 }
66
GetDataPath()67 const std::string& CPathManager::GetDataPath()
68 {
69 return m_dataPath;
70 }
71
GetLangPath()72 const std::string& CPathManager::GetLangPath()
73 {
74 return m_langPath;
75 }
76
GetSavePath()77 const std::string& CPathManager::GetSavePath()
78 {
79 return m_savePath;
80 }
81
VerifyPaths()82 std::string CPathManager::VerifyPaths()
83 {
84 #if PLATFORM_WINDOWS
85 boost::filesystem::path dataPath(CSystemUtilsWindows::UTF8_Decode(m_dataPath));
86 #else
87 boost::filesystem::path dataPath(m_dataPath);
88 #endif
89 if (! (boost::filesystem::exists(dataPath) && boost::filesystem::is_directory(dataPath)) )
90 {
91 GetLogger()->Error("Data directory '%s' doesn't exist or is not a directory\n", m_dataPath.c_str());
92 return std::string("Could not read from data directory:\n") +
93 std::string("'") + m_dataPath + std::string("'\n") +
94 std::string("Please check your installation, or supply a valid data directory by -datadir option.");
95 }
96
97 #if PLATFORM_WINDOWS
98 boost::filesystem::path langPath(CSystemUtilsWindows::UTF8_Decode(m_langPath));
99 #else
100 boost::filesystem::path langPath(m_langPath);
101 #endif
102 if (! (boost::filesystem::exists(langPath) && boost::filesystem::is_directory(langPath)) )
103 {
104 GetLogger()->Warn("Language path '%s' is invalid, assuming translation files not installed\n", m_langPath.c_str());
105 }
106
107 #if PLATFORM_WINDOWS
108 boost::filesystem::create_directories(CSystemUtilsWindows::UTF8_Decode(m_savePath));
109 boost::filesystem::create_directories(CSystemUtilsWindows::UTF8_Decode(m_savePath+"/mods"));
110 #else
111 boost::filesystem::create_directories(m_savePath);
112 boost::filesystem::create_directories(m_savePath+"/mods");
113 #endif
114
115 return "";
116 }
117
InitPaths()118 void CPathManager::InitPaths()
119 {
120 GetLogger()->Info("Data path: %s\n", m_dataPath.c_str());
121 GetLogger()->Info("Save path: %s\n", m_savePath.c_str());
122
123 m_modSearchDirs.push_back(m_dataPath + "/mods");
124 m_modSearchDirs.push_back(m_savePath + "/mods");
125
126 if (!m_modSearchDirs.empty())
127 {
128 GetLogger()->Info("Mod search dirs:\n");
129 for(const std::string& modSearchDir : m_modSearchDirs)
130 GetLogger()->Info(" * %s\n", modSearchDir.c_str());
131 }
132
133 CResourceManager::AddLocation(m_dataPath);
134
135 CResourceManager::SetSaveLocation(m_savePath);
136 CResourceManager::AddLocation(m_savePath);
137
138 GetLogger()->Debug("Finished initalizing data paths\n");
139 GetLogger()->Debug("PHYSFS search path is:\n");
140 for (const std::string& path : CResourceManager::GetLocations())
141 GetLogger()->Debug(" * %s\n", path.c_str());
142 }
143
AddMod(const std::string & path)144 void CPathManager::AddMod(const std::string &path)
145 {
146 m_mods.push_back(path);
147 }
148
FindMods() const149 std::vector<std::string> CPathManager::FindMods() const
150 {
151 std::vector<std::string> mods;
152 GetLogger()->Info("Found mods:\n");
153 for (const auto &searchPath : m_modSearchDirs)
154 {
155 for (const auto &modPath : FindModsInDir(searchPath))
156 {
157 GetLogger()->Info(" * %s\n", modPath.c_str());
158 mods.push_back(modPath);
159 }
160 }
161 GetLogger()->Info("Additional mod paths:\n");
162 for (const auto& modPath : m_mods)
163 {
164 if (boost::filesystem::exists(modPath))
165 {
166 GetLogger()->Info(" * %s\n", modPath.c_str());
167 mods.push_back(modPath);
168 }
169 else
170 {
171 GetLogger()->Warn("Mod does not exist: %s\n", modPath.c_str());
172 }
173 }
174 return mods;
175 }
176
AddModSearchDir(const std::string & modSearchDirPath)177 void CPathManager::AddModSearchDir(const std::string &modSearchDirPath)
178 {
179 m_modSearchDirs.push_back(modSearchDirPath);
180 }
181
FindModsInDir(const std::string & dir) const182 std::vector<std::string> CPathManager::FindModsInDir(const std::string &dir) const
183 {
184 std::vector<std::string> ret;
185 try
186 {
187 #if PLATFORM_WINDOWS
188 boost::filesystem::directory_iterator iterator(CSystemUtilsWindows::UTF8_Decode(dir));
189 #else
190 boost::filesystem::directory_iterator iterator(dir);
191 #endif
192 for(; iterator != boost::filesystem::directory_iterator(); ++iterator)
193 {
194 #if PLATFORM_WINDOWS
195 ret.push_back(CSystemUtilsWindows::UTF8_Encode(iterator->path().wstring()));
196 #else
197 ret.push_back(iterator->path().string());
198 #endif
199 }
200 }
201 catch (std::exception &e)
202 {
203 GetLogger()->Warn("Unable to load mods from directory '%s': %s\n", dir.c_str(), e.what());
204 }
205 return ret;
206 }
207