90960adf56
Reworking handling of player specific data (static player configuration, as well as information retrieved from the server) changed the behaviour on a non-present configuration entry. This eventually caused the mountpoint not being set for players that don't have a bootloader file on disk. Fixing this accidentially removed the default-if-not-found handling for the bootloader file. Restore the old default value behaviour for both cases. Change-Id: I627782ccdef198619fb507f8b09a64811b3bd18f
372 lines
12 KiB
C++
372 lines
12 KiB
C++
/***************************************************************************
|
|
* __________ __ ___.
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
* \/ \/ \/ \/ \/
|
|
*
|
|
* Copyright (C) 2020 by Dominik Riebeling
|
|
*
|
|
* All files in this archive are subject to the GNU General Public License.
|
|
* See the file COPYING in the source tree root for full license agreement.
|
|
*
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
* KIND, either express or implied.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include "playerbuildinfo.h"
|
|
#include "rbsettings.h"
|
|
#include "Logger.h"
|
|
|
|
PlayerBuildInfo* PlayerBuildInfo::infoInstance = nullptr;
|
|
|
|
PlayerBuildInfo* PlayerBuildInfo::instance()
|
|
{
|
|
if (infoInstance == nullptr) {
|
|
infoInstance = new PlayerBuildInfo();
|
|
}
|
|
return infoInstance;
|
|
}
|
|
|
|
// server infos
|
|
const static struct {
|
|
PlayerBuildInfo::BuildInfo item;
|
|
const char* name;
|
|
} ServerInfoList[] = {
|
|
{ PlayerBuildInfo::BuildVoiceLangs, "voices/:version:" },
|
|
{ PlayerBuildInfo::BuildVersion, ":build:/:target:" },
|
|
{ PlayerBuildInfo::BuildUrl, ":build:/build_url" },
|
|
{ PlayerBuildInfo::BuildVoiceUrl, ":build:/voice_url" },
|
|
{ PlayerBuildInfo::BuildManualUrl, ":build:/manual_url" },
|
|
{ PlayerBuildInfo::BuildSourceUrl, ":build:/source_url" },
|
|
{ PlayerBuildInfo::BuildFontUrl, ":build:/font_url" },
|
|
|
|
// other URLs -- those are not directly related to the build, but handled here.
|
|
{ PlayerBuildInfo::DoomUrl, "other/doom_url" },
|
|
{ PlayerBuildInfo::Duke3DUrl, "other/duke3d_url" },
|
|
{ PlayerBuildInfo::PuzzFontsUrl, "other/puzzfonts_url" },
|
|
{ PlayerBuildInfo::QuakeUrl, "other/quake_url" },
|
|
{ PlayerBuildInfo::Wolf3DUrl, "other/wolf3d_url" },
|
|
{ PlayerBuildInfo::XWorldUrl, "other/xworld_url" },
|
|
{ PlayerBuildInfo::MidiPatchsetUrl, "other/patcheset_url" },
|
|
};
|
|
|
|
const static struct {
|
|
PlayerBuildInfo::DeviceInfo item;
|
|
const char* name;
|
|
} PlayerInfoList[] = {
|
|
{ PlayerBuildInfo::BuildStatus, "status/:target:" },
|
|
{ PlayerBuildInfo::DisplayName, ":target:/name" },
|
|
{ PlayerBuildInfo::BootloaderMethod, ":target:/bootloadermethod" },
|
|
{ PlayerBuildInfo::BootloaderName, ":target:/bootloadername" },
|
|
{ PlayerBuildInfo::BootloaderFile, ":target:/bootloaderfile" },
|
|
{ PlayerBuildInfo::BootloaderFilter, ":target:/bootloaderfilter" },
|
|
{ PlayerBuildInfo::Encoder, ":target:/encoder" },
|
|
{ PlayerBuildInfo::Brand, ":target:/brand" },
|
|
{ PlayerBuildInfo::PlayerPicture, ":target:/playerpic" },
|
|
{ PlayerBuildInfo::TargetNamesAll, "_targets/all" },
|
|
{ PlayerBuildInfo::TargetNamesEnabled, "_targets/enabled" },
|
|
{ PlayerBuildInfo::LanguageInfo, "languages/:target:" },
|
|
{ PlayerBuildInfo::LanguageList, "_languages/list" },
|
|
{ PlayerBuildInfo::UsbIdErrorList, "_usb/error" },
|
|
{ PlayerBuildInfo::UsbIdTargetList, "_usb/target" },
|
|
};
|
|
|
|
const static struct {
|
|
PlayerBuildInfo::SystemUrl item;
|
|
const char* name;
|
|
} PlayerSystemUrls[] = {
|
|
{ PlayerBuildInfo::BootloaderUrl, "bootloader/download_url" },
|
|
{ PlayerBuildInfo::BuildInfoUrl, "build_info_url" },
|
|
{ PlayerBuildInfo::GenlangUrl, "genlang_url" },
|
|
{ PlayerBuildInfo::ThemesUrl, "themes_url" },
|
|
{ PlayerBuildInfo::ThemesInfoUrl, "themes_info_url" },
|
|
{ PlayerBuildInfo::RbutilUrl, "rbutil_url" },
|
|
};
|
|
|
|
PlayerBuildInfo::PlayerBuildInfo() :
|
|
serverInfo(nullptr),
|
|
playerInfo(":/ini/rbutil.ini", QSettings::IniFormat)
|
|
{
|
|
|
|
}
|
|
|
|
void PlayerBuildInfo::setBuildInfo(QString file)
|
|
{
|
|
if (serverInfo)
|
|
delete serverInfo;
|
|
LOG_INFO() << "updated:" << file;
|
|
serverInfo = new QSettings(file, QSettings::IniFormat);
|
|
}
|
|
|
|
QVariant PlayerBuildInfo::value(BuildInfo item, BuildType type)
|
|
{
|
|
// locate setting item in server info file
|
|
int i = 0;
|
|
while(ServerInfoList[i].item != item)
|
|
i++;
|
|
|
|
// split of variant for target.
|
|
// we can have an optional variant part in the target string.
|
|
// For build info we don't use that.
|
|
QString target = RbSettings::value(RbSettings::CurrentPlatform).toString().split('.').at(0);
|
|
|
|
QString serverinfo = ServerInfoList[i].name;
|
|
serverinfo.replace(":target:", target);
|
|
QString buildtypename;
|
|
switch(type) {
|
|
case TypeRelease:
|
|
buildtypename = "release";
|
|
break;
|
|
case TypeCandidate:
|
|
buildtypename = "release-candidate";
|
|
break;
|
|
case TypeDaily:
|
|
buildtypename = "daily";
|
|
break;
|
|
case TypeDevel:
|
|
buildtypename = "development";
|
|
// manual and fonts don't exist for development builds. We do have an
|
|
// URL configured, but need to get the daily version instead.
|
|
if(item == BuildManualUrl || item == BuildFontUrl) {
|
|
LOG_INFO() << "falling back to daily build for this info value";
|
|
buildtypename = "daily";
|
|
}
|
|
break;
|
|
}
|
|
|
|
QVariant result;
|
|
if (!serverInfo)
|
|
return QString();
|
|
QStringList version = serverInfo->value(buildtypename + "/" + target, "").toStringList();
|
|
serverinfo.replace(":build:", buildtypename);
|
|
serverinfo.replace(":version:", version.at(0));
|
|
|
|
// get value from server build-info
|
|
// we need to get a version string, otherwise the data is invalid.
|
|
// For invalid data return an empty string.
|
|
if(version.at(0).isEmpty()) {
|
|
LOG_INFO() << serverinfo << "(version invalid)";
|
|
return QString();
|
|
}
|
|
if(!serverinfo.isEmpty())
|
|
result = serverInfo->value(serverinfo);
|
|
|
|
// depending on the actual value we need more replacements.
|
|
switch(item) {
|
|
case BuildVersion:
|
|
result = result.toStringList().at(0);
|
|
break;
|
|
|
|
case BuildUrl:
|
|
if(version.size() > 1) {
|
|
// version info has an URL appended. Takes precendence.
|
|
result = version.at(1);
|
|
}
|
|
break;
|
|
|
|
case BuildVoiceLangs:
|
|
if (type == TypeDaily)
|
|
serverinfo = "voices/daily";
|
|
result = serverInfo->value(serverinfo);
|
|
break;
|
|
|
|
case BuildManualUrl:
|
|
{
|
|
// special case: if playerInfo has a non-empty manualname entry for the
|
|
// target, use that as target for the manual name.
|
|
QString manualtarget = playerInfo.value(target + "/manualname", "").toString();
|
|
if(!manualtarget.isEmpty())
|
|
target = manualtarget;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
// if the value is a string we can replace some patterns.
|
|
// if we cannot convert it (f.e. for a QStringList) we leave as-is, since
|
|
// the conversion would return an empty type.
|
|
#if QT_VERSION < 0x060000
|
|
if (result.type() == QVariant::String)
|
|
#else
|
|
if (result.metaType().id() == QMetaType::QString)
|
|
#endif
|
|
result = result.toString()
|
|
.replace("%TARGET%", target)
|
|
.replace("%VERSION%", version.at(0));
|
|
|
|
LOG_INFO() << "B:" << serverinfo << result;
|
|
return result;
|
|
}
|
|
|
|
QVariant PlayerBuildInfo::value(DeviceInfo item, QString target)
|
|
{
|
|
// locate setting item in server info file
|
|
int i = 0;
|
|
while(PlayerInfoList[i].item != item)
|
|
i++;
|
|
|
|
// split of variant for target.
|
|
// we can have an optional variant part in the target string.
|
|
// For device info we use this.
|
|
if (target.isEmpty())
|
|
target = RbSettings::value(RbSettings::CurrentPlatform).toString();
|
|
|
|
QVariant result = QString();
|
|
|
|
QString s = PlayerInfoList[i].name;
|
|
s.replace(":target:", target);
|
|
|
|
switch(item) {
|
|
case BuildStatus:
|
|
{
|
|
// build status is the only value that doesn't depend on the version
|
|
// but the selected target instead.
|
|
bool ok = false;
|
|
if (serverInfo)
|
|
result = serverInfo->value(s).toInt(&ok);
|
|
if (!ok)
|
|
result = -1;
|
|
break;
|
|
}
|
|
case TargetNamesAll:
|
|
// list of all internal target names. Doesn't depend on the passed target.
|
|
result = targetNames(true);
|
|
break;
|
|
case TargetNamesEnabled:
|
|
// list of all non-disabled target names. Doesn't depend on the passed target.
|
|
result = targetNames(false);
|
|
break;
|
|
|
|
case LanguageList:
|
|
// Return a map (language, display string).
|
|
{
|
|
// need to use (QString, QVariant) here, so we can put the map into
|
|
// a QVariant by itself.
|
|
QMap<QString, QVariant> m;
|
|
|
|
playerInfo.beginGroup("languages");
|
|
QStringList a = playerInfo.childKeys();
|
|
|
|
for(int i = 0; i < a.size(); i++) {
|
|
QStringList v = playerInfo.value(a.at(i)).toStringList();
|
|
m[v.at(0)] = v.at(1);
|
|
}
|
|
playerInfo.endGroup();
|
|
result = m;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
result = playerInfo.value(s, "");
|
|
break;
|
|
}
|
|
|
|
LOG_INFO() << "T:" << s << result;
|
|
return result;
|
|
}
|
|
|
|
QVariant PlayerBuildInfo::value(DeviceInfo item, unsigned int match)
|
|
{
|
|
QStringList result;
|
|
int i = 0;
|
|
while(PlayerInfoList[i].item != item)
|
|
i++;
|
|
QString s = PlayerInfoList[i].name;
|
|
|
|
switch(item) {
|
|
case UsbIdErrorList:
|
|
{
|
|
// go through all targets and find the one indicated by the usb id "target".
|
|
// return list of matching players (since it could be more than one)
|
|
QStringList targets = targetNames(true);
|
|
for(int i = 0; i < targets.size(); i++) {
|
|
QStringList usbids = playerInfo.value(targets.at(i) + "/usberror").toStringList();
|
|
for(int j = 0; j < usbids.size(); j++) {
|
|
if(usbids.at(j).toUInt(nullptr, 0) == match) {
|
|
result << targets.at(i);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case UsbIdTargetList:
|
|
{
|
|
QStringList targets = targetNames(true);
|
|
for(int i = 0; i < targets.size(); i++) {
|
|
QStringList usbids = playerInfo.value(targets.at(i) + "/usbid").toStringList();
|
|
for(int j = 0; j < usbids.size(); j++) {
|
|
if(usbids.at(j).toUInt(nullptr, 0) == match) {
|
|
result << targets.at(i);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
LOG_INFO() << "T:" << s << result;
|
|
return result;
|
|
}
|
|
|
|
QVariant PlayerBuildInfo::value(SystemUrl item)
|
|
{
|
|
// locate setting item in server info file
|
|
int i = 0;
|
|
while(PlayerSystemUrls[i].item != item)
|
|
i++;
|
|
|
|
QVariant result = playerInfo.value(PlayerSystemUrls[i].name);
|
|
LOG_INFO() << "U:" << PlayerSystemUrls[i].name << result;
|
|
return result;
|
|
}
|
|
|
|
|
|
QString PlayerBuildInfo::statusAsString(QString platform)
|
|
{
|
|
QString result;
|
|
switch(value(BuildStatus, platform).toInt())
|
|
{
|
|
case STATUS_RETIRED:
|
|
result = tr("Stable (Retired)");
|
|
break;
|
|
case STATUS_UNUSABLE:
|
|
result = tr("Unusable");
|
|
break;
|
|
case STATUS_UNSTABLE:
|
|
result = tr("Unstable");
|
|
break;
|
|
case STATUS_STABLE:
|
|
result = tr("Stable");
|
|
break;
|
|
default:
|
|
result = tr("Unknown");
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
QStringList PlayerBuildInfo::targetNames(bool all)
|
|
{
|
|
QStringList result;
|
|
playerInfo.beginGroup("platforms");
|
|
QStringList a = playerInfo.childKeys();
|
|
playerInfo.endGroup();
|
|
for(int i = 0; i < a.size(); i++)
|
|
{
|
|
QString target = playerInfo.value("platforms/" + a.at(i), "null").toString();
|
|
if(playerInfo.value(target + "/status").toString() != "disabled" || all) {
|
|
result.append(target);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|