/src/flatbuffers/include/flatbuffers/util.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright 2014 Google Inc. All rights reserved. |
3 | | * |
4 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | | * you may not use this file except in compliance with the License. |
6 | | * You may obtain a copy of 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, |
12 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | | * See the License for the specific language governing permissions and |
14 | | * limitations under the License. |
15 | | */ |
16 | | |
17 | | #ifndef FLATBUFFERS_UTIL_H_ |
18 | | #define FLATBUFFERS_UTIL_H_ |
19 | | |
20 | | #include <ctype.h> |
21 | | #include <errno.h> |
22 | | |
23 | | #include "flatbuffers/base.h" |
24 | | #include "flatbuffers/stl_emulation.h" |
25 | | |
26 | | #ifndef FLATBUFFERS_PREFER_PRINTF |
27 | | #include <iomanip> |
28 | | #include <sstream> |
29 | | #else // FLATBUFFERS_PREFER_PRINTF |
30 | | #include <float.h> |
31 | | #include <stdio.h> |
32 | | #endif // FLATBUFFERS_PREFER_PRINTF |
33 | | |
34 | | #include <cmath> |
35 | | #include <limits> |
36 | | #include <string> |
37 | | |
38 | | namespace flatbuffers { |
39 | | |
40 | | // @locale-independent functions for ASCII characters set. |
41 | | |
42 | | // Fast checking that character lies in closed range: [a <= x <= b] |
43 | | // using one compare (conditional branch) operator. |
44 | 547M | inline bool check_ascii_range(char x, char a, char b) { |
45 | 547M | FLATBUFFERS_ASSERT(a <= b); |
46 | | // (Hacker's Delight): `a <= x <= b` <=> `(x-a) <={u} (b-a)`. |
47 | | // The x, a, b will be promoted to int and subtracted without overflow. |
48 | 547M | return static_cast<unsigned int>(x - a) <= static_cast<unsigned int>(b - a); |
49 | 547M | } |
50 | | |
51 | | // Case-insensitive isalpha |
52 | 248M | inline bool is_alpha(char c) { |
53 | | // ASCII only: alpha to upper case => reset bit 0x20 (~0x20 = 0xDF). |
54 | 248M | return check_ascii_range(c & 0xDF, 'a' & 0xDF, 'z' & 0xDF); |
55 | 248M | } |
56 | | |
57 | | // Check for uppercase alpha |
58 | 0 | inline bool is_alpha_upper(char c) { return check_ascii_range(c, 'A', 'Z'); } |
59 | | |
60 | | // Check (case-insensitive) that `c` is equal to alpha. |
61 | 227M | inline bool is_alpha_char(char c, char alpha) { |
62 | 227M | FLATBUFFERS_ASSERT(is_alpha(alpha)); |
63 | | // ASCII only: alpha to upper case => reset bit 0x20 (~0x20 = 0xDF). |
64 | 227M | return ((c & 0xDF) == (alpha & 0xDF)); |
65 | 227M | } |
66 | | |
67 | | // https://en.cppreference.com/w/cpp/string/byte/isxdigit |
68 | | // isdigit and isxdigit are the only standard narrow character classification |
69 | | // functions that are not affected by the currently installed C locale. although |
70 | | // some implementations (e.g. Microsoft in 1252 codepage) may classify |
71 | | // additional single-byte characters as digits. |
72 | 268M | inline bool is_digit(char c) { return check_ascii_range(c, '0', '9'); } |
73 | | |
74 | 3.27M | inline bool is_xdigit(char c) { |
75 | | // Replace by look-up table. |
76 | 3.27M | return is_digit(c) || check_ascii_range(c & 0xDF, 'a' & 0xDF, 'f' & 0xDF); |
77 | 3.27M | } |
78 | | |
79 | | // Case-insensitive isalnum |
80 | 38.3k | inline bool is_alnum(char c) { return is_alpha(c) || is_digit(c); } |
81 | | |
82 | 0 | inline char CharToUpper(char c) { |
83 | 0 | return static_cast<char>(::toupper(static_cast<unsigned char>(c))); |
84 | 0 | } |
85 | | |
86 | 0 | inline char CharToLower(char c) { |
87 | 0 | return static_cast<char>(::tolower(static_cast<unsigned char>(c))); |
88 | 0 | } |
89 | | |
90 | | // @end-locale-independent functions for ASCII character set |
91 | | |
92 | | #ifdef FLATBUFFERS_PREFER_PRINTF |
93 | | template <typename T> |
94 | | size_t IntToDigitCount(T t) { |
95 | | size_t digit_count = 0; |
96 | | // Count the sign for negative numbers |
97 | | if (t < 0) digit_count++; |
98 | | // Count a single 0 left of the dot for fractional numbers |
99 | | if (-1 < t && t < 1) digit_count++; |
100 | | // Count digits until fractional part |
101 | | T eps = std::numeric_limits<T>::epsilon(); |
102 | | while (t <= (-1 + eps) || (1 - eps) <= t) { |
103 | | t /= 10; |
104 | | digit_count++; |
105 | | } |
106 | | return digit_count; |
107 | | } |
108 | | |
109 | | template <typename T> |
110 | | size_t NumToStringWidth(T t, int precision = 0) { |
111 | | size_t string_width = IntToDigitCount(t); |
112 | | // Count the dot for floating point numbers |
113 | | if (precision) string_width += (precision + 1); |
114 | | return string_width; |
115 | | } |
116 | | |
117 | | template <typename T> |
118 | | std::string NumToStringImplWrapper(T t, const char* fmt, int precision = 0) { |
119 | | size_t string_width = NumToStringWidth(t, precision); |
120 | | std::string s(string_width, 0x00); |
121 | | // Allow snprintf to use std::string trailing null to detect buffer overflow |
122 | | snprintf(const_cast<char*>(s.data()), (s.size() + 1), fmt, string_width, t); |
123 | | return s; |
124 | | } |
125 | | #endif // FLATBUFFERS_PREFER_PRINTF |
126 | | |
127 | | // Convert an integer or floating point value to a string. |
128 | | // In contrast to std::stringstream, "char" values are |
129 | | // converted to a string of digits, and we don't use scientific notation. |
130 | | template <typename T> |
131 | 3.70M | std::string NumToString(T t) { |
132 | | // clang-format off |
133 | | |
134 | 3.70M | #ifndef FLATBUFFERS_PREFER_PRINTF |
135 | 3.70M | std::stringstream ss; |
136 | 3.70M | ss << t; |
137 | 3.70M | return ss.str(); |
138 | | #else // FLATBUFFERS_PREFER_PRINTF |
139 | | auto v = static_cast<long long>(t); |
140 | | return NumToStringImplWrapper(v, "%.*lld"); |
141 | | #endif // FLATBUFFERS_PREFER_PRINTF |
142 | | // clang-format on |
143 | 3.70M | } Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::NumToString<bool>(bool) std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::NumToString<unsigned long>(unsigned long) Line | Count | Source | 131 | 392k | std::string NumToString(T t) { | 132 | | // clang-format off | 133 | | | 134 | 392k | #ifndef FLATBUFFERS_PREFER_PRINTF | 135 | 392k | std::stringstream ss; | 136 | 392k | ss << t; | 137 | 392k | return ss.str(); | 138 | | #else // FLATBUFFERS_PREFER_PRINTF | 139 | | auto v = static_cast<long long>(t); | 140 | | return NumToStringImplWrapper(v, "%.*lld"); | 141 | | #endif // FLATBUFFERS_PREFER_PRINTF | 142 | | // clang-format on | 143 | 392k | } |
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::NumToString<long>(long) Line | Count | Source | 131 | 1.23M | std::string NumToString(T t) { | 132 | | // clang-format off | 133 | | | 134 | 1.23M | #ifndef FLATBUFFERS_PREFER_PRINTF | 135 | 1.23M | std::stringstream ss; | 136 | 1.23M | ss << t; | 137 | 1.23M | return ss.str(); | 138 | | #else // FLATBUFFERS_PREFER_PRINTF | 139 | | auto v = static_cast<long long>(t); | 140 | | return NumToStringImplWrapper(v, "%.*lld"); | 141 | | #endif // FLATBUFFERS_PREFER_PRINTF | 142 | | // clang-format on | 143 | 1.23M | } |
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::NumToString<int>(int) Line | Count | Source | 131 | 1.12M | std::string NumToString(T t) { | 132 | | // clang-format off | 133 | | | 134 | 1.12M | #ifndef FLATBUFFERS_PREFER_PRINTF | 135 | 1.12M | std::stringstream ss; | 136 | 1.12M | ss << t; | 137 | 1.12M | return ss.str(); | 138 | | #else // FLATBUFFERS_PREFER_PRINTF | 139 | | auto v = static_cast<long long>(t); | 140 | | return NumToStringImplWrapper(v, "%.*lld"); | 141 | | #endif // FLATBUFFERS_PREFER_PRINTF | 142 | | // clang-format on | 143 | 1.12M | } |
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::NumToString<unsigned int>(unsigned int) Line | Count | Source | 131 | 759k | std::string NumToString(T t) { | 132 | | // clang-format off | 133 | | | 134 | 759k | #ifndef FLATBUFFERS_PREFER_PRINTF | 135 | 759k | std::stringstream ss; | 136 | 759k | ss << t; | 137 | 759k | return ss.str(); | 138 | | #else // FLATBUFFERS_PREFER_PRINTF | 139 | | auto v = static_cast<long long>(t); | 140 | | return NumToStringImplWrapper(v, "%.*lld"); | 141 | | #endif // FLATBUFFERS_PREFER_PRINTF | 142 | | // clang-format on | 143 | 759k | } |
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::NumToString<short>(short) Line | Count | Source | 131 | 63.5k | std::string NumToString(T t) { | 132 | | // clang-format off | 133 | | | 134 | 63.5k | #ifndef FLATBUFFERS_PREFER_PRINTF | 135 | 63.5k | std::stringstream ss; | 136 | 63.5k | ss << t; | 137 | 63.5k | return ss.str(); | 138 | | #else // FLATBUFFERS_PREFER_PRINTF | 139 | | auto v = static_cast<long long>(t); | 140 | | return NumToStringImplWrapper(v, "%.*lld"); | 141 | | #endif // FLATBUFFERS_PREFER_PRINTF | 142 | | // clang-format on | 143 | 63.5k | } |
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::NumToString<unsigned short>(unsigned short) Line | Count | Source | 131 | 131k | std::string NumToString(T t) { | 132 | | // clang-format off | 133 | | | 134 | 131k | #ifndef FLATBUFFERS_PREFER_PRINTF | 135 | 131k | std::stringstream ss; | 136 | 131k | ss << t; | 137 | 131k | return ss.str(); | 138 | | #else // FLATBUFFERS_PREFER_PRINTF | 139 | | auto v = static_cast<long long>(t); | 140 | | return NumToStringImplWrapper(v, "%.*lld"); | 141 | | #endif // FLATBUFFERS_PREFER_PRINTF | 142 | | // clang-format on | 143 | 131k | } |
|
144 | | // Avoid char types used as character data. |
145 | | template <> |
146 | 66.0k | inline std::string NumToString<signed char>(signed char t) { |
147 | 66.0k | return NumToString(static_cast<int>(t)); |
148 | 66.0k | } |
149 | | template <> |
150 | 91.5k | inline std::string NumToString<unsigned char>(unsigned char t) { |
151 | 91.5k | return NumToString(static_cast<int>(t)); |
152 | 91.5k | } |
153 | | template <> |
154 | 23.5k | inline std::string NumToString<char>(char t) { |
155 | 23.5k | return NumToString(static_cast<int>(t)); |
156 | 23.5k | } |
157 | | |
158 | | // Special versions for floats/doubles. |
159 | | template <typename T> |
160 | 827k | std::string FloatToString(T t, int precision) { |
161 | | // clang-format off |
162 | | |
163 | 827k | #ifndef FLATBUFFERS_PREFER_PRINTF |
164 | | // to_string() prints different numbers of digits for floats depending on |
165 | | // platform and isn't available on Android, so we use stringstream |
166 | 827k | std::stringstream ss; |
167 | | // Use std::fixed to suppress scientific notation. |
168 | 827k | ss << std::fixed; |
169 | | // Default precision is 6, we want that to be higher for doubles. |
170 | 827k | ss << std::setprecision(precision); |
171 | 827k | ss << t; |
172 | 827k | auto s = ss.str(); |
173 | | #else // FLATBUFFERS_PREFER_PRINTF |
174 | | auto v = static_cast<double>(t); |
175 | | auto s = NumToStringImplWrapper(v, "%0.*f", precision); |
176 | | #endif // FLATBUFFERS_PREFER_PRINTF |
177 | | // clang-format on |
178 | | // Sadly, std::fixed turns "1" into "1.00000", so here we undo that. |
179 | 827k | auto p = s.find_last_not_of('0'); |
180 | 827k | if (p != std::string::npos) { |
181 | | // Strip trailing zeroes. If it is a whole number, keep one zero. |
182 | 827k | s.resize(p + (s[p] == '.' ? 2 : 1)); |
183 | 827k | } |
184 | 827k | return s; |
185 | 827k | } std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::FloatToString<double>(double, int) Line | Count | Source | 160 | 767k | std::string FloatToString(T t, int precision) { | 161 | | // clang-format off | 162 | | | 163 | 767k | #ifndef FLATBUFFERS_PREFER_PRINTF | 164 | | // to_string() prints different numbers of digits for floats depending on | 165 | | // platform and isn't available on Android, so we use stringstream | 166 | 767k | std::stringstream ss; | 167 | | // Use std::fixed to suppress scientific notation. | 168 | 767k | ss << std::fixed; | 169 | | // Default precision is 6, we want that to be higher for doubles. | 170 | 767k | ss << std::setprecision(precision); | 171 | 767k | ss << t; | 172 | 767k | auto s = ss.str(); | 173 | | #else // FLATBUFFERS_PREFER_PRINTF | 174 | | auto v = static_cast<double>(t); | 175 | | auto s = NumToStringImplWrapper(v, "%0.*f", precision); | 176 | | #endif // FLATBUFFERS_PREFER_PRINTF | 177 | | // clang-format on | 178 | | // Sadly, std::fixed turns "1" into "1.00000", so here we undo that. | 179 | 767k | auto p = s.find_last_not_of('0'); | 180 | 767k | if (p != std::string::npos) { | 181 | | // Strip trailing zeroes. If it is a whole number, keep one zero. | 182 | 767k | s.resize(p + (s[p] == '.' ? 2 : 1)); | 183 | 767k | } | 184 | 767k | return s; | 185 | 767k | } |
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::FloatToString<float>(float, int) Line | Count | Source | 160 | 60.4k | std::string FloatToString(T t, int precision) { | 161 | | // clang-format off | 162 | | | 163 | 60.4k | #ifndef FLATBUFFERS_PREFER_PRINTF | 164 | | // to_string() prints different numbers of digits for floats depending on | 165 | | // platform and isn't available on Android, so we use stringstream | 166 | 60.4k | std::stringstream ss; | 167 | | // Use std::fixed to suppress scientific notation. | 168 | 60.4k | ss << std::fixed; | 169 | | // Default precision is 6, we want that to be higher for doubles. | 170 | 60.4k | ss << std::setprecision(precision); | 171 | 60.4k | ss << t; | 172 | 60.4k | auto s = ss.str(); | 173 | | #else // FLATBUFFERS_PREFER_PRINTF | 174 | | auto v = static_cast<double>(t); | 175 | | auto s = NumToStringImplWrapper(v, "%0.*f", precision); | 176 | | #endif // FLATBUFFERS_PREFER_PRINTF | 177 | | // clang-format on | 178 | | // Sadly, std::fixed turns "1" into "1.00000", so here we undo that. | 179 | 60.4k | auto p = s.find_last_not_of('0'); | 180 | 60.4k | if (p != std::string::npos) { | 181 | | // Strip trailing zeroes. If it is a whole number, keep one zero. | 182 | 60.4k | s.resize(p + (s[p] == '.' ? 2 : 1)); | 183 | 60.4k | } | 184 | 60.4k | return s; | 185 | 60.4k | } |
|
186 | | |
187 | | template <> |
188 | 767k | inline std::string NumToString<double>(double t) { |
189 | 767k | return FloatToString(t, 12); |
190 | 767k | } |
191 | | template <> |
192 | 60.4k | inline std::string NumToString<float>(float t) { |
193 | 60.4k | return FloatToString(t, 6); |
194 | 60.4k | } |
195 | | |
196 | | // Convert an integer value to a hexadecimal string. |
197 | | // The returned string length is always xdigits long, prefixed by 0 digits. |
198 | | // For example, IntToStringHex(0x23, 8) returns the string "00000023". |
199 | 374k | inline std::string IntToStringHex(int i, int xdigits) { |
200 | 374k | FLATBUFFERS_ASSERT(i >= 0); |
201 | | // clang-format off |
202 | | |
203 | 374k | #ifndef FLATBUFFERS_PREFER_PRINTF |
204 | 374k | std::stringstream ss; |
205 | 374k | ss << std::setw(xdigits) << std::setfill('0') << std::hex << std::uppercase |
206 | 374k | << i; |
207 | 374k | return ss.str(); |
208 | | #else // FLATBUFFERS_PREFER_PRINTF |
209 | | return NumToStringImplWrapper(i, "%.*X", xdigits); |
210 | | #endif // FLATBUFFERS_PREFER_PRINTF |
211 | | // clang-format on |
212 | 374k | } |
213 | | |
214 | | // clang-format off |
215 | | // Use locale independent functions {strtod_l, strtof_l, strtoll_l, strtoull_l}. |
216 | | #if defined(FLATBUFFERS_LOCALE_INDEPENDENT) && (FLATBUFFERS_LOCALE_INDEPENDENT > 0) |
217 | | class ClassicLocale { |
218 | | #ifdef _MSC_VER |
219 | | typedef _locale_t locale_type; |
220 | | #else |
221 | | typedef locale_t locale_type; // POSIX.1-2008 locale_t type |
222 | | #endif |
223 | | ClassicLocale(); |
224 | | ~ClassicLocale(); |
225 | | locale_type locale_; |
226 | | static ClassicLocale instance_; |
227 | | public: |
228 | 226M | static locale_type Get() { return instance_.locale_; } |
229 | | }; |
230 | | |
231 | | #ifdef _MSC_VER |
232 | | #define __strtoull_impl(s, pe, b) _strtoui64_l(s, pe, b, ClassicLocale::Get()) |
233 | | #define __strtoll_impl(s, pe, b) _strtoi64_l(s, pe, b, ClassicLocale::Get()) |
234 | | #define __strtod_impl(s, pe) _strtod_l(s, pe, ClassicLocale::Get()) |
235 | | #define __strtof_impl(s, pe) _strtof_l(s, pe, ClassicLocale::Get()) |
236 | | #else |
237 | 65.7M | #define __strtoull_impl(s, pe, b) strtoull_l(s, pe, b, ClassicLocale::Get()) |
238 | 159M | #define __strtoll_impl(s, pe, b) strtoll_l(s, pe, b, ClassicLocale::Get()) |
239 | 1.04M | #define __strtod_impl(s, pe) strtod_l(s, pe, ClassicLocale::Get()) |
240 | 176k | #define __strtof_impl(s, pe) strtof_l(s, pe, ClassicLocale::Get()) |
241 | | #endif |
242 | | #else |
243 | | #define __strtod_impl(s, pe) strtod(s, pe) |
244 | | #define __strtof_impl(s, pe) static_cast<float>(strtod(s, pe)) |
245 | | #ifdef _MSC_VER |
246 | | #define __strtoull_impl(s, pe, b) _strtoui64(s, pe, b) |
247 | | #define __strtoll_impl(s, pe, b) _strtoi64(s, pe, b) |
248 | | #else |
249 | | #define __strtoull_impl(s, pe, b) strtoull(s, pe, b) |
250 | | #define __strtoll_impl(s, pe, b) strtoll(s, pe, b) |
251 | | #endif |
252 | | #endif |
253 | | |
254 | | inline void strtoval_impl(int64_t *val, const char *str, char **endptr, |
255 | 159M | int base) { |
256 | 159M | *val = __strtoll_impl(str, endptr, base); |
257 | 159M | } |
258 | | |
259 | | inline void strtoval_impl(uint64_t *val, const char *str, char **endptr, |
260 | 65.7M | int base) { |
261 | 65.7M | *val = __strtoull_impl(str, endptr, base); |
262 | 65.7M | } |
263 | | |
264 | 1.04M | inline void strtoval_impl(double *val, const char *str, char **endptr) { |
265 | 1.04M | *val = __strtod_impl(str, endptr); |
266 | 1.04M | } |
267 | | |
268 | | // UBSAN: double to float is safe if numeric_limits<float>::is_iec559 is true. |
269 | | FLATBUFFERS_SUPPRESS_UBSAN("float-cast-overflow") |
270 | 176k | inline void strtoval_impl(float *val, const char *str, char **endptr) { |
271 | 176k | *val = __strtof_impl(str, endptr); |
272 | 176k | } |
273 | | #undef __strtoull_impl |
274 | | #undef __strtoll_impl |
275 | | #undef __strtod_impl |
276 | | #undef __strtof_impl |
277 | | // clang-format on |
278 | | |
279 | | // Adaptor for strtoull()/strtoll(). |
280 | | // Flatbuffers accepts numbers with any count of leading zeros (-009 is -9), |
281 | | // while strtoll with base=0 interprets first leading zero as octal prefix. |
282 | | // In future, it is possible to add prefixed 0b0101. |
283 | | // 1) Checks errno code for overflow condition (out of range). |
284 | | // 2) If base <= 0, function try to detect base of number by prefix. |
285 | | // |
286 | | // Return value (like strtoull and strtoll, but reject partial result): |
287 | | // - If successful, an integer value corresponding to the str is returned. |
288 | | // - If full string conversion can't be performed, 0 is returned. |
289 | | // - If the converted value falls out of range of corresponding return type, a |
290 | | // range error occurs. In this case value MAX(T)/MIN(T) is returned. |
291 | | template <typename T> |
292 | | inline bool StringToIntegerImpl(T* val, const char* const str, |
293 | | const int base = 0, |
294 | 450M | const bool check_errno = true) { |
295 | | // T is int64_t or uint64_T |
296 | 450M | FLATBUFFERS_ASSERT(str); |
297 | 450M | if (base <= 0) { |
298 | 224M | auto s = str; |
299 | 224M | while (*s && !is_digit(*s)) s++; |
300 | 224M | if (s[0] == '0' && is_alpha_char(s[1], 'X')) |
301 | 107k | return StringToIntegerImpl(val, str, 16, check_errno); |
302 | | // if a prefix not match, try base=10 |
303 | 224M | return StringToIntegerImpl(val, str, 10, check_errno); |
304 | 225M | } else { |
305 | 225M | if (check_errno) errno = 0; // clear thread-local errno |
306 | 225M | auto endptr = str; |
307 | 225M | strtoval_impl(val, str, const_cast<char**>(&endptr), base); |
308 | 225M | if ((*endptr != '\0') || (endptr == str)) { |
309 | 62.9k | *val = 0; // erase partial result |
310 | 62.9k | return false; // invalid string |
311 | 62.9k | } |
312 | | // errno is out-of-range, return MAX/MIN |
313 | 225M | if (check_errno && errno) return false; |
314 | 225M | return true; |
315 | 225M | } |
316 | 450M | } Unexecuted instantiation: bool flatbuffers::StringToIntegerImpl<long>(long*, char const*, int, bool) Unexecuted instantiation: bool flatbuffers::StringToIntegerImpl<unsigned long>(unsigned long*, char const*, int, bool) bool flatbuffers::StringToIntegerImpl<long>(long*, char const*, int, bool) Line | Count | Source | 294 | 318M | const bool check_errno = true) { | 295 | | // T is int64_t or uint64_T | 296 | 318M | FLATBUFFERS_ASSERT(str); | 297 | 318M | if (base <= 0) { | 298 | 158M | auto s = str; | 299 | 159M | while (*s && !is_digit(*s)) s++; | 300 | 158M | if (s[0] == '0' && is_alpha_char(s[1], 'X')) | 301 | 73.3k | return StringToIntegerImpl(val, str, 16, check_errno); | 302 | | // if a prefix not match, try base=10 | 303 | 158M | return StringToIntegerImpl(val, str, 10, check_errno); | 304 | 159M | } else { | 305 | 159M | if (check_errno) errno = 0; // clear thread-local errno | 306 | 159M | auto endptr = str; | 307 | 159M | strtoval_impl(val, str, const_cast<char**>(&endptr), base); | 308 | 159M | if ((*endptr != '\0') || (endptr == str)) { | 309 | 54.7k | *val = 0; // erase partial result | 310 | 54.7k | return false; // invalid string | 311 | 54.7k | } | 312 | | // errno is out-of-range, return MAX/MIN | 313 | 159M | if (check_errno && errno) return false; | 314 | 159M | return true; | 315 | 159M | } | 316 | 318M | } |
bool flatbuffers::StringToIntegerImpl<unsigned long>(unsigned long*, char const*, int, bool) Line | Count | Source | 294 | 131M | const bool check_errno = true) { | 295 | | // T is int64_t or uint64_T | 296 | 131M | FLATBUFFERS_ASSERT(str); | 297 | 131M | if (base <= 0) { | 298 | 65.4M | auto s = str; | 299 | 65.5M | while (*s && !is_digit(*s)) s++; | 300 | 65.4M | if (s[0] == '0' && is_alpha_char(s[1], 'X')) | 301 | 33.6k | return StringToIntegerImpl(val, str, 16, check_errno); | 302 | | // if a prefix not match, try base=10 | 303 | 65.4M | return StringToIntegerImpl(val, str, 10, check_errno); | 304 | 65.7M | } else { | 305 | 65.7M | if (check_errno) errno = 0; // clear thread-local errno | 306 | 65.7M | auto endptr = str; | 307 | 65.7M | strtoval_impl(val, str, const_cast<char**>(&endptr), base); | 308 | 65.7M | if ((*endptr != '\0') || (endptr == str)) { | 309 | 8.15k | *val = 0; // erase partial result | 310 | 8.15k | return false; // invalid string | 311 | 8.15k | } | 312 | | // errno is out-of-range, return MAX/MIN | 313 | 65.7M | if (check_errno && errno) return false; | 314 | 65.7M | return true; | 315 | 65.7M | } | 316 | 131M | } |
|
317 | | |
318 | | template <typename T> |
319 | 1.21M | inline bool StringToFloatImpl(T* val, const char* const str) { |
320 | | // Type T must be either float or double. |
321 | 1.21M | FLATBUFFERS_ASSERT(str && val); |
322 | 1.21M | auto end = str; |
323 | 1.21M | strtoval_impl(val, str, const_cast<char**>(&end)); |
324 | 1.21M | auto done = (end != str) && (*end == '\0'); |
325 | 1.21M | if (!done) *val = 0; // erase partial result |
326 | 1.21M | if (done && std::isnan(*val)) { |
327 | 15.6k | *val = std::numeric_limits<T>::quiet_NaN(); |
328 | 15.6k | } |
329 | 1.21M | return done; |
330 | 1.21M | } bool flatbuffers::StringToFloatImpl<double>(double*, char const*) Line | Count | Source | 319 | 1.04M | inline bool StringToFloatImpl(T* val, const char* const str) { | 320 | | // Type T must be either float or double. | 321 | 1.04M | FLATBUFFERS_ASSERT(str && val); | 322 | 1.04M | auto end = str; | 323 | 1.04M | strtoval_impl(val, str, const_cast<char**>(&end)); | 324 | 1.04M | auto done = (end != str) && (*end == '\0'); | 325 | 1.04M | if (!done) *val = 0; // erase partial result | 326 | 1.04M | if (done && std::isnan(*val)) { | 327 | 8.88k | *val = std::numeric_limits<T>::quiet_NaN(); | 328 | 8.88k | } | 329 | 1.04M | return done; | 330 | 1.04M | } |
bool flatbuffers::StringToFloatImpl<float>(float*, char const*) Line | Count | Source | 319 | 176k | inline bool StringToFloatImpl(T* val, const char* const str) { | 320 | | // Type T must be either float or double. | 321 | 176k | FLATBUFFERS_ASSERT(str && val); | 322 | 176k | auto end = str; | 323 | 176k | strtoval_impl(val, str, const_cast<char**>(&end)); | 324 | 176k | auto done = (end != str) && (*end == '\0'); | 325 | 176k | if (!done) *val = 0; // erase partial result | 326 | 176k | if (done && std::isnan(*val)) { | 327 | 6.74k | *val = std::numeric_limits<T>::quiet_NaN(); | 328 | 6.74k | } | 329 | 176k | return done; | 330 | 176k | } |
|
331 | | |
332 | | // Convert a string to an instance of T. |
333 | | // Return value (matched with StringToInteger64Impl and strtod): |
334 | | // - If successful, a numeric value corresponding to the str is returned. |
335 | | // - If full string conversion can't be performed, 0 is returned. |
336 | | // - If the converted value falls out of range of corresponding return type, a |
337 | | // range error occurs. In this case value MAX(T)/MIN(T) is returned. |
338 | | template <typename T> |
339 | 81.8M | inline bool StringToNumber(const char* s, T* val) { |
340 | | // Assert on `unsigned long` and `signed long` on LP64. |
341 | | // If it is necessary, it could be solved with flatbuffers::enable_if<B,T>. |
342 | 81.8M | static_assert(sizeof(T) < sizeof(int64_t), "unexpected type T"); |
343 | 81.8M | FLATBUFFERS_ASSERT(s && val); |
344 | 81.8M | int64_t i64; |
345 | | // The errno check isn't needed, will return MAX/MIN on overflow. |
346 | 81.8M | if (StringToIntegerImpl(&i64, s, 0, false)) { |
347 | 81.7M | const int64_t max = (flatbuffers::numeric_limits<T>::max)(); |
348 | 81.7M | const int64_t min = flatbuffers::numeric_limits<T>::lowest(); |
349 | 81.7M | if (i64 > max) { |
350 | 30.0k | *val = static_cast<T>(max); |
351 | 30.0k | return false; |
352 | 30.0k | } |
353 | 81.7M | if (i64 < min) { |
354 | | // For unsigned types return max to distinguish from |
355 | | // "no conversion can be performed" when 0 is returned. |
356 | 74.3k | *val = static_cast<T>(flatbuffers::is_unsigned<T>::value ? max : min); |
357 | 74.3k | return false; |
358 | 74.3k | } |
359 | 81.6M | *val = static_cast<T>(i64); |
360 | 81.6M | return true; |
361 | 81.7M | } |
362 | 48.0k | *val = 0; |
363 | 48.0k | return false; |
364 | 81.8M | } bool flatbuffers::StringToNumber<unsigned char>(char const*, unsigned char*) Line | Count | Source | 339 | 309k | inline bool StringToNumber(const char* s, T* val) { | 340 | | // Assert on `unsigned long` and `signed long` on LP64. | 341 | | // If it is necessary, it could be solved with flatbuffers::enable_if<B,T>. | 342 | 309k | static_assert(sizeof(T) < sizeof(int64_t), "unexpected type T"); | 343 | 309k | FLATBUFFERS_ASSERT(s && val); | 344 | 309k | int64_t i64; | 345 | | // The errno check isn't needed, will return MAX/MIN on overflow. | 346 | 309k | if (StringToIntegerImpl(&i64, s, 0, false)) { | 347 | 296k | const int64_t max = (flatbuffers::numeric_limits<T>::max)(); | 348 | 296k | const int64_t min = flatbuffers::numeric_limits<T>::lowest(); | 349 | 296k | if (i64 > max) { | 350 | 5.59k | *val = static_cast<T>(max); | 351 | 5.59k | return false; | 352 | 5.59k | } | 353 | 290k | if (i64 < min) { | 354 | | // For unsigned types return max to distinguish from | 355 | | // "no conversion can be performed" when 0 is returned. | 356 | 15.6k | *val = static_cast<T>(flatbuffers::is_unsigned<T>::value ? max : min); | 357 | 15.6k | return false; | 358 | 15.6k | } | 359 | 274k | *val = static_cast<T>(i64); | 360 | 274k | return true; | 361 | 290k | } | 362 | 13.8k | *val = 0; | 363 | 13.8k | return false; | 364 | 309k | } |
bool flatbuffers::StringToNumber<unsigned short>(char const*, unsigned short*) Line | Count | Source | 339 | 80.5M | inline bool StringToNumber(const char* s, T* val) { | 340 | | // Assert on `unsigned long` and `signed long` on LP64. | 341 | | // If it is necessary, it could be solved with flatbuffers::enable_if<B,T>. | 342 | 80.5M | static_assert(sizeof(T) < sizeof(int64_t), "unexpected type T"); | 343 | 80.5M | FLATBUFFERS_ASSERT(s && val); | 344 | 80.5M | int64_t i64; | 345 | | // The errno check isn't needed, will return MAX/MIN on overflow. | 346 | 80.5M | if (StringToIntegerImpl(&i64, s, 0, false)) { | 347 | 80.5M | const int64_t max = (flatbuffers::numeric_limits<T>::max)(); | 348 | 80.5M | const int64_t min = flatbuffers::numeric_limits<T>::lowest(); | 349 | 80.5M | if (i64 > max) { | 350 | 4.45k | *val = static_cast<T>(max); | 351 | 4.45k | return false; | 352 | 4.45k | } | 353 | 80.5M | if (i64 < min) { | 354 | | // For unsigned types return max to distinguish from | 355 | | // "no conversion can be performed" when 0 is returned. | 356 | 18.4k | *val = static_cast<T>(flatbuffers::is_unsigned<T>::value ? max : min); | 357 | 18.4k | return false; | 358 | 18.4k | } | 359 | 80.4M | *val = static_cast<T>(i64); | 360 | 80.4M | return true; | 361 | 80.5M | } | 362 | 5.79k | *val = 0; | 363 | 5.79k | return false; | 364 | 80.5M | } |
bool flatbuffers::StringToNumber<unsigned int>(char const*, unsigned int*) Line | Count | Source | 339 | 531k | inline bool StringToNumber(const char* s, T* val) { | 340 | | // Assert on `unsigned long` and `signed long` on LP64. | 341 | | // If it is necessary, it could be solved with flatbuffers::enable_if<B,T>. | 342 | 531k | static_assert(sizeof(T) < sizeof(int64_t), "unexpected type T"); | 343 | 531k | FLATBUFFERS_ASSERT(s && val); | 344 | 531k | int64_t i64; | 345 | | // The errno check isn't needed, will return MAX/MIN on overflow. | 346 | 531k | if (StringToIntegerImpl(&i64, s, 0, false)) { | 347 | 525k | const int64_t max = (flatbuffers::numeric_limits<T>::max)(); | 348 | 525k | const int64_t min = flatbuffers::numeric_limits<T>::lowest(); | 349 | 525k | if (i64 > max) { | 350 | 4.20k | *val = static_cast<T>(max); | 351 | 4.20k | return false; | 352 | 4.20k | } | 353 | 521k | if (i64 < min) { | 354 | | // For unsigned types return max to distinguish from | 355 | | // "no conversion can be performed" when 0 is returned. | 356 | 10.9k | *val = static_cast<T>(flatbuffers::is_unsigned<T>::value ? max : min); | 357 | 10.9k | return false; | 358 | 10.9k | } | 359 | 510k | *val = static_cast<T>(i64); | 360 | 510k | return true; | 361 | 521k | } | 362 | 6.49k | *val = 0; | 363 | 6.49k | return false; | 364 | 531k | } |
bool flatbuffers::StringToNumber<signed char>(char const*, signed char*) Line | Count | Source | 339 | 166k | inline bool StringToNumber(const char* s, T* val) { | 340 | | // Assert on `unsigned long` and `signed long` on LP64. | 341 | | // If it is necessary, it could be solved with flatbuffers::enable_if<B,T>. | 342 | 166k | static_assert(sizeof(T) < sizeof(int64_t), "unexpected type T"); | 343 | 166k | FLATBUFFERS_ASSERT(s && val); | 344 | 166k | int64_t i64; | 345 | | // The errno check isn't needed, will return MAX/MIN on overflow. | 346 | 166k | if (StringToIntegerImpl(&i64, s, 0, false)) { | 347 | 159k | const int64_t max = (flatbuffers::numeric_limits<T>::max)(); | 348 | 159k | const int64_t min = flatbuffers::numeric_limits<T>::lowest(); | 349 | 159k | if (i64 > max) { | 350 | 7.52k | *val = static_cast<T>(max); | 351 | 7.52k | return false; | 352 | 7.52k | } | 353 | 151k | if (i64 < min) { | 354 | | // For unsigned types return max to distinguish from | 355 | | // "no conversion can be performed" when 0 is returned. | 356 | 9.33k | *val = static_cast<T>(flatbuffers::is_unsigned<T>::value ? max : min); | 357 | 9.33k | return false; | 358 | 9.33k | } | 359 | 142k | *val = static_cast<T>(i64); | 360 | 142k | return true; | 361 | 151k | } | 362 | 7.28k | *val = 0; | 363 | 7.28k | return false; | 364 | 166k | } |
bool flatbuffers::StringToNumber<short>(char const*, short*) Line | Count | Source | 339 | 104k | inline bool StringToNumber(const char* s, T* val) { | 340 | | // Assert on `unsigned long` and `signed long` on LP64. | 341 | | // If it is necessary, it could be solved with flatbuffers::enable_if<B,T>. | 342 | 104k | static_assert(sizeof(T) < sizeof(int64_t), "unexpected type T"); | 343 | 104k | FLATBUFFERS_ASSERT(s && val); | 344 | 104k | int64_t i64; | 345 | | // The errno check isn't needed, will return MAX/MIN on overflow. | 346 | 104k | if (StringToIntegerImpl(&i64, s, 0, false)) { | 347 | 97.4k | const int64_t max = (flatbuffers::numeric_limits<T>::max)(); | 348 | 97.4k | const int64_t min = flatbuffers::numeric_limits<T>::lowest(); | 349 | 97.4k | if (i64 > max) { | 350 | 3.08k | *val = static_cast<T>(max); | 351 | 3.08k | return false; | 352 | 3.08k | } | 353 | 94.3k | if (i64 < min) { | 354 | | // For unsigned types return max to distinguish from | 355 | | // "no conversion can be performed" when 0 is returned. | 356 | 10.7k | *val = static_cast<T>(flatbuffers::is_unsigned<T>::value ? max : min); | 357 | 10.7k | return false; | 358 | 10.7k | } | 359 | 83.5k | *val = static_cast<T>(i64); | 360 | 83.5k | return true; | 361 | 94.3k | } | 362 | 7.31k | *val = 0; | 363 | 7.31k | return false; | 364 | 104k | } |
bool flatbuffers::StringToNumber<int>(char const*, int*) Line | Count | Source | 339 | 187k | inline bool StringToNumber(const char* s, T* val) { | 340 | | // Assert on `unsigned long` and `signed long` on LP64. | 341 | | // If it is necessary, it could be solved with flatbuffers::enable_if<B,T>. | 342 | 187k | static_assert(sizeof(T) < sizeof(int64_t), "unexpected type T"); | 343 | 187k | FLATBUFFERS_ASSERT(s && val); | 344 | 187k | int64_t i64; | 345 | | // The errno check isn't needed, will return MAX/MIN on overflow. | 346 | 187k | if (StringToIntegerImpl(&i64, s, 0, false)) { | 347 | 179k | const int64_t max = (flatbuffers::numeric_limits<T>::max)(); | 348 | 179k | const int64_t min = flatbuffers::numeric_limits<T>::lowest(); | 349 | 179k | if (i64 > max) { | 350 | 5.15k | *val = static_cast<T>(max); | 351 | 5.15k | return false; | 352 | 5.15k | } | 353 | 174k | if (i64 < min) { | 354 | | // For unsigned types return max to distinguish from | 355 | | // "no conversion can be performed" when 0 is returned. | 356 | 9.25k | *val = static_cast<T>(flatbuffers::is_unsigned<T>::value ? max : min); | 357 | 9.25k | return false; | 358 | 9.25k | } | 359 | 165k | *val = static_cast<T>(i64); | 360 | 165k | return true; | 361 | 174k | } | 362 | 7.33k | *val = 0; | 363 | 7.33k | return false; | 364 | 187k | } |
|
365 | | |
366 | | template <> |
367 | 77.1M | inline bool StringToNumber<int64_t>(const char* str, int64_t* val) { |
368 | 77.1M | return StringToIntegerImpl(val, str); |
369 | 77.1M | } |
370 | | |
371 | | template <> |
372 | 65.4M | inline bool StringToNumber<uint64_t>(const char* str, uint64_t* val) { |
373 | 65.4M | if (!StringToIntegerImpl(val, str)) return false; |
374 | | // The strtoull accepts negative numbers: |
375 | | // If the minus sign was part of the input sequence, the numeric value |
376 | | // calculated from the sequence of digits is negated as if by unary minus |
377 | | // in the result type, which applies unsigned integer wraparound rules. |
378 | | // Fix this behaviour (except -0). |
379 | 65.4M | if (*val) { |
380 | 210k | auto s = str; |
381 | 218k | while (*s && !is_digit(*s)) s++; |
382 | 210k | s = (s > str) ? (s - 1) : s; // step back to one symbol |
383 | 210k | if (*s == '-') { |
384 | | // For unsigned types return the max to distinguish from |
385 | | // "no conversion can be performed". |
386 | 4.96k | *val = (flatbuffers::numeric_limits<uint64_t>::max)(); |
387 | 4.96k | return false; |
388 | 4.96k | } |
389 | 210k | } |
390 | 65.4M | return true; |
391 | 65.4M | } |
392 | | |
393 | | template <> |
394 | 176k | inline bool StringToNumber(const char* s, float* val) { |
395 | 176k | return StringToFloatImpl(val, s); |
396 | 176k | } |
397 | | |
398 | | template <> |
399 | 1.04M | inline bool StringToNumber(const char* s, double* val) { |
400 | 1.04M | return StringToFloatImpl(val, s); |
401 | 1.04M | } |
402 | | |
403 | 1.02M | inline int64_t StringToInt(const char* s, int base = 10) { |
404 | 1.02M | int64_t val; |
405 | 1.02M | return StringToIntegerImpl(&val, s, base) ? val : 0; |
406 | 1.02M | } |
407 | | |
408 | 320k | inline uint64_t StringToUInt(const char* s, int base = 10) { |
409 | 320k | uint64_t val; |
410 | 320k | return StringToIntegerImpl(&val, s, base) ? val : 0; |
411 | 320k | } |
412 | | |
413 | 0 | inline bool StringIsFlatbufferNan(const std::string& s) { |
414 | 0 | return s == "nan" || s == "+nan" || s == "-nan"; |
415 | 0 | } |
416 | | |
417 | 0 | inline bool StringIsFlatbufferPositiveInfinity(const std::string& s) { |
418 | 0 | return s == "inf" || s == "+inf" || s == "infinity" || s == "+infinity"; |
419 | 0 | } |
420 | | |
421 | 0 | inline bool StringIsFlatbufferNegativeInfinity(const std::string& s) { |
422 | 0 | return s == "-inf" || s == "-infinity"; |
423 | 0 | } |
424 | | |
425 | | typedef bool (*LoadFileFunction)(const char* filename, bool binary, |
426 | | std::string* dest); |
427 | | typedef bool (*FileExistsFunction)(const char* filename); |
428 | | |
429 | | LoadFileFunction SetLoadFileFunction(LoadFileFunction load_file_function); |
430 | | |
431 | | FileExistsFunction SetFileExistsFunction( |
432 | | FileExistsFunction file_exists_function); |
433 | | |
434 | | // Check if file "name" exists. |
435 | | bool FileExists(const char* name); |
436 | | |
437 | | // Check if "name" exists and it is also a directory. |
438 | | bool DirExists(const char* name); |
439 | | |
440 | | // Load file "name" into "buf" returning true if successful |
441 | | // false otherwise. If "binary" is false data is read |
442 | | // using ifstream's text mode, otherwise data is read with |
443 | | // no transcoding. |
444 | | bool LoadFile(const char* name, bool binary, std::string* buf); |
445 | | |
446 | | // Save data "buf" of length "len" bytes into a file |
447 | | // "name" returning true if successful, false otherwise. |
448 | | // If "binary" is false data is written using ifstream's |
449 | | // text mode, otherwise data is written with no |
450 | | // transcoding. |
451 | | bool SaveFile(const char* name, const char* buf, size_t len, bool binary); |
452 | | |
453 | | // Save data "buf" into file "name" returning true if |
454 | | // successful, false otherwise. If "binary" is false |
455 | | // data is written using ifstream's text mode, otherwise |
456 | | // data is written with no transcoding. |
457 | 0 | inline bool SaveFile(const char* name, const std::string& buf, bool binary) { |
458 | 0 | return SaveFile(name, buf.c_str(), buf.size(), binary); |
459 | 0 | } |
460 | | |
461 | | // Functionality for minimalistic portable path handling. |
462 | | |
463 | | // The functions below behave correctly regardless of whether posix ('/') or |
464 | | // Windows ('/' or '\\') separators are used. |
465 | | |
466 | | // Any new separators inserted are always posix. |
467 | | FLATBUFFERS_CONSTEXPR char kPathSeparator = '/'; |
468 | | |
469 | | // Returns the path with the extension, if any, removed. |
470 | | std::string StripExtension(const std::string& filepath); |
471 | | |
472 | | // Returns the extension, if any. |
473 | | std::string GetExtension(const std::string& filepath); |
474 | | |
475 | | // Return the last component of the path, after the last separator. |
476 | | std::string StripPath(const std::string& filepath); |
477 | | |
478 | | // Strip the last component of the path + separator. |
479 | | std::string StripFileName(const std::string& filepath); |
480 | | |
481 | | std::string StripPrefix(const std::string& filepath, |
482 | | const std::string& prefix_to_remove); |
483 | | |
484 | | // Concatenates a path with a filename, regardless of whether the path |
485 | | // ends in a separator or not. |
486 | | std::string ConCatPathFileName(const std::string& path, |
487 | | const std::string& filename); |
488 | | |
489 | | // Replaces any '\\' separators with '/' |
490 | | std::string PosixPath(const char* path); |
491 | | std::string PosixPath(const std::string& path); |
492 | | |
493 | | // This function ensure a directory exists, by recursively |
494 | | // creating dirs for any parts of the path that don't exist yet. |
495 | | void EnsureDirExists(const std::string& filepath); |
496 | | |
497 | | // Obtains the relative or absolute path. |
498 | | std::string FilePath(const std::string& project, const std::string& filePath, |
499 | | bool absolute); |
500 | | |
501 | | // Obtains the absolute path from any other path. |
502 | | // Returns the input path if the absolute path couldn't be resolved. |
503 | | std::string AbsolutePath(const std::string& filepath); |
504 | | |
505 | | // Returns files relative to the --project_root path, prefixed with `//`. |
506 | | std::string RelativeToRootPath(const std::string& project, |
507 | | const std::string& filepath); |
508 | | |
509 | | // To and from UTF-8 unicode conversion functions |
510 | | |
511 | | // Convert a unicode code point into a UTF-8 representation by appending it |
512 | | // to a string. Returns the number of bytes generated. |
513 | 38.1k | inline int ToUTF8(uint32_t ucc, std::string* out) { |
514 | 38.1k | FLATBUFFERS_ASSERT(!(ucc & 0x80000000)); // Top bit can't be set. |
515 | | // 6 possible encodings: http://en.wikipedia.org/wiki/UTF-8 |
516 | 82.5k | for (int i = 0; i < 6; i++) { |
517 | | // Max bits this encoding can represent. |
518 | 82.5k | uint32_t max_bits = 6 + i * 5 + static_cast<int>(!i); |
519 | 82.5k | if (ucc < (1u << max_bits)) { // does it fit? |
520 | | // Remaining bits not encoded in the first byte, store 6 bits each |
521 | 38.1k | uint32_t remain_bits = i * 6; |
522 | | // Store first byte: |
523 | 38.1k | (*out) += static_cast<char>((0xFE << (max_bits - remain_bits)) | |
524 | 38.1k | (ucc >> remain_bits)); |
525 | | // Store remaining bytes: |
526 | 82.5k | for (int j = i - 1; j >= 0; j--) { |
527 | 44.3k | (*out) += static_cast<char>(((ucc >> (j * 6)) & 0x3F) | 0x80); |
528 | 44.3k | } |
529 | 38.1k | return i + 1; // Return the number of bytes added. |
530 | 38.1k | } |
531 | 82.5k | } |
532 | 0 | FLATBUFFERS_ASSERT(0); // Impossible to arrive here. |
533 | 0 | return -1; |
534 | 0 | } |
535 | | |
536 | | // Converts whatever prefix of the incoming string corresponds to a valid |
537 | | // UTF-8 sequence into a unicode code. The incoming pointer will have been |
538 | | // advanced past all bytes parsed. |
539 | | // returns -1 upon corrupt UTF-8 encoding (ignore the incoming pointer in |
540 | | // this case). |
541 | 1.72M | inline int FromUTF8(const char** in) { |
542 | 1.72M | int len = 0; |
543 | | // Count leading 1 bits. |
544 | 2.96M | for (int mask = 0x80; mask >= 0x04; mask >>= 1) { |
545 | 2.87M | if (**in & mask) { |
546 | 1.23M | len++; |
547 | 1.63M | } else { |
548 | 1.63M | break; |
549 | 1.63M | } |
550 | 2.87M | } |
551 | 1.72M | if ((static_cast<unsigned char>(**in) << len) & 0x80) |
552 | 94.8k | return -1; // Bit after leading 1's must be 0. |
553 | 1.63M | if (!len) return *(*in)++; |
554 | | // UTF-8 encoded values with a length are between 2 and 4 bytes. |
555 | 311k | if (len < 2 || len > 4) { |
556 | 127k | return -1; |
557 | 127k | } |
558 | | // Grab initial bits of the code. |
559 | 183k | int ucc = *(*in)++ & ((1 << (7 - len)) - 1); |
560 | 279k | for (int i = 0; i < len - 1; i++) { |
561 | 238k | if ((**in & 0xC0) != 0x80) return -1; // Upper bits must 1 0. |
562 | 95.6k | ucc <<= 6; |
563 | 95.6k | ucc |= *(*in)++ & 0x3F; // Grab 6 more bits of the code. |
564 | 95.6k | } |
565 | | // UTF-8 cannot encode values between 0xD800 and 0xDFFF (reserved for |
566 | | // UTF-16 surrogate pairs). |
567 | 41.4k | if (ucc >= 0xD800 && ucc <= 0xDFFF) { |
568 | 1.51k | return -1; |
569 | 1.51k | } |
570 | | // UTF-8 must represent code points in their shortest possible encoding. |
571 | 39.9k | switch (len) { |
572 | 10.8k | case 2: |
573 | | // Two bytes of UTF-8 can represent code points from U+0080 to U+07FF. |
574 | 10.8k | if (ucc < 0x0080 || ucc > 0x07FF) { |
575 | 2.33k | return -1; |
576 | 2.33k | } |
577 | 8.53k | break; |
578 | 15.0k | case 3: |
579 | | // Three bytes of UTF-8 can represent code points from U+0800 to U+FFFF. |
580 | 15.0k | if (ucc < 0x0800 || ucc > 0xFFFF) { |
581 | 1.87k | return -1; |
582 | 1.87k | } |
583 | 13.1k | break; |
584 | 14.0k | case 4: |
585 | | // Four bytes of UTF-8 can represent code points from U+10000 to U+10FFFF. |
586 | 14.0k | if (ucc < 0x10000 || ucc > 0x10FFFF) { |
587 | 3.77k | return -1; |
588 | 3.77k | } |
589 | 10.3k | break; |
590 | 39.9k | } |
591 | 31.9k | return ucc; |
592 | 39.9k | } |
593 | | |
594 | | #ifndef FLATBUFFERS_PREFER_PRINTF |
595 | | // Wraps a string to a maximum length, inserting new lines where necessary. Any |
596 | | // existing whitespace will be collapsed down to a single space. A prefix or |
597 | | // suffix can be provided, which will be inserted before or after a wrapped |
598 | | // line, respectively. |
599 | | inline std::string WordWrap(const std::string in, size_t max_length, |
600 | | const std::string wrapped_line_prefix, |
601 | 0 | const std::string wrapped_line_suffix) { |
602 | 0 | std::istringstream in_stream(in); |
603 | 0 | std::string wrapped, line, word; |
604 | 0 |
|
605 | 0 | in_stream >> word; |
606 | 0 | line = word; |
607 | 0 |
|
608 | 0 | while (in_stream >> word) { |
609 | 0 | if ((line.length() + 1 + word.length() + wrapped_line_suffix.length()) < |
610 | 0 | max_length) { |
611 | 0 | line += " " + word; |
612 | 0 | } else { |
613 | 0 | wrapped += line + wrapped_line_suffix + "\n"; |
614 | 0 | line = wrapped_line_prefix + word; |
615 | 0 | } |
616 | 0 | } |
617 | 0 | wrapped += line; |
618 | 0 |
|
619 | 0 | return wrapped; |
620 | 0 | } |
621 | | #endif // !FLATBUFFERS_PREFER_PRINTF |
622 | | |
623 | | inline bool EscapeString(const char* s, size_t length, std::string* _text, |
624 | 141k | bool allow_non_utf8, bool natural_utf8) { |
625 | 141k | std::string& text = *_text; |
626 | 141k | text += "\""; |
627 | 1.28M | for (uoffset_t i = 0; i < length; i++) { |
628 | 1.14M | char c = s[i]; |
629 | 1.14M | switch (c) { |
630 | 688 | case '\n': |
631 | 688 | text += "\\n"; |
632 | 688 | break; |
633 | 880 | case '\t': |
634 | 880 | text += "\\t"; |
635 | 880 | break; |
636 | 722 | case '\r': |
637 | 722 | text += "\\r"; |
638 | 722 | break; |
639 | 426 | case '\b': |
640 | 426 | text += "\\b"; |
641 | 426 | break; |
642 | 550 | case '\f': |
643 | 550 | text += "\\f"; |
644 | 550 | break; |
645 | 1.59k | case '\"': |
646 | 1.59k | text += "\\\""; |
647 | 1.59k | break; |
648 | 1.49k | case '\\': |
649 | 1.49k | text += "\\\\"; |
650 | 1.49k | break; |
651 | 1.14M | default: |
652 | 1.14M | if (c >= ' ' && c <= '~') { |
653 | 768k | text += c; |
654 | 768k | } else { |
655 | | // Not printable ASCII data. Let's see if it's valid UTF-8 first: |
656 | 372k | const char* utf8 = s + i; |
657 | 372k | int ucc = FromUTF8(&utf8); |
658 | 372k | if (ucc < 0) { |
659 | 352k | if (allow_non_utf8) { |
660 | 352k | text += "\\x"; |
661 | 352k | text += IntToStringHex(static_cast<uint8_t>(c), 2); |
662 | 352k | } else { |
663 | | // There are two cases here: |
664 | | // |
665 | | // 1) We reached here by parsing an IDL file. In that case, |
666 | | // we previously checked for non-UTF-8, so we shouldn't reach |
667 | | // here. |
668 | | // |
669 | | // 2) We reached here by someone calling GenText() |
670 | | // on a previously-serialized flatbuffer. The data might have |
671 | | // non-UTF-8 Strings, or might be corrupt. |
672 | | // |
673 | | // In both cases, we have to give up and inform the caller |
674 | | // they have no JSON. |
675 | 0 | return false; |
676 | 0 | } |
677 | 352k | } else { |
678 | 20.2k | if (natural_utf8) { |
679 | | // utf8 points to past all utf-8 bytes parsed |
680 | 0 | text.append(s + i, static_cast<size_t>(utf8 - s - i)); |
681 | 20.2k | } else if (ucc <= 0xFFFF) { |
682 | | // Parses as Unicode within JSON's \uXXXX range, so use that. |
683 | 18.4k | text += "\\u"; |
684 | 18.4k | text += IntToStringHex(ucc, 4); |
685 | 18.4k | } else if (ucc <= 0x10FFFF) { |
686 | | // Encode Unicode SMP values to a surrogate pair using two \u |
687 | | // escapes. |
688 | 1.74k | uint32_t base = ucc - 0x10000; |
689 | 1.74k | auto high_surrogate = (base >> 10) + 0xD800; |
690 | 1.74k | auto low_surrogate = (base & 0x03FF) + 0xDC00; |
691 | 1.74k | text += "\\u"; |
692 | 1.74k | text += IntToStringHex(high_surrogate, 4); |
693 | 1.74k | text += "\\u"; |
694 | 1.74k | text += IntToStringHex(low_surrogate, 4); |
695 | 1.74k | } |
696 | | // Skip past characters recognized. |
697 | 20.2k | i = static_cast<uoffset_t>(utf8 - s - 1); |
698 | 20.2k | } |
699 | 372k | } |
700 | 1.14M | break; |
701 | 1.14M | } |
702 | 1.14M | } |
703 | 141k | text += "\""; |
704 | 141k | return true; |
705 | 141k | } |
706 | | |
707 | | inline std::string BufferToHexText(const void* buffer, size_t buffer_size, |
708 | | size_t max_length, |
709 | | const std::string& wrapped_line_prefix, |
710 | 0 | const std::string& wrapped_line_suffix) { |
711 | 0 | std::string text = wrapped_line_prefix; |
712 | 0 | size_t start_offset = 0; |
713 | 0 | const char* s = reinterpret_cast<const char*>(buffer); |
714 | 0 | for (size_t i = 0; s && i < buffer_size; i++) { |
715 | 0 | // Last iteration or do we have more? |
716 | 0 | bool have_more = i + 1 < buffer_size; |
717 | 0 | text += "0x"; |
718 | 0 | text += IntToStringHex(static_cast<uint8_t>(s[i]), 2); |
719 | 0 | if (have_more) { |
720 | 0 | text += ','; |
721 | 0 | } |
722 | 0 | // If we have more to process and we reached max_length |
723 | 0 | if (have_more && |
724 | 0 | text.size() + wrapped_line_suffix.size() >= start_offset + max_length) { |
725 | 0 | text += wrapped_line_suffix; |
726 | 0 | text += '\n'; |
727 | 0 | start_offset = text.size(); |
728 | 0 | text += wrapped_line_prefix; |
729 | 0 | } |
730 | 0 | } |
731 | 0 | text += wrapped_line_suffix; |
732 | 0 | return text; |
733 | 0 | } |
734 | | |
735 | | // Remove paired quotes in a string: "text"|'text' -> text. |
736 | | std::string RemoveStringQuotes(const std::string& s); |
737 | | |
738 | | // Change th global C-locale to locale with name <locale_name>. |
739 | | // Returns an actual locale name in <_value>, useful if locale_name is "" or |
740 | | // null. |
741 | | bool SetGlobalTestLocale(const char* locale_name, |
742 | | std::string* _value = nullptr); |
743 | | |
744 | | // Read (or test) a value of environment variable. |
745 | | bool ReadEnvironmentVariable(const char* var_name, |
746 | | std::string* _value = nullptr); |
747 | | |
748 | | enum class Case { |
749 | | kUnknown = 0, |
750 | | // TheQuickBrownFox |
751 | | kUpperCamel = 1, |
752 | | // theQuickBrownFox |
753 | | kLowerCamel = 2, |
754 | | // the_quick_brown_fox |
755 | | kSnake = 3, |
756 | | // THE_QUICK_BROWN_FOX |
757 | | kScreamingSnake = 4, |
758 | | // THEQUICKBROWNFOX |
759 | | kAllUpper = 5, |
760 | | // thequickbrownfox |
761 | | kAllLower = 6, |
762 | | // the-quick-brown-fox |
763 | | kDasher = 7, |
764 | | // THEQuiCKBr_ownFox (or whatever you want, we won't change it) |
765 | | kKeep = 8, |
766 | | // the_quick_brown_fox123 (as opposed to the_quick_brown_fox_123) |
767 | | kSnake2 = 9, |
768 | | }; |
769 | | |
770 | | // Convert the `input` string of case `input_case` to the specified |
771 | | // `output_case`. |
772 | | std::string ConvertCase(const std::string& input, Case output_case, |
773 | | Case input_case = Case::kSnake); |
774 | | |
775 | | } // namespace flatbuffers |
776 | | |
777 | | #endif // FLATBUFFERS_UTIL_H_ |