blob: e4166834b30adbd246c6d4c66e0840544771761a [file] [log] [blame]
Ed Tanous57fce802019-05-21 13:00:34 -07001#include <nlohmann/json.hpp>
2
3#include <algorithm>
4
5namespace json_html_util
6{
7
8static constexpr uint8_t utf8Accept = 0;
9static constexpr uint8_t utf8Reject = 1;
10
11inline uint8_t decode(uint8_t& state, uint32_t& codePoint,
12 const uint8_t byte) noexcept
13{
14 // clang-format off
15 static const std::array<std::uint8_t, 400> utf8d =
16 {
17 {
18 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F
19 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F
20 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F
21 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F
22 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F
23 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF
24 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF
25 0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF
26 0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF
27 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0
28 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2
29 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4
30 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6
31 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8
32 }
33 };
34 // clang-format on
35
36 if (state > 0x8)
37 {
38 return state;
39 }
40
41 const uint8_t type = utf8d[byte];
42
43 codePoint = (state != utf8Accept)
Ed Tanousdbb59d42022-01-25 11:09:55 -080044 ? (byte & 0x3fU) | (codePoint << 6)
Ed Tanous57fce802019-05-21 13:00:34 -070045 : static_cast<uint32_t>(0xff >> type) & (byte);
46
Ed Tanousdbb59d42022-01-25 11:09:55 -080047 state = utf8d[256U + state * 16U + type];
Ed Tanous57fce802019-05-21 13:00:34 -070048 return state;
49}
50
51inline void dumpEscaped(std::string& out, const std::string& str)
52{
53 std::array<char, 512> stringBuffer{{}};
54 uint32_t codePoint = 0;
55 uint8_t state = utf8Accept;
56 std::size_t bytes = 0; // number of bytes written to string_buffer
57
58 // number of bytes written at the point of the last valid byte
Ed Tanous2c70f802020-09-28 14:29:23 -070059 std::size_t bytesAfterLastAccept = 0;
Ed Tanous57fce802019-05-21 13:00:34 -070060 std::size_t undumpedChars = 0;
61
62 for (std::size_t i = 0; i < str.size(); ++i)
63 {
64 const uint8_t byte = static_cast<uint8_t>(str[i]);
65
66 switch (decode(state, codePoint, byte))
67 {
68 case utf8Accept: // decode found a new code point
69 {
70 switch (codePoint)
71 {
72 case 0x08: // backspace
73 {
74 stringBuffer[bytes++] = '\\';
75 stringBuffer[bytes++] = 'b';
76 break;
77 }
78
79 case 0x09: // horizontal tab
80 {
81 stringBuffer[bytes++] = '\\';
82 stringBuffer[bytes++] = 't';
83 break;
84 }
85
86 case 0x0A: // newline
87 {
88 stringBuffer[bytes++] = '\\';
89 stringBuffer[bytes++] = 'n';
90 break;
91 }
92
93 case 0x0C: // formfeed
94 {
95 stringBuffer[bytes++] = '\\';
96 stringBuffer[bytes++] = 'f';
97 break;
98 }
99
100 case 0x0D: // carriage return
101 {
102 stringBuffer[bytes++] = '\\';
103 stringBuffer[bytes++] = 'r';
104 break;
105 }
106
107 case 0x22: // quotation mark
108 {
109 stringBuffer[bytes++] = '&';
110 stringBuffer[bytes++] = 'q';
111 stringBuffer[bytes++] = 'u';
112 stringBuffer[bytes++] = 'o';
113 stringBuffer[bytes++] = 't';
114 stringBuffer[bytes++] = ';';
115 break;
116 }
117
118 case 0x27: // apostrophe
119 {
120 stringBuffer[bytes++] = '&';
121 stringBuffer[bytes++] = 'a';
122 stringBuffer[bytes++] = 'p';
123 stringBuffer[bytes++] = 'o';
124 stringBuffer[bytes++] = 's';
125 stringBuffer[bytes++] = ';';
126 break;
127 }
128
129 case 0x26: // ampersand
130 {
131 stringBuffer[bytes++] = '&';
132 stringBuffer[bytes++] = 'a';
133 stringBuffer[bytes++] = 'm';
134 stringBuffer[bytes++] = 'p';
135 stringBuffer[bytes++] = ';';
136 break;
137 }
138
139 case 0x3C: // less than
140 {
141 stringBuffer[bytes++] = '\\';
142 stringBuffer[bytes++] = 'l';
143 stringBuffer[bytes++] = 't';
144 stringBuffer[bytes++] = ';';
145 break;
146 }
147
148 case 0x3E: // greater than
149 {
150 stringBuffer[bytes++] = '\\';
151 stringBuffer[bytes++] = 'g';
152 stringBuffer[bytes++] = 't';
153 stringBuffer[bytes++] = ';';
154 break;
155 }
156
157 default:
158 {
159 // escape control characters (0x00..0x1F)
160 if ((codePoint <= 0x1F) or (codePoint >= 0x7F))
161 {
162 if (codePoint <= 0xFFFF)
163 {
Ed Tanous49d1eea2022-01-07 09:39:33 -0800164 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
Patrick Williams84ea4b12023-05-10 17:07:06 -0500165 std::snprintf(&stringBuffer[bytes], 7,
Ed Tanous49d1eea2022-01-07 09:39:33 -0800166 "\\u%04x",
167 static_cast<uint16_t>(codePoint));
Ed Tanous57fce802019-05-21 13:00:34 -0700168 bytes += 6;
169 }
170 else
171 {
Ed Tanous49d1eea2022-01-07 09:39:33 -0800172 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
173 std::snprintf(
Patrick Williams84ea4b12023-05-10 17:07:06 -0500174 &stringBuffer[bytes], 13, "\\u%04x\\u%04x",
Ed Tanous57fce802019-05-21 13:00:34 -0700175 static_cast<uint16_t>(0xD7C0 +
176 (codePoint >> 10)),
177 static_cast<uint16_t>(0xDC00 +
178 (codePoint & 0x3FF)));
179 bytes += 12;
180 }
181 }
182 else
183 {
184 // copy byte to buffer (all previous bytes
185 // been copied have in default case above)
186 stringBuffer[bytes++] = str[i];
187 }
188 break;
189 }
190 }
191
192 // write buffer and reset index; there must be 13 bytes
193 // left, as this is the maximal number of bytes to be
194 // written ("\uxxxx\uxxxx\0") for one code point
195 if (stringBuffer.size() - bytes < 13)
196 {
197 out.append(stringBuffer.data(), bytes);
198 bytes = 0;
199 }
200
201 // remember the byte position of this accept
Ed Tanous2c70f802020-09-28 14:29:23 -0700202 bytesAfterLastAccept = bytes;
Ed Tanous57fce802019-05-21 13:00:34 -0700203 undumpedChars = 0;
204 break;
205 }
206
207 case utf8Reject: // decode found invalid UTF-8 byte
208 {
209 // in case we saw this character the first time, we
210 // would like to read it again, because the byte
211 // may be OK for itself, but just not OK for the
212 // previous sequence
213 if (undumpedChars > 0)
214 {
215 --i;
216 }
217
218 // reset length buffer to the last accepted index;
219 // thus removing/ignoring the invalid characters
Ed Tanous2c70f802020-09-28 14:29:23 -0700220 bytes = bytesAfterLastAccept;
Ed Tanous57fce802019-05-21 13:00:34 -0700221
222 stringBuffer[bytes++] = '\\';
223 stringBuffer[bytes++] = 'u';
224 stringBuffer[bytes++] = 'f';
225 stringBuffer[bytes++] = 'f';
226 stringBuffer[bytes++] = 'f';
227 stringBuffer[bytes++] = 'd';
228
Ed Tanous2c70f802020-09-28 14:29:23 -0700229 bytesAfterLastAccept = bytes;
Ed Tanous57fce802019-05-21 13:00:34 -0700230
231 undumpedChars = 0;
232
233 // continue processing the string
234 state = utf8Accept;
235 break;
Ed Tanous57fce802019-05-21 13:00:34 -0700236 }
237
238 default: // decode found yet incomplete multi-byte code point
239 {
240 ++undumpedChars;
241 break;
242 }
243 }
244 }
245
246 // we finished processing the string
247 if (state == utf8Accept)
248 {
249 // write buffer
250 if (bytes > 0)
251 {
252 out.append(stringBuffer.data(), bytes);
253 }
254 }
255 else
256 {
257 // write all accepted bytes
Ed Tanous2c70f802020-09-28 14:29:23 -0700258 out.append(stringBuffer.data(), bytesAfterLastAccept);
Ed Tanous57fce802019-05-21 13:00:34 -0700259 out += "\\ufffd";
260 }
261}
262
263inline unsigned int countDigits(uint64_t number) noexcept
264{
Ed Tanous2c70f802020-09-28 14:29:23 -0700265 unsigned int nDigits = 1;
Ed Tanous57fce802019-05-21 13:00:34 -0700266 for (;;)
267 {
268 if (number < 10)
269 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700270 return nDigits;
Ed Tanous57fce802019-05-21 13:00:34 -0700271 }
272 if (number < 100)
273 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700274 return nDigits + 1;
Ed Tanous57fce802019-05-21 13:00:34 -0700275 }
276 if (number < 1000)
277 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700278 return nDigits + 2;
Ed Tanous57fce802019-05-21 13:00:34 -0700279 }
280 if (number < 10000)
281 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700282 return nDigits + 3;
Ed Tanous57fce802019-05-21 13:00:34 -0700283 }
Ed Tanousdbb59d42022-01-25 11:09:55 -0800284 number = number / 10000U;
Ed Tanous2c70f802020-09-28 14:29:23 -0700285 nDigits += 4;
Ed Tanous57fce802019-05-21 13:00:34 -0700286 }
287}
288
289template <typename NumberType,
290 std::enable_if_t<std::is_same<NumberType, uint64_t>::value or
291 std::is_same<NumberType, int64_t>::value,
292 int> = 0>
293void dumpInteger(std::string& out, NumberType number)
294{
295 std::array<char, 64> numberbuffer{{}};
296
Ed Tanous2c70f802020-09-28 14:29:23 -0700297 static constexpr std::array<std::array<char, 2>, 100> digitsTo99{{
Ed Tanous57fce802019-05-21 13:00:34 -0700298 {'0', '0'}, {'0', '1'}, {'0', '2'}, {'0', '3'}, {'0', '4'}, {'0', '5'},
299 {'0', '6'}, {'0', '7'}, {'0', '8'}, {'0', '9'}, {'1', '0'}, {'1', '1'},
300 {'1', '2'}, {'1', '3'}, {'1', '4'}, {'1', '5'}, {'1', '6'}, {'1', '7'},
301 {'1', '8'}, {'1', '9'}, {'2', '0'}, {'2', '1'}, {'2', '2'}, {'2', '3'},
302 {'2', '4'}, {'2', '5'}, {'2', '6'}, {'2', '7'}, {'2', '8'}, {'2', '9'},
303 {'3', '0'}, {'3', '1'}, {'3', '2'}, {'3', '3'}, {'3', '4'}, {'3', '5'},
304 {'3', '6'}, {'3', '7'}, {'3', '8'}, {'3', '9'}, {'4', '0'}, {'4', '1'},
305 {'4', '2'}, {'4', '3'}, {'4', '4'}, {'4', '5'}, {'4', '6'}, {'4', '7'},
306 {'4', '8'}, {'4', '9'}, {'5', '0'}, {'5', '1'}, {'5', '2'}, {'5', '3'},
307 {'5', '4'}, {'5', '5'}, {'5', '6'}, {'5', '7'}, {'5', '8'}, {'5', '9'},
308 {'6', '0'}, {'6', '1'}, {'6', '2'}, {'6', '3'}, {'6', '4'}, {'6', '5'},
309 {'6', '6'}, {'6', '7'}, {'6', '8'}, {'6', '9'}, {'7', '0'}, {'7', '1'},
310 {'7', '2'}, {'7', '3'}, {'7', '4'}, {'7', '5'}, {'7', '6'}, {'7', '7'},
311 {'7', '8'}, {'7', '9'}, {'8', '0'}, {'8', '1'}, {'8', '2'}, {'8', '3'},
312 {'8', '4'}, {'8', '5'}, {'8', '6'}, {'8', '7'}, {'8', '8'}, {'8', '9'},
313 {'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, {'9', '4'}, {'9', '5'},
314 {'9', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'},
315 }};
316
317 // special case for "0"
318 if (number == 0)
319 {
320 out += '0';
321 return;
322 }
323
324 // use a pointer to fill the buffer
Patrick Williams84396af2023-05-11 11:47:45 -0500325 auto* bufferPtr = numberbuffer.begin();
Ed Tanous57fce802019-05-21 13:00:34 -0700326
327 const bool isNegative = std::is_same<NumberType, int64_t>::value &&
328 !(number >= 0); // see issue #755
Ed Tanous543f4402022-01-06 13:12:53 -0800329 uint64_t absValue = 0;
Ed Tanous57fce802019-05-21 13:00:34 -0700330
Ed Tanous543f4402022-01-06 13:12:53 -0800331 unsigned int nChars = 0;
Ed Tanous57fce802019-05-21 13:00:34 -0700332
333 if (isNegative)
334 {
335 *bufferPtr = '-';
336 absValue = static_cast<uint64_t>(0 - number);
337
338 // account one more byte for the minus sign
339 nChars = 1 + countDigits(absValue);
340 }
341 else
342 {
343 absValue = static_cast<uint64_t>(number);
344 nChars = countDigits(absValue);
345 }
346
347 // spare 1 byte for '\0'
348 if (nChars >= numberbuffer.size() - 1)
349 {
350 return;
351 }
352
353 // jump to the end to generate the string from backward
354 // so we later avoid reversing the result
Jason M. Bills17b4d6b2023-05-18 12:53:52 -0700355 std::advance(bufferPtr, nChars - 1);
Ed Tanous57fce802019-05-21 13:00:34 -0700356
357 // Fast int2ascii implementation inspired by "Fastware" talk by Andrei
358 // Alexandrescu See: https://www.youtube.com/watch?v=o4-CwDo2zpg
359 while (absValue >= 100)
360 {
361 const auto digitsIndex = static_cast<unsigned>((absValue % 100));
362 absValue /= 100;
Patrick Williams84ea4b12023-05-10 17:07:06 -0500363 *bufferPtr = digitsTo99[digitsIndex][1];
364 bufferPtr = std::prev(bufferPtr);
365 *bufferPtr = digitsTo99[digitsIndex][0];
366 bufferPtr = std::prev(bufferPtr);
Ed Tanous57fce802019-05-21 13:00:34 -0700367 }
368
369 if (absValue >= 10)
370 {
371 const auto digitsIndex = static_cast<unsigned>(absValue);
Patrick Williams84ea4b12023-05-10 17:07:06 -0500372 *bufferPtr = digitsTo99[digitsIndex][1];
373 bufferPtr = std::prev(bufferPtr);
374 *bufferPtr = digitsTo99[digitsIndex][0];
375 // assignment never used: bufferPtr = std::prev(bufferPtr);
Ed Tanous57fce802019-05-21 13:00:34 -0700376 }
377 else
378 {
Patrick Williams84ea4b12023-05-10 17:07:06 -0500379 *bufferPtr = static_cast<char>('0' + absValue);
380 // assignment never used: bufferPtr = std::prev(bufferPtr);
Ed Tanous57fce802019-05-21 13:00:34 -0700381 }
382
383 out.append(numberbuffer.data(), nChars);
384}
385
386inline void dumpfloat(std::string& out, double number,
387 std::true_type /*isIeeeSingleOrDouble*/)
388{
389 std::array<char, 64> numberbuffer{{}};
Ed Tanousca45aa32022-01-07 09:28:45 -0800390
Patrick Williams84ea4b12023-05-10 17:07:06 -0500391 ::nlohmann::detail::to_chars(numberbuffer.begin(), numberbuffer.end(),
392 number);
Ed Tanous57fce802019-05-21 13:00:34 -0700393
Patrick Williams84ea4b12023-05-10 17:07:06 -0500394 out += numberbuffer.data();
Ed Tanous57fce802019-05-21 13:00:34 -0700395}
396
397inline void dumpfloat(std::string& out, double number,
398 std::false_type /*isIeeeSingleOrDouble*/)
399{
400 std::array<char, 64> numberbuffer{{}};
401 // get number of digits for a float -> text -> float round-trip
402 static constexpr auto d = std::numeric_limits<double>::max_digits10;
403
404 // the actual conversion
Ed Tanous49d1eea2022-01-07 09:39:33 -0800405 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
Ed Tanous3c2a8d02021-09-22 10:07:25 -0700406 std::ptrdiff_t len = std::snprintf(numberbuffer.data(), numberbuffer.size(),
407 "%.*g", d, number);
Ed Tanous57fce802019-05-21 13:00:34 -0700408
409 // negative value indicates an error
410 if (len <= 0)
411 {
412 return;
413 }
414
415 // check if buffer was large enough
416 if (numberbuffer.size() < static_cast<std::size_t>(len))
417 {
418 return;
419 }
420
Patrick Williams84396af2023-05-11 11:47:45 -0500421 auto* end = numberbuffer.begin();
Patrick Williams84ea4b12023-05-10 17:07:06 -0500422 std::advance(end, len);
423 end = std::remove(numberbuffer.begin(), end, ',');
Ed Tanous57fce802019-05-21 13:00:34 -0700424 std::fill(end, numberbuffer.end(), '\0');
425
Patrick Williams84ea4b12023-05-10 17:07:06 -0500426 if (std::distance(numberbuffer.begin(), end) > len)
Ed Tanous57fce802019-05-21 13:00:34 -0700427 {
428 return;
429 }
Patrick Williams84ea4b12023-05-10 17:07:06 -0500430 len = std::distance(numberbuffer.begin(), end);
Ed Tanous57fce802019-05-21 13:00:34 -0700431
432 out.append(numberbuffer.data(), static_cast<std::size_t>(len));
433
434 // determine if need to append ".0"
Patrick Williams84396af2023-05-11 11:47:45 -0500435 auto* newEnd = numberbuffer.begin();
Patrick Williams84ea4b12023-05-10 17:07:06 -0500436 std::advance(newEnd, len + 1);
437
Ed Tanous57fce802019-05-21 13:00:34 -0700438 const bool valueIsIntLike =
Patrick Williams84ea4b12023-05-10 17:07:06 -0500439 std::none_of(numberbuffer.begin(), newEnd,
Ed Tanous57fce802019-05-21 13:00:34 -0700440 [](char c) { return (c == '.' or c == 'e'); });
441
442 if (valueIsIntLike)
443 {
444 out += ".0";
445 }
446}
447
448inline void dumpfloat(std::string& out, double number)
449{
450 // NaN / inf
451 if (!std::isfinite(number))
452 {
453 out += "null";
454 return;
455 }
456
457 // If float is an IEEE-754 single or double precision number,
458 // use the Grisu2 algorithm to produce short numbers which are
459 // guaranteed to round-trip, using strtof and strtod, resp.
460 //
461 // NB: The test below works if <long double> == <double>.
462 static constexpr bool isIeeeSingleOrDouble =
463 (std::numeric_limits<double>::is_iec559 and
464 std::numeric_limits<double>::digits == 24 and
465 std::numeric_limits<double>::max_exponent == 128) or
466 (std::numeric_limits<double>::is_iec559 and
467 std::numeric_limits<double>::digits == 53 and
468 std::numeric_limits<double>::max_exponent == 1024);
469
470 dumpfloat(out, number,
471 std::integral_constant<bool, isIeeeSingleOrDouble>());
472}
473
474inline void dump(std::string& out, const nlohmann::json& val)
475{
476 switch (val.type())
477 {
478 case nlohmann::json::value_t::object:
479 {
480 if (val.empty())
481 {
482 out += "{}";
483 return;
484 }
485
486 out += "{";
487
488 out += "<div class=tab>";
489 for (auto i = val.begin(); i != val.end();)
490 {
491 out += "&quot";
492 dumpEscaped(out, i.key());
493 out += "&quot: ";
494
495 bool inATag = false;
496 if (i.key() == "@odata.id" || i.key() == "@odata.context" ||
497 i.key() == "Members@odata.nextLink" || i.key() == "Uri")
498 {
499 inATag = true;
500 out += "<a href=\"";
501 dumpEscaped(out, i.value());
502 out += "\">";
503 }
504 dump(out, i.value());
505 if (inATag)
506 {
507 out += "</a>";
508 }
509 i++;
510 if (i != val.end())
511 {
512 out += ",";
513 }
514 out += "<br>";
515 }
516 out += "</div>";
517 out += '}';
518
519 return;
520 }
521
522 case nlohmann::json::value_t::array:
523 {
524 if (val.empty())
525 {
526 out += "[]";
527 return;
528 }
529
530 out += "[";
531
532 out += "<div class=tab>";
533
534 // first n-1 elements
535 for (auto i = val.cbegin(); i != val.cend() - 1; ++i)
536 {
537 dump(out, *i);
538 out += ",<br>";
539 }
540
541 // last element
542 dump(out, val.back());
543
544 out += "</div>";
545 out += ']';
546
547 return;
548 }
549
550 case nlohmann::json::value_t::string:
551 {
552 out += '\"';
553 const std::string* ptr = val.get_ptr<const std::string*>();
554 dumpEscaped(out, *ptr);
555 out += '\"';
556 return;
557 }
558
559 case nlohmann::json::value_t::boolean:
560 {
561 if (*(val.get_ptr<const bool*>()))
562 {
563 out += "true";
564 }
565 else
566 {
567 out += "false";
568 }
569 return;
570 }
571
572 case nlohmann::json::value_t::number_integer:
573 {
574 dumpInteger(out, *(val.get_ptr<const int64_t*>()));
575 return;
576 }
577
578 case nlohmann::json::value_t::number_unsigned:
579 {
580 dumpInteger(out, *(val.get_ptr<const uint64_t*>()));
581 return;
582 }
583
584 case nlohmann::json::value_t::number_float:
585 {
586 dumpfloat(out, *(val.get_ptr<const double*>()));
587 return;
588 }
589
590 case nlohmann::json::value_t::discarded:
591 {
592 out += "<discarded>";
593 return;
594 }
595
596 case nlohmann::json::value_t::null:
597 {
598 out += "null";
599 return;
600 }
Ed Tanous3e4c7792020-09-25 08:12:41 -0700601 case nlohmann::json::value_t::binary:
602 {
603 // Do nothing; Should never happen.
604 return;
605 }
Ed Tanous57fce802019-05-21 13:00:34 -0700606 }
607}
608
609inline void dumpHtml(std::string& out, const nlohmann::json& json)
610{
611 out += "<html>\n"
612 "<head>\n"
613 "<title>Redfish API</title>\n"
614 "<link href=\"/redfish.css\" rel=\"stylesheet\">\n"
615 "</head>\n"
616 "<body>\n"
617 "<div class=\"container\">\n"
618 "<img src=\"/DMTF_Redfish_logo_2017.svg\" alt=\"redfish\" "
619 "height=\"406px\" "
620 "width=\"576px\">\n"
621 "<div class=\"content\">\n";
622 dump(out, json);
623 out += "</div>\n"
624 "</div>\n"
625 "</body>\n"
626 "</html>\n";
627}
628
629} // namespace json_html_util