SettingsHandler: Don't output null bytes

https://bugs.dolphin-emu.org/issues/12019, take two.
This commit is contained in:
JosJuice 2020-03-24 16:58:54 +01:00
parent 5b10f4b71e
commit 5d6f23e424
2 changed files with 29 additions and 18 deletions

View File

@ -6,6 +6,7 @@
#include "Common/SettingsHandler.h" #include "Common/SettingsHandler.h"
#include <algorithm>
#include <cstddef> #include <cstddef>
#include <ctime> #include <ctime>
#include <iomanip> #include <iomanip>
@ -79,12 +80,10 @@ void SettingsHandler::Decrypt()
m_key = (m_key >> 31) | (m_key << 1); m_key = (m_key >> 31) | (m_key << 1);
} }
// Decryption done. Now get rid of all CR in the output. // The decoded data normally uses CRLF line endings, but occasionally
// The decoded file is supposed to contain Windows line endings // (see the comment in WriteLine), lines can be separated by CRLFLF.
// (CR-LF), but sometimes also contains CR-LF-LF endings which // To handle this, we remove every CR and treat LF as the line ending.
// confuse the parsing code, so let's just get rid of all CR // (We ignore empty lines.)
// line endings.
decoded.erase(std::remove(decoded.begin(), decoded.end(), '\x0d'), decoded.end()); decoded.erase(std::remove(decoded.begin(), decoded.end(), '\x0d'), decoded.end());
} }
@ -96,22 +95,33 @@ void SettingsHandler::Reset()
m_buffer = {}; m_buffer = {};
} }
void SettingsHandler::AddSetting(std::string_view key, std::string_view value) void SettingsHandler::AddSetting(const std::string& key, const std::string& value)
{ {
for (const char& c : key) WriteLine(key + '=' + value + "\r\n");
{
WriteByte(c);
} }
WriteByte('='); void SettingsHandler::WriteLine(const std::string& str)
for (const char& c : value)
{ {
WriteByte(c); const u32 old_position = m_position;
} const u32 old_key = m_key;
WriteByte(13); // Encode and write the line
WriteByte(10); for (char c : str)
WriteByte(c);
// If the encoded data contains a null byte, Nintendo's decoder will stop at that null byte
// instead of decoding all the data. To avoid this: If the data we just wrote contains
// a null byte, add an LF right before the line to prod the values into being different,
// just like Nintendo does. Due to the chosen key, LF itself never encodes into a null byte.
const auto begin = m_buffer.cbegin() + old_position;
const auto end = m_buffer.cbegin() + m_position;
if (std::find(begin, end, 0) != end)
{
m_key = old_key;
m_position = old_position;
WriteByte('\n');
WriteLine(str);
}
} }
void SettingsHandler::WriteByte(u8 b) void SettingsHandler::WriteByte(u8 b)

View File

@ -28,7 +28,7 @@ public:
SettingsHandler(); SettingsHandler();
explicit SettingsHandler(Buffer&& buffer); explicit SettingsHandler(Buffer&& buffer);
void AddSetting(std::string_view key, std::string_view value); void AddSetting(const std::string& key, const std::string& value);
const Buffer& GetBytes() const; const Buffer& GetBytes() const;
void SetBytes(Buffer&& buffer); void SetBytes(Buffer&& buffer);
@ -39,6 +39,7 @@ public:
static std::string GenerateSerialNumber(); static std::string GenerateSerialNumber();
private: private:
void WriteLine(const std::string& str);
void WriteByte(u8 b); void WriteByte(u8 b);
std::array<u8, SETTINGS_SIZE> m_buffer; std::array<u8, SETTINGS_SIZE> m_buffer;