/src/wt/src/web/WebUtils.C
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2008 Emweb bv, Herent, Belgium. |
3 | | * |
4 | | * See the LICENSE file for terms of use. |
5 | | */ |
6 | | |
7 | | #include "WebUtils.h" |
8 | | #include "DomElement.h" |
9 | | #include "thirdparty/rapidxml/rapidxml.hpp" |
10 | | #include "Wt/WException.h" |
11 | | #include "Wt/WString.h" |
12 | | #include "Wt/WStringUtil.h" |
13 | | #include "Wt/Utils.h" |
14 | | |
15 | | #include <boost/algorithm/string.hpp> |
16 | | #include <boost/version.hpp> |
17 | | |
18 | | #include <cctype> |
19 | | #include <cfloat> |
20 | | #include <cstdio> |
21 | | #include <fstream> |
22 | | #include <iomanip> |
23 | | #include <regex> |
24 | | #include <unordered_map> |
25 | | |
26 | | #ifdef WT_WIN32 |
27 | | #define WIN32_LEAN_AND_MEAN |
28 | | #define NOMINMAX |
29 | | #include <windows.h> |
30 | | #define snprintf _snprintf |
31 | | #else |
32 | | #include <cstdlib> |
33 | | #endif // WIN32 |
34 | | |
35 | | #if !defined(WT_NO_SPIRIT) && BOOST_VERSION >= 104700 && (BOOST_VERSION < 107600 || BOOST_VERSION >= 107900) |
36 | | # define SPIRIT_FLOAT_FORMAT |
37 | | #endif |
38 | | |
39 | | #ifdef SPIRIT_FLOAT_FORMAT |
40 | | #include <boost/config/warning_disable.hpp> |
41 | | #include <boost/spirit/include/karma.hpp> |
42 | | #else |
43 | | #include <boost/math/special_functions/fpclassify.hpp> |
44 | | #include <boost/math/special_functions/sign.hpp> |
45 | | #endif // SPIRIT_FLOAT_FORMAT |
46 | | |
47 | | #include <boost/spirit/include/qi_parse.hpp> |
48 | | #include <boost/spirit/include/qi_numeric.hpp> |
49 | | |
50 | | // Qnx gcc 4.4.2 |
51 | | #ifdef isnan |
52 | | #undef isnan |
53 | | #endif |
54 | | #ifdef isinf |
55 | | #undef isinf |
56 | | #endif |
57 | | |
58 | | namespace Wt { |
59 | | namespace Utils { |
60 | | |
61 | | std::string append(const std::string& s, char c) |
62 | 0 | { |
63 | 0 | if (s.empty() || s[s.length() - 1] != c) |
64 | 0 | return s + c; |
65 | 0 | else |
66 | 0 | return s; |
67 | 0 | } |
68 | | |
69 | | std::string prepend(const std::string& s, char c) |
70 | 0 | { |
71 | 0 | if (s.empty() || s[0] != c) |
72 | 0 | return c + s; |
73 | 0 | else |
74 | 0 | return s; |
75 | 0 | } |
76 | | |
77 | | std::string& replace(std::string& s, char c, const std::string& r) |
78 | 0 | { |
79 | 0 | std::string::size_type p = 0; |
80 | |
|
81 | 0 | while ((p = s.find(c, p)) != std::string::npos) { |
82 | 0 | s.replace(p, 1, r); |
83 | 0 | p += r.length(); |
84 | 0 | } |
85 | |
|
86 | 0 | return s; |
87 | 0 | } |
88 | | |
89 | | std::string& replace(std::string& s, const std::string& k, const std::string& r) |
90 | 0 | { |
91 | 0 | std::string::size_type p = 0; |
92 | |
|
93 | 0 | while ((p = s.find(k, p)) != std::string::npos) { |
94 | 0 | s.replace(p, k.length(), r); |
95 | 0 | p += r.length(); |
96 | 0 | } |
97 | |
|
98 | 0 | return s; |
99 | 0 | } |
100 | | |
101 | | std::string lowerCase(const std::string& s) |
102 | 134k | { |
103 | 134k | std::string result = s; |
104 | 5.81M | for (unsigned i = 0; i < result.length(); ++i) |
105 | 5.68M | result[i] = tolower(result[i]); |
106 | 134k | return result; |
107 | 134k | } |
108 | | |
109 | | void sanitizeUnicode(EscapeOStream& sout, const std::string& text) |
110 | 0 | { |
111 | 0 | char buf[4]; |
112 | |
|
113 | 0 | for (const char *c = text.c_str(); *c;) { |
114 | 0 | char *b = buf; |
115 | | // but copy_check_utf8() does not declare the following ranges illegal: |
116 | | // U+D800-U+DFFF |
117 | | // U+FFFE-U+FFFF |
118 | 0 | Wt::rapidxml::xml_document<>::copy_check_utf8(c, b); |
119 | 0 | for (char *i = buf; i < b; ++i) |
120 | 0 | sout << *i; |
121 | 0 | } |
122 | 0 | } |
123 | | |
124 | | std::string eraseWord(const std::string& s, const std::string& w) |
125 | 0 | { |
126 | 0 | std::string::size_type p; |
127 | 0 | std::string::size_type pos = 0; |
128 | |
|
129 | 0 | while ((p = s.find(w, pos)) != std::string::npos) { |
130 | 0 | std::string::size_type e = p + w.length(); |
131 | 0 | if ((p == 0 || s[p-1] == ' ') && |
132 | 0 | (e == s.length() || s[e] == ' ')) { |
133 | 0 | std::string ss = s; |
134 | 0 | ss.erase(ss.begin() + p, ss.begin() + e); |
135 | 0 | if (p > 1) |
136 | 0 | ss.erase(ss.begin() + (p - 1)); |
137 | 0 | else if (e < ss.length()) |
138 | 0 | ss.erase(ss.begin() + p); |
139 | |
|
140 | 0 | return ss; |
141 | 0 | } |
142 | | |
143 | 0 | pos = p + 1; |
144 | 0 | } |
145 | | |
146 | 0 | return s; |
147 | 0 | } |
148 | | |
149 | | std::string addWord(const std::string& s, const std::string& w) |
150 | 0 | { |
151 | 0 | if (s.empty()) |
152 | 0 | return w; |
153 | 0 | else |
154 | 0 | return s + ' ' + w; |
155 | 0 | } |
156 | | |
157 | 4.59k | char *itoa(int value, char *result, int base) { |
158 | 4.59k | char* out = result; |
159 | 4.59k | int quotient = value; |
160 | | |
161 | 4.59k | if (quotient < 0) |
162 | 0 | quotient = -quotient; |
163 | | |
164 | 13.9k | do { |
165 | 13.9k | *out = |
166 | 13.9k | "0123456789abcdefghijklmnopqrstuvwxyz"[quotient % base]; |
167 | 13.9k | ++out; |
168 | 13.9k | quotient /= base; |
169 | 13.9k | } while (quotient); |
170 | | |
171 | 4.59k | if (value < 0 && base == 10) |
172 | 0 | *out++ = '-'; |
173 | | |
174 | 4.59k | std::reverse(result, out); |
175 | 4.59k | *out = 0; |
176 | | |
177 | 4.59k | return result; |
178 | 4.59k | } |
179 | | |
180 | 0 | char *utoa(unsigned int value, char* result, int base) { |
181 | 0 | char* out = result; |
182 | 0 | unsigned int quotient = value; |
183 | |
|
184 | 0 | do { |
185 | 0 | *out = |
186 | 0 | "0123456789abcdefghijklmnopqrstuvwxyz"[quotient % base]; |
187 | 0 | ++out; |
188 | 0 | quotient /= base; |
189 | 0 | } while (quotient); |
190 | |
|
191 | 0 | std::reverse(result, out); |
192 | 0 | *out = 0; |
193 | |
|
194 | 0 | return result; |
195 | 0 | } |
196 | | |
197 | 0 | char *lltoa(long long value, char *result, int base) { |
198 | 0 | char* out = result; |
199 | 0 | long long quotient = value; |
200 | |
|
201 | 0 | if (quotient < 0) |
202 | 0 | quotient = -quotient; |
203 | |
|
204 | 0 | do { |
205 | 0 | *out = |
206 | 0 | "0123456789abcdefghijklmnopqrstuvwxyz"[ quotient % base ]; |
207 | 0 | ++out; |
208 | 0 | quotient /= base; |
209 | 0 | } while (quotient); |
210 | |
|
211 | 0 | if (value < 0 && base == 10) |
212 | 0 | *out++ = '-'; |
213 | 0 | std::reverse(result, out); |
214 | 0 | *out = 0; |
215 | |
|
216 | 0 | return result; |
217 | 0 | } |
218 | | |
219 | 0 | char *pad_itoa(int value, int length, char *result) { |
220 | 0 | static const int exp[] = { 1, 10, 100, 1000, 10000, 100000, 100000 }; |
221 | |
|
222 | 0 | result[length] = 0; |
223 | |
|
224 | 0 | for (int i = 0; i < length; ++i) { |
225 | 0 | int b = exp[length - i - 1]; |
226 | 0 | if (value >= b) |
227 | 0 | result[i] = '0' + (value / b) % 10; |
228 | 0 | else |
229 | 0 | result[i] = '0'; |
230 | 0 | } |
231 | |
|
232 | 0 | return result; |
233 | 0 | } |
234 | | |
235 | | #ifdef SPIRIT_FLOAT_FORMAT |
236 | | namespace { |
237 | | using namespace boost::spirit; |
238 | | using namespace boost::spirit::karma; |
239 | | |
240 | | // adjust rendering for JS flaots |
241 | | template <typename T, int Precision> |
242 | | struct JavaScriptPolicy : karma::real_policies<T> |
243 | | { |
244 | | // not 'nan', but 'NaN' |
245 | | template <typename CharEncoding, typename Tag, typename OutputIterator> |
246 | | static bool nan (OutputIterator& sink, WT_MAYBE_UNUSED T n, WT_MAYBE_UNUSED bool forceSign) |
247 | 0 | { |
248 | 0 | return string_inserter<CharEncoding, Tag>::call(sink, "NaN"); |
249 | 0 | } Unexecuted instantiation: WebUtils.C:bool Wt::Utils::(anonymous namespace)::JavaScriptPolicy<double, 7>::nan<boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::karma::detail::output_iterator<char*, mpl_::int_<0>, boost::spirit::unused_type> >(boost::spirit::karma::detail::output_iterator<char*, mpl_::int_<0>, boost::spirit::unused_type>&, double, bool) Unexecuted instantiation: WebUtils.C:bool Wt::Utils::(anonymous namespace)::JavaScriptPolicy<double, 15>::nan<boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::karma::detail::output_iterator<char*, mpl_::int_<0>, boost::spirit::unused_type> >(boost::spirit::karma::detail::output_iterator<char*, mpl_::int_<0>, boost::spirit::unused_type>&, double, bool) |
250 | | |
251 | | // not 'inf', but 'Infinity' |
252 | | template <typename CharEncoding, typename Tag, typename OutputIterator> |
253 | | static bool inf (OutputIterator& sink, T n, bool force_sign) |
254 | 0 | { |
255 | 0 | return sign_inserter::call(sink, false, (n<0), force_sign) && |
256 | 0 | string_inserter<CharEncoding, Tag>::call(sink, "Infinity"); |
257 | 0 | } Unexecuted instantiation: WebUtils.C:bool Wt::Utils::(anonymous namespace)::JavaScriptPolicy<double, 7>::inf<boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::karma::detail::output_iterator<char*, mpl_::int_<0>, boost::spirit::unused_type> >(boost::spirit::karma::detail::output_iterator<char*, mpl_::int_<0>, boost::spirit::unused_type>&, double, bool) Unexecuted instantiation: WebUtils.C:bool Wt::Utils::(anonymous namespace)::JavaScriptPolicy<double, 15>::inf<boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::karma::detail::output_iterator<char*, mpl_::int_<0>, boost::spirit::unused_type> >(boost::spirit::karma::detail::output_iterator<char*, mpl_::int_<0>, boost::spirit::unused_type>&, double, bool) |
258 | | |
259 | 0 | static int floatfield(T t) { |
260 | 0 | return (t != 0.0) && ((std::abs(t) < 0.001) || (std::abs(t) > 1E8)) ? |
261 | 0 | karma::real_policies<T>::fmtflags::scientific : |
262 | 0 | karma::real_policies<T>::fmtflags::fixed; |
263 | 0 | } Unexecuted instantiation: WebUtils.C:Wt::Utils::(anonymous namespace)::JavaScriptPolicy<double, 7>::floatfield(double) Unexecuted instantiation: WebUtils.C:Wt::Utils::(anonymous namespace)::JavaScriptPolicy<double, 15>::floatfield(double) |
264 | | |
265 | | // 7 significant numbers; about float precision |
266 | 0 | static unsigned precision(T) { return Precision; }Unexecuted instantiation: WebUtils.C:Wt::Utils::(anonymous namespace)::JavaScriptPolicy<double, 7>::precision(double) Unexecuted instantiation: WebUtils.C:Wt::Utils::(anonymous namespace)::JavaScriptPolicy<double, 15>::precision(double) |
267 | | |
268 | | }; |
269 | | |
270 | | typedef real_generator<double, JavaScriptPolicy<double, 7> > |
271 | | KarmaJavaScriptReal; |
272 | | typedef real_generator<double, JavaScriptPolicy<double, 15> > |
273 | | KarmaJavaScriptDouble; |
274 | | |
275 | | } |
276 | | |
277 | | static inline char *generic_double_to_str(double d, int precision, char *buf) |
278 | 0 | { |
279 | 0 | using namespace boost::spirit; |
280 | 0 | using namespace boost::spirit::karma; |
281 | 0 | char *p = buf; |
282 | 0 | if (d != 0) { |
283 | 0 | if (fabs(d) < DBL_MIN) { |
284 | 0 | std::stringstream ss; |
285 | 0 | ss.imbue(std::locale("C")); |
286 | 0 | ss << std::setprecision(precision) << d; |
287 | 0 | std::string str = ss.str(); |
288 | 0 | memcpy(p, str.c_str(), str.length()); |
289 | 0 | p += str.length(); |
290 | 0 | } else { |
291 | 0 | if (precision <= 7) |
292 | 0 | generate(p, KarmaJavaScriptReal(), d); |
293 | 0 | else |
294 | 0 | generate(p, KarmaJavaScriptDouble(), d); |
295 | 0 | } |
296 | 0 | } else |
297 | 0 | *p++ = '0'; |
298 | 0 | *p = '\0'; |
299 | 0 | return buf; |
300 | 0 | } |
301 | | #else |
302 | | static inline char *generic_double_to_str(double d, char *buf) |
303 | | { |
304 | | if (!boost::math::isnan(d)) { |
305 | | if (!boost::math::isinf(d)) { |
306 | | sprintf(buf, "%.7g", d); |
307 | | } else { |
308 | | if (d > 0) { |
309 | | sprintf(buf, "Infinity"); |
310 | | } else { |
311 | | sprintf(buf, "-Infinity"); |
312 | | } |
313 | | } |
314 | | } else { |
315 | | sprintf(buf, "NaN"); |
316 | | } |
317 | | return buf; |
318 | | } |
319 | | #endif |
320 | | |
321 | | char *round_css_str(double d, int digits, char *buf) |
322 | 0 | { |
323 | 0 | static const int exp[] = { 1, 10, 100, 1000, 10000, 100000, 1000000 }; |
324 | |
|
325 | 0 | long long i |
326 | 0 | = static_cast<long long>(d * exp[digits] + (d > 0 ? 0.49 : -0.49)); |
327 | |
|
328 | 0 | lltoa(i, buf); |
329 | 0 | char *num = buf; |
330 | |
|
331 | 0 | if (num[0] == '-') |
332 | 0 | ++num; |
333 | 0 | int len = std::strlen(num); |
334 | |
|
335 | 0 | if (len <= digits) { |
336 | 0 | int shift = digits + 1 - len; |
337 | 0 | for (int i = digits + 1; i >= 0; --i) { |
338 | 0 | if (i >= shift) |
339 | 0 | num[i] = num[i - shift]; |
340 | 0 | else |
341 | 0 | num[i] = '0'; |
342 | 0 | } |
343 | 0 | len = digits + 1; |
344 | 0 | } |
345 | |
|
346 | 0 | int dotPos = (std::max)(len - digits, 0); |
347 | |
|
348 | 0 | for (int i = digits + 1; i >= 0; --i) |
349 | 0 | num[dotPos + i + 1] = num[dotPos + i]; |
350 | |
|
351 | 0 | num[dotPos] = '.'; |
352 | |
|
353 | 0 | return buf; |
354 | 0 | } |
355 | | |
356 | 0 | char *round_js_str(double d, int digits, char *buf) { |
357 | 0 | #ifdef SPIRIT_FLOAT_FORMAT |
358 | 0 | return generic_double_to_str(d, digits, buf); |
359 | | #else |
360 | | return generic_double_to_str(d, buf); |
361 | | #endif |
362 | 0 | } |
363 | | |
364 | | std::string urlEncode(const std::string& url, const std::string& allowed) |
365 | 0 | { |
366 | 0 | return DomElement::urlEncodeS(url, allowed); |
367 | 0 | } |
368 | | |
369 | | std::string dataUrlDecode(WT_MAYBE_UNUSED const std::string& url, |
370 | | WT_MAYBE_UNUSED std::vector<unsigned char>& data) |
371 | 0 | { |
372 | 0 | return std::string(); |
373 | 0 | } |
374 | | |
375 | | void inplaceUrlDecode(std::string &text) |
376 | 274k | { |
377 | | // Note: there is a Java-too duplicate of this function in Wt/Utils.C |
378 | 274k | std::size_t j = 0; |
379 | | |
380 | 3.38M | for (std::size_t i = 0; i < text.length(); ++i) { |
381 | 3.10M | char c = text[i]; |
382 | | |
383 | 3.10M | if (c == '+') { |
384 | 621 | text[j++] = ' '; |
385 | 3.10M | } else if (c == '%' && i + 2 < text.length()) { |
386 | 94.3k | std::string h = text.substr(i + 1, 2); |
387 | 94.3k | char *e = 0; |
388 | 94.3k | int hval = std::strtol(h.c_str(), &e, 16); |
389 | | |
390 | 94.3k | if (*e == 0) { |
391 | 1.09k | text[j++] = (char)hval; |
392 | 1.09k | i += 2; |
393 | 93.2k | } else { |
394 | | // not a proper %XX with XX hexadecimal format |
395 | 93.2k | text[j++] = c; |
396 | 93.2k | } |
397 | 94.3k | } else |
398 | 3.01M | text[j++] = c; |
399 | 3.10M | } |
400 | | |
401 | 274k | text.erase(j); |
402 | 274k | } |
403 | | |
404 | | namespace { |
405 | | static const std::unordered_map<wchar_t, wchar_t> asciiReplaceMap = { |
406 | | {L'à', L'a'}, {L'á', L'a'}, {L'â', L'a'}, {L'ã', L'a'}, {L'ä', L'a'}, |
407 | | {L'å', L'a'}, {L'ā', L'a'}, {L'ă', L'a'}, {L'ą', L'a'}, {L'ǎ', L'a'}, |
408 | | {L'ǻ', L'a'}, {L'ạ', L'a'}, {L'ả', L'a'}, {L'ấ', L'a'}, {L'ầ', L'a'}, |
409 | | {L'ẩ', L'a'}, {L'ẫ', L'a'}, {L'ậ', L'a'}, {L'ắ', L'a'}, {L'ằ', L'a'}, |
410 | | {L'ẳ', L'a'}, {L'ẵ', L'a'}, {L'ặ', L'a'}, |
411 | | {L'è', L'e'}, {L'é', L'e'}, {L'ê', L'e'}, {L'ë', L'e'}, {L'ē', L'e'}, |
412 | | {L'ĕ', L'e'}, {L'ė', L'e'}, {L'ę', L'e'}, {L'ě', L'e'}, {L'ẹ', L'e'}, |
413 | | {L'ẻ', L'e'}, {L'ẽ', L'e'}, {L'ế', L'e'}, {L'ề', L'e'}, {L'ể', L'e'}, |
414 | | {L'ễ', L'e'}, {L'ệ', L'e'}, |
415 | | {L'ì', L'i'}, {L'í', L'i'}, {L'î', L'i'}, {L'ï', L'i'}, {L'ĩ', L'i'}, |
416 | | {L'ī', L'i'}, {L'ĭ', L'i'}, {L'į', L'i'}, {L'ǐ', L'i'}, {L'ỉ', L'i'}, |
417 | | {L'ị', L'i'}, |
418 | | {L'ò', L'o'}, {L'ó', L'o'}, {L'ô', L'o'}, {L'õ', L'o'}, {L'ö', L'o'}, |
419 | | {L'ø', L'o'}, {L'ō', L'o'}, {L'ŏ', L'o'}, {L'ő', L'o'}, {L'ǒ', L'o'}, |
420 | | {L'ǿ', L'o'}, {L'ọ', L'o'}, {L'ỏ', L'o'}, {L'ố', L'o'}, {L'ồ', L'o'}, |
421 | | {L'ổ', L'o'}, {L'ỗ', L'o'}, {L'ộ', L'o'}, {L'ớ', L'o'}, {L'ờ', L'o'}, |
422 | | {L'ở', L'o'}, {L'ỡ', L'o'}, {L'ợ', L'o'}, |
423 | | {L'ù', L'u'}, {L'ú', L'u'}, {L'û', L'u'}, {L'ü', L'u'}, {L'ũ', L'u'}, |
424 | | {L'ū', L'u'}, {L'ŭ', L'u'}, {L'ů', L'u'}, {L'ű', L'u'}, {L'ų', L'u'}, |
425 | | {L'ǔ', L'u'}, {L'ụ', L'u'}, {L'ủ', L'u'}, {L'ứ', L'u'}, {L'ừ', L'u'}, |
426 | | {L'ử', L'u'}, {L'ữ', L'u'}, {L'ự', L'u'}, |
427 | | {L'ý', L'y'}, {L'ÿ', L'y'}, {L'ŷ', L'y'}, {L'ỳ', L'y'}, {L'ỵ', L'y'}, |
428 | | {L'ỷ', L'y'}, {L'ỹ', L'y'}, |
429 | | |
430 | | {L'À', L'A'}, {L'Á', L'A'}, {L'Â', L'A'}, {L'Ã', L'A'}, {L'Ä', L'A'}, |
431 | | {L'Å', L'A'}, {L'Ā', L'A'}, {L'Ă', L'A'}, {L'Ą', L'A'}, {L'Ǎ', L'A'}, |
432 | | {L'Ǻ', L'A'}, {L'Ạ', L'A'}, {L'Ả', L'A'}, {L'Ấ', L'A'}, {L'Ầ', L'A'}, |
433 | | {L'Ẩ', L'A'}, {L'Ẫ', L'A'}, {L'Ậ', L'A'}, {L'Ắ', L'A'}, {L'Ằ', L'A'}, |
434 | | {L'Ẳ', L'A'}, {L'Ẵ', L'A'}, {L'Ặ', L'A'}, |
435 | | {L'È', L'E'}, {L'É', L'E'}, {L'Ê', L'E'}, {L'Ë', L'E'}, {L'Ē', L'E'}, |
436 | | {L'Ĕ', L'E'}, {L'Ė', L'E'}, {L'Ę', L'E'}, {L'Ě', L'E'}, {L'Ẹ', L'E'}, |
437 | | {L'Ẻ', L'E'}, {L'Ẽ', L'E'}, {L'Ế', L'E'}, {L'Ề', L'E'}, {L'Ể', L'E'}, |
438 | | {L'Ễ', L'E'}, {L'Ệ', L'E'}, |
439 | | {L'Ì', L'I'}, {L'Í', L'I'}, {L'Î', L'I'}, {L'Ï', L'I'}, {L'Ĩ', L'I'}, |
440 | | {L'Ī', L'I'}, {L'Ĭ', L'I'}, {L'Į', L'I'}, {L'Ǐ', L'I'}, {L'Ỉ', L'I'}, |
441 | | {L'Ị', L'I'}, |
442 | | {L'Ò', L'O'}, {L'Ó', L'O'}, {L'Ô', L'O'}, {L'Õ', L'O'}, {L'Ö', L'O'}, |
443 | | {L'Ø', L'O'}, {L'Ō', L'O'}, {L'ŏ', L'O'}, {L'Ő', L'O'}, {L'Ǒ', L'O'}, |
444 | | {L'Ǿ', L'O'}, {L'Ọ', L'O'}, {L'Ỏ', L'O'}, {L'Ố', L'O'}, {L'Ồ', L'O'}, |
445 | | {L'Ổ', L'O'}, {L'Ỗ', L'O'}, {L'Ộ', L'O'}, {L'Ớ', L'O'}, {L'Ờ', L'O'}, |
446 | | {L'Ở', L'O'}, {L'Ỡ', L'O'}, {L'Ợ', L'O'}, |
447 | | {L'Ù', L'U'}, {L'Ú', L'U'}, {L'Û', L'U'}, {L'Ü', L'U'}, {L'Ũ', L'U'}, |
448 | | {L'Ū', L'U'}, {L'Ŭ', L'U'}, {L'Ů', L'U'}, {L'Ű', L'U'}, {L'Ų', L'U'}, |
449 | | {L'Ǔ', L'U'}, {L'Ụ', L'U'}, {L'Ủ', L'U'}, {L'Ứ', L'U'}, {L'Ừ', L'U'}, |
450 | | {L'Ử', L'U'}, {L'Ữ', L'U'}, {L'Ự', L'U'}, |
451 | | {L'Ý', L'Y'}, {L'Ÿ', L'Y'}, {L'Ŷ', L'Y'}, {L'Ỳ', L'Y'}, {L'Ỵ', L'Y'}, |
452 | | {L'Ỷ', L'Y'}, {L'Ỹ', L'Y'}, |
453 | | |
454 | | {L'ç', L'c'}, {L'ć', L'c'}, {L'ĉ', L'c'}, {L'ċ', L'c'}, {L'č', L'c'}, |
455 | | {L'Ç', L'C'}, {L'Ć', L'C'}, {L'Ĉ', L'C'}, {L'Ċ', L'C'}, {L'Č', L'C'}, |
456 | | {L'ď', L'd'}, {L'đ', L'd'}, {L'Ď', L'D'}, {L'Đ', L'D'}, |
457 | | {L'ĝ', L'g'}, {L'ğ', L'g'}, {L'ġ', L'g'}, {L'ģ', L'g'}, |
458 | | {L'Ĝ', L'G'}, {L'Ğ', L'G'}, {L'Ġ', L'G'}, {L'Ģ', L'G'}, |
459 | | {L'ĥ', L'h'}, {L'ħ', L'h'}, {L'Ĥ', L'H'}, {L'Ħ', L'H'}, |
460 | | {L'ĵ', L'j'}, {L'Ĵ', L'J'}, |
461 | | {L'ķ', L'k'}, {L'Ķ', L'K'}, |
462 | | {L'ĺ', L'l'}, {L'ļ', L'l'}, {L'ľ', L'l'}, {L'ŀ', L'l'}, {L'ł', L'l'}, |
463 | | {L'Ĺ', L'L'}, {L'Ļ', L'L'}, {L'Ľ', L'L'}, {L'Ŀ', L'L'}, {L'Ł', L'L'}, |
464 | | {L'ñ', L'n'}, {L'ń', L'n'}, {L'ņ', L'n'}, {L'ň', L'n'}, {L'ʼn', L'n'}, |
465 | | {L'Ñ', L'N'}, {L'Ń', L'N'}, {L'Ņ', L'N'}, {L'Ň', L'N'}, |
466 | | {L'ŕ', L'r'}, {L'ŗ', L'r'}, {L'ř', L'r'}, |
467 | | {L'Ŕ', L'R'}, {L'Ŗ', L'R'}, {L'Ř', L'R'}, |
468 | | {L'ś', L's'}, {L'ŝ', L's'}, {L'ş', L's'}, {L'š', L's'}, {L'ș', L's'}, |
469 | | {L'Ś', L'S'}, {L'Ŝ', L'S'}, {L'Ş', L'S'}, {L'Š', L'S'}, {L'Ș', L'S'}, |
470 | | {L'ţ', L't'}, {L'ť', L't'}, {L'ŧ', L't'}, {L'ț', L't'}, |
471 | | {L'Ţ', L'T'}, {L'Ť', L'T'}, {L'Ŧ', L'T'}, {L'Ț', L'T'}, |
472 | | {L'ŵ', L'w'}, {L'Ŵ', L'W'}, |
473 | | {L'ź', L'z'}, {L'ż', L'z'}, {L'ž', L'z'}, |
474 | | {L'Ź', L'Z'}, {L'Ż', L'Z'}, {L'Ž', L'Z'}, |
475 | | |
476 | | {L'‘', L'\''}, {L'’', L'\''}, {L'‚', L'\''}, {L'‛', L'\''}, |
477 | | {L'“', L'"'}, {L'”', L'"'}, {L'„', L'"'}, {L'‟', L'"'}, |
478 | | {L'‹', L'<'}, {L'›', L'>'}, |
479 | | {L'«', L'"'}, {L'»', L'"'}, |
480 | | {L'‐', L'-'}, {L'‑', L'-'}, {L'–', L'-'}, {L'—', L'-'}, |
481 | | {L'―', L'-'}, {L'⸗', L'-'}, |
482 | | {L'˜', L'~'}, |
483 | | {L'·', L'.'}, {L'•', L'.'} |
484 | | }; |
485 | | } |
486 | | |
487 | 0 | std::string toAscii(const std::wstring& input) { |
488 | 0 | if (input.empty()) { |
489 | 0 | return ""; |
490 | 0 | } |
491 | | |
492 | 0 | std::wstring s = input; |
493 | 0 | for (auto& c : s) { |
494 | 0 | auto it = asciiReplaceMap.find(c); |
495 | 0 | if (it != asciiReplaceMap.end()) { |
496 | 0 | c = it->second; |
497 | 0 | } |
498 | 0 | } |
499 | | |
500 | | // Remove any remaining bytes that are outside the standard 7-bit ASCII range |
501 | 0 | std::wregex nonAsciiRegex(L"[^\\x00-\\x7F]"); |
502 | 0 | return Wt::toUTF8(std::regex_replace(s, nonAsciiRegex, L"?")); |
503 | 0 | } |
504 | | |
505 | | std::string EncodeHttpHeaderField(const std::string &fieldname, |
506 | | const WString &fieldValue) |
507 | 0 | { |
508 | | // This implements RFC 5987 |
509 | 0 | return fieldname + "*=UTF-8''" + urlEncode(fieldValue.toUTF8()); |
510 | 0 | } |
511 | | |
512 | | std::string readFile(const std::string& fname) |
513 | 0 | { |
514 | 0 | std::ifstream f(fname.c_str(), std::ios::in | std::ios::binary); |
515 | |
|
516 | 0 | if (!f) |
517 | 0 | throw WException("Could not load " + fname); |
518 | | |
519 | 0 | f.seekg(0, std::ios::end); |
520 | 0 | int length = f.tellg(); |
521 | 0 | f.seekg(0, std::ios::beg); |
522 | |
|
523 | 0 | std::unique_ptr<char[]> ftext(new char[length + 1]); |
524 | 0 | f.read(ftext.get(), length); |
525 | 0 | ftext[length] = 0; |
526 | |
|
527 | 0 | return std::string(ftext.get()); |
528 | 0 | } |
529 | | |
530 | | WString formatFloat(const WString &format, double value) |
531 | 0 | { |
532 | 0 | std::string f = format.toUTF8(); |
533 | 0 | int buflen = f.length() + 15; |
534 | |
|
535 | 0 | char *buf = new char[buflen]; |
536 | |
|
537 | 0 | snprintf(buf, buflen, f.c_str(), value); |
538 | 0 | buf[buflen - 1] = 0; |
539 | |
|
540 | 0 | WString result = WT_USTRING::fromUTF8(buf); |
541 | |
|
542 | 0 | delete[] buf; |
543 | |
|
544 | 0 | return result; |
545 | 0 | } |
546 | | |
547 | | template<typename ResultType, typename SpiritType> |
548 | | ResultType convert(const char *fname, const SpiritType &t, const std::string& v) |
549 | 2.04k | { |
550 | 8.33k | auto is_space = [](char c) { return c == ' '; };Unexecuted instantiation: Wt::Utils::convert<long, boost::spirit::terminal<boost::spirit::tag::long_> >(char const*, boost::spirit::terminal<boost::spirit::tag::long_> const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)::{lambda(char)#1}::operator()(char) constUnexecuted instantiation: Wt::Utils::convert<unsigned long, boost::spirit::terminal<boost::spirit::tag::ulong_> >(char const*, boost::spirit::terminal<boost::spirit::tag::ulong_> const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)::{lambda(char)#1}::operator()(char) constWt::Utils::convert<long long, boost::spirit::terminal<boost::spirit::tag::long_long> >(char const*, boost::spirit::terminal<boost::spirit::tag::long_long> const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)::{lambda(char)#1}::operator()(char) constLine | Count | Source | 550 | 3.78k | auto is_space = [](char c) { return c == ' '; }; |
Unexecuted instantiation: Wt::Utils::convert<unsigned long long, boost::spirit::terminal<boost::spirit::tag::ulong_long> >(char const*, boost::spirit::terminal<boost::spirit::tag::ulong_long> const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)::{lambda(char)#1}::operator()(char) constWt::Utils::convert<int, boost::spirit::terminal<boost::spirit::tag::int_> >(char const*, boost::spirit::terminal<boost::spirit::tag::int_> const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)::{lambda(char)#1}::operator()(char) constLine | Count | Source | 550 | 4.55k | auto is_space = [](char c) { return c == ' '; }; |
Unexecuted instantiation: Wt::Utils::convert<double, boost::spirit::terminal<boost::spirit::tag::double_> >(char const*, boost::spirit::terminal<boost::spirit::tag::double_> const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)::{lambda(char)#1}::operator()(char) constUnexecuted instantiation: Wt::Utils::convert<float, boost::spirit::terminal<boost::spirit::tag::float_> >(char const*, boost::spirit::terminal<boost::spirit::tag::float_> const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)::{lambda(char)#1}::operator()(char) const |
551 | 2.04k | auto it = std::find_if_not(v.cbegin(), v.cend(), is_space); |
552 | 2.04k | ResultType result{0}; |
553 | 2.04k | bool success = |
554 | 2.04k | it < v.cend() && |
555 | 2.02k | boost::spirit::qi::parse(it, v.cend(), t, result) && |
556 | 1.60k | std::all_of(it, v.cend(), is_space); |
557 | 2.04k | if (!success) |
558 | 1.61k | throw std::invalid_argument(std::string(fname) + "() of " + v + " failed"); |
559 | 429 | return result; |
560 | 2.04k | } Unexecuted instantiation: long Wt::Utils::convert<long, boost::spirit::terminal<boost::spirit::tag::long_> >(char const*, boost::spirit::terminal<boost::spirit::tag::long_> const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) Unexecuted instantiation: unsigned long Wt::Utils::convert<unsigned long, boost::spirit::terminal<boost::spirit::tag::ulong_> >(char const*, boost::spirit::terminal<boost::spirit::tag::ulong_> const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) long long Wt::Utils::convert<long long, boost::spirit::terminal<boost::spirit::tag::long_long> >(char const*, boost::spirit::terminal<boost::spirit::tag::long_long> const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) Line | Count | Source | 549 | 1.10k | { | 550 | 1.10k | auto is_space = [](char c) { return c == ' '; }; | 551 | 1.10k | auto it = std::find_if_not(v.cbegin(), v.cend(), is_space); | 552 | 1.10k | ResultType result{0}; | 553 | 1.10k | bool success = | 554 | 1.10k | it < v.cend() && | 555 | 1.10k | boost::spirit::qi::parse(it, v.cend(), t, result) && | 556 | 909 | std::all_of(it, v.cend(), is_space); | 557 | 1.10k | if (!success) | 558 | 1.10k | throw std::invalid_argument(std::string(fname) + "() of " + v + " failed"); | 559 | 0 | return result; | 560 | 1.10k | } |
Unexecuted instantiation: unsigned long long Wt::Utils::convert<unsigned long long, boost::spirit::terminal<boost::spirit::tag::ulong_long> >(char const*, boost::spirit::terminal<boost::spirit::tag::ulong_long> const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) int Wt::Utils::convert<int, boost::spirit::terminal<boost::spirit::tag::int_> >(char const*, boost::spirit::terminal<boost::spirit::tag::int_> const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) Line | Count | Source | 549 | 941 | { | 550 | 941 | auto is_space = [](char c) { return c == ' '; }; | 551 | 941 | auto it = std::find_if_not(v.cbegin(), v.cend(), is_space); | 552 | 941 | ResultType result{0}; | 553 | 941 | bool success = | 554 | 941 | it < v.cend() && | 555 | 913 | boost::spirit::qi::parse(it, v.cend(), t, result) && | 556 | 696 | std::all_of(it, v.cend(), is_space); | 557 | 941 | if (!success) | 558 | 512 | throw std::invalid_argument(std::string(fname) + "() of " + v + " failed"); | 559 | 429 | return result; | 560 | 941 | } |
Unexecuted instantiation: double Wt::Utils::convert<double, boost::spirit::terminal<boost::spirit::tag::double_> >(char const*, boost::spirit::terminal<boost::spirit::tag::double_> const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) Unexecuted instantiation: float Wt::Utils::convert<float, boost::spirit::terminal<boost::spirit::tag::float_> >(char const*, boost::spirit::terminal<boost::spirit::tag::float_> const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) |
561 | | |
562 | | long stol(const std::string& v) |
563 | 0 | { |
564 | 0 | return convert<long>("stol", boost::spirit::long_, v); |
565 | 0 | } |
566 | | |
567 | | unsigned long stoul(const std::string& v) |
568 | 0 | { |
569 | 0 | return convert<unsigned long>("stoul", boost::spirit::ulong_, v); |
570 | 0 | } |
571 | | |
572 | | long long stoll(const std::string& v) |
573 | 1.10k | { |
574 | 1.10k | return convert<long long>("stoll", boost::spirit::long_long, v); |
575 | 1.10k | } |
576 | | |
577 | | unsigned long long stoull(const std::string& v) |
578 | 0 | { |
579 | 0 | return convert<unsigned long long>("stoull", boost::spirit::ulong_long, v); |
580 | 0 | } |
581 | | |
582 | | int stoi(const std::string& v) |
583 | 941 | { |
584 | 941 | return convert<int>("stoi", boost::spirit::int_, v); |
585 | 941 | } |
586 | | |
587 | | double stod(const std::string& v) |
588 | 0 | { |
589 | 0 | return convert<double>("stod", boost::spirit::double_, v); |
590 | 0 | } |
591 | | |
592 | | float stof(const std::string& v) |
593 | 0 | { |
594 | 0 | return convert<float>("stof", boost::spirit::float_, v); |
595 | 0 | } |
596 | | |
597 | | void fixSelfClosingTags(Wt::rapidxml::xml_node<> *x_node) |
598 | 8.85k | { |
599 | 17.3k | for (Wt::rapidxml::xml_node<> *x_child = x_node->first_node(); x_child; |
600 | 8.85k | x_child = x_child->next_sibling()) |
601 | 8.50k | fixSelfClosingTags(x_child); |
602 | | |
603 | 8.85k | if (!x_node->first_node() |
604 | 8.16k | && x_node->value_size() == 0 |
605 | 5.39k | && !Wt::DomElement::isSelfClosingTag |
606 | 5.39k | (std::string(x_node->name(), x_node->name_size()))) { |
607 | | // We need to add an emtpy data node since <div /> is illegal HTML |
608 | | // (but valid XML / XHTML) |
609 | 3.87k | Wt::rapidxml::xml_node<> *empty = x_node->document()->allocate_node(Wt::rapidxml::node_data); |
610 | 3.87k | x_node->append_node(empty); |
611 | 3.87k | } |
612 | 8.85k | } |
613 | | |
614 | | } |
615 | | } |