Coverage Report

Created: 2025-11-16 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/spotify-json/src/detail/escape_common.hpp
Line
Count
Source
1
/*
2
 * Copyright (c) 2014-2016 Spotify AB
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5
 * use this file except in compliance with the License. You may obtain a copy of
6
 * the License at
7
 *
8
 * http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
 * License for the specific language governing permissions and limitations under
14
 * the License.
15
 */
16
17
#pragma once
18
19
#include <cstdint>
20
#include <cstring>
21
22
#include <spotify/json/detail/macros.hpp>
23
24
#if _MSC_VER
25
#pragma intrinsic (memcpy)
26
#endif
27
28
namespace spotify {
29
namespace json {
30
namespace detail {
31
32
2.34k
json_force_inline void write_escaped_c(char *&out, const char c) {
33
2.34k
  static const char HEX[] = "0123456789ABCDEF";
34
2.34k
  static const char POPULAR_CONTROL_CHARACTERS[] = {
35
2.34k
    'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u',
36
2.34k
    'b', 't', 'n', 'u', 'f', 'r', 'u', 'u',
37
2.34k
    'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u',
38
2.34k
    'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u'
39
2.34k
  };
40
41
  // All characters above 0x20 can be written as is, except for ", /. The former
42
  // is below 0x30 and the latter is at 0x5C. As an optimization, for most
43
  // simple strings (letters, numbers, some punctuation), check for this first
44
  // before doing more complicated checks (more expensive checks).
45
2.34k
  if (json_likely(uint8_t(c) >= 0x30)) {
46
2.34k
    if (json_likely(c != '\\')) {
47
2.34k
      *(out++) = c;
48
2.34k
    } else {
49
0
      *(out++) = '\\';
50
0
      *(out++) = c;
51
0
    }
52
2.34k
    return;
53
2.34k
  }
54
55
  // In the next step, consider the characters between 0x20 and 0x30, which are
56
  // different punctuation and special characters. We will write most of them as
57
  // is, except for ", which is trivially escaped. Note that JSON allows for /
58
  // to be escaped as well, but most JSON serializers do not.
59
0
  if (json_likely(uint8_t(c) >= 0x20)) {
60
0
    if (json_likely(c != '"')) {
61
0
      *(out++) = c;
62
0
    } else {
63
0
      *(out++) = '\\';
64
0
      *(out++) = c;
65
0
    }
66
0
    return;
67
0
  }
68
69
  // Finally handle all control characters (below 0x20). These all need escaping
70
  // to some degree. There are some "popular" control characters, such as tabs,>
71
  // newline, and carriage return, with simple escape codes. All other control
72
  // characters get an escape code on the form \u00xx. Six bytes. Isch.
73
0
  const auto control_character = POPULAR_CONTROL_CHARACTERS[int(c)];
74
0
  if (json_likely(control_character != 'u')) {
75
0
    out[0] = '\\';
76
0
    out[1] = control_character;
77
0
    out += 2;
78
0
  } else {
79
0
    memcpy(out, "\\u00", 4);
80
0
    out[4] = HEX[(c >> 4)];
81
0
    out[5] = HEX[(c & 0x0F)];
82
0
    out += 6;
83
0
  }
84
0
}
85
86
2.34k
json_force_inline void write_escaped_1(char *&out, const char *&begin) {
87
2.34k
  struct blob_1_t { char a; };
88
2.34k
  const auto b = *reinterpret_cast<const blob_1_t *>(begin);
89
2.34k
  write_escaped_c(out, b.a);
90
2.34k
  begin += sizeof(blob_1_t);
91
2.34k
}
92
93
0
json_force_inline void write_escaped_2(char *&out, const char *&begin) {
94
0
  struct blob_2_t { char a, b; };
95
0
  const auto b = *reinterpret_cast<const blob_2_t *>(begin);
96
0
  write_escaped_c(out, b.a);
97
0
  write_escaped_c(out, b.b);
98
0
  begin += sizeof(blob_2_t);
99
0
}
100
101
0
json_force_inline void write_escaped_4(char *&out, const char *&begin) {
102
0
  struct blob_4_t { char a, b, c, d; };
103
0
  const auto b = *reinterpret_cast<const blob_4_t *>(begin);
104
0
  write_escaped_c(out, b.a);
105
0
  write_escaped_c(out, b.b);
106
0
  write_escaped_c(out, b.c);
107
0
  write_escaped_c(out, b.d);
108
0
  begin += sizeof(blob_4_t);
109
0
}
110
111
0
json_force_inline void write_escaped_8(char *&out, const char *&begin) {
112
0
  struct blob_8_t { char a, b, c, d, e, f, g, h; };
113
0
  const auto b = *reinterpret_cast<const blob_8_t *>(begin);
114
0
  write_escaped_c(out, b.a);
115
0
  write_escaped_c(out, b.b);
116
0
  write_escaped_c(out, b.c);
117
0
  write_escaped_c(out, b.d);
118
0
  write_escaped_c(out, b.e);
119
0
  write_escaped_c(out, b.f);
120
0
  write_escaped_c(out, b.g);
121
0
  write_escaped_c(out, b.h);
122
0
  begin += sizeof(blob_8_t);
123
0
}
124
125
}  // namespace detail
126
}  // namespace json
127
}  // namespace spotify