Fix Windows config writing of custom key overloads

alut-include-path
Sven Eberhardt 2017-03-26 20:55:27 -04:00
parent 83af5ad794
commit 66117de82f
4 changed files with 135 additions and 62 deletions

View File

@ -55,6 +55,19 @@ char StdCompiler::SeparatorToChar(Sep eSep)
return ' ';
}
bool StdCompiler::IsStringEnd(char c, RawCompileType eType)
{
switch (eType)
{
case RCT_Escaped: return c == '"' || !c || c == '\n' || c == '\r';
case RCT_All: return !c || c == '\n' || c == '\r';
// '-' is needed for Layers in Scenario.txt (C4NameList) and other Material-Texture combinations
case RCT_Idtf: case RCT_IdtfAllowEmpty: case RCT_ID: return !isalnum((unsigned char)c) && c != '_' && c != '-';
}
// unreachable
return true;
}
// *** StdCompilerBinWrite
void StdCompilerBinWrite::DWord(int32_t &rInt) { WriteValue(rInt); }
@ -960,19 +973,6 @@ StdBuf StdCompilerINIRead::ReadString(size_t iLength, RawCompileType eRawType, b
return OutBuf;
}
bool StdCompilerINIRead::TestStringEnd(RawCompileType eType)
{
switch (eType)
{
case RCT_Escaped: return *pPos == '"' || !*pPos || *pPos == '\n' || *pPos == '\r';
case RCT_All: return !*pPos || *pPos == '\n' || *pPos == '\r';
// '-' is needed for Layers in Scenario.txt (C4NameList) and other Material-Texture combinations
case RCT_Idtf: case RCT_IdtfAllowEmpty: case RCT_ID: return !isalnum((unsigned char)*pPos) && *pPos != '_' && *pPos != '-';
}
// unreachable
return true;
}
char StdCompilerINIRead::ReadEscapedChar()
{
// Catch some no-noes like \0, \n etc.

View File

@ -302,7 +302,8 @@ protected:
// Standard separator character
static char SeparatorToChar(Sep eSep);
// String end test depending on encoding type
static bool IsStringEnd(char c, RawCompileType eType);
};
// Standard compile funcs
@ -730,7 +731,7 @@ protected:
long ReadNum();
size_t GetStringLength(RawCompileType eTyped);
StdBuf ReadString(size_t iLength, RawCompileType eTyped, bool fAppendNull = true);
bool TestStringEnd(RawCompileType eType);
bool TestStringEnd(RawCompileType eType) { return IsStringEnd(*pPos, eType); }
char ReadEscapedChar();
unsigned long ReadUNum();

View File

@ -283,6 +283,7 @@ bool StdCompilerConfigWrite::Name(const char *szName)
pnKey->Parent = pKey;
pKey = pnKey;
iDepth++;
last_written_string.clear();
return true;
}
@ -297,6 +298,7 @@ void StdCompilerConfigWrite::NameEnd(bool fBreak)
pKey = poKey->Parent;
delete poKey;
iDepth--;
last_written_string.clear();
}
bool StdCompilerConfigWrite::FollowName(const char *szName)
@ -317,8 +319,10 @@ bool StdCompilerConfigWrite::Default(const char *szName)
bool StdCompilerConfigWrite::Separator(Sep eSep)
{
assert(!"StdCompilerConfigWrite::Separator: not supported");
return false;
// Just append separator and re-write last string
const char s[2] = { SeparatorToChar(eSep) , '\0' };
WriteString(s);
return true;
}
void StdCompilerConfigWrite::DWord(int32_t &rInt)
@ -356,19 +360,16 @@ void StdCompilerConfigWrite::Character(char &rChar)
void StdCompilerConfigWrite::String(char *szString, size_t iMaxLength, RawCompileType eType)
{
assert(eType != RCT_Idtf && eType != RCT_IdtfAllowEmpty);
WriteString(szString);
}
void StdCompilerConfigWrite::String(char **pszString, RawCompileType eType)
{
assert(eType != RCT_Idtf && eType != RCT_IdtfAllowEmpty);
WriteString(pszString ? *pszString : "");
}
void StdCompilerConfigWrite::String(std::string &str, RawCompileType eType)
{
assert(eType != RCT_Idtf && eType != RCT_IdtfAllowEmpty);
WriteString(str.c_str());
}
@ -412,7 +413,10 @@ void StdCompilerConfigWrite::WriteDWord(uint32_t iVal)
void StdCompilerConfigWrite::WriteString(const char *szString)
{
StdBuf v = GetWideCharBuf(szString);
// Append to write-string and just re-write
// This is probably pretty inefficient, but config saving only uses it for a few key overloads
last_written_string += szString;
StdBuf v = GetWideCharBuf(last_written_string.c_str());
if (RegSetValueExW(pKey->Parent->Handle, pKey->Name.GetWideChar(),
0, REG_SZ, getBufPtr<BYTE>(v), v.getSize()) != ERROR_SUCCESS)
excCorrupt("Could not write key %s!", pKey->Name.getData());
@ -474,6 +478,7 @@ bool StdCompilerConfigRead::Name(const char *szName)
pnKey->Type = dwType;
pKey = pnKey;
iDepth++;
ResetLastString();
return fFound;
}
@ -488,6 +493,14 @@ void StdCompilerConfigRead::NameEnd(bool fBreak)
pKey = poKey->Parent;
delete poKey;
iDepth--;
ResetLastString();
}
void StdCompilerConfigRead::ResetLastString()
{
has_read_string = false;
has_separator_mismatch = false;
last_read_string.clear();
}
bool StdCompilerConfigRead::FollowName(const char *szName)
@ -497,8 +510,21 @@ bool StdCompilerConfigRead::FollowName(const char *szName)
bool StdCompilerConfigRead::Separator(Sep eSep)
{
assert(!"StdCompilerConfigRead::Separator: not supported");
return false;
// Make sure there's a string to work on
ReadString();
// Match?
if (last_read_string.size() && (last_read_string.front() == SeparatorToChar(eSep)))
{
// Match found. Just advance.
last_read_string = last_read_string.substr(1);
return true;
}
else
{
// Separator mismatch? Let all read attempts fail until the correct separator is found or the naming ends.
has_separator_mismatch = true;
return false;
}
}
void StdCompilerConfigRead::DWord(int32_t &rInt)
@ -529,8 +555,8 @@ void StdCompilerConfigRead::Boolean(bool &rBool)
{
try
{
StdStrBuf szVal = ReadString();
rBool = (szVal == "true");
ReadString();
rBool = (!has_separator_mismatch && (last_read_string == "true"));
}
catch (NotFoundException *pExc)
{
@ -543,8 +569,8 @@ void StdCompilerConfigRead::Character(char &rChar)
{
try
{
StdStrBuf szVal = ReadString();
rChar = *szVal.getData();
ReadString();
rChar = (last_read_string.length() && !has_separator_mismatch) ? last_read_string.front() : '\0';
}
catch (NotFoundException *pExc)
{
@ -556,22 +582,39 @@ void StdCompilerConfigRead::Character(char &rChar)
void StdCompilerConfigRead::String(char *szString, size_t iMaxLength, RawCompileType eType)
{
assert(eType != RCT_Idtf && eType != RCT_IdtfAllowEmpty);
StdStrBuf str = ReadString();
if (!str.getLength()) { *szString='\0'; return; }
SCopy(str.getData(), szString, iMaxLength);
std::string s;
String(s, eType);
SCopy(s.c_str(), szString, iMaxLength);
}
void StdCompilerConfigRead::String(char **pszString, RawCompileType eType)
{
assert(eType != RCT_Idtf && eType != RCT_IdtfAllowEmpty);
*pszString = ReadString().GrabPointer();
// Read string, copy into buffer and release buffer (to use buffer allocation method)
std::string s;
String(s, eType);
StdStrBuf sbuf(s.c_str(), true);
*pszString = sbuf.GrabPointer();
}
void StdCompilerConfigRead::String(std::string &str, RawCompileType type)
{
assert(type != RCT_Idtf && type != RCT_IdtfAllowEmpty);
str = ReadString().getData();
// Read from string until end marker is found
ReadString();
if (has_separator_mismatch || !last_read_string.length()) { str = "\0"; return; }
size_t string_end_pos = 0;
const char *s = last_read_string.c_str();
size_t spos = 0;
while (!IsStringEnd(s[spos], type)) ++spos;
if (spos < last_read_string.length())
{
str = last_read_string.substr(0, spos);
last_read_string = last_read_string.substr(spos);
}
else
{
str = last_read_string;
last_read_string.clear();
}
}
void StdCompilerConfigRead::Raw(void *pData, size_t iSize, RawCompileType eType)
@ -597,6 +640,8 @@ uint32_t StdCompilerConfigRead::ReadDWord()
// Wrong type?
if (pKey->Type != REG_DWORD && pKey->Type != REG_DWORD_LITTLE_ENDIAN)
{ excNotFound("Wrong value type!"); return 0; }
// Clear previous string
ResetLastString();
// Read
uint32_t iVal; DWORD iSize = sizeof(iVal);
if (RegQueryValueExW(pKey->Parent->Handle, pKey->Name.GetWideChar(),
@ -611,33 +656,51 @@ uint32_t StdCompilerConfigRead::ReadDWord()
return iVal;
}
StdStrBuf StdCompilerConfigRead::ReadString()
void StdCompilerConfigRead::ReadString()
{
// Virtual key?
if (pKey->Virtual)
{ excNotFound("Could not read value %s! Parent key doesn't exist!", pKey->Name.getData()); return StdStrBuf(); }
// Wrong type?
if (pKey->Type != REG_SZ)
{ excNotFound("Wrong value type!"); return StdStrBuf(); }
// Get size of string
DWORD iSize;
if (RegQueryValueExW(pKey->Parent->Handle, pKey->Name.GetWideChar(),
0, nullptr,
nullptr,
&iSize) != ERROR_SUCCESS)
{ excNotFound("Could not read value %s!", pKey->Name.getData()); return StdStrBuf(); }
// Allocate string
StdBuf Result; Result.SetSize(iSize);
// Read
if (RegQueryValueExW(pKey->Parent->Handle, pKey->Name.GetWideChar(),
0, nullptr,
reinterpret_cast<BYTE *>(Result.getMData()),
&iSize) != ERROR_SUCCESS)
{ excNotFound("Could not read value %s!", pKey->Name.getData()); return StdStrBuf(); }
// Check size
if (wcslen(getBufPtr<wchar_t>(Result)) + 1 != iSize / sizeof(wchar_t))
{ excCorrupt("Wrong size of a string!"); return StdStrBuf(); }
return StdStrBuf(getBufPtr<wchar_t>(Result));
// Already read?
if (!has_read_string)
{
ResetLastString();
// Virtual key?
if (pKey->Virtual)
{
excNotFound("Could not read value %s! Parent key doesn't exist!", pKey->Name.getData()); return;
}
// Wrong type?
if (pKey->Type != REG_SZ)
{
excNotFound("Wrong value type!"); return;
}
// Get size of string
DWORD iSize;
if (RegQueryValueExW(pKey->Parent->Handle, pKey->Name.GetWideChar(),
0, nullptr,
nullptr,
&iSize) != ERROR_SUCCESS)
{
excNotFound("Could not read value %s!", pKey->Name.getData()); return;
}
// Allocate string
StdBuf Result; Result.SetSize(iSize);
// Read
if (RegQueryValueExW(pKey->Parent->Handle, pKey->Name.GetWideChar(),
0, nullptr,
reinterpret_cast<BYTE *>(Result.getMData()),
&iSize) != ERROR_SUCCESS)
{
excNotFound("Could not read value %s!", pKey->Name.getData()); return;
}
// Check size
if (wcslen(getBufPtr<wchar_t>(Result)) + 1 != iSize / sizeof(wchar_t))
{
excCorrupt("Wrong size of a string!"); return;
}
// Remember string
StdStrBuf str_result(getBufPtr<wchar_t>(Result));
last_read_string = str_result.getData();
has_read_string = true;
}
}
#endif // _WIN32

View File

@ -99,6 +99,9 @@ private:
Key *Parent;
} *pKey;
// Current string for writing with separators
std::string last_written_string;
// Writing
void CreateKey(HKEY hParent = 0);
void WriteDWord(uint32_t iVal);
@ -161,9 +164,15 @@ private:
DWORD Type; // for values only
} *pKey;
// Current string for reading with separators
std::string last_read_string;
bool has_read_string = false;
bool has_separator_mismatch = false;
// Reading
uint32_t ReadDWord();
StdStrBuf ReadString();
void ReadString();
void ResetLastString();
};