Coverage Report

Created: 2024-02-11 06:25

/src/poco/JSON/src/ParserImpl.cpp
Line
Count
Source (jump to first uncovered line)
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
typedef struct json_stream json_stream;
31
32
33
namespace Poco {
34
namespace JSON {
35
36
37
extern "C"
38
{
39
  static int istream_get(void* ptr)
40
0
  {
41
0
    std::streambuf* pBuf = reinterpret_cast<std::streambuf*>(ptr);
42
0
    return pBuf->sbumpc();
43
0
  }
44
45
  static int istream_peek(void* ptr)
46
0
  {
47
0
    std::streambuf* pBuf = reinterpret_cast<std::streambuf*>(ptr);
48
0
    return pBuf->sgetc();
49
0
  }
50
}
51
52
53
ParserImpl::ParserImpl(const Handler::Ptr& pHandler):
54
  _pJSON(new json_stream),
55
  _pHandler(pHandler),
56
  _depth(JSON_DEFAULT_DEPTH),
57
  _decimalPoint('.'),
58
  _allowNullByte(true),
59
  _allowComments(false)
60
6.24k
{
61
6.24k
}
62
63
64
ParserImpl::~ParserImpl()
65
6.24k
{
66
6.24k
  delete _pJSON;
67
6.24k
}
68
69
70
void ParserImpl::handle(const std::string& json)
71
6.24k
{
72
6.24k
  if (!_allowNullByte && json.find("\\u0000") != json.npos)
73
0
    throw JSONException("Null bytes in strings not allowed.");
74
75
6.24k
  try
76
6.24k
  {
77
6.24k
    json_open_buffer(_pJSON, json.data(), json.size());
78
6.24k
    checkError();
79
    //////////////////////////////////
80
    // Underlying parser is capable of parsing multiple consecutive JSONs;
81
    // we do not currently support this feature; to force error on
82
    // excessive characters past valid JSON end, this MUST be called
83
    // AFTER opening the buffer - otherwise it is overwritten by
84
    // json_open*() call, which calls internal init()
85
6.24k
    json_set_streaming(_pJSON, false);
86
    /////////////////////////////////
87
6.24k
    handle();
88
6.24k
    checkError();
89
6.24k
    if (JSON_DONE != json_next(_pJSON))
90
19
      throw JSONException("Excess characters found after JSON end.");
91
6.22k
    json_close(_pJSON);
92
6.22k
  }
93
6.24k
  catch (...)
94
6.24k
  {
95
6.16k
    json_close(_pJSON);
96
6.16k
    throw;
97
6.16k
  }
98
6.24k
}
99
100
101
void ParserImpl::handle(std::istream& json)
102
0
{
103
0
  try
104
0
  {
105
0
    json_open_user(_pJSON, istream_get, istream_peek, json.rdbuf());
106
0
    checkError();
107
0
    json_set_streaming(_pJSON, false);
108
0
    handle();
109
0
    checkError();
110
0
    if (JSON_DONE != json_next(_pJSON))
111
0
      throw JSONException("Excess characters found after JSON end.");
112
0
    json_close(_pJSON);
113
0
  }
114
0
  catch (...)
115
0
  {
116
0
    json_close(_pJSON);
117
0
    throw;
118
0
  }
119
0
}
120
121
122
Dynamic::Var ParserImpl::parseImpl(const std::string& json)
123
6.24k
{
124
6.24k
  if (_allowComments)
125
0
  {
126
0
    std::string str = json;
127
0
    stripComments(str);
128
0
    handle(str);
129
0
  }
130
6.24k
  else
131
6.24k
  {
132
6.24k
    handle(json);
133
6.24k
  }
134
135
6.24k
  return asVarImpl();
136
6.24k
}
137
138
139
Dynamic::Var ParserImpl::parseImpl(std::istream& json)
140
0
{
141
0
  if (_allowComments || !_allowNullByte)
142
0
  {
143
0
    std::string str;
144
0
    Poco::StreamCopier::copyToString(json, str);
145
0
    if (_allowComments)
146
0
    {
147
0
      stripComments(str);
148
0
    }
149
0
    handle(str);
150
0
  }
151
0
  else
152
0
  {
153
0
    handle(json);
154
0
  }
155
156
0
  return asVarImpl();
157
0
}
158
159
160
void ParserImpl::stripComments(std::string& json)
161
0
{
162
0
  if (_allowComments)
163
0
  {
164
0
    bool inString = false;
165
0
    bool inComment = false;
166
0
    char prevChar = 0;
167
0
    std::string::iterator it = json.begin();
168
0
    for (; it != json.end();)
169
0
    {
170
0
      if (*it == '"' && !inString) inString = true;
171
0
      else inString = false;
172
0
      if (!inString)
173
0
      {
174
0
        if (*it == '/' && it + 1 != json.end() && *(it + 1) == '*')
175
0
          inComment = true;
176
0
      }
177
0
      if (inComment)
178
0
      {
179
0
        char c = *it;
180
0
        it = json.erase(it);
181
0
        if (prevChar == '*' && c == '/')
182
0
        {
183
0
          inComment = false;
184
0
          prevChar = 0;
185
0
        }
186
0
        else prevChar = c;
187
0
      }
188
0
      else ++it;
189
0
    }
190
0
  }
191
0
}
192
193
194
void ParserImpl::handleArray()
195
30.3k
{
196
30.3k
  if (json_get_depth(_pJSON) > _depth)
197
8
    throw JSONException("Maximum depth exceeded");
198
199
30.3k
  json_type tok = json_peek(_pJSON);
200
1.93M
  while (tok != JSON_ARRAY_END && checkError())
201
1.90M
  {
202
1.90M
    handle();
203
1.90M
    tok = json_peek(_pJSON);
204
1.90M
  }
205
206
30.3k
  if (tok == JSON_ARRAY_END)
207
19.3k
  {
208
19.3k
    handle();
209
19.3k
  }
210
11.0k
  else throw JSONException("JSON array end not found");
211
30.3k
}
212
213
214
void ParserImpl::handleObject()
215
28.1k
{
216
28.1k
  if (json_get_depth(_pJSON) > _depth)
217
8
    throw JSONException("Maximum depth exceeded");
218
219
28.1k
  json_type tok = json_peek(_pJSON);
220
198k
  while (tok != JSON_OBJECT_END && checkError())
221
170k
  {
222
170k
    json_next(_pJSON);
223
170k
    if (_pHandler) _pHandler->key(std::string(json_get_string(_pJSON, NULL)));
224
170k
    handle();
225
170k
    tok = json_peek(_pJSON);
226
170k
  }
227
228
28.1k
  if (tok == JSON_OBJECT_END)
229
23.8k
  {
230
23.8k
    handle();
231
23.8k
  }
232
4.30k
  else throw JSONException("JSON object end not found");
233
28.1k
}
234
235
236
void ParserImpl::handle()
237
2.12M
{
238
2.12M
  enum json_type type = json_next(_pJSON);
239
2.12M
  switch (type)
240
2.12M
  {
241
0
  case JSON_DONE:
242
0
    return;
243
990
  case JSON_NULL:
244
990
    _pHandler->null();
245
990
    break;
246
262
  case JSON_TRUE:
247
262
    if (_pHandler) _pHandler->value(true);
248
262
    break;
249
194
  case JSON_FALSE:
250
194
    if (_pHandler) _pHandler->value(false);
251
194
    break;
252
2.01M
  case JSON_NUMBER:
253
2.01M
    if (_pHandler)
254
2.01M
    {
255
2.01M
      std::string str(json_get_string(_pJSON, NULL));
256
2.01M
      if (str.find(_decimalPoint) != str.npos || str.find('e') != str.npos || str.find('E') != str.npos)
257
13.9k
      {
258
13.9k
        _pHandler->value(NumberParser::parseFloat(str));
259
13.9k
      }
260
2.00M
      else
261
2.00M
      {
262
2.00M
        Poco::Int64 val;
263
2.00M
        if (NumberParser::tryParse64(str, val))
264
2.00M
          _pHandler->value(val);
265
925
        else
266
925
          _pHandler->value(NumberParser::parseUnsigned64(str));
267
2.00M
      }
268
2.01M
    }
269
2.01M
    break;
270
1.20k
  case JSON_STRING:
271
1.20k
    if (_pHandler)
272
1.20k
    {
273
1.20k
      std::size_t length = 0;
274
1.20k
      const char* val = json_get_string(_pJSON, &length);
275
1.20k
      _pHandler->value(std::string(val, length == 0 ? 0 : length - 1)); // Decrease the length by 1 because it also contains the terminating null character
276
1.20k
    }
277
1.20k
    break;
278
28.1k
  case JSON_OBJECT:
279
28.1k
    if (_pHandler) _pHandler->startObject();
280
28.1k
    handleObject();
281
28.1k
    break;
282
23.8k
  case JSON_OBJECT_END:
283
23.8k
    if (_pHandler) _pHandler->endObject();
284
23.8k
    return;
285
30.3k
  case JSON_ARRAY:
286
30.3k
    if (_pHandler) _pHandler->startArray();
287
30.3k
    handleArray();
288
30.3k
    break;
289
19.3k
  case JSON_ARRAY_END:
290
19.3k
    if (_pHandler) _pHandler->endArray();
291
19.3k
    return;
292
1.89k
  case JSON_ERROR:
293
1.89k
    {
294
1.89k
      const char* pErr = json_get_error(_pJSON);
295
1.89k
      std::string err(pErr ? pErr : "JSON parser error.");
296
1.89k
      throw JSONException(err);
297
0
    }
298
2.12M
  }
299
2.12M
}
300
301
302
bool ParserImpl::checkError()
303
2.08M
{
304
2.08M
  const char* err = json_get_error(_pJSON);
305
2.08M
  if (err) throw Poco::JSON::JSONException(err);
306
2.08M
  return true;
307
2.08M
}
308
309
310
} } // namespace Poco::JSON