]> git.mxchange.org Git - simgear.git/blob - simgear/misc/strutils.cxx
Reset: allow re-init of Nasal Ghosts.
[simgear.git] / simgear / misc / strutils.cxx
1 // String utilities.
2 //
3 // Written by Bernie Bright, started 1998
4 //
5 // Copyright (C) 1998  Bernie Bright - bbright@bigpond.net.au
6 //
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.
11 //
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.
16 //
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.
20 //
21 // $Id$
22
23 #include <ctype.h>
24 #include <cstring>
25 #include <sstream>
26
27 #include "strutils.hxx"
28
29 #include <simgear/debug/logstream.hxx>
30
31 using std::string;
32 using std::vector;
33 using std::stringstream;
34
35 namespace simgear {
36     namespace strutils {
37
38         /**
39          * 
40          */
41         static vector<string>
42         split_whitespace( const string& str, int maxsplit )
43         {
44             vector<string> result;
45             string::size_type len = str.length();
46             string::size_type i = 0;
47             string::size_type j;
48             int countsplit = 0;
49
50             while (i < len)
51             {
52                 while (i < len && isspace((unsigned char)str[i]))
53                 {
54                     ++i;
55                 }
56
57                 j = i;
58
59                 while (i < len && !isspace((unsigned char)str[i]))
60                 {
61                     ++i;
62                 }
63
64                 if (j < i)
65                 {
66                     result.push_back( str.substr(j, i-j) );
67                     ++countsplit;
68                     while (i < len && isspace((unsigned char)str[i]))
69                     {
70                         ++i;
71                     }
72
73                     if (maxsplit && (countsplit >= maxsplit) && i < len)
74                     {
75                         result.push_back( str.substr( i, len-i ) );
76                         i = len;
77                     }
78                 }
79             }
80
81             return result;
82         }
83
84         /**
85          * 
86          */
87         vector<string>
88         split( const string& str, const char* sep, int maxsplit )
89         {
90             if (sep == 0)
91                 return split_whitespace( str, maxsplit );
92
93             vector<string> result;
94             int n = std::strlen( sep );
95             if (n == 0)
96             {
97                 // Error: empty separator string
98                 return result;
99             }
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;
104             int splitcount = 0;
105
106             while (i+n <= len)
107             {
108                 if (s[i] == sep[0] && (n == 1 || std::memcmp(s+i, sep, n) == 0))
109                 {
110                     result.push_back( str.substr(j,i-j) );
111                     i = j = i + n;
112                     ++splitcount;
113                     if (maxsplit && (splitcount >= maxsplit))
114                         break;
115                 }
116                 else
117                 {
118                     ++i;
119                 }
120             }
121
122             result.push_back( str.substr(j,len-j) );
123             return result;
124         }
125
126         /**
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.
130          */
131         const int LEFTSTRIP = 0;
132         const int RIGHTSTRIP = 1;
133         const int BOTHSTRIP = 2;
134
135         static string
136         do_strip( const string& s, int striptype )
137         {
138             string::size_type len = s.length();
139             if( len == 0 ) // empty string is trivial
140                 return s;
141             string::size_type i = 0;
142             if (striptype != RIGHTSTRIP)
143             {
144                 while (i < len && isspace(s[i]))
145                 {
146                     ++i;
147                 }
148             }
149
150             string::size_type j = len;
151             if (striptype != LEFTSTRIP)
152             {
153                 do
154                 {
155                     --j;
156                 }
157                 while (j >= 1 && isspace(s[j]));
158                 ++j;
159             }
160
161             if (i == 0 && j == len)
162             {
163                 return s;
164             }
165             else
166             {
167                 return s.substr( i, j - i );
168             }
169         }
170
171         string
172         lstrip( const string& s )
173         {
174             return do_strip( s, LEFTSTRIP );
175         }
176
177         string
178         rstrip( const string& s )
179         {
180             return do_strip( s, RIGHTSTRIP );
181         }
182
183         string
184         strip( const string& s )
185         {
186             return do_strip( s, BOTHSTRIP );
187         }
188
189         string 
190         rpad( const string & s, string::size_type length, char c )
191         {
192             string::size_type l = s.length();
193             if( l >= length ) return s;
194             string reply = s;
195             return reply.append( length-l, c );
196         }
197
198         string 
199         lpad( const string & s, size_t length, char c )
200         {
201             string::size_type l = s.length();
202             if( l >= length ) return s;
203             string reply = s;
204             return reply.insert( 0, length-l, c );
205         }
206
207         bool
208         starts_with( const string & s, const string & substr )
209         {
210           return s.compare(0, substr.length(), substr) == 0;
211         }
212
213         bool
214         ends_with( const string & s, const string & substr )
215         {
216           if( substr.length() > s.length() )
217             return false;
218           return s.compare( s.length() - substr.length(),
219                             substr.length(),
220                             substr ) == 0;
221         }
222
223     string simplify(const string& s)
224     {
225         string result; // reserve size of 's'?
226         string::const_iterator it = s.begin(),
227             end = s.end();
228     
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 */ }
233         
234         bool lastWasSpace = false;
235         for (; it != end; ++it) {
236             char c = *it;
237             if (isspace(c)) {
238                 lastWasSpace = true;
239                 continue;
240             }
241             
242             if (lastWasSpace) {
243                 result.push_back(' ');
244             }
245             
246             lastWasSpace = false;
247             result.push_back(c);
248         }
249         
250         return result;
251     }
252     
253     int to_int(const std::string& s, int base)
254     {
255         stringstream ss(s);
256         switch (base) {
257         case 8:      ss >> std::oct; break;
258         case 16:     ss >> std::hex; break;
259         default: break;
260         }
261         
262         int result;
263         ss >> result;
264         return result;
265     }
266     
267     int compare_versions(const string& v1, const string& v2)
268     {
269         vector<string> v1parts(split(v1, "."));
270         vector<string> v2parts(split(v2, "."));
271
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]);
276
277             if (part1 != part2) {
278                 return part1 - part2;
279             }
280         } // of parts iteration
281
282         // reached end - longer wins
283         return v1parts.size() - v2parts.size();
284     }
285     
286     string join(const string_list& l, const string& joinWith)
287     {
288         string result;
289         unsigned int count = l.size();
290         for (unsigned int i=0; i < count; ++i) {
291             result += l[i];
292             if (i < (count - 1)) {
293                 result += joinWith;
294             }
295         }
296         
297         return result;
298     }
299     
300     string uppercase(const string &s) {
301       string rslt(s);
302       for(string::iterator p = rslt.begin(); p != rslt.end(); p++){
303         *p = toupper(*p);
304       }
305       return rslt;
306     }
307
308     string lowercase(const string &s) {
309       string rslt(s);
310       for(string::iterator p = rslt.begin(); p != rslt.end(); p++){
311         *p = tolower(*p);
312       }
313       return rslt;
314     }
315
316     void lowercase(string &s) {
317       for(string::iterator p = s.begin(); p != s.end(); p++){
318         *p = tolower(*p);
319       }
320     }
321     
322 #if defined(SG_WINDOWS)
323
324 #include <windows.h>
325     
326 static WCharVec convertMultiByteToWString(DWORD encoding, const std::string& a)
327 {
328     WCharVec result;
329     DWORD flags = 0;
330     int requiredWideChars = MultiByteToWideChar(encoding, flags, 
331                         a.c_str(), a.size(),
332                         NULL, 0);
333     result.resize(requiredWideChars);
334     MultiByteToWideChar(encoding, flags, a.c_str(), a.size(),
335                         result.data(), result.size());
336     return result;
337 }
338
339 WCharVec convertUtf8ToWString(const std::string& a)
340 {
341     return convertMultiByteToWString(CP_UTF8, a);
342 }
343
344 #endif
345
346 std::string convertWindowsLocal8BitToUtf8(const std::string& a)
347 {
348 #ifdef SG_WINDOWS
349     DWORD flags = 0;
350     WCharVec wideString = convertMultiByteToWString(CP_ACP, a);
351    
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());
362 #else
363     return a;
364 #endif
365 }
366
367
368
369 static const std::string base64_chars =
370 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
371 "abcdefghijklmnopqrstuvwxyz"
372 "0123456789+/";
373
374 static const unsigned char base64_decode_map[128] =
375 {
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
389 };
390  
391         
392 static inline bool is_base64(unsigned char c) {
393   return (isalnum(c) || (c == '+') || (c == '/'));
394 }
395
396 static bool is_whitespace(unsigned char c) {
397     return ((c == ' ') || (c == '\r') || (c == '\n'));
398 }
399
400 void decodeBase64(const std::string& encoded_string, std::vector<unsigned char>& ret)
401 {
402   int in_len = encoded_string.size();
403   int i = 0;
404   int j = 0;
405   int in_ = 0;
406   unsigned char char_array_4[4], char_array_3[3];
407   
408   while (in_len-- && ( encoded_string[in_] != '=')) {
409     if (is_whitespace( encoded_string[in_])) {
410         in_++; 
411         continue;
412     }
413     
414     if (!is_base64(encoded_string[in_])) {
415         break;
416     }
417     
418     char_array_4[i++] = encoded_string[in_]; in_++;
419     if (i ==4) {
420       for (i = 0; i <4; i++)
421         char_array_4[i] = base64_decode_map[char_array_4[i]];
422       
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];
426       
427       for (i = 0; (i < 3); i++)
428         ret.push_back(char_array_3[i]);
429       i = 0;
430     }
431   }
432   
433   if (i) {
434     for (j = i; j <4; j++)
435       char_array_4[j] = 0;
436     
437     for (j = 0; j <4; j++)
438       char_array_4[j] = base64_decode_map[char_array_4[j]];
439     
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];
443     
444     for (j = 0; (j < i - 1); j++) ret.push_back(char_array_3[j]);
445   }
446 }  
447
448 const char hexChar[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
449
450 std::string encodeHex(const std::string& bytes)
451 {
452   std::string hex;
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]);
458   }
459   
460   return hex;
461 }
462
463 std::string encodeHex(const unsigned char* rawBytes, unsigned int length)
464 {
465   std::string hex;
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]);
470   }
471   
472   return hex;
473 }
474
475 //------------------------------------------------------------------------------
476 std::string unescape(const char* s)
477 {
478   std::string r;
479   while( *s )
480   {
481     if( *s != '\\' )
482     {
483       r += *s++;
484       continue;
485     }
486
487     if( !*++s )
488       break;
489
490     if (*s == '\\') {
491         r += '\\';
492     } else if (*s == 'n') {
493         r += '\n';
494     } else if (*s == 'r') {
495         r += '\r';
496     } else if (*s == 't') {
497         r += '\t';
498     } else if (*s == 'v') {
499         r += '\v';
500     } else if (*s == 'f') {
501         r += '\f';
502     } else if (*s == 'a') {
503         r += '\a';
504     } else if (*s == 'b') {
505         r += '\b';
506     } else if (*s == 'x') {
507         if (!*++s)
508             break;
509         int v = 0;
510         for (int i = 0; i < 2 && isxdigit(*s); i++, s++)
511             v = v * 16 + (isdigit(*s) ? *s - '0' : 10 + tolower(*s) - 'a');
512         r += v;
513         continue;
514
515     } else if (*s >= '0' && *s <= '7') {
516         int v = *s++ - '0';
517         for (int i = 0; i < 3 && *s >= '0' && *s <= '7'; i++, s++)
518             v = v * 8 + *s - '0';
519         r += v;
520         continue;
521
522     } else {
523         r += *s;
524     }
525     s++;
526   }
527   return r;
528 }
529
530 string sanitizePrintfFormat(const string& input)
531 {
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);
535         return string();
536     }
537     
538     return input;
539 }
540
541 } // end namespace strutils
542     
543 } // end namespace simgear