HyperDbg Debugger
Loading...
Searching...
No Matches
CommandParser Class Reference

Public Member Functions

std::vector< CommandTokenParse (const std::string &ConstInput)
 Parse the input string (commands).
std::string TokenTypeToString (CommandParsingTokenType Type)
 Function to convert CommandParsingTokenType to a string.
VOID PrintTokens (const std::vector< CommandToken > &Tokens)
 Function to print the elements of a vector of Tokens.

Member Function Documentation

◆ Parse()

std::vector< CommandToken > CommandParser::Parse ( const std::string & ConstInput)
inline

Parse the input string (commands).

Parameters
input
Returns
std::vector<CommandToken>
45 {
46 std::vector<CommandToken> tokens;
47 std::string current;
48 BOOLEAN InQuotes = FALSE;
49 INT IdxBracket = 0;
50
51 //
52 // mainly for removing \ from escaped chars
53 //
54 std::string input = ConstInput;
55 for (SIZE_T i = 0; i < input.length(); ++i)
56 {
57 CHAR c = input[i];
58
59 if (c == '/') // start comment parse
60 {
61 //
62 // if we're in a script bracket, should we skip? it'll be handled later?
63 //
64 if (!InQuotes)
65 {
66 SIZE_T j = i;
67 CHAR c2 = input[++j];
68
69 if (c2 == '/') // start to look for comments
70 {
71 //
72 // to solve cases like: //"}"
73 //
74 SIZE_T StrLitEnd = 0;
75 SIZE_T StrLitBeg = input.find("\"", i);
76 if (StrLitBeg != std::string::npos)
77 {
78 if (i)
79 {
80 if (input[i - 1] != '\\') // if not escaped
81 {
82 StrLitEnd = input.find("\"", StrLitBeg + 1);
83 if (StrLitEnd != std::string::npos)
84 {
85 std::string StrLit(input.substr(i, StrLitEnd - i + 1));
86 }
87 }
88 }
89 else
90 {
91 StrLitEnd = input.find("\"", StrLitBeg + 1);
92 if (StrLitEnd != std::string::npos)
93 {
94 std::string StrLit(input.substr(i, StrLitEnd - i + 1));
95 }
96 }
97 }
98
99 //
100 // assuming " }" as the end of a line comment aka //, if we are within {}
101 //
102 BOOLEAN CmntEndBrkt = FALSE;
103 SIZE_T CloseBrktPos = 0;
104 if (IdxBracket)
105 {
106 //
107 // loop for escaped }
108 //
109 auto pos = (StrLitEnd > i) ? StrLitEnd : i;
110 for (CloseBrktPos = input.find("}", pos); CloseBrktPos != std::string::npos;)
111 {
112 CloseBrktPos = input.find("}", CloseBrktPos);
113 if (input[CloseBrktPos - 1] == '\\')
114 {
115 input.erase(CloseBrktPos - 1, 1);
116 CloseBrktPos += 1;
117 }
118 else
119 {
120 break;
121 }
122 }
123 }
124 else
125 {
126 CloseBrktPos = std::string::npos;
127 }
128
129 SIZE_T NewLineSrtPos = input.find("\\n", i); // "\\n" entered by user
130 if (StrLitBeg && StrLitBeg <= NewLineSrtPos && NewLineSrtPos <= StrLitEnd) // is it within the string literal?
131 {
132 NewLineSrtPos = std::string::npos;
133 }
134 SIZE_T NewLineChrPos = input.find('\n', i);
135
136 std::vector<SIZE_T> PosVec = {CloseBrktPos, NewLineSrtPos, NewLineChrPos};
137
138 auto min = *(min_element(PosVec.begin(), PosVec.end())); // see which one occurs first
139
140 if (min != std::string::npos && input[min - 1] != '\\')
141 {
142 //
143 // here we could get the comment but for now we just skip
144 //
145 std::string comment(input.substr(i, min - i));
146
147 //
148 // append comments to be passed to script engine
149 //
150 if (IdxBracket)
151 {
152 current += comment;
153 }
154
155 //
156 // forward the buffer
157 //
158 auto diff = (min > i) ? (min - i) : (i - min);
159 i = i + diff - 1;
160
161 continue;
162 }
163 else
164 {
165 BOOLEAN IsNewLineEsc = FALSE;
166 if (NewLineSrtPos != std::string::npos)
167 {
168 IsNewLineEsc = input[NewLineSrtPos - 1] == '\\';
169 }
170
171 // if (NewLineSrtPos != std::string::npos && !IsNewLineEsc) // is not escaped
172 //{
173 // //
174 // // here we could get the comment but for now we just skip
175 // //
176 // std::string comment(input.substr(i, NewLineSrtPos - i));
177
178 // //
179 // // append comments to be passed to script engine
180 // //
181 // if (IdxBracket)
182 // {
183 // current += comment;
184 // }
185
186 // //
187 // // forward the buffer
188 // //
189 // i = i + (NewLineSrtPos - i) + 1; // +1 for "\n". the "continue;" will also go past another time.
190
191 // continue;
192 //}
193 // else if (NewLineChrPos != std::string::npos)
194 //{
195 // //
196 // // here we could get the comment but for now we just skip
197 // //
198 // std::string comment(input.substr(i, NewLineChrPos - i));
199
200 // //
201 // // append comments to be passed to script engine
202 // //
203 // if (IdxBracket)
204 // {
205 // current += comment;
206 // }
207
208 // //
209 // // forward the buffer
210 // //
211 // i = i + (NewLineChrPos - i);
212
213 // continue; // go past '\n'
214 //}
215 // else
216 //{
217 //
218 // no "\\n" nor '\n' found so we just mark the chars as comment till end of string
219 //
220 std::string comment(input.substr(i, input.size()));
221
222 // fix the escaped newline
223 if (IsNewLineEsc)
224 {
225 SIZE_T start_pos = 0;
226 while ((start_pos = comment.find("\\\\n", start_pos)) != std::string::npos)
227 {
228 comment.replace(start_pos, 3, "\\n");
229 start_pos += 2; // Handles case where 'to' is a substring of 'from'
230 }
231
232 IsNewLineEsc = FALSE;
233 }
234
235 //
236 // append comments to be passed to script engine
237 //
238 if (IdxBracket)
239 {
240 current += comment;
241 }
242
243 //
244 // forward the buffer
245 //
246 i = i + (input.size() - i);
247
248 continue;
249 }
250 //}
251 }
252 else if (c2 == '*')
253 {
254 SIZE_T EndPose = input.find("*/", i + 2); // +2 for cases like /*/
255
256 if (EndPose != std::string::npos)
257 {
258 //
259 // here we could get the comment but for now we just skip
260 //
261 std::string comment(input.substr(i, EndPose - i + 2)); // */ is two bytes long
262
263 //
264 // append comments to be passed to script engine
265 //
266 if (IdxBracket)
267 {
268 current += comment;
269 }
270
271 //
272 // forward the buffer
273 //
274 i = (i + (EndPose - i)) + 1; // +1 for /
275
276 continue;
277 }
278 else
279 {
280 // error: comment not closed
281 }
282 }
283 }
284 }
285
286 if (InQuotes)
287 {
288 if (c == '"')
289 {
290 if (input[i - 1] != '\\')
291 {
292 InQuotes = FALSE;
293
294 //
295 // if the quoted text is not within brackets, regard it as a StringLiteral token
296 //
297 if (!IdxBracket)
298 {
299 AddStringToken(tokens, current, TRUE); // TRUE for StringLiteral type
300 current.clear();
301 continue; // dont add " char
302 }
303 else
304 {
305 current += c;
306 continue; // dont add " char
307 }
308 //
309 // if we are indeed within brackets, we continue to add the '"' char to the current buffer
310 //
311 }
312 else
313 {
314 input.erase(i - 1, 1);
315 i--; // compensate for the removed char
316
317 //
318 // remove last read "\\" if we are not within a {}
319 //
320 if (!IdxBracket)
321 {
322 current.pop_back();
323 }
324 current += c;
325 continue;
326 }
327 }
328 }
329
330 if (c == '}')
331 {
332 if (input[i - 1] != '\\')
333 {
334 if (IdxBracket)
335 {
336 if (!InQuotes) // not closing "
337 {
338 IdxBracket--;
339 }
340
341 if (!IdxBracket) // is closing }
342 {
343 AddBracketStringToken(tokens, current);
344 current.clear();
345
346 continue;
347 }
348 }
349 }
350 else if (!InQuotes)
351 {
352 input.erase(i - 1, 1);
353 i--; // compensate for the removed char
354 current.pop_back(); // remove last read \\
355
356 }
357 }
358
359 if (((c == ' ' && !InQuotes) || c == ' ') && !InQuotes && !IdxBracket) // finding separator space char // Tab separator added too
360 {
361 if (!current.empty() && current != " ")
362 {
363 AddToken(tokens, current);
364 current.clear();
365
366 continue;
367 }
368 continue; // avoid adding extra space char
369 }
370 else if (c == '"') // string literal is adjacent to previous command
371 {
372 if (i) // check if this " is the first char to avoid out of range check
373 {
374 if (input[i - 1] != ' ' && !IdxBracket && !current.empty() && !InQuotes) // is prev cmd adjacent to "
375 {
376 AddStringToken(tokens, current);
377 current.clear();
378 }
379
380 if (input[i - 1] != '\\')
381 {
382 InQuotes = TRUE;
383 if (!IdxBracket)
384 {
385 continue; // don't include '"' in string
386 }
387 }
388 }
389 else
390 {
391 InQuotes = TRUE;
392 if (!IdxBracket)
393 {
394 continue; // don't include '"' in string
395 }
396 }
397 }
398 else if (c == '{' && !InQuotes)
399 {
400 if (i) // check if this { is the first char to avoid out of range check
401 {
402 if (input[i - 1] != '\\')
403 {
404 if (input[i - 1] != ' ' && !IdxBracket) // in case '{' is adjacent to previous command like "command{", on first {
405 {
406 AddToken(tokens, current);
407 current.clear();
408 }
409
410 IdxBracket++;
411 if (IdxBracket == 1) // first {
412 continue; // don't include '{' in string
413 }
414 else
415 {
416 input.erase(i - 1, 1);
417 i--; // compensate for the removed char
418 current.pop_back(); // remove last read \\
419
420 }
421 }
422 else
423 {
424 IdxBracket++;
425 if (IdxBracket == 1) // first {
426 continue; // don't include '{' in string
427 }
428 }
429
430 //
431 // ignore astray \n
432 //
433 if (c == '\\' && !InQuotes)
434 {
435 if (current.empty() && input[i + 1] == 'n')
436 {
437 i++;
438 continue;
439 }
440 }
441
442 current += c;
443 }
444
445 if (!current.empty() && current != " ")
446 {
447 AddToken(tokens, current);
448 }
449
450 if (IdxBracket)
451 {
452 // error: script bracket not closed
453 }
454
455 if (InQuotes)
456 {
457 // error: Quote not closed
458 }
459
460 return tokens;
461 }
UCHAR BOOLEAN
Definition BasicTypes.h:35
int INT
Definition BasicTypes.h:43
#define TRUE
Definition BasicTypes.h:114
#define FALSE
Definition BasicTypes.h:113
char CHAR
Definition BasicTypes.h:33

◆ PrintTokens()

VOID CommandParser::PrintTokens ( const std::vector< CommandToken > & Tokens)
inline

Function to print the elements of a vector of Tokens.

Parameters
Tokens
Returns
VOID
497 {
498 //
499 // get len of longest string
500 //
501 const INT sz = 200; // size
502 INT g_s1Len = 0, g_s2Len = 0, g_s3Len = 0;
503 INT s1 = 0, s2 = 0, s3 = 0;
504 CHAR LineToPrint1[sz], LineToPrint2[sz], LineToPrint3[sz];
505
506 for (const auto & Token : Tokens)
507 {
508 s1 = snprintf(LineToPrint1, sz, "CommandParsingTokenType: %s ", TokenTypeToString(std::get<0>(Token)).c_str());
509 s2 = snprintf(LineToPrint2, sz, ", Value 1: '%s'", std::get<1>(Token).c_str());
510 s3 = snprintf(LineToPrint3, sz, ", Value 2 (lower): '%s'", std::get<2>(Token).c_str());
511
512 if (s1 > g_s1Len)
513 g_s1Len = s1;
514
515 if (s2 > g_s2Len)
516 g_s2Len = s2;
517
518 if (s3 > g_s3Len)
519 g_s3Len = s3;
520 }
521
522 for (const auto & Token : Tokens)
523 {
524 auto CaseSensitiveText = std::get<1>(Token);
525 auto LowerCaseText = std::get<2>(Token);
526
527 if (std::get<0>(Token) == CommandParsingTokenType::BracketString ||
528 std::get<0>(Token) == CommandParsingTokenType::String ||
529 std::get<0>(Token) == CommandParsingTokenType::StringLiteral)
530 {
531 //
532 // Replace \n with \\n
533 //
534
535 //
536 // Search for \n and replace with \\n
537 //
538 std::string::size_type pos = 0;
539 while ((pos = CaseSensitiveText.find("\n", pos)) != std::string::npos)
540 {
541 CaseSensitiveText.replace(pos, 1, "\\n");
542 pos += 2; // Move past the newly added characters
543 }
544
545 //
546 // Do the same for lower case text
547 //
548 pos = 0;
549 while ((pos = LowerCaseText.find("\n", pos)) != std::string::npos)
550 {
551 LowerCaseText.replace(pos, 1, "\\n");
552 pos += 2; // Move past the newly added characters
553 }
554 }
555
556 snprintf(LineToPrint1, sz, "CommandParsingTokenType: %s ", TokenTypeToString(std::get<0>(Token)).c_str());
557 snprintf(LineToPrint2, sz, ", Value 1: '%s'", CaseSensitiveText.c_str());
558 snprintf(LineToPrint3, sz, ", Value 2 (lower): '%s'", LowerCaseText.c_str());
559
560 ShowMessages("%-*s %-*s %-*s\n", // - for left align
561 g_s1Len,
562 LineToPrint1,
563 g_s2Len,
564 LineToPrint2,
565 g_s3Len,
566 LineToPrint3);
567
568 /*ShowMessages("CommandParsingTokenType: %s , Value 1: '%s', Value 2 (lower): '%s'\n",
569 TokenTypeToString(std::get<0>(Token)).c_str(),
570 CaseSensitiveText.c_str(),
571 LowerCaseText.c_str());*/
572 }
573 }
std::string TokenTypeToString(CommandParsingTokenType Type)
Function to convert CommandParsingTokenType to a string.
Definition interpreter.cpp:469
@ StringLiteral
Definition commands.h:169
@ String
Definition commands.h:168
@ BracketString
Definition commands.h:170
VOID ShowMessages(const CHAR *Fmt,...)
Show messages.
Definition messaging.cpp:84

◆ TokenTypeToString()

std::string CommandParser::TokenTypeToString ( CommandParsingTokenType Type)
inline

Function to convert CommandParsingTokenType to a string.

Parameters
Type
Returns
std::string
470 {
471 switch (Type)
472 {
474 return "Num";
475
477 return "String";
478
480 return "StringLiteral";
481
483 return "BracketString";
484
485 default:
486 return "Unknown";
487 }
488 }
@ Num
Definition commands.h:167

The documentation for this class was generated from the following file: