Fix infinite loop detection when placing players randomly on the newer random map...
[0ad.git] / source / ps / CStr.cpp
blob82fafbf13be1c6719bc0b5520463311cab4175d2
1 /* Copyright (C) 2014 Wildfire Games.
2 * This file is part of 0 A.D.
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.
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.
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/>.
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"
26 #ifndef CStr_CPP_FIRST
27 #define CStr_CPP_FIRST
29 #include "lib/fnv_hash.h"
30 #include "lib/utf8.h"
31 #include "lib/byte_order.h"
32 #include "network/Serialization.h"
34 #include <iomanip>
35 #include <sstream>
37 #define UNIDOUBLER_HEADER "CStr.cpp"
38 #include "UniDoubler.h"
41 // Only include these function definitions in the first instance of CStr.cpp:
43 /**
44 * Convert CStr to UTF-8
46 * @return CStr8 converted string
47 **/
48 CStr8 CStrW::ToUTF8() const
50 Status err;
51 return utf8_from_wstring(*this, &err);
54 /**
55 * Convert UTF-8 to CStr
57 * @return CStrW converted string
58 **/
59 CStrW CStr8::FromUTF8() const
61 Status err;
62 return wstring_from_utf8(*this, &err);
65 #else
67 // The following code is compiled twice, as CStrW then as CStr8:
69 #include "CStr.h"
71 #include <sstream>
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
85 CStr CStr::Repeat(const CStr& String, size_t Reps)
87 CStr ret;
88 ret.reserve(String.length() * Reps);
89 while (Reps--) ret += String;
90 return ret;
93 // Construction from numbers:
95 CStr CStr::FromInt(int n)
97 std::tstringstream ss;
98 ss << n;
99 return ss.str();
102 CStr CStr::FromUInt(unsigned int n)
104 std::tstringstream ss;
105 ss << n;
106 return ss.str();
109 CStr CStr::FromInt64(i64 n)
111 std::tstringstream ss;
112 ss << n;
113 return ss.str();
116 CStr CStr::FromDouble(double n)
118 std::tstringstream ss;
119 ss << n;
120 return ss.str();
123 // Conversion to numbers:
125 int CStr::ToInt() const
127 int ret = 0;
128 std::tstringstream str(*this);
129 str >> ret;
130 return ret;
133 unsigned int CStr::ToUInt() const
135 unsigned int ret = 0;
136 std::tstringstream str(*this);
137 str >> ret;
138 return ret;
141 long CStr::ToLong() const
143 long ret = 0;
144 std::tstringstream str(*this);
145 str >> ret;
146 return ret;
149 unsigned long CStr::ToULong() const
151 unsigned long ret = 0;
152 std::tstringstream str(*this);
153 str >> ret;
154 return ret;
157 float CStr::ToFloat() const
159 float ret = 0;
160 std::tstringstream str(*this);
161 str >> ret;
162 return ret;
165 double CStr::ToDouble() const
167 double ret = 0;
168 std::tstringstream str(*this);
169 str >> ret;
170 return ret;
174 // Search the string for another string
175 long CStr::Find(const CStr& Str) const
177 size_t Pos = find(Str, 0);
179 if (Pos != npos)
180 return (long)Pos;
182 return -1;
185 // Search the string for another string
186 long CStr::Find(const tchar chr) const
188 size_t Pos = find(chr, 0);
190 if (Pos != npos)
191 return (long)Pos;
193 return -1;
196 // Search the string for another string
197 long CStr::Find(const int start, const tchar chr) const
199 size_t Pos = find(chr, start);
201 if (Pos != npos)
202 return (long)Pos;
204 return -1;
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()); }
212 long CStr::ReverseFind(const CStr& Str) const
214 size_t Pos = rfind(Str, length() );
216 if (Pos != npos)
217 return (long)Pos;
219 return -1;
223 // Lowercase and uppercase
224 CStr CStr::LowerCase() const
226 std::tstring NewString = *this;
227 for (size_t i = 0; i < length(); i++)
228 NewString[i] = (tchar)_totlower((*this)[i]);
230 return NewString;
233 CStr CStr::UpperCase() const
235 std::tstring NewString = *this;
236 for (size_t i = 0; i < length(); i++)
237 NewString[i] = (tchar)_totupper((*this)[i]);
239 return NewString;
243 // Retrieve the substring of the first n characters
244 CStr CStr::Left(size_t len) const
246 ENSURE(len <= length());
247 return substr(0, len);
250 // Retrieve the substring of the last n characters
251 CStr CStr::Right(size_t len) const
253 ENSURE(len <= length());
254 return substr(length()-len, len);
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
261 size_t pos = rfind(Str, startPos);
262 if (pos == npos)
263 return *this;
264 else
265 return substr(pos + Str.length());
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
272 size_t pos = rfind(Str, startPos);
273 if (pos == npos)
274 return *this;
275 else
276 return substr(0, pos);
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
283 size_t pos = find(Str, startPos);
284 if (pos == npos)
285 return *this;
286 else
287 return substr(pos + Str.length());
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
294 size_t pos = find(Str, startPos);
295 if (pos == npos)
296 return *this;
297 else
298 return substr(0, pos);
301 // Remove all occurrences of some character or substring
302 void CStr::Remove(const CStr& Str)
304 size_t FoundAt = 0;
305 while (FoundAt != npos)
307 FoundAt = find(Str, 0);
309 if (FoundAt != npos)
310 erase(FoundAt, Str.length());
314 // Replace all occurrences of some substring by another
315 void CStr::Replace(const CStr& ToReplace, const CStr& ReplaceWith)
317 size_t Pos = 0;
319 while (Pos != npos)
321 Pos = find(ToReplace, Pos);
322 if (Pos != npos)
324 erase(Pos, ToReplace.length());
325 insert(Pos, ReplaceWith);
326 Pos += ReplaceWith.length();
331 std::string CStr::EscapeToPrintableASCII() const
333 std::string NewString;
334 for (size_t i = 0; i < length(); i++)
336 tchar ch = (*this)[i];
338 if (ch == '"') NewString += "\\\"";
339 else if (ch == '\\') NewString += "\\\\";
340 else if (ch == '\b') NewString += "\\b";
341 else if (ch == '\f') NewString += "\\f";
342 else if (ch == '\n') NewString += "\\n";
343 else if (ch == '\r') NewString += "\\r";
344 else if (ch == '\t') NewString += "\\t";
345 else if (ch >= 32 && ch <= 126)
346 NewString += ch;
347 else
349 std::stringstream ss;
350 ss << "\\u" << std::hex << std::setfill('0') << std::setw(4) << (int)(unsigned char)ch;
351 NewString += ss.str();
354 return NewString;
357 // Returns a trimmed string, removes whitespace from the left/right/both
358 CStr CStr::Trim(PS_TRIM_MODE Mode) const
360 size_t Left = 0, Right = 0;
362 switch (Mode)
364 case PS_TRIM_LEFT:
366 for (Left = 0; Left < length(); Left++)
367 if (_istspace((*this)[Left]) == false)
368 break; // end found, trim 0 to Left-1 inclusive
369 } break;
371 case PS_TRIM_RIGHT:
373 Right = length();
374 while (Right--)
375 if (_istspace((*this)[Right]) == false)
376 break; // end found, trim len-1 to Right+1 inclusive
377 } break;
379 case PS_TRIM_BOTH:
381 for (Left = 0; Left < length(); Left++)
382 if (_istspace((*this)[Left]) == false)
383 break; // end found, trim 0 to Left-1 inclusive
385 Right = length();
386 while (Right--)
387 if (_istspace((*this)[Right]) == false)
388 break; // end found, trim len-1 to Right+1 inclusive
389 } break;
391 default:
392 debug_warn(L"CStr::Trim: invalid Mode");
396 return substr(Left, Right-Left+1);
399 CStr CStr::Pad(PS_TRIM_MODE Mode, size_t Length) const
401 size_t Left = 0, Right = 0;
403 if (Length <= length())
404 return *this;
406 // From here: Length-length() >= 1
408 switch (Mode)
410 case PS_TRIM_LEFT:
411 Left = Length - length();
412 break;
414 case PS_TRIM_RIGHT:
415 Right = Length - length();
416 break;
418 case PS_TRIM_BOTH:
419 Left = (Length - length() + 1)/2;
420 Right = (Length - length() - 1)/2; // cannot be negative
421 break;
423 default:
424 debug_warn(L"CStr::Trim: invalid Mode");
427 return std::tstring(Left, _T(' ')) + *this + std::tstring(Right, _T(' '));
430 size_t CStr::GetHashCode() const
432 return (size_t)fnv_hash(data(), length()*sizeof(value_type));
433 // janwas 2005-03-18: now use 32-bit version; 64 is slower and
434 // the result was truncated down to 32 anyway.
437 #ifdef _UNICODE
439 CStrW is always serialized to/from UTF-16
442 u8* CStrW::Serialize(u8* buffer) const
444 size_t len = length();
445 size_t i = 0;
446 for (i = 0; i < len; i++)
448 const u16 bigEndian = to_be16((*this)[i]);
449 *(u16 *)(buffer + i*2) = bigEndian;
451 *(u16 *)(buffer + i*2) = 0;
452 return buffer + len*2 + 2;
455 const u8* CStrW::Deserialize(const u8* buffer, const u8* bufferend)
457 const u16 *strend = (const u16 *)buffer;
458 while ((const u8 *)strend < bufferend && *strend) strend++;
459 if ((const u8 *)strend >= bufferend) return NULL;
461 resize(strend - (const u16 *)buffer);
462 const u16 *ptr = (const u16 *)buffer;
464 std::wstring::iterator str = begin();
465 while (ptr < strend)
467 const u16 native = to_be16(*(ptr++)); // we want from_be16, but that's the same
468 *(str++) = (tchar)native;
471 return (const u8 *)(strend+1);
474 size_t CStr::GetSerializedLength() const
476 return size_t(length()*2 + 2);
479 #else
481 CStr8 is always serialized to/from ASCII (or whatever 8-bit codepage stored
482 in the CStr)
485 u8* CStr8::Serialize(u8* buffer) const
487 size_t len = length();
488 Serialize_int_4(buffer, (u32)len);
489 size_t i = 0;
490 for (i = 0; i < len; i++)
491 buffer[i] = (*this)[i];
492 return buffer + len;
495 const u8* CStr8::Deserialize(const u8* buffer, const u8* bufferend)
497 u32 len;
498 Deserialize_int_4(buffer, len);
499 if (buffer + len > bufferend)
500 return NULL;
501 *this = std::string(buffer, buffer + len);
502 return buffer + len;
505 size_t CStr::GetSerializedLength() const
507 return length() + 4;
510 #endif // _UNICODE
512 // Clean up, to keep the second pass through unidoubler happy
513 #undef tstringstream
514 #undef _tstod
515 #undef _ttoi
516 #undef _ttol
517 #undef _istspace
518 #undef _totlower
519 #undef _totupper
521 #endif // CStr_CPP_FIRST