mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-24 04:51:19 +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 "doomtype.h"
|
||||||
#include "configfile.h"
|
#include "configfile.h"
|
||||||
|
#include "m_random.h"
|
||||||
|
|
||||||
#define READBUFFERSIZE 256
|
#define READBUFFERSIZE 256
|
||||||
|
|
||||||
|
static FRandom pr_endtag;
|
||||||
|
|
||||||
//====================================================================
|
//====================================================================
|
||||||
//
|
//
|
||||||
// FConfigFile Constructor
|
// FConfigFile Constructor
|
||||||
|
@ -679,13 +682,68 @@ bool FConfigFile::ReadConfig (void *file)
|
||||||
whiteprobe++;
|
whiteprobe++;
|
||||||
}
|
}
|
||||||
*(whiteprobe - 1) = 0;
|
*(whiteprobe - 1) = 0;
|
||||||
NewConfigEntry (section, start, whiteprobe);
|
// 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;
|
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
|
// FConfigFile :: ReadLine
|
||||||
|
@ -732,7 +790,16 @@ bool FConfigFile::WriteConfigFile () const
|
||||||
fprintf (file, "[%s]\n", section->Name);
|
fprintf (file, "[%s]\n", section->Name);
|
||||||
while (entry != NULL)
|
while (entry != NULL)
|
||||||
{
|
{
|
||||||
fprintf (file, "%s=%s\n", entry->Key, entry->Value);
|
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;
|
entry = entry->Next;
|
||||||
}
|
}
|
||||||
section = section->Next;
|
section = section->Next;
|
||||||
|
@ -742,6 +809,44 @@ bool FConfigFile::WriteConfigFile () const
|
||||||
return true;
|
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
|
// FConfigFile :: WriteCommentHeader
|
||||||
|
|
|
@ -78,6 +78,7 @@ protected:
|
||||||
|
|
||||||
virtual char *ReadLine (char *string, int n, void *file) const;
|
virtual char *ReadLine (char *string, int n, void *file) const;
|
||||||
bool ReadConfig (void *file);
|
bool ReadConfig (void *file);
|
||||||
|
static const char *GenerateEndTag(const char *value);
|
||||||
|
|
||||||
bool OkayToWrite;
|
bool OkayToWrite;
|
||||||
bool FileExisted;
|
bool FileExisted;
|
||||||
|
@ -110,6 +111,7 @@ private:
|
||||||
FConfigEntry *FindEntry (FConfigSection *section, const char *key) const;
|
FConfigEntry *FindEntry (FConfigSection *section, const char *key) const;
|
||||||
FConfigSection *NewConfigSection (const char *name);
|
FConfigSection *NewConfigSection (const char *name);
|
||||||
FConfigEntry *NewConfigEntry (FConfigSection *section, const char *key, const char *value);
|
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);
|
void SetSectionNote (FConfigSection *section, const char *note);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
Loading…
Reference in a new issue