1/*
2 * Copyright (C) 2020-2022 Roy Qu (royqh1979@gmail.com)
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17#include "gdbmiresultparser.h"
18
19#include <QFileInfo>
20#include <QList>
21#include <QDebug>
22
23GDBMIResultParser::GDBMIResultParser()
24{
25 mResultTypes.insert("-break-insert",GDBMIResultType::Breakpoint);
26 //mResultTypes.insert("BreakpointTable",GDBMIResultType::BreakpointTable);
27 mResultTypes.insert("-stack-list-frames",GDBMIResultType::FrameStack);
28 mResultTypes.insert("-stack-list-variables", GDBMIResultType::LocalVariables);
29 //mResultTypes.insert("frame",GDBMIResultType::Frame);
30 mResultTypes.insert("-data-disassemble",GDBMIResultType::Disassembly);
31 mResultTypes.insert("-data-evaluate-expression",GDBMIResultType::Evaluation);
32// mResultTypes.insert("register-names",GDBMIResultType::RegisterNames);
33// mResultTypes.insert("register-values",GDBMIResultType::RegisterValues);
34 mResultTypes.insert("-data-read-memory",GDBMIResultType::Memory);
35 mResultTypes.insert("-data-list-register-names",GDBMIResultType::RegisterNames);
36 mResultTypes.insert("-data-list-register-values",GDBMIResultType::RegisterValues);
37 mResultTypes.insert("-var-create",GDBMIResultType::CreateVar);
38 mResultTypes.insert("-var-list-children",GDBMIResultType::ListVarChildren);
39 mResultTypes.insert("-var-update",GDBMIResultType::UpdateVarValue);
40}
41
42bool GDBMIResultParser::parse(const QByteArray &record, const QString& command, GDBMIResultType &type, ParseObject& multiValues)
43{
44 const char* p = record.data();
45 bool result = parseMultiValues(p,multiValues);
46 if (!result)
47 return false;
48// if (*p!=0)
49// return false;
50 if (!mResultTypes.contains(command))
51 return false;
52 type = mResultTypes[command];
53 return true;
54}
55
56bool GDBMIResultParser::parseAsyncResult(const QByteArray &record, QByteArray &result, ParseObject &multiValue)
57{
58 const char* p =record.data();
59 if (*p!='*')
60 return false;
61 p++;
62 const char* start=p;
63 while (*p && *p!=',')
64 p++;
65 result = QByteArray(start,p-start);
66 if (*p==0)
67 return true;
68 p++;
69 return parseMultiValues(p,multiValue);
70}
71
72bool GDBMIResultParser::parseMultiValues(const char* p, ParseObject &multiValue)
73{
74 while (*p) {
75 QByteArray propName;
76 ParseValue propValue;
77 bool result = parseNameAndValue(p,propName,propValue);
78 if (result) {
79 multiValue[propName]=propValue;
80 } else {
81 return false;
82 }
83 skipSpaces(p);
84 if (*p==0)
85 break;
86 if (*p!=',')
87 return false;
88 p++; //skip ','
89 skipSpaces(p);
90 }
91 return true;
92}
93
94bool GDBMIResultParser::parseNameAndValue(const char *&p, QByteArray &name, ParseValue &value)
95{
96 skipSpaces(p);
97 const char* nameStart =p;
98 while (*p!=0 && isNameChar(*p)) {
99 p++;
100 }
101 if (*p==0)
102 return false;
103 name = QByteArray(nameStart,p-nameStart);
104 skipSpaces(p);
105 if (*p!='=')
106 return false;
107 p++;
108 return parseValue(p,value);
109}
110
111bool GDBMIResultParser::parseValue(const char *&p, ParseValue &value)
112{
113 skipSpaces(p);
114 bool result;
115 switch (*p) {
116 case '{': {
117 ParseObject obj;
118 result = parseObject(p,obj);
119 value = obj;
120 break;
121 }
122 case '[': {
123 QList<ParseValue> array;
124 result = parseArray(p,array);
125 value = array;
126 break;
127 }
128 case '"': {
129 QByteArray s;
130 result = parseStringValue(p,s);
131 value = s;
132 break;
133 }
134 default:
135 return false;
136 }
137 if (!result)
138 return false;
139 skipSpaces(p);
140 return true;
141}
142
143bool GDBMIResultParser::parseStringValue(const char *&p, QByteArray& stringValue)
144{
145 if (*p!='"')
146 return false;
147 p++;
148 stringValue.clear();
149 while (*p!=0) {
150 if (*p == '"') {
151 break;
152 } else if (*p=='\\' && *(p+1)!=0) {
153 p++;
154 switch (*p) {
155 case '\'':
156 stringValue+=0x27;
157 p++;
158 break;
159 case '"':
160 stringValue+=0x22;
161 p++;
162 break;
163 case '?':
164 stringValue+=0x3f;
165 p++;
166 break;
167 case '\\':
168 stringValue+=0x5c;
169 p++;
170 break;
171 case 'a':
172 stringValue+=0x07;
173 p++;
174 break;
175 case 'b':
176 stringValue+=0x08;
177 p++;
178 break;
179 case 'f':
180 stringValue+=0x0c;
181 p++;
182 break;
183 case 'n':
184 stringValue+=0x0a;
185 p++;
186 break;
187 case 'r':
188 stringValue+=0x0d;
189 p++;
190 break;
191 case 't':
192 stringValue+=0x09;
193 p++;
194 break;
195 case 'v':
196 stringValue+=0x0b;
197 p++;
198 break;
199 case '0':
200 case '1':
201 case '2':
202 case '3':
203 case '4':
204 case '5':
205 case '6':
206 case '7':
207 {
208 int i=0;
209 for (i=0;i<3;i++) {
210 if (*(p+i)<'0' || *(p+i)>'7')
211 break;
212 }
213 QByteArray numStr(p,i);
214 bool ok;
215 unsigned char ch = numStr.toInt(&ok,8);
216 stringValue+=ch;
217 p+=i;
218 break;
219 }
220 }
221 } else {
222 stringValue+=*p;
223 p++;
224 }
225 }
226 if (*p=='"') {
227 p++; //skip '"'
228 return true;
229 }
230 return false;
231}
232
233bool GDBMIResultParser::parseObject(const char *&p, ParseObject &obj)
234{
235 if (*p!='{')
236 return false;
237 p++;
238
239 if (*p!='}') {
240 while (*p!=0) {
241 QByteArray propName;
242 ParseValue propValue;
243 bool result = parseNameAndValue(p,propName,propValue);
244 if (result) {
245 obj[propName]=propValue;
246 } else {
247 return false;
248 }
249 skipSpaces(p);
250 if (*p=='}')
251 break;
252 if (*p!=',') {
253 return false;
254 }
255 p++; //skip ','
256 skipSpaces(p);
257 }
258 }
259 if (*p=='}') {
260 p++; //skip '}'
261 return true;
262 }
263 return false;
264}
265
266bool GDBMIResultParser::parseArray(const char *&p, QList<GDBMIResultParser::ParseValue> &array)
267{
268 if (*p!='[')
269 return false;
270 p++;
271 if (*p!=']') {
272 while (*p!=0) {
273 skipSpaces(p);
274 if (*p=='{' || *p=='"' || *p=='[') {
275 ParseValue val;
276 bool result = parseValue(p,val);
277 if (result) {
278 array.append(val);
279 } else {
280 return false;
281 }
282 } else {
283 QByteArray name;
284 ParseValue val;
285 bool result = parseNameAndValue(p,name,val);
286 if (result) {
287 array.append(val);
288 } else {
289 return false;
290 }
291 }
292 skipSpaces(p);
293 if (*p==']')
294 break;
295 if (*p!=',')
296 return false;
297 p++; //skip ','
298 skipSpaces(p);
299 }
300 }
301 if (*p==']') {
302 p++; //skip ']'
303 return true;
304 }
305 return false;
306}
307
308bool GDBMIResultParser::isNameChar(char ch)
309{
310 if (ch=='-')
311 return true;
312 if (ch=='_')
313 return true;
314 if (ch>='a' && ch<='z')
315 return true;
316 if (ch>='A' && ch<='Z')
317 return true;
318 return false;
319}
320
321bool GDBMIResultParser::isSpaceChar(char ch)
322{
323 switch(ch) {
324 case ' ':
325 case '\t':
326 return true;
327 }
328 return false;
329}
330
331void GDBMIResultParser::skipSpaces(const char *&p)
332{
333 while (*p!=0 && isSpaceChar(*p))
334 p++;
335}
336
337const QByteArray &GDBMIResultParser::ParseValue::value() const
338{
339 return mValue;
340}
341
342const QList<::GDBMIResultParser::ParseValue> &GDBMIResultParser::ParseValue::array() const
343{
344 return mArray;
345}
346
347const GDBMIResultParser::ParseObject &GDBMIResultParser::ParseValue::object() const
348{
349 return mObject;
350}
351
352int GDBMIResultParser::ParseValue::intValue(int defaultValue) const
353{
354 //Q_ASSERT(mType == ParseValueType::Value);
355 bool ok;
356 int value = QString(mValue).toInt(&ok);
357 if (ok)
358 return value;
359 else
360 return defaultValue;
361}
362
363int GDBMIResultParser::ParseValue::hexValue(int defaultValue) const
364{
365 //Q_ASSERT(mType == ParseValueType::Value);
366 bool ok;
367 int value = QString(mValue).toInt(&ok,16);
368 if (ok)
369 return value;
370 else
371 return defaultValue;
372}
373
374QString GDBMIResultParser::ParseValue::pathValue() const
375{
376 //Q_ASSERT(mType == ParseValueType::Value);
377 return QFileInfo(QString::fromLocal8Bit(mValue)).absoluteFilePath();
378}
379
380QString GDBMIResultParser::ParseValue::utf8PathValue() const
381{
382 return QFileInfo(QString::fromUtf8(mValue)).absoluteFilePath();
383}
384
385GDBMIResultParser::ParseValueType GDBMIResultParser::ParseValue::type() const
386{
387 return mType;
388}
389
390bool GDBMIResultParser::ParseValue::isValid() const
391{
392 return mType!=ParseValueType::NotAssigned;
393}
394
395GDBMIResultParser::ParseValue::ParseValue():
396 mType(ParseValueType::NotAssigned) {
397
398}
399
400GDBMIResultParser::ParseValue::ParseValue(const QByteArray &value):
401 mValue(value),
402 mType(ParseValueType::Value)
403{
404}
405
406GDBMIResultParser::ParseValue::ParseValue(const ParseObject &object):
407 mObject(object),
408 mType(ParseValueType::Object)
409{
410}
411
412GDBMIResultParser::ParseValue::ParseValue(const QList<ParseValue> &array):
413 mArray(array),
414 mType(ParseValueType::Array)
415{
416}
417
418GDBMIResultParser::ParseValue::ParseValue(const ParseValue &value):
419 mValue(value.mValue),
420 mArray(value.mArray),
421 mObject(value.mObject),
422 mType(value.mType)
423{
424}
425
426GDBMIResultParser::ParseValue &GDBMIResultParser::ParseValue::operator=(const GDBMIResultParser::ParseValue &value)
427{
428 mType = value.mType;
429 mValue = value.mValue;
430 mArray = value.mArray;
431 mObject = value.mObject;
432 return *this;
433}
434
435GDBMIResultParser::ParseValue &GDBMIResultParser::ParseValue::operator=(const QByteArray &value)
436{
437 Q_ASSERT(mType == ParseValueType::NotAssigned);
438 mType = ParseValueType::Value;
439 mValue = value;
440 return *this;
441}
442
443GDBMIResultParser::ParseValue &GDBMIResultParser::ParseValue::operator=(const ParseObject& object)
444{
445 Q_ASSERT(mType == ParseValueType::NotAssigned);
446 mType = ParseValueType::Object;
447 mObject = object;
448 return *this;
449}
450
451GDBMIResultParser::ParseValue &GDBMIResultParser::ParseValue::operator=(const QList<ParseValue>& array)
452{
453 Q_ASSERT(mType == ParseValueType::NotAssigned);
454 mType = ParseValueType::Array;
455 mArray = array;
456 return *this;
457}
458
459
460GDBMIResultParser::ParseObject::ParseObject()
461{
462
463}
464
465GDBMIResultParser::ParseObject::ParseObject(const ParseObject &object):
466 mProps(object.mProps)
467{
468
469}
470
471GDBMIResultParser::ParseValue GDBMIResultParser::ParseObject::operator[](const QByteArray &name) const
472{
473 if (mProps.contains(name)) {
474 ParseValue value(mProps[name]);
475 return value;
476 }
477 return ParseValue();
478}
479
480GDBMIResultParser::ParseObject &GDBMIResultParser::ParseObject::operator=(const ParseObject &object)
481{
482 mProps = object.mProps;
483 return *this;
484}
485
486GDBMIResultParser::ParseValue &GDBMIResultParser::ParseObject::operator[](const QByteArray &name) {
487 if (!mProps.contains(name))
488 mProps[name]=ParseValue();
489 return mProps[name];
490}
491
492