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 void decodeBase64(const std::string& encoded_string, std::vector<unsigned char>& ret)
375 int in_len = encoded_string.size();
379 unsigned char char_array_4[4], char_array_3[3];
381 while (in_len-- && ( encoded_string[in_] != '=')) {
382 if (is_whitespace( encoded_string[in_])) {
387 if (!is_base64(encoded_string[in_])) {
391 char_array_4[i++] = encoded_string[in_]; in_++;
393 for (i = 0; i <4; i++)
394 char_array_4[i] = base64_decode_map[char_array_4[i]];
396 char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
397 char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
398 char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
400 for (i = 0; (i < 3); i++)
401 ret.push_back(char_array_3[i]);
407 for (j = i; j <4; j++)
410 for (j = 0; j <4; j++)
411 char_array_4[j] = base64_decode_map[char_array_4[j]];
413 char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
414 char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
415 char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
417 for (j = 0; (j < i - 1); j++) ret.push_back(char_array_3[j]);
421 const char hexChar[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
423 std::string encodeHex(const std::string& bytes)
426 size_t count = bytes.size();
427 for (unsigned int i=0; i<count;++i) {
428 unsigned char c = bytes[i];
429 hex.push_back(hexChar[c >> 4]);
430 hex.push_back(hexChar[c & 0x0f]);
436 std::string encodeHex(const unsigned char* rawBytes, unsigned int length)
439 for (unsigned int i=0; i<length;++i) {
440 unsigned char c = *rawBytes++;
441 hex.push_back(hexChar[c >> 4]);
442 hex.push_back(hexChar[c & 0x0f]);
448 //------------------------------------------------------------------------------
449 std::string unescape(const char* s)
465 } else if (*s == 'n') {
467 } else if (*s == 'r') {
469 } else if (*s == 't') {
471 } else if (*s == 'v') {
473 } else if (*s == 'f') {
475 } else if (*s == 'a') {
477 } else if (*s == 'b') {
479 } else if (*s == 'x') {
483 for (int i = 0; i < 2 && isxdigit(*s); i++, s++)
484 v = v * 16 + (isdigit(*s) ? *s - '0' : 10 + tolower(*s) - 'a');
488 } else if (*s >= '0' && *s <= '7') {
490 for (int i = 0; i < 3 && *s >= '0' && *s <= '7'; i++, s++)
491 v = v * 8 + *s - '0';
503 string sanitizePrintfFormat(const string& input)
505 string::size_type i = input.find("%n");
506 if (i != string::npos) {
507 SG_LOG(SG_IO, SG_WARN, "sanitizePrintfFormat: bad format string:" << input);
514 } // end namespace strutils
516 } // end namespace simgear