mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2024-11-15 16:51:31 +00:00
- Addded support for multi-line values in INI files, so you can't maliciously inject stray
newline characters into the config file using ACS's SetCVarString. SVN r4326 (trunk)
This commit is contained in:
parent
c4b7335312
commit
5e7ee8f33e
2 changed files with 109 additions and 2 deletions
|
@ -38,9 +38,12 @@
|
|||
|
||||
#include "doomtype.h"
|
||||
#include "configfile.h"
|
||||
#include "m_random.h"
|
||||
|
||||
#define READBUFFERSIZE 256
|
||||
|
||||
static FRandom pr_endtag;
|
||||
|
||||
//====================================================================
|
||||
//
|
||||
// FConfigFile Constructor
|
||||
|
@ -679,13 +682,68 @@ bool FConfigFile::ReadConfig (void *file)
|
|||
whiteprobe++;
|
||||
}
|
||||
*(whiteprobe - 1) = 0;
|
||||
// Check for multi-line value
|
||||
if (whiteprobe[0] == '<' && whiteprobe[1] == '<' && whiteprobe[2] == '<' && whiteprobe[3] != '\0')
|
||||
{
|
||||
ReadMultiLineValue (file, section, start, whiteprobe + 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
NewConfigEntry (section, start, whiteprobe);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
//
|
||||
// FConfigFile :: ReadMultiLineValue
|
||||
//
|
||||
// Reads a multi-line value, with format as follows:
|
||||
//
|
||||
// key=<<<ENDTAG
|
||||
// ... blah blah blah ...
|
||||
// >>>ENDTAG
|
||||
//
|
||||
// The final ENDTAG must be on a line all by itself.
|
||||
//
|
||||
//====================================================================
|
||||
|
||||
FConfigFile::FConfigEntry *FConfigFile::ReadMultiLineValue(void *file, FConfigSection *section, const char *key, const char *endtag)
|
||||
{
|
||||
char readbuf[READBUFFERSIZE];
|
||||
FString value;
|
||||
size_t endlen = strlen(endtag);
|
||||
|
||||
// Keep on reading lines until we reach a line that matches >>>endtag
|
||||
while (ReadLine(readbuf, READBUFFERSIZE, file) != NULL)
|
||||
{
|
||||
// Does the start of this line match the endtag?
|
||||
if (readbuf[0] == '>' && readbuf[1] == '>' && readbuf[2] == '>' &&
|
||||
strncmp(readbuf + 3, endtag, endlen) == 0)
|
||||
{ // Is there nothing but line break characters after the match?
|
||||
size_t i;
|
||||
for (i = endlen + 3; readbuf[i] != '\0'; ++i)
|
||||
{
|
||||
if (readbuf[i] != '\n' && readbuf[i] != '\r')
|
||||
{ // Not a line break character
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (readbuf[i] == '\0')
|
||||
{ // We're done; strip the previous line's line breaks, since it's not part of the value.
|
||||
value.StripRight("\n\r");
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Append this line to the value.
|
||||
value << readbuf;
|
||||
}
|
||||
return NewConfigEntry(section, key, value);
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
//
|
||||
// FConfigFile :: ReadLine
|
||||
|
@ -732,7 +790,16 @@ bool FConfigFile::WriteConfigFile () const
|
|||
fprintf (file, "[%s]\n", section->Name);
|
||||
while (entry != NULL)
|
||||
{
|
||||
if (strpbrk(entry->Value, "\r\n") == NULL)
|
||||
{ // Single-line value
|
||||
fprintf (file, "%s=%s\n", entry->Key, entry->Value);
|
||||
}
|
||||
else
|
||||
{ // Multi-line value
|
||||
const char *endtag = GenerateEndTag(entry->Value);
|
||||
fprintf (file, "%s=<<<%s\n%s\n>>>%s\n", entry->Key,
|
||||
endtag, entry->Value, endtag);
|
||||
}
|
||||
entry = entry->Next;
|
||||
}
|
||||
section = section->Next;
|
||||
|
@ -742,6 +809,44 @@ bool FConfigFile::WriteConfigFile () const
|
|||
return true;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
//
|
||||
// FConfigFile :: GenerateEndTag
|
||||
//
|
||||
// Generates a terminator sequence for multi-line values that does
|
||||
// not appear anywhere in the value.
|
||||
//
|
||||
//====================================================================
|
||||
|
||||
const char *FConfigFile::GenerateEndTag(const char *value)
|
||||
{
|
||||
static const char Base64Table[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._";
|
||||
static char EndTag[25] = "EOV-";
|
||||
|
||||
// Try different 20-character sequences until we find one that
|
||||
// isn't in the value. We create the sequences by generating two
|
||||
// 64-bit random numbers and Base64 encoding the first 15 bytes
|
||||
// from them.
|
||||
union { QWORD rand_num[2]; BYTE rand_bytes[16]; };
|
||||
do
|
||||
{
|
||||
rand_num[0] = pr_endtag.GenRand64();
|
||||
rand_num[1] = pr_endtag.GenRand64();
|
||||
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
DWORD three_bytes = (rand_bytes[i*3] << 16) | (rand_bytes[i*3+1] << 8) | (rand_bytes[i*3+2]);
|
||||
EndTag[4+i*4 ] = Base64Table[rand_bytes[i*3] >> 2];
|
||||
EndTag[4+i*4+1] = Base64Table[((rand_bytes[i*3] & 3) << 4) | (rand_bytes[i*3+1] >> 4)];
|
||||
EndTag[4+i*4+2] = Base64Table[((rand_bytes[i*3+1] & 15) << 2) | (rand_bytes[i*3+2] >> 6)];
|
||||
EndTag[4+i*4+3] = Base64Table[rand_bytes[i*3+2] & 63];
|
||||
}
|
||||
}
|
||||
while (strstr(value, EndTag) != NULL);
|
||||
return EndTag;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
//
|
||||
// FConfigFile :: WriteCommentHeader
|
||||
|
|
|
@ -78,6 +78,7 @@ protected:
|
|||
|
||||
virtual char *ReadLine (char *string, int n, void *file) const;
|
||||
bool ReadConfig (void *file);
|
||||
static const char *GenerateEndTag(const char *value);
|
||||
|
||||
bool OkayToWrite;
|
||||
bool FileExisted;
|
||||
|
@ -110,6 +111,7 @@ private:
|
|||
FConfigEntry *FindEntry (FConfigSection *section, const char *key) const;
|
||||
FConfigSection *NewConfigSection (const char *name);
|
||||
FConfigEntry *NewConfigEntry (FConfigSection *section, const char *key, const char *value);
|
||||
FConfigEntry *ReadMultiLineValue (void *file, FConfigSection *section, const char *key, const char *terminator);
|
||||
void SetSectionNote (FConfigSection *section, const char *note);
|
||||
|
||||
public:
|
||||
|
|
Loading…
Reference in a new issue