/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 |