config.cpp (7365B)
1 /* ReaPack: Package manager for REAPER 2 * Copyright (C) 2015-2025 Christian Fillion 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU Lesser General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program 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 Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #include "config.hpp" 19 20 #include "path.hpp" 21 #include "win32.hpp" 22 23 #include <algorithm> 24 25 #ifdef _WIN32 26 # include <windows.h> 27 #else 28 # include <swell/swell.h> 29 #endif 30 31 static const char *GENERAL_GRP = "general"; 32 static const char *VERSION_KEY = "version"; 33 34 static const char *INSTALL_GRP = "install"; 35 static const char *AUTOINSTALL_KEY = "autoinstall"; 36 static const char *PRERELEASES_KEY = "prereleases"; 37 static const char *PROMPTOBSOLETE_KEY = "promptobsolete"; 38 39 static const char *ABOUT_GRP = "about"; 40 static const char *MANAGER_GRP = "manager"; 41 42 static const char *BROWSER_GRP = "browser"; 43 static const char *STATE_KEY = "state"; 44 static const char *SYNONYMS_KEY = "synonyms"; 45 46 static const char *NETWORK_GRP = "network"; 47 static const char *PROXY_KEY = "proxy"; 48 static const char *VERIFYPEER_KEY = "verifypeer"; 49 static const char *STALETHRSH_KEY = "stalethreshold"; 50 51 static const char *SIZE_KEY = "size"; 52 53 static const char *REMOTES_GRP = "remotes"; 54 static const char *REMOTE_KEY = "remote"; 55 56 static std::string nKey(const char *key, const unsigned int i) 57 { 58 return key + std::to_string(i); 59 } 60 61 Config::Config(const Path &path) 62 : m_path(path.join()), m_isFirstRun(false), m_version(0), m_remotesIniSize(0) 63 { 64 resetOptions(); 65 read(); 66 } 67 68 Config::~Config() 69 { 70 write(); 71 } 72 73 void Config::resetOptions() 74 { 75 install = {false, false, true}; 76 network = {"", true, NetworkOpts::OneWeekThreshold}; 77 filter = {true}; 78 windowState = {}; 79 } 80 81 void Config::restoreSelfRemote() 82 { 83 const std::string name = "ReaPack"; 84 const std::string url = "https://reapack.com/index.xml"; 85 86 Remote remote = remotes.get(name); 87 remote.setName(name); 88 remote.setUrl(url); 89 remote.protect(); 90 91 remotes.add(remote); 92 } 93 94 void Config::restoreDefaultRemotes() 95 { 96 Remote self = remotes.get("ReaPack"); 97 self.setEnabled(true); 98 remotes.add(self); 99 100 const Remote repos[] { 101 {"ReaTeam Scripts", 102 "https://github.com/ReaTeam/ReaScripts/raw/master/index.xml"}, 103 {"ReaTeam JSFX", 104 "https://github.com/ReaTeam/JSFX/raw/master/index.xml"}, 105 {"ReaTeam Themes", 106 "https://github.com/ReaTeam/Themes/raw/master/index.xml"}, 107 {"ReaTeam LangPacks", 108 "https://github.com/ReaTeam/LangPacks/raw/master/index.xml"}, 109 {"ReaTeam Extensions", 110 "https://github.com/ReaTeam/Extensions/raw/master/index.xml"}, 111 112 {"MPL Scripts", 113 "https://github.com/MichaelPilyavskiy/ReaScripts/raw/master/index.xml"}, 114 {"X-Raym Scripts", 115 "https://github.com/X-Raym/REAPER-ReaScripts/raw/master/index.xml"}, 116 }; 117 118 for(const Remote &repo : repos) 119 remotes.add(repo); 120 } 121 122 void Config::migrate() 123 { 124 const unsigned int version = getUInt(GENERAL_GRP, VERSION_KEY); 125 126 switch(version) { 127 case 0: // v1.0 128 case 1: // v1.1rc3 129 case 2: // v1.1 130 case 3: // v1.2rc2: added ReaTeam/Extensions 131 m_isFirstRun = true; 132 restoreDefaultRemotes(); 133 break; 134 default: 135 // configuration is up-to-date, don't write anything now 136 // keep the version intact in case it comes from a newer version of ReaPack 137 m_version = version; 138 return; 139 }; 140 141 m_version = 4; 142 write(); 143 } 144 145 void Config::read() 146 { 147 install.autoInstall = getBool(INSTALL_GRP, AUTOINSTALL_KEY, install.autoInstall); 148 install.bleedingEdge = getBool(INSTALL_GRP, PRERELEASES_KEY, install.bleedingEdge); 149 install.promptObsolete = getBool(INSTALL_GRP, PROMPTOBSOLETE_KEY, install.promptObsolete); 150 151 network.proxy = getString(NETWORK_GRP, PROXY_KEY, network.proxy); 152 network.verifyPeer = getBool(NETWORK_GRP, VERIFYPEER_KEY, network.verifyPeer); 153 network.staleThreshold = static_cast<time_t>(getUInt(NETWORK_GRP, 154 STALETHRSH_KEY, static_cast<unsigned int>(network.staleThreshold))); 155 156 filter.expandSynonyms = getBool(BROWSER_GRP, SYNONYMS_KEY, filter.expandSynonyms); 157 158 windowState.about = getString(ABOUT_GRP, STATE_KEY, windowState.about); 159 windowState.browser = getString(BROWSER_GRP, STATE_KEY, windowState.browser); 160 windowState.manager = getString(MANAGER_GRP, STATE_KEY, windowState.manager); 161 162 readRemotes(); 163 restoreSelfRemote(); 164 migrate(); 165 } 166 167 void Config::write() 168 { 169 setUInt(GENERAL_GRP, VERSION_KEY, m_version); 170 171 setUInt(INSTALL_GRP, AUTOINSTALL_KEY, install.autoInstall); 172 setUInt(INSTALL_GRP, PRERELEASES_KEY, install.bleedingEdge); 173 setUInt(INSTALL_GRP, PROMPTOBSOLETE_KEY, install.promptObsolete); 174 175 setString(NETWORK_GRP, PROXY_KEY, network.proxy); 176 setUInt(NETWORK_GRP, VERIFYPEER_KEY, network.verifyPeer); 177 setUInt(NETWORK_GRP, STALETHRSH_KEY, static_cast<unsigned int>(network.staleThreshold)); 178 179 setUInt(BROWSER_GRP, SYNONYMS_KEY, filter.expandSynonyms); 180 181 setString(ABOUT_GRP, STATE_KEY, windowState.about); 182 setString(BROWSER_GRP, STATE_KEY, windowState.browser); 183 setString(MANAGER_GRP, STATE_KEY, windowState.manager); 184 185 writeRemotes(); 186 } 187 188 void Config::readRemotes() 189 { 190 m_remotesIniSize = getUInt(REMOTES_GRP, SIZE_KEY); 191 192 for(unsigned int i = 0; i < m_remotesIniSize; i++) { 193 const std::string data = getString(REMOTES_GRP, nKey(REMOTE_KEY, i).c_str()); 194 195 remotes.add(Remote::fromString(data)); 196 } 197 } 198 199 void Config::writeRemotes() 200 { 201 m_remotesIniSize = std::max(static_cast<unsigned int>(remotes.size()), m_remotesIniSize); 202 203 unsigned int i = 0; 204 for(auto it = remotes.begin(); it != remotes.end(); it++, i++) 205 setString(REMOTES_GRP, nKey(REMOTE_KEY, i).c_str(), it->toString()); 206 207 cleanupArray(REMOTES_GRP, REMOTE_KEY, i, m_remotesIniSize); 208 209 setUInt(REMOTES_GRP, SIZE_KEY, m_remotesIniSize = i); 210 } 211 212 std::string Config::getString(const char *group, const char *key, const std::string &fallback) const 213 { 214 return Win32::getPrivateProfileString(group, key, fallback.c_str(), m_path.c_str()); 215 } 216 217 void Config::setString(const char *group, const char *key, const std::string &val) const 218 { 219 Win32::writePrivateProfileString(group, key, val.c_str(), m_path.c_str()); 220 } 221 222 unsigned int Config::getUInt(const char *group, 223 const char *key, const unsigned int fallback) const 224 { 225 return Win32::getPrivateProfileInt(group, key, fallback, m_path.c_str()); 226 } 227 228 bool Config::getBool(const char *group, const char *key, const bool fallback) const 229 { 230 return getUInt(group, key, fallback) > 0; 231 } 232 233 void Config::setUInt(const char *group, const char *key, const unsigned int val) const 234 { 235 setString(group, key, std::to_string(val)); 236 } 237 238 void Config::deleteKey(const char *group, const char *key) const 239 { 240 Win32::writePrivateProfileString(group, key, nullptr, m_path.c_str()); 241 } 242 243 void Config::cleanupArray(const char *group, const char *key, 244 const unsigned int begin, const unsigned int end) const 245 { 246 for(unsigned int i = begin; i < end; i++) 247 deleteKey(group, nKey(key, i).c_str()); 248 }