1//
2// Parser.cpp
3//
4// Library: JSON
5// Package: JSON
6// Module: Parser
7//
8// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/JSON/Parser.h"
16#include "Poco/JSON/JSONException.h"
17#include "Poco/Ascii.h"
18#include "Poco/Token.h"
19#include "Poco/UTF8Encoding.h"
20#include "Poco/String.h"
21#include "Poco/StreamCopier.h"
22#undef min
23#undef max
24#include <limits>
25#include <clocale>
26#include <istream>
27extern "C" {
28#include "pd_json.h"
29}
30
31
32namespace Poco {
33namespace JSON {
34
35
36ParserImpl::ParserImpl(const Handler::Ptr& pHandler, std::size_t bufSize):
37 _pJSON(new json_stream),
38 _pHandler(pHandler),
39 _depth(JSON_UNLIMITED_DEPTH),
40 _decimalPoint('.'),
41 _allowNullByte(true),
42 _allowComments(false)
43{
44}
45
46
47ParserImpl::~ParserImpl()
48{
49 delete _pJSON;
50}
51
52
53void ParserImpl::handle(const std::string& json)
54{
55 if (!_allowNullByte && json.find("\\u0000") != json.npos)
56 throw JSONException("Null bytes in strings not allowed.");
57
58 try
59 {
60 json_open_buffer(_pJSON, json.data(), json.size());
61 checkError();
62 //////////////////////////////////
63 // Underlying parser is capable of parsing multiple consecutive JSONs;
64 // we do not currently support this feature; to force error on
65 // excessive characters past valid JSON end, this MUST be called
66 // AFTER opening the buffer - otherwise it is overwritten by
67 // json_open*() call, which calls internal init()
68 json_set_streaming(_pJSON, false);
69 /////////////////////////////////
70 handle(); checkError();
71 if (JSON_DONE != json_next(_pJSON))
72 throw JSONException("Excess characters found after JSON end.");
73 json_close(_pJSON);
74 }
75 catch (std::exception&)
76 {
77 json_close(_pJSON);
78 throw;
79 }
80}
81
82
83Dynamic::Var ParserImpl::parseImpl(const std::string& json)
84{
85 if (_allowComments)
86 {
87 std::string str = json;
88 stripComments(str);
89 handle(str);
90 }
91 else handle(json);
92
93 return asVarImpl();
94}
95
96
97Dynamic::Var ParserImpl::parseImpl(std::istream& in)
98{
99 std::ostringstream os;
100 StreamCopier::copyStream(in, os);
101 return parseImpl(os.str());
102}
103
104
105void ParserImpl::stripComments(std::string& json)
106{
107 if (_allowComments)
108 {
109 bool inString = false;
110 bool inComment = false;
111 char prevChar = 0;
112 std::string::iterator it = json.begin();
113 for (; it != json.end();)
114 {
115 if (*it == '"' && !inString) inString = true;
116 else inString = false;
117 if (!inString)
118 {
119 if (*it == '/' && it + 1 != json.end() && *(it + 1) == '*')
120 inComment = true;
121 }
122 if (inComment)
123 {
124 char c = *it;
125 it = json.erase(it);
126 if (prevChar == '*' && c == '/')
127 {
128 inComment = false;
129 prevChar = 0;
130 }
131 else prevChar = c;
132 }
133 else ++it;
134 }
135 }
136}
137
138
139void ParserImpl::handleArray()
140{
141 json_type tok = json_peek(_pJSON);
142 while (tok != JSON_ARRAY_END && checkError())
143 {
144 handle();
145 tok = json_peek(_pJSON);
146 }
147
148 if (tok == JSON_ARRAY_END) handle();
149 else throw JSONException("JSON array end not found");
150}
151
152
153void ParserImpl::handleObject()
154{
155 json_type tok = json_peek(_pJSON);
156 while (tok != JSON_OBJECT_END && checkError())
157 {
158 json_next(_pJSON);
159 if (_pHandler) _pHandler->key(std::string(json_get_string(_pJSON, NULL)));
160 handle();
161 tok = json_peek(_pJSON);
162 }
163
164 if (tok == JSON_OBJECT_END) handle();
165 else throw JSONException("JSON object end not found");
166}
167
168
169void ParserImpl::handle()
170{
171 enum json_type type = json_next(_pJSON);
172 switch (type)
173 {
174 case JSON_DONE:
175 return;
176 case JSON_NULL:
177 _pHandler->null();
178 break;
179 case JSON_TRUE:
180 if (_pHandler) _pHandler->value(true);
181 break;
182 case JSON_FALSE:
183 if (_pHandler) _pHandler->value(false);
184 break;
185 case JSON_NUMBER:
186 {
187 if (_pHandler)
188 {
189 std::string str(json_get_string(_pJSON, NULL));
190 if (str.find(_decimalPoint) != str.npos || str.find('e') != str.npos || str.find('E') != str.npos)
191 {
192 _pHandler->value(NumberParser::parseFloat(str));
193 }
194 else
195 {
196 Poco::Int64 val;
197 if (NumberParser::tryParse64(str, val))
198 _pHandler->value(val);
199 else
200 _pHandler->value(NumberParser::parseUnsigned64(str));
201 }
202 }
203 break;
204 }
205 case JSON_STRING:
206 if (_pHandler) _pHandler->value(std::string(json_get_string(_pJSON, NULL)));
207 break;
208 case JSON_OBJECT:
209 if (_pHandler) _pHandler->startObject();
210 handleObject();
211 break;
212 case JSON_OBJECT_END:
213 if (_pHandler) _pHandler->endObject();
214 return;
215 case JSON_ARRAY:
216 if (_pHandler) _pHandler->startArray();
217 handleArray();
218 break;
219 case JSON_ARRAY_END:
220 if (_pHandler) _pHandler->endArray();
221 return;
222 case JSON_ERROR:
223 {
224 const char* pErr = json_get_error(_pJSON);
225 std::string err(pErr ? pErr : "JSON parser error.");
226 throw JSONException(err);
227 }
228 }
229}
230
231
232bool ParserImpl::checkError()
233{
234 const char* err = json_get_error(_pJSON);
235 if (err) throw Poco::JSON::JSONException(err);
236 return true;
237}
238
239
240
241} } // namespace Poco::JSON
242