Arcane  4.2.2.0
User documentation
Loading...
Searching...
No Matches
JSONReader.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* JSONReader.cc (C) 2000-2026 */
9/* */
10/* JSON format reader. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arccore/common/JSONReader.h"
15
16#include "arccore/base/FatalErrorException.h"
17#include "arccore/base/CheckedConvert.h"
18#include "arccore/base/internal/ConvertInternal.h"
19
20#define RAPIDJSON_HAS_STDSTRING 1
21#include "arccore/common/internal/json/rapidjson/document.h"
22#include "arccore/common/internal/json/rapidjson/stringbuffer.h"
23
24#include <iostream>
25
26/*---------------------------------------------------------------------------*/
27/*---------------------------------------------------------------------------*/
28
29namespace Arcane
30{
31
32/*---------------------------------------------------------------------------*/
33/*---------------------------------------------------------------------------*/
34
36{
37 public:
38
39 rapidjson::Value::Member* toMember() const
40 {
41 return (rapidjson::Value::Member*)(this);
42 }
43};
44
46{
47 public:
48
49 rapidjson::Value* toValue() const
50 {
51 return (rapidjson::Value*)(this);
52 }
53};
54
56{
57 public:
58
59 static JSONKeyValue build(rapidjson::Value::Member* v)
60 {
61 return JSONKeyValue((JSONKeyValue::Impl*)(v));
62 }
63 static JSONKeyValue build(rapidjson::Value::ConstMemberIterator v)
64 {
65 return JSONKeyValue((JSONKeyValue::Impl*)&(*v));
66 }
67 static JSONValue build(rapidjson::Value* v)
68 {
69 return JSONValue((JSONValue::Impl*)(v));
70 }
71};
72
73/*
74 * Types defined by rapidjson.
75 enum Type {
76 kNullType = 0, //!< null
77 kFalseType = 1, //!< false
78 kTrueType = 2, //!< true
79 kObjectType = 3, //!< object
80 kArrayType = 4, //!< array
81 kStringType = 5, //!< string
82 kNumberType = 6 //!< number
83};
84*/
85
86/*---------------------------------------------------------------------------*/
87/*---------------------------------------------------------------------------*/
88
89StringView JSONKeyValue::
90name() const
91{
92 if (!m_p)
93 return StringView();
94 auto& x = m_p->toMember()->name;
95 if (x.IsString())
96 return StringView(Span<const Byte>((const Byte*)x.GetString(), x.GetStringLength()));
97 return StringView();
98}
99
100/*---------------------------------------------------------------------------*/
101/*---------------------------------------------------------------------------*/
102
103JSONValue JSONKeyValue::
104value() const
105{
106 if (!m_p)
107 return JSONValue();
108 auto& x = m_p->toMember()->value;
109 return JSONWrapperUtils::build(&x);
110}
111
112/*---------------------------------------------------------------------------*/
113/*---------------------------------------------------------------------------*/
114
116value() const
117{
118 if (!m_p)
119 return String();
120 auto x = m_p->toValue();
121 if (x->IsString())
122 return String(Span<const Byte>((const Byte*)x->GetString(), x->GetStringLength()));
123 return String();
124}
125
126/*---------------------------------------------------------------------------*/
127/*---------------------------------------------------------------------------*/
128
130valueAsStringView() const
131{
132 if (!m_p)
133 return StringView();
134 auto x = m_p->toValue();
135 if (x->IsString())
136 return StringView(Span<const Byte>((const Byte*)x->GetString(), x->GetStringLength()));
137 return StringView();
138}
139
140/*---------------------------------------------------------------------------*/
141/*---------------------------------------------------------------------------*/
142
143StringView JSONValue::
144valueAsString() const
145{
146 return valueAsStringView();
147}
148
149/*---------------------------------------------------------------------------*/
150/*---------------------------------------------------------------------------*/
151
153valueAsInt64() const
154{
155 if (!m_p)
156 return 0;
157 auto x = m_p->toValue();
158 if (x->IsInt64())
159 return x->GetInt64();
160 return 0;
161}
162
163/*---------------------------------------------------------------------------*/
164/*---------------------------------------------------------------------------*/
165
167valueAsBool() const
168{
169 if (!m_p)
170 return false;
171 auto x = m_p->toValue();
172 if (x->IsBool())
173 return x->GetBool();
174 return false;
175}
176
177/*---------------------------------------------------------------------------*/
178/*---------------------------------------------------------------------------*/
179
181valueAsInt32() const
182{
183 Int64 v = valueAsInt64();
184 return CheckedConvert::toInt32(v);
185}
186
187/*---------------------------------------------------------------------------*/
188/*---------------------------------------------------------------------------*/
189
191valueAsReal() const
192{
193 if (!m_p)
194 return 0;
195 auto x = m_p->toValue();
196 if (x->IsDouble())
197 return x->GetDouble();
198 if (x->GetType() == rapidjson::kStringType) {
199 // Convert the string into a real
200 StringView s = this->valueAsStringView();
201 Real r = 0.0;
202 if (!Convert::Impl::StringViewToIntegral::getValue(r, s))
203 return r;
204 }
205 return 0.0;
206}
207
209valueAsUInt64() const
210{
211 if (!m_p)
212 return 0;
213 auto x = m_p->toValue();
214 if (x->IsUint64())
215 return x->GetUint64();
216 return 0;
217}
218
219/*---------------------------------------------------------------------------*/
220/*---------------------------------------------------------------------------*/
221
222JSONKeyValue JSONValue::
223keyValueChild(StringView name) const
224{
225 if (!m_p)
226 return JSONKeyValue();
227 auto d = m_p->toValue();
228 rapidjson::Value::MemberIterator x = d->FindMember((const char*)(name.bytes().data()));
229 if (x == d->MemberEnd())
230 return JSONKeyValue();
231 return JSONWrapperUtils::build(x);
232}
233
234/*---------------------------------------------------------------------------*/
235/*---------------------------------------------------------------------------*/
236
237JSONValue JSONValue::
238child(StringView name) const
239{
240 return keyValueChild(name).value();
241}
242
243/*---------------------------------------------------------------------------*/
244/*---------------------------------------------------------------------------*/
245
246JSONValue JSONValue::
247expectedChild(StringView name) const
248{
249 JSONKeyValue k = keyValueChild(name);
250 if (!k)
251 ARCCORE_FATAL("No key '{0}' found in json document", name);
252 return k.value();
253}
254
255/*---------------------------------------------------------------------------*/
256/*---------------------------------------------------------------------------*/
257
258JSONValueList JSONValue::
259children() const
260{
261 if (!m_p)
262 return JSONValueList();
263 auto d = m_p->toValue();
264 JSONValueList values;
265 if (!d->IsObject())
266 ARCCORE_FATAL("The value has to be of type 'object'");
267 for (auto& x : d->GetObject()) {
268 auto y = JSONWrapperUtils::build(&x);
269 values.add(y.value());
270 }
271 return values;
272}
273
274/*---------------------------------------------------------------------------*/
275/*---------------------------------------------------------------------------*/
276
277JSONValueList JSONValue::
278valueAsArray() const
279{
280 if (!m_p)
281 return JSONValueList();
282 auto d = m_p->toValue();
283 JSONValueList values;
284 if (!d->IsArray())
285 ARCCORE_FATAL("The value has to be of type 'array'");
286 for (rapidjson::SizeType i = 0; i < d->Size(); ++i) {
287 rapidjson::Value& x = (*d)[i];
288 auto y = JSONWrapperUtils::build(&x);
289 values.add(y);
290 }
291 return values;
292}
293
294/*---------------------------------------------------------------------------*/
295/*---------------------------------------------------------------------------*/
296
297bool JSONValue::
298isArray() const
299{
300 if (!m_p)
301 return false;
302 auto d = m_p->toValue();
303 return d->IsArray();
304}
305
306/*---------------------------------------------------------------------------*/
307/*---------------------------------------------------------------------------*/
308
309bool JSONValue::
310isObject() const
311{
312 if (!m_p)
313 return false;
314 auto d = m_p->toValue();
315 return d->IsObject();
316}
317
318/*---------------------------------------------------------------------------*/
319/*---------------------------------------------------------------------------*/
320
321JSONKeyValueList JSONValue::
322keyValueChildren() const
323{
324 if (!m_p)
325 return JSONKeyValueList();
326 auto d = m_p->toValue();
327 JSONKeyValueList values;
328 for (auto& x : d->GetObject()) {
329 auto y = JSONWrapperUtils::build(&x);
330 values.add(y);
331 }
332 return values;
333}
334
336isNull() const
337{
338 if (!m_p)
339 return true;
340 return m_p->toValue()->IsNull();
341}
342
344isBool() const
345{
346 if (!m_p)
347 return false;
348 return m_p->toValue()->IsBool();
349}
350
352isString() const
353{
354 if (!m_p)
355 return false;
356 return m_p->toValue()->IsString();
357}
358
360isNumber() const
361{
362 if (!m_p)
363 return false;
364 return m_p->toValue()->IsNumber();
365}
366
368isInt64() const
369{
370 if (!m_p)
371 return false;
372 return m_p->toValue()->IsInt64();
373}
374
376isUint64() const
377{
378 if (!m_p)
379 return false;
380 return m_p->toValue()->IsUint64();
381}
382
383/*---------------------------------------------------------------------------*/
384/*---------------------------------------------------------------------------*/
385
386/*---------------------------------------------------------------------------*/
387/*---------------------------------------------------------------------------*/
388
390{
391 public:
392
393 Impl()
394 : m_document()
395 {
396 }
397
398 public:
399
400 rapidjson::Document m_document;
401};
402
403/*---------------------------------------------------------------------------*/
404/*---------------------------------------------------------------------------*/
405
406JSONDocument::
407JSONDocument()
408{
409 m_p = new Impl();
410}
411
412JSONDocument::
413~JSONDocument()
414{
415 delete m_p;
416}
417
418namespace
419{
420 using namespace rapidjson;
421
422 const char*
423 _getErrorCodeString(ParseErrorCode c)
424 {
425 switch (c) {
426 case kParseErrorNone:
427 return "No error";
428 case kParseErrorDocumentEmpty:
429 return "The document is empty";
430 case kParseErrorDocumentRootNotSingular:
431 return "The document root must not follow by other values";
432 case kParseErrorValueInvalid:
433 return "Invalid value";
434 case kParseErrorObjectMissName:
435 return "Missing a name for object member";
436 case kParseErrorObjectMissColon:
437 return "Missing a colon after a name of object member";
438 case kParseErrorObjectMissCommaOrCurlyBracket:
439 return "Missing a comma or '}' after an object member";
440 case kParseErrorArrayMissCommaOrSquareBracket:
441 return "Missing a comma or ']' after an array element";
442 case kParseErrorStringUnicodeEscapeInvalidHex:
443 return "Incorrect hex digit after \\u escape in string";
444 case kParseErrorStringUnicodeSurrogateInvalid:
445 return "The surrogate pair in string is invalid";
446 case kParseErrorStringEscapeInvalid:
447 return "Invalid escape character in string";
448 case kParseErrorStringMissQuotationMark:
449 return "Missing a closing quotation mark in string";
450 case kParseErrorStringInvalidEncoding:
451 return "Invalid encoding in string";
452 case kParseErrorNumberTooBig:
453 return "Number too big to be stored in double";
454 case kParseErrorNumberMissFraction:
455 return "Miss fraction part in number";
456 case kParseErrorNumberMissExponent:
457 return "Miss exponent in number";
458 case kParseErrorTermination:
459 return "Parsing was terminated";
460 case kParseErrorUnspecificSyntaxError:
461 return "Unspecific syntax error";
462 default:
463 return "Unknown";
464 }
465 return "Unknown";
466 }
467} // namespace
468
469/*---------------------------------------------------------------------------*/
470/*---------------------------------------------------------------------------*/
471
473parse(Span<const std::byte> bytes, StringView filename, Int16 flags)
474{
475 using namespace rapidjson;
476
477 Document& d = m_p->m_document;
478 ParseResult r;
479
480 switch (flags) {
481 case ParseNoFlags:
482 r = d.Parse<kParseNoFlags>(reinterpret_cast<const char*>(bytes.data()), bytes.size());
483 break;
485 r = d.Parse<kParseCommentsFlag>(reinterpret_cast<const char*>(bytes.data()), bytes.size());
486 break;
488 r = d.Parse<kParseNumbersAsStringsFlag>(reinterpret_cast<const char*>(bytes.data()), bytes.size());
489 break;
491 r = d.Parse<kParseCommentsFlag | kParseNumbersAsStringsFlag>(reinterpret_cast<const char*>(bytes.data()), bytes.size());
492 break;
493 default:
494 ARCCORE_FATAL("Unknown flags");
495 }
496
497 if (d.HasParseError()) {
498 std::cout << "ERROR: " << d.GetParseError() << "\n";
499 ARCCORE_FATAL("Parsing error file='{0}' ret={1} position={2} message='{3}'",
500 filename, d.GetParseError(),
501 r.Offset(), _getErrorCodeString(r.Code()));
502 }
503}
504
505/*---------------------------------------------------------------------------*/
506/*---------------------------------------------------------------------------*/
507
510{
511 parse(bytes, "(Unknown)", flags);
512}
513
514/*---------------------------------------------------------------------------*/
515/*---------------------------------------------------------------------------*/
516
518parse(Span<const Byte> bytes, Int16 flags)
519{
520 parse(asBytes(bytes), flags);
521}
522
523/*---------------------------------------------------------------------------*/
524/*---------------------------------------------------------------------------*/
525
527parse(Span<const Byte> bytes, StringView filename, Int16 flags)
528{
529 parse(asBytes(bytes), filename, flags);
530}
531
532/*---------------------------------------------------------------------------*/
533/*---------------------------------------------------------------------------*/
534
536root() const
537{
538 rapidjson::Value& d = m_p->m_document;
539 return JSONWrapperUtils::build(&d);
540}
541
542/*---------------------------------------------------------------------------*/
543/*---------------------------------------------------------------------------*/
544
545} // namespace Arcane
546
547/*---------------------------------------------------------------------------*/
548/*---------------------------------------------------------------------------*/
#define ARCCORE_FATAL(...)
Macro throwing a FatalErrorException.
void parse(Span< const Byte > bytes, Int16 flags=ParseNoFlags)
Reads the file in UTF-8 format.
@ ParseNumbersAsStringsFlag
Parse all numbers (ints/doubles) as strings.
@ ParseCommentsFlag
Allow one-line (//) and multi-line (/‍**/) comments.
JSONValue root() const
Root element.
List of (key,value) pairs of a JSON document.
String value() const
Value in String format. The returned string is null if 'null()' is true.
bool isUint64() const
True if the value is an integer in the 'UInt64' range.
UInt64 valueAsUInt64() const
Value in UInt64 format. Returns 0 if 'null()' is true.
Int32 valueAsInt32() const
Value in Int64 format. Returns 0 if 'null()' is true.
Real valueAsReal() const
Value in Real format. Returns 0.0 if 'null()' is true.
bool valueAsBool() const
Value in boolean format. Returns false if 'null()' is true.
Int64 valueAsInt64() const
Value in Int64 format. Returns 0 if 'null()' is true.
bool isInt64() const
True if the value is an integer in the 'Int64' range.
StringView valueAsStringView() const
Value in StringView format. The string is empty if 'null()' is true.
JSONValue expectedChild(StringView name) const
Child value with name name. Throws an exception if not found.
bool isBool() const
True if the value is a boolean.
bool isString() const
True if the value is a string.
bool isNull() const
True if the value is of 'null' type.
JSONValue child(StringView name) const
Child value with name name. Returns a null value if not found.
bool isNumber() const
True if the value is a number.
constexpr __host__ __device__ pointer data() const noexcept
Pointer to the start of the view.
Definition Span.h:537
constexpr __host__ __device__ SizeType size() const noexcept
Returns the size of the array.
Definition Span.h:325
View of an array of elements of type T.
Definition Span.h:633
View of a UTF-8 character string.
Definition StringView.h:44
constexpr Span< const Byte > bytes() const ARCCORE_NOEXCEPT
Returns the conversion of the instance in UTF-8 encoding.
Definition StringView.h:93
constexpr __host__ __device__ pointer data() const noexcept
Pointer to the start of the view.
Definition Span.h:537
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
std::uint64_t UInt64
Unsigned integer type of 64 bits.
std::int64_t Int64
Signed integer type of 64 bits.
std::int16_t Int16
Signed integer type of 16 bits.
double Real
Type representing a real number.
Impl::SpanTypeFromSize< conststd::byte, SizeType >::SpanType asBytes(const SpanImpl< DataType, SizeType, Extent > &s)
Converts the view into an array of non-modifiable bytes.
Definition Span.h:1030
unsigned char Byte
Type of a byte.
Definition BaseTypes.h:42
std::int32_t Int32
Signed integer type of 32 bits.