2009-04-18 19:00:33 +02:00
|
|
|
/* Copyright (C) 2009 Wildfire Games.
|
|
|
|
* This file is part of 0 A.D.
|
|
|
|
*
|
|
|
|
* 0 A.D. is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* 0 A.D. is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2007-02-01 02:34:17 +01:00
|
|
|
/**
|
|
|
|
* File : CStr.cpp
|
|
|
|
* Project : engine
|
|
|
|
* Description : Controls compilation of CStr class and
|
|
|
|
* : includes some function implementations.
|
|
|
|
**/
|
2004-06-03 20:38:14 +02:00
|
|
|
#include "precompiled.h"
|
|
|
|
|
2004-06-11 04:55:09 +02:00
|
|
|
#ifndef CStr_CPP_FIRST
|
|
|
|
#define CStr_CPP_FIRST
|
|
|
|
|
2007-01-01 22:25:47 +01:00
|
|
|
#include "lib/posix/posix_sock.h" // htons, ntohs
|
2007-05-09 23:01:11 +02:00
|
|
|
#include "lib/fnv_hash.h"
|
2010-03-01 15:55:34 +01:00
|
|
|
#include "lib/utf8.h"
|
2006-08-26 22:25:37 +02:00
|
|
|
#include "network/Serialization.h"
|
2004-06-03 03:43:33 +02:00
|
|
|
#include <cassert>
|
2003-10-03 16:10:38 +02:00
|
|
|
|
2005-06-01 22:12:45 +02:00
|
|
|
#include <sstream>
|
|
|
|
|
2004-06-11 04:55:09 +02:00
|
|
|
#define UNIDOUBLER_HEADER "CStr.cpp"
|
|
|
|
#include "UniDoubler.h"
|
|
|
|
|
2005-06-01 22:12:45 +02:00
|
|
|
|
2004-09-06 13:15:43 +02:00
|
|
|
// Only include these function definitions in the first instance of CStr.cpp:
|
2005-08-16 21:51:18 +02:00
|
|
|
|
2004-10-31 21:29:09 +01:00
|
|
|
CStrW::CStrW(const CStr8 &asciStr) : std::wstring(asciStr.begin(), asciStr.end()) {}
|
2006-07-20 16:37:58 +02:00
|
|
|
CStr8::CStr8(const CStrW& wideStr) : std:: string(wideStr.begin(), wideStr.end()) {}
|
2004-09-06 13:15:43 +02:00
|
|
|
|
2007-02-01 02:34:17 +01:00
|
|
|
/**
|
|
|
|
* Convert CStr to UTF-8
|
|
|
|
*
|
|
|
|
* @return CStr8 converted string
|
|
|
|
**/
|
2005-05-10 20:15:03 +02:00
|
|
|
CStr8 CStrW::ToUTF8() const
|
|
|
|
{
|
2009-11-24 16:36:08 +01:00
|
|
|
LibError err;
|
|
|
|
return utf8_from_wstring(*this, &err);
|
2005-01-12 15:31:47 +01:00
|
|
|
}
|
|
|
|
|
2007-02-01 02:34:17 +01:00
|
|
|
/**
|
|
|
|
* Convert UTF-8 to CStr
|
|
|
|
*
|
|
|
|
* @return CStrW converted string
|
|
|
|
**/
|
2005-05-10 20:15:03 +02:00
|
|
|
CStrW CStr8::FromUTF8() const
|
|
|
|
{
|
2009-11-24 16:36:08 +01:00
|
|
|
LibError err;
|
|
|
|
return wstring_from_utf8(*this, &err);
|
2005-05-10 20:15:03 +02:00
|
|
|
}
|
|
|
|
|
2004-06-11 04:55:09 +02:00
|
|
|
#else
|
|
|
|
|
2005-08-16 21:51:18 +02:00
|
|
|
// The following code is compiled twice, as CStrW then as CStr8:
|
|
|
|
|
2004-06-11 04:55:09 +02:00
|
|
|
#include "CStr.h"
|
|
|
|
|
2004-06-18 15:22:26 +02:00
|
|
|
#include <sstream>
|
|
|
|
|
2005-06-01 22:12:45 +02:00
|
|
|
#ifdef _UNICODE
|
|
|
|
#define tstringstream wstringstream
|
|
|
|
#define _tstod wcstod
|
|
|
|
#define _ttoi(a) wcstol(a, NULL, 0)
|
|
|
|
#define _ttol(a) wcstol(a, NULL, 0)
|
|
|
|
#define _istspace iswspace
|
|
|
|
#define _totlower towlower
|
|
|
|
#define _totupper towupper
|
|
|
|
#else
|
|
|
|
#define tstringstream stringstream
|
|
|
|
#define _tstod strtod
|
|
|
|
#define _ttoi atoi
|
|
|
|
#define _ttol atol
|
|
|
|
#define _istspace isspace
|
|
|
|
#define _totlower tolower
|
|
|
|
#define _totupper toupper
|
|
|
|
#endif
|
|
|
|
|
2006-07-20 16:37:58 +02:00
|
|
|
CStr CStr::Repeat(const CStr& String, size_t Reps)
|
2005-12-17 03:33:57 +01:00
|
|
|
{
|
|
|
|
CStr ret;
|
2007-02-01 15:46:14 +01:00
|
|
|
ret.reserve(String.length() * Reps);
|
2005-12-17 03:33:57 +01:00
|
|
|
while (Reps--) ret += String;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2004-10-31 21:29:09 +01:00
|
|
|
// Construction and assignment from numbers:
|
|
|
|
|
|
|
|
#define NUM_TYPE(T) \
|
|
|
|
CStr::CStr(T Number) \
|
|
|
|
{ \
|
|
|
|
std::tstringstream ss; \
|
|
|
|
ss << Number; \
|
|
|
|
ss >> *this; \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
CStr& CStr::operator=(T Number) \
|
|
|
|
{ \
|
|
|
|
std::tstringstream ss; \
|
|
|
|
ss << Number; \
|
|
|
|
ss >> *this; \
|
|
|
|
return *this; \
|
|
|
|
}
|
2003-10-03 16:10:38 +02:00
|
|
|
|
2004-10-31 21:29:09 +01:00
|
|
|
NUM_TYPE(int)
|
|
|
|
NUM_TYPE(long)
|
|
|
|
NUM_TYPE(unsigned int)
|
|
|
|
NUM_TYPE(unsigned long)
|
|
|
|
NUM_TYPE(float)
|
|
|
|
NUM_TYPE(double)
|
2003-10-03 16:10:38 +02:00
|
|
|
|
2004-10-31 21:29:09 +01:00
|
|
|
#undef NUM_TYPE
|
2003-10-03 16:10:38 +02:00
|
|
|
|
2004-10-31 21:29:09 +01:00
|
|
|
// Conversion to numbers:
|
2003-10-03 16:10:38 +02:00
|
|
|
|
2004-06-01 18:51:37 +02:00
|
|
|
int CStr::ToInt() const
|
2003-10-03 16:10:38 +02:00
|
|
|
{
|
2004-10-31 21:29:09 +01:00
|
|
|
return _ttoi(c_str());
|
2003-10-03 16:10:38 +02:00
|
|
|
}
|
|
|
|
|
2004-06-01 18:51:37 +02:00
|
|
|
unsigned int CStr::ToUInt() const
|
2003-10-03 16:10:38 +02:00
|
|
|
{
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 20:48:32 +02:00
|
|
|
return (unsigned int)_ttoi(c_str());
|
2003-10-03 16:10:38 +02:00
|
|
|
}
|
|
|
|
|
2004-06-01 18:51:37 +02:00
|
|
|
long CStr::ToLong() const
|
2003-10-03 16:10:38 +02:00
|
|
|
{
|
2004-10-31 21:29:09 +01:00
|
|
|
return _ttol(c_str());
|
2003-10-03 16:10:38 +02:00
|
|
|
}
|
|
|
|
|
2004-06-01 18:51:37 +02:00
|
|
|
unsigned long CStr::ToULong() const
|
2003-10-03 16:10:38 +02:00
|
|
|
{
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 20:48:32 +02:00
|
|
|
return (unsigned long)_ttol(c_str());
|
2003-10-03 16:10:38 +02:00
|
|
|
}
|
|
|
|
|
2004-06-01 18:51:37 +02:00
|
|
|
float CStr::ToFloat() const
|
2003-10-03 16:10:38 +02:00
|
|
|
{
|
2004-10-31 21:29:09 +01:00
|
|
|
return (float)_tstod(c_str(), NULL);
|
2003-10-03 16:10:38 +02:00
|
|
|
}
|
|
|
|
|
2004-10-31 21:29:09 +01:00
|
|
|
double CStr::ToDouble() const
|
2003-10-03 16:10:38 +02:00
|
|
|
{
|
2004-10-31 21:29:09 +01:00
|
|
|
return _tstod(c_str(), NULL);
|
2003-10-03 16:10:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-10-31 21:29:09 +01:00
|
|
|
// Search the string for another string
|
2004-06-18 15:22:26 +02:00
|
|
|
long CStr::Find(const CStr& Str) const
|
2003-10-03 16:10:38 +02:00
|
|
|
{
|
2004-10-31 21:29:09 +01:00
|
|
|
size_t Pos = find(Str, 0);
|
2003-10-03 16:10:38 +02:00
|
|
|
|
2004-10-31 21:29:09 +01:00
|
|
|
if (Pos != npos)
|
2004-06-21 18:29:47 +02:00
|
|
|
return (long)Pos;
|
2003-10-03 16:10:38 +02:00
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2004-10-31 21:29:09 +01:00
|
|
|
// Search the string for another string
|
2007-02-01 15:46:14 +01:00
|
|
|
long CStr::Find(const tchar chr) const
|
2004-05-29 05:53:38 +02:00
|
|
|
{
|
2005-06-01 22:12:45 +02:00
|
|
|
size_t Pos = find(chr, 0);
|
2004-05-29 05:53:38 +02:00
|
|
|
|
2004-10-31 21:29:09 +01:00
|
|
|
if (Pos != npos)
|
2004-06-21 18:29:47 +02:00
|
|
|
return (long)Pos;
|
2004-05-29 05:53:38 +02:00
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2004-10-31 21:29:09 +01:00
|
|
|
// Search the string for another string
|
2007-02-01 15:46:14 +01:00
|
|
|
long CStr::Find(const int start, const tchar chr) const
|
2004-05-29 05:53:38 +02:00
|
|
|
{
|
2005-06-01 22:12:45 +02:00
|
|
|
size_t Pos = find(chr, start);
|
2004-05-29 05:53:38 +02:00
|
|
|
|
2004-10-31 21:29:09 +01:00
|
|
|
if (Pos != npos)
|
2004-06-21 18:29:47 +02:00
|
|
|
return (long)Pos;
|
2004-05-29 05:53:38 +02:00
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-02-01 15:46:14 +01:00
|
|
|
long CStr::FindInsensitive(const int start, const tchar chr) const { return LowerCase().Find(start, _totlower(chr)); }
|
|
|
|
long CStr::FindInsensitive(const tchar chr) const { return LowerCase().Find(_totlower(chr)); }
|
|
|
|
long CStr::FindInsensitive(const CStr& Str) const { return LowerCase().Find(Str.LowerCase()); }
|
2004-12-09 17:54:02 +01:00
|
|
|
|
|
|
|
|
2004-06-18 15:22:26 +02:00
|
|
|
long CStr::ReverseFind(const CStr& Str) const
|
2003-10-03 16:10:38 +02:00
|
|
|
{
|
2004-10-31 21:29:09 +01:00
|
|
|
size_t Pos = rfind(Str, length() );
|
2003-10-03 16:10:38 +02:00
|
|
|
|
2004-10-31 21:29:09 +01:00
|
|
|
if (Pos != npos)
|
2004-06-21 18:29:47 +02:00
|
|
|
return (long)Pos;
|
2003-10-03 16:10:38 +02:00
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lowercase and uppercase
|
2004-05-29 05:53:38 +02:00
|
|
|
CStr CStr::LowerCase() const
|
2003-10-03 16:10:38 +02:00
|
|
|
{
|
2006-11-07 22:03:13 +01:00
|
|
|
std::tstring NewString = *this;
|
2004-10-31 21:29:09 +01:00
|
|
|
for (size_t i = 0; i < length(); i++)
|
2005-06-01 22:12:45 +02:00
|
|
|
NewString[i] = (tchar)_totlower((*this)[i]);
|
2003-10-03 16:10:38 +02:00
|
|
|
|
2004-10-31 21:29:09 +01:00
|
|
|
return NewString;
|
2003-10-03 16:10:38 +02:00
|
|
|
}
|
|
|
|
|
2004-05-29 05:53:38 +02:00
|
|
|
CStr CStr::UpperCase() const
|
2003-10-03 16:10:38 +02:00
|
|
|
{
|
2006-11-07 22:03:13 +01:00
|
|
|
std::tstring NewString = *this;
|
2004-10-31 21:29:09 +01:00
|
|
|
for (size_t i = 0; i < length(); i++)
|
2005-06-01 22:12:45 +02:00
|
|
|
NewString[i] = (tchar)_totupper((*this)[i]);
|
2003-10-03 16:10:38 +02:00
|
|
|
|
2004-10-31 21:29:09 +01:00
|
|
|
return NewString;
|
2003-10-03 16:10:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-10-31 21:29:09 +01:00
|
|
|
// Retrieve the substring of the first n characters
|
2005-01-12 15:31:47 +01:00
|
|
|
CStr CStr::Left(size_t len) const
|
2003-10-03 16:10:38 +02:00
|
|
|
{
|
2005-06-28 06:06:25 +02:00
|
|
|
debug_assert(len <= length());
|
2004-10-31 21:29:09 +01:00
|
|
|
return substr(0, len);
|
2003-10-03 16:10:38 +02:00
|
|
|
}
|
|
|
|
|
2004-10-31 21:29:09 +01:00
|
|
|
// Retrieve the substring of the last n characters
|
2005-01-12 15:31:47 +01:00
|
|
|
CStr CStr::Right(size_t len) const
|
2003-10-03 16:10:38 +02:00
|
|
|
{
|
2005-06-28 06:06:25 +02:00
|
|
|
debug_assert(len <= length());
|
2004-10-31 21:29:09 +01:00
|
|
|
return substr(length()-len, len);
|
2003-10-03 16:10:38 +02:00
|
|
|
}
|
|
|
|
|
2005-03-18 23:30:23 +01:00
|
|
|
// Retrieve the substring following the last occurrence of Str
|
|
|
|
// (or the whole string if it doesn't contain Str)
|
2007-02-01 15:46:14 +01:00
|
|
|
CStr CStr::AfterLast(const CStr& Str, size_t startPos) const
|
2005-03-18 23:30:23 +01:00
|
|
|
{
|
2007-02-01 15:46:14 +01:00
|
|
|
size_t pos = rfind(Str, startPos);
|
|
|
|
if (pos == npos)
|
2005-03-18 23:30:23 +01:00
|
|
|
return *this;
|
|
|
|
else
|
|
|
|
return substr(pos + Str.length());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Retrieve the substring preceding the last occurrence of Str
|
|
|
|
// (or the whole string if it doesn't contain Str)
|
2007-02-01 15:46:14 +01:00
|
|
|
CStr CStr::BeforeLast(const CStr& Str, size_t startPos) const
|
2005-03-18 23:30:23 +01:00
|
|
|
{
|
2007-02-01 15:46:14 +01:00
|
|
|
size_t pos = rfind(Str, startPos);
|
|
|
|
if (pos == npos)
|
2005-03-18 23:30:23 +01:00
|
|
|
return *this;
|
|
|
|
else
|
|
|
|
return substr(0, pos);
|
|
|
|
}
|
|
|
|
|
2005-03-30 07:43:22 +02:00
|
|
|
// Retrieve the substring following the first occurrence of Str
|
|
|
|
// (or the whole string if it doesn't contain Str)
|
2007-02-01 15:46:14 +01:00
|
|
|
CStr CStr::AfterFirst(const CStr& Str, size_t startPos) const
|
2005-03-30 07:43:22 +02:00
|
|
|
{
|
2007-02-01 15:46:14 +01:00
|
|
|
size_t pos = find(Str, startPos);
|
|
|
|
if (pos == npos)
|
2005-03-30 07:43:22 +02:00
|
|
|
return *this;
|
|
|
|
else
|
|
|
|
return substr(pos + Str.length());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Retrieve the substring preceding the first occurrence of Str
|
|
|
|
// (or the whole string if it doesn't contain Str)
|
2007-02-01 15:46:14 +01:00
|
|
|
CStr CStr::BeforeFirst(const CStr& Str, size_t startPos) const
|
2005-03-30 07:43:22 +02:00
|
|
|
{
|
2007-02-01 15:46:14 +01:00
|
|
|
size_t pos = find(Str, startPos);
|
|
|
|
if (pos == npos)
|
2005-03-30 07:43:22 +02:00
|
|
|
return *this;
|
|
|
|
else
|
|
|
|
return substr(0, pos);
|
|
|
|
}
|
|
|
|
|
2004-10-31 21:29:09 +01:00
|
|
|
// Remove all occurrences of some character or substring
|
2004-06-18 15:22:26 +02:00
|
|
|
void CStr::Remove(const CStr& Str)
|
2003-10-03 16:10:38 +02:00
|
|
|
{
|
2003-11-30 17:39:22 +01:00
|
|
|
size_t FoundAt = 0;
|
2004-10-31 21:29:09 +01:00
|
|
|
while (FoundAt != npos)
|
2003-10-03 16:10:38 +02:00
|
|
|
{
|
2004-10-31 21:29:09 +01:00
|
|
|
FoundAt = find(Str, 0);
|
2003-10-03 16:10:38 +02:00
|
|
|
|
2004-10-31 21:29:09 +01:00
|
|
|
if (FoundAt != npos)
|
|
|
|
erase(FoundAt, Str.length());
|
2003-10-03 16:10:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-10-31 21:29:09 +01:00
|
|
|
// Replace all occurrences of some substring by another
|
2004-06-18 15:22:26 +02:00
|
|
|
void CStr::Replace(const CStr& ToReplace, const CStr& ReplaceWith)
|
2003-10-03 16:10:38 +02:00
|
|
|
{
|
2003-11-30 17:39:22 +01:00
|
|
|
size_t Pos = 0;
|
2003-10-03 16:10:38 +02:00
|
|
|
|
2004-10-31 21:29:09 +01:00
|
|
|
while (Pos != npos)
|
2003-10-03 16:10:38 +02:00
|
|
|
{
|
2004-10-31 21:29:09 +01:00
|
|
|
Pos = find(ToReplace, Pos);
|
|
|
|
if (Pos != npos)
|
2003-10-03 16:10:38 +02:00
|
|
|
{
|
2004-10-31 21:29:09 +01:00
|
|
|
erase(Pos, ToReplace.length());
|
|
|
|
insert(Pos, ReplaceWith);
|
|
|
|
Pos += ReplaceWith.length();
|
2003-10-03 16:10:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-01 15:46:14 +01:00
|
|
|
CStr CStr::UnescapeBackslashes() const
|
2004-12-28 14:13:27 +01:00
|
|
|
{
|
|
|
|
// Currently only handle \n and \\, because they're the only interesting ones
|
|
|
|
CStr NewString;
|
|
|
|
bool escaping = false;
|
|
|
|
for (size_t i = 0; i < length(); i++)
|
|
|
|
{
|
2005-06-01 22:12:45 +02:00
|
|
|
tchar ch = (*this)[i];
|
2004-12-28 14:13:27 +01:00
|
|
|
if (escaping)
|
|
|
|
{
|
|
|
|
switch (ch)
|
|
|
|
{
|
2005-06-01 22:12:45 +02:00
|
|
|
case 'n': NewString += '\n'; break;
|
2004-12-28 14:13:27 +01:00
|
|
|
default: NewString += ch; break;
|
|
|
|
}
|
|
|
|
escaping = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-06-01 22:12:45 +02:00
|
|
|
if (ch == '\\')
|
2004-12-28 14:13:27 +01:00
|
|
|
escaping = true;
|
|
|
|
else
|
|
|
|
NewString += ch;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NewString;
|
|
|
|
}
|
|
|
|
|
2004-10-31 21:29:09 +01:00
|
|
|
// Returns a trimmed string, removes whitespace from the left/right/both
|
|
|
|
CStr CStr::Trim(PS_TRIM_MODE Mode) const
|
2003-10-03 16:10:38 +02:00
|
|
|
{
|
2004-06-21 18:29:47 +02:00
|
|
|
size_t Left = 0, Right = 0;
|
2003-10-03 16:10:38 +02:00
|
|
|
|
|
|
|
switch (Mode)
|
|
|
|
{
|
|
|
|
case PS_TRIM_LEFT:
|
|
|
|
{
|
2004-10-31 21:29:09 +01:00
|
|
|
for (Left = 0; Left < length(); Left++)
|
|
|
|
if (_istspace((*this)[Left]) == false)
|
2003-10-03 16:10:38 +02:00
|
|
|
break; // end found, trim 0 to Left-1 inclusive
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case PS_TRIM_RIGHT:
|
|
|
|
{
|
2004-10-31 21:29:09 +01:00
|
|
|
Right = length();
|
2003-12-01 13:14:21 +01:00
|
|
|
while (Right--)
|
2004-10-31 21:29:09 +01:00
|
|
|
if (_istspace((*this)[Right]) == false)
|
2003-10-03 16:10:38 +02:00
|
|
|
break; // end found, trim len-1 to Right+1 inclusive
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case PS_TRIM_BOTH:
|
|
|
|
{
|
2004-10-31 21:29:09 +01:00
|
|
|
for (Left = 0; Left < length(); Left++)
|
|
|
|
if (_istspace((*this)[Left]) == false)
|
2003-10-03 16:10:38 +02:00
|
|
|
break; // end found, trim 0 to Left-1 inclusive
|
|
|
|
|
2004-10-31 21:29:09 +01:00
|
|
|
Right = length();
|
2003-12-01 13:14:21 +01:00
|
|
|
while (Right--)
|
2004-10-31 21:29:09 +01:00
|
|
|
if (_istspace((*this)[Right]) == false)
|
2003-10-03 16:10:38 +02:00
|
|
|
break; // end found, trim len-1 to Right+1 inclusive
|
|
|
|
} break;
|
2004-06-21 18:29:47 +02:00
|
|
|
|
|
|
|
default:
|
2009-11-03 22:46:35 +01:00
|
|
|
debug_warn(L"CStr::Trim: invalid Mode");
|
2003-10-03 16:10:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-10-31 21:29:09 +01:00
|
|
|
return substr(Left, Right-Left+1);
|
2003-10-03 16:10:38 +02:00
|
|
|
}
|
|
|
|
|
2005-12-17 03:33:57 +01:00
|
|
|
CStr CStr::Pad(PS_TRIM_MODE Mode, size_t Length) const
|
|
|
|
{
|
|
|
|
size_t Left = 0, Right = 0;
|
|
|
|
|
|
|
|
if (Length <= length())
|
|
|
|
return *this;
|
|
|
|
|
|
|
|
// From here: Length-length() >= 1
|
|
|
|
|
|
|
|
switch (Mode)
|
|
|
|
{
|
|
|
|
case PS_TRIM_LEFT:
|
|
|
|
Left = Length - length();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PS_TRIM_RIGHT:
|
|
|
|
Right = Length - length();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PS_TRIM_BOTH:
|
|
|
|
Left = (Length - length() + 1)/2;
|
|
|
|
Right = (Length - length() - 1)/2; // cannot be negative
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2009-11-03 22:46:35 +01:00
|
|
|
debug_warn(L"CStr::Trim: invalid Mode");
|
2005-12-17 03:33:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return std::tstring(Left, _T(' ')) + *this + std::tstring(Right, _T(' '));
|
|
|
|
}
|
|
|
|
|
2004-10-31 21:29:09 +01:00
|
|
|
// Concatenation:
|
2003-10-03 16:10:38 +02:00
|
|
|
|
2004-06-18 15:22:26 +02:00
|
|
|
CStr CStr::operator+(const CStr& Str)
|
2003-10-03 16:10:38 +02:00
|
|
|
{
|
2008-07-17 19:00:00 +02:00
|
|
|
CStr tmp(*this);
|
|
|
|
tmp += Str;
|
|
|
|
return tmp;
|
2003-10-03 16:10:38 +02:00
|
|
|
}
|
|
|
|
|
2005-06-01 22:12:45 +02:00
|
|
|
CStr CStr::operator+(const tchar* Str)
|
2003-10-03 16:10:38 +02:00
|
|
|
{
|
2008-07-17 19:00:00 +02:00
|
|
|
CStr tmp(*this);
|
|
|
|
tmp += Str;
|
|
|
|
return tmp;
|
2003-10-03 16:10:38 +02:00
|
|
|
}
|
|
|
|
|
2004-10-31 21:29:09 +01:00
|
|
|
// Joining ASCII and Unicode strings:
|
|
|
|
#ifndef _UNICODE
|
|
|
|
CStr8 CStr::operator+(const CStrW& Str)
|
2003-11-24 03:18:41 +01:00
|
|
|
{
|
2004-10-31 21:29:09 +01:00
|
|
|
return std::operator+(*this, CStr8(Str));
|
2003-11-24 03:18:41 +01:00
|
|
|
}
|
2004-10-31 21:29:09 +01:00
|
|
|
#else
|
|
|
|
CStrW CStr::operator+(const CStr8& Str)
|
2003-10-03 16:10:38 +02:00
|
|
|
{
|
2004-10-31 21:29:09 +01:00
|
|
|
return std::operator+(*this, CStrW(Str));
|
2003-10-03 16:10:38 +02:00
|
|
|
}
|
2004-10-31 21:29:09 +01:00
|
|
|
#endif
|
2003-10-03 16:10:38 +02:00
|
|
|
|
|
|
|
|
2005-06-01 22:12:45 +02:00
|
|
|
CStr::operator const tchar*() const
|
2003-10-03 16:10:38 +02:00
|
|
|
{
|
2004-10-31 21:29:09 +01:00
|
|
|
return c_str();
|
2003-10-03 16:10:38 +02:00
|
|
|
}
|
|
|
|
|
2003-11-30 17:39:22 +01:00
|
|
|
|
2004-05-22 01:46:16 +02:00
|
|
|
size_t CStr::GetHashCode() const
|
|
|
|
{
|
2009-11-03 22:46:35 +01:00
|
|
|
return (size_t)fnv_hash(data(), length()*sizeof(value_type));
|
2005-03-18 22:57:07 +01:00
|
|
|
// janwas 2005-03-18: now use 32-bit version; 64 is slower and
|
|
|
|
// the result was truncated down to 32 anyway.
|
2004-05-22 01:46:16 +02:00
|
|
|
}
|
|
|
|
|
2004-08-16 17:19:17 +02:00
|
|
|
#ifdef _UNICODE
|
|
|
|
/*
|
|
|
|
CStrW is always serialized to/from UTF-16
|
|
|
|
*/
|
|
|
|
|
2007-02-01 15:46:14 +01:00
|
|
|
u8* CStrW::Serialize(u8* buffer) const
|
2003-11-30 17:39:22 +01:00
|
|
|
{
|
2004-10-31 21:29:09 +01:00
|
|
|
size_t len = length();
|
|
|
|
size_t i = 0;
|
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
*(u16 *)(buffer + i*2) = htons((*this)[i]); // convert to network order (big-endian)
|
2007-02-01 15:46:14 +01:00
|
|
|
*(u16 *)(buffer + i*2) = 0;
|
|
|
|
return buffer + len*2 + 2;
|
2003-11-30 17:39:22 +01:00
|
|
|
}
|
|
|
|
|
2007-02-01 15:46:14 +01:00
|
|
|
const u8* CStrW::Deserialize(const u8* buffer, const u8* bufferend)
|
2003-11-30 17:39:22 +01:00
|
|
|
{
|
2004-10-31 21:29:09 +01:00
|
|
|
const u16 *strend = (const u16 *)buffer;
|
2004-06-11 04:55:09 +02:00
|
|
|
while ((const u8 *)strend < bufferend && *strend) strend++;
|
|
|
|
if ((const u8 *)strend >= bufferend) return NULL;
|
|
|
|
|
2004-10-31 21:29:09 +01:00
|
|
|
resize(strend - (const u16 *)buffer);
|
|
|
|
const u16 *ptr = (const u16 *)buffer;
|
|
|
|
|
|
|
|
std::wstring::iterator str = begin();
|
|
|
|
while (ptr < strend)
|
2005-06-01 22:12:45 +02:00
|
|
|
*(str++) = (tchar)ntohs(*(ptr++)); // convert from network order (big-endian)
|
2004-06-11 04:55:09 +02:00
|
|
|
|
|
|
|
return (const u8 *)(strend+1);
|
2004-06-02 17:31:55 +02:00
|
|
|
}
|
2005-01-17 05:52:02 +01:00
|
|
|
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 20:48:32 +02:00
|
|
|
size_t CStr::GetSerializedLength() const
|
2005-01-17 05:52:02 +01:00
|
|
|
{
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 20:48:32 +02:00
|
|
|
return size_t(length()*2 + 2);
|
2005-01-17 05:52:02 +01:00
|
|
|
}
|
|
|
|
|
2004-08-16 17:19:17 +02:00
|
|
|
#else
|
|
|
|
/*
|
|
|
|
CStr8 is always serialized to/from ASCII (or whatever 8-bit codepage stored
|
|
|
|
in the CStr)
|
|
|
|
*/
|
|
|
|
|
2007-02-01 15:46:14 +01:00
|
|
|
u8* CStr8::Serialize(u8* buffer) const
|
2004-08-16 17:19:17 +02:00
|
|
|
{
|
2004-10-31 21:29:09 +01:00
|
|
|
size_t len = length();
|
|
|
|
size_t i = 0;
|
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
buffer[i] = (*this)[i];
|
2010-05-22 16:05:56 +02:00
|
|
|
return buffer+len;
|
2004-08-16 17:19:17 +02:00
|
|
|
}
|
|
|
|
|
2007-02-01 15:46:14 +01:00
|
|
|
const u8* CStr8::Deserialize(const u8* buffer, const u8* bufferend)
|
2004-08-16 17:19:17 +02:00
|
|
|
{
|
2010-05-22 16:05:56 +02:00
|
|
|
*this = std::string(buffer, bufferend);
|
|
|
|
return bufferend;
|
2004-08-16 17:19:17 +02:00
|
|
|
}
|
2005-01-17 05:52:02 +01:00
|
|
|
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 20:48:32 +02:00
|
|
|
size_t CStr::GetSerializedLength() const
|
2005-01-17 05:52:02 +01:00
|
|
|
{
|
2010-05-22 16:05:56 +02:00
|
|
|
return length();
|
2005-01-17 05:52:02 +01:00
|
|
|
}
|
|
|
|
|
2004-10-31 21:29:09 +01:00
|
|
|
#endif // _UNICODE
|
2004-06-11 04:55:09 +02:00
|
|
|
|
2005-06-01 22:12:45 +02:00
|
|
|
// Clean up, to keep the second pass through unidoubler happy
|
|
|
|
#undef tstringstream
|
|
|
|
#undef _tstod
|
|
|
|
#undef _ttoi
|
|
|
|
#undef _ttol
|
|
|
|
#undef _istspace
|
|
|
|
#undef _totlower
|
|
|
|
#undef _totupper
|
|
|
|
|
2004-10-31 21:29:09 +01:00
|
|
|
#endif // CStr_CPP_FIRST
|