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++){
313 std::string convertWindowsLocal8BitToUtf8(const std::string& a)
317 std::vector<wchar_t> wideString;
319 // call to query transform size
320 int requiredWideChars = MultiByteToWideChar(CP_ACP, flags, a.c_str(), a.size(),
322 // allocate storage and call for real
323 wideString.resize(requiredWideChars);
324 MultiByteToWideChar(CP_ACP, flags, a.c_str(), a.size(),
325 wideString.data(), wideString.size());
327 // now convert back down to UTF-8
328 std::vector<char> result;
329 int requiredUTF8Chars = WideCharToMultiByte(CP_UTF8, flags,
330 wideString.data(), wideString.size(),
331 NULL, 0, NULL, NULL);
332 result.resize(requiredUTF8Chars);
333 WideCharToMultiByte(CP_UTF8, flags,
334 wideString.data(), wideString.size(),
335 result.data(), result.size(), NULL, NULL);
336 return std::string(result.data(), result.size());
342 static const std::string base64_chars =
343 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
344 "abcdefghijklmnopqrstuvwxyz"
347 static const unsigned char base64_decode_map[128] =
349 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
350 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
351 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
352 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
353 127, 127, 127, 62, 127, 127, 127, 63, 52, 53,
354 54, 55, 56, 57, 58, 59, 60, 61, 127, 127,
355 127, 64, 127, 127, 127, 0, 1, 2, 3, 4,
356 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
357 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
358 25, 127, 127, 127, 127, 127, 127, 26, 27, 28,
359 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
360 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
361 49, 50, 51, 127, 127, 127, 127, 127
365 static inline bool is_base64(unsigned char c) {
366 return (isalnum(c) || (c == '+') || (c == '/'));
369 static bool is_whitespace(unsigned char c) {
370 return ((c == ' ') || (c == '\r') || (c == '\n'));
373 std::string decodeBase64(const std::string& encoded_string)
375 int in_len = encoded_string.size();
379 unsigned char char_array_4[4], char_array_3[3];
382 while (in_len-- && ( encoded_string[in_] != '=')) {
383 if (is_whitespace( encoded_string[in_])) {
388 if (!is_base64(encoded_string[in_])) {
392 char_array_4[i++] = encoded_string[in_]; in_++;
394 for (i = 0; i <4; i++)
395 char_array_4[i] = base64_decode_map[char_array_4[i]];
397 char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
398 char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
399 char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
401 for (i = 0; (i < 3); i++)
402 ret += char_array_3[i];
408 for (j = i; j <4; j++)
411 for (j = 0; j <4; j++)
412 char_array_4[j] = base64_decode_map[char_array_4[j]];
414 char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
415 char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
416 char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
418 for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
424 const char hexChar[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
426 std::string encodeHex(const std::string& bytes)
429 size_t count = bytes.size();
430 for (unsigned int i=0; i<count;++i) {
431 unsigned char c = bytes[i];
432 hex.push_back(hexChar[c >> 4]);
433 hex.push_back(hexChar[c & 0x0f]);
439 std::string encodeHex(const unsigned char* rawBytes, unsigned int length)
442 for (unsigned int i=0; i<length;++i) {
443 unsigned char c = *rawBytes++;
444 hex.push_back(hexChar[c >> 4]);
445 hex.push_back(hexChar[c & 0x0f]);
451 //------------------------------------------------------------------------------
452 std::string unescape(const char* s)
468 } else if (*s == 'n') {
470 } else if (*s == 'r') {
472 } else if (*s == 't') {
474 } else if (*s == 'v') {
476 } else if (*s == 'f') {
478 } else if (*s == 'a') {
480 } else if (*s == 'b') {
482 } else if (*s == 'x') {
486 for (int i = 0; i < 2 && isxdigit(*s); i++, s++)
487 v = v * 16 + (isdigit(*s) ? *s - '0' : 10 + tolower(*s) - 'a');
491 } else if (*s >= '0' && *s <= '7') {
493 for (int i = 0; i < 3 && *s >= '0' && *s <= '7'; i++, s++)
494 v = v * 8 + *s - '0';
506 string sanitizePrintfFormat(const string& input)
508 string::size_type i = input.find("%n");
509 if (i != string::npos) {
510 SG_LOG(SG_IO, SG_WARN, "sanitizePrintfFormat: bad format string:" << input);
517 } // end namespace strutils
519 } // end namespace simgear