diff options
Diffstat (limited to 'utils/rbutilqt/base/playerbuildinfo.cpp')
-rw-r--r-- | utils/rbutilqt/base/playerbuildinfo.cpp | 362 |
1 files changed, 362 insertions, 0 deletions
diff --git a/utils/rbutilqt/base/playerbuildinfo.cpp b/utils/rbutilqt/base/playerbuildinfo.cpp new file mode 100644 index 0000000000..f118a9fd7a --- /dev/null +++ b/utils/rbutilqt/base/playerbuildinfo.cpp | |||
@@ -0,0 +1,362 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2020 by Dominik Riebeling | ||
10 | * | ||
11 | * All files in this archive are subject to the GNU General Public License. | ||
12 | * See the file COPYING in the source tree root for full license agreement. | ||
13 | * | ||
14 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
15 | * KIND, either express or implied. | ||
16 | * | ||
17 | ****************************************************************************/ | ||
18 | |||
19 | #include "playerbuildinfo.h" | ||
20 | #include "rbsettings.h" | ||
21 | #include "Logger.h" | ||
22 | |||
23 | PlayerBuildInfo* PlayerBuildInfo::infoInstance = nullptr; | ||
24 | |||
25 | PlayerBuildInfo* PlayerBuildInfo::instance() | ||
26 | { | ||
27 | if (infoInstance == nullptr) { | ||
28 | infoInstance = new PlayerBuildInfo(); | ||
29 | } | ||
30 | return infoInstance; | ||
31 | } | ||
32 | |||
33 | // server infos | ||
34 | const static struct { | ||
35 | PlayerBuildInfo::BuildInfo item; | ||
36 | const char* name; | ||
37 | } ServerInfoList[] = { | ||
38 | { PlayerBuildInfo::BuildVoiceLangs, "voices/:version:" }, | ||
39 | { PlayerBuildInfo::BuildVersion, ":build:/:target:" }, | ||
40 | { PlayerBuildInfo::BuildUrl, ":build:/build_url" }, | ||
41 | { PlayerBuildInfo::BuildVoiceUrl, ":build:/voice_url" }, | ||
42 | { PlayerBuildInfo::BuildManualUrl, ":build:/manual_url" }, | ||
43 | { PlayerBuildInfo::BuildSourceUrl, ":build:/source_url" }, | ||
44 | { PlayerBuildInfo::BuildFontUrl, ":build:/font_url" }, | ||
45 | |||
46 | // other URLs -- those are not directly related to the build, but handled here. | ||
47 | { PlayerBuildInfo::DoomUrl, "other/doom_url" }, | ||
48 | { PlayerBuildInfo::Duke3DUrl, "other/duke3d_url" }, | ||
49 | { PlayerBuildInfo::PuzzFontsUrl, "other/puzzfonts_url" }, | ||
50 | { PlayerBuildInfo::QuakeUrl, "other/quake_url" }, | ||
51 | { PlayerBuildInfo::Wolf3DUrl, "other/wolf3d_url" }, | ||
52 | { PlayerBuildInfo::XWorldUrl, "other/xworld_url" }, | ||
53 | { PlayerBuildInfo::MidiPatchsetUrl, "other/patcheset_url" }, | ||
54 | }; | ||
55 | |||
56 | const static struct { | ||
57 | PlayerBuildInfo::DeviceInfo item; | ||
58 | const char* name; | ||
59 | } PlayerInfoList[] = { | ||
60 | { PlayerBuildInfo::BuildStatus, "status/:target:" }, | ||
61 | { PlayerBuildInfo::DisplayName, ":target:/name" }, | ||
62 | { PlayerBuildInfo::BootloaderMethod, ":target:/bootloadermethod" }, | ||
63 | { PlayerBuildInfo::BootloaderName, ":target:/bootloadername" }, | ||
64 | { PlayerBuildInfo::BootloaderFile, ":target:/bootloaderfile" }, | ||
65 | { PlayerBuildInfo::BootloaderFilter, ":target:/bootloaderfilter" }, | ||
66 | { PlayerBuildInfo::Encoder, ":target:/encoder" }, | ||
67 | { PlayerBuildInfo::Brand, ":target:/brand" }, | ||
68 | { PlayerBuildInfo::PlayerPicture, ":target:/playerpic" }, | ||
69 | { PlayerBuildInfo::TargetNamesAll, "_targets/all" }, | ||
70 | { PlayerBuildInfo::TargetNamesEnabled, "_targets/enabled" }, | ||
71 | { PlayerBuildInfo::LanguageInfo, "languages/:target:" }, | ||
72 | { PlayerBuildInfo::LanguageList, "_languages/list" }, | ||
73 | { PlayerBuildInfo::UsbIdErrorList, "_usb/error" }, | ||
74 | { PlayerBuildInfo::UsbIdTargetList, "_usb/target" }, | ||
75 | }; | ||
76 | |||
77 | const static struct { | ||
78 | PlayerBuildInfo::SystemUrl item; | ||
79 | const char* name; | ||
80 | } PlayerSystemUrls[] = { | ||
81 | { PlayerBuildInfo::BootloaderUrl, "bootloader/download_url" }, | ||
82 | { PlayerBuildInfo::BuildInfoUrl, "build_info_url" }, | ||
83 | { PlayerBuildInfo::GenlangUrl, "genlang_url" }, | ||
84 | { PlayerBuildInfo::ThemesUrl, "themes_url" }, | ||
85 | { PlayerBuildInfo::ThemesInfoUrl, "themes_info_url" }, | ||
86 | { PlayerBuildInfo::RbutilUrl, "rbutil_url" }, | ||
87 | }; | ||
88 | |||
89 | PlayerBuildInfo::PlayerBuildInfo() : | ||
90 | serverInfo(nullptr), | ||
91 | playerInfo(":/ini/rbutil.ini", QSettings::IniFormat) | ||
92 | { | ||
93 | |||
94 | } | ||
95 | |||
96 | void PlayerBuildInfo::setBuildInfo(QString file) | ||
97 | { | ||
98 | if (serverInfo) | ||
99 | delete serverInfo; | ||
100 | LOG_INFO() << "updated:" << file; | ||
101 | serverInfo = new QSettings(file, QSettings::IniFormat); | ||
102 | } | ||
103 | |||
104 | QVariant PlayerBuildInfo::value(BuildInfo item, BuildType type) | ||
105 | { | ||
106 | // locate setting item in server info file | ||
107 | int i = 0; | ||
108 | while(ServerInfoList[i].item != item) | ||
109 | i++; | ||
110 | |||
111 | // split of variant for target. | ||
112 | // we can have an optional variant part in the target string. | ||
113 | // For build info we don't use that. | ||
114 | QString target = RbSettings::value(RbSettings::CurrentPlatform).toString().split('.').at(0); | ||
115 | |||
116 | QString s = ServerInfoList[i].name; | ||
117 | s.replace(":target:", target); | ||
118 | QString v; | ||
119 | switch(type) { | ||
120 | case TypeRelease: | ||
121 | v = "release"; | ||
122 | break; | ||
123 | case TypeCandidate: | ||
124 | v = "release-candidate"; | ||
125 | break; | ||
126 | case TypeDaily: | ||
127 | v = "daily"; | ||
128 | break; | ||
129 | case TypeDevel: | ||
130 | v = "development"; | ||
131 | break; | ||
132 | } | ||
133 | |||
134 | QVariant result = QString(); | ||
135 | if (!serverInfo) | ||
136 | return result; | ||
137 | QStringList version = serverInfo->value(v + "/" + target, "").toStringList(); | ||
138 | s.replace(":build:", v); | ||
139 | s.replace(":version:", version.at(0)); | ||
140 | |||
141 | // get value from server build-info | ||
142 | // we need to get a version string, otherwise the data is invalid. | ||
143 | // For invalid data return an empty string. | ||
144 | if(version.at(0).isEmpty()) { | ||
145 | LOG_INFO() << s << "(version invalid)"; | ||
146 | return result; | ||
147 | } | ||
148 | if(!s.isEmpty()) | ||
149 | result = serverInfo->value(s); | ||
150 | |||
151 | // depending on the actual value we need more replacements. | ||
152 | switch(item) { | ||
153 | case BuildVersion: | ||
154 | result = result.toStringList().at(0); | ||
155 | break; | ||
156 | |||
157 | case BuildUrl: | ||
158 | if(version.size() > 1) { | ||
159 | // version info has an URL appended. Takes precendence. | ||
160 | result = version.at(1); | ||
161 | } | ||
162 | break; | ||
163 | |||
164 | case BuildVoiceLangs: | ||
165 | if (type == TypeDaily) | ||
166 | s = "voices/daily"; | ||
167 | result = serverInfo->value(s); | ||
168 | break; | ||
169 | |||
170 | case BuildManualUrl: | ||
171 | { | ||
172 | // special case: if playerInfo has a non-empty manualname entry for the | ||
173 | // target, use that as target for the manual name. | ||
174 | QString manualtarget = playerInfo.value(target + "/manualname", "").toString(); | ||
175 | if(!manualtarget.isEmpty()) | ||
176 | target = manualtarget; | ||
177 | break; | ||
178 | } | ||
179 | |||
180 | default: | ||
181 | break; | ||
182 | } | ||
183 | // if the value is a string we can replace some patterns. | ||
184 | // if we cannot convert it (f.e. for a QStringList) we leave as-is, since | ||
185 | // the conversion would return an empty type. | ||
186 | if (result.canConvert(QMetaType::QString)) | ||
187 | result = result.toString() | ||
188 | .replace("%TARGET%", target) | ||
189 | .replace("%VERSION%", version.at(0)); | ||
190 | |||
191 | LOG_INFO() << "B:" << s << result; | ||
192 | return result; | ||
193 | } | ||
194 | |||
195 | QVariant PlayerBuildInfo::value(DeviceInfo item, QString target) | ||
196 | { | ||
197 | // locate setting item in server info file | ||
198 | int i = 0; | ||
199 | while(PlayerInfoList[i].item != item) | ||
200 | i++; | ||
201 | |||
202 | // split of variant for target. | ||
203 | // we can have an optional variant part in the target string. | ||
204 | // For device info we use this. | ||
205 | if (target.isEmpty()) | ||
206 | target = RbSettings::value(RbSettings::CurrentPlatform).toString(); | ||
207 | |||
208 | QVariant result = QString(); | ||
209 | |||
210 | QString s = PlayerInfoList[i].name; | ||
211 | s.replace(":target:", target); | ||
212 | |||
213 | switch(item) { | ||
214 | case BuildStatus: | ||
215 | { | ||
216 | // build status is the only value that doesn't depend on the version | ||
217 | // but the selected target instead. | ||
218 | bool ok = false; | ||
219 | if (serverInfo) | ||
220 | result = serverInfo->value(s).toInt(&ok); | ||
221 | if (!ok) | ||
222 | result = -1; | ||
223 | break; | ||
224 | } | ||
225 | case TargetNamesAll: | ||
226 | // list of all internal target names. Doesn't depend on the passed target. | ||
227 | result = targetNames(true); | ||
228 | break; | ||
229 | case TargetNamesEnabled: | ||
230 | // list of all non-disabled target names. Doesn't depend on the passed target. | ||
231 | result = targetNames(false); | ||
232 | break; | ||
233 | |||
234 | case LanguageList: | ||
235 | // Return a map (language, display string). | ||
236 | { | ||
237 | // need to use (QString, QVariant) here, so we can put the map into | ||
238 | // a QVariant by itself. | ||
239 | QMap<QString, QVariant> m; | ||
240 | |||
241 | playerInfo.beginGroup("languages"); | ||
242 | QStringList a = playerInfo.childKeys(); | ||
243 | |||
244 | for(int i = 0; i < a.size(); i++) { | ||
245 | QStringList v = playerInfo.value(a.at(i)).toStringList(); | ||
246 | m[v.at(0)] = v.at(1); | ||
247 | } | ||
248 | playerInfo.endGroup(); | ||
249 | result = m; | ||
250 | } | ||
251 | break; | ||
252 | |||
253 | default: | ||
254 | result = playerInfo.value(s); | ||
255 | break; | ||
256 | } | ||
257 | |||
258 | LOG_INFO() << "T:" << s << result; | ||
259 | return result; | ||
260 | } | ||
261 | |||
262 | QVariant PlayerBuildInfo::value(DeviceInfo item, unsigned int match) | ||
263 | { | ||
264 | QStringList result; | ||
265 | int i = 0; | ||
266 | while(PlayerInfoList[i].item != item) | ||
267 | i++; | ||
268 | QString s = PlayerInfoList[i].name; | ||
269 | |||
270 | switch(item) { | ||
271 | case UsbIdErrorList: | ||
272 | { | ||
273 | // go through all targets and find the one indicated by the usb id "target". | ||
274 | // return list of matching players (since it could be more than one) | ||
275 | QStringList targets = targetNames(true); | ||
276 | for(int i = 0; i < targets.size(); i++) { | ||
277 | QStringList usbids = playerInfo.value(targets.at(i) + "/usberror").toStringList(); | ||
278 | for(int j = 0; j < usbids.size(); j++) { | ||
279 | if(usbids.at(j).toUInt(nullptr, 0) == match) { | ||
280 | result << targets.at(i); | ||
281 | } | ||
282 | } | ||
283 | } | ||
284 | break; | ||
285 | } | ||
286 | |||
287 | case UsbIdTargetList: | ||
288 | { | ||
289 | QStringList targets = targetNames(true); | ||
290 | for(int i = 0; i < targets.size(); i++) { | ||
291 | QStringList usbids = playerInfo.value(targets.at(i) + "/usbid").toStringList(); | ||
292 | for(int j = 0; j < usbids.size(); j++) { | ||
293 | if(usbids.at(j).toUInt(nullptr, 0) == match) { | ||
294 | result << targets.at(i); | ||
295 | } | ||
296 | } | ||
297 | } | ||
298 | break; | ||
299 | } | ||
300 | |||
301 | default: | ||
302 | break; | ||
303 | } | ||
304 | LOG_INFO() << "T:" << s << result; | ||
305 | return result; | ||
306 | } | ||
307 | |||
308 | QVariant PlayerBuildInfo::value(SystemUrl item) | ||
309 | { | ||
310 | // locate setting item in server info file | ||
311 | int i = 0; | ||
312 | while(PlayerSystemUrls[i].item != item) | ||
313 | i++; | ||
314 | |||
315 | QVariant result = playerInfo.value(PlayerSystemUrls[i].name); | ||
316 | LOG_INFO() << "U:" << PlayerSystemUrls[i].name << result; | ||
317 | return result; | ||
318 | } | ||
319 | |||
320 | |||
321 | QString PlayerBuildInfo::statusAsString(QString platform) | ||
322 | { | ||
323 | QString result; | ||
324 | switch(value(BuildStatus, platform).toInt()) | ||
325 | { | ||
326 | case STATUS_RETIRED: | ||
327 | result = tr("Stable (Retired)"); | ||
328 | break; | ||
329 | case STATUS_UNUSABLE: | ||
330 | result = tr("Unusable"); | ||
331 | break; | ||
332 | case STATUS_UNSTABLE: | ||
333 | result = tr("Unstable"); | ||
334 | break; | ||
335 | case STATUS_STABLE: | ||
336 | result = tr("Stable"); | ||
337 | break; | ||
338 | default: | ||
339 | result = tr("Unknown"); | ||
340 | break; | ||
341 | } | ||
342 | |||
343 | return result; | ||
344 | } | ||
345 | |||
346 | |||
347 | QStringList PlayerBuildInfo::targetNames(bool all) | ||
348 | { | ||
349 | QStringList result; | ||
350 | playerInfo.beginGroup("platforms"); | ||
351 | QStringList a = playerInfo.childKeys(); | ||
352 | playerInfo.endGroup(); | ||
353 | for(int i = 0; i < a.size(); i++) | ||
354 | { | ||
355 | QString target = playerInfo.value("platforms/" + a.at(i), "null").toString(); | ||
356 | if(playerInfo.value(target + "/status").toString() != "disabled" || all) { | ||
357 | result.append(target); | ||
358 | } | ||
359 | } | ||
360 | return result; | ||
361 | } | ||
362 | |||