Coverage Report

Created: 2026-07-25 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/yaml-cpp/src/exp.cpp
Line
Count
Source
1
#include <sstream>
2
3
#include "exp.h"
4
#include "stream.h"
5
#include "yaml-cpp/exceptions.h"  // IWYU pragma: keep
6
7
namespace YAML {
8
struct Mark;
9
}  // namespace YAML
10
11
namespace YAML {
12
namespace Exp {
13
1.72k
unsigned ParseHex(const std::string& str, const Mark& mark) {
14
1.72k
  unsigned value = 0;
15
7.66k
  for (char ch : str) {
16
7.66k
    int digit = 0;
17
7.66k
    if ('a' <= ch && ch <= 'f')
18
1.19k
      digit = ch - 'a' + 10;
19
6.47k
    else if ('A' <= ch && ch <= 'F')
20
1.92k
      digit = ch - 'A' + 10;
21
4.55k
    else if ('0' <= ch && ch <= '9')
22
4.45k
      digit = ch - '0';
23
91
    else
24
91
      throw ParserException(mark, ErrorMsg::INVALID_HEX);
25
26
7.57k
    value = (value << 4) + digit;
27
7.57k
  }
28
29
1.63k
  return value;
30
1.72k
}
31
32
4.10k
std::string Str(unsigned ch) { return std::string(1, static_cast<char>(ch)); }
33
34
// Escape
35
// . Translates the next 'codeLength' characters into a hex number and returns
36
// the result.
37
// . Throws if it's not actually hex.
38
1.72k
std::string Escape(Stream& in, int codeLength) {
39
  // grab string
40
1.72k
  std::string str;
41
9.76k
  for (int i = 0; i < codeLength; i++)
42
8.04k
    str += in.get();
43
44
  // get the value
45
1.72k
  unsigned value = ParseHex(str, in.mark());
46
47
  // legal unicode?
48
1.72k
  if ((value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF) {
49
51
    std::stringstream msg;
50
51
    msg << ErrorMsg::INVALID_UNICODE << value;
51
51
    throw ParserException(in.mark(), msg.str());
52
51
  }
53
54
  // now break it up into chars
55
1.67k
  if (value <= 0x7F)
56
349
    return Str(value);
57
58
1.32k
  if (value <= 0x7FF)
59
279
    return Str(0xC0 + (value >> 6)) + Str(0x80 + (value & 0x3F));
60
61
1.04k
  if (value <= 0xFFFF)
62
625
    return Str(0xE0 + (value >> 12)) + Str(0x80 + ((value >> 6) & 0x3F)) +
63
625
           Str(0x80 + (value & 0x3F));
64
65
422
  return Str(0xF0 + (value >> 18)) + Str(0x80 + ((value >> 12) & 0x3F)) +
66
422
         Str(0x80 + ((value >> 6) & 0x3F)) + Str(0x80 + (value & 0x3F));
67
1.04k
}
68
69
// Escape
70
// . Escapes the sequence starting 'in' (it must begin with a '\' or single
71
// quote)
72
//   and returns the result.
73
// . Throws if it's an unknown escape character.
74
46.3k
std::string Escape(Stream& in) {
75
  // eat slash
76
46.3k
  char escape = in.get();
77
78
  // switch on escape character
79
46.3k
  char ch = in.get();
80
81
  // first do single quote, since it's easier
82
46.3k
  if (escape == '\'' && ch == '\'')
83
785
    return "\'";
84
85
  // now do the slash (we're not gonna check if it's a slash - you better pass
86
  // one!)
87
45.5k
  switch (ch) {
88
883
    case '0':
89
883
      return std::string(1, '\x00');
90
219
    case 'a':
91
219
      return "\x07";
92
980
    case 'b':
93
980
      return "\x08";
94
898
    case 't':
95
5.45k
    case '\t':
96
5.45k
      return "\x09";
97
8.57k
    case 'n':
98
8.57k
      return "\x0A";
99
321
    case 'v':
100
321
      return "\x0B";
101
325
    case 'f':
102
325
      return "\x0C";
103
202
    case 'r':
104
202
      return "\x0D";
105
458
    case 'e':
106
458
      return "\x1B";
107
463
    case ' ':
108
463
      return R"( )";
109
7.68k
    case '\"':
110
7.68k
      return "\"";
111
327
    case '\'':
112
327
      return "\'";
113
621
    case '\\':
114
621
      return "\\";
115
333
    case '/':
116
333
      return "/";
117
647
    case 'N':
118
647
      return "\xC2\x85";      // NEL (U+0085)
119
232
    case '_':
120
232
      return "\xC2\xA0";      // NBSP (U+00A0)
121
12.6k
    case 'L':
122
12.6k
      return "\xE2\x80\xA8";  // LS (U+2028)
123
3.20k
    case 'P':
124
3.20k
      return "\xE2\x80\xA9";  // PS (U+2029)
125
545
    case 'x':
126
545
      return Escape(in, 2);
127
624
    case 'u':
128
624
      return Escape(in, 4);
129
557
    case 'U':
130
557
      return Escape(in, 8);
131
45.5k
  }
132
133
248
  std::stringstream msg;
134
248
  throw ParserException(in.mark(), std::string(ErrorMsg::INVALID_ESCAPE) + ch);
135
45.5k
}
136
}  // namespace Exp
137
}  // namespace YAML