From: fgsfds Date: Tue, 24 Dec 2019 14:28:52 +0000 (+0300) Subject: escape strings in stat files X-Git-Url: http://deadsoftware.ru/gitweb?p=d2df-sdl.git;a=commitdiff_plain;h=1b867d9fa61767acfef258fe29b900d3fd1af104 escape strings in stat files --- diff --git a/src/game/g_game.pas b/src/game/g_game.pas index b34e2ef..ef256d1 100644 --- a/src/game/g_game.pas +++ b/src/game/g_game.pas @@ -660,30 +660,43 @@ begin AssignFile(s, fname); try Rewrite(s); - // line 1: stats version, datetime, server name, map name, game mode, time limit, score limit, dmflags, game time, number of players + // line 1: stats ver, datetime, server name, map name, game mode, time limit, score limit, dmflags, game time, num players if g_Game_IsNet then fname := NetServerName else fname := ''; map := g_ExtractWadNameNoPath(gMapInfo.Map) + ':/' + g_ExtractFileName(gMapInfo.Map); mode := g_Game_ModeToText(Stat.GameMode); - etime := Format('%d:%.2d:%.2d', [Stat.GameTime div 1000 div 3600, - (Stat.GameTime div 1000 div 60) mod 60, - Stat.GameTime div 1000 mod 60]); + etime := Format('%d:%.2d:%.2d', [ + Stat.GameTime div 1000 div 3600, + (Stat.GameTime div 1000 div 60) mod 60, + Stat.GameTime div 1000 mod 60 + ]); WriteLn(s, 'stats_ver,datetime,server,map,mode,timelimit,scorelimit,dmflags,time,num_players'); - WriteLn(s, - Format('%d,%s,%s,%s,%s,%u,%u,%u,%s,%d', - [STATFILE_VERSION, StatDate, fname, map, mode, gGameSettings.TimeLimit, gGameSettings.GoalLimit, gGameSettings.Options, etime, Length(Stat.PlayerStat)])); + WriteLn(s, Format('%d,%s,%s,%s,%s,%u,%u,%u,%s,%d', [ + STATFILE_VERSION, + StatDate, + dquoteStr(fname), + dquoteStr(map), + mode, + gGameSettings.TimeLimit, + gGameSettings.GoalLimit, + gGameSettings.Options, + etime, + Length(Stat.PlayerStat) + ])); // line 2: game specific shit // if it's a team game: red score, blue score // if it's a coop game: monsters killed, monsters total, secrets found, secrets total // otherwise nothing if Stat.GameMode in [GM_TDM, GM_CTF] then - WriteLn(s, Format('red_score,blue_score' + LineEnding + '%d,%d', [Stat.TeamStat[TEAM_RED].Goals, Stat.TeamStat[TEAM_BLUE].Goals])) + WriteLn(s, + Format('red_score,blue_score' + LineEnding + '%d,%d', [Stat.TeamStat[TEAM_RED].Goals, Stat.TeamStat[TEAM_BLUE].Goals])) else if Stat.GameMode in [GM_COOP, GM_SINGLE] then - WriteLn(s, Format('mon_killed,mon_total,secrets_found,secrets_total' + LineEnding + '%d,%d,%d,%d', [gCoopMonstersKilled, gTotalMonsters, gCoopSecretsFound, gSecretsCount])); + WriteLn(s, + Format('mon_killed,mon_total,secrets_found,secrets_total' + LineEnding + '%d,%d,%d,%d',[gCoopMonstersKilled, gTotalMonsters, gCoopSecretsFound, gSecretsCount])); // lines 3-...: team, player name, frags, deaths WriteLn(s, 'team,name,frags,deaths'); for I := Low(Stat.PlayerStat) to High(Stat.PlayerStat) do with Stat.PlayerStat[I] do - WriteLn(s, Format('%d,%s,%d,%d', [Team, Name, Frags, Deaths])); + WriteLn(s, Format('%d,%s,%d,%d', [Team, dquoteStr(Name), Frags, Deaths])); except g_Console_Add(Format(_lc[I_CONSOLE_ERROR_WRITE], [fname])); end; diff --git a/src/shared/utils.pas b/src/shared/utils.pas index f5f762c..946e4f5 100644 --- a/src/shared/utils.pas +++ b/src/shared/utils.pas @@ -247,6 +247,9 @@ function digitInBase (ch: AnsiChar; base: Integer): Integer; // double quotes supports c-style escapes // function will select quote mode automatically function quoteStr (const s: AnsiString): AnsiString; +// separate single-quote and double-quote escape functions +function squoteStr (const s: AnsiString): AnsiString; +function dquoteStr (const s: AnsiString): AnsiString; type @@ -720,53 +723,52 @@ end; // ////////////////////////////////////////////////////////////////////////// // -function quoteStr (const s: AnsiString): AnsiString; - - function squote (const s: AnsiString): AnsiString; - var - f: Integer; +function squoteStr (const s: AnsiString): AnsiString; +var + f: Integer; +begin + result := ''''; + for f := 1 to Length(s) do begin - result := ''''; - for f := 1 to Length(s) do - begin - if (s[f] = '''') then result += ''''; - result += s[f]; - end; - result += ''''; + if (s[f] = '''') then result += ''''; + result += s[f]; end; + result += ''''; +end; - function dquote (const s: AnsiString): AnsiString; - var - f: Integer; - ch: AnsiChar; +function dquoteStr (const s: AnsiString): AnsiString; +var + f: Integer; + ch: AnsiChar; +begin + result := '"'; + for f := 1 to Length(s) do begin - result := '"'; - for f := 1 to Length(s) do + ch := s[f]; + if (ch = #0) then result += '\z' + else if (ch = #9) then result += '\t' + else if (ch = #10) then result += '\n' + else if (ch = #13) then result += '\r' + else if (ch = #27) then result += '\e' + else if (ch < ' ') or (ch = #127) then begin - ch := s[f]; - if (ch = #0) then result += '\z' - else if (ch = #9) then result += '\t' - else if (ch = #10) then result += '\n' - else if (ch = #13) then result += '\r' - else if (ch = #27) then result += '\e' - else if (ch < ' ') or (ch = #127) then - begin - result += '\x'; - result += LowerCase(IntToHex(Integer(ch), 2)); - end - else if (ch = '"') or (ch = '\') then - begin - result += '\'; - result += ch; - end - else - begin - result += ch; - end; + result += '\x'; + result += LowerCase(IntToHex(Integer(ch), 2)); + end + else if (ch = '"') or (ch = '\') then + begin + result += '\'; + result += ch; + end + else + begin + result += ch; end; - result += '"'; end; + result += '"'; +end; +function quoteStr (const s: AnsiString): AnsiString; var needSingle: Boolean = false; f: Integer; @@ -774,9 +776,9 @@ begin for f := 1 to Length(s) do begin if (s[f] = '''') then begin needSingle := true; continue; end; - if (s[f] < ' ') or (s[f] = #127) then begin result := dquote(s); exit; end; + if (s[f] < ' ') or (s[f] = #127) then begin result := dquoteStr(s); exit; end; end; - if needSingle then result := squote(s) else result := ''''+s+''''; + if needSingle then result := squoteStr(s) else result := ''''+s+''''; end;