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 | |
30 | namespace Poco { |
31 | namespace JSON { |
32 | |
33 | |
34 | ParserImpl::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 | |
45 | ParserImpl::~ParserImpl() |
46 | { |
47 | delete _pJSON; |
48 | } |
49 | |
50 | |
51 | void 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 | |
81 | Dynamic::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 | |
95 | Dynamic::Var ParserImpl::parseImpl(std::istream& in) |
96 | { |
97 | std::ostringstream os; |
98 | StreamCopier::copyStream(in, os); |
99 | return parseImpl(os.str()); |
100 | } |
101 | |
102 | |
103 | void ParserImpl::(std::string& json) |
104 | { |
105 | if (_allowComments) |
106 | { |
107 | bool inString = false; |
108 | bool = 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 | |
137 | void 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 | |
151 | void 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 | |
167 | void 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 | |
230 | bool 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 | |