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