From d86f020e81f3df53a83c80f1a0a99f1b12093010 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Fri, 10 Mar 2017 18:11:45 +0100 Subject: [PATCH] Rewrite SysConf handling This rewrites the SysConf code for several reasons: * Modernising the SysConf class. The naming was entirely cleaned up. constexpr for constants. * Exposing less stuff in the header. * Probably less efficient parsing and writing logic, but much simpler to understand and use in my opinion. No more hardcoded offsets. No more duplicated code for the initial SYSCONF generation. * More flexibility. It is now possible to add and remove entries, since we rebuild the file. This allows us to stop spamming "section not found" panic alerts; we can now use and insert default entries. --- Source/Core/Common/SysConf.cpp | 640 +++++++----------- Source/Core/Common/SysConf.h | 221 ++---- Source/Core/Core/ConfigManager.cpp | 42 +- Source/Core/Core/IOS/USB/Bluetooth/BTBase.cpp | 13 +- Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp | 65 +- 5 files changed, 377 insertions(+), 604 deletions(-) diff --git a/Source/Core/Common/SysConf.cpp b/Source/Core/Common/SysConf.cpp index a1865f7fc3..44c0603dd5 100644 --- a/Source/Core/Common/SysConf.cpp +++ b/Source/Core/Common/SysConf.cpp @@ -5,80 +5,259 @@ #include "Common/SysConf.h" #include -#include +#include #include -#include -#include -#include #include "Common/CommonPaths.h" #include "Common/CommonTypes.h" #include "Common/File.h" #include "Common/FileUtil.h" +#include "Common/Logging/Log.h" #include "Common/Swap.h" #include "Core/Movie.h" +constexpr size_t SYSCONF_SIZE = 0x4000; + +static size_t GetNonArrayEntrySize(SysConf::Entry::Type type) +{ + switch (type) + { + case SysConf::Entry::Type::Byte: + case SysConf::Entry::Type::ByteBool: + return 1; + case SysConf::Entry::Type::Short: + return 2; + case SysConf::Entry::Type::Long: + return 4; + case SysConf::Entry::Type::LongLong: + return 8; + default: + _assert_(false); + return 0; + } +} SysConf::SysConf(const Common::FromWhichRoot root_type) { - UpdateLocation(root_type); + m_file_name = Common::RootUserPath(root_type) + DIR_SEP WII_SYSCONF_DIR DIR_SEP WII_SYSCONF; + Load(); } SysConf::~SysConf() { - if (!m_IsValid) - return; - Save(); - Clear(); } void SysConf::Clear() { - m_Entries.clear(); + m_entries.clear(); } -bool SysConf::LoadFromFile(const std::string& filename) +void SysConf::Load() { - if (m_IsValid) - Clear(); - m_IsValid = false; + Clear(); - // Basic check - if (!File::Exists(filename)) + if (!File::Exists(m_file_name) || File::GetSize(m_file_name) != SYSCONF_SIZE || + !LoadFromFile(m_file_name)) { - File::CreateFullPath(filename); - GenerateSysConf(); - ApplySettingsFromMovie(); - return true; + WARN_LOG(CORE, "No valid SYSCONF detected. Creating a new one."); + InsertDefaultEntries(); } - u64 size = File::GetSize(filename); - if (size != SYSCONF_SIZE) + ApplySettingsFromMovie(); +} + +bool SysConf::LoadFromFile(const std::string& file_name) +{ + File::IOFile file(file_name, "rb"); + file.Seek(4, SEEK_SET); + u16 number_of_entries; + file.ReadBytes(&number_of_entries, sizeof(number_of_entries)); + number_of_entries = Common::swap16(number_of_entries); + + std::vector offsets(number_of_entries); + for (u16& offset : offsets) { - if (AskYesNoT("Your SYSCONF file is the wrong size.\nIt should be 0x%04x (but is 0x%04" PRIx64 - ")\nDo you want to generate a new one?", - SYSCONF_SIZE, size)) + file.ReadBytes(&offset, sizeof(offset)); + offset = Common::swap16(offset); + } + + for (const u16 offset : offsets) + { + file.Seek(offset, SEEK_SET); + + // Metadata + u8 description = 0; + file.ReadBytes(&description, sizeof(description)); + const Entry::Type type = static_cast((description & 0xe0) >> 5); + const u8 name_length = (description & 0x1f) + 1; + std::string name(name_length, '\0'); + file.ReadBytes(&name[0], name.size()); + + // Data + std::vector data; + switch (type) { - GenerateSysConf(); - ApplySettingsFromMovie(); - return true; + case Entry::Type::BigArray: + { + u16 data_length = 0; + file.ReadBytes(&data_length, sizeof(data_length)); + data.resize(Common::swap16(data_length)); + break; } - return false; - } - - File::IOFile f(filename, "rb"); - if (f.IsOpen()) - { - if (LoadFromFileInternal(std::move(f))) + case Entry::Type::SmallArray: { - m_Filename = filename; - m_IsValid = true; - ApplySettingsFromMovie(); - return true; + u8 data_length = 0; + file.ReadBytes(&data_length, sizeof(data_length)); + data.resize(data_length); + break; + } + case Entry::Type::Byte: + case Entry::Type::ByteBool: + case Entry::Type::Short: + case Entry::Type::Long: + case Entry::Type::LongLong: + data.resize(GetNonArrayEntrySize(type)); + break; + default: + ERROR_LOG(CORE, "Unknown entry type %d in SYSCONF for %s (offset %u)", static_cast(type), + name.c_str(), offset); + return false; + } + + file.ReadBytes(data.data(), data.size()); + AddEntry({type, name, std::move(data)}); + } + return true; +} + +template +static void AppendToBuffer(std::vector* vector, T value) +{ + const T swapped_value = Common::FromBigEndian(value); + vector->resize(vector->size() + sizeof(T)); + std::memcpy(&*(vector->end() - sizeof(T)), &swapped_value, sizeof(T)); +} + +bool SysConf::Save() const +{ + std::vector buffer; + buffer.reserve(SYSCONF_SIZE); + + // Header + constexpr std::array version{{'S', 'C', 'v', '0'}}; + buffer.insert(buffer.end(), version.cbegin(), version.cend()); + AppendToBuffer(&buffer, static_cast(m_entries.size())); + + const size_t entries_begin_offset = buffer.size() + sizeof(u16) * (m_entries.size() + 1); + std::vector entries; + for (const auto& item : m_entries) + { + // Offset + AppendToBuffer(&buffer, static_cast(entries_begin_offset + entries.size())); + + // Entry metadata (type and name) + entries.insert(entries.end(), + (static_cast(item.type) << 5) | (static_cast(item.name.size()) - 1)); + entries.insert(entries.end(), item.name.cbegin(), item.name.cend()); + + // Entry data + switch (item.type) + { + case Entry::Type::BigArray: + { + const u16 data_size = static_cast(item.bytes.size()); + AppendToBuffer(&entries, data_size); + entries.insert(entries.end(), item.bytes.cbegin(), item.bytes.cbegin() + data_size); + // Unused byte. + entries.insert(entries.end(), '\0'); + break; + } + + case Entry::Type::SmallArray: + { + const u8 data_size = static_cast(item.bytes.size()); + AppendToBuffer(&entries, data_size); + entries.insert(entries.end(), item.bytes.cbegin(), item.bytes.cbegin() + data_size); + // Unused byte. + entries.insert(entries.end(), '\0'); + break; + } + + default: + entries.insert(entries.end(), item.bytes.cbegin(), item.bytes.cend()); + break; } } + // Offset for the dummy past-the-end entry. + AppendToBuffer(&buffer, static_cast(entries_begin_offset + entries.size())); - return false; + // Main data. + buffer.insert(buffer.end(), entries.cbegin(), entries.cend()); + + // Make sure the buffer size is 0x4000 bytes now and write the footer. + buffer.resize(SYSCONF_SIZE); + constexpr std::array footer = {{'S', 'C', 'e', 'd'}}; + std::copy(footer.cbegin(), footer.cend(), buffer.end() - footer.size()); + + // Write the new data. + const std::string temp_file = File::GetTempFilenameForAtomicWrite(m_file_name); + File::CreateFullPath(temp_file); + { + File::IOFile file(temp_file, "wb"); + if (!file.WriteBytes(buffer.data(), buffer.size())) + return false; + } + return File::RenameSync(temp_file, m_file_name); +} + +SysConf::Entry::Entry(Type type_, const std::string& name_) : type(type_), name(name_) +{ + if (type != Type::SmallArray && type != Type::BigArray) + bytes.resize(GetNonArrayEntrySize(type)); +} + +SysConf::Entry::Entry(Type type_, const std::string& name_, const std::vector& bytes_) + : type(type_), name(name_), bytes(bytes_) +{ +} + +SysConf::Entry::Entry(Type type_, const std::string& name_, std::vector&& bytes_) + : type(type_), name(name_), bytes(std::move(bytes_)) +{ +} + +void SysConf::AddEntry(Entry&& entry) +{ + m_entries.emplace_back(std::move(entry)); +} + +SysConf::Entry* SysConf::GetEntry(const std::string& key) +{ + const auto iterator = std::find_if(m_entries.begin(), m_entries.end(), + [&key](const auto& entry) { return entry.name == key; }); + return iterator != m_entries.end() ? &*iterator : nullptr; +} + +const SysConf::Entry* SysConf::GetEntry(const std::string& key) const +{ + const auto iterator = std::find_if(m_entries.begin(), m_entries.end(), + [&key](const auto& entry) { return entry.name == key; }); + return iterator != m_entries.end() ? &*iterator : nullptr; +} + +SysConf::Entry* SysConf::GetOrAddEntry(const std::string& key, Entry::Type type) +{ + if (Entry* entry = GetEntry(key)) + return entry; + AddEntry({type, key}); + return GetEntry(key); +} + +void SysConf::RemoveEntry(const std::string& key) +{ + m_entries.erase(std::remove_if(m_entries.begin(), m_entries.end(), + [&key](const auto& entry) { return entry.name == key; }), + m_entries.end()); } // Apply Wii settings from normal SYSCONF on Movie recording/playback @@ -87,358 +266,51 @@ void SysConf::ApplySettingsFromMovie() if (!Movie::IsMovieActive()) return; - SetData("IPL.LNG", Movie::GetLanguage()); - SetData("IPL.E60", Movie::IsPAL60()); - SetData("IPL.PGS", Movie::IsProgressive()); + SetData("IPL.LNG", Entry::Type::Byte, Movie::GetLanguage()); + SetData("IPL.E60", Entry::Type::Byte, Movie::IsPAL60()); + SetData("IPL.PGS", Entry::Type::Byte, Movie::IsProgressive()); } -bool SysConf::LoadFromFileInternal(File::IOFile&& file) +void SysConf::InsertDefaultEntries() { - // Fill in infos - SSysConfHeader s_Header; - file.ReadArray(s_Header.version, 4); - file.ReadArray(&s_Header.numEntries, 1); - s_Header.numEntries = Common::swap16(s_Header.numEntries) + 1; + AddEntry({Entry::Type::BigArray, "BT.DINF", std::vector(0x460)}); + AddEntry({Entry::Type::BigArray, "BT.CDIF", std::vector(0x204)}); + AddEntry({Entry::Type::Long, "BT.SENS", {0, 0, 0, 3}}); + AddEntry({Entry::Type::Byte, "BT.BAR", {1}}); + AddEntry({Entry::Type::Byte, "BT.SPKV", {0x58}}); + AddEntry({Entry::Type::Byte, "BT.MOT", {1}}); - for (u16 index = 0; index < s_Header.numEntries; index++) - { - SSysConfEntry tmpEntry; - file.ReadArray(&tmpEntry.offset, 1); - tmpEntry.offset = Common::swap16(tmpEntry.offset); - m_Entries.push_back(std::move(tmpEntry)); - } + const std::vector console_nick = {0, 'd', 0, 'o', 0, 'l', 0, 'p', 0, 'h', 0, 'i', 0, 'n'}; + AddEntry({Entry::Type::SmallArray, "IPL.NIK", std::move(console_nick)}); - // Last offset is an invalid entry. We ignore it throughout this class - for (auto i = m_Entries.begin(); i < m_Entries.end() - 1; ++i) - { - SSysConfEntry& curEntry = *i; - file.Seek(curEntry.offset, SEEK_SET); + AddEntry({Entry::Type::Byte, "IPL.LNG", {1}}); + std::vector ipl_sadr(0x1007); + ipl_sadr[0] = 0x6c; + AddEntry({Entry::Type::BigArray, "IPL.SADR", std::move(ipl_sadr)}); - u8 description = 0; - file.ReadArray(&description, 1); - // Data type - curEntry.type = (SysconfType)((description & 0xe0) >> 5); - // Length of name in bytes - 1 - curEntry.nameLength = (description & 0x1f) + 1; - // Name - file.ReadArray(curEntry.name, curEntry.nameLength); - curEntry.name[curEntry.nameLength] = '\0'; - // Get length of data - curEntry.data.clear(); - curEntry.dataLength = 0; - switch (curEntry.type) - { - case Type_BigArray: - file.ReadArray(&curEntry.dataLength, 1); - curEntry.dataLength = Common::swap16(curEntry.dataLength); - break; + std::vector ipl_pc(0x50); + ipl_pc[1] = 0x04; + ipl_pc[2] = 0x14; + AddEntry({Entry::Type::SmallArray, "IPL.PC", std::move(ipl_pc)}); - case Type_SmallArray: - { - u8 dlength = 0; - file.ReadBytes(&dlength, 1); - curEntry.dataLength = dlength; - break; - } + AddEntry({Entry::Type::Long, "IPL.CB", {0x0f, 0x11, 0x14, 0xa6}}); + AddEntry({Entry::Type::Byte, "IPL.AR", {1}}); + AddEntry({Entry::Type::Byte, "IPL.SSV", {1}}); - case Type_Byte: - case Type_Bool: - curEntry.dataLength = 1; - break; + AddEntry({Entry::Type::ByteBool, "IPL.CD", {1}}); + AddEntry({Entry::Type::ByteBool, "IPL.CD2", {1}}); + AddEntry({Entry::Type::ByteBool, "IPL.EULA", {1}}); + AddEntry({Entry::Type::Byte, "IPL.UPT", {2}}); + AddEntry({Entry::Type::Byte, "IPL.PGS", {0}}); + AddEntry({Entry::Type::Byte, "IPL.E60", {1}}); + AddEntry({Entry::Type::Byte, "IPL.DH", {0}}); + AddEntry({Entry::Type::Long, "IPL.INC", {0, 0, 0, 8}}); + AddEntry({Entry::Type::Long, "IPL.FRC", {0, 0, 0, 0x28}}); + AddEntry({Entry::Type::SmallArray, "IPL.IDL", {0}}); - case Type_Short: - curEntry.dataLength = 2; - break; + AddEntry({Entry::Type::Long, "NET.WCFG", {0, 0, 0, 1}}); + AddEntry({Entry::Type::Long, "NET.CTPC", std::vector(4)}); + AddEntry({Entry::Type::Byte, "WWW.RST", {0}}); - case Type_Long: - curEntry.dataLength = 4; - break; - - case Type_LongLong: - curEntry.dataLength = 8; - break; - - default: - PanicAlertT("Unknown entry type %i in SYSCONF (%s@%x)!", curEntry.type, curEntry.name, - curEntry.offset); - return false; - break; - } - // Fill in the actual data - if (curEntry.dataLength) - { - curEntry.data.resize(curEntry.dataLength); - file.ReadArray(curEntry.data.data(), curEntry.dataLength); - } - } - - return file.IsGood(); -} - -// Returns the size of the item in file -static unsigned int create_item(SSysConfEntry& item, SysconfType type, const std::string& name, - const int data_length, unsigned int offset) -{ - item.offset = offset; - item.type = type; - item.nameLength = (u8)(name.length()); - strncpy(item.name, name.c_str(), 32); - item.dataLength = data_length; - item.data.resize(data_length); - switch (type) - { - case Type_BigArray: - // size of description + name length + size of dataLength + data length + null - return 1 + item.nameLength + 2 + item.dataLength + 1; - case Type_SmallArray: - // size of description + name length + size of dataLength + data length + null - return 1 + item.nameLength + 1 + item.dataLength + 1; - case Type_Byte: - case Type_Bool: - case Type_Short: - case Type_Long: - // size of description + name length + data length - return 1 + item.nameLength + item.dataLength; - default: - return 0; - } -} - -void SysConf::GenerateSysConf() -{ - SSysConfHeader s_Header; - strncpy(s_Header.version, "SCv0", 4); - s_Header.numEntries = Common::swap16(28 - 1); - - std::vector items(27); - - // version length + size of numEntries + 28 * size of offset - unsigned int current_offset = 4 + 2 + 28 * 2; - - // BT.DINF - current_offset += create_item(items[0], Type_BigArray, "BT.DINF", 0x460, current_offset); - items[0].data[0] = 4; - for (u8 i = 0; i < 4; ++i) - { - const u8 bt_addr[6] = {i, 0x00, 0x79, 0x19, 0x02, 0x11}; - memcpy(&items[0].data[1 + 70 * i], bt_addr, sizeof(bt_addr)); - memcpy(&items[0].data[7 + 70 * i], "Nintendo RVL-CNT-01", 19); - } - - // BT.SENS - current_offset += create_item(items[1], Type_Long, "BT.SENS", 4, current_offset); - items[1].data[3] = 0x03; - - // IPL.NIK - current_offset += create_item(items[2], Type_SmallArray, "IPL.NIK", 0x15, current_offset); - const u8 console_nick[14] = {0, 'd', 0, 'o', 0, 'l', 0, 'p', 0, 'h', 0, 'i', 0, 'n'}; - memcpy(items[2].data.data(), console_nick, 14); - - // IPL.AR - current_offset += create_item(items[3], Type_Byte, "IPL.AR", 1, current_offset); - items[3].data[0] = 0x01; - - // BT.BAR - current_offset += create_item(items[4], Type_Byte, "BT.BAR", 1, current_offset); - items[4].data[0] = 0x01; - - // IPL.SSV - current_offset += create_item(items[5], Type_Byte, "IPL.SSV", 1, current_offset); - - // IPL.LNG - current_offset += create_item(items[6], Type_Byte, "IPL.LNG", 1, current_offset); - items[6].data[0] = 0x01; - - // IPL.SADR - current_offset += create_item(items[7], Type_BigArray, "IPL.SADR", 0x1007, current_offset); - items[7].data[0] = 0x6c; //(Switzerland) TODO should this default be changed? - - // IPL.CB - current_offset += create_item(items[8], Type_Long, "IPL.CB", 4, current_offset); - items[8].data[0] = 0x0f; - items[8].data[1] = 0x11; - items[8].data[2] = 0x14; - items[8].data[3] = 0xa6; - - // BT.SPKV - current_offset += create_item(items[9], Type_Byte, "BT.SPKV", 1, current_offset); - items[9].data[0] = 0x58; - - // IPL.PC - current_offset += create_item(items[10], Type_SmallArray, "IPL.PC", 0x49, current_offset); - items[10].data[1] = 0x04; - items[10].data[2] = 0x14; - - // NET.CTPC - current_offset += create_item(items[11], Type_Long, "NET.CTPC", 4, current_offset); - - // WWW.RST - current_offset += create_item(items[12], Type_Bool, "WWW.RST", 1, current_offset); - - // BT.CDIF - current_offset += create_item(items[13], Type_BigArray, "BT.CDIF", 0x204, current_offset); - - // IPL.INC - current_offset += create_item(items[14], Type_Long, "IPL.INC", 4, current_offset); - items[14].data[3] = 0x08; - - // IPL.FRC - current_offset += create_item(items[15], Type_Long, "IPL.FRC", 4, current_offset); - items[15].data[3] = 0x28; - - // IPL.CD - current_offset += create_item(items[16], Type_Bool, "IPL.CD", 1, current_offset); - items[16].data[0] = 0x01; - - // IPL.CD2 - current_offset += create_item(items[17], Type_Bool, "IPL.CD2", 1, current_offset); - items[17].data[0] = 0x01; - - // IPL.UPT - current_offset += create_item(items[18], Type_Byte, "IPL.UPT", 1, current_offset); - items[18].data[0] = 0x02; - - // IPL.PGS - current_offset += create_item(items[19], Type_Byte, "IPL.PGS", 1, current_offset); - - // IPL.E60 - current_offset += create_item(items[20], Type_Byte, "IPL.E60", 1, current_offset); - items[20].data[0] = 0x01; - - // IPL.DH - current_offset += create_item(items[21], Type_Byte, "IPL.DH", 1, current_offset); - - // NET.WCFG - current_offset += create_item(items[22], Type_Long, "NET.WCFG", 4, current_offset); - items[22].data[3] = 0x01; - - // IPL.IDL - current_offset += create_item(items[23], Type_SmallArray, "IPL.IDL", 1, current_offset); - items[23].data[0] = 0x00; - - // IPL.EULA - current_offset += create_item(items[24], Type_Bool, "IPL.EULA", 1, current_offset); - items[24].data[0] = 0x01; - - // BT.MOT - current_offset += create_item(items[25], Type_Byte, "BT.MOT", 1, current_offset); - items[25].data[0] = 0x01; - - // MPLS.MOVIE - current_offset += create_item(items[26], Type_Bool, "MPLS.MOVIE", 1, current_offset); - items[26].data[0] = 0x01; - - File::CreateFullPath(m_FilenameDefault); - File::IOFile g(m_FilenameDefault, "wb"); - - // Write the header and item offsets - g.WriteBytes(&s_Header.version, sizeof(s_Header.version)); - g.WriteBytes(&s_Header.numEntries, sizeof(u16)); - for (const auto& item : items) - { - const u16 tmp_offset = Common::swap16(item.offset); - g.WriteBytes(&tmp_offset, 2); - } - const u16 end_data_offset = Common::swap16(current_offset); - g.WriteBytes(&end_data_offset, 2); - - // Write the items - const u8 null_byte = 0; - for (const auto& item : items) - { - u8 description = (item.type << 5) | (item.nameLength - 1); - g.WriteBytes(&description, sizeof(description)); - g.WriteBytes(&item.name, item.nameLength); - switch (item.type) - { - case Type_BigArray: - { - const u16 tmpDataLength = Common::swap16(item.dataLength); - g.WriteBytes(&tmpDataLength, 2); - g.WriteBytes(item.data.data(), item.dataLength); - g.WriteBytes(&null_byte, 1); - } - break; - - case Type_SmallArray: - g.WriteBytes(&item.dataLength, 1); - g.WriteBytes(item.data.data(), item.dataLength); - g.WriteBytes(&null_byte, 1); - break; - - default: - g.WriteBytes(item.data.data(), item.dataLength); - break; - } - } - - // Pad file to the correct size - const u64 cur_size = g.GetSize(); - for (unsigned int i = 0; i != 16380 - cur_size; ++i) - g.WriteBytes(&null_byte, 1); - - // Write the footer - g.WriteBytes("SCed", 4); - - m_Entries = std::move(items); - m_Filename = m_FilenameDefault; - m_IsValid = true; -} - -bool SysConf::SaveToFile(const std::string& filename) -{ - File::IOFile f(filename, "r+b"); - - for (auto i = m_Entries.begin(); i < m_Entries.end() - 1; ++i) - { - // Seek to after the name of this entry - f.Seek(i->offset + i->nameLength + 1, SEEK_SET); - - // We may have to write array length value... - if (i->type == Type_BigArray) - { - const u16 tmpDataLength = Common::swap16(i->dataLength); - f.WriteArray(&tmpDataLength, 1); - } - else if (i->type == Type_SmallArray) - { - const u8 len = (u8)(i->dataLength); - f.WriteArray(&len, 1); - } - - // Now write the actual data - f.WriteBytes(i->data.data(), i->dataLength); - } - - return f.IsGood(); -} - -bool SysConf::Save() -{ - if (!m_IsValid) - return false; - - return SaveToFile(m_Filename); -} - -void SysConf::UpdateLocation(const Common::FromWhichRoot root_type) -{ - // if the old Wii User dir had a sysconf file save any settings that have been changed to it - if (m_IsValid) - Save(); - - // Clear the old filename and set the default filename to the new user path - // So that it can be generated if the file does not exist in the new location - m_Filename.clear(); - // In the future the SYSCONF should probably just be synced with the other settings. - m_FilenameDefault = Common::RootUserPath(root_type) + DIR_SEP WII_SYSCONF_DIR DIR_SEP WII_SYSCONF; - Reload(); -} - -bool SysConf::Reload() -{ - std::string& filename = m_Filename.empty() ? m_FilenameDefault : m_Filename; - - LoadFromFile(filename); - return m_IsValid; + AddEntry({Entry::Type::ByteBool, "MPLS.MOVIE", {1}}); } diff --git a/Source/Core/Common/SysConf.h b/Source/Core/Common/SysConf.h index 0d7e9c3e41..9600e725bd 100644 --- a/Source/Core/Common/SysConf.h +++ b/Source/Core/Common/SysConf.h @@ -2,193 +2,92 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +// Utilities to parse and modify a Wii SYSCONF file and its sections. + #pragma once -#include -#include #include #include #include +#include "Common/Assert.h" #include "Common/CommonTypes.h" -#include "Common/Logging/Log.h" -#include "Common/MsgHandler.h" #include "Common/NandPaths.h" -namespace File -{ -class IOFile; -} - -// This class is meant to edit the values in a given Wii SYSCONF file -// It currently does not add/remove/rearrange sections, -// instead only modifies exiting sections' data - -#define SYSCONF_SIZE 0x4000 - -enum SysconfType -{ - Type_BigArray = 1, - Type_SmallArray, - Type_Byte, - Type_Short, - Type_Long, - Type_LongLong, - Type_Bool -}; - -struct SSysConfHeader -{ - char version[4]; - u16 numEntries; -}; - -struct SSysConfEntry -{ - u16 offset = 0; - SysconfType type; - u8 nameLength = 0; - char name[32] = {}; - u16 dataLength = 0; - std::vector data; - - template - T GetData() const - { - T extracted_data; - std::memcpy(&extracted_data, data.data(), sizeof(T)); - return extracted_data; - } - bool GetArrayData(u8* dest, u16 destSize) const - { - if (dest && destSize >= dataLength) - { - memcpy(dest, data.data(), dataLength); - return true; - } - return false; - } - bool SetArrayData(const u8* buffer, u16 bufferSize) - { - if (buffer) - { - memcpy(data.data(), buffer, std::min(bufferSize, dataLength)); - return true; - } - return false; - } -}; - -class SysConf +class SysConf final { public: SysConf(Common::FromWhichRoot root_type); ~SysConf(); - bool IsValid() const { return m_IsValid; } - template - T GetData(const char* sectionName) const + void Clear(); + void Load(); + bool Save() const; + + struct Entry { - if (!m_IsValid) + enum Type : u8 { - PanicAlertT("Trying to read from invalid SYSCONF"); - return 0; + BigArray = 1, + SmallArray = 2, + Byte = 3, + Short = 4, + Long = 5, + LongLong = 6, + // Should really be named Bool, but this conflicts with some random macro. :/ + ByteBool = 7, + }; + + Entry(Type type_, const std::string& name_); + Entry(Type type_, const std::string& name_, const std::vector& bytes_); + Entry(Type type_, const std::string& name_, std::vector&& bytes_); + + // Intended for use with the non array types. + template + T GetData(T default_value) const + { + if (bytes.size() != sizeof(T)) + return default_value; + T value; + std::memcpy(&value, bytes.data(), bytes.size()); + return value; + } + template + void SetData(T value) + { + _assert_(sizeof(value) == bytes.size()); + std::memcpy(bytes.data(), &value, bytes.size()); } - auto index = m_Entries.cbegin(); - for (; index < m_Entries.cend() - 1; ++index) - { - if (strcmp(index->name, sectionName) == 0) - break; - } - if (index == m_Entries.cend() - 1) - { - PanicAlertT("Section %s not found in SYSCONF", sectionName); - return 0; - } + Type type; + std::string name; + std::vector bytes; + }; - return index->GetData(); - } + void AddEntry(Entry&& entry); + Entry* GetEntry(const std::string& key); + const Entry* GetEntry(const std::string& key) const; + Entry* GetOrAddEntry(const std::string& key, Entry::Type type); + void RemoveEntry(const std::string& key); - bool GetArrayData(const char* sectionName, u8* dest, u16 destSize) const + // Intended for use with the non array types. + template + T GetData(const std::string& key, T default_value) const { - if (!m_IsValid) - { - PanicAlertT("Trying to read from invalid SYSCONF"); - return false; - } - - auto index = m_Entries.cbegin(); - for (; index < m_Entries.cend() - 1; ++index) - { - if (strcmp(index->name, sectionName) == 0) - break; - } - if (index == m_Entries.cend() - 1) - { - PanicAlertT("Section %s not found in SYSCONF", sectionName); - return false; - } - - return index->GetArrayData(dest, destSize); + const Entry* entry = GetEntry(key); + return entry ? entry->GetData(default_value) : default_value; } - - bool SetArrayData(const char* sectionName, const u8* buffer, u16 bufferSize) + template + void SetData(const std::string& key, Entry::Type type, T value) { - if (!m_IsValid) - return false; - - auto index = m_Entries.begin(); - for (; index < m_Entries.end() - 1; ++index) - { - if (strcmp(index->name, sectionName) == 0) - break; - } - if (index == m_Entries.end() - 1) - { - PanicAlertT("Section %s not found in SYSCONF", sectionName); - return false; - } - - return index->SetArrayData(buffer, bufferSize); + GetOrAddEntry(key, type)->SetData(value); } - template - bool SetData(const char* sectionName, T newValue) - { - if (!m_IsValid) - return false; - - auto index = m_Entries.begin(); - for (; index < m_Entries.end() - 1; ++index) - { - if (strcmp(index->name, sectionName) == 0) - break; - } - if (index == m_Entries.end() - 1) - { - PanicAlertT("Section %s not found in SYSCONF", sectionName); - return false; - } - - std::memcpy(index->data.data(), &newValue, sizeof(T)); - return true; - } - - bool Save(); - bool SaveToFile(const std::string& filename); - bool LoadFromFile(const std::string& filename); - bool Reload(); - void UpdateLocation(Common::FromWhichRoot root_type); - private: - bool LoadFromFileInternal(File::IOFile&& file); - void GenerateSysConf(); - void Clear(); void ApplySettingsFromMovie(); + void InsertDefaultEntries(); + bool LoadFromFile(const std::string& file_name); - std::string m_Filename; - std::string m_FilenameDefault; - std::vector m_Entries; - bool m_IsValid = false; + std::string m_file_name; + std::vector m_entries; }; diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index 86d499c4de..19af3de572 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -376,21 +376,25 @@ void SConfig::SaveSettingsToSysconf() { SysConf sysconf{Common::FromWhichRoot::FROM_CONFIGURED_ROOT}; - sysconf.SetData("IPL.SSV", m_wii_screensaver); - sysconf.SetData("IPL.LNG", m_wii_language); + sysconf.SetData("IPL.SSV", SysConf::Entry::Type::Byte, m_wii_screensaver); + sysconf.SetData("IPL.LNG", SysConf::Entry::Type::Byte, m_wii_language); - sysconf.SetData("IPL.AR", m_wii_aspect_ratio); - sysconf.SetData("BT.BAR", m_sensor_bar_position); - sysconf.SetData("BT.SENS", m_sensor_bar_sensitivity); - sysconf.SetData("BT.SPKV", m_speaker_volume); - sysconf.SetData("BT.MOT", m_wiimote_motor); - sysconf.SetData("IPL.PGS", bProgressive); - sysconf.SetData("IPL.E60", bPAL60); + sysconf.SetData("IPL.AR", SysConf::Entry::Type::Byte, m_wii_aspect_ratio); + sysconf.SetData("BT.BAR", SysConf::Entry::Type::Byte, m_sensor_bar_position); + sysconf.SetData("BT.SENS", SysConf::Entry::Type::Long, m_sensor_bar_sensitivity); + sysconf.SetData("BT.SPKV", SysConf::Entry::Type::Byte, m_speaker_volume); + sysconf.SetData("BT.MOT", SysConf::Entry::Type::Byte, m_wiimote_motor); + sysconf.SetData("IPL.PGS", SysConf::Entry::Type::Byte, bProgressive); + sysconf.SetData("IPL.E60", SysConf::Entry::Type::Byte, bPAL60); // Disable WiiConnect24's standby mode. If it is enabled, it prevents us from receiving // shutdown commands in the State Transition Manager (STM). // TODO: remove this if and once Dolphin supports WC24 standby mode. - sysconf.SetData("IPL.IDL", 0x00); + SysConf::Entry* idle_entry = sysconf.GetOrAddEntry("IPL.IDL", SysConf::Entry::Type::SmallArray); + if (idle_entry->bytes.empty()) + idle_entry->bytes = std::vector(2); + else + idle_entry->bytes[0] = 0; NOTICE_LOG(COMMON, "Disabling WC24 'standby' (shutdown to idle) to avoid hanging on shutdown"); IOS::HLE::RestoreBTInfoSection(&sysconf); @@ -706,15 +710,15 @@ void SConfig::LoadSettingsFromSysconf() { SysConf sysconf{Common::FromWhichRoot::FROM_CONFIGURED_ROOT}; - m_wii_screensaver = sysconf.GetData("IPL.SSV"); - m_wii_language = sysconf.GetData("IPL.LNG"); - m_wii_aspect_ratio = sysconf.GetData("IPL.AR"); - m_sensor_bar_position = sysconf.GetData("BT.BAR"); - m_sensor_bar_sensitivity = sysconf.GetData("BT.SENS"); - m_speaker_volume = sysconf.GetData("BT.SPKV"); - m_wiimote_motor = sysconf.GetData("BT.MOT") != 0; - bProgressive = sysconf.GetData("IPL.PGS") != 0; - bPAL60 = sysconf.GetData("IPL.E60") != 0; + m_wii_screensaver = sysconf.GetData("IPL.SSV", m_wii_screensaver); + m_wii_language = sysconf.GetData("IPL.LNG", m_wii_language); + m_wii_aspect_ratio = sysconf.GetData("IPL.AR", m_wii_aspect_ratio); + m_sensor_bar_position = sysconf.GetData("BT.BAR", m_sensor_bar_position); + m_sensor_bar_sensitivity = sysconf.GetData("BT.SENS", m_sensor_bar_sensitivity); + m_speaker_volume = sysconf.GetData("BT.SPKV", m_speaker_volume); + m_wiimote_motor = sysconf.GetData("BT.MOT", m_wiimote_motor) != 0; + bProgressive = sysconf.GetData("IPL.PGS", bProgressive) != 0; + bPAL60 = sysconf.GetData("IPL.E60", bPAL60) != 0; } void SConfig::ResetRunningGameMetadata() diff --git a/Source/Core/Core/IOS/USB/Bluetooth/BTBase.cpp b/Source/Core/Core/IOS/USB/Bluetooth/BTBase.cpp index 7622e967d4..c90dfa3e14 100644 --- a/Source/Core/Core/IOS/USB/Bluetooth/BTBase.cpp +++ b/Source/Core/Core/IOS/USB/Bluetooth/BTBase.cpp @@ -27,12 +27,12 @@ void BackUpBTInfoSection(const SysConf* sysconf) if (File::Exists(filename)) return; File::IOFile backup(filename, "wb"); - std::vector section(BT_INFO_SECTION_LENGTH); - if (!sysconf->GetArrayData("BT.DINF", section.data(), static_cast(section.size()))) - { - ERROR_LOG(IOS_WIIMOTE, "Failed to read source BT.DINF section"); + + const SysConf::Entry* btdinf = sysconf->GetEntry("BT.DINF"); + if (!btdinf) return; - } + + const std::vector& section = btdinf->bytes; if (!backup.WriteBytes(section.data(), section.size())) ERROR_LOG(IOS_WIIMOTE, "Failed to back up BT.DINF section"); } @@ -49,7 +49,8 @@ void RestoreBTInfoSection(SysConf* sysconf) ERROR_LOG(IOS_WIIMOTE, "Failed to read backed up BT.DINF section"); return; } - sysconf->SetArrayData("BT.DINF", section.data(), static_cast(section.size())); + + sysconf->GetOrAddEntry("BT.DINF", SysConf::Entry::Type::BigArray)->bytes = std::move(section); File::Delete(filename); } } // namespace HLE diff --git a/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp b/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp index baaee5440b..00e290541e 100644 --- a/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp +++ b/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp @@ -48,44 +48,41 @@ BluetoothEmu::BluetoothEmu(Kernel& ios, const std::string& device_name) BackUpBTInfoSection(&sysconf); _conf_pads BT_DINF; - if (!sysconf.GetArrayData("BT.DINF", (u8*)&BT_DINF, sizeof(_conf_pads))) + bdaddr_t tmpBD = BDADDR_ANY; + u8 i = 0; + while (i < MAX_BBMOTES) { - PanicAlertT("Trying to read from invalid SYSCONF\nWii Remote Bluetooth IDs are not available"); + // Previous records can be safely overwritten, since they are backed up + tmpBD.b[5] = BT_DINF.active[i].bdaddr[0] = BT_DINF.registered[i].bdaddr[0] = i; + tmpBD.b[4] = BT_DINF.active[i].bdaddr[1] = BT_DINF.registered[i].bdaddr[1] = 0; + tmpBD.b[3] = BT_DINF.active[i].bdaddr[2] = BT_DINF.registered[i].bdaddr[2] = 0x79; + tmpBD.b[2] = BT_DINF.active[i].bdaddr[3] = BT_DINF.registered[i].bdaddr[3] = 0x19; + tmpBD.b[1] = BT_DINF.active[i].bdaddr[4] = BT_DINF.registered[i].bdaddr[4] = 2; + tmpBD.b[0] = BT_DINF.active[i].bdaddr[5] = BT_DINF.registered[i].bdaddr[5] = 0x11; + + const char* wmName; + if (i == WIIMOTE_BALANCE_BOARD) + wmName = "Nintendo RVL-WBC-01"; + else + wmName = "Nintendo RVL-CNT-01"; + memcpy(BT_DINF.registered[i].name, wmName, 20); + memcpy(BT_DINF.active[i].name, wmName, 20); + + DEBUG_LOG(IOS_WIIMOTE, "Wii Remote %d BT ID %x,%x,%x,%x,%x,%x", i, tmpBD.b[0], tmpBD.b[1], + tmpBD.b[2], tmpBD.b[3], tmpBD.b[4], tmpBD.b[5]); + m_WiiMotes.emplace_back(this, i, tmpBD, g_wiimote_sources[i] != WIIMOTE_SRC_NONE); + i++; } - else - { - bdaddr_t tmpBD = BDADDR_ANY; - u8 i = 0; - while (i < MAX_BBMOTES) - { - // Previous records can be safely overwritten, since they are backed up - tmpBD.b[5] = BT_DINF.active[i].bdaddr[0] = BT_DINF.registered[i].bdaddr[0] = i; - tmpBD.b[4] = BT_DINF.active[i].bdaddr[1] = BT_DINF.registered[i].bdaddr[1] = 0; - tmpBD.b[3] = BT_DINF.active[i].bdaddr[2] = BT_DINF.registered[i].bdaddr[2] = 0x79; - tmpBD.b[2] = BT_DINF.active[i].bdaddr[3] = BT_DINF.registered[i].bdaddr[3] = 0x19; - tmpBD.b[1] = BT_DINF.active[i].bdaddr[4] = BT_DINF.registered[i].bdaddr[4] = 2; - tmpBD.b[0] = BT_DINF.active[i].bdaddr[5] = BT_DINF.registered[i].bdaddr[5] = 0x11; - const char* wmName; - if (i == WIIMOTE_BALANCE_BOARD) - wmName = "Nintendo RVL-WBC-01"; - else - wmName = "Nintendo RVL-CNT-01"; - memcpy(BT_DINF.registered[i].name, wmName, 20); - memcpy(BT_DINF.active[i].name, wmName, 20); + BT_DINF.num_registered = MAX_BBMOTES; - DEBUG_LOG(IOS_WIIMOTE, "Wii Remote %d BT ID %x,%x,%x,%x,%x,%x", i, tmpBD.b[0], tmpBD.b[1], - tmpBD.b[2], tmpBD.b[3], tmpBD.b[4], tmpBD.b[5]); - m_WiiMotes.emplace_back(this, i, tmpBD, g_wiimote_sources[i] != WIIMOTE_SRC_NONE); - i++; - } - - BT_DINF.num_registered = MAX_BBMOTES; - // save now so that when games load sysconf file it includes the new Wii Remotes - // and the correct order for connected Wii Remotes - if (!sysconf.SetArrayData("BT.DINF", (u8*)&BT_DINF, sizeof(_conf_pads)) || !sysconf.Save()) - PanicAlertT("Failed to write BT.DINF to SYSCONF"); - } + // save now so that when games load sysconf file it includes the new Wii Remotes + // and the correct order for connected Wii Remotes + std::vector data(sizeof(_conf_pads)); + std::memcpy(data.data(), &BT_DINF, data.size()); + sysconf.GetOrAddEntry("BT.DINF", SysConf::Entry::Type::BigArray)->bytes = std::move(data); + if (!sysconf.Save()) + PanicAlertT("Failed to write BT.DINF to SYSCONF"); // The BCM2045's btaddr: m_ControllerBD.b[0] = 0x11;