Coverage Report

Created: 2026-02-14 07:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wt/src/Wt/Json/Value.C
Line
Count
Source
1
/*
2
 * Copyright (C) 2011 Emweb bv, Herent, Belgium.
3
 *
4
 * See the LICENSE file for terms of use.
5
 */
6
7
#include "Wt/Json/Value.h"
8
#include "Wt/Json/Object.h"
9
#include "Wt/Json/Array.h"
10
#include "Wt/WAny.h"
11
#include "Wt/WLogger.h"
12
13
#include "WebUtils.h"
14
15
namespace Wt {
16
17
LOGGER("Json.Value");
18
19
  namespace Json {
20
21
    namespace {
22
      const char *typeNames[] = {
23
        "Null",
24
        "String",
25
        "Bool",
26
        "Number",
27
        "Object",
28
        "Array"
29
      };
30
    }
31
32
TypeException::TypeException(const std::string& name,
33
                             Type actualType, Type expectedType)
34
0
  : WException("Type error: " + name + " is "
35
0
               + typeNames[static_cast<unsigned int>(actualType)]
36
0
               + ", expected "
37
0
               + typeNames[static_cast<unsigned int>(expectedType)]),
38
0
    name_(name),
39
0
    actualType_(actualType),
40
0
    expectedType_(expectedType)
41
0
{ }
42
43
TypeException::TypeException(Type actualType, Type expectedType)
44
20
  : WException(std::string("Type error: value is ")
45
20
               + typeNames[static_cast<unsigned int>(actualType)]
46
20
               + ", expected "
47
20
               + typeNames[static_cast<unsigned int>(expectedType)]),
48
20
    actualType_(actualType),
49
20
    expectedType_(expectedType)
50
20
{ }
51
52
TypeException::~TypeException() throw()
53
20
{ }
54
55
template <typename T> T Value::get(Type requestedType) const
56
0
{
57
0
  try {
58
0
    return cpp17::any_cast<T>(v_);
59
0
  } catch (cpp17::bad_any_cast& e) {
60
0
    throw TypeException(type(), requestedType);
61
0
  }
62
0
}
63
64
template <typename T> const T& Value::getCR(Type requestedType) const
65
0
{
66
0
  try {
67
0
    return cpp17::any_cast<const T&>(v_);
68
0
  } catch (cpp17::bad_any_cast& e) {
69
0
    throw TypeException(type(), requestedType);
70
0
  }
71
0
}
Unexecuted instantiation: Wt::WString const& Wt::Json::Value::getCR<Wt::WString>(Wt::Json::Type) const
Unexecuted instantiation: Wt::Json::Array const& Wt::Json::Value::getCR<Wt::Json::Array>(Wt::Json::Type) const
Unexecuted instantiation: Wt::Json::Object const& Wt::Json::Value::getCR<Wt::Json::Object>(Wt::Json::Type) const
72
73
template <typename T> T& Value::getR(Type requestedType)
74
87.8k
{
75
87.8k
  try {
76
87.8k
    return cpp17::any_cast<T&>(v_);
77
87.8k
  } catch (cpp17::bad_any_cast& e) {
78
20
    throw TypeException(type(), requestedType);
79
20
  }
80
87.8k
}
Wt::Json::Array& Wt::Json::Value::getR<Wt::Json::Array>(Wt::Json::Type)
Line
Count
Source
74
76.6k
{
75
76.6k
  try {
76
76.6k
    return cpp17::any_cast<T&>(v_);
77
76.6k
  } catch (cpp17::bad_any_cast& e) {
78
0
    throw TypeException(type(), requestedType);
79
0
  }
80
76.6k
}
Wt::Json::Object& Wt::Json::Value::getR<Wt::Json::Object>(Wt::Json::Type)
Line
Count
Source
74
11.2k
{
75
11.2k
  try {
76
11.2k
    return cpp17::any_cast<T&>(v_);
77
11.2k
  } catch (cpp17::bad_any_cast& e) {
78
20
    throw TypeException(type(), requestedType);
79
20
  }
80
11.2k
}
81
82
const Value Value::Null;
83
const Value Value::True(true);
84
const Value Value::False(false);
85
86
Value::Value()
87
137k
{ }
88
89
Value::Value(bool value)
90
20
  : v_(value)
91
20
{ }
92
93
Value::Value(const WT_USTRING& value)
94
0
  : v_(value)
95
0
{ }
96
97
Value::Value(WT_USTRING&& value)
98
6.11k
  : v_(std::move(value))
99
6.11k
{ }
100
101
Value::Value(int value)
102
0
  : v_(value)
103
0
{ }
104
105
Value::Value(long value)
106
0
  : v_(value)
107
0
{ }
108
109
110
Value::Value(long long value)
111
0
  : v_(value)
112
0
{ }
113
114
Value::Value(double value)
115
43.2k
  : v_(value)
116
43.2k
{ }
117
118
Value::Value(const char* value)
119
0
  : v_(WString(value))
120
0
{ }
121
122
Value::Value(const Array& value)
123
0
  : v_(value)
124
0
{ }
125
126
Value::Value(const Object& value)
127
0
  : v_(value)
128
0
{ }
129
130
Value::Value(Type type)
131
87.8k
{
132
87.8k
  switch (type) {
133
0
  case Type::Null: break;
134
0
  case Type::Bool: v_ = false; break;
135
0
  case Type::Number: v_ = double(0.0); break;
136
0
  case Type::String: v_ = std::string(); break;
137
11.2k
  case Type::Object: v_ = Object(); break;
138
76.6k
  case Type::Array: v_ = Array(); break;
139
87.8k
  }
140
87.8k
}
141
142
Value::Value(const Value& other)
143
110k
  : v_(other.v_)
144
110k
{ }
145
146
Value::Value(Value&& other)
147
112k
  : v_(std::move(other.v_))
148
112k
{ }
149
150
Value::Value(Object&& other)
151
0
  : v_(std::move(other))
152
0
{ }
153
154
Value::Value(Array&& other)
155
0
  : v_(std::move(other))
156
0
{ }
157
158
Value& Value::operator= (const Value& other)
159
21.7k
{
160
21.7k
  v_ = other.v_;
161
21.7k
  return *this;
162
21.7k
}
163
164
Value& Value::operator= (Value &&other)
165
137k
{
166
137k
  v_ = std::move(other.v_);
167
137k
  return *this;
168
137k
}
169
170
Value& Value::operator= (Object&& other)
171
0
{
172
0
  v_ = std::move(other);
173
0
  return *this;
174
0
}
175
176
Value& Value::operator= (Array&& other)
177
0
{
178
0
  v_ = std::move(other);
179
0
  return *this;
180
0
}
181
182
bool Value::operator== (const Value& other) const
183
0
{
184
0
  if (typeid(v_) != typeid(other.v_))
185
0
    return false;
186
0
  else if (!cpp17::any_has_value(v_) || !cpp17::any_has_value(other.v_))
187
0
    return cpp17::any_has_value(v_) == cpp17::any_has_value(other.v_);
188
0
  else if (v_.type() == typeid(Json::Object))
189
0
    return cpp17::any_cast<Json::Object>(v_) ==
190
0
      cpp17::any_cast<Json::Object>(other.v_);
191
0
  else if (v_.type() == typeid(Json::Array))
192
0
    return cpp17::any_cast<Json::Array>(v_) ==
193
0
      cpp17::any_cast<Json::Array>(other.v_);
194
0
  else if (v_.type() == typeid(bool))
195
0
    return cpp17::any_cast<bool>(v_) == cpp17::any_cast<bool>(other.v_);
196
0
  else if (v_.type() == typeid(int))
197
0
    return cpp17::any_cast<int>(v_) == cpp17::any_cast<int>(other.v_);
198
0
  else if (v_.type() == typeid(long))
199
0
    return cpp17::any_cast<long>(v_) == cpp17::any_cast<long>(other.v_);
200
0
  else if (v_.type() == typeid(long long))
201
0
    return cpp17::any_cast<long long>(v_) ==
202
0
      cpp17::any_cast<long long>(other.v_);
203
0
  else if (v_.type() == typeid(double))
204
0
    return cpp17::any_cast<double>(v_) == cpp17::any_cast<double>(other.v_);
205
0
  else if (v_.type() == typeid(Wt::WString))
206
0
    return cpp17::any_cast<Wt::WString>(v_) == cpp17::any_cast<Wt::WString>(other.v_);
207
0
  else {
208
0
    WStringStream ss;
209
0
    ss << "Value::operator== : unknown value type: " << std::string(v_.type().name());
210
0
    throw WException(ss.str());
211
0
  }
212
0
}
213
214
bool Value::operator!= (const Value& other) const
215
0
{
216
0
  return !(*this == other);
217
0
}
218
219
Type Value::type() const
220
20
{
221
20
  if (!cpp17::any_has_value(v_))
222
0
    return Type::Null;
223
20
  else {
224
20
    return typeOf(v_.type());
225
20
  }
226
20
}
227
228
bool Value::hasType(const std::type_info& aType) const
229
0
{
230
0
  return type() == typeOf(aType);
231
0
}
232
233
Type Value::typeOf(const std::type_info& t)
234
20
{
235
20
  if (t == typeid(bool))
236
0
    return Type::Bool;
237
20
  else if (t == typeid(double) || t == typeid(long long) || t == typeid(int) || t == typeid(long))
238
0
    return Type::Number;
239
20
  else if (t == typeid(WT_USTRING))
240
0
    return Type::String;
241
20
  else if (t == typeid(Object))
242
0
    return Type::Object;
243
20
  else if (t == typeid(Array))
244
20
    return Type::Array;
245
0
  else
246
0
    throw WException(std::string("Value::typeOf(): unsupported type ")
247
0
                     + t.name());
248
20
}
249
250
Value::operator const WT_USTRING&() const
251
0
{
252
0
  return getCR<WT_USTRING>(Type::String);
253
0
}
254
255
Value::operator std::string() const
256
0
{
257
0
  return ((const WT_USTRING&)(*this)).toUTF8();
258
0
}
259
260
Value::operator bool() const
261
0
{
262
0
  return get<bool>(Type::Bool);
263
0
}
264
265
Value::operator int() const
266
0
{
267
0
  const std::type_info& t = v_.type();
268
269
0
  if (t == typeid(double))
270
0
    return static_cast<int>(cpp17::any_cast<double>(v_));
271
0
  else if (t == typeid(long))
272
0
    return static_cast<int>(cpp17::any_cast<long>(v_));
273
0
  else if (t == typeid(long long))
274
0
    return static_cast<int>(cpp17::any_cast<long long>(v_));
275
0
  else if (t == typeid(int))
276
0
    return cpp17::any_cast<int>(v_);
277
0
  else
278
0
    throw TypeException(type(), Type::Number);
279
0
}
280
281
Value::operator long() const
282
0
{
283
0
  const std::type_info& t = v_.type();
284
285
0
  if (t == typeid(double))
286
0
    return static_cast<long>(cpp17::any_cast<double>(v_));
287
0
  else if (t == typeid(long))
288
0
    return cpp17::any_cast<long>(v_);
289
0
  else if (t == typeid(long long))
290
0
    return static_cast<long>(cpp17::any_cast<long long>(v_));
291
0
  else if (t == typeid(int))
292
0
    return static_cast<long>(cpp17::any_cast<int>(v_));
293
0
  else
294
0
    throw TypeException(type(), Type::Number);
295
0
}
296
297
Value::operator long long() const
298
0
{
299
0
  const std::type_info& t = v_.type();
300
301
0
  if (t == typeid(double))
302
0
    return static_cast<long long>(cpp17::any_cast<double>(v_));
303
0
  else if (t == typeid(long))
304
0
    return static_cast<long long>(cpp17::any_cast<long>(v_));
305
0
  else if (t == typeid(long long))
306
0
    return cpp17::any_cast<long long>(v_);
307
0
  else if (t == typeid(int))
308
0
    return static_cast<long long>(cpp17::any_cast<int>(v_));
309
0
  else
310
0
    throw TypeException(type(), Type::Number);
311
0
}
312
313
Value::operator double() const
314
0
{
315
0
  const std::type_info& t = v_.type();
316
317
0
  if (t == typeid(double))
318
0
    return cpp17::any_cast<double>(v_);
319
0
  else if (t == typeid(long))
320
0
    return static_cast<double>(cpp17::any_cast<long>(v_));
321
0
  else if (t == typeid(long long))
322
0
    return static_cast<double>(cpp17::any_cast<long long>(v_));
323
0
  else if (t == typeid(int))
324
0
    return static_cast<double>(cpp17::any_cast<int>(v_));
325
0
  else
326
0
    throw TypeException(type(), Type::Number);
327
0
}
328
329
Value::operator const Array&() const
330
0
{
331
0
  return getCR<Array>(Type::Array);
332
0
}
333
334
Value::operator const Object&() const
335
0
{
336
0
  return getCR<Object>(Type::Object);
337
0
}
338
339
Value::operator Array&()
340
76.6k
{
341
76.6k
  return getR<Array>(Type::Array);
342
76.6k
}
343
344
Value::operator Object&()
345
11.2k
{
346
11.2k
  return getR<Object>(Type::Object);
347
11.2k
}
348
349
const WT_USTRING& Value::orIfNull(const WT_USTRING& v) const
350
0
{
351
0
  if (cpp17::any_has_value(v_))
352
0
    return *this;
353
0
  else
354
0
    return v;
355
0
}
356
357
std::string Value::orIfNull(const std::string& v) const
358
0
{
359
0
  if (cpp17::any_has_value(v_))
360
0
    return *this;
361
0
  else
362
0
    return v;
363
0
}
364
365
std::string Value::orIfNull(const char *v) const
366
0
{
367
0
  return orIfNull(std::string(v));
368
0
}
369
370
bool Value::orIfNull(bool v) const
371
0
{
372
0
  if (cpp17::any_has_value(v_))
373
0
    return *this;
374
0
  else
375
0
    return v;
376
0
}
377
378
int Value::orIfNull(int v) const
379
0
{
380
0
  if (cpp17::any_has_value(v_))
381
0
    return *this;
382
0
  else
383
0
    return v;
384
0
}
385
386
long long Value::orIfNull(long long v) const
387
0
{
388
0
  if (cpp17::any_has_value(v_))
389
0
    return *this;
390
0
  else
391
0
    return v;
392
0
}
393
394
double Value::orIfNull(double v) const
395
0
{
396
0
  if (cpp17::any_has_value(v_))
397
0
    return *this;
398
0
  else
399
0
    return v;
400
0
}
401
402
const Array& Value::orIfNull(const Array& v) const
403
0
{
404
0
  if (cpp17::any_has_value(v_))
405
0
    return *this;
406
0
  else
407
0
    return v;
408
0
}
409
410
const Object& Value::orIfNull(const Object& v) const
411
0
{
412
0
  if (cpp17::any_has_value(v_))
413
0
    return *this;
414
0
  else
415
0
    return v;
416
0
}
417
418
Value Value::toString() const
419
0
{
420
0
  const std::type_info& t = v_.type();
421
422
0
  if (t == typeid(Object) || t == typeid(Array))
423
0
    return Null;
424
0
  else if (t == typeid(WT_USTRING))
425
0
    return *this;
426
0
  else if(type() == Type::Number) {
427
0
    WString str = asString(v_);
428
0
    std::string sstr = str.toUTF8();
429
0
    if (sstr.find("nan") != std::string::npos ||
430
0
        sstr.find("inf") != std::string::npos)
431
0
      throw WException(std::string("Value::toString(): Not a Number"));
432
0
    return Value(str);
433
0
  } else
434
0
    return Value(asString(v_));
435
0
}
436
437
Value Value::toBool() const
438
0
{
439
0
  const std::type_info& t = v_.type();
440
441
0
  if (t == typeid(Object) || t == typeid(Array))
442
0
    return Null;
443
0
  else if (t == typeid(bool))
444
0
    return *this;
445
0
  else if (t == typeid(WT_USTRING)) {
446
0
    const WT_USTRING& s = cpp17::any_cast<const WT_USTRING& >(v_);
447
0
    if (s == "true")
448
0
      return True;
449
0
    else if (s == "false")
450
0
      return False;
451
0
    else
452
0
      return Null;
453
0
  } else
454
0
    return Null;
455
0
}
456
457
Value Value::toNumber() const
458
0
{
459
0
  const std::type_info& t = v_.type();
460
461
0
  if (t == typeid(Object) || t == typeid(Array))
462
0
    return Null;
463
0
  else if (t == typeid(double) || t == typeid(long long) || t == typeid(int) || t == typeid(long))
464
0
    return *this;
465
0
  else if (t == typeid(WT_USTRING)) {
466
0
    const WT_USTRING& s = cpp17::any_cast<const WT_USTRING& >(v_);
467
0
    try {
468
0
      return Utils::stod(s.toUTF8());
469
0
    } catch (std::exception& e) {
470
0
      LOG_WARN("toNumber() could not cast '" << s << "'");
471
0
      return Null;
472
0
    }
473
0
  } else
474
0
    return Null;
475
0
}
476
477
  }
478
}