blob: e7e0423e9e817f6de3de4ce494ea3f9c0545e8e3 [file] [log] [blame]
Todd Fiala75930012016-08-19 04:21:48 +00001//===--------------------- JSON.cpp -----------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "JSON.h"
11
12// C includes
13#include <assert.h>
14#include <limits.h>
15
16// C++ includes
17#include <iomanip>
18#include <sstream>
19#include "lldb/Host/StringConvert.h"
20
21using namespace lldb_private;
22
23std::string
24JSONString::json_string_quote_metachars (const std::string &s)
25{
26 if (s.find('"') == std::string::npos)
27 return s;
28
29 std::string output;
30 const size_t s_size = s.size();
31 const char *s_chars = s.c_str();
32 for (size_t i = 0; i < s_size; i++)
33 {
34 unsigned char ch = *(s_chars + i);
35 if (ch == '"')
36 {
37 output.push_back ('\\');
38 }
39 output.push_back (ch);
40 }
41 return output;
42}
43
44JSONString::JSONString () :
45 JSONValue(JSONValue::Kind::String),
46 m_data()
47{
48}
49
50JSONString::JSONString (const char* s) :
51 JSONValue(JSONValue::Kind::String),
52 m_data(s ? s : "")
53{
54}
55
56JSONString::JSONString (const std::string& s) :
57 JSONValue(JSONValue::Kind::String),
58 m_data(s)
59{
60}
61
62void
63JSONString::Write (std::ostream& s)
64{
65 s << "\"" << json_string_quote_metachars(m_data).c_str() <<"\"";
66}
67
68uint64_t
69JSONNumber::GetAsUnsigned() const
70{
71 switch (m_data_type)
72 {
73 case DataType::Unsigned:
74 return m_data.m_unsigned;
75 case DataType::Signed:
76 return (uint64_t)m_data.m_signed;
77 case DataType::Double:
78 return (uint64_t)m_data.m_double;
79 }
80 assert("Unhandled data type");
81}
82
83int64_t
84JSONNumber::GetAsSigned() const
85{
86 switch (m_data_type)
87 {
88 case DataType::Unsigned:
89 return (int64_t)m_data.m_unsigned;
90 case DataType::Signed:
91 return m_data.m_signed;
92 case DataType::Double:
93 return (int64_t)m_data.m_double;
94 }
95 assert("Unhandled data type");
96}
97
98double
99JSONNumber::GetAsDouble() const
100{
101 switch (m_data_type)
102 {
103 case DataType::Unsigned:
104 return (double)m_data.m_unsigned;
105 case DataType::Signed:
106 return (double)m_data.m_signed;
107 case DataType::Double:
108 return m_data.m_double;
109 }
110 assert("Unhandled data type");
111}
112
113void
114JSONNumber::Write (std::ostream& s)
115{
116 switch (m_data_type)
117 {
118 case DataType::Unsigned:
119 s << m_data.m_unsigned;
120 break;
121 case DataType::Signed:
122 s << m_data.m_signed;
123 break;
124 case DataType::Double:
125 // Set max precision to emulate %g.
126 s << std::setprecision(std::numeric_limits<double>::digits10 + 1);
127 s << m_data.m_double;
128 break;
129 }
130}
131
132JSONTrue::JSONTrue () :
133 JSONValue(JSONValue::Kind::True)
134{
135}
136
137void
138JSONTrue::Write(std::ostream& s)
139{
140 s << "true";
141}
142
143JSONFalse::JSONFalse () :
144 JSONValue(JSONValue::Kind::False)
145{
146}
147
148void
149JSONFalse::Write(std::ostream& s)
150{
151 s << "false";
152}
153
154JSONNull::JSONNull () :
155 JSONValue(JSONValue::Kind::Null)
156{
157}
158
159void
160JSONNull::Write(std::ostream& s)
161{
162 s << "null";
163}
164
165JSONObject::JSONObject () :
166 JSONValue(JSONValue::Kind::Object)
167{
168}
169
170void
171JSONObject::Write (std::ostream& s)
172{
173 bool first = true;
174 s << '{';
175 auto iter = m_elements.begin(), end = m_elements.end();
176 for (;iter != end; iter++)
177 {
178 if (first)
179 first = false;
180 else
181 s << ',';
182 JSONString key(iter->first);
183 JSONValue::SP value(iter->second);
184 key.Write(s);
185 s << ':';
186 value->Write(s);
187 }
188 s << '}';
189}
190
191bool
192JSONObject::SetObject (const std::string& key,
193 JSONValue::SP value)
194{
195 if (key.empty() || nullptr == value.get())
196 return false;
197 m_elements[key] = value;
198 return true;
199}
200
201JSONValue::SP
202JSONObject::GetObject (const std::string& key) const
203{
204 auto iter = m_elements.find(key), end = m_elements.end();
205 if (iter == end)
206 return JSONValue::SP();
207 return iter->second;
208}
209
210bool
211JSONObject::GetObjectAsBool (const std::string& key, bool& value) const
212{
213 auto value_sp = GetObject(key);
214 if (!value_sp)
215 {
216 // The given key doesn't exist, so we have no value.
217 return false;
218 }
219
220 if (JSONTrue::classof(value_sp.get()))
221 {
222 // We have the value, and it is true.
223 value = true;
224 return true;
225 }
226 else if (JSONFalse::classof(value_sp.get()))
227 {
228 // We have the value, and it is false.
229 value = false;
230 return true;
231 }
232 else
233 {
234 // We don't have a valid bool value for the given key.
235 return false;
236 }
237}
238
239bool
240JSONObject::GetObjectAsString (const std::string& key, std::string& value) const
241{
242 auto value_sp = GetObject(key);
243 if (!value_sp)
244 {
245 // The given key doesn't exist, so we have no value.
246 return false;
247 }
248
249 if (!JSONString::classof(value_sp.get()))
250 return false;
251
252 value = static_cast<JSONString*>(value_sp.get())->GetData();
253 return true;
254}
255
256JSONArray::JSONArray () :
257 JSONValue(JSONValue::Kind::Array)
258{
259}
260
261void
262JSONArray::Write (std::ostream& s)
263{
264 bool first = true;
265 s << '[';
266 auto iter = m_elements.begin(), end = m_elements.end();
267 for (;iter != end; iter++)
268 {
269 if (first)
270 first = false;
271 else
272 s << ',';
273 (*iter)->Write(s);
274 }
275 s << ']';
276}
277
278bool
279JSONArray::SetObject (Index i,
280 JSONValue::SP value)
281{
282 if (value.get() == nullptr)
283 return false;
284 if (i < m_elements.size())
285 {
286 m_elements[i] = value;
287 return true;
288 }
289 if (i == m_elements.size())
290 {
291 m_elements.push_back(value);
292 return true;
293 }
294 return false;
295}
296
297bool
298JSONArray::AppendObject (JSONValue::SP value)
299{
300 if (value.get() == nullptr)
301 return false;
302 m_elements.push_back(value);
303 return true;
304}
305
306JSONValue::SP
307JSONArray::GetObject (Index i)
308{
309 if (i < m_elements.size())
310 return m_elements[i];
311 return JSONValue::SP();
312}
313
314JSONArray::Size
315JSONArray::GetNumElements ()
316{
317 return m_elements.size();
318}
319
320
321JSONParser::JSONParser (const char *cstr) :
322 StringExtractor(cstr)
323{
324}
325
326JSONParser::Token
327JSONParser::GetToken (std::string &value)
328{
329 std::ostringstream error;
330
331 value.clear();
332 SkipSpaces ();
333 const uint64_t start_index = m_index;
334 const char ch = GetChar();
335 switch (ch)
336 {
337 case '{': return Token::ObjectStart;
338 case '}': return Token::ObjectEnd;
339 case '[': return Token::ArrayStart;
340 case ']': return Token::ArrayEnd;
341 case ',': return Token::Comma;
342 case ':': return Token::Colon;
343 case '\0': return Token::EndOfFile;
344 case 't':
345 if (GetChar() == 'r')
346 if (GetChar() == 'u')
347 if (GetChar() == 'e')
348 return Token::True;
349 break;
350
351 case 'f':
352 if (GetChar() == 'a')
353 if (GetChar() == 'l')
354 if (GetChar() == 's')
355 if (GetChar() == 'e')
356 return Token::False;
357 break;
358
359 case 'n':
360 if (GetChar() == 'u')
361 if (GetChar() == 'l')
362 if (GetChar() == 'l')
363 return Token::Null;
364 break;
365
366 case '"':
367 {
368 while (1)
369 {
370 bool was_escaped = false;
371 int escaped_ch = GetEscapedChar(was_escaped);
372 if (escaped_ch == -1)
373 {
374 error << "error: an error occurred getting a character from offset " <<start_index;
375 value = std::move(error.str());
376 return Token::Error;
377
378 }
379 else
380 {
381 const bool is_end_quote = escaped_ch == '"';
382 const bool is_null = escaped_ch == 0;
383 if (was_escaped || (!is_end_quote && !is_null))
384 {
385 if (CHAR_MIN <= escaped_ch && escaped_ch <= CHAR_MAX)
386 {
387 value.append(1, (char)escaped_ch);
388 }
389 else
390 {
391 error << "error: wide character support is needed for unicode character 0x" << std::setprecision(4) << std::hex << escaped_ch;
392 error << " at offset " << start_index;
393 value = std::move(error.str());
394 return Token::Error;
395 }
396 }
397 else if (is_end_quote)
398 {
399 return Token::String;
400 }
401 else if (is_null)
402 {
403 value = "error: missing end quote for string";
404 return Token::Error;
405 }
406 }
407 }
408 }
409 break;
410
411 case '-':
412 case '0':
413 case '1':
414 case '2':
415 case '3':
416 case '4':
417 case '5':
418 case '6':
419 case '7':
420 case '8':
421 case '9':
422 {
423 bool done = false;
424 bool got_decimal_point = false;
425 uint64_t exp_index = 0;
426 bool got_int_digits = (ch >= '0') && (ch <= '9');
427 bool got_frac_digits = false;
428 bool got_exp_digits = false;
429 while (!done)
430 {
431 const char next_ch = PeekChar();
432 switch (next_ch)
433 {
434 case '0':
435 case '1':
436 case '2':
437 case '3':
438 case '4':
439 case '5':
440 case '6':
441 case '7':
442 case '8':
443 case '9':
444 if (exp_index != 0)
445 {
446 got_exp_digits = true;
447 }
448 else if (got_decimal_point)
449 {
450 got_frac_digits = true;
451 }
452 else
453 {
454 got_int_digits = true;
455 }
456 ++m_index; // Skip this character
457 break;
458
459 case '.':
460 if (got_decimal_point)
461 {
462 error << "error: extra decimal point found at offset " << start_index;
463 value = std::move(error.str());
464 return Token::Error;
465 }
466 else
467 {
468 got_decimal_point = true;
469 ++m_index; // Skip this character
470 }
471 break;
472
473 case 'e':
474 case 'E':
475 if (exp_index != 0)
476 {
477 error << "error: extra exponent character found at offset " << start_index;
478 value = std::move(error.str());
479 return Token::Error;
480 }
481 else
482 {
483 exp_index = m_index;
484 ++m_index; // Skip this character
485 }
486 break;
487
488 case '+':
489 case '-':
490 // The '+' and '-' can only come after an exponent character...
491 if (exp_index == m_index - 1)
492 {
493 ++m_index; // Skip the exponent sign character
494 }
495 else
496 {
497 error << "error: unexpected " << next_ch << " character at offset " << start_index;
498 value = std::move(error.str());
499 return Token::Error;
500 }
501 break;
502
503 default:
504 done = true;
505 break;
506 }
507 }
508
509 if (m_index > start_index)
510 {
511 value = m_packet.substr(start_index, m_index - start_index);
512 if (got_decimal_point)
513 {
514 if (exp_index != 0)
515 {
516 // We have an exponent, make sure we got exponent digits
517 if (got_exp_digits)
518 {
519 return Token::Float;
520 }
521 else
522 {
523 error << "error: got exponent character but no exponent digits at offset in float value \"" << value.c_str() << "\"";
524 value = std::move(error.str());
525 return Token::Error;
526 }
527 }
528 else
529 {
530 // No exponent, but we need at least one decimal after the decimal point
531 if (got_frac_digits)
532 {
533 return Token::Float;
534 }
535 else
536 {
537 error << "error: no digits after decimal point \"" << value.c_str() << "\"";
538 value = std::move(error.str());
539 return Token::Error;
540 }
541 }
542 }
543 else
544 {
545 // No decimal point
546 if (got_int_digits)
547 {
548 // We need at least some integer digits to make an integer
549 return Token::Integer;
550 }
551 else
552 {
553 error << "error: no digits negate sign \"" << value.c_str() << "\"";
554 value = std::move(error.str());
555 return Token::Error;
556 }
557 }
558 }
559 else
560 {
561 error << "error: invalid number found at offset " << start_index;
562 value = std::move(error.str());
563 return Token::Error;
564 }
565 }
566 break;
567 default:
568 break;
569 }
570 error << "error: failed to parse token at offset " << start_index << " (around character '" << ch << "')";
571 value = std::move(error.str());
572 return Token::Error;
573}
574
575int
576JSONParser::GetEscapedChar(bool &was_escaped)
577{
578 was_escaped = false;
579 const char ch = GetChar();
580 if (ch == '\\')
581 {
582 was_escaped = true;
583 const char ch2 = GetChar();
584 switch (ch2)
585 {
586 case '"':
587 case '\\':
588 case '/':
589 default:
590 break;
591
592 case 'b': return '\b';
593 case 'f': return '\f';
594 case 'n': return '\n';
595 case 'r': return '\r';
596 case 't': return '\t';
597 case 'u':
598 {
599 const int hi_byte = DecodeHexU8();
600 const int lo_byte = DecodeHexU8();
601 if (hi_byte >=0 && lo_byte >= 0)
602 return hi_byte << 8 | lo_byte;
603 return -1;
604 }
605 break;
606 }
607 return ch2;
608 }
609 return ch;
610}
611
612JSONValue::SP
613JSONParser::ParseJSONObject ()
614{
615 // The "JSONParser::Token::ObjectStart" token should have already been consumed
616 // by the time this function is called
617 std::unique_ptr<JSONObject> dict_up(new JSONObject());
618
619 std::string value;
620 std::string key;
621 while (1)
622 {
623 JSONParser::Token token = GetToken(value);
624
625 if (token == JSONParser::Token::String)
626 {
627 key.swap(value);
628 token = GetToken(value);
629 if (token == JSONParser::Token::Colon)
630 {
631 JSONValue::SP value_sp = ParseJSONValue();
632 if (value_sp)
633 dict_up->SetObject(key, value_sp);
634 else
635 break;
636 }
637 }
638 else if (token == JSONParser::Token::ObjectEnd)
639 {
640 return JSONValue::SP(dict_up.release());
641 }
642 else if (token == JSONParser::Token::Comma)
643 {
644 continue;
645 }
646 else
647 {
648 break;
649 }
650 }
651 return JSONValue::SP();
652}
653
654JSONValue::SP
655JSONParser::ParseJSONArray ()
656{
657 // The "JSONParser::Token::ObjectStart" token should have already been consumed
658 // by the time this function is called
659 std::unique_ptr<JSONArray> array_up(new JSONArray());
660
661 std::string value;
662 std::string key;
663 while (1)
664 {
665 JSONValue::SP value_sp = ParseJSONValue();
666 if (value_sp)
667 array_up->AppendObject(value_sp);
668 else
669 break;
670
671 JSONParser::Token token = GetToken(value);
672 if (token == JSONParser::Token::Comma)
673 {
674 continue;
675 }
676 else if (token == JSONParser::Token::ArrayEnd)
677 {
678 return JSONValue::SP(array_up.release());
679 }
680 else
681 {
682 break;
683 }
684 }
685 return JSONValue::SP();
686}
687
688JSONValue::SP
689JSONParser::ParseJSONValue ()
690{
691 std::string value;
692 const JSONParser::Token token = GetToken(value);
693 switch (token)
694 {
695 case JSONParser::Token::ObjectStart:
696 return ParseJSONObject();
697
698 case JSONParser::Token::ArrayStart:
699 return ParseJSONArray();
700
701 case JSONParser::Token::Integer:
702 {
703 if (value.front() == '-')
704 {
705 bool success = false;
706 int64_t sval = StringConvert::ToSInt64(value.c_str(), 0, 0, &success);
707 if (success)
708 return JSONValue::SP(new JSONNumber(sval));
709 }
710 else
711 {
712 bool success = false;
713 uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success);
714 if (success)
715 return JSONValue::SP(new JSONNumber(uval));
716 }
717 }
718 break;
719
720 case JSONParser::Token::Float:
721 {
722 bool success = false;
723 double val = StringConvert::ToDouble(value.c_str(), 0.0, &success);
724 if (success)
725 return JSONValue::SP(new JSONNumber(val));
726 }
727 break;
728
729 case JSONParser::Token::String:
730 return JSONValue::SP(new JSONString(value));
731
732 case JSONParser::Token::True:
733 return JSONValue::SP(new JSONTrue());
734
735 case JSONParser::Token::False:
736 return JSONValue::SP(new JSONFalse());
737
738 case JSONParser::Token::Null:
739 return JSONValue::SP(new JSONNull());
740
741 default:
742 break;
743 }
744 return JSONValue::SP();
745
746}