Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
CStr.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2011 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 /**
19  * File : CStr.cpp
20  * Project : engine
21  * Description : Controls compilation of CStr class and
22  * : includes some function implementations.
23  **/
24 #include "precompiled.h"
25 
26 #ifndef CStr_CPP_FIRST
27 #define CStr_CPP_FIRST
28 
29 #include "lib/fnv_hash.h"
30 #include "lib/utf8.h"
31 #include "lib/byte_order.h"
32 #include "network/Serialization.h"
33 
34 #include <iomanip>
35 #include <sstream>
36 
37 #define UNIDOUBLER_HEADER "CStr.cpp"
38 #include "UniDoubler.h"
39 
40 
41 // Only include these function definitions in the first instance of CStr.cpp:
42 
43 /**
44  * Convert CStr to UTF-8
45  *
46  * @return CStr8 converted string
47  **/
48 CStr8 CStrW::ToUTF8() const
49 {
50  Status err;
51  return utf8_from_wstring(*this, &err);
52 }
53 
54 /**
55  * Convert UTF-8 to CStr
56  *
57  * @return CStrW converted string
58  **/
59 CStrW CStr8::FromUTF8() const
60 {
61  Status err;
62  return wstring_from_utf8(*this, &err);
63 }
64 
65 #else
66 
67 // The following code is compiled twice, as CStrW then as CStr8:
68 
69 #include "CStr.h"
70 
71 #include <sstream>
72 
73 #ifdef _UNICODE
74  #define tstringstream wstringstream
75  #define _istspace iswspace
76  #define _totlower towlower
77  #define _totupper towupper
78 #else
79  #define tstringstream stringstream
80  #define _istspace isspace
81  #define _totlower tolower
82  #define _totupper toupper
83 #endif
84 
85 CStr CStr::Repeat(const CStr& String, size_t Reps)
86 {
87  CStr ret;
88  ret.reserve(String.length() * Reps);
89  while (Reps--) ret += String;
90  return ret;
91 }
92 
93 // Construction from numbers:
94 
95 CStr CStr::FromInt(int n)
96 {
97  std::tstringstream ss;
98  ss << n;
99  return ss.str();
100 }
101 
102 CStr CStr::FromUInt(unsigned int n)
103 {
104  std::tstringstream ss;
105  ss << n;
106  return ss.str();
107 }
108 
109 CStr CStr::FromInt64(i64 n)
110 {
111  std::tstringstream ss;
112  ss << n;
113  return ss.str();
114 }
115 
116 CStr CStr::FromDouble(double n)
117 {
118  std::tstringstream ss;
119  ss << n;
120  return ss.str();
121 }
122 
123 // Conversion to numbers:
124 
125 int CStr::ToInt() const
126 {
127  int ret = 0;
128  std::tstringstream str(*this);
129  str >> ret;
130  return ret;
131 }
132 
133 unsigned int CStr::ToUInt() const
134 {
135  unsigned int ret = 0;
136  std::tstringstream str(*this);
137  str >> ret;
138  return ret;
139 }
140 
141 long CStr::ToLong() const
142 {
143  long ret = 0;
144  std::tstringstream str(*this);
145  str >> ret;
146  return ret;
147 }
148 
149 unsigned long CStr::ToULong() const
150 {
151  unsigned long ret = 0;
152  std::tstringstream str(*this);
153  str >> ret;
154  return ret;
155 }
156 
157 float CStr::ToFloat() const
158 {
159  float ret = 0;
160  std::tstringstream str(*this);
161  str >> ret;
162  return ret;
163 }
164 
165 double CStr::ToDouble() const
166 {
167  double ret = 0;
168  std::tstringstream str(*this);
169  str >> ret;
170  return ret;
171 }
172 
173 
174 // Search the string for another string
175 long CStr::Find(const CStr& Str) const
176 {
177  size_t Pos = find(Str, 0);
178 
179  if (Pos != npos)
180  return (long)Pos;
181 
182  return -1;
183 }
184 
185 // Search the string for another string
186 long CStr::Find(const tchar chr) const
187 {
188  size_t Pos = find(chr, 0);
189 
190  if (Pos != npos)
191  return (long)Pos;
192 
193  return -1;
194 }
195 
196 // Search the string for another string
197 long CStr::Find(const int start, const tchar chr) const
198 {
199  size_t Pos = find(chr, start);
200 
201  if (Pos != npos)
202  return (long)Pos;
203 
204  return -1;
205 }
206 
207 long CStr::FindInsensitive(const int start, const tchar chr) const { return LowerCase().Find(start, _totlower(chr)); }
208 long CStr::FindInsensitive(const tchar chr) const { return LowerCase().Find(_totlower(chr)); }
209 long CStr::FindInsensitive(const CStr& Str) const { return LowerCase().Find(Str.LowerCase()); }
210 
211 
212 long CStr::ReverseFind(const CStr& Str) const
213 {
214  size_t Pos = rfind(Str, length() );
215 
216  if (Pos != npos)
217  return (long)Pos;
218 
219  return -1;
220 
221 }
222 
223 // Lowercase and uppercase
224 CStr CStr::LowerCase() const
225 {
226  std::tstring NewString = *this;
227  for (size_t i = 0; i < length(); i++)
228  NewString[i] = (tchar)_totlower((*this)[i]);
229 
230  return NewString;
231 }
232 
233 CStr CStr::UpperCase() const
234 {
235  std::tstring NewString = *this;
236  for (size_t i = 0; i < length(); i++)
237  NewString[i] = (tchar)_totupper((*this)[i]);
238 
239  return NewString;
240 }
241 
242 
243 // Retrieve the substring of the first n characters
244 CStr CStr::Left(size_t len) const
245 {
246  ENSURE(len <= length());
247  return substr(0, len);
248 }
249 
250 // Retrieve the substring of the last n characters
251 CStr CStr::Right(size_t len) const
252 {
253  ENSURE(len <= length());
254  return substr(length()-len, len);
255 }
256 
257 // Retrieve the substring following the last occurrence of Str
258 // (or the whole string if it doesn't contain Str)
259 CStr CStr::AfterLast(const CStr& Str, size_t startPos) const
260 {
261  size_t pos = rfind(Str, startPos);
262  if (pos == npos)
263  return *this;
264  else
265  return substr(pos + Str.length());
266 }
267 
268 // Retrieve the substring preceding the last occurrence of Str
269 // (or the whole string if it doesn't contain Str)
270 CStr CStr::BeforeLast(const CStr& Str, size_t startPos) const
271 {
272  size_t pos = rfind(Str, startPos);
273  if (pos == npos)
274  return *this;
275  else
276  return substr(0, pos);
277 }
278 
279 // Retrieve the substring following the first occurrence of Str
280 // (or the whole string if it doesn't contain Str)
281 CStr CStr::AfterFirst(const CStr& Str, size_t startPos) const
282 {
283  size_t pos = find(Str, startPos);
284  if (pos == npos)
285  return *this;
286  else
287  return substr(pos + Str.length());
288 }
289 
290 // Retrieve the substring preceding the first occurrence of Str
291 // (or the whole string if it doesn't contain Str)
292 CStr CStr::BeforeFirst(const CStr& Str, size_t startPos) const
293 {
294  size_t pos = find(Str, startPos);
295  if (pos == npos)
296  return *this;
297  else
298  return substr(0, pos);
299 }
300 
301 // Remove all occurrences of some character or substring
302 void CStr::Remove(const CStr& Str)
303 {
304  size_t FoundAt = 0;
305  while (FoundAt != npos)
306  {
307  FoundAt = find(Str, 0);
308 
309  if (FoundAt != npos)
310  erase(FoundAt, Str.length());
311  }
312 }
313 
314 // Replace all occurrences of some substring by another
315 void CStr::Replace(const CStr& ToReplace, const CStr& ReplaceWith)
316 {
317  size_t Pos = 0;
318 
319  while (Pos != npos)
320  {
321  Pos = find(ToReplace, Pos);
322  if (Pos != npos)
323  {
324  erase(Pos, ToReplace.length());
325  insert(Pos, ReplaceWith);
326  Pos += ReplaceWith.length();
327  }
328  }
329 }
330 
331 CStr CStr::UnescapeBackslashes() const
332 {
333  // Currently only handle \n and \\, because they're the only interesting ones
334  CStr NewString;
335  bool escaping = false;
336  for (size_t i = 0; i < length(); i++)
337  {
338  tchar ch = (*this)[i];
339  if (escaping)
340  {
341  switch (ch)
342  {
343  case 'n': NewString += '\n'; break;
344  default: NewString += ch; break;
345  }
346  escaping = false;
347  }
348  else
349  {
350  if (ch == '\\')
351  escaping = true;
352  else
353  NewString += ch;
354  }
355  }
356  return NewString;
357 }
358 
359 std::string CStr::EscapeToPrintableASCII() const
360 {
361  std::string NewString;
362  for (size_t i = 0; i < length(); i++)
363  {
364  tchar ch = (*this)[i];
365 
366  if (ch == '"') NewString += "\\\"";
367  else if (ch == '\\') NewString += "\\\\";
368  else if (ch == '\b') NewString += "\\b";
369  else if (ch == '\f') NewString += "\\f";
370  else if (ch == '\n') NewString += "\\n";
371  else if (ch == '\r') NewString += "\\r";
372  else if (ch == '\t') NewString += "\\t";
373  else if (ch >= 32 && ch <= 126)
374  NewString += ch;
375  else
376  {
377  std::stringstream ss;
378  ss << "\\u" << std::hex << std::setfill('0') << std::setw(4) << (int)(unsigned char)ch;
379  NewString += ss.str();
380  }
381  }
382  return NewString;
383 }
384 
385 // Returns a trimmed string, removes whitespace from the left/right/both
386 CStr CStr::Trim(PS_TRIM_MODE Mode) const
387 {
388  size_t Left = 0, Right = 0;
389 
390  switch (Mode)
391  {
392  case PS_TRIM_LEFT:
393  {
394  for (Left = 0; Left < length(); Left++)
395  if (_istspace((*this)[Left]) == false)
396  break; // end found, trim 0 to Left-1 inclusive
397  } break;
398 
399  case PS_TRIM_RIGHT:
400  {
401  Right = length();
402  while (Right--)
403  if (_istspace((*this)[Right]) == false)
404  break; // end found, trim len-1 to Right+1 inclusive
405  } break;
406 
407  case PS_TRIM_BOTH:
408  {
409  for (Left = 0; Left < length(); Left++)
410  if (_istspace((*this)[Left]) == false)
411  break; // end found, trim 0 to Left-1 inclusive
412 
413  Right = length();
414  while (Right--)
415  if (_istspace((*this)[Right]) == false)
416  break; // end found, trim len-1 to Right+1 inclusive
417  } break;
418 
419  default:
420  debug_warn(L"CStr::Trim: invalid Mode");
421  }
422 
423 
424  return substr(Left, Right-Left+1);
425 }
426 
427 CStr CStr::Pad(PS_TRIM_MODE Mode, size_t Length) const
428 {
429  size_t Left = 0, Right = 0;
430 
431  if (Length <= length())
432  return *this;
433 
434  // From here: Length-length() >= 1
435 
436  switch (Mode)
437  {
438  case PS_TRIM_LEFT:
439  Left = Length - length();
440  break;
441 
442  case PS_TRIM_RIGHT:
443  Right = Length - length();
444  break;
445 
446  case PS_TRIM_BOTH:
447  Left = (Length - length() + 1)/2;
448  Right = (Length - length() - 1)/2; // cannot be negative
449  break;
450 
451  default:
452  debug_warn(L"CStr::Trim: invalid Mode");
453  }
454 
455  return std::tstring(Left, _T(' ')) + *this + std::tstring(Right, _T(' '));
456 }
457 
458 size_t CStr::GetHashCode() const
459 {
460  return (size_t)fnv_hash(data(), length()*sizeof(value_type));
461  // janwas 2005-03-18: now use 32-bit version; 64 is slower and
462  // the result was truncated down to 32 anyway.
463 }
464 
465 #ifdef _UNICODE
466 /*
467  CStrW is always serialized to/from UTF-16
468 */
469 
470 u8* CStrW::Serialize(u8* buffer) const
471 {
472  size_t len = length();
473  size_t i = 0;
474  for (i = 0; i < len; i++)
475  {
476  const u16 bigEndian = to_be16((*this)[i]);
477  *(u16 *)(buffer + i*2) = bigEndian;
478  }
479  *(u16 *)(buffer + i*2) = 0;
480  return buffer + len*2 + 2;
481 }
482 
483 const u8* CStrW::Deserialize(const u8* buffer, const u8* bufferend)
484 {
485  const u16 *strend = (const u16 *)buffer;
486  while ((const u8 *)strend < bufferend && *strend) strend++;
487  if ((const u8 *)strend >= bufferend) return NULL;
488 
489  resize(strend - (const u16 *)buffer);
490  const u16 *ptr = (const u16 *)buffer;
491 
492  std::wstring::iterator str = begin();
493  while (ptr < strend)
494  {
495  const u16 native = to_be16(*(ptr++)); // we want from_be16, but that's the same
496  *(str++) = (tchar)native;
497  }
498 
499  return (const u8 *)(strend+1);
500 }
501 
502 size_t CStr::GetSerializedLength() const
503 {
504  return size_t(length()*2 + 2);
505 }
506 
507 #else
508 /*
509  CStr8 is always serialized to/from ASCII (or whatever 8-bit codepage stored
510  in the CStr)
511 */
512 
513 u8* CStr8::Serialize(u8* buffer) const
514 {
515  size_t len = length();
516  Serialize_int_4(buffer, (u32)len);
517  size_t i = 0;
518  for (i = 0; i < len; i++)
519  buffer[i] = (*this)[i];
520  return buffer + len;
521 }
522 
523 const u8* CStr8::Deserialize(const u8* buffer, const u8* bufferend)
524 {
525  u32 len;
526  Deserialize_int_4(buffer, len);
527  if (buffer + len > bufferend)
528  return NULL;
529  *this = std::string(buffer, buffer + len);
530  return buffer + len;
531 }
532 
533 size_t CStr::GetSerializedLength() const
534 {
535  return length() + 4;
536 }
537 
538 #endif // _UNICODE
539 
540 // Clean up, to keep the second pass through unidoubler happy
541 #undef tstringstream
542 #undef _tstod
543 #undef _ttoi
544 #undef _ttol
545 #undef _istspace
546 #undef _totlower
547 #undef _totupper
548 
549 #endif // CStr_CPP_FIRST
#define u8
Definition: types.h:39
Trim all white space from the beginning of the string.
Definition: CStr.h:34
std::string utf8_from_wstring(const std::wstring &src, Status *err)
opposite of wstring_from_utf8
Definition: utf8.cpp:208
#define Serialize_int_4(_pos, _val)
Definition: Serialization.h:34
Trim all white space from the end of the string.
Definition: CStr.h:35
#define ENSURE(expr)
ensure the expression &lt;expr&gt; evaluates to non-zero.
Definition: debug.h:282
#define tchar
Definition: secure_crt.cpp:69
i64 Status
Error handling system.
Definition: status.h:171
#define to_be16(x)
Definition: byte_order.h:81
std::wstring wstring_from_utf8(const std::string &src, Status *err)
convert UTF-8 to a wide string (UTF-16 or UCS-4, depending on the platform&#39;s wchar_t).
Definition: utf8.cpp:225
u32 fnv_hash(const void *buf, size_t len)
rationale: this algorithm was chosen because it delivers &#39;good&#39; results for string data and is relati...
Definition: fnv_hash.cpp:33
#define Deserialize_int_4(_pos, _val)
Definition: Serialization.h:59
#define u16
Definition: types.h:40
#define i64
Definition: types.h:37
#define u32
Definition: types.h:41
#define debug_warn(expr)
display the error dialog with the given text.
Definition: debug.h:324
static float Length(const SVec3 v)
Definition: mikktspace.cpp:112
PS_TRIM_MODE
File : CStr.h Project : engine Description : Contains CStr class which is a versatile class for makin...
Definition: CStr.h:31