Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file StringUtils.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Laura Bieker
17 : /// @author Michael Behrisch
18 : /// @author Robert Hilbrich
19 : /// @date unknown
20 : ///
21 : // Some static methods for string processing
22 : /****************************************************************************/
23 : #include <config.h>
24 :
25 : #include <string>
26 : #include <iostream>
27 : #include <cstdio>
28 : #include <cstring>
29 : #include <regex>
30 : #ifdef WIN32
31 : #define NOMINMAX
32 : #include <windows.h>
33 : #undef NOMINMAX
34 : #else
35 : #include <unistd.h>
36 : #endif
37 : #include <xercesc/util/TransService.hpp>
38 : #include <xercesc/util/TranscodingException.hpp>
39 : #include <utils/common/UtilExceptions.h>
40 : #include <utils/common/ToString.h>
41 : #include <utils/common/StringTokenizer.h>
42 : #include "StringUtils.h"
43 :
44 : #define KM_PER_MILE 1.609344
45 :
46 :
47 : // ===========================================================================
48 : // static member definitions
49 : // ===========================================================================
50 : std::string StringUtils::emptyString;
51 : XERCES_CPP_NAMESPACE::XMLLCPTranscoder* StringUtils::myLCPTranscoder = nullptr;
52 :
53 :
54 : // ===========================================================================
55 : // method definitions
56 : // ===========================================================================
57 : std::string
58 1610703 : StringUtils::prune(const std::string& str) {
59 : const std::string::size_type endpos = str.find_last_not_of(" \t\n\r");
60 1610703 : if (std::string::npos != endpos) {
61 1607566 : const int startpos = (int)str.find_first_not_of(" \t\n\r");
62 1607566 : return str.substr(startpos, endpos - startpos + 1);
63 : }
64 3137 : return "";
65 : }
66 :
67 :
68 : std::string
69 56820 : StringUtils::pruneZeros(const std::string& str, int max) {
70 : const std::string::size_type endpos = str.find_last_not_of("0");
71 56820 : if (endpos != std::string::npos && str.back() == '0') {
72 38001 : std::string res = str.substr(0, MAX2((int)str.size() - max, (int)endpos + 1));
73 38001 : return res;
74 : }
75 : return str;
76 : }
77 :
78 : std::string
79 8321769 : StringUtils::to_lower_case(const std::string& str) {
80 : std::string s = str;
81 : std::transform(s.begin(), s.end(), s.begin(), [](char c) {
82 56357572 : return (char)::tolower(c);
83 : });
84 8321769 : return s;
85 : }
86 :
87 :
88 : std::string
89 1885 : StringUtils::latin1_to_utf8(std::string str) {
90 : // inspired by http://stackoverflow.com/questions/4059775/convert-iso-8859-1-strings-to-utf-8-in-c-c
91 : std::string result;
92 8168 : for (const auto& c : str) {
93 6283 : const unsigned char uc = (unsigned char)c;
94 6283 : if (uc < 128) {
95 : result += uc;
96 : } else {
97 81 : result += (char)(0xc2 + (uc > 0xbf));
98 81 : result += (char)((uc & 0x3f) + 0x80);
99 : }
100 : }
101 1885 : return result;
102 : }
103 :
104 :
105 : std::string
106 853867 : StringUtils::convertUmlaute(std::string str) {
107 2561601 : str = replace(str, "\xE4", "ae");
108 2561601 : str = replace(str, "\xC4", "Ae");
109 2561601 : str = replace(str, "\xF6", "oe");
110 2561601 : str = replace(str, "\xD6", "Oe");
111 2561601 : str = replace(str, "\xFC", "ue");
112 2561601 : str = replace(str, "\xDC", "Ue");
113 2561601 : str = replace(str, "\xDF", "ss");
114 2561601 : str = replace(str, "\xC9", "E");
115 2561601 : str = replace(str, "\xE9", "e");
116 2561601 : str = replace(str, "\xC8", "E");
117 2561601 : str = replace(str, "\xE8", "e");
118 853867 : return str;
119 : }
120 :
121 :
122 : std::string
123 61895546 : StringUtils::replace(std::string str, const std::string& what, const std::string& by) {
124 : std::string::size_type idx = str.find(what);
125 61895546 : const int what_len = (int)what.length();
126 61895546 : if (what_len > 0) {
127 61895545 : const int by_len = (int)by.length();
128 61898754 : while (idx != std::string::npos) {
129 3209 : str = str.replace(idx, what_len, by);
130 3209 : idx = str.find(what, idx + by_len);
131 : }
132 : }
133 61895546 : return str;
134 : }
135 :
136 :
137 : std::string
138 1249117 : StringUtils::substituteEnvironment(const std::string& str, const std::chrono::time_point<std::chrono::system_clock>* const timeRef) {
139 : std::string s = str;
140 1249117 : if (timeRef != nullptr) {
141 : const std::string::size_type localTimeIndex = str.find("${LOCALTIME}");
142 : const std::string::size_type utcIndex = str.find("${UTC}");
143 : const bool isUTC = utcIndex != std::string::npos;
144 1249111 : if (localTimeIndex != std::string::npos || isUTC) {
145 6 : const time_t rawtime = std::chrono::system_clock::to_time_t(*timeRef);
146 : char buffer [80];
147 6 : struct tm* timeinfo = isUTC ? gmtime(&rawtime) : localtime(&rawtime);
148 6 : strftime(buffer, 80, "%Y-%m-%d-%H-%M-%S.", timeinfo);
149 : auto seconds = std::chrono::time_point_cast<std::chrono::seconds>(*timeRef);
150 : auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(*timeRef - seconds);
151 6 : const std::string micro = buffer + toString(microseconds.count());
152 6 : if (isUTC) {
153 : s.replace(utcIndex, 6, micro);
154 : } else {
155 : s.replace(localTimeIndex, 12, micro);
156 : }
157 : }
158 : }
159 : const std::string::size_type pidIndex = str.find("${PID}");
160 1249117 : if (pidIndex != std::string::npos) {
161 : #ifdef WIN32
162 : s.replace(pidIndex, 6, toString(::GetCurrentProcessId()));
163 : #else
164 6 : s.replace(pidIndex, 6, toString(::getpid()));
165 : #endif
166 : }
167 1249117 : if (std::getenv("SUMO_LOGO") == nullptr) {
168 3747351 : s = replace(s, "${SUMO_LOGO}", "${SUMO_HOME}/data/logo/sumo-128x138.png");
169 : }
170 : const std::string::size_type tildeIndex = str.find("~");
171 1249117 : if (tildeIndex == 0) {
172 3 : s.replace(0, 1, "${HOME}");
173 : }
174 3747351 : s = replace(s, ",~", ",${HOME}");
175 : #ifdef WIN32
176 : if (std::getenv("HOME") == nullptr) {
177 : s = replace(s, "${HOME}", "${USERPROFILE}");
178 : }
179 : #endif
180 :
181 : // Expression for an environment variables, e.g. ${NAME}
182 : // Note: - R"(...)" is a raw string literal syntax to simplify a regex declaration
183 : // - .+? looks for the shortest match (non-greedy)
184 : // - (.+?) defines a "subgroup" which is already stripped of the $ and {, }
185 1249117 : std::regex envVarExpr(R"(\$\{(.+?)\})");
186 :
187 : // Are there any variables in this string?
188 : std::smatch match;
189 : std::string strIter = s;
190 :
191 : // Loop over the entire value string and look for variable names
192 1249183 : while (std::regex_search(strIter, match, envVarExpr)) {
193 : std::string varName = match[1];
194 :
195 : // Find the variable in the environment and its value
196 : std::string varValue;
197 66 : if (std::getenv(varName.c_str()) != nullptr) {
198 65 : varValue = std::getenv(varName.c_str());
199 : }
200 :
201 : // Replace the variable placeholder with its value in the original string
202 264 : s = std::regex_replace(s, std::regex("\\$\\{" + varName + "\\}"), varValue);
203 :
204 : // Continue the loop with the remainder of the string
205 132 : strIter = match.suffix();
206 : }
207 1249117 : return s;
208 1249117 : }
209 :
210 :
211 : bool
212 4920826 : StringUtils::startsWith(const std::string& str, const std::string prefix) {
213 4920826 : return str.compare(0, prefix.length(), prefix) == 0;
214 : }
215 :
216 :
217 : bool
218 220129 : StringUtils::endsWith(const std::string& str, const std::string suffix) {
219 220129 : if (str.length() >= suffix.length()) {
220 220107 : return str.compare(str.length() - suffix.length(), suffix.length(), suffix) == 0;
221 : } else {
222 : return false;
223 : }
224 : }
225 :
226 :
227 : std::string
228 0 : StringUtils::padFront(const std::string& str, int length, char padding) {
229 0 : return std::string(MAX2(0, length - (int)str.size()), padding) + str;
230 : }
231 :
232 :
233 : std::string
234 1366691 : StringUtils::escapeXML(const std::string& orig, const bool maskDoubleHyphen) {
235 4100073 : std::string result = replace(orig, "&", "&");
236 4100073 : result = replace(result, ">", ">");
237 4100073 : result = replace(result, "<", "<");
238 4100073 : result = replace(result, "\"", """);
239 1366691 : if (maskDoubleHyphen) {
240 2407317 : result = replace(result, "--", "--");
241 : }
242 43734112 : for (char invalid = '\1'; invalid < ' '; invalid++) {
243 211837105 : result = replace(result, std::string(1, invalid).c_str(), "");
244 : }
245 4100073 : return replace(result, "'", "'");
246 : }
247 :
248 :
249 : std::string
250 0 : StringUtils::escapeShell(const std::string& orig) {
251 0 : std::string result = replace(orig, "\"", "\\\"");
252 0 : return result;
253 : }
254 :
255 :
256 : std::string
257 3681 : StringUtils::urlEncode(const std::string& toEncode, const std::string encodeWhich) {
258 3681 : std::ostringstream out;
259 :
260 97050 : for (int i = 0; i < (int)toEncode.length(); ++i) {
261 93369 : const char t = toEncode.at(i);
262 :
263 93369 : if ((encodeWhich != "" && encodeWhich.find(t) == std::string::npos) ||
264 1 : (encodeWhich == "" &&
265 0 : ((t >= 45 && t <= 57) || // hyphen, period, slash, 0-9
266 0 : (t >= 65 && t <= 90) || // A-Z
267 : t == 95 || // underscore
268 : (t >= 97 && t <= 122) || // a-z
269 : t == 126)) // tilde
270 : ) {
271 93368 : out << toEncode.at(i);
272 : } else {
273 2 : out << charToHex(toEncode.at(i));
274 : }
275 : }
276 :
277 3681 : return out.str();
278 3681 : }
279 :
280 :
281 : std::string
282 76465 : StringUtils::urlDecode(const std::string& toDecode) {
283 76465 : std::ostringstream out;
284 :
285 1140857 : for (int i = 0; i < (int)toDecode.length(); ++i) {
286 1064394 : if (toDecode.at(i) == '%') {
287 2 : std::string str(toDecode.substr(i + 1, 2));
288 2 : out << hexToChar(str);
289 0 : i += 2;
290 : } else {
291 1064392 : out << toDecode.at(i);
292 : }
293 : }
294 :
295 76463 : return out.str();
296 76465 : }
297 :
298 : std::string
299 1 : StringUtils::charToHex(unsigned char c) {
300 : short i = c;
301 :
302 1 : std::stringstream s;
303 :
304 1 : s << "%" << std::setw(2) << std::setfill('0') << std::hex << i;
305 :
306 1 : return s.str();
307 1 : }
308 :
309 :
310 : unsigned char
311 2 : StringUtils::hexToChar(const std::string& str) {
312 2 : short c = 0;
313 2 : if (!str.empty()) {
314 2 : std::istringstream in(str);
315 2 : in >> std::hex >> c;
316 2 : if (in.fail()) {
317 4 : throw NumberFormatException(str + " could not be interpreted as hex");
318 : }
319 2 : }
320 0 : return static_cast<unsigned char>(c);
321 : }
322 :
323 :
324 : int
325 19322145 : StringUtils::toInt(const std::string& sData) {
326 19322145 : long long int result = toLong(sData);
327 19295665 : if (result > std::numeric_limits<int>::max() || result < std::numeric_limits<int>::min()) {
328 3 : throw NumberFormatException(toString(result) + " int overflow");
329 : }
330 19295664 : return (int)result;
331 : }
332 :
333 :
334 : bool
335 8 : StringUtils::isInt(const std::string& sData) {
336 : // first check if can be converted to long int
337 8 : if (isLong(sData)) {
338 0 : const long long int result = toLong(sData);
339 : // now check if the result is in the range of an int
340 0 : return ((result <= std::numeric_limits<int>::max()) && (result >= std::numeric_limits<int>::min()));
341 : }
342 : return false;
343 : }
344 :
345 :
346 : int
347 0 : StringUtils::toIntSecure(const std::string& sData, int def) {
348 0 : if (sData.length() == 0) {
349 : return def;
350 : }
351 0 : return toInt(sData);
352 : }
353 :
354 :
355 : long long int
356 20740617 : StringUtils::toLong(const std::string& sData) {
357 : const char* const data = sData.c_str();
358 20740617 : if (data == 0 || data[0] == 0) {
359 64 : throw EmptyData();
360 : }
361 : char* end;
362 20740553 : errno = 0;
363 : #ifdef _MSC_VER
364 : long long int ret = _strtoi64(data, &end, 10);
365 : #else
366 20740553 : long long int ret = strtoll(data, &end, 10);
367 : #endif
368 20740553 : if (errno == ERANGE) {
369 0 : errno = 0;
370 0 : throw NumberFormatException("(long long integer range) " + sData);
371 : }
372 20740553 : if ((int)(end - data) != (int)strlen(data)) {
373 72848 : throw NumberFormatException("(long long integer format) " + sData);
374 : }
375 20704129 : return ret;
376 : }
377 :
378 :
379 : bool
380 8 : StringUtils::isLong(const std::string& sData) {
381 : const char* const data = sData.c_str();
382 8 : if (data == 0 || data[0] == 0) {
383 : return false;
384 : }
385 : char* end;
386 : // reset errno before parsing, to keep errors
387 8 : errno = 0;
388 : // continue depending of current plattform
389 : #ifdef _MSC_VER
390 : _strtoi64(data, &end, 10);
391 : #else
392 8 : strtoll(data, &end, 10);
393 : #endif
394 : // check out of range
395 8 : if (errno == ERANGE) {
396 : return false;
397 : }
398 : // check lenght of converted data
399 8 : if ((int)(end - data) != (int)strlen(data)) {
400 : return false;
401 : }
402 : return true;
403 : }
404 :
405 :
406 : int
407 936 : StringUtils::hexToInt(const std::string& sData) {
408 936 : if (sData.length() == 0) {
409 0 : throw EmptyData();
410 : }
411 936 : size_t idx = 0;
412 : int result;
413 : try {
414 936 : if (sData[0] == '#') { // for html color codes
415 852 : result = std::stoi(sData.substr(1), &idx, 16);
416 852 : idx++;
417 : } else {
418 : result = std::stoi(sData, &idx, 16);
419 : }
420 0 : } catch (...) {
421 0 : throw NumberFormatException("(hex integer format) " + sData);
422 0 : }
423 936 : if (idx != sData.length()) {
424 0 : throw NumberFormatException("(hex integer format) " + sData);
425 : }
426 936 : return result;
427 : }
428 :
429 :
430 : bool
431 0 : StringUtils::isHex(std::string sData) {
432 0 : if (sData.length() == 0) {
433 : return false;
434 : }
435 : // remove the first character (for HTML color codes)
436 0 : if (sData[0] == '#') {
437 0 : sData = sData.substr(1);
438 : }
439 : const char* sDataPtr = sData.c_str();
440 : char* returnPtr;
441 : // reset errno
442 0 : errno = 0;
443 : // call string to long (size 16) from standard library
444 0 : strtol(sDataPtr, &returnPtr, 16);
445 : // check out of range
446 0 : if (errno == ERANGE) {
447 : return false;
448 : }
449 : // check if there was an error converting sDataPtr to double,
450 0 : if (sDataPtr == returnPtr) {
451 : return false;
452 : }
453 : // compare size of start and end points
454 0 : if (static_cast<size_t>(returnPtr - sDataPtr) != sData.size()) {
455 : return false;
456 : }
457 : return true;
458 : }
459 :
460 :
461 : double
462 70070791 : StringUtils::toDouble(const std::string& sData) {
463 70070791 : if (sData.size() == 0) {
464 191 : throw EmptyData();
465 : }
466 : try {
467 70070600 : size_t idx = 0;
468 : const double result = std::stod(sData, &idx);
469 70069027 : if (idx != sData.size()) {
470 30 : throw NumberFormatException("(double format) " + sData);
471 : } else {
472 70069012 : return result;
473 : }
474 1588 : } catch (...) {
475 : // invalid_argument or out_of_range
476 3176 : throw NumberFormatException("(double) " + sData);
477 1588 : }
478 : }
479 :
480 :
481 : bool
482 0 : StringUtils::isDouble(const std::string& sData) {
483 0 : if (sData.size() == 0) {
484 : return false;
485 : }
486 : const char* sDataPtr = sData.c_str();
487 : char* returnPtr;
488 : // reset errno
489 0 : errno = 0;
490 : // call string to double from standard library
491 0 : strtod(sDataPtr, &returnPtr);
492 : // check out of range
493 0 : if (errno == ERANGE) {
494 : return false;
495 : }
496 : // check if there was an error converting sDataPtr to double,
497 0 : if (sDataPtr == returnPtr) {
498 : return false;
499 : }
500 : // compare size of start and end points
501 0 : if (static_cast<size_t>(returnPtr - sDataPtr) != sData.size()) {
502 : return false;
503 : }
504 : return true;
505 : }
506 :
507 :
508 : double
509 330 : StringUtils::toDoubleSecure(const std::string& sData, const double def) {
510 330 : if (sData.length() == 0) {
511 : return def;
512 : }
513 330 : return toDouble(sData);
514 : }
515 :
516 :
517 : bool
518 3426481 : StringUtils::toBool(const std::string& sData) {
519 3426481 : if (sData.length() == 0) {
520 1 : throw EmptyData();
521 : }
522 3426480 : const std::string s = to_lower_case(sData);
523 3426480 : if (s == "1" || s == "yes" || s == "true" || s == "on" || s == "x" || s == "t") {
524 : return true;
525 : }
526 2820508 : if (s == "0" || s == "no" || s == "false" || s == "off" || s == "-" || s == "f") {
527 : return false;
528 : }
529 63 : throw BoolFormatException(s);
530 : }
531 :
532 :
533 : bool
534 0 : StringUtils::isBool(const std::string& sData) {
535 0 : if (sData.length() == 0) {
536 : return false;
537 : }
538 0 : const std::string s = to_lower_case(sData);
539 : // check true values
540 0 : if (s == "1" || s == "yes" || s == "true" || s == "on" || s == "x" || s == "t") {
541 : return true;
542 : }
543 : // check false values
544 0 : if (s == "0" || s == "no" || s == "false" || s == "off" || s == "-" || s == "f") {
545 : return true;
546 : }
547 : // no valid true or false values
548 : return false;
549 : }
550 :
551 :
552 : MMVersion
553 54843 : StringUtils::toVersion(const std::string& sData) {
554 164529 : std::vector<std::string> parts = StringTokenizer(sData, ".").getVector();
555 109686 : return MMVersion(toInt(parts.front()), toDouble(parts.back()));
556 54843 : }
557 :
558 :
559 : double
560 2197 : StringUtils::parseDist(const std::string& sData) {
561 2197 : if (sData.size() == 0) {
562 1 : throw EmptyData();
563 : }
564 : try {
565 2196 : size_t idx = 0;
566 : const double result = std::stod(sData, &idx);
567 2195 : if (idx != sData.size()) {
568 4 : const std::string unit = prune(sData.substr(idx));
569 4 : if (unit == "m" || unit == "metre" || unit == "meter" || unit == "metres" || unit == "meters") {
570 : return result;
571 : }
572 2 : if (unit == "km" || unit == "kilometre" || unit == "kilometer" || unit == "kilometres" || unit == "kilometers") {
573 1 : return result * 1000.;
574 : }
575 1 : if (unit == "mi" || unit == "mile" || unit == "miles") {
576 0 : return result * 1000. * KM_PER_MILE;
577 : }
578 1 : if (unit == "nmi") {
579 0 : return result * 1852.;
580 : }
581 1 : if (unit == "ft" || unit == "foot" || unit == "feet") {
582 0 : return result * 12. * 0.0254;
583 : }
584 1 : if (unit == "\"" || unit == "in" || unit == "inch" || unit == "inches") {
585 0 : return result * 0.0254;
586 : }
587 1 : if (unit[0] == '\'') {
588 0 : double inches = 12 * result;
589 0 : if (unit.length() > 1) {
590 0 : inches += std::stod(unit.substr(1), &idx);
591 1 : if (unit.substr(idx) == "\"") {
592 0 : return inches * 0.0254;
593 : }
594 : }
595 : }
596 2 : throw NumberFormatException("(distance format) " + sData);
597 : } else {
598 : return result;
599 : }
600 2 : } catch (...) {
601 : // invalid_argument or out_of_range
602 4 : throw NumberFormatException("(double) " + sData);
603 2 : }
604 : }
605 :
606 :
607 : double
608 7111 : StringUtils::parseSpeed(const std::string& sData, const bool defaultKmph) {
609 7111 : if (sData.size() == 0) {
610 1 : throw EmptyData();
611 : }
612 : try {
613 7110 : size_t idx = 0;
614 : const double result = std::stod(sData, &idx);
615 7106 : if (idx != sData.size()) {
616 577 : const std::string unit = prune(sData.substr(idx));
617 577 : if (unit == "km/h" || unit == "kph" || unit == "kmh" || unit == "kmph") {
618 3 : return result / 3.6;
619 : }
620 574 : if (unit == "m/s") {
621 : return result;
622 : }
623 572 : if (unit == "mph") {
624 571 : return result * KM_PER_MILE / 3.6;
625 : }
626 1 : if (unit == "knots") {
627 0 : return result * 1.852 / 3.6;
628 : }
629 2 : throw NumberFormatException("(speed format) " + sData);
630 : } else {
631 6529 : return defaultKmph ? result / 3.6 : result;
632 : }
633 5 : } catch (...) {
634 : // invalid_argument or out_of_range
635 10 : throw NumberFormatException("(double) " + sData);
636 5 : }
637 : }
638 :
639 :
640 : std::string
641 106477714 : StringUtils::transcode(const XMLCh* const data, int length) {
642 106477714 : if (data == 0) {
643 0 : throw EmptyData();
644 : }
645 106477714 : if (length == 0) {
646 353875 : return "";
647 : }
648 : #if _XERCES_VERSION < 30100
649 : char* t = XERCES_CPP_NAMESPACE::XMLString::transcode(data);
650 : std::string result(t);
651 : XERCES_CPP_NAMESPACE::XMLString::release(&t);
652 : return result;
653 : #else
654 : try {
655 106123839 : XERCES_CPP_NAMESPACE::TranscodeToStr utf8(data, "UTF-8");
656 106123839 : return reinterpret_cast<const char*>(utf8.str());
657 106123839 : } catch (XERCES_CPP_NAMESPACE::TranscodingException&) {
658 0 : return "?";
659 0 : }
660 : #endif
661 : }
662 :
663 :
664 : std::string
665 768920 : StringUtils::transcodeFromLocal(const std::string& localString) {
666 : #if _XERCES_VERSION > 30100
667 : try {
668 768920 : if (myLCPTranscoder == nullptr) {
669 58428 : myLCPTranscoder = XERCES_CPP_NAMESPACE::XMLPlatformUtils::fgTransService->makeNewLCPTranscoder(XERCES_CPP_NAMESPACE::XMLPlatformUtils::fgMemoryManager);
670 : }
671 768920 : if (myLCPTranscoder != nullptr) {
672 768920 : return transcode(myLCPTranscoder->transcode(localString.c_str()));
673 : }
674 0 : } catch (XERCES_CPP_NAMESPACE::TranscodingException&) {}
675 : #endif
676 : return localString;
677 : }
678 :
679 :
680 : std::string
681 1005674 : StringUtils::transcodeToLocal(const std::string& utf8String) {
682 : #if _XERCES_VERSION > 30100
683 : try {
684 1005674 : if (myLCPTranscoder == nullptr) {
685 1092 : myLCPTranscoder = XERCES_CPP_NAMESPACE::XMLPlatformUtils::fgTransService->makeNewLCPTranscoder(XERCES_CPP_NAMESPACE::XMLPlatformUtils::fgMemoryManager);
686 : }
687 1005674 : if (myLCPTranscoder != nullptr) {
688 1005674 : XERCES_CPP_NAMESPACE::TranscodeFromStr utf8(reinterpret_cast<const XMLByte*>(utf8String.c_str()), utf8String.size(), "UTF-8");
689 1005674 : return myLCPTranscoder->transcode(utf8.str());
690 1005674 : }
691 0 : } catch (XERCES_CPP_NAMESPACE::TranscodingException&) {}
692 : #endif
693 : return utf8String;
694 : }
695 :
696 :
697 : std::string
698 0 : StringUtils::trim_left(const std::string s, const std::string& t) {
699 : std::string result = s;
700 0 : result.erase(0, s.find_first_not_of(t));
701 0 : return result;
702 : }
703 :
704 : std::string
705 0 : StringUtils::trim_right(const std::string s, const std::string& t) {
706 : std::string result = s;
707 0 : result.erase(s.find_last_not_of(t) + 1);
708 0 : return result;
709 : }
710 :
711 : std::string
712 0 : StringUtils::trim(const std::string s, const std::string& t) {
713 0 : return trim_right(trim_left(s, t), t);
714 : }
715 :
716 :
717 : std::string
718 0 : StringUtils::wrapText(const std::string s, int width) {
719 0 : std::vector<std::string> parts = StringTokenizer(s).getVector();
720 : std::string result;
721 : std::string line;
722 : bool firstLine = true;
723 : bool firstWord = true;
724 0 : for (std::string p : parts) {
725 0 : if ((int)(line.size() + p.size()) < width || firstWord) {
726 0 : if (firstWord) {
727 : firstWord = false;
728 : } else {
729 : line += " ";
730 : }
731 0 : line = line + p;
732 : } else {
733 0 : if (firstLine) {
734 : firstLine = false;
735 : } else {
736 : result += "\n";
737 : }
738 0 : result = result + line;
739 : line.clear();
740 : firstWord = true;
741 : }
742 : }
743 0 : if (line.size() > 0) {
744 0 : if (firstLine) {
745 : firstLine = false;
746 : } else {
747 : result += "\n";
748 : }
749 0 : result = result + line;
750 : }
751 0 : return result;
752 0 : }
753 :
754 :
755 : void
756 59774 : StringUtils::resetTranscoder() {
757 59774 : myLCPTranscoder = nullptr;
758 59774 : }
759 :
760 : /****************************************************************************/
|