Coverage Report

Created: 2025-12-12 07:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hermes/include/hermes/Support/JSON.h
Line
Count
Source
1
/*
2
 * Copyright (c) Meta Platforms, Inc. and affiliates.
3
 *
4
 * This source code is licensed under the MIT license found in the
5
 * LICENSE file in the root directory of this source tree.
6
 */
7
8
#ifndef HERMES_SUPPORT_JSON_H
9
#define HERMES_SUPPORT_JSON_H
10
11
#include "hermes/Platform/Unicode/CharacterProperties.h"
12
13
#include "llvh/ADT/ArrayRef.h"
14
15
namespace hermes {
16
17
template <typename Output>
18
0
void appendUTF16Escaped(Output &output, char16_t cp) {
19
0
  auto toLowerHex = [](uint8_t u) {
20
0
    assert(u <= 0xF);
21
0
    return u"0123456789abcdef"[u];
22
0
  };
23
0
  output.append({u'\\', u'u'});
24
0
  output.push_back(toLowerHex(cp >> 12));
25
0
  output.push_back(toLowerHex((cp >> 8) & 0xF));
26
0
  output.push_back(toLowerHex((cp >> 4) & 0xF));
27
0
  output.push_back(toLowerHex(cp & 0xF));
28
0
}
29
30
// If there is a valid surrogate pair at position \p i in \p view, then write
31
// both the high and low surrogate into \p output. Otherwise, write an escaped
32
// UTF16 value into \p output. \return true if a pair was found.
33
template <typename Output, typename CharT>
34
0
bool handleSurrogate(Output &output, llvh::ArrayRef<CharT> view, size_t i) {
35
0
  char16_t ch = view[i];
36
0
  assert(
37
0
      ch >= UNICODE_SURROGATE_FIRST && ch <= UNICODE_SURROGATE_LAST &&
38
0
      "charcter should be a surrogate character");
39
  // Handle well-formed-ness here: Represent unpaired surrogate code points as
40
  // JSON escape sequences.
41
0
  if (isHighSurrogate(ch) && i + 1 < view.size()) {
42
0
    char16_t next = view[i + 1];
43
0
    if (isLowSurrogate(next)) {
44
      // We found a surrogate pair. Simply write both of them unescaped to the
45
      // output.
46
0
      output.push_back(ch);
47
0
      output.push_back(next);
48
0
      return true;
49
0
    }
50
0
  }
51
  // We did not find a valid pair, so the current surrogate character must be
52
  // written as an escaped JSON sequence.
53
0
  appendUTF16Escaped(output, ch);
54
0
  return false;
55
0
}
56
57
/// Quotes a string given by \p view and puts the quoted version into \p output.
58
/// \p view must be utf16 or ASCII encoded.
59
/// \post output is a container that has a sequential list of utf16 characters
60
///   that can be embedded into a JSON string.
61
template <typename Output, typename CharT>
62
0
void quoteStringForJSON(Output &output, llvh::ArrayRef<CharT> view) {
63
  // Quote.1.
64
0
  output.push_back(u'"');
65
  // Quote.2.
66
0
  for (size_t i = 0, e = view.size(); i < e; ++i) {
67
0
    CharT ch = view[i];
68
0
#define ESCAPE(ch, replace)    \
69
0
  case ch:                     \
70
0
    output.push_back(u'\\');   \
71
0
    output.push_back(replace); \
72
0
    break
73
74
0
    switch (ch) {
75
      // Quote.2.a.
76
0
      ESCAPE(u'\\', u'\\');
77
0
      ESCAPE(u'"', u'"');
78
      // Quote.2.b.
79
0
      ESCAPE(u'\b', u'b');
80
0
      ESCAPE(u'\f', u'f');
81
0
      ESCAPE(u'\n', u'n');
82
0
      ESCAPE(u'\r', u'r');
83
0
      ESCAPE(u'\t', u't');
84
0
      default:
85
0
        if (ch < u' ') {
86
          // Quote.2.c.
87
0
          output.append({u'\\', u'u', u'0', u'0'});
88
0
          output.push_back(u'0' + (ch / 16));
89
0
          if (ch % 16 < 10) {
90
0
            output.push_back(u'0' + (ch % 16));
91
0
          } else {
92
0
            output.push_back(u'a' + (ch % 16 - 10));
93
0
          }
94
0
        } else {
95
          // This check should only generate code when CharT is more than 1
96
          // byte.
97
          if constexpr (
98
0
              std::numeric_limits<CharT>::max() >= UNICODE_SURROGATE_FIRST) {
99
0
            if (ch >= UNICODE_SURROGATE_FIRST && ch <= UNICODE_SURROGATE_LAST) {
100
0
              if (handleSurrogate(output, view, i)) {
101
                // Found a valid surrogate pair, so skip over the next
102
                // character.
103
0
                i++;
104
0
              }
105
0
            } else {
106
              // Quote.2.d.
107
0
              output.push_back(ch);
108
0
            }
109
0
          } else {
110
            // Quote.2.d.
111
0
            output.push_back(ch);
112
0
          }
113
0
        }
114
0
    }
115
0
  }
116
  // Quote.3.
117
0
  output.push_back(u'"');
118
0
}
Unexecuted instantiation: void hermes::quoteStringForJSON<llvh::SmallVector<char16_t, 32u>, char>(llvh::SmallVector<char16_t, 32u>&, llvh::ArrayRef<char>)
Unexecuted instantiation: void hermes::quoteStringForJSON<llvh::SmallVector<char16_t, 32u>, char16_t>(llvh::SmallVector<char16_t, 32u>&, llvh::ArrayRef<char16_t>)
119
120
} // namespace hermes
121
122
#endif