Coverage Report

Created: 2025-12-05 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/jsoncpp/include/json/reader.h
Line
Count
Source
1
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
2
// Distributed under MIT license, or public domain if desired and
3
// recognized in your jurisdiction.
4
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
5
6
#ifndef JSON_READER_H_INCLUDED
7
#define JSON_READER_H_INCLUDED
8
9
#if !defined(JSON_IS_AMALGAMATION)
10
#include "json_features.h"
11
#include "value.h"
12
#endif // if !defined(JSON_IS_AMALGAMATION)
13
#include <deque>
14
#include <iosfwd>
15
#include <istream>
16
#include <stack>
17
#include <string>
18
19
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
20
// be used by...
21
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
22
#pragma warning(push)
23
#pragma warning(disable : 4251)
24
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
25
26
#pragma pack(push)
27
#pragma pack()
28
29
namespace Json {
30
31
/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a
32
 * Value.
33
 *
34
 * \deprecated Use CharReader and CharReaderBuilder.
35
 */
36
37
class JSON_API Reader {
38
public:
39
  using Char = char;
40
  using Location = const Char*;
41
42
  /** \brief An error tagged with where in the JSON text it was encountered.
43
   *
44
   * The offsets give the [start, limit) range of bytes within the text. Note
45
   * that this is bytes, not codepoints.
46
   */
47
  struct StructuredError {
48
    ptrdiff_t offset_start;
49
    ptrdiff_t offset_limit;
50
    String message;
51
  };
52
53
  /** \brief Constructs a Reader allowing all features for parsing.
54
   * \deprecated Use CharReader and CharReaderBuilder.
55
   */
56
  Reader();
57
58
  /** \brief Constructs a Reader allowing the specified feature set for parsing.
59
   * \deprecated Use CharReader and CharReaderBuilder.
60
   */
61
  Reader(const Features& features);
62
63
  /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
64
   * document.
65
   *
66
   * \param      document        UTF-8 encoded string containing the document
67
   *                             to read.
68
   * \param[out] root            Contains the root value of the document if it
69
   *                             was successfully parsed.
70
   * \param      collectComments \c true to collect comment and allow writing
71
   *                             them back during serialization, \c false to
72
   *                             discard comments.  This parameter is ignored
73
   *                             if Features::allowComments_ is \c false.
74
   * \return \c true if the document was successfully parsed, \c false if an
75
   * error occurred.
76
   */
77
  bool parse(const std::string& document, Value& root,
78
             bool collectComments = true);
79
80
  /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
81
   * document.
82
   *
83
   * \param      beginDoc        Pointer on the beginning of the UTF-8 encoded
84
   *                             string of the document to read.
85
   * \param      endDoc          Pointer on the end of the UTF-8 encoded string
86
   *                             of the document to read.  Must be >= beginDoc.
87
   * \param[out] root            Contains the root value of the document if it
88
   *                             was successfully parsed.
89
   * \param      collectComments \c true to collect comment and allow writing
90
   *                             them back during serialization, \c false to
91
   *                             discard comments.  This parameter is ignored
92
   *                             if Features::allowComments_ is \c false.
93
   * \return \c true if the document was successfully parsed, \c false if an
94
   * error occurred.
95
   */
96
  bool parse(const char* beginDoc, const char* endDoc, Value& root,
97
             bool collectComments = true);
98
99
  /// \brief Parse from input stream.
100
  /// \see Json::operator>>(std::istream&, Json::Value&).
101
  bool parse(IStream& is, Value& root, bool collectComments = true);
102
103
  /** \brief Returns a user friendly string that list errors in the parsed
104
   * document.
105
   *
106
   * \return Formatted error message with the list of errors with their
107
   * location in the parsed document. An empty string is returned if no error
108
   * occurred during parsing.
109
   * \deprecated Use getFormattedErrorMessages() instead (typo fix).
110
   */
111
  JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.")
112
  String getFormatedErrorMessages() const;
113
114
  /** \brief Returns a user friendly string that list errors in the parsed
115
   * document.
116
   *
117
   * \return Formatted error message with the list of errors with their
118
   * location in the parsed document. An empty string is returned if no error
119
   * occurred during parsing.
120
   */
121
  String getFormattedErrorMessages() const;
122
123
  /** \brief Returns a vector of structured errors encountered while parsing.
124
   *
125
   * \return A (possibly empty) vector of StructuredError objects. Currently
126
   * only one error can be returned, but the caller should tolerate multiple
127
   * errors.  This can occur if the parser recovers from a non-fatal parse
128
   * error and then encounters additional errors.
129
   */
130
  std::vector<StructuredError> getStructuredErrors() const;
131
132
  /** \brief Add a semantic error message.
133
   *
134
   * \param value   JSON Value location associated with the error
135
   * \param message The error message.
136
   * \return \c true if the error was successfully added, \c false if the Value
137
   * offset exceeds the document size.
138
   */
139
  bool pushError(const Value& value, const String& message);
140
141
  /** \brief Add a semantic error message with extra context.
142
   *
143
   * \param value   JSON Value location associated with the error
144
   * \param message The error message.
145
   * \param extra   Additional JSON Value location to contextualize the error
146
   * \return \c true if the error was successfully added, \c false if either
147
   * Value offset exceeds the document size.
148
   */
149
  bool pushError(const Value& value, const String& message, const Value& extra);
150
151
  /** \brief Return whether there are any errors.
152
   *
153
   * \return \c true if there are no errors to report \c false if errors have
154
   * occurred.
155
   */
156
  bool good() const;
157
158
private:
159
  enum TokenType {
160
    tokenEndOfStream = 0,
161
    tokenObjectBegin,
162
    tokenObjectEnd,
163
    tokenArrayBegin,
164
    tokenArrayEnd,
165
    tokenString,
166
    tokenNumber,
167
    tokenTrue,
168
    tokenFalse,
169
    tokenNull,
170
    tokenArraySeparator,
171
    tokenMemberSeparator,
172
    tokenComment,
173
    tokenError
174
  };
175
176
  class Token {
177
  public:
178
    TokenType type_;
179
    Location start_;
180
    Location end_;
181
  };
182
183
  class ErrorInfo {
184
  public:
185
    Token token_;
186
    String message_;
187
    Location extra_;
188
  };
189
190
  using Errors = std::deque<ErrorInfo>;
191
192
  bool readToken(Token& token);
193
  bool readTokenSkippingComments(Token& token);
194
  void skipSpaces();
195
  bool match(const Char* pattern, int patternLength);
196
  bool readComment();
197
  bool readCStyleComment();
198
  bool readCppStyleComment();
199
  bool readString();
200
  void readNumber();
201
  bool readValue();
202
  bool readObject(Token& token);
203
  bool readArray(Token& token);
204
  bool decodeNumber(Token& token);
205
  bool decodeNumber(Token& token, Value& decoded);
206
  bool decodeString(Token& token);
207
  bool decodeString(Token& token, String& decoded);
208
  bool decodeDouble(Token& token);
209
  bool decodeDouble(Token& token, Value& decoded);
210
  bool decodeUnicodeCodePoint(Token& token, Location& current, Location end,
211
                              unsigned int& unicode);
212
  bool decodeUnicodeEscapeSequence(Token& token, Location& current,
213
                                   Location end, unsigned int& unicode);
214
  bool addError(const String& message, Token& token, Location extra = nullptr);
215
  bool recoverFromError(TokenType skipUntilToken);
216
  bool addErrorAndRecover(const String& message, Token& token,
217
                          TokenType skipUntilToken);
218
  void skipUntilSpace();
219
  Value& currentValue();
220
  Char getNextChar();
221
  void getLocationLineAndColumn(Location location, int& line,
222
                                int& column) const;
223
  String getLocationLineAndColumn(Location location) const;
224
  void addComment(Location begin, Location end, CommentPlacement placement);
225
226
  static bool containsNewLine(Location begin, Location end);
227
  static String normalizeEOL(Location begin, Location end);
228
229
  using Nodes = std::stack<Value*>;
230
  Nodes nodes_;
231
  Errors errors_;
232
  String document_;
233
  Location begin_{};
234
  Location end_{};
235
  Location current_{};
236
  Location lastValueEnd_{};
237
  Value* lastValue_{};
238
  String commentsBefore_;
239
  Features features_;
240
  bool collectComments_{};
241
}; // Reader
242
243
/** Interface for reading JSON from a char array.
244
 */
245
class JSON_API CharReader {
246
public:
247
  struct JSON_API StructuredError {
248
    ptrdiff_t offset_start;
249
    ptrdiff_t offset_limit;
250
    String message;
251
  };
252
253
5.94k
  virtual ~CharReader() = default;
254
  /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
255
   * document. The document must be a UTF-8 encoded string containing the
256
   * document to read.
257
   *
258
   * \param      beginDoc Pointer on the beginning of the UTF-8 encoded string
259
   *                      of the document to read.
260
   * \param      endDoc   Pointer on the end of the UTF-8 encoded string of the
261
   *                      document to read. Must be >= beginDoc.
262
   * \param[out] root     Contains the root value of the document if it was
263
   *                      successfully parsed.
264
   * \param[out] errs     Formatted error messages (if not NULL) a user
265
   *                      friendly string that lists errors in the parsed
266
   *                      document.
267
   * \return \c true if the document was successfully parsed, \c false if an
268
   * error occurred.
269
   */
270
  virtual bool parse(char const* beginDoc, char const* endDoc, Value* root,
271
                     String* errs);
272
273
  /** \brief Returns a vector of structured errors encountered while parsing.
274
   * Each parse call resets the stored list of errors.
275
   */
276
  std::vector<StructuredError> getStructuredErrors() const;
277
278
  class JSON_API Factory {
279
  public:
280
5.94k
    virtual ~Factory() = default;
281
    /** \brief Allocate a CharReader via operator new().
282
     * \throw std::exception if something goes wrong (e.g. invalid settings)
283
     */
284
    virtual CharReader* newCharReader() const = 0;
285
  }; // Factory
286
287
protected:
288
  class Impl {
289
  public:
290
5.94k
    virtual ~Impl() = default;
291
    virtual bool parse(char const* beginDoc, char const* endDoc, Value* root,
292
                       String* errs) = 0;
293
    virtual std::vector<StructuredError> getStructuredErrors() const = 0;
294
  };
295
296
5.94k
  explicit CharReader(std::unique_ptr<Impl> impl) : _impl(std::move(impl)) {}
297
298
private:
299
  std::unique_ptr<Impl> _impl;
300
}; // CharReader
301
302
/** \brief Build a CharReader implementation.
303
 *
304
 * Usage:
305
 *   \code
306
 *   using namespace Json;
307
 *   CharReaderBuilder builder;
308
 *   builder["collectComments"] = false;
309
 *   Value value;
310
 *   String errs;
311
 *   bool ok = parseFromStream(builder, std::cin, &value, &errs);
312
 *   \endcode
313
 */
314
class JSON_API CharReaderBuilder : public CharReader::Factory {
315
public:
316
  // Note: We use a Json::Value so that we can add data-members to this class
317
  // without a major version bump.
318
  /** Configuration of this builder.
319
   * These are case-sensitive.
320
   * Available settings (case-sensitive):
321
   * - `"collectComments": false or true`
322
   *   - true to collect comment and allow writing them back during
323
   *     serialization, false to discard comments.  This parameter is ignored
324
   *     if allowComments is false.
325
   * - `"allowComments": false or true`
326
   *   - true if comments are allowed.
327
   * - `"allowTrailingCommas": false or true`
328
   *   - true if trailing commas in objects and arrays are allowed.
329
   * - `"strictRoot": false or true`
330
   *   - true if root must be either an array or an object value
331
   * - `"allowDroppedNullPlaceholders": false or true`
332
   *   - true if dropped null placeholders are allowed. (See
333
   *     StreamWriterBuilder.)
334
   * - `"allowNumericKeys": false or true`
335
   *   - true if numeric object keys are allowed.
336
   * - `"allowSingleQuotes": false or true`
337
   *   - true if '' are allowed for strings (both keys and values)
338
   * - `"stackLimit": integer`
339
   *   - Exceeding stackLimit (recursive depth of `readValue()`) will cause an
340
   *     exception.
341
   *   - This is a security issue (seg-faults caused by deeply nested JSON), so
342
   *     the default is low.
343
   * - `"failIfExtra": false or true`
344
   *   - If true, `parse()` returns false when extra non-whitespace trails the
345
   *     JSON value in the input string.
346
   * - `"rejectDupKeys": false or true`
347
   *   - If true, `parse()` returns false when a key is duplicated within an
348
   *     object.
349
   * - `"allowSpecialFloats": false or true`
350
   *   - If true, special float values (NaNs and infinities) are allowed and
351
   *     their values are lossfree restorable.
352
   * - `"skipBom": false or true`
353
   *   - If true, if the input starts with the Unicode byte order mark (BOM),
354
   *     it is skipped.
355
   *
356
   * You can examine 'settings_` yourself to see the defaults. You can also
357
   * write and read them just like any JSON Value.
358
   * \sa setDefaults()
359
   */
360
  Json::Value settings_;
361
362
  CharReaderBuilder();
363
  ~CharReaderBuilder() override;
364
365
  CharReader* newCharReader() const override;
366
367
  /** \return true if 'settings' are legal and consistent;
368
   *   otherwise, indicate bad settings via 'invalid'.
369
   */
370
  bool validate(Json::Value* invalid) const;
371
372
  /** A simple way to update a specific setting.
373
   */
374
  Value& operator[](const String& key);
375
376
  /** Called by ctor, but you can use this to reset settings_.
377
   * \pre 'settings' != NULL (but Json::null is fine)
378
   * \remark Defaults:
379
   * \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults
380
   */
381
  static void setDefaults(Json::Value* settings);
382
  /** Same as old Features::strictMode().
383
   * \pre 'settings' != NULL (but Json::null is fine)
384
   * \remark Defaults:
385
   * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode
386
   */
387
  static void strictMode(Json::Value* settings);
388
  /** ECMA-404 mode.
389
   * \pre 'settings' != NULL (but Json::null is fine)
390
   * \remark Defaults:
391
   * \snippet src/lib_json/json_reader.cpp CharReaderBuilderECMA404Mode
392
   */
393
  static void ecma404Mode(Json::Value* settings);
394
};
395
396
/** Consume entire stream and use its begin/end.
397
 * Someday we might have a real StreamReader, but for now this
398
 * is convenient.
399
 */
400
bool JSON_API parseFromStream(CharReader::Factory const&, IStream&, Value* root,
401
                              String* errs);
402
403
/** \brief Read from 'sin' into 'root'.
404
 *
405
 * Always keep comments from the input JSON.
406
 *
407
 * This can be used to read a file into a particular sub-object.
408
 * For example:
409
 *   \code
410
 *   Json::Value root;
411
 *   cin >> root["dir"]["file"];
412
 *   cout << root;
413
 *   \endcode
414
 * Result:
415
 * \verbatim
416
 * {
417
 * "dir": {
418
 *    "file": {
419
 *    // The input stream JSON would be nested here.
420
 *    }
421
 * }
422
 * }
423
 * \endverbatim
424
 * \throw std::exception on parse error.
425
 * \see Json::operator<<()
426
 */
427
JSON_API IStream& operator>>(IStream&, Value&);
428
429
} // namespace Json
430
431
#pragma pack(pop)
432
433
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
434
#pragma warning(pop)
435
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
436
437
#endif // JSON_READER_H_INCLUDED