@@ -47,7 +47,7 @@ int CConditional::ParseValue(char *pBuf, int Length)
4747 int Index;
4848 if (str_toint (pBuf, &Index))
4949 {
50- if (Index >= 0 && Index < m_pResult-> NumArguments () )
50+ if (Index >= 0 )
5151 return str_copy (pBuf, m_pResult->GetString (Index), Length);
5252 else
5353 return str_copy (pBuf, " " , Length);
@@ -62,16 +62,16 @@ int CConditional::ParseValue(char *pBuf, int Length)
6262
6363void CConditional::ParseString (char *pBuf, int Length)
6464{
65- // May give incorrect values on buffer overflow
6665 if (!pBuf || Length <= 0 )
6766 return ;
68-
69- std::vector<std::pair<int , int >> vParsedRanges;
70- const auto IsInParsedRegion = [&vParsedRanges](int Pos) {
71- return std::any_of (vParsedRanges.begin (), vParsedRanges.end (), [Pos](const auto &ParsedRange) {
72- return Pos >= ParsedRange.first && Pos < ParsedRange.second ;
73- });
74- };
67+ bool HasBrackets = false ;
68+ for (const char *p = pBuf; *p != ' \0 ' ; ++p)
69+ if (*p == ' {' || *p == ' }' )
70+ HasBrackets = true ;
71+ if (!HasBrackets)
72+ return ;
73+
74+ // May give malformed result on buffer overflow
7575
7676 int Len = strnlen (pBuf, Length);
7777 while (true )
@@ -82,11 +82,19 @@ void CConditional::ParseString(char *pBuf, int Length)
8282 // Find the innermost {...} not inside any parsed range
8383 for (int i = 0 ; i < Len; ++i)
8484 {
85- if (pBuf[i] == ' {' && !IsInParsedRegion (i))
85+ if (pBuf[i] != ' {' && pBuf[i] != ' }' )
86+ continue ;
87+ // Count number of backslashes before this character
88+ int BackslashCount = 0 ;
89+ for (int j = i - 1 ; j >= 0 && pBuf[j] == ' \\ ' ; --j)
90+ BackslashCount++;
91+ if (BackslashCount % 2 != 0 )
92+ continue ;
93+ if (pBuf[i] == ' {' )
8694 {
8795 LastOpen = i;
8896 }
89- else if (pBuf[i] == ' }' && LastOpen != -1 && ! IsInParsedRegion (i) )
97+ else if (pBuf[i] == ' }' && LastOpen != -1 )
9098 {
9199 ClosePos = i;
92100 break ;
@@ -106,44 +114,76 @@ void CConditional::ParseString(char *pBuf, int Length)
106114 int ResultLen = ParseValue (aTemp, sizeof (aTemp));
107115 if (ResultLen == -1 )
108116 {
109- ResultLen = CopyLen;
117+ if (Len + 2 >= Length)
118+ break ; // Not enough space; stop
119+ mem_move (pBuf + ClosePos + 1 , pBuf + ClosePos, Len - ClosePos + 1 );
120+ pBuf[ClosePos] = ' \\ ' ;
121+ Len++;
122+ mem_move (pBuf + LastOpen + 1 , pBuf + LastOpen, Len - LastOpen + 1 );
123+ pBuf[LastOpen] = ' \\ ' ;
124+ Len++;
110125 }
111126 else
112127 {
113- int TailLen = Len - ClosePos - 1 ;
114- int NewLen = LastOpen + ResultLen + TailLen;
128+ for (const char *p = aTemp; *p != ' \0 ' ; ++p)
129+ if (*p == ' {' || *p == ' }' || *p == ' \\ ' )
130+ ResultLen++;
131+ mem_move (pBuf + LastOpen + ResultLen, pBuf + ClosePos + 1 , Len - ClosePos);
132+ EscapeString (aTemp, pBuf + LastOpen, Length - LastOpen);
133+ Len -= ClosePos - LastOpen + 1 ;
134+ Len += ResultLen;
135+ pBuf[Len] = ' \0 ' ;
136+ }
137+ }
138+ UnescapeString (pBuf, Length);
139+ }
115140
116- if (NewLen >= Length)
117- {
118- ResultLen = Length - 1 - LastOpen - TailLen;
119- if (ResultLen < 0 )
120- ResultLen = 0 ;
121- NewLen = LastOpen + ResultLen + TailLen;
122- }
141+ int CConditional::EscapeString (char *pIn, char *pBuf, int Length)
142+ {
143+ int WriteIndex = 0 ;
144+ for (int i = 0 ; pIn[i] != ' \0 ' ; ++i)
145+ {
146+ char c = pIn[i];
123147
124- // Move tail forward/backward
125- mem_move (pBuf + LastOpen + ResultLen, pBuf + ClosePos + 1 , TailLen);
126- pBuf[NewLen] = ' \0 ' ;
148+ // If we need to write an escape character and the actual character
149+ if ((c == ' {' || c == ' }' || c == ' \\ ' ))
150+ {
151+ if (WriteIndex + 2 >= Length)
152+ break ; // not enough room for escape + char + null
153+ pBuf[WriteIndex++] = ' \\ ' ;
154+ }
155+ else
156+ {
157+ if (WriteIndex + 1 >= Length)
158+ break ; // not enough room for char + null
159+ }
127160
128- // Copy result
129- mem_copy (pBuf + LastOpen, aTemp, ResultLen);
130- Len = NewLen;
161+ pBuf[WriteIndex++] = c;
162+ }
163+ return WriteIndex;
164+ }
131165
132- // Shift existing ranges after ClosePos
133- for (auto &ParsedRange : vParsedRanges)
166+ void CConditional::UnescapeString (char *pString, int Length)
167+ {
168+ int WritePos = 0 ; // Position to write the unescaped char
169+ for (int ReadPos = 0 ; ReadPos < Length - 1 ; ReadPos++)
170+ {
171+ if (pString[ReadPos] == ' \\ ' && ReadPos + 1 < Length)
172+ {
173+ char NextChar = pString[ReadPos + 1 ];
174+ if (NextChar == ' \\ ' || NextChar == ' {' || NextChar == ' }' )
134175 {
135- if (ParsedRange.first > ClosePos)
136- {
137- int Delta = ResultLen - (ClosePos + 1 - LastOpen);
138- ParsedRange.first += Delta;
139- ParsedRange.second += Delta;
140- }
176+ // Replace the escape sequence by the actual character
177+ pString[WritePos++] = NextChar;
178+ ReadPos++; // Skip the escaped character
179+ continue ;
141180 }
142181 }
143-
144- // Add this region to parsed ranges
145- vParsedRanges.emplace_back (LastOpen, LastOpen + ResultLen);
182+ // Normal character, copy as-is
183+ pString[WritePos++] = pString[ReadPos];
146184 }
185+ // Null-terminate the resulting string
186+ pString[WritePos] = ' \0 ' ;
147187}
148188
149189void CConditional::ConIfeq (IConsole::IResult *pResult, void *pUserData)
@@ -230,12 +270,6 @@ static int TimeFromStr(const char *pStr, char OutUnit)
230270
231271void CConditional::OnConsoleInit ()
232272{
233- m_vVariables.emplace_back (" l" , [&](char *pOut, int Length) {
234- return str_copy (pOut, " {" , Length);
235- });
236- m_vVariables.emplace_back (" r" , [&](char *pOut, int Length) {
237- return str_copy (pOut, " }" , Length);
238- });
239273 m_vVariables.emplace_back (" game_mode" , [&](char *pOut, int Length) {
240274 return str_copy (pOut, GameClient ()->m_GameInfo .m_aGameType , Length);
241275 });
0 commit comments