Coverage Report

Created: 2026-02-09 06:05

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