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;
42 split_whitespace( const string& str, int maxsplit )
44 vector<string> result;
45 string::size_type len = str.length();
46 string::size_type i = 0;
52 while (i < len && isspace((unsigned char)str[i]))
59 while (i < len && !isspace((unsigned char)str[i]))
66 result.push_back( str.substr(j, i-j) );
68 while (i < len && isspace((unsigned char)str[i]))
73 if (maxsplit && (countsplit >= maxsplit) && i < len)
75 result.push_back( str.substr( i, len-i ) );
88 split( const string& str, const char* sep, int maxsplit )
91 return split_whitespace( str, maxsplit );
93 vector<string> result;
94 int n = std::strlen( sep );
97 // Error: empty separator string
100 const char* s = str.c_str();
101 string::size_type len = str.length();
102 string::size_type i = 0;
103 string::size_type j = 0;
108 if (s[i] == sep[0] && (n == 1 || std::memcmp(s+i, sep, n) == 0))
110 result.push_back( str.substr(j,i-j) );
113 if (maxsplit && (splitcount >= maxsplit))
122 result.push_back( str.substr(j,len-j) );
127 * The lstrip(), rstrip() and strip() functions are implemented
128 * in do_strip() which uses an additional parameter to indicate what
129 * type of strip should occur.
131 const int LEFTSTRIP = 0;
132 const int RIGHTSTRIP = 1;
133 const int BOTHSTRIP = 2;
136 do_strip( const string& s, int striptype )
138 string::size_type len = s.length();
139 if( len == 0 ) // empty string is trivial
141 string::size_type i = 0;
142 if (striptype != RIGHTSTRIP)
144 while (i < len && isspace(s[i]))
150 string::size_type j = len;
151 if (striptype != LEFTSTRIP)
157 while (j >= 1 && isspace(s[j]));
161 if (i == 0 && j == len)
167 return s.substr( i, j - i );
172 lstrip( const string& s )
174 return do_strip( s, LEFTSTRIP );
178 rstrip( const string& s )
180 return do_strip( s, RIGHTSTRIP );
184 strip( const string& s )
186 return do_strip( s, BOTHSTRIP );
190 rpad( const string & s, string::size_type length, char c )
192 string::size_type l = s.length();
193 if( l >= length ) return s;
195 return reply.append( length-l, c );
199 lpad( const string & s, size_t length, char c )
201 string::size_type l = s.length();
202 if( l >= length ) return s;
204 return reply.insert( 0, length-l, c );
208 starts_with( const string & s, const string & substr )
210 return s.compare(0, substr.length(), substr) == 0;
214 ends_with( const string & s, const string & substr )
216 if( substr.length() > s.length() )
218 return s.compare( s.length() - substr.length(),
223 string simplify(const string& s)
225 string result; // reserve size of 's'?
226 string::const_iterator it = s.begin(),
229 // advance to first non-space char - simplifes logic in main loop,
230 // since we can always prepend a single space when we see a
231 // space -> non-space transition
232 for (; (it != end) && isspace(*it); ++it) { /* nothing */ }
234 bool lastWasSpace = false;
235 for (; it != end; ++it) {
243 result.push_back(' ');
246 lastWasSpace = false;
253 int to_int(const std::string& s, int base)
257 case 8: ss >> std::oct; break;
258 case 16: ss >> std::hex; break;
267 int compare_versions(const string& v1, const string& v2)
269 vector<string> v1parts(split(v1, "."));
270 vector<string> v2parts(split(v2, "."));
272 int lastPart = std::min(v1parts.size(), v2parts.size());
273 for (int part=0; part < lastPart; ++part) {
274 int part1 = to_int(v1parts[part]);
275 int part2 = to_int(v2parts[part]);
277 if (part1 != part2) {
278 return part1 - part2;
280 } // of parts iteration
282 // reached end - longer wins
283 return v1parts.size() - v2parts.size();
286 string join(const string_list& l, const string& joinWith)
289 unsigned int count = l.size();
290 for (unsigned int i=0; i < count; ++i) {
292 if (i < (count - 1)) {
300 string uppercase(const string &s) {
302 for(string::iterator p = rslt.begin(); p != rslt.end(); p++){
308 string lowercase(const string &s) {
310 for(string::iterator p = rslt.begin(); p != rslt.end(); p++){
316 void lowercase(string &s) {
317 for(string::iterator p = s.begin(); p != s.end(); p++){
322 #if defined(SG_WINDOWS)
326 static WCharVec convertMultiByteToWString(DWORD encoding, const std::string& a)
330 int requiredWideChars = MultiByteToWideChar(encoding, flags,
333 result.resize(requiredWideChars);
334 MultiByteToWideChar(encoding, flags, a.c_str(), a.size(),
335 result.data(), result.size());
339 WCharVec convertUtf8ToWString(const std::string& a)
341 return convertMultiByteToWString(CP_UTF8, a);
346 std::string convertWindowsLocal8BitToUtf8(const std::string& a)
350 WCharVec wideString = convertMultiByteToWString(CP_ACP, a);
352 // convert down to UTF-8
353 std::vector<char> result;
354 int requiredUTF8Chars = WideCharToMultiByte(CP_UTF8, flags,
355 wideString.data(), wideString.size(),
356 NULL, 0, NULL, NULL);
357 result.resize(requiredUTF8Chars);
358 WideCharToMultiByte(CP_UTF8, flags,
359 wideString.data(), wideString.size(),
360 result.data(), result.size(), NULL, NULL);
361 return std::string(result.data(), result.size());
369 static const std::string base64_chars =
370 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
371 "abcdefghijklmnopqrstuvwxyz"
374 static const unsigned char base64_decode_map[128] =
376 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
377 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
378 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
379 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
380 127, 127, 127, 62, 127, 127, 127, 63, 52, 53,
381 54, 55, 56, 57, 58, 59, 60, 61, 127, 127,
382 127, 64, 127, 127, 127, 0, 1, 2, 3, 4,
383 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
384 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
385 25, 127, 127, 127, 127, 127, 127, 26, 27, 28,
386 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
387 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
388 49, 50, 51, 127, 127, 127, 127, 127
392 static inline bool is_base64(unsigned char c) {
393 return (isalnum(c) || (c == '+') || (c == '/'));
396 static bool is_whitespace(unsigned char c) {
397 return ((c == ' ') || (c == '\r') || (c == '\n'));
400 void decodeBase64(const std::string& encoded_string, std::vector<unsigned char>& ret)
402 int in_len = encoded_string.size();
406 unsigned char char_array_4[4], char_array_3[3];
408 while (in_len-- && ( encoded_string[in_] != '=')) {
409 if (is_whitespace( encoded_string[in_])) {
414 if (!is_base64(encoded_string[in_])) {
418 char_array_4[i++] = encoded_string[in_]; in_++;
420 for (i = 0; i <4; i++)
421 char_array_4[i] = base64_decode_map[char_array_4[i]];
423 char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
424 char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
425 char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
427 for (i = 0; (i < 3); i++)
428 ret.push_back(char_array_3[i]);
434 for (j = i; j <4; j++)
437 for (j = 0; j <4; j++)
438 char_array_4[j] = base64_decode_map[char_array_4[j]];
440 char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
441 char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
442 char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
444 for (j = 0; (j < i - 1); j++) ret.push_back(char_array_3[j]);
448 const char hexChar[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
450 std::string encodeHex(const std::string& bytes)
453 size_t count = bytes.size();
454 for (unsigned int i=0; i<count;++i) {
455 unsigned char c = bytes[i];
456 hex.push_back(hexChar[c >> 4]);
457 hex.push_back(hexChar[c & 0x0f]);
463 std::string encodeHex(const unsigned char* rawBytes, unsigned int length)
466 for (unsigned int i=0; i<length;++i) {
467 unsigned char c = *rawBytes++;
468 hex.push_back(hexChar[c >> 4]);
469 hex.push_back(hexChar[c & 0x0f]);
475 //------------------------------------------------------------------------------
476 std::string unescape(const char* s)
492 } else if (*s == 'n') {
494 } else if (*s == 'r') {
496 } else if (*s == 't') {
498 } else if (*s == 'v') {
500 } else if (*s == 'f') {
502 } else if (*s == 'a') {
504 } else if (*s == 'b') {
506 } else if (*s == 'x') {
510 for (int i = 0; i < 2 && isxdigit(*s); i++, s++)
511 v = v * 16 + (isdigit(*s) ? *s - '0' : 10 + tolower(*s) - 'a');
515 } else if (*s >= '0' && *s <= '7') {
517 for (int i = 0; i < 3 && *s >= '0' && *s <= '7'; i++, s++)
518 v = v * 8 + *s - '0';
530 string sanitizePrintfFormat(const string& input)
532 string::size_type i = input.find("%n");
533 if (i != string::npos) {
534 SG_LOG(SG_IO, SG_WARN, "sanitizePrintfFormat: bad format string:" << input);
541 } // end namespace strutils
543 } // end namespace simgear