3 // Written by Bernie Bright, started 1998
5 // Copyright (C) 1998 Bernie Bright - bbright@bigpond.net.au
7 // This library is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU Library General Public
9 // License as published by the Free Software Foundation; either
10 // version 2 of the License, or (at your option) any later version.
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // Library General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27 #include "strutils.hxx"
29 #include <simgear/debug/logstream.hxx>
33 using std::stringstream;
39 * utf8ToLatin1() convert utf8 to latin, useful for accent character (i.e éâàîè...)
41 template <typename Iterator> size_t get_length (Iterator p) {
42 unsigned char c = static_cast<unsigned char> (*p);
43 if (c < 0x80) return 1;
44 else if (!(c & 0x20)) return 2;
45 else if (!(c & 0x10)) return 3;
46 else if (!(c & 0x08)) return 4;
47 else if (!(c & 0x04)) return 5;
51 typedef unsigned int value_type;
52 template <typename Iterator> value_type get_value (Iterator p) {
53 size_t len = get_length (p);
54 if (len == 1) return *p;
55 value_type res = static_cast<unsigned char> ( *p & (0xff >> (len + 1))) << ((len - 1) * 6 );
56 for (--len; len; --len)
57 res |= (static_cast<unsigned char> (*(++p)) - 0x80) << ((len - 1) * 6);
61 string utf8ToLatin1( string& s_utf8 ) {
63 for (string::iterator p = s_utf8.begin(); p != s_utf8.end(); ++p) {
64 value_type value = get_value<string::iterator&>(p);
65 if (value > 0xff) SG_LOG(SG_IO, SG_WARN, "utf8ToLatin1: wrong char value: " << value);
66 s_latin1 += static_cast<char>(value);
75 split_whitespace( const string& str, int maxsplit )
77 vector<string> result;
78 string::size_type len = str.length();
79 string::size_type i = 0;
85 while (i < len && isspace((unsigned char)str[i]))
92 while (i < len && !isspace((unsigned char)str[i]))
99 result.push_back( str.substr(j, i-j) );
101 while (i < len && isspace((unsigned char)str[i]))
106 if (maxsplit && (countsplit >= maxsplit) && i < len)
108 result.push_back( str.substr( i, len-i ) );
121 split( const string& str, const char* sep, int maxsplit )
124 return split_whitespace( str, maxsplit );
126 vector<string> result;
127 int n = std::strlen( sep );
130 // Error: empty separator string
133 const char* s = str.c_str();
134 string::size_type len = str.length();
135 string::size_type i = 0;
136 string::size_type j = 0;
141 if (s[i] == sep[0] && (n == 1 || std::memcmp(s+i, sep, n) == 0))
143 result.push_back( str.substr(j,i-j) );
146 if (maxsplit && (splitcount >= maxsplit))
155 result.push_back( str.substr(j,len-j) );
160 * The lstrip(), rstrip() and strip() functions are implemented
161 * in do_strip() which uses an additional parameter to indicate what
162 * type of strip should occur.
164 const int LEFTSTRIP = 0;
165 const int RIGHTSTRIP = 1;
166 const int BOTHSTRIP = 2;
169 do_strip( const string& s, int striptype )
171 string::size_type len = s.length();
172 if( len == 0 ) // empty string is trivial
174 string::size_type i = 0;
175 if (striptype != RIGHTSTRIP)
177 while (i < len && isspace(s[i]))
183 string::size_type j = len;
184 if (striptype != LEFTSTRIP)
190 while (j >= 1 && isspace(s[j]));
194 if (i == 0 && j == len)
200 return s.substr( i, j - i );
205 lstrip( const string& s )
207 return do_strip( s, LEFTSTRIP );
211 rstrip( const string& s )
213 return do_strip( s, RIGHTSTRIP );
217 strip( const string& s )
219 return do_strip( s, BOTHSTRIP );
223 rpad( const string & s, string::size_type length, char c )
225 string::size_type l = s.length();
226 if( l >= length ) return s;
228 return reply.append( length-l, c );
232 lpad( const string & s, size_t length, char c )
234 string::size_type l = s.length();
235 if( l >= length ) return s;
237 return reply.insert( 0, length-l, c );
241 starts_with( const string & s, const string & substr )
243 return s.compare(0, substr.length(), substr) == 0;
247 ends_with( const string & s, const string & substr )
249 if( substr.length() > s.length() )
251 return s.compare( s.length() - substr.length(),
256 string simplify(const string& s)
258 string result; // reserve size of 's'?
259 string::const_iterator it = s.begin(),
262 // advance to first non-space char - simplifes logic in main loop,
263 // since we can always prepend a single space when we see a
264 // space -> non-space transition
265 for (; (it != end) && isspace(*it); ++it) { /* nothing */ }
267 bool lastWasSpace = false;
268 for (; it != end; ++it) {
276 result.push_back(' ');
279 lastWasSpace = false;
286 int to_int(const std::string& s, int base)
290 case 8: ss >> std::oct; break;
291 case 16: ss >> std::hex; break;
300 int compare_versions(const string& v1, const string& v2)
302 vector<string> v1parts(split(v1, "."));
303 vector<string> v2parts(split(v2, "."));
305 int lastPart = std::min(v1parts.size(), v2parts.size());
306 for (int part=0; part < lastPart; ++part) {
307 int part1 = to_int(v1parts[part]);
308 int part2 = to_int(v2parts[part]);
310 if (part1 != part2) {
311 return part1 - part2;
313 } // of parts iteration
315 // reached end - longer wins
316 return v1parts.size() - v2parts.size();
319 string join(const string_list& l, const string& joinWith)
322 unsigned int count = l.size();
323 for (unsigned int i=0; i < count; ++i) {
325 if (i < (count - 1)) {
333 string uppercase(const string &s) {
335 for(string::iterator p = rslt.begin(); p != rslt.end(); p++){
341 string lowercase(const string &s) {
343 for(string::iterator p = rslt.begin(); p != rslt.end(); p++){
349 void lowercase(string &s) {
350 for(string::iterator p = s.begin(); p != s.end(); p++){
355 #if defined(SG_WINDOWS)
359 static WCharVec convertMultiByteToWString(DWORD encoding, const std::string& a)
363 int requiredWideChars = MultiByteToWideChar(encoding, flags,
366 result.resize(requiredWideChars);
367 MultiByteToWideChar(encoding, flags, a.c_str(), a.size(),
368 result.data(), result.size());
372 WCharVec convertUtf8ToWString(const std::string& a)
374 return convertMultiByteToWString(CP_UTF8, a);
379 std::string convertWindowsLocal8BitToUtf8(const std::string& a)
383 WCharVec wideString = convertMultiByteToWString(CP_ACP, a);
385 // convert down to UTF-8
386 std::vector<char> result;
387 int requiredUTF8Chars = WideCharToMultiByte(CP_UTF8, flags,
388 wideString.data(), wideString.size(),
389 NULL, 0, NULL, NULL);
390 result.resize(requiredUTF8Chars);
391 WideCharToMultiByte(CP_UTF8, flags,
392 wideString.data(), wideString.size(),
393 result.data(), result.size(), NULL, NULL);
394 return std::string(result.data(), result.size());
402 static const std::string base64_chars =
403 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
404 "abcdefghijklmnopqrstuvwxyz"
407 static const unsigned char base64_decode_map[128] =
409 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
410 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
411 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
412 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
413 127, 127, 127, 62, 127, 127, 127, 63, 52, 53,
414 54, 55, 56, 57, 58, 59, 60, 61, 127, 127,
415 127, 64, 127, 127, 127, 0, 1, 2, 3, 4,
416 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
417 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
418 25, 127, 127, 127, 127, 127, 127, 26, 27, 28,
419 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
420 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
421 49, 50, 51, 127, 127, 127, 127, 127
425 static inline bool is_base64(unsigned char c) {
426 return (isalnum(c) || (c == '+') || (c == '/'));
429 static bool is_whitespace(unsigned char c) {
430 return ((c == ' ') || (c == '\r') || (c == '\n'));
433 void decodeBase64(const std::string& encoded_string, std::vector<unsigned char>& ret)
435 int in_len = encoded_string.size();
439 unsigned char char_array_4[4], char_array_3[3];
441 while (in_len-- && ( encoded_string[in_] != '=')) {
442 if (is_whitespace( encoded_string[in_])) {
447 if (!is_base64(encoded_string[in_])) {
451 char_array_4[i++] = encoded_string[in_]; in_++;
453 for (i = 0; i <4; i++)
454 char_array_4[i] = base64_decode_map[char_array_4[i]];
456 char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
457 char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
458 char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
460 for (i = 0; (i < 3); i++)
461 ret.push_back(char_array_3[i]);
467 for (j = i; j <4; j++)
470 for (j = 0; j <4; j++)
471 char_array_4[j] = base64_decode_map[char_array_4[j]];
473 char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
474 char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
475 char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
477 for (j = 0; (j < i - 1); j++) ret.push_back(char_array_3[j]);
481 const char hexChar[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
483 std::string encodeHex(const std::string& bytes)
486 size_t count = bytes.size();
487 for (unsigned int i=0; i<count;++i) {
488 unsigned char c = bytes[i];
489 hex.push_back(hexChar[c >> 4]);
490 hex.push_back(hexChar[c & 0x0f]);
496 std::string encodeHex(const unsigned char* rawBytes, unsigned int length)
499 for (unsigned int i=0; i<length;++i) {
500 unsigned char c = *rawBytes++;
501 hex.push_back(hexChar[c >> 4]);
502 hex.push_back(hexChar[c & 0x0f]);
508 //------------------------------------------------------------------------------
509 std::string unescape(const char* s)
525 } else if (*s == 'n') {
527 } else if (*s == 'r') {
529 } else if (*s == 't') {
531 } else if (*s == 'v') {
533 } else if (*s == 'f') {
535 } else if (*s == 'a') {
537 } else if (*s == 'b') {
539 } else if (*s == 'x') {
543 for (int i = 0; i < 2 && isxdigit(*s); i++, s++)
544 v = v * 16 + (isdigit(*s) ? *s - '0' : 10 + tolower(*s) - 'a');
548 } else if (*s >= '0' && *s <= '7') {
550 for (int i = 0; i < 3 && *s >= '0' && *s <= '7'; i++, s++)
551 v = v * 8 + *s - '0';
563 string sanitizePrintfFormat(const string& input)
565 string::size_type i = input.find("%n");
566 if (i != string::npos) {
567 SG_LOG(SG_IO, SG_WARN, "sanitizePrintfFormat: bad format string:" << input);
574 } // end namespace strutils
576 } // end namespace simgear