- Added "\c" support to ParseCommandLine() when it parses quoted strings.

- Fixed: When changing your name from the menu, you got an extra " appended
  to your name if it ended with a backslash.
- Added escape sequences for user info strings, so now they can contain
  embedded backslashes.
- Fixed an array-out-of-bounds access when drawing the player setup menu with
  an invalid team number.


SVN r598 (trunk)
This commit is contained in:
Randy Heit 2007-12-15 03:27:40 +00:00
parent 089c2dab48
commit 8d5402cec2
5 changed files with 123 additions and 37 deletions

View file

@ -1,3 +1,12 @@
December 14, 2007
- Added "\c" support to ParseCommandLine() when it parses quoted strings.
- Fixed: When changing your name from the menu, you got an extra " appended
to your name if it ended with a backslash.
- Added escape sequences for user info strings, so now they can contain
embedded backslashes.
- Fixed an array-out-of-bounds access when drawing the player setup menu with
an invalid team number.
December 10, 2007
- Fixed: The MAPINFO flags that control jumping, crouching, and freelook,
rather than overriding the dmflags values, actually overwrote the dmflags

View file

@ -718,8 +718,11 @@ void AddCommandString (char *cmd, int keynum)
// to point to a buffer large enough to hold all the arguments. The
// return value is the necessary size of this buffer.
//
// Special processing: Inside quoted strings, \" becomes just "
// $<cvar> is replaced by the contents of <cvar>
// Special processing:
// Inside quoted strings, \" becomes just "
// \\ becomes just \
// \c becomes just TEXTCOLOR_ESCAPE
// $<cvar> is replaced by the contents of <cvar>
static long ParseCommandLine (const char *args, int *argc, char **argv)
{
@ -759,6 +762,14 @@ static long ParseCommandLine (const char *args, int *argc, char **argv)
{
stuff = '\"', args++;
}
else if (stuff == '\\' && *args == '\\')
{
args++;
}
else if (stuff == '\\' && *args == 'c')
{
stuff = TEXTCOLOR_ESCAPE, args++;
}
else if (stuff == '\"')
{
stuff = 0;

View file

@ -110,6 +110,55 @@ static const char *UserInfoStrings[] =
NULL
};
// Replace \ with %/ and % with %%
FString D_EscapeUserInfo (const char *str)
{
FString ret;
for (; *str != '\0'; ++str)
{
if (*str == '\\')
{
ret << '%' << '/';
}
else if (*str == '%')
{
ret << '%' << '%';
}
else
{
ret << *str;
}
}
return ret;
}
// Replace %/ with \ and %% with %
FString D_UnescapeUserInfo (const char *str, size_t len)
{
const char *end = str + len;
FString ret;
while (*str != '\0' && str < end)
{
if (*str == '%')
{
if (*(str + 1) == '/')
{
ret << '\\';
str += 2;
continue;
}
else if (*(str + 1) == '%')
{
str++;
}
}
ret << *str++;
}
return ret;
}
int D_GenderToInt (const char *gender)
{
if (!stricmp (gender, "female"))
@ -339,6 +388,7 @@ void D_SetupUserInfo ()
void D_UserInfoChanged (FBaseCVar *cvar)
{
UCVarValue val;
FString escaped_val;
char foo[256];
if (cvar == &autoaim)
@ -356,10 +406,11 @@ void D_UserInfoChanged (FBaseCVar *cvar)
}
val = cvar->GetGenericRep (CVAR_String);
if (4 + strlen (cvar->GetName ()) + strlen (val.String) > 256)
escaped_val = D_EscapeUserInfo(val.String);
if (4 + strlen(cvar->GetName()) + escaped_val.Len() > 256)
I_Error ("User info descriptor too big");
sprintf (foo, "\\%s\\%s", cvar->GetName (), val.String);
sprintf (foo, "\\%s\\%s", cvar->GetName(), escaped_val.GetChars());
Net_WriteByte (DEM_UINFCHANGED);
Net_WriteString (foo);
@ -518,17 +569,18 @@ void D_WriteUserInfoStrings (int i, BYTE **stream, bool compact)
"\\stillbob\\%g"
"\\playerclass\\%s"
,
info->netname,
D_EscapeUserInfo(info->netname).GetChars(),
(double)info->aimdist / (float)ANGLE_1,
RPART(info->color), GPART(info->color), BPART(info->color),
skins[info->skin].name, info->team,
D_EscapeUserInfo(skins[info->skin].name).GetChars(),
info->team,
info->gender == GENDER_FEMALE ? "female" :
info->gender == GENDER_NEUTER ? "other" : "male",
info->neverswitch,
(float)(info->MoveBob) / 65536.f,
(float)(info->StillBob) / 65536.f,
info->PlayerClass == -1 ? "Random" :
type->Meta.GetMetaString (APMETA_DisplayName)
D_EscapeUserInfo(type->Meta.GetMetaString (APMETA_DisplayName)).GetChars()
);
}
else
@ -546,10 +598,10 @@ void D_WriteUserInfoStrings (int i, BYTE **stream, bool compact)
"\\%g" // stillbob
"\\%s" // playerclass
,
info->netname,
D_EscapeUserInfo(info->netname).GetChars(),
(double)info->aimdist / (float)ANGLE_1,
RPART(info->color), GPART(info->color), BPART(info->color),
skins[info->skin].name,
D_EscapeUserInfo(skins[info->skin].name).GetChars(),
info->team,
info->gender == GENDER_FEMALE ? "female" :
info->gender == GENDER_NEUTER ? "other" : "male",
@ -557,7 +609,7 @@ void D_WriteUserInfoStrings (int i, BYTE **stream, bool compact)
(float)(info->MoveBob) / 65536.f,
(float)(info->StillBob) / 65536.f,
info->PlayerClass == -1 ? "Random" :
type->Meta.GetMetaString (APMETA_DisplayName)
D_EscapeUserInfo(type->Meta.GetMetaString (APMETA_DisplayName)).GetChars()
);
}
}
@ -568,9 +620,9 @@ void D_WriteUserInfoStrings (int i, BYTE **stream, bool compact)
void D_ReadUserInfoStrings (int i, BYTE **stream, bool update)
{
userinfo_t *info = &players[i].userinfo;
char *ptr = *((char **)stream);
char *breakpt;
char *value;
const char *ptr = *((const char **)stream);
const char *breakpt;
FString value;
bool compact;
int infotype = -1;
@ -583,25 +635,37 @@ void D_ReadUserInfoStrings (int i, BYTE **stream, bool update)
{
for (;;)
{
breakpt = strchr (ptr, '\\');
int j;
if (breakpt != NULL)
*breakpt = 0;
breakpt = strchr (ptr, '\\');
if (compact)
{
value = ptr;
value = D_UnescapeUserInfo(ptr, breakpt - ptr);
infotype++;
}
else if (breakpt != NULL)
else
{
value = breakpt + 1;
if ( (breakpt = strchr (value, '\\')) )
*breakpt = 0;
assert(breakpt != NULL);
// A malicious remote machine could invalidate the above assert.
if (breakpt == NULL)
{
break;
}
const char *valstart = breakpt + 1;
if ( (breakpt = strchr (valstart, '\\')) != NULL )
{
value = D_UnescapeUserInfo(valstart, breakpt - valstart);
}
else
{
value = D_UnescapeUserInfo(valstart, strlen(valstart));
}
int j = 0;
while (UserInfoStrings[j] && stricmp (UserInfoStrings[j], ptr) != 0)
j++;
for (j = 0;
UserInfoStrings[j] && strnicmp (UserInfoStrings[j], ptr, valstart - ptr - 1) != 0;
++j)
{ }
if (UserInfoStrings[j] == NULL)
{
infotype = -1;
@ -611,10 +675,6 @@ void D_ReadUserInfoStrings (int i, BYTE **stream, bool update)
infotype = j;
}
}
else
{ // Shush, GCC.
value = NULL;
}
switch (infotype)
{
@ -718,13 +778,8 @@ void D_ReadUserInfoStrings (int i, BYTE **stream, bool update)
break;
}
if (!compact)
{
*(value - 1) = '\\';
}
if (breakpt)
{
*breakpt = '\\';
ptr = breakpt + 1;
}
else

View file

@ -2078,7 +2078,7 @@ static void M_PlayerSetupDrawer ()
screen->DrawText (label, PSetupDef.x, PSetupDef.y + LINEHEIGHT+yo, "Team",
DTA_Clean, true, TAG_DONE);
screen->DrawText (value, x, PSetupDef.y + LINEHEIGHT+yo,
players[consoleplayer].userinfo.team == TEAM_None ? "None" :
(unsigned)players[consoleplayer].userinfo.team >= NUM_TEAMS ? "None" :
TeamNames[players[consoleplayer].userinfo.team],
DTA_Clean, true, TAG_DONE);
@ -2279,6 +2279,7 @@ static BYTE smoke[1024] =
7, 7, 0, 5, 1, 6, 7, 9,12, 9,12,21,22,25,24,22,23,25,24,18,24,22,17,13,10, 9,10, 9, 6,11, 6, 5,
};
// This is one plasma and two rotozoomers. I think it turned out quite awesome.
static void M_RenderPlayerBackdrop ()
{
BYTE *from;
@ -2521,9 +2522,19 @@ static void M_PlayerNameNotChanged ()
static void M_PlayerNameChanged (FSaveGameNode *dummy)
{
char command[SAVESTRINGSIZE+8];
const char *p;
FString command("name \"");
sprintf (command, "name \"%s\"", savegamestring);
// Escape any backslashes or quotation marks before sending the name to the console.
for (p = savegamestring; *p != '\0'; ++p)
{
if (*p == '"' || *p == '\\')
{
command << '\\';
}
command << *p;
}
command << '"';
C_DoCommand (command);
}

View file

@ -4478,7 +4478,7 @@ newline:
normal_token:
ScriptPtr = (YYCURSOR >= YYLIMIT) ? ScriptEndPtr : cursor;
sc_StringLen = MIN (ScriptPtr - tok, MAX_STRING_SIZE-1);
sc_StringLen = (unsigned int)MIN<size_t> (ScriptPtr - tok, MAX_STRING_SIZE-1);
if (tokens && (sc_TokenType == TK_StringConst || sc_TokenType == TK_NameConst))
{
sc_StringLen -= 2;