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