5177 lines
108 KiB
C++
5177 lines
108 KiB
C++
// Copyright (C) 2013 Jérôme Leclercq
|
|
// This file is part of the "Nazara Engine - Core module"
|
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
|
|
|
#include <Nazara/Core/String.hpp>
|
|
#include <Nazara/Core/Config.hpp>
|
|
#include <Nazara/Core/Error.hpp>
|
|
#include <Nazara/Core/HashImpl.hpp>
|
|
#include <Nazara/Core/Unicode.hpp>
|
|
#include <Nazara/Math/Basic.hpp>
|
|
#include <algorithm>
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include <limits>
|
|
#include <sstream>
|
|
#include <Utfcpp/utf8.h>
|
|
#include <Nazara/Core/Debug.hpp>
|
|
|
|
inline unsigned int nzPow2(unsigned int n)
|
|
{
|
|
unsigned int x = 1;
|
|
|
|
// Tant que x est plus petit que n, on décale ses bits vers la gauche, ce qui revient à multiplier par deux
|
|
while(x <= n)
|
|
x <<= 1;
|
|
|
|
return x;
|
|
}
|
|
// Cet algorithme est inspiré de la documentation de Qt
|
|
inline unsigned int nzGetNewSize(unsigned int newSize)
|
|
{
|
|
if (newSize < 20)
|
|
return newSize+4;
|
|
else
|
|
{
|
|
if (newSize < (1 << 12)-12)
|
|
return nzPow2(newSize << 1)-12;
|
|
else
|
|
return newSize + (1 << 11);
|
|
}
|
|
}
|
|
|
|
inline char nzToLower(char character)
|
|
{
|
|
if (character >= 'A' && character <= 'Z')
|
|
return character + ('a' - 'A');
|
|
else
|
|
return character;
|
|
}
|
|
|
|
inline char nzToUpper(char character)
|
|
{
|
|
if (character >= 'a' && character <= 'z')
|
|
return character + ('A' - 'a');
|
|
else
|
|
return character;
|
|
}
|
|
|
|
inline int nzStrcasecmp(const char* s1, const char* s2)
|
|
{
|
|
int ret = 0;
|
|
|
|
while (!(ret = static_cast<unsigned char>(nzToLower(*s1)) - static_cast<unsigned char>(nzToLower(*s2))) && *s2)
|
|
++s1, ++s2;
|
|
|
|
return ret != 0 ? (ret > 0 ? 1 : -1) : 0;
|
|
}
|
|
|
|
inline int nzUnicodecasecmp(const char* s1, const char* s2)
|
|
{
|
|
int ret = 0;
|
|
utf8::unchecked::iterator<const char*> it1(s1);
|
|
utf8::unchecked::iterator<const char*> it2(s2);
|
|
|
|
while (!(ret = NzUnicode::GetLowercase(*it1) - NzUnicode::GetLowercase(*it2)) && *it2)
|
|
++it1, ++it2;
|
|
|
|
return ret != 0 ? (ret > 0 ? 1 : -1) : 0;
|
|
}
|
|
|
|
NzString::NzString() :
|
|
m_sharedString(&emptyString)
|
|
{
|
|
}
|
|
|
|
NzString::NzString(char character)
|
|
{
|
|
if (character == '\0')
|
|
m_sharedString = &emptyString;
|
|
else
|
|
{
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = 1;
|
|
m_sharedString->size = 1;
|
|
m_sharedString->string = new char[2];
|
|
m_sharedString->string[0] = character;
|
|
m_sharedString->string[1] = '\0';
|
|
}
|
|
}
|
|
|
|
NzString::NzString(const char* string)
|
|
{
|
|
if (string)
|
|
{
|
|
unsigned int size = std::strlen(string);
|
|
if (size > 0)
|
|
{
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = size;
|
|
m_sharedString->size = size;
|
|
m_sharedString->string = new char[size+1];
|
|
std::memcpy(m_sharedString->string, string, size+1);
|
|
}
|
|
else
|
|
m_sharedString = &emptyString;
|
|
}
|
|
else
|
|
m_sharedString = &emptyString;
|
|
}
|
|
|
|
NzString::NzString(const std::string& string)
|
|
{
|
|
if (string.size() > 0)
|
|
{
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = string.capacity();
|
|
m_sharedString->size = string.size();
|
|
m_sharedString->string = new char[string.capacity()+1];
|
|
std::memcpy(m_sharedString->string, string.c_str(), string.size()+1);
|
|
}
|
|
else
|
|
m_sharedString = &emptyString;
|
|
}
|
|
|
|
NzString::NzString(const NzString& string) :
|
|
m_sharedString(string.m_sharedString)
|
|
{
|
|
if (m_sharedString != &emptyString)
|
|
{
|
|
NazaraMutexLock(m_sharedString->mutex);
|
|
m_sharedString->refCount++;
|
|
NazaraMutexUnlock(m_sharedString->mutex);
|
|
}
|
|
}
|
|
|
|
NzString::NzString(NzString&& string) noexcept :
|
|
m_sharedString(string.m_sharedString)
|
|
{
|
|
string.m_sharedString = &emptyString;
|
|
}
|
|
|
|
NzString::NzString(SharedString* sharedString) :
|
|
m_sharedString(sharedString)
|
|
{
|
|
}
|
|
|
|
NzString::~NzString()
|
|
{
|
|
ReleaseString();
|
|
}
|
|
|
|
NzString& NzString::Append(char character)
|
|
{
|
|
if (character == '\0')
|
|
return *this;
|
|
|
|
if (m_sharedString->size == 0 && m_sharedString->capacity == 0)
|
|
return operator=(character);
|
|
|
|
if (m_sharedString->capacity > m_sharedString->size)
|
|
{
|
|
EnsureOwnership();
|
|
|
|
m_sharedString->string[m_sharedString->size] = character;
|
|
m_sharedString->string[m_sharedString->size+1] = '\0';
|
|
m_sharedString->size++;
|
|
}
|
|
else
|
|
{
|
|
unsigned int newSize = m_sharedString->size+1;
|
|
unsigned int bufferSize = nzGetNewSize(newSize);
|
|
|
|
char* str = new char[bufferSize+1];
|
|
std::memcpy(str, m_sharedString->string, m_sharedString->size);
|
|
str[m_sharedString->size] = character;
|
|
str[newSize] = '\0';
|
|
|
|
ReleaseString();
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = bufferSize;
|
|
m_sharedString->size = newSize;
|
|
m_sharedString->string = str;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
NzString& NzString::Append(const char* string)
|
|
{
|
|
return Append(string, std::strlen(string));
|
|
}
|
|
|
|
NzString& NzString::Append(const char* string, unsigned int length)
|
|
{
|
|
if (!string || !string[0] || length == 0)
|
|
return *this;
|
|
|
|
if (m_sharedString->capacity >= m_sharedString->size + length)
|
|
{
|
|
EnsureOwnership();
|
|
|
|
std::memcpy(&m_sharedString->string[m_sharedString->size], string, length+1);
|
|
m_sharedString->size += length;
|
|
}
|
|
else
|
|
{
|
|
unsigned int newSize = m_sharedString->size + length;
|
|
unsigned int bufferSize = nzGetNewSize(newSize);
|
|
|
|
char* str = new char[bufferSize+1];
|
|
std::memcpy(str, m_sharedString->string, m_sharedString->size);
|
|
std::memcpy(&str[m_sharedString->size], string, length+1);
|
|
|
|
ReleaseString();
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = bufferSize;
|
|
m_sharedString->size = newSize;
|
|
m_sharedString->string = str;
|
|
}
|
|
|
|
m_sharedString->string[m_sharedString->size] = '\0';
|
|
|
|
return *this;
|
|
}
|
|
|
|
NzString& NzString::Append(const NzString& string)
|
|
{
|
|
if (string.m_sharedString->size == 0)
|
|
return *this;
|
|
|
|
if (m_sharedString->size == 0 && m_sharedString->capacity < string.m_sharedString->size)
|
|
return operator=(string);
|
|
|
|
if (m_sharedString->capacity >= m_sharedString->size + string.m_sharedString->size)
|
|
{
|
|
EnsureOwnership();
|
|
|
|
std::memcpy(&m_sharedString->string[m_sharedString->size], string.m_sharedString->string, string.m_sharedString->size+1);
|
|
m_sharedString->size += string.m_sharedString->size;
|
|
}
|
|
else
|
|
{
|
|
unsigned int newSize = m_sharedString->size + string.m_sharedString->size;
|
|
unsigned int bufferSize = nzGetNewSize(newSize);
|
|
|
|
char* str = new char[bufferSize+1];
|
|
std::memcpy(str, m_sharedString->string, m_sharedString->size);
|
|
std::memcpy(&str[m_sharedString->size], string.m_sharedString->string, string.m_sharedString->size+1);
|
|
|
|
ReleaseString();
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = bufferSize;
|
|
m_sharedString->size = newSize;
|
|
m_sharedString->string = str;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
void NzString::Clear(bool keepBuffer)
|
|
{
|
|
if (keepBuffer)
|
|
{
|
|
EnsureOwnership();
|
|
m_sharedString->size = 0;
|
|
}
|
|
else
|
|
ReleaseString();
|
|
}
|
|
|
|
bool NzString::Contains(char character, int start, nzUInt32 flags) const
|
|
{
|
|
return Find(character, start, flags) != npos;
|
|
}
|
|
|
|
bool NzString::Contains(const char* string, int start, nzUInt32 flags) const
|
|
{
|
|
return Find(string, start, flags) != npos;
|
|
}
|
|
|
|
bool NzString::Contains(const NzString& string, int start, nzUInt32 flags) const
|
|
{
|
|
return Find(string, start, flags) != npos;
|
|
}
|
|
|
|
unsigned int NzString::Count(char character, int start, nzUInt32 flags) const
|
|
{
|
|
if (character == '\0' || m_sharedString->size == 0)
|
|
return 0;
|
|
|
|
if (start < 0)
|
|
start = std::max(static_cast<int>(m_sharedString->size + start), 0);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return 0;
|
|
|
|
char* str = &m_sharedString->string[pos];
|
|
unsigned int count = 0;
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
char character_lower = nzToLower(character);
|
|
char character_upper = nzToUpper(character);
|
|
do
|
|
{
|
|
if (*str == character_lower || *str == character_upper)
|
|
count++;
|
|
}
|
|
while (*++str);
|
|
}
|
|
else
|
|
{
|
|
while ((str = std::strchr(str, character)))
|
|
{
|
|
count++;
|
|
str++;
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
unsigned int NzString::Count(const char* string, int start, nzUInt32 flags) const
|
|
{
|
|
if (!string || !string[0] || m_sharedString->size == 0)
|
|
return 0;
|
|
|
|
if (start < 0)
|
|
start = std::max(static_cast<int>(m_sharedString->size + start), 0);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return 0;
|
|
|
|
char* str = &m_sharedString->string[pos];
|
|
unsigned int count = 0;
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
if (flags & HandleUtf8)
|
|
{
|
|
while (utf8::internal::is_trail(*str))
|
|
str++;
|
|
|
|
utf8::unchecked::iterator<const char*> it(str);
|
|
|
|
const char* t = string;
|
|
char32_t c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
|
|
do
|
|
{
|
|
if (NzUnicode::GetLowercase(*it) == c)
|
|
{
|
|
++it;
|
|
|
|
utf8::unchecked::iterator<const char*> it2(t);
|
|
while (true)
|
|
{
|
|
if (*it2 == '\0')
|
|
{
|
|
count++;
|
|
break;
|
|
}
|
|
|
|
if (*it == '\0')
|
|
return count;
|
|
|
|
if (NzUnicode::GetLowercase(*it) != NzUnicode::GetLowercase(*it2))
|
|
break;
|
|
|
|
++it;
|
|
++it2;
|
|
}
|
|
}
|
|
}
|
|
while (*++it);
|
|
}
|
|
else
|
|
{
|
|
char c = nzToLower(string[0]);
|
|
do
|
|
{
|
|
if (nzToLower(*str) == c)
|
|
{
|
|
str++;
|
|
|
|
const char* ptr = &string[1];
|
|
while (true)
|
|
{
|
|
if (*ptr == '\0')
|
|
{
|
|
count++;
|
|
break;
|
|
}
|
|
|
|
if (*str == '\0')
|
|
return count;
|
|
|
|
if (nzToLower(*str) != nzToLower(*ptr))
|
|
break;
|
|
|
|
ptr++;
|
|
str++;
|
|
}
|
|
}
|
|
}
|
|
while (*++str);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while ((str = std::strstr(str, string)))
|
|
{
|
|
count++;
|
|
str++;
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
unsigned int NzString::Count(const NzString& string, int start, nzUInt32 flags) const
|
|
{
|
|
if (string.m_sharedString->size == 0 || string.m_sharedString->size > m_sharedString->size)
|
|
return 0;
|
|
|
|
if (start < 0)
|
|
start = std::max(static_cast<int>(m_sharedString->size + start), 0);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return 0;
|
|
|
|
char* str = &m_sharedString->string[pos];
|
|
unsigned int count = 0;
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
if (flags & HandleUtf8)
|
|
{
|
|
while (utf8::internal::is_trail(*str))
|
|
str++;
|
|
|
|
utf8::unchecked::iterator<const char*> it(str);
|
|
|
|
const char* t = string.m_sharedString->string;
|
|
char32_t c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
|
|
do
|
|
{
|
|
if (NzUnicode::GetLowercase(*it) == c)
|
|
{
|
|
++it;
|
|
|
|
utf8::unchecked::iterator<const char*> it2(t);
|
|
while (true)
|
|
{
|
|
if (*it2 == '\0')
|
|
{
|
|
count++;
|
|
break;
|
|
}
|
|
|
|
if (*it == '\0')
|
|
return count;
|
|
|
|
if (NzUnicode::GetLowercase(*it) != NzUnicode::GetLowercase(*it2))
|
|
break;
|
|
|
|
++it;
|
|
++it2;
|
|
}
|
|
}
|
|
}
|
|
while (*++it);
|
|
}
|
|
else
|
|
{
|
|
char c = nzToLower(string.m_sharedString->string[0]);
|
|
do
|
|
{
|
|
if (nzToLower(*str) == c)
|
|
{
|
|
str++;
|
|
|
|
const char* ptr = &string.m_sharedString->string[1];
|
|
while (true)
|
|
{
|
|
if (*ptr == '\0')
|
|
{
|
|
count++;
|
|
break;
|
|
}
|
|
|
|
if (*str == '\0')
|
|
return count;
|
|
|
|
if (nzToLower(*str) != nzToLower(*ptr))
|
|
break;
|
|
|
|
ptr++;
|
|
str++;
|
|
}
|
|
}
|
|
}
|
|
while (*++str);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while ((str = std::strstr(str, string.m_sharedString->string)))
|
|
{
|
|
count++;
|
|
str++;
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
unsigned int NzString::CountAny(const char* string, int start, nzUInt32 flags) const
|
|
{
|
|
if (!string || !string[0] || m_sharedString->size == 0)
|
|
return 0;
|
|
|
|
if (start < 0)
|
|
start = std::max(static_cast<int>(m_sharedString->size + start), 0);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return 0;
|
|
|
|
char* str = &m_sharedString->string[pos];
|
|
unsigned int count = 0;
|
|
if (flags & HandleUtf8)
|
|
{
|
|
while (utf8::internal::is_trail(*str))
|
|
str++;
|
|
|
|
utf8::unchecked::iterator<const char*> it(str);
|
|
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
do
|
|
{
|
|
utf8::unchecked::iterator<const char*> it2(string);
|
|
do
|
|
{
|
|
if (NzUnicode::GetLowercase(*it) == NzUnicode::GetLowercase(*it2))
|
|
{
|
|
count++;
|
|
break;
|
|
}
|
|
}
|
|
while (*++it2);
|
|
}
|
|
while (*++str);
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
utf8::unchecked::iterator<const char*> it2(string);
|
|
do
|
|
{
|
|
if (*it == *it2)
|
|
{
|
|
count++;
|
|
break;
|
|
}
|
|
}
|
|
while (*++it2);
|
|
}
|
|
while (*++str);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
do
|
|
{
|
|
const char* c = string;
|
|
do
|
|
{
|
|
if (nzToLower(*str) == nzToLower(*c))
|
|
{
|
|
count++;
|
|
break;
|
|
}
|
|
}
|
|
while (*++c);
|
|
}
|
|
while (*++str);
|
|
}
|
|
else
|
|
{
|
|
while ((str = std::strpbrk(str, string)))
|
|
{
|
|
count++;
|
|
str++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
unsigned int NzString::CountAny(const NzString& string, int start, nzUInt32 flags) const
|
|
{
|
|
if (string.m_sharedString->size == 0 || m_sharedString->size == 0)
|
|
return 0;
|
|
|
|
if (start < 0)
|
|
start = std::max(static_cast<int>(m_sharedString->size + start), 0);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return 0;
|
|
|
|
char* str = &m_sharedString->string[pos];
|
|
unsigned int count = 0;
|
|
if (flags & HandleUtf8)
|
|
{
|
|
while (utf8::internal::is_trail(*str))
|
|
str++;
|
|
|
|
utf8::unchecked::iterator<const char*> it(str);
|
|
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
do
|
|
{
|
|
utf8::unchecked::iterator<const char*> it2(string.m_sharedString->string);
|
|
do
|
|
{
|
|
if (NzUnicode::GetLowercase(*it) == NzUnicode::GetLowercase(*it2))
|
|
{
|
|
count++;
|
|
break;
|
|
}
|
|
}
|
|
while (*++it2);
|
|
}
|
|
while (*++str);
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
utf8::unchecked::iterator<const char*> it2(string.m_sharedString->string);
|
|
do
|
|
{
|
|
if (*it == *it2)
|
|
{
|
|
count++;
|
|
break;
|
|
}
|
|
}
|
|
while (*++it2);
|
|
}
|
|
while (*++str);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
do
|
|
{
|
|
const char* c = string.m_sharedString->string;
|
|
do
|
|
{
|
|
if (nzToLower(*str) == nzToLower(*c))
|
|
{
|
|
count++;
|
|
break;
|
|
}
|
|
}
|
|
while (*++c);
|
|
}
|
|
while (*++str);
|
|
}
|
|
else
|
|
{
|
|
while ((str = std::strpbrk(str, string.m_sharedString->string)))
|
|
{
|
|
count++;
|
|
str++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
bool NzString::EndsWith(char character, nzUInt32 flags) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return 0;
|
|
|
|
if (flags & CaseInsensitive)
|
|
return nzToLower(m_sharedString->string[m_sharedString->size-1]) == nzToLower(character);
|
|
else
|
|
return m_sharedString->string[m_sharedString->size-1] == character; // character == '\0' sera toujours faux
|
|
}
|
|
|
|
bool NzString::EndsWith(const char* string, nzUInt32 flags) const
|
|
{
|
|
if (!string || !string[0] || m_sharedString->size == 0)
|
|
return false;
|
|
|
|
unsigned int len = std::strlen(string);
|
|
if (len > m_sharedString->size)
|
|
return false;
|
|
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
if (flags & HandleUtf8)
|
|
return nzUnicodecasecmp(&m_sharedString->string[m_sharedString->size - len], string) == 0;
|
|
else
|
|
return nzStrcasecmp(&m_sharedString->string[m_sharedString->size - len], string) == 0;
|
|
}
|
|
else
|
|
return std::strcmp(&m_sharedString->string[m_sharedString->size - len], string) == 0;
|
|
}
|
|
|
|
bool NzString::EndsWith(const NzString& string, nzUInt32 flags) const
|
|
{
|
|
if (string.m_sharedString->size == 0 || string.m_sharedString->size > m_sharedString->size)
|
|
return false;
|
|
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
if (flags & HandleUtf8)
|
|
return nzUnicodecasecmp(&m_sharedString->string[m_sharedString->size - string.m_sharedString->size], string.m_sharedString->string) == 0;
|
|
else
|
|
return nzStrcasecmp(&m_sharedString->string[m_sharedString->size - string.m_sharedString->size], string.m_sharedString->string) == 0;
|
|
}
|
|
else
|
|
return std::strcmp(&m_sharedString->string[m_sharedString->size - string.m_sharedString->size], string.m_sharedString->string) == 0;
|
|
}
|
|
|
|
unsigned int NzString::Find(char character, int start, nzUInt32 flags) const
|
|
{
|
|
if (character == '\0' || m_sharedString->size == 0)
|
|
return npos;
|
|
|
|
if (start < 0)
|
|
start = std::max(static_cast<int>(m_sharedString->size + start), 0);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return npos;
|
|
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
char ch = nzToLower(character);
|
|
const char* str = m_sharedString->string;
|
|
do
|
|
{
|
|
if (nzToLower(*str) == ch)
|
|
return static_cast<unsigned int>(str - m_sharedString->string);
|
|
}
|
|
while (*++str);
|
|
|
|
return npos;
|
|
}
|
|
else
|
|
{
|
|
char* ch = std::strchr(&m_sharedString->string[pos], character);
|
|
if (ch)
|
|
return static_cast<unsigned int>(ch - m_sharedString->string);
|
|
else
|
|
return npos;
|
|
}
|
|
}
|
|
|
|
unsigned int NzString::Find(const char* string, int start, nzUInt32 flags) const
|
|
{
|
|
if (!string || !string[0] || m_sharedString->size == 0)
|
|
return npos;
|
|
|
|
if (start < 0)
|
|
start = std::max(static_cast<int>(m_sharedString->size + start), 0);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return npos;
|
|
|
|
char* str = &m_sharedString->string[pos];
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
if (flags & HandleUtf8)
|
|
{
|
|
while (utf8::internal::is_trail(*str))
|
|
str++;
|
|
|
|
utf8::unchecked::iterator<const char*> it(str);
|
|
|
|
const char* t = string;
|
|
char32_t c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
|
|
do
|
|
{
|
|
if (NzUnicode::GetLowercase(*it) == c)
|
|
{
|
|
const char* ptrPos = it.base();
|
|
++it;
|
|
|
|
utf8::unchecked::iterator<const char*> it2(t);
|
|
while (true)
|
|
{
|
|
if (*it2 == '\0')
|
|
return static_cast<unsigned int>(ptrPos - m_sharedString->string);
|
|
|
|
if (*it == '\0')
|
|
return npos;
|
|
|
|
if (NzUnicode::GetLowercase(*it) != NzUnicode::GetLowercase(*it2))
|
|
break;
|
|
|
|
++it;
|
|
++it2;
|
|
}
|
|
}
|
|
}
|
|
while (*++it);
|
|
}
|
|
else
|
|
{
|
|
char c = nzToLower(string[0]);
|
|
do
|
|
{
|
|
if (nzToLower(*str) == c)
|
|
{
|
|
char* ptrPos = str;
|
|
str++;
|
|
|
|
const char* ptr = &string[1];
|
|
while (true)
|
|
{
|
|
if (*ptr == '\0')
|
|
return static_cast<unsigned int>(ptrPos - m_sharedString->string);
|
|
|
|
if (*str == '\0')
|
|
return npos;
|
|
|
|
if (nzToLower(*str) != nzToLower(*ptr))
|
|
break;
|
|
|
|
ptr++;
|
|
str++;
|
|
}
|
|
}
|
|
}
|
|
while (*++str);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
char* ch = std::strstr(&m_sharedString->string[pos], string);
|
|
if (ch)
|
|
return static_cast<unsigned int>(ch - m_sharedString->string);
|
|
}
|
|
|
|
return npos;
|
|
}
|
|
|
|
unsigned int NzString::Find(const NzString& string, int start, nzUInt32 flags) const
|
|
{
|
|
if (string.m_sharedString->size == 0 || string.m_sharedString->size > m_sharedString->size)
|
|
return npos;
|
|
|
|
if (start < 0)
|
|
start = std::max(static_cast<int>(m_sharedString->size + start), 0);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return npos;
|
|
|
|
char* str = &m_sharedString->string[pos];
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
if (flags & HandleUtf8)
|
|
{
|
|
while (utf8::internal::is_trail(*str))
|
|
str++;
|
|
|
|
utf8::unchecked::iterator<const char*> it(str);
|
|
|
|
const char* t = string.m_sharedString->string;
|
|
char32_t c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
|
|
do
|
|
{
|
|
if (NzUnicode::GetLowercase(*it) == c)
|
|
{
|
|
const char* ptrPos = it.base();
|
|
++it;
|
|
|
|
utf8::unchecked::iterator<const char*> it2(t);
|
|
while (true)
|
|
{
|
|
if (*it2 == '\0')
|
|
return static_cast<unsigned int>(ptrPos - m_sharedString->string);
|
|
|
|
if (*it == '\0')
|
|
return npos;
|
|
|
|
if (NzUnicode::GetLowercase(*it) != NzUnicode::GetLowercase(*it2))
|
|
break;
|
|
|
|
++it;
|
|
++it2;
|
|
}
|
|
}
|
|
}
|
|
while (*++it);
|
|
}
|
|
else
|
|
{
|
|
char c = nzToLower(string.m_sharedString->string[0]);
|
|
do
|
|
{
|
|
if (nzToLower(*str) == c)
|
|
{
|
|
char* ptrPos = str;
|
|
str++;
|
|
|
|
const char* ptr = &string.m_sharedString->string[1];
|
|
while (true)
|
|
{
|
|
if (*ptr == '\0')
|
|
return static_cast<unsigned int>(ptrPos - m_sharedString->string);
|
|
|
|
if (*str == '\0')
|
|
return npos;
|
|
|
|
if (nzToLower(*str) != nzToLower(*ptr))
|
|
break;
|
|
|
|
ptr++;
|
|
str++;
|
|
}
|
|
}
|
|
}
|
|
while (*++str);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
char* ch = std::strstr(&m_sharedString->string[pos], string.m_sharedString->string);
|
|
if (ch)
|
|
return static_cast<unsigned int>(ch - m_sharedString->string);
|
|
}
|
|
|
|
return npos;
|
|
}
|
|
|
|
unsigned int NzString::FindAny(const char* string, int start, nzUInt32 flags) const
|
|
{
|
|
if (m_sharedString->size == 0 || !string || !string[0])
|
|
return npos;
|
|
|
|
if (start < 0)
|
|
start = std::max(m_sharedString->size+start, 0U);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return npos;
|
|
|
|
char* str = &m_sharedString->string[pos];
|
|
if (flags & HandleUtf8)
|
|
{
|
|
while (utf8::internal::is_trail(*str))
|
|
str++;
|
|
|
|
utf8::unchecked::iterator<const char*> it(str);
|
|
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
do
|
|
{
|
|
utf8::unchecked::iterator<const char*> it2(string);
|
|
char32_t character = NzUnicode::GetLowercase(*it);
|
|
do
|
|
{
|
|
if (character == NzUnicode::GetLowercase(*it2))
|
|
return it.base() - m_sharedString->string;
|
|
}
|
|
while (*++it2);
|
|
}
|
|
while (*++it);
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
utf8::unchecked::iterator<const char*> it2(string);
|
|
do
|
|
{
|
|
if (*it == *it2)
|
|
return it.base() - m_sharedString->string;
|
|
}
|
|
while (*++it2);
|
|
}
|
|
while (*++it);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
do
|
|
{
|
|
const char* c = string;
|
|
char character = nzToLower(*str);
|
|
do
|
|
{
|
|
if (character == nzToLower(*c))
|
|
return str - m_sharedString->string;
|
|
}
|
|
while (*++c);
|
|
}
|
|
while (*++str);
|
|
}
|
|
else
|
|
{
|
|
str = std::strpbrk(str, string);
|
|
if (str)
|
|
return str - m_sharedString->string;
|
|
}
|
|
}
|
|
|
|
return npos;
|
|
}
|
|
|
|
unsigned int NzString::FindAny(const NzString& string, int start, nzUInt32 flags) const
|
|
{
|
|
if (m_sharedString->size == 0 || string.m_sharedString->size == 0)
|
|
return npos;
|
|
|
|
if (string.m_sharedString->size > m_sharedString->size)
|
|
return npos;
|
|
|
|
if (start < 0)
|
|
start = std::max(m_sharedString->size+start, 0U);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return npos;
|
|
|
|
char* str = &m_sharedString->string[pos];
|
|
if (flags & HandleUtf8)
|
|
{
|
|
while (utf8::internal::is_trail(*str))
|
|
str++;
|
|
|
|
utf8::unchecked::iterator<const char*> it(str);
|
|
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
do
|
|
{
|
|
utf8::unchecked::iterator<const char*> it2(string.m_sharedString->string);
|
|
char32_t character = NzUnicode::GetLowercase(*it);
|
|
do
|
|
{
|
|
if (character == NzUnicode::GetLowercase(*it2))
|
|
return it.base() - m_sharedString->string;
|
|
}
|
|
while (*++it2);
|
|
}
|
|
while (*++it);
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
utf8::unchecked::iterator<const char*> it2(string.m_sharedString->string);
|
|
do
|
|
{
|
|
if (*it == *it2)
|
|
return it.base() - m_sharedString->string;
|
|
}
|
|
while (*++it2);
|
|
}
|
|
while (*++it);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
do
|
|
{
|
|
const char* c = string.m_sharedString->string;
|
|
char character = nzToLower(*str);
|
|
do
|
|
{
|
|
if (character == nzToLower(*c))
|
|
return str - m_sharedString->string;
|
|
}
|
|
while (*++c);
|
|
}
|
|
while (*++str);
|
|
}
|
|
else
|
|
{
|
|
str = std::strpbrk(str, string.m_sharedString->string);
|
|
if (str)
|
|
return str - m_sharedString->string;
|
|
}
|
|
}
|
|
|
|
return npos;
|
|
}
|
|
|
|
unsigned int NzString::FindLast(char character, int start, nzUInt32 flags) const
|
|
{
|
|
if (character == '\0' || m_sharedString->size == 0)
|
|
return npos;
|
|
|
|
if (start < 0)
|
|
start = std::max(static_cast<int>(m_sharedString->size + start), 0);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return npos;
|
|
|
|
char* ptr = &m_sharedString->string[m_sharedString->size-1];
|
|
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
character = nzToLower(character);
|
|
do
|
|
{
|
|
if (nzToLower(*ptr) == character)
|
|
return static_cast<unsigned int>(ptr - m_sharedString->string);
|
|
}
|
|
while (ptr-- != m_sharedString->string);
|
|
}
|
|
else
|
|
{
|
|
// strrchr ?
|
|
do
|
|
{
|
|
if (*ptr == character)
|
|
return static_cast<unsigned int>(ptr - m_sharedString->string);
|
|
}
|
|
while (ptr-- != m_sharedString->string);
|
|
}
|
|
|
|
return npos;
|
|
}
|
|
|
|
unsigned int NzString::FindLast(const char* string, int start, nzUInt32 flags) const
|
|
{
|
|
if (!string || !string[0] ||m_sharedString->size == 0)
|
|
return npos;
|
|
|
|
if (start < 0)
|
|
start = std::max(static_cast<int>(m_sharedString->size + start), 0);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return npos;
|
|
|
|
///Algo 1.FindLast#3 (Taille du pattern inconnue)
|
|
const char* ptr = &m_sharedString->string[pos];
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
if (flags & HandleUtf8)
|
|
{
|
|
if (utf8::internal::is_trail(*ptr))
|
|
utf8::unchecked::prior(ptr); // On s'assure d'avoir un pointeur vers le début d'un caractère
|
|
|
|
utf8::unchecked::iterator<const char*> it(ptr);
|
|
const char* t = string;
|
|
char32_t c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
|
|
do
|
|
{
|
|
if (NzUnicode::GetLowercase(*it) == c)
|
|
{
|
|
utf8::unchecked::iterator<const char*> it2(t);
|
|
utf8::unchecked::iterator<const char*> tIt(it);
|
|
++tIt;
|
|
|
|
while (true)
|
|
{
|
|
if (*it2 == '\0')
|
|
return it.base() - m_sharedString->string;
|
|
|
|
if (tIt.base() > &m_sharedString->string[pos])
|
|
break;
|
|
|
|
if (NzUnicode::GetLowercase(*tIt) != NzUnicode::GetLowercase(*it2))
|
|
break;
|
|
|
|
++it2;
|
|
++tIt;
|
|
}
|
|
}
|
|
}
|
|
while (it--.base() != m_sharedString->string);
|
|
}
|
|
else
|
|
{
|
|
char c = nzToLower(string[0]);
|
|
do
|
|
{
|
|
if (nzToLower(*ptr) == c)
|
|
{
|
|
const char* p = &string[1];
|
|
const char* tPtr = ptr+1;
|
|
while (true)
|
|
{
|
|
if (*p == '\0')
|
|
return ptr - m_sharedString->string;
|
|
|
|
if (tPtr > &m_sharedString->string[pos])
|
|
break;
|
|
|
|
if (nzToLower(*tPtr) != nzToLower(*p))
|
|
break;
|
|
|
|
p++;
|
|
tPtr++;
|
|
}
|
|
}
|
|
}
|
|
while (ptr-- != m_sharedString->string);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
if (*ptr == string[0])
|
|
{
|
|
const char* p = &string[1];
|
|
const char* tPtr = ptr+1;
|
|
while (true)
|
|
{
|
|
if (*p == '\0')
|
|
return ptr - m_sharedString->string;
|
|
|
|
if (tPtr > &m_sharedString->string[pos])
|
|
break;
|
|
|
|
if (*tPtr != *p)
|
|
break;
|
|
|
|
p++;
|
|
tPtr++;
|
|
}
|
|
}
|
|
}
|
|
while (ptr-- != m_sharedString->string);
|
|
}
|
|
|
|
return npos;
|
|
}
|
|
|
|
unsigned int NzString::FindLast(const NzString& string, int start, nzUInt32 flags) const
|
|
{
|
|
if (string.m_sharedString->size == 0 || string.m_sharedString->size > m_sharedString->size)
|
|
return npos;
|
|
|
|
if (start < 0)
|
|
start = std::max(static_cast<int>(m_sharedString->size + start), 0);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size || string.m_sharedString->size > m_sharedString->size)
|
|
return npos;
|
|
|
|
const char* ptr = &m_sharedString->string[pos];
|
|
const char* limit = &m_sharedString->string[string.m_sharedString->size-1];
|
|
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
if (flags & HandleUtf8)
|
|
{
|
|
///Algo 1.FindLast#3 (Itérateur non-adapté)
|
|
if (utf8::internal::is_trail(*ptr))
|
|
utf8::unchecked::prior(ptr); // On s'assure d'avoir un pointeur vers le début d'un caractère
|
|
|
|
utf8::unchecked::iterator<const char*> it(ptr);
|
|
const char* t = string.m_sharedString->string;
|
|
char32_t c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
|
|
do
|
|
{
|
|
if (NzUnicode::GetLowercase(*it) == c)
|
|
{
|
|
utf8::unchecked::iterator<const char*> it2(t);
|
|
utf8::unchecked::iterator<const char*> tIt(it);
|
|
++tIt;
|
|
|
|
while (true)
|
|
{
|
|
if (*it2 == '\0')
|
|
return it.base() - m_sharedString->string;
|
|
|
|
if (tIt.base() > &m_sharedString->string[pos])
|
|
break;
|
|
|
|
if (NzUnicode::GetLowercase(*tIt) != NzUnicode::GetLowercase(*it2))
|
|
break;
|
|
|
|
++it2;
|
|
++tIt;
|
|
}
|
|
}
|
|
}
|
|
while (it--.base() != limit);
|
|
}
|
|
else
|
|
{
|
|
///Algo 1.FindLast#4 (Taille du pattern connue)
|
|
char c = nzToLower(string.m_sharedString->string[string.m_sharedString->size-1]);
|
|
while (true)
|
|
{
|
|
if (nzToLower(*ptr) == c)
|
|
{
|
|
const char* p = &string.m_sharedString->string[string.m_sharedString->size-1];
|
|
for (; p >= &string.m_sharedString->string[0]; --p, --ptr)
|
|
{
|
|
if (nzToLower(*ptr) != nzToLower(*p))
|
|
break;
|
|
|
|
if (p == &string.m_sharedString->string[0])
|
|
return ptr-m_sharedString->string;
|
|
|
|
if (ptr == m_sharedString->string)
|
|
return npos;
|
|
}
|
|
}
|
|
else if (ptr-- <= limit)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
///Algo 1.FindLast#4 (Taille du pattern connue)
|
|
while (true)
|
|
{
|
|
if (*ptr == string.m_sharedString->string[string.m_sharedString->size-1])
|
|
{
|
|
const char* p = &string.m_sharedString->string[string.m_sharedString->size-1];
|
|
for (; p >= &string.m_sharedString->string[0]; --p, --ptr)
|
|
{
|
|
if (*ptr != *p)
|
|
break;
|
|
|
|
if (p == &string.m_sharedString->string[0])
|
|
return ptr-m_sharedString->string;
|
|
|
|
if (ptr == m_sharedString->string)
|
|
return npos;
|
|
}
|
|
}
|
|
else if (ptr-- <= limit)
|
|
break;
|
|
}
|
|
}
|
|
|
|
return npos;
|
|
}
|
|
|
|
unsigned int NzString::FindLastAny(const char* string, int start, nzUInt32 flags) const
|
|
{
|
|
if (m_sharedString->size == 0 || !string || !string[0])
|
|
return npos;
|
|
|
|
if (start < 0)
|
|
start = std::max(m_sharedString->size+start, 0U);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return npos;
|
|
|
|
char* str = &m_sharedString->string[pos];
|
|
if (flags & HandleUtf8)
|
|
{
|
|
while (utf8::internal::is_trail(*str))
|
|
str++;
|
|
|
|
utf8::unchecked::iterator<const char*> it(str);
|
|
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
do
|
|
{
|
|
utf8::unchecked::iterator<const char*> it2(string);
|
|
char32_t character = NzUnicode::GetLowercase(*it);
|
|
do
|
|
{
|
|
if (character == NzUnicode::GetLowercase(*it2))
|
|
return it.base() - m_sharedString->string;
|
|
}
|
|
while (*++it2);
|
|
}
|
|
while (it--.base() != m_sharedString->string);
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
utf8::unchecked::iterator<const char*> it2(string);
|
|
do
|
|
{
|
|
if (*it == *it2)
|
|
return it.base() - m_sharedString->string;
|
|
}
|
|
while (*++it2);
|
|
}
|
|
while (it--.base() != m_sharedString->string);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
do
|
|
{
|
|
const char* c = string;
|
|
char character = nzToLower(*str);
|
|
do
|
|
{
|
|
if (character == nzToLower(*c))
|
|
return str - m_sharedString->string;
|
|
}
|
|
while (*++c);
|
|
}
|
|
while (str-- != m_sharedString->string);
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
const char* c = string;
|
|
do
|
|
{
|
|
if (*str == *c)
|
|
return str - m_sharedString->string;
|
|
}
|
|
while (*++c);
|
|
}
|
|
while (str-- != m_sharedString->string);
|
|
}
|
|
}
|
|
|
|
return npos;
|
|
}
|
|
|
|
unsigned int NzString::FindLastAny(const NzString& string, int start, nzUInt32 flags) const
|
|
{
|
|
if (m_sharedString->size == 0 || string.m_sharedString->size == 0)
|
|
return npos;
|
|
|
|
if (start < 0)
|
|
start = std::max(m_sharedString->size+start, 0U);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return npos;
|
|
|
|
char* str = &m_sharedString->string[pos];
|
|
if (flags & HandleUtf8)
|
|
{
|
|
while (utf8::internal::is_trail(*str))
|
|
str++;
|
|
|
|
utf8::unchecked::iterator<const char*> it(str);
|
|
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
do
|
|
{
|
|
utf8::unchecked::iterator<const char*> it2(string.m_sharedString->string);
|
|
char32_t character = NzUnicode::GetLowercase(*it);
|
|
do
|
|
{
|
|
if (character == NzUnicode::GetLowercase(*it2))
|
|
return it.base() - m_sharedString->string;
|
|
}
|
|
while (*++it2);
|
|
}
|
|
while (it--.base() != m_sharedString->string);
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
utf8::unchecked::iterator<const char*> it2(string.m_sharedString->string);
|
|
do
|
|
{
|
|
if (*it == *it2)
|
|
return it.base() - m_sharedString->string;
|
|
}
|
|
while (*++it2);
|
|
}
|
|
while (it--.base() != m_sharedString->string);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
do
|
|
{
|
|
const char* c = string.m_sharedString->string;
|
|
char character = nzToLower(*str);
|
|
do
|
|
{
|
|
if (character == nzToLower(*c))
|
|
return str - m_sharedString->string;
|
|
}
|
|
while (*++c);
|
|
}
|
|
while (str-- != m_sharedString->string);
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
const char* c = string.m_sharedString->string;
|
|
do
|
|
{
|
|
if (*str == *c)
|
|
return str - m_sharedString->string;
|
|
}
|
|
while (*++c);
|
|
}
|
|
while (str-- != m_sharedString->string);
|
|
}
|
|
}
|
|
|
|
return npos;
|
|
}
|
|
|
|
unsigned int NzString::FindLastWord(const char* string, int start, nzUInt32 flags) const
|
|
{
|
|
if (!string || !string[0] || m_sharedString->size == 0)
|
|
return npos;
|
|
|
|
if (start < 0)
|
|
start = std::max(static_cast<int>(m_sharedString->size + start), 0);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return npos;
|
|
|
|
///Algo 2.FindLastWord#1 (Taille du pattern inconnue)
|
|
const char* ptr = &m_sharedString->string[pos];
|
|
|
|
if (flags & HandleUtf8)
|
|
{
|
|
if (utf8::internal::is_trail(*ptr))
|
|
utf8::unchecked::prior(ptr); // On s'assure d'avoir un pointeur vers le début d'un caractère
|
|
|
|
utf8::unchecked::iterator<const char*> it(ptr);
|
|
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
const char* t = string; // utf8(::unchecked)::next affecte l'itérateur en argument
|
|
nzUInt32 c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
|
|
do
|
|
{
|
|
if (NzUnicode::GetLowercase(*it) == c)
|
|
{
|
|
if (it.base() != m_sharedString->string)
|
|
{
|
|
it--;
|
|
if (!(NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator))
|
|
continue;
|
|
}
|
|
|
|
utf8::unchecked::iterator<const char*> p(t);
|
|
utf8::unchecked::iterator<const char*> tIt = it;
|
|
++tIt;
|
|
|
|
while (true)
|
|
{
|
|
if (*p == '\0')
|
|
{
|
|
if (*tIt == '\0' || NzUnicode::GetCategory(*tIt) & NzUnicode::Category_Separator)
|
|
return it.base() - m_sharedString->string;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (tIt.base() > &m_sharedString->string[pos])
|
|
break;
|
|
|
|
if (NzUnicode::GetLowercase(*tIt) != NzUnicode::GetLowercase(*p))
|
|
break;
|
|
|
|
++p;
|
|
++tIt;
|
|
}
|
|
}
|
|
}
|
|
while (it--.base() != m_sharedString->string);
|
|
}
|
|
else
|
|
{
|
|
const char* t = string; // utf8(::unchecked)::next affecte l'itérateur en argument
|
|
nzUInt32 c = utf8::unchecked::next(t);
|
|
do
|
|
{
|
|
if (*it == c)
|
|
{
|
|
if (it.base() != m_sharedString->string)
|
|
{
|
|
it--;
|
|
if (!(NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator))
|
|
continue;
|
|
}
|
|
|
|
utf8::unchecked::iterator<const char*> p(t);
|
|
utf8::unchecked::iterator<const char*> tIt = it;
|
|
++tIt;
|
|
|
|
while (true)
|
|
{
|
|
if (*p == '\0')
|
|
{
|
|
if (*tIt == '\0' || NzUnicode::GetCategory(*tIt) & NzUnicode::Category_Separator)
|
|
return it.base() - m_sharedString->string;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (tIt.base() > &m_sharedString->string[pos])
|
|
break;
|
|
|
|
if (*tIt != *p)
|
|
break;
|
|
|
|
++p;
|
|
++tIt;
|
|
}
|
|
}
|
|
}
|
|
while (it--.base() != m_sharedString->string);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
char c = nzToLower(string[0]);
|
|
do
|
|
{
|
|
if (nzToLower(*ptr) == c)
|
|
{
|
|
if (ptr != m_sharedString->string && !std::isspace(*(ptr-1)))
|
|
continue;
|
|
|
|
const char* p = &string[1];
|
|
const char* tPtr = ptr+1;
|
|
while (true)
|
|
{
|
|
if (*p == '\0')
|
|
{
|
|
if (*tPtr == '\0' || std::isspace(*tPtr))
|
|
return ptr-m_sharedString->string;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (tPtr > &m_sharedString->string[pos])
|
|
break;
|
|
|
|
if (nzToLower(*tPtr) != nzToLower(*p))
|
|
break;
|
|
|
|
p++;
|
|
tPtr++;
|
|
}
|
|
}
|
|
}
|
|
while (ptr-- != m_sharedString->string);
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
if (*ptr == string[0])
|
|
{
|
|
if (ptr != m_sharedString->string && !std::isspace(*(ptr-1)))
|
|
continue;
|
|
|
|
const char* p = &string[1];
|
|
const char* tPtr = ptr+1;
|
|
while (true)
|
|
{
|
|
if (*p == '\0')
|
|
{
|
|
if (*tPtr == '\0' || std::isspace(*tPtr))
|
|
return ptr-m_sharedString->string;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (tPtr > &m_sharedString->string[pos])
|
|
break;
|
|
|
|
if (*tPtr != *p)
|
|
break;
|
|
|
|
p++;
|
|
tPtr++;
|
|
}
|
|
}
|
|
}
|
|
while (ptr-- != m_sharedString->string);
|
|
}
|
|
}
|
|
|
|
return npos;
|
|
}
|
|
|
|
unsigned int NzString::FindLastWord(const NzString& string, int start, nzUInt32 flags) const
|
|
{
|
|
if (string.m_sharedString->size == 0 || string.m_sharedString->size > m_sharedString->size)
|
|
return npos;
|
|
|
|
if (start < 0)
|
|
start = std::max(static_cast<int>(m_sharedString->size + start), 0);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return npos;
|
|
|
|
const char* ptr = &m_sharedString->string[pos];
|
|
const char* limit = &m_sharedString->string[string.m_sharedString->size-1];
|
|
|
|
if (flags & HandleUtf8)
|
|
{
|
|
if (utf8::internal::is_trail(*ptr))
|
|
utf8::unchecked::prior(ptr); // On s'assure d'avoir un pointeur vers le début d'un caractère
|
|
|
|
utf8::unchecked::iterator<const char*> it(ptr);
|
|
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
const char* t = string.m_sharedString->string; // utf8(::unchecked)::next affecte l'itérateur en argument
|
|
nzUInt32 c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
|
|
do
|
|
{
|
|
if (NzUnicode::GetLowercase(*it) == c)
|
|
{
|
|
if (it.base() != m_sharedString->string)
|
|
{
|
|
it--;
|
|
if (!(NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator))
|
|
continue;
|
|
}
|
|
|
|
utf8::unchecked::iterator<const char*> p(t);
|
|
utf8::unchecked::iterator<const char*> tIt = it;
|
|
++tIt;
|
|
|
|
while (true)
|
|
{
|
|
if (*p == '\0')
|
|
{
|
|
if (*tIt == '\0' || NzUnicode::GetCategory(*tIt) & NzUnicode::Category_Separator)
|
|
return it.base() - m_sharedString->string;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (tIt.base() > &m_sharedString->string[pos])
|
|
break;
|
|
|
|
if (NzUnicode::GetLowercase(*tIt) != NzUnicode::GetLowercase(*p))
|
|
break;
|
|
|
|
++p;
|
|
++tIt;
|
|
}
|
|
}
|
|
}
|
|
while (it--.base() != m_sharedString->string);
|
|
}
|
|
else
|
|
{
|
|
const char* t = string.m_sharedString->string; // utf8(::unchecked)::next affecte l'itérateur en argument
|
|
nzUInt32 c = utf8::unchecked::next(t);
|
|
do
|
|
{
|
|
if (*it == c)
|
|
{
|
|
if (it.base() != m_sharedString->string)
|
|
{
|
|
it--;
|
|
if (!(NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator))
|
|
continue;
|
|
}
|
|
|
|
utf8::unchecked::iterator<const char*> p(t);
|
|
utf8::unchecked::iterator<const char*> tIt = it;
|
|
++tIt;
|
|
|
|
while (true)
|
|
{
|
|
if (*p == '\0')
|
|
{
|
|
if (*tIt == '\0' || NzUnicode::GetCategory(*tIt) & NzUnicode::Category_Separator)
|
|
return it.base() - m_sharedString->string;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (tIt.base() > &m_sharedString->string[pos])
|
|
break;
|
|
|
|
if (*tIt != *p)
|
|
break;
|
|
|
|
++p;
|
|
++tIt;
|
|
}
|
|
}
|
|
}
|
|
while (it--.base() != m_sharedString->string);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
///Algo 2.FindLastWord#2 (Taille du pattern connue)
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
char c = nzToLower(string.m_sharedString->string[string.m_sharedString->size-1]);
|
|
do
|
|
{
|
|
if (nzToLower(*ptr) == c)
|
|
{
|
|
if (*(ptr+1) != '\0' && !std::isspace(*(ptr+1)))
|
|
continue;
|
|
|
|
const char* p = &string.m_sharedString->string[string.m_sharedString->size-1];
|
|
for (; p >= &string.m_sharedString->string[0]; --p, --ptr)
|
|
{
|
|
if (nzToLower(*ptr) != nzToLower(*p))
|
|
break;
|
|
|
|
if (p == &string.m_sharedString->string[0])
|
|
{
|
|
if (ptr == m_sharedString->string || std::isspace(*(ptr-1)))
|
|
return ptr-m_sharedString->string;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (ptr == m_sharedString->string)
|
|
return npos;
|
|
}
|
|
}
|
|
}
|
|
while (ptr-- > limit);
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
if (*ptr == string.m_sharedString->string[string.m_sharedString->size-1])
|
|
{
|
|
if (*(ptr+1) != '\0' && !std::isspace(*(ptr+1)))
|
|
continue;
|
|
|
|
const char* p = &string.m_sharedString->string[string.m_sharedString->size-1];
|
|
for (; p >= &string.m_sharedString->string[0]; --p, --ptr)
|
|
{
|
|
if (*ptr != *p)
|
|
break;
|
|
|
|
if (p == &string.m_sharedString->string[0])
|
|
{
|
|
if (ptr == m_sharedString->string || std::isspace(*(ptr-1)))
|
|
return ptr-m_sharedString->string;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (ptr == m_sharedString->string)
|
|
return npos;
|
|
}
|
|
}
|
|
}
|
|
while (ptr-- > limit);
|
|
}
|
|
}
|
|
|
|
return npos;
|
|
}
|
|
|
|
unsigned int NzString::FindWord(const char* string, int start, nzUInt32 flags) const
|
|
{
|
|
if (!string || !string[0] || m_sharedString->size == 0)
|
|
return npos;
|
|
|
|
if (start < 0)
|
|
start = std::max(static_cast<int>(m_sharedString->size + start), 0);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return npos;
|
|
|
|
///Algo 3.FindWord#3 (Taille du pattern inconnue)
|
|
const char* ptr = m_sharedString->string;
|
|
if (flags & HandleUtf8)
|
|
{
|
|
if (utf8::internal::is_trail(*ptr))
|
|
utf8::unchecked::prior(ptr); // On s'assure d'avoir un pointeur vers le début d'un caractère
|
|
|
|
utf8::unchecked::iterator<const char*> it(ptr);
|
|
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
const char* t = string; // utf8(::unchecked)::next affecte l'itérateur en argument
|
|
nzUInt32 c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
|
|
|
|
do
|
|
{
|
|
if (*it == c)
|
|
{
|
|
if (it.base() != m_sharedString->string)
|
|
{
|
|
it--;
|
|
if (!(NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator))
|
|
continue;
|
|
}
|
|
|
|
utf8::unchecked::iterator<const char*> p(t);
|
|
utf8::unchecked::iterator<const char*> tIt = it;
|
|
++tIt;
|
|
|
|
while (true)
|
|
{
|
|
if (*p == '\0')
|
|
{
|
|
if (*tIt == '\0' || NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator)
|
|
return it.base() - m_sharedString->string;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (NzUnicode::GetLowercase(*tIt) != NzUnicode::GetLowercase(*p))
|
|
break;
|
|
|
|
p++;
|
|
tIt++;
|
|
}
|
|
}
|
|
}
|
|
while (*++ptr);
|
|
}
|
|
else
|
|
{
|
|
const char* t = string; // utf8(::unchecked)::next affecte l'itérateur en argument
|
|
nzUInt32 c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
|
|
|
|
do
|
|
{
|
|
if (*it == c)
|
|
{
|
|
if (it.base() != m_sharedString->string)
|
|
{
|
|
it--;
|
|
if (!(NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator))
|
|
continue;
|
|
}
|
|
|
|
utf8::unchecked::iterator<const char*> p(t);
|
|
utf8::unchecked::iterator<const char*> tIt = it;
|
|
++tIt;
|
|
|
|
while (true)
|
|
{
|
|
if (*p == '\0')
|
|
{
|
|
if (*tIt == '\0' || NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator)
|
|
return it.base() - m_sharedString->string;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (*tIt != *p)
|
|
break;
|
|
|
|
p++;
|
|
tIt++;
|
|
}
|
|
}
|
|
}
|
|
while (*++ptr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
char c = nzToLower(string[0]);
|
|
do
|
|
{
|
|
if (nzToLower(*ptr) == c)
|
|
{
|
|
if (ptr != m_sharedString->string && !std::isspace(*(ptr-1)))
|
|
continue;
|
|
|
|
const char* p = &string[1];
|
|
const char* tPtr = ptr+1;
|
|
while (true)
|
|
{
|
|
if (*p == '\0')
|
|
{
|
|
if (*tPtr == '\0' || std::isspace(*tPtr))
|
|
return ptr - m_sharedString->string;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (nzToLower(*tPtr) != nzToLower(*p))
|
|
break;
|
|
|
|
p++;
|
|
tPtr++;
|
|
}
|
|
}
|
|
}
|
|
while (*++ptr);
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
if (*ptr == string[0])
|
|
{
|
|
if (ptr != m_sharedString->string && !std::isspace(*(ptr-1)))
|
|
continue;
|
|
|
|
const char* p = &string[1];
|
|
const char* tPtr = ptr+1;
|
|
while (true)
|
|
{
|
|
if (*p == '\0')
|
|
{
|
|
if (*tPtr == '\0' || std::isspace(*tPtr))
|
|
return ptr - m_sharedString->string;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (*tPtr != *p)
|
|
break;
|
|
|
|
p++;
|
|
tPtr++;
|
|
}
|
|
}
|
|
}
|
|
while (*++ptr);
|
|
}
|
|
}
|
|
|
|
return npos;
|
|
}
|
|
|
|
unsigned int NzString::FindWord(const NzString& string, int start, nzUInt32 flags) const
|
|
{
|
|
if (string.m_sharedString->size == 0 || string.m_sharedString->size > m_sharedString->size)
|
|
return npos;
|
|
|
|
if (start < 0)
|
|
start = std::max(static_cast<int>(m_sharedString->size + start), 0);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return npos;
|
|
|
|
char* ptr = m_sharedString->string;
|
|
if (flags & HandleUtf8)
|
|
{
|
|
///Algo 3.FindWord#3 (Itérateur trop lent pour #2)
|
|
if (utf8::internal::is_trail(*ptr))
|
|
utf8::unchecked::prior(ptr); // On s'assure d'avoir un pointeur vers le début d'un caractère
|
|
|
|
utf8::unchecked::iterator<const char*> it(ptr);
|
|
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
const char* t = string.m_sharedString->string; // utf8(::unchecked)::next affecte l'itérateur en argument
|
|
nzUInt32 c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
|
|
|
|
do
|
|
{
|
|
if (*it == c)
|
|
{
|
|
if (it.base() != m_sharedString->string)
|
|
{
|
|
it--;
|
|
if (!(NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator))
|
|
continue;
|
|
}
|
|
|
|
utf8::unchecked::iterator<const char*> p(t);
|
|
utf8::unchecked::iterator<const char*> tIt = it;
|
|
++tIt;
|
|
|
|
while (true)
|
|
{
|
|
if (*p == '\0')
|
|
{
|
|
if (*tIt == '\0' || NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator)
|
|
return it.base() - m_sharedString->string;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (NzUnicode::GetLowercase(*tIt) != NzUnicode::GetLowercase(*p))
|
|
break;
|
|
|
|
p++;
|
|
tIt++;
|
|
}
|
|
}
|
|
}
|
|
while (*++ptr);
|
|
}
|
|
else
|
|
{
|
|
const char* t = string.m_sharedString->string; // utf8(::unchecked)::next affecte l'itérateur en argument
|
|
nzUInt32 c = NzUnicode::GetLowercase(utf8::unchecked::next(t));
|
|
|
|
do
|
|
{
|
|
if (*it == c)
|
|
{
|
|
if (it.base() != m_sharedString->string)
|
|
{
|
|
it--;
|
|
if (!(NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator))
|
|
continue;
|
|
}
|
|
|
|
utf8::unchecked::iterator<const char*> p(t);
|
|
utf8::unchecked::iterator<const char*> tIt = it;
|
|
++tIt;
|
|
|
|
while (true)
|
|
{
|
|
if (*p == '\0')
|
|
{
|
|
if (*tIt == '\0' || NzUnicode::GetCategory(*it++) & NzUnicode::Category_Separator)
|
|
return it.base() - m_sharedString->string;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (*tIt != *p)
|
|
break;
|
|
|
|
p++;
|
|
tIt++;
|
|
}
|
|
}
|
|
}
|
|
while (*++ptr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
///Algo 3.FindWord#2 (Taille du pattern connue)
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
char c = nzToLower(string.m_sharedString->string[0]);
|
|
do
|
|
{
|
|
if (nzToLower(*ptr) == c)
|
|
{
|
|
if (ptr != m_sharedString->string && !std::isspace(*(ptr-1)))
|
|
continue;
|
|
|
|
const char* p = &string.m_sharedString->string[1];
|
|
const char* tPtr = ptr+1;
|
|
while (true)
|
|
{
|
|
if (*p == '\0')
|
|
{
|
|
if (*tPtr == '\0' || std::isspace(*tPtr))
|
|
return ptr - m_sharedString->string;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (nzToLower(*tPtr) != nzToLower(*p))
|
|
break;
|
|
|
|
p++;
|
|
tPtr++;
|
|
}
|
|
}
|
|
}
|
|
while (*++ptr);
|
|
}
|
|
else
|
|
{
|
|
while ((ptr = std::strstr(ptr, string.m_sharedString->string)))
|
|
{
|
|
// Si le mot est bien isolé
|
|
if ((ptr == m_sharedString->string || std::isspace(*(ptr-1))) && (*(ptr+m_sharedString->size) == '\0' || std::isspace(*(ptr+m_sharedString->size))))
|
|
return ptr - m_sharedString->string;
|
|
|
|
ptr++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return npos;
|
|
}
|
|
|
|
char* NzString::GetBuffer()
|
|
{
|
|
EnsureOwnership();
|
|
|
|
return m_sharedString->string;
|
|
}
|
|
|
|
unsigned int NzString::GetCapacity() const
|
|
{
|
|
return m_sharedString->capacity;
|
|
}
|
|
|
|
const char* NzString::GetConstBuffer() const
|
|
{
|
|
return m_sharedString->string;
|
|
}
|
|
|
|
unsigned int NzString::GetLength() const
|
|
{
|
|
#if NAZARA_CORE_SAFE
|
|
try
|
|
{
|
|
#endif
|
|
return utf8::distance(m_sharedString->string, &m_sharedString->string[m_sharedString->size]);
|
|
#if NAZARA_CORE_SAFE
|
|
}
|
|
catch (const utf8::exception& exception)
|
|
{
|
|
NazaraError("UTF-8 error : " + NzString(exception.what()));
|
|
return 0;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
unsigned int NzString::GetSize() const
|
|
{
|
|
return m_sharedString->size;
|
|
}
|
|
|
|
char* NzString::GetUtf8Buffer(unsigned int* size) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return nullptr;
|
|
|
|
char* buffer = new char[m_sharedString->size+1];
|
|
std::memcpy(buffer, m_sharedString->string, m_sharedString->size+1);
|
|
|
|
if (size)
|
|
*size = m_sharedString->size;
|
|
|
|
return buffer;
|
|
}
|
|
|
|
char16_t* NzString::GetUtf16Buffer(unsigned int* size) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return nullptr;
|
|
|
|
std::vector<char16_t> utf16;
|
|
utf16.reserve(m_sharedString->size);
|
|
#if NAZARA_CORE_SAFE
|
|
try
|
|
{
|
|
#endif
|
|
utf8::utf8to16(m_sharedString->string, &m_sharedString->string[m_sharedString->size], std::back_inserter(utf16));
|
|
#if NAZARA_CORE_SAFE
|
|
}
|
|
catch (const utf8::exception& exception)
|
|
{
|
|
NazaraError("UTF-8 error : " + NzString(exception.what()));
|
|
return nullptr;
|
|
}
|
|
#endif
|
|
|
|
unsigned int bufferSize = utf16.size();
|
|
if (bufferSize == 0)
|
|
return nullptr;
|
|
|
|
char16_t* buffer = new char16_t[bufferSize+1];
|
|
std::memcpy(buffer, &utf16[0], bufferSize*sizeof(char16_t));
|
|
buffer[bufferSize] ='\0';
|
|
|
|
if (size)
|
|
*size = bufferSize;
|
|
|
|
return buffer;
|
|
}
|
|
|
|
char32_t* NzString::GetUtf32Buffer(unsigned int* size) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return nullptr;
|
|
|
|
#if NAZARA_CORE_SAFE
|
|
try
|
|
{
|
|
#endif
|
|
unsigned int bufferSize = utf8::distance(m_sharedString->string, &m_sharedString->string[m_sharedString->size]);
|
|
if (bufferSize == 0)
|
|
return nullptr;
|
|
|
|
char32_t* buffer = new char32_t[bufferSize+1];
|
|
utf8::utf8to32(m_sharedString->string, &m_sharedString->string[m_sharedString->size], buffer);
|
|
buffer[bufferSize] ='\0';
|
|
|
|
if (size)
|
|
*size = bufferSize;
|
|
|
|
return buffer;
|
|
#if NAZARA_CORE_SAFE
|
|
}
|
|
catch (const utf8::exception& exception)
|
|
{
|
|
NazaraError("UTF-8 error : " + NzString(exception.what()));
|
|
return nullptr;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
wchar_t* NzString::GetWideBuffer(unsigned int* size) const
|
|
{
|
|
static_assert(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4, "wchar_t size is not supported");
|
|
if (m_sharedString->size == 0)
|
|
return nullptr;
|
|
|
|
#if NAZARA_CORE_SAFE
|
|
try
|
|
{
|
|
#endif
|
|
unsigned int bufferSize = utf8::distance(m_sharedString->string, &m_sharedString->string[m_sharedString->size]);
|
|
if (bufferSize == 0)
|
|
return nullptr;
|
|
|
|
wchar_t* buffer = new wchar_t[bufferSize+1];
|
|
if (sizeof(wchar_t) == 4)
|
|
utf8::utf8to32(m_sharedString->string, &m_sharedString->string[m_sharedString->size], buffer);
|
|
else
|
|
{
|
|
wchar_t* ptr = buffer;
|
|
|
|
utf8::unchecked::iterator<const char*> it(m_sharedString->string);
|
|
do
|
|
{
|
|
char32_t cp = *it;
|
|
if (cp <= 0xFFFF && (cp < 0xD800 || cp > 0xDFFF)) // @Laurent Gomila
|
|
*ptr++ = static_cast<wchar_t>(cp);
|
|
else
|
|
*ptr++ = L'?';
|
|
}
|
|
while (*it++);
|
|
}
|
|
|
|
if (size)
|
|
*size = bufferSize;
|
|
|
|
return buffer;
|
|
#if NAZARA_CORE_SAFE
|
|
}
|
|
catch (const utf8::exception& exception)
|
|
{
|
|
NazaraError("UTF-8 error : " + NzString(exception.what()));
|
|
return nullptr;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
NzString NzString::GetWord(unsigned int index, nzUInt32 flags) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return NzString();
|
|
|
|
NzString temp = Simplified(flags); // Évitons les mauvaises surprises
|
|
if (temp.IsEmpty())
|
|
return NzString();
|
|
|
|
unsigned int foundPos = temp.Find(' '); // Simplified nous assure que nous n'avons plus que des espaces comme séparation
|
|
unsigned int lastPos = 0;
|
|
for (; index > 0; --index)
|
|
{
|
|
if (foundPos == npos)
|
|
return NzString();
|
|
|
|
lastPos = foundPos;
|
|
foundPos = temp.Find(' ', foundPos+1);
|
|
}
|
|
return temp.Substr((lastPos == 0) ? 0 : lastPos+1, (foundPos == npos) ? -1 : static_cast<int>(foundPos-1));
|
|
}
|
|
|
|
unsigned int NzString::GetWordPosition(unsigned int index, nzUInt32 flags) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return npos;
|
|
|
|
unsigned int currentWord = 0;
|
|
bool inWord = false;
|
|
|
|
const char* ptr = m_sharedString->string;
|
|
if (flags & HandleUtf8)
|
|
{
|
|
utf8::unchecked::iterator<const char*> it(ptr);
|
|
do
|
|
{
|
|
if (NzUnicode::GetCategory(*it) & NzUnicode::Category_Separator)
|
|
inWord = false;
|
|
else
|
|
{
|
|
if (!inWord)
|
|
{
|
|
inWord = true;
|
|
if (++currentWord > index)
|
|
return static_cast<unsigned int>(it.base() - m_sharedString->string);
|
|
}
|
|
}
|
|
}
|
|
while (*++it);
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
if (std::isspace(*ptr))
|
|
inWord = false;
|
|
else
|
|
{
|
|
if (!inWord)
|
|
{
|
|
inWord = true;
|
|
if (++currentWord > index)
|
|
return ptr - m_sharedString->string;
|
|
}
|
|
}
|
|
}
|
|
while (*++ptr);
|
|
}
|
|
|
|
return npos;
|
|
}
|
|
|
|
NzString& NzString::Insert(int pos, char character)
|
|
{
|
|
if (character == '\0')
|
|
return *this;
|
|
|
|
if (m_sharedString->size == 0 && m_sharedString->capacity == 0)
|
|
return operator=(character);
|
|
|
|
if (pos < 0)
|
|
pos = std::max(static_cast<int>(m_sharedString->size + pos), 0);
|
|
|
|
unsigned int start = std::min(static_cast<unsigned int>(pos), m_sharedString->size);
|
|
|
|
// Si le buffer est déjà suffisamment grand
|
|
if (m_sharedString->capacity >= m_sharedString->size+1)
|
|
{
|
|
EnsureOwnership();
|
|
|
|
std::memmove(&m_sharedString->string[start+1], &m_sharedString->string[start], m_sharedString->size);
|
|
m_sharedString->string[start] = character;
|
|
|
|
m_sharedString->size += 1;
|
|
}
|
|
else
|
|
{
|
|
unsigned int newSize = m_sharedString->size+1;
|
|
char* newString = new char[newSize+1];
|
|
|
|
char* ptr = newString;
|
|
const char* s = m_sharedString->string;
|
|
while (ptr != &newString[start])
|
|
*ptr++ = *s++;
|
|
|
|
*ptr++ = character;
|
|
|
|
std::strcpy(ptr, s);
|
|
|
|
ReleaseString();
|
|
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = newSize;
|
|
m_sharedString->size = newSize;
|
|
m_sharedString->string = newString;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
NzString& NzString::Insert(int pos, const char* string)
|
|
{
|
|
if (!string || !string[0])
|
|
return *this;
|
|
|
|
if (pos < 0)
|
|
pos = std::max(static_cast<int>(m_sharedString->size + pos), 0);
|
|
|
|
unsigned int start = std::min(static_cast<unsigned int>(pos), m_sharedString->size);
|
|
|
|
// Si le buffer est déjà suffisamment grand
|
|
unsigned int len = std::strlen(string);
|
|
if (m_sharedString->capacity >= m_sharedString->size+len)
|
|
{
|
|
EnsureOwnership();
|
|
|
|
std::memmove(&m_sharedString->string[start+len], &m_sharedString->string[start], m_sharedString->size);
|
|
std::memcpy(&m_sharedString->string[start], string, len+1);
|
|
|
|
m_sharedString->size += len;
|
|
}
|
|
else
|
|
{
|
|
unsigned int newSize = m_sharedString->size+len;
|
|
char* newString = new char[newSize+1];
|
|
|
|
char* ptr = newString;
|
|
const char* s = m_sharedString->string;
|
|
|
|
while (ptr != &newString[start])
|
|
*ptr++ = *s++;
|
|
|
|
const char* p = string;
|
|
while (ptr != &newString[start+len])
|
|
*ptr++ = *p++;
|
|
|
|
std::strcpy(ptr, s);
|
|
|
|
ReleaseString();
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = newSize;
|
|
m_sharedString->size = newSize;
|
|
m_sharedString->string = newString;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
NzString& NzString::Insert(int pos, const NzString& string)
|
|
{
|
|
if (string.m_sharedString->size == 0)
|
|
return *this;
|
|
|
|
if (m_sharedString->size == 0 && m_sharedString->capacity < string.m_sharedString->size)
|
|
return operator=(string);
|
|
|
|
if (pos < 0)
|
|
pos = std::max(static_cast<int>(m_sharedString->size + pos), 0);
|
|
|
|
unsigned int start = std::min(static_cast<unsigned int>(pos), m_sharedString->size);
|
|
|
|
// Si le buffer est déjà suffisamment grand
|
|
if (m_sharedString->capacity >= m_sharedString->size + string.m_sharedString->size)
|
|
{
|
|
EnsureOwnership();
|
|
|
|
std::memmove(&m_sharedString->string[start+string.m_sharedString->size], &m_sharedString->string[start], m_sharedString->size);
|
|
std::memcpy(&m_sharedString->string[start], string.m_sharedString->string, string.m_sharedString->size+1);
|
|
|
|
m_sharedString->size += string.m_sharedString->size;
|
|
}
|
|
else
|
|
{
|
|
unsigned int newSize = m_sharedString->size+string.m_sharedString->size;
|
|
char* newString = new char[newSize+1];
|
|
|
|
char* ptr = newString;
|
|
const char* s = m_sharedString->string;
|
|
|
|
while (ptr != &newString[start])
|
|
*ptr++ = *s++;
|
|
|
|
const char* p = string.m_sharedString->string;
|
|
while (ptr != &newString[start+string.m_sharedString->size])
|
|
*ptr++ = *p++;
|
|
|
|
std::strcpy(ptr, s);
|
|
|
|
ReleaseString();
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = newSize;
|
|
m_sharedString->size = newSize;
|
|
m_sharedString->string = newString;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
bool NzString::IsEmpty() const
|
|
{
|
|
return m_sharedString->size == 0;
|
|
}
|
|
|
|
bool NzString::IsNull() const
|
|
{
|
|
return m_sharedString == &emptyString;
|
|
}
|
|
|
|
bool NzString::IsNumber(nzUInt8 base, nzUInt32 flags) const
|
|
{
|
|
#if NAZARA_CORE_SAFE
|
|
if (base < 2 || base > 36)
|
|
{
|
|
NazaraError("Base must be between 2 and 36");
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
if (m_sharedString->size == 0)
|
|
return false;
|
|
|
|
NzString check = Simplified();
|
|
if (check.m_sharedString->size == 0)
|
|
return false;
|
|
|
|
char* ptr = (check.m_sharedString->string[0] == '-') ? &check.m_sharedString->string[1] : check.m_sharedString->string;
|
|
|
|
if (base > 10)
|
|
{
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
char limitLower = 'a'+base-1;
|
|
char limitUpper = 'A'+base-1;
|
|
|
|
do
|
|
{
|
|
char c = *ptr;
|
|
if (c != ' ' && (c < '0' || (c > '9' && c < 'A') || (c > limitUpper && c < 'a') || c > limitLower))
|
|
return false;
|
|
}
|
|
while (*++ptr);
|
|
}
|
|
else
|
|
{
|
|
char limit = 'a'+base-1;
|
|
do
|
|
{
|
|
char c = *ptr;
|
|
if (c != ' ' && (c < '0' || (c > '9' && c < 'a') || c > limit))
|
|
return false;
|
|
}
|
|
while (*++ptr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
char limit = '0'+base-1;
|
|
|
|
do
|
|
{
|
|
char c = *ptr;
|
|
if (c != ' ' && (c < '0' || c > limit))
|
|
return false;
|
|
}
|
|
while (*++ptr);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool NzString::Match(const char* pattern) const
|
|
{
|
|
if (m_sharedString->size == 0 || !pattern)
|
|
return false;
|
|
|
|
// Par Jack Handy - akkhandy@hotmail.com
|
|
// From : http://www.codeproject.com/Articles/1088/Wildcard-string-compare-globbing
|
|
const char* str = m_sharedString->string;
|
|
while (*str && *pattern != '*')
|
|
{
|
|
if (*pattern != *str && *pattern != '?')
|
|
return false;
|
|
|
|
pattern++;
|
|
str++;
|
|
}
|
|
|
|
const char* cp = nullptr;
|
|
const char* mp = nullptr;
|
|
while (*str)
|
|
{
|
|
if (*pattern == '*')
|
|
{
|
|
if (!*++pattern)
|
|
return true;
|
|
|
|
mp = pattern;
|
|
cp = str+1;
|
|
}
|
|
else if (*pattern == *str || *pattern == '?')
|
|
{
|
|
pattern++;
|
|
str++;
|
|
}
|
|
else
|
|
{
|
|
pattern = mp;
|
|
str = cp++;
|
|
}
|
|
}
|
|
|
|
while (*pattern == '*')
|
|
pattern++;
|
|
|
|
return !*pattern;
|
|
}
|
|
|
|
bool NzString::Match(const NzString& pattern) const
|
|
{
|
|
return Match(pattern.m_sharedString->string);
|
|
}
|
|
|
|
NzString& NzString::Prepend(char character)
|
|
{
|
|
return Insert(0, character);
|
|
}
|
|
|
|
NzString& NzString::Prepend(const char* string)
|
|
{
|
|
return Insert(0, string);
|
|
}
|
|
|
|
NzString& NzString::Prepend(const NzString& string)
|
|
{
|
|
return Insert(0, string);
|
|
}
|
|
|
|
unsigned int NzString::Replace(char oldCharacter, char newCharacter, int start, nzUInt32 flags)
|
|
{
|
|
if (oldCharacter == '\0' || oldCharacter == newCharacter)
|
|
return 0;
|
|
|
|
if (newCharacter == '\0') // Dans ce cas, il faut passer par un algorithme plus complexe
|
|
return Replace(NzString(oldCharacter), NzString(), start);
|
|
|
|
if (start < 0)
|
|
start = std::max(m_sharedString->size + start, 0U);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return npos;
|
|
|
|
unsigned int count = 0;
|
|
char* ptr = &m_sharedString->string[pos];
|
|
bool found = false;
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
char character_lower = nzToLower(oldCharacter);
|
|
char character_upper = nzToUpper(oldCharacter);
|
|
do
|
|
{
|
|
if (*ptr == character_lower || *ptr == character_upper)
|
|
{
|
|
if (!found)
|
|
{
|
|
unsigned int offset = ptr-m_sharedString->string;
|
|
|
|
EnsureOwnership();
|
|
|
|
ptr = &m_sharedString->string[offset];
|
|
found = true;
|
|
}
|
|
|
|
*ptr = newCharacter;
|
|
++count;
|
|
}
|
|
}
|
|
while (*++ptr);
|
|
}
|
|
else
|
|
{
|
|
while ((ptr = std::strchr(ptr, oldCharacter)))
|
|
{
|
|
if (!found)
|
|
{
|
|
unsigned int offset = ptr-m_sharedString->string;
|
|
|
|
EnsureOwnership();
|
|
|
|
ptr = &m_sharedString->string[offset];
|
|
found = true;
|
|
}
|
|
|
|
*ptr = newCharacter;
|
|
++count;
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
unsigned int NzString::Replace(const char* oldString, const char* replaceString, int start, nzUInt32 flags)
|
|
{
|
|
if (!oldString || !oldString[0])
|
|
return 0;
|
|
|
|
if (start < 0)
|
|
start = std::max(m_sharedString->size + start, 0U);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return 0;
|
|
|
|
unsigned int oSize = std::strlen(oldString);
|
|
if (oSize == 0)
|
|
return 0;
|
|
|
|
unsigned int rSize = (replaceString) ? std::strlen(replaceString) : 0;
|
|
|
|
unsigned int count = 0;
|
|
if (oSize == rSize)
|
|
{
|
|
bool found = false;
|
|
|
|
// Si aucun changement de taille n'est nécessaire, nous pouvons alors utiliser un algorithme bien plus rapide
|
|
while ((pos = Find(oldString, pos, flags)) != npos)
|
|
{
|
|
if (!found)
|
|
{
|
|
EnsureOwnership();
|
|
found = true;
|
|
}
|
|
|
|
std::memcpy(&m_sharedString->string[pos], replaceString, oSize);
|
|
pos += oSize;
|
|
|
|
++count;
|
|
}
|
|
}
|
|
else ///TODO: Algorithme de remplacement sans changement de buffer (si rSize < oSize)
|
|
{
|
|
unsigned int newSize = m_sharedString->size + Count(oldString)*(rSize - oSize);
|
|
if (newSize == m_sharedString->size) // Alors c'est que Count(oldString) == 0
|
|
return 0;
|
|
|
|
char* newString = new char[newSize+1];
|
|
|
|
///Algo 4.Replace#2
|
|
char* ptr = newString;
|
|
const char* p = m_sharedString->string;
|
|
|
|
while ((pos = Find(oldString, pos, flags)) != npos)
|
|
{
|
|
const char* r = &m_sharedString->string[pos];
|
|
|
|
std::memcpy(ptr, p, r-p);
|
|
ptr += r-p;
|
|
std::memcpy(ptr, replaceString, rSize);
|
|
ptr += rSize;
|
|
p = r+oSize;
|
|
pos += oSize;
|
|
|
|
count++;
|
|
}
|
|
|
|
std::strcpy(ptr, p); // Ajoute le caractère de fin par la même occasion
|
|
|
|
ReleaseString();
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = newSize;
|
|
m_sharedString->size = newSize;
|
|
m_sharedString->string = newString;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
unsigned int NzString::Replace(const NzString& oldString, const NzString& replaceString, int start, nzUInt32 flags)
|
|
{
|
|
if (oldString.m_sharedString->size == 0)
|
|
return 0;
|
|
|
|
if (start < 0)
|
|
start = std::max(m_sharedString->size + start, 0U);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size || oldString.m_sharedString->size == 0)
|
|
return 0;
|
|
|
|
unsigned int count = 0;
|
|
if (oldString.m_sharedString->size == replaceString.m_sharedString->size)
|
|
{
|
|
bool found = false;
|
|
|
|
// Si aucun changement de taille n'est nécessaire, nous pouvons alors utiliser un algorithme bien plus rapide
|
|
while ((pos = Find(oldString, pos, flags)) != npos)
|
|
{
|
|
if (!found)
|
|
{
|
|
EnsureOwnership();
|
|
found = true;
|
|
}
|
|
|
|
std::memcpy(&m_sharedString->string[pos], replaceString.m_sharedString->string, oldString.m_sharedString->size);
|
|
pos += oldString.m_sharedString->size;
|
|
|
|
++count;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
unsigned int newSize = m_sharedString->size + Count(oldString)*(replaceString.m_sharedString->size - oldString.m_sharedString->size);
|
|
if (newSize == m_sharedString->size) // Alors c'est que Count(oldString) == 0
|
|
return 0;
|
|
|
|
char* newString = new char[newSize+1];
|
|
|
|
///Algo 4.Replace#2
|
|
char* ptr = newString;
|
|
const char* p = m_sharedString->string;
|
|
|
|
while ((pos = Find(oldString, pos, flags)) != npos)
|
|
{
|
|
const char* r = &m_sharedString->string[pos];
|
|
|
|
std::memcpy(ptr, p, r-p);
|
|
ptr += r-p;
|
|
std::memcpy(ptr, replaceString.m_sharedString->string, replaceString.m_sharedString->size);
|
|
ptr += replaceString.m_sharedString->size;
|
|
p = r+oldString.m_sharedString->size;
|
|
pos += oldString.m_sharedString->size;
|
|
|
|
count++;
|
|
}
|
|
|
|
std::strcpy(ptr, p); // Ajoute le caractère de fin par la même occasion
|
|
|
|
ReleaseString();
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = newSize;
|
|
m_sharedString->size = newSize;
|
|
m_sharedString->string = newString;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
unsigned int NzString::ReplaceAny(const char* oldCharacters, char replaceCharacter, int start, nzUInt32 flags)
|
|
{
|
|
///FIXME: Ne gère pas l'UTF-8
|
|
if (!oldCharacters || !oldCharacters[0])
|
|
return 0;
|
|
|
|
/*if (replaceCharacter == '\0') // Dans ce cas, il faut passer par un algorithme plus complexe
|
|
return ReplaceAny(NzString(oldCharacters), NzString(), start);*/
|
|
|
|
if (start < 0)
|
|
start = std::max(m_sharedString->size + start, 0U);
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
if (pos >= m_sharedString->size)
|
|
return npos;
|
|
|
|
unsigned int count = 0;
|
|
char* ptr = &m_sharedString->string[pos];
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
do
|
|
{
|
|
const char* c = oldCharacters;
|
|
char character = nzToLower(*ptr);
|
|
bool found = false;
|
|
do
|
|
{
|
|
if (character == nzToLower(*c))
|
|
{
|
|
if (!found)
|
|
{
|
|
unsigned int offset = ptr-m_sharedString->string;
|
|
|
|
EnsureOwnership();
|
|
|
|
ptr = &m_sharedString->string[offset];
|
|
found = true;
|
|
}
|
|
|
|
*ptr = replaceCharacter;
|
|
++count;
|
|
break;
|
|
}
|
|
}
|
|
while (*++c);
|
|
}
|
|
while (*++ptr);
|
|
}
|
|
else
|
|
{
|
|
bool found = false;
|
|
while ((ptr = std::strpbrk(ptr, oldCharacters)))
|
|
{
|
|
if (!found)
|
|
{
|
|
unsigned int offset = ptr-m_sharedString->string;
|
|
|
|
EnsureOwnership();
|
|
|
|
ptr = &m_sharedString->string[offset];
|
|
found = true;
|
|
}
|
|
|
|
*ptr++ = replaceCharacter;
|
|
++count;
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
/*
|
|
unsigned int NzString::ReplaceAny(const char* oldCharacters, const char* replaceString, int start, nzUInt32 flags)
|
|
{
|
|
if (start < 0)
|
|
{
|
|
start = m_sharedString->size+start;
|
|
if (start < 0)
|
|
start = 0;
|
|
}
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
unsigned int oSize = (oldCharacters) ? std::strlen(oldCharacters) : 0;
|
|
unsigned int rSize = (replaceString) ? std::strlen(replaceString) : 0;
|
|
|
|
if (pos >= m_sharedString->size || m_sharedString->size == 0 || oSize == 0)
|
|
return 0;
|
|
|
|
unsigned int count = 0;
|
|
|
|
if (rSize == 1) // On utilise un algorithme optimisé
|
|
{
|
|
EnsureOwnership();
|
|
|
|
f or (; pos < m_sharedString->size; ++pos)
|
|
{
|
|
for (unsigned int i = 0; i < oSize; ++i)
|
|
{
|
|
if (m_sharedString->string[pos] == oldCharacters[i])
|
|
{
|
|
m_sharedString->string[pos] = replaceString[0];
|
|
++count;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
unsigned int newSize;
|
|
{
|
|
unsigned int count = CountAny(oldCharacters);
|
|
newSize = m_sharedString->size - count + count*rSize;
|
|
}
|
|
char* newString = new char[newSize+1];
|
|
|
|
unsigned int j = 0;
|
|
for (unsigned int i = 0; i < m_sharedString->size; ++i)
|
|
{
|
|
if (i < pos) // Avant la position où on est censé commencer à remplacer, on ne fait que recopier
|
|
newString[j++] = m_sharedString->string[i];
|
|
else
|
|
{
|
|
bool found = false;
|
|
for (unsigned int l = 0; l < oSize; ++l)
|
|
{
|
|
if (m_sharedString->string[i] == oldCharacters[l])
|
|
{
|
|
for (unsigned int k = 0; k < rSize; ++k)
|
|
newString[j++] = replaceString[k];
|
|
|
|
++count;
|
|
found = true;
|
|
break; // Simple façon d'éviter la ligne après la boucle
|
|
}
|
|
}
|
|
|
|
if (!found)
|
|
newString[j++] = m_sharedString->string[i];
|
|
}
|
|
}
|
|
newString[newSize] = '\0';
|
|
|
|
ReleaseString();
|
|
|
|
m_sharedString->size = newSize;
|
|
m_sharedString->string = newString;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
unsigned int NzString::ReplaceAny(const NzString& oldCharacters, const NzString& replaceString, int start, nzUInt32 flags)
|
|
{
|
|
if (start < 0)
|
|
{
|
|
start = m_sharedString->size+start;
|
|
if (start < 0)
|
|
start = 0;
|
|
}
|
|
|
|
unsigned int pos = static_cast<unsigned int>(start);
|
|
|
|
if (pos >= m_sharedString->size || m_sharedString->size == 0 || oldCharacters.m_sharedString->size == 0)
|
|
return 0;
|
|
|
|
unsigned int count = 0;
|
|
|
|
if (replaceString.m_sharedString->size == 1) // On utilise un algorithme optimisé
|
|
{
|
|
EnsureOwnership();
|
|
|
|
char character = replaceString[0];
|
|
for (; pos < m_sharedString->size; ++pos)
|
|
{
|
|
for (unsigned int i = 0; i < oldCharacters.m_sharedString->size; ++i)
|
|
{
|
|
if (m_sharedString->string[pos] == oldCharacters[i])
|
|
{
|
|
m_sharedString->string[pos] = character;
|
|
++count;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
unsigned int newSize;
|
|
{
|
|
unsigned int count = CountAny(oldCharacters);
|
|
newSize = m_sharedString->size - count + count*replaceString.m_sharedString->size;
|
|
}
|
|
char* newString = new char[newSize+1];
|
|
|
|
unsigned int j = 0;
|
|
for (unsigned int i = 0; i < m_sharedString->size; ++i)
|
|
{
|
|
if (i < pos) // Avant la position où on est censé commencer à remplacer, on ne fait que recopier
|
|
newString[j++] = m_sharedString->string[i];
|
|
else
|
|
{
|
|
bool found = false;
|
|
for (unsigned int l = 0; l < oldCharacters.m_sharedString->size; ++l)
|
|
{
|
|
if (m_sharedString->string[i] == oldCharacters[l])
|
|
{
|
|
for (unsigned int k = 0; k < replaceString.m_sharedString->size; ++k)
|
|
newString[j++] = replaceString[k];
|
|
|
|
++count;
|
|
found = true;
|
|
break; // Simple façon d'éviter la ligne après la boucle
|
|
}
|
|
}
|
|
|
|
if (!found)
|
|
newString[j++] = m_sharedString->string[i];
|
|
}
|
|
}
|
|
newString[newSize] = '\0';
|
|
|
|
ReleaseString();
|
|
|
|
m_sharedString->size = newSize;
|
|
m_sharedString->string = newString;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
*/
|
|
void NzString::Reserve(unsigned int bufferSize)
|
|
{
|
|
if (m_sharedString->capacity >= bufferSize)
|
|
return;
|
|
|
|
char* ptr = new char[bufferSize+1];
|
|
if (m_sharedString->size > 0)
|
|
std::memcpy(ptr, m_sharedString->string, m_sharedString->size+1);
|
|
|
|
unsigned int size = m_sharedString->size;
|
|
|
|
ReleaseString();
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = bufferSize;
|
|
m_sharedString->size = size;
|
|
m_sharedString->string = ptr;
|
|
}
|
|
|
|
NzString& NzString::Resize(int size, char character)
|
|
{
|
|
if (size == 0)
|
|
{
|
|
Clear(true);
|
|
return *this;
|
|
}
|
|
|
|
if (size < 0)
|
|
size = std::max(static_cast<int>(m_sharedString->size + size), 0);
|
|
|
|
unsigned int newSize = static_cast<unsigned int>(size);
|
|
|
|
if (m_sharedString->capacity >= newSize)
|
|
{
|
|
EnsureOwnership();
|
|
|
|
// Nous avons déjà la place requise, contentons-nous de remplir le buffer
|
|
if (character != '\0' && newSize > m_sharedString->size)
|
|
{
|
|
char* ptr = &m_sharedString->string[m_sharedString->size];
|
|
char* limit = &m_sharedString->string[newSize];
|
|
while (ptr != limit)
|
|
*ptr++ = character;
|
|
}
|
|
|
|
m_sharedString->size = newSize;
|
|
m_sharedString->string[newSize] = '\0';
|
|
}
|
|
else // On veut forcément agrandir la chaine
|
|
{
|
|
char* newString = new char[newSize+1];
|
|
if (m_sharedString->size != 0)
|
|
std::memcpy(newString, m_sharedString->string, newSize);
|
|
|
|
char* ptr = &newString[m_sharedString->size];
|
|
char* limit = &newString[newSize];
|
|
while (ptr != limit)
|
|
*ptr++ = character;
|
|
|
|
ReleaseString();
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = newSize;
|
|
m_sharedString->size = newSize;
|
|
m_sharedString->string = newString;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
NzString NzString::Resized(int size, char character) const
|
|
{
|
|
if (size < 0)
|
|
size = m_sharedString->size + size;
|
|
|
|
if (size <= 0)
|
|
return NzString();
|
|
|
|
unsigned int newSize = static_cast<unsigned int>(size);
|
|
if (newSize == m_sharedString->size)
|
|
return *this;
|
|
|
|
char* str = new char[newSize+1];
|
|
if (newSize > m_sharedString->size)
|
|
{
|
|
std::memcpy(str, m_sharedString->string, m_sharedString->size);
|
|
if (character != '\0')
|
|
{
|
|
char* ptr = &str[m_sharedString->size];
|
|
char* limit = &str[newSize];
|
|
while (ptr != limit)
|
|
*ptr++ = character;
|
|
}
|
|
}
|
|
else
|
|
std::memcpy(str, m_sharedString->string, newSize);
|
|
|
|
str[newSize] = '\0';
|
|
|
|
return NzString(new SharedString(1, newSize, newSize, str));
|
|
}
|
|
|
|
NzString& NzString::Reverse()
|
|
{
|
|
if (m_sharedString->size != 0)
|
|
{
|
|
unsigned int i = 0;
|
|
unsigned int j = m_sharedString->size-1;
|
|
|
|
while (i < j)
|
|
std::swap(m_sharedString->string[i++], m_sharedString->string[j--]);
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
NzString NzString::Reversed() const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return NzString();
|
|
|
|
char* str = new char[m_sharedString->size+1];
|
|
|
|
char* ptr = &str[m_sharedString->size-1];
|
|
char* p = m_sharedString->string;
|
|
|
|
do
|
|
*ptr-- = *p;
|
|
while (*(++p));
|
|
|
|
str[m_sharedString->size] = '\0';
|
|
|
|
return NzString(new SharedString(1, m_sharedString->size, m_sharedString->size, str));
|
|
}
|
|
|
|
NzString NzString::Simplified(nzUInt32 flags) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return NzString();
|
|
|
|
char* str = new char[m_sharedString->size+1];
|
|
char* p = str;
|
|
|
|
const char* ptr = m_sharedString->string;
|
|
bool inword = false;
|
|
if (flags & HandleUtf8)
|
|
{
|
|
utf8::unchecked::iterator<const char*> it(ptr);
|
|
do
|
|
{
|
|
if (NzUnicode::GetCategory(*it) & NzUnicode::Category_Separator)
|
|
{
|
|
if (inword)
|
|
{
|
|
*p++ = ' ';
|
|
inword = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
p = utf8::append(*it, p);
|
|
inword = true;
|
|
}
|
|
}
|
|
while (*++it);
|
|
}
|
|
else
|
|
{
|
|
const char* limit = &m_sharedString->string[m_sharedString->size];
|
|
do
|
|
{
|
|
if (std::isspace(*ptr))
|
|
{
|
|
if (inword)
|
|
{
|
|
*p++ = ' ';
|
|
inword = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*p++ = *ptr;
|
|
inword = true;
|
|
}
|
|
}
|
|
while (++ptr != limit);
|
|
}
|
|
|
|
if (!inword && p != str)
|
|
p--;
|
|
|
|
*p = '\0';
|
|
|
|
return NzString(new SharedString(1, m_sharedString->size, p-str, str));
|
|
}
|
|
|
|
NzString& NzString::Simplify(nzUInt32 flags)
|
|
{
|
|
return operator=(Simplified(flags));
|
|
}
|
|
|
|
unsigned int NzString::Split(std::vector<NzString>& result, char separation, int start, nzUInt32 flags) const
|
|
{
|
|
if (separation == '\0' || m_sharedString->size == 0)
|
|
return 0;
|
|
|
|
unsigned int lastSep = Find(separation, start, flags);
|
|
if (lastSep == npos)
|
|
{
|
|
result.push_back(*this);
|
|
return 1;
|
|
}
|
|
else if (lastSep != 0)
|
|
result.push_back(Substr(0, lastSep-1));
|
|
|
|
while (true)
|
|
{
|
|
unsigned int sep = Find(separation, lastSep+1, flags);
|
|
if (sep == npos)
|
|
break;
|
|
|
|
if (sep-lastSep > 1)
|
|
result.push_back(Substr(lastSep+1, sep-1));
|
|
|
|
lastSep = sep;
|
|
}
|
|
|
|
if (lastSep != m_sharedString->size-1)
|
|
result.push_back(Substr(lastSep+1));
|
|
|
|
return result.size();
|
|
}
|
|
|
|
unsigned int NzString::Split(std::vector<NzString>& result, const char* separation, int start, nzUInt32 flags) const
|
|
{
|
|
unsigned int size = (separation) ? std::strlen(separation) : 0;
|
|
if (m_sharedString->size == 0)
|
|
return 0;
|
|
else if (size == 0)
|
|
{
|
|
result.reserve(m_sharedString->size);
|
|
for (unsigned int i = 0; i < m_sharedString->size; ++i)
|
|
result.push_back(NzString(m_sharedString->string[i]));
|
|
|
|
return m_sharedString->size;
|
|
}
|
|
else if (size > m_sharedString->size)
|
|
{
|
|
result.push_back(*this);
|
|
return 1;
|
|
}
|
|
|
|
unsigned int lastSep = Find(separation, start, flags);
|
|
unsigned int oldSize = result.size();
|
|
if (lastSep == npos)
|
|
{
|
|
result.push_back(*this);
|
|
return 1;
|
|
}
|
|
else if (lastSep != 0)
|
|
result.push_back(Substr(0, lastSep-1));
|
|
|
|
unsigned int sep;
|
|
while ((sep = Find(separation, lastSep+size, flags)) != npos)
|
|
{
|
|
if (sep-lastSep > size)
|
|
result.push_back(Substr(lastSep+size, sep-1));
|
|
|
|
lastSep = sep;
|
|
}
|
|
|
|
if (lastSep != m_sharedString->size-size)
|
|
result.push_back(Substr(lastSep+size));
|
|
|
|
return result.size()-oldSize;
|
|
}
|
|
|
|
unsigned int NzString::Split(std::vector<NzString>& result, const NzString& separation, int start, nzUInt32 flags) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return 0;
|
|
else if (separation.m_sharedString->size == 0)
|
|
{
|
|
result.reserve(m_sharedString->size);
|
|
for (unsigned int i = 0; i < m_sharedString->size; ++i)
|
|
result.push_back(NzString(m_sharedString->string[i]));
|
|
|
|
return m_sharedString->size;
|
|
}
|
|
else if (separation.m_sharedString->size > m_sharedString->size)
|
|
{
|
|
result.push_back(*this);
|
|
return 1;
|
|
}
|
|
|
|
unsigned int lastSep = Find(separation, start, flags);
|
|
unsigned int oldSize = result.size();
|
|
if (lastSep == npos)
|
|
{
|
|
result.push_back(*this);
|
|
return 1;
|
|
}
|
|
else if (lastSep != 0)
|
|
result.push_back(Substr(0, lastSep-1));
|
|
|
|
unsigned int sep;
|
|
while ((sep = Find(separation, lastSep+separation.m_sharedString->size, flags)) != npos)
|
|
{
|
|
if (sep-lastSep > separation.m_sharedString->size)
|
|
result.push_back(Substr(lastSep+separation.m_sharedString->size, sep-1));
|
|
|
|
lastSep = sep;
|
|
}
|
|
|
|
if (lastSep != m_sharedString->size-separation.m_sharedString->size)
|
|
result.push_back(Substr(lastSep+separation.m_sharedString->size));
|
|
|
|
return result.size()-oldSize;
|
|
}
|
|
|
|
unsigned int NzString::SplitAny(std::vector<NzString>& result, const char* separations, int start, nzUInt32 flags) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return 0;
|
|
|
|
unsigned int oldSize = result.size();
|
|
|
|
unsigned int lastSep = FindAny(separations, start, flags);
|
|
if (lastSep == npos)
|
|
{
|
|
result.push_back(*this);
|
|
return 1;
|
|
}
|
|
else if (lastSep != 0)
|
|
result.push_back(Substr(0, lastSep-1));
|
|
|
|
unsigned int sep;
|
|
while ((sep = FindAny(separations, lastSep+1, flags)) != npos)
|
|
{
|
|
if (sep-lastSep > 1)
|
|
result.push_back(Substr(lastSep+1, sep-1));
|
|
|
|
lastSep = sep;
|
|
}
|
|
|
|
if (lastSep != m_sharedString->size-1)
|
|
result.push_back(Substr(lastSep+1));
|
|
|
|
return result.size()-oldSize;
|
|
}
|
|
|
|
unsigned int NzString::SplitAny(std::vector<NzString>& result, const NzString& separations, int start, nzUInt32 flags) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return 0;
|
|
|
|
unsigned int lastSep = FindAny(separations, start, flags);
|
|
unsigned int oldSize = result.size();
|
|
if (lastSep == npos)
|
|
{
|
|
result.push_back(*this);
|
|
return 1;
|
|
}
|
|
else if (lastSep != 0)
|
|
result.push_back(Substr(0, lastSep-1));
|
|
|
|
unsigned int sep;
|
|
while ((sep = FindAny(separations, lastSep+1, flags)) != npos)
|
|
{
|
|
if (sep-lastSep > 1)
|
|
result.push_back(Substr(lastSep+1, sep-1));
|
|
|
|
lastSep = sep;
|
|
}
|
|
|
|
if (lastSep != m_sharedString->size-1)
|
|
result.push_back(Substr(lastSep+1));
|
|
|
|
return result.size()-oldSize;
|
|
}
|
|
|
|
bool NzString::StartsWith(char character, nzUInt32 flags) const
|
|
{
|
|
if (character == '\0' || m_sharedString->size == 0)
|
|
return false;
|
|
|
|
if (flags & CaseInsensitive)
|
|
return nzToLower(m_sharedString->string[0]) == nzToLower(character);
|
|
else
|
|
return m_sharedString->string[0] == character;
|
|
}
|
|
|
|
bool NzString::StartsWith(const char* string, nzUInt32 flags) const
|
|
{
|
|
if (!string || !string[0] || m_sharedString->size == 0)
|
|
return false;
|
|
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
if (flags & HandleUtf8)
|
|
{
|
|
utf8::unchecked::iterator<const char*> it(m_sharedString->string);
|
|
utf8::unchecked::iterator<const char*> it2(string);
|
|
do
|
|
{
|
|
if (*it2 == '\0')
|
|
return true;
|
|
|
|
if (NzUnicode::GetLowercase(*it) != NzUnicode::GetLowercase(*it2))
|
|
return false;
|
|
|
|
++it2;
|
|
}
|
|
while (*it++);
|
|
}
|
|
else
|
|
{
|
|
char* ptr = m_sharedString->string;
|
|
const char* s = string;
|
|
do
|
|
{
|
|
if (*s == '\0')
|
|
return true;
|
|
|
|
if (nzToLower(*ptr) != nzToLower(*s))
|
|
return false;
|
|
|
|
s++;
|
|
}
|
|
while (*ptr++);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
char* ptr = m_sharedString->string;
|
|
const char* s = string;
|
|
do
|
|
{
|
|
if (*s == '\0')
|
|
return true;
|
|
|
|
if (*ptr != *s)
|
|
return false;
|
|
|
|
s++;
|
|
}
|
|
while (*ptr++);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool NzString::StartsWith(const NzString& string, nzUInt32 flags) const
|
|
{
|
|
if (string.m_sharedString->size == 0)
|
|
return false;
|
|
|
|
if (m_sharedString->size < string.m_sharedString->size)
|
|
return false;
|
|
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
if (flags & HandleUtf8)
|
|
{
|
|
utf8::unchecked::iterator<const char*> it(m_sharedString->string);
|
|
utf8::unchecked::iterator<const char*> it2(string.m_sharedString->string);
|
|
do
|
|
{
|
|
if (*it2 == '\0')
|
|
return true;
|
|
|
|
if (NzUnicode::GetLowercase(*it) != NzUnicode::GetLowercase(*it2))
|
|
return false;
|
|
|
|
++it2;
|
|
}
|
|
while (*it++);
|
|
}
|
|
else
|
|
{
|
|
char* ptr = m_sharedString->string;
|
|
const char* s = string.m_sharedString->string;
|
|
do
|
|
{
|
|
if (*s == '\0')
|
|
return true;
|
|
|
|
if (nzToLower(*ptr) != nzToLower(*s))
|
|
return false;
|
|
|
|
s++;
|
|
}
|
|
while (*ptr++);
|
|
}
|
|
}
|
|
else
|
|
return std::memcmp(m_sharedString->string, string.m_sharedString->string, string.m_sharedString->size) == 0;
|
|
|
|
return false;
|
|
}
|
|
|
|
NzString NzString::Substr(int startPos, int endPos) const
|
|
{
|
|
if (startPos < 0)
|
|
startPos = std::max(m_sharedString->size+startPos, 0U);
|
|
|
|
unsigned int start = static_cast<unsigned int>(startPos);
|
|
|
|
if (endPos < 0)
|
|
{
|
|
endPos = m_sharedString->size+endPos;
|
|
if (endPos < 0)
|
|
return NzString();
|
|
}
|
|
|
|
unsigned int minEnd = std::min(static_cast<unsigned int>(endPos), m_sharedString->size-1);
|
|
|
|
if (start > minEnd || start >= m_sharedString->size)
|
|
return NzString();
|
|
|
|
unsigned int size = minEnd-start+1;
|
|
char* str = new char[size+1];
|
|
std::memcpy(str, &m_sharedString->string[start], size);
|
|
str[size] = '\0';
|
|
|
|
return NzString(new SharedString(1, size, size, str));
|
|
}
|
|
|
|
NzString NzString::SubstrFrom(char character, int startPos, bool fromLast, bool include, nzUInt32 flags) const
|
|
{
|
|
if (character == '\0')
|
|
return *this;
|
|
|
|
unsigned int pos;
|
|
if (fromLast)
|
|
pos = FindLast(character, startPos, flags);
|
|
else
|
|
pos = Find(character, startPos, flags);
|
|
|
|
if (pos == 0 and include)
|
|
return *this;
|
|
else if (pos == npos)
|
|
return NzString();
|
|
|
|
return Substr(pos+((include) ? 0 : 1));
|
|
}
|
|
|
|
NzString NzString::SubstrFrom(const char* string, int startPos, bool fromLast, bool include, nzUInt32 flags) const
|
|
{
|
|
unsigned int pos;
|
|
if (fromLast)
|
|
pos = FindLast(string, startPos, flags);
|
|
else
|
|
pos = Find(string, startPos, flags);
|
|
|
|
if (pos == 0 && include)
|
|
return *this;
|
|
else if (pos == npos)
|
|
return NzString();
|
|
|
|
return Substr(pos+((include) ? 0 : std::strlen(string)));
|
|
}
|
|
|
|
NzString NzString::SubstrFrom(const NzString& string, int startPos, bool fromLast, bool include, nzUInt32 flags) const
|
|
{
|
|
unsigned int pos;
|
|
if (fromLast)
|
|
pos = FindLast(string, startPos, flags);
|
|
else
|
|
pos = Find(string, startPos, flags);
|
|
|
|
if (pos == 0 && include)
|
|
return *this;
|
|
else if (pos == npos)
|
|
return NzString();
|
|
|
|
return Substr(pos+((include) ? 0 : string.m_sharedString->size));
|
|
}
|
|
|
|
NzString NzString::SubstrTo(char character, int startPos, bool toLast, bool include, nzUInt32 flags) const
|
|
{
|
|
if (character == '\0')
|
|
return *this;
|
|
|
|
unsigned int pos;
|
|
if (toLast)
|
|
pos = FindLast(character, startPos);
|
|
else
|
|
pos = Find(character, startPos, flags);
|
|
|
|
if (pos == 0)
|
|
return (include) ? character : NzString();
|
|
else if (pos == npos)
|
|
return *this;
|
|
|
|
return Substr(0, pos+((include) ? 1 : 0)-1);
|
|
}
|
|
|
|
NzString NzString::SubstrTo(const char* string, int startPos, bool toLast, bool include, nzUInt32 flags) const
|
|
{
|
|
unsigned int pos;
|
|
if (toLast)
|
|
pos = FindLast(string, startPos, flags);
|
|
else
|
|
pos = Find(string, startPos, flags);
|
|
|
|
if (pos == 0)
|
|
return (include) ? string : NzString();
|
|
else if (pos == npos)
|
|
return *this;
|
|
|
|
return Substr(0, pos+((include) ? std::strlen(string) : 0)-1);
|
|
}
|
|
|
|
NzString NzString::SubstrTo(const NzString& string, int startPos, bool toLast, bool include, nzUInt32 flags) const
|
|
{
|
|
unsigned int pos;
|
|
if (toLast)
|
|
pos = FindLast(string, startPos, flags);
|
|
else
|
|
pos = Find(string, startPos, flags);
|
|
|
|
if (pos == 0)
|
|
return (include) ? string : NzString();
|
|
else if (pos == npos)
|
|
return *this;
|
|
|
|
return Substr(0, pos+((include) ? string.m_sharedString->size : 0)-1);
|
|
}
|
|
|
|
void NzString::Swap(NzString& str)
|
|
{
|
|
std::swap(m_sharedString, str.m_sharedString);
|
|
}
|
|
|
|
bool NzString::ToBool(bool* value, nzUInt32 flags) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return false;
|
|
|
|
NzString word = GetWord(0);
|
|
|
|
if (word[0] == '1')
|
|
{
|
|
if (value)
|
|
*value = true;
|
|
}
|
|
else if (word[0] == '0')
|
|
{
|
|
if (value)
|
|
*value = false;
|
|
}
|
|
else
|
|
{
|
|
if (flags & CaseInsensitive)
|
|
word = word.ToLower(); // Les mots identifiés sont en ASCII, inutile de passer le flag unicode
|
|
|
|
if (word == "true")
|
|
{
|
|
if (value)
|
|
*value = true;
|
|
}
|
|
else if (word == "false")
|
|
{
|
|
if (value)
|
|
*value = false;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool NzString::ToDouble(double* value) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return false;
|
|
|
|
if (value)
|
|
*value = std::atof(m_sharedString->string);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool NzString::ToInteger(long long* value, nzUInt8 base) const
|
|
{
|
|
if (value)
|
|
{
|
|
bool ok;
|
|
*value = NzStringToNumber(*this, base, &ok);
|
|
|
|
return ok;
|
|
}
|
|
else
|
|
return IsNumber(base);
|
|
}
|
|
|
|
NzString NzString::ToLower(nzUInt32 flags) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return *this;
|
|
|
|
if (flags & HandleUtf8)
|
|
{
|
|
NzString lower;
|
|
lower.Reserve(m_sharedString->size);
|
|
utf8::unchecked::iterator<const char*> it(m_sharedString->string);
|
|
do
|
|
utf8::append(NzUnicode::GetLowercase(*it), std::back_inserter(lower));
|
|
while (*++it);
|
|
|
|
return lower;
|
|
}
|
|
else
|
|
{
|
|
char* str = new char[m_sharedString->size+1];
|
|
|
|
char* ptr = m_sharedString->string;
|
|
char* s = str;
|
|
do
|
|
*s++ = nzToLower(*ptr);
|
|
while (*++ptr);
|
|
|
|
*s = '\0';
|
|
|
|
return NzString(new SharedString(1, m_sharedString->size, m_sharedString->size, str));
|
|
}
|
|
}
|
|
|
|
NzString NzString::ToUpper(nzUInt32 flags) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return *this;
|
|
|
|
if (flags & HandleUtf8)
|
|
{
|
|
NzString upper;
|
|
upper.Reserve(m_sharedString->size);
|
|
utf8::unchecked::iterator<const char*> it(m_sharedString->string);
|
|
do
|
|
utf8::append(NzUnicode::GetUppercase(*it), std::back_inserter(upper));
|
|
while (*++it);
|
|
|
|
return upper;
|
|
}
|
|
else
|
|
{
|
|
char* str = new char[m_sharedString->size+1];
|
|
|
|
char* ptr = m_sharedString->string;
|
|
char* s = str;
|
|
do
|
|
*s++ = nzToUpper(*ptr);
|
|
while (*++ptr);
|
|
|
|
*s = '\0';
|
|
|
|
return NzString(new SharedString(1, m_sharedString->size, m_sharedString->size, str));
|
|
}
|
|
}
|
|
|
|
NzString& NzString::Trim(nzUInt32 flags)
|
|
{
|
|
return operator=(Trimmed(flags));
|
|
}
|
|
|
|
NzString& NzString::Trim(char character, nzUInt32 flags)
|
|
{
|
|
return operator=(Trimmed(character, flags));
|
|
}
|
|
|
|
NzString NzString::Trimmed(nzUInt32 flags) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return *this;
|
|
|
|
unsigned int startPos;
|
|
unsigned int endPos;
|
|
if (flags & HandleUtf8)
|
|
{
|
|
if ((flags & TrimOnlyRight) == 0)
|
|
{
|
|
utf8::unchecked::iterator<const char*> it(m_sharedString->string);
|
|
do
|
|
{
|
|
if (NzUnicode::GetCategory(*it) & NzUnicode::Category_Separator)
|
|
break;
|
|
}
|
|
while (*++it);
|
|
|
|
startPos = it.base() - m_sharedString->string;
|
|
}
|
|
else
|
|
startPos = 0;
|
|
|
|
if ((flags & TrimOnlyLeft) == 0)
|
|
{
|
|
utf8::unchecked::iterator<const char*> it(&m_sharedString->string[m_sharedString->size]);
|
|
while ((it--).base() != m_sharedString->string)
|
|
{
|
|
if (NzUnicode::GetCategory(*it) & NzUnicode::Category_Separator)
|
|
break;
|
|
}
|
|
|
|
endPos = it.base() - m_sharedString->string;
|
|
}
|
|
else
|
|
endPos = m_sharedString->size-1;
|
|
}
|
|
else
|
|
{
|
|
startPos = 0;
|
|
if ((flags & TrimOnlyRight) == 0)
|
|
{
|
|
for (; startPos < m_sharedString->size; ++startPos)
|
|
{
|
|
if (!std::isspace(m_sharedString->string[startPos]))
|
|
break;
|
|
}
|
|
}
|
|
|
|
endPos = m_sharedString->size-1;
|
|
if ((flags & TrimOnlyLeft) == 0)
|
|
{
|
|
for (; endPos > 0; --endPos)
|
|
{
|
|
if (!std::isspace(m_sharedString->string[endPos]))
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Substr(startPos, endPos);
|
|
}
|
|
|
|
NzString NzString::Trimmed(char character, nzUInt32 flags) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return *this;
|
|
|
|
unsigned int startPos = 0;
|
|
unsigned int endPos = m_sharedString->size-1;
|
|
if (flags & CaseInsensitive)
|
|
{
|
|
char ch = nzToLower(character);
|
|
if ((flags & TrimOnlyRight) == 0)
|
|
{
|
|
for (; startPos < m_sharedString->size; ++startPos)
|
|
{
|
|
if (nzToLower(m_sharedString->string[startPos]) != ch)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((flags & TrimOnlyLeft) == 0)
|
|
{
|
|
for (; endPos > 0; --endPos)
|
|
{
|
|
if (nzToLower(m_sharedString->string[endPos]) != ch)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((flags & TrimOnlyRight) == 0)
|
|
{
|
|
for (; startPos < m_sharedString->size; ++startPos)
|
|
{
|
|
if (m_sharedString->string[startPos] != character)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((flags & TrimOnlyLeft) == 0)
|
|
{
|
|
for (; endPos > 0; --endPos)
|
|
{
|
|
if (m_sharedString->string[endPos] != character)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Substr(startPos, endPos);
|
|
}
|
|
|
|
char* NzString::begin()
|
|
{
|
|
return m_sharedString->string;
|
|
}
|
|
|
|
const char* NzString::begin() const
|
|
{
|
|
return m_sharedString->string;
|
|
}
|
|
|
|
char* NzString::end()
|
|
{
|
|
return &m_sharedString->string[m_sharedString->size];
|
|
}
|
|
|
|
const char* NzString::end() const
|
|
{
|
|
return &m_sharedString->string[m_sharedString->size];
|
|
}
|
|
|
|
void NzString::push_front(char c)
|
|
{
|
|
operator=(c + *this);
|
|
}
|
|
|
|
void NzString::push_back(char c)
|
|
{
|
|
operator+=(c);
|
|
}
|
|
/*
|
|
char* NzString::rbegin()
|
|
{
|
|
return &m_sharedString->string[m_sharedString->size-1];
|
|
}
|
|
|
|
const char* NzString::rbegin() const
|
|
{
|
|
return &m_sharedString->string[m_sharedString->size-1];
|
|
}
|
|
|
|
char* NzString::rend()
|
|
{
|
|
return &m_sharedString->string[-1];
|
|
}
|
|
|
|
const char* NzString::rend() const
|
|
{
|
|
return &m_sharedString->string[-1];
|
|
}
|
|
*/
|
|
|
|
NzString::operator std::string() const
|
|
{
|
|
return std::string(m_sharedString->string, m_sharedString->size);
|
|
}
|
|
|
|
char& NzString::operator[](unsigned int pos)
|
|
{
|
|
EnsureOwnership();
|
|
|
|
if (pos >= m_sharedString->size)
|
|
Resize(pos+1);
|
|
|
|
return m_sharedString->string[pos];
|
|
}
|
|
|
|
char NzString::operator[](unsigned int pos) const
|
|
{
|
|
#if NAZARA_CORE_SAFE
|
|
if (pos >= m_sharedString->size)
|
|
{
|
|
NazaraError("Index out of range (" + Number(pos) + " >= " + Number(m_sharedString->size) + ')');
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
return m_sharedString->string[pos];
|
|
}
|
|
|
|
NzString& NzString::operator=(char character)
|
|
{
|
|
if (character != '\0')
|
|
{
|
|
if (m_sharedString->capacity >= 1)
|
|
EnsureOwnership();
|
|
else
|
|
{
|
|
ReleaseString();
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = 1;
|
|
m_sharedString->string = new char[2];
|
|
}
|
|
|
|
m_sharedString->size = 1;
|
|
m_sharedString->string[0] = character;
|
|
m_sharedString->string[1] = '\0';
|
|
}
|
|
else
|
|
ReleaseString();
|
|
|
|
return *this;
|
|
}
|
|
|
|
NzString& NzString::operator=(const char* string)
|
|
{
|
|
if (string && string[0] != '\0')
|
|
{
|
|
unsigned int size = std::strlen(string);
|
|
if (m_sharedString->capacity >= size)
|
|
EnsureOwnership();
|
|
else
|
|
{
|
|
ReleaseString();
|
|
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = size;
|
|
m_sharedString->string = new char[size+1];
|
|
}
|
|
|
|
m_sharedString->size = size;
|
|
std::memcpy(m_sharedString->string, string, size+1);
|
|
}
|
|
else
|
|
ReleaseString();
|
|
|
|
return *this;
|
|
}
|
|
|
|
NzString& NzString::operator=(const std::string& string)
|
|
{
|
|
if (string.size() > 0)
|
|
{
|
|
if (m_sharedString->capacity >= string.size())
|
|
EnsureOwnership();
|
|
else
|
|
{
|
|
ReleaseString();
|
|
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = string.size();
|
|
m_sharedString->string = new char[string.size()+1];
|
|
}
|
|
|
|
m_sharedString->size = string.size();
|
|
std::memcpy(m_sharedString->string, string.c_str(), string.size()+1);
|
|
}
|
|
else
|
|
ReleaseString();
|
|
|
|
return *this;
|
|
}
|
|
|
|
NzString& NzString::operator=(const NzString& string)
|
|
{
|
|
ReleaseString();
|
|
|
|
m_sharedString = string.m_sharedString;
|
|
if (m_sharedString != &emptyString)
|
|
{
|
|
NazaraMutexLock(m_sharedString->mutex);
|
|
m_sharedString->refCount++;
|
|
NazaraMutexUnlock(m_sharedString->mutex);
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
NzString& NzString::operator=(NzString&& string) noexcept
|
|
{
|
|
std::swap(m_sharedString, string.m_sharedString);
|
|
|
|
return *this;
|
|
}
|
|
|
|
NzString NzString::operator+(char character) const
|
|
{
|
|
if (character == '\0')
|
|
return *this;
|
|
|
|
unsigned int totalSize = m_sharedString->size+1;
|
|
char* str = new char[totalSize+1];
|
|
std::memcpy(str, m_sharedString->string, m_sharedString->size);
|
|
|
|
str[m_sharedString->size] = character;
|
|
str[totalSize] = '\0';
|
|
|
|
return NzString(new SharedString(1, totalSize, totalSize, str));
|
|
}
|
|
|
|
NzString NzString::operator+(const char* string) const
|
|
{
|
|
if (!string || !string[0])
|
|
return *this;
|
|
|
|
if (m_sharedString->size == 0)
|
|
return string;
|
|
|
|
unsigned int length = std::strlen(string);
|
|
if (length == 0)
|
|
return *this;
|
|
|
|
unsigned int totalSize = m_sharedString->size + length;
|
|
char* str = new char[totalSize+1];
|
|
std::memcpy(str, m_sharedString->string, m_sharedString->size);
|
|
std::memcpy(&str[m_sharedString->size], string, length+1);
|
|
|
|
return NzString(new SharedString(1, totalSize, totalSize, str));
|
|
}
|
|
|
|
NzString NzString::operator+(const std::string& string) const
|
|
{
|
|
if (string.empty())
|
|
return *this;
|
|
|
|
if (m_sharedString->size == 0)
|
|
return string;
|
|
|
|
unsigned int totalSize = m_sharedString->size + string.size();
|
|
char* str = new char[totalSize+1];
|
|
std::memcpy(str, m_sharedString->string, m_sharedString->size);
|
|
std::memcpy(&str[m_sharedString->size], string.c_str(), string.size()+1);
|
|
|
|
return NzString(new SharedString(1, totalSize, totalSize, str));
|
|
}
|
|
|
|
NzString NzString::operator+(const NzString& string) const
|
|
{
|
|
if (string.m_sharedString->size == 0)
|
|
return *this;
|
|
|
|
if (m_sharedString->size == 0)
|
|
return string;
|
|
|
|
unsigned int totalSize = m_sharedString->size + string.m_sharedString->size;
|
|
char* str = new char[totalSize+1];
|
|
std::memcpy(str, m_sharedString->string, m_sharedString->size);
|
|
std::memcpy(&str[m_sharedString->size], string.m_sharedString->string, string.m_sharedString->size+1);
|
|
|
|
return NzString(new SharedString(1, totalSize, totalSize, str));
|
|
}
|
|
|
|
NzString& NzString::operator+=(char character)
|
|
{
|
|
if (character == '\0')
|
|
return *this;
|
|
|
|
if (m_sharedString->size == 0)
|
|
return operator=(character);
|
|
|
|
if (m_sharedString->capacity > m_sharedString->size)
|
|
{
|
|
EnsureOwnership();
|
|
|
|
m_sharedString->string[m_sharedString->size] = character;
|
|
m_sharedString->string[m_sharedString->size+1] = '\0';
|
|
m_sharedString->size++;
|
|
}
|
|
else
|
|
{
|
|
unsigned int newSize = m_sharedString->size+1;
|
|
unsigned int bufferSize = nzGetNewSize(newSize);
|
|
|
|
char* str = new char[bufferSize+1];
|
|
std::memcpy(str, m_sharedString->string, m_sharedString->size);
|
|
str[m_sharedString->size] = character;
|
|
str[newSize] = '\0';
|
|
|
|
ReleaseString();
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = bufferSize;
|
|
m_sharedString->size = newSize;
|
|
m_sharedString->string = str;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
NzString& NzString::operator+=(const char* string)
|
|
{
|
|
if (!string || !string[0])
|
|
return *this;
|
|
|
|
if (m_sharedString->size == 0)
|
|
return operator=(string);
|
|
|
|
unsigned int size = std::strlen(string);
|
|
if (size == 0)
|
|
return *this;
|
|
|
|
if (m_sharedString->capacity >= m_sharedString->size + size)
|
|
{
|
|
EnsureOwnership();
|
|
|
|
std::memcpy(&m_sharedString->string[m_sharedString->size], string, size+1);
|
|
m_sharedString->size += size;
|
|
}
|
|
else
|
|
{
|
|
unsigned int newSize = m_sharedString->size + size;
|
|
unsigned int bufferSize = nzGetNewSize(newSize);
|
|
|
|
char* str = new char[bufferSize+1];
|
|
std::memcpy(str, m_sharedString->string, m_sharedString->size);
|
|
std::memcpy(&str[m_sharedString->size], string, size+1);
|
|
|
|
ReleaseString();
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = bufferSize;
|
|
m_sharedString->size = newSize;
|
|
m_sharedString->string = str;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
NzString& NzString::operator+=(const std::string& string)
|
|
{
|
|
if (string.empty())
|
|
return *this;
|
|
|
|
if (m_sharedString->size == 0)
|
|
return operator=(string);
|
|
|
|
if (m_sharedString->capacity >= m_sharedString->size + string.size())
|
|
{
|
|
EnsureOwnership();
|
|
|
|
std::memcpy(&m_sharedString->string[m_sharedString->size], string.c_str(), string.size()+1);
|
|
m_sharedString->size += string.size();
|
|
}
|
|
else
|
|
{
|
|
unsigned int newSize = m_sharedString->size + string.size();
|
|
unsigned int bufferSize = nzGetNewSize(newSize);
|
|
|
|
char* str = new char[bufferSize+1];
|
|
std::memcpy(str, m_sharedString->string, m_sharedString->size);
|
|
std::memcpy(&str[m_sharedString->size], string.c_str(), string.size()+1);
|
|
|
|
ReleaseString();
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = bufferSize;
|
|
m_sharedString->size = newSize;
|
|
m_sharedString->string = str;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
NzString& NzString::operator+=(const NzString& string)
|
|
{
|
|
if (string.m_sharedString->size == 0)
|
|
return *this;
|
|
|
|
if (m_sharedString->size == 0)
|
|
return operator=(string);
|
|
|
|
if (m_sharedString->capacity >= m_sharedString->size + string.m_sharedString->size)
|
|
{
|
|
EnsureOwnership();
|
|
|
|
std::memcpy(&m_sharedString->string[m_sharedString->size], string.m_sharedString->string, string.m_sharedString->size+1);
|
|
m_sharedString->size += string.m_sharedString->size;
|
|
}
|
|
else
|
|
{
|
|
unsigned int newSize = m_sharedString->size + string.m_sharedString->size;
|
|
unsigned int bufferSize = nzGetNewSize(newSize);
|
|
|
|
char* str = new char[bufferSize+1];
|
|
std::memcpy(str, m_sharedString->string, m_sharedString->size);
|
|
std::memcpy(&str[m_sharedString->size], string.m_sharedString->string, string.m_sharedString->size+1);
|
|
|
|
ReleaseString();
|
|
m_sharedString = new SharedString;
|
|
m_sharedString->capacity = bufferSize;
|
|
m_sharedString->size = newSize;
|
|
m_sharedString->string = str;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
bool NzString::operator==(char character) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return character == '\0';
|
|
|
|
if (m_sharedString->size > 1)
|
|
return false;
|
|
|
|
return m_sharedString->string[0] == character;
|
|
}
|
|
|
|
bool NzString::operator==(const char* string) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return !string || !string[0];
|
|
|
|
if (!string || !string[0])
|
|
return false;
|
|
|
|
return std::strcmp(m_sharedString->string, string) == 0;
|
|
}
|
|
|
|
bool NzString::operator==(const std::string& string) const
|
|
{
|
|
if (m_sharedString->size == 0 || string.empty())
|
|
return m_sharedString->size == string.size();
|
|
|
|
if (m_sharedString->size != string.size())
|
|
return false;
|
|
|
|
return std::strcmp(m_sharedString->string, string.c_str()) == 0;
|
|
}
|
|
|
|
bool NzString::operator!=(char character) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return character != '\0';
|
|
|
|
if (character == '\0' || m_sharedString->size != 1)
|
|
return true;
|
|
|
|
if (m_sharedString->size != 1)
|
|
return true;
|
|
|
|
return m_sharedString->string[0] != character;
|
|
}
|
|
|
|
bool NzString::operator!=(const char* string) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return string && string[0];
|
|
|
|
if (!string || !string[0])
|
|
return true;
|
|
|
|
return std::strcmp(m_sharedString->string, string) != 0;
|
|
}
|
|
|
|
bool NzString::operator!=(const std::string& string) const
|
|
{
|
|
if (m_sharedString->size == 0 || string.empty())
|
|
return m_sharedString->size == string.size();
|
|
|
|
if (m_sharedString->size != string.size())
|
|
return false;
|
|
|
|
return std::strcmp(m_sharedString->string, string.c_str()) != 0;
|
|
}
|
|
|
|
bool NzString::operator<(char character) const
|
|
{
|
|
if (character == '\0')
|
|
return false;
|
|
|
|
if (m_sharedString->size == 0)
|
|
return true;
|
|
|
|
return m_sharedString->string[0] < character;
|
|
}
|
|
|
|
bool NzString::operator<(const char* string) const
|
|
{
|
|
if (!string || !string[0])
|
|
return false;
|
|
|
|
if (m_sharedString->size == 0)
|
|
return true;
|
|
|
|
return std::strcmp(m_sharedString->string, string) < 0;
|
|
}
|
|
|
|
bool NzString::operator<(const std::string& string) const
|
|
{
|
|
if (string.empty())
|
|
return false;
|
|
|
|
if (m_sharedString->size == 0)
|
|
return true;
|
|
|
|
return std::strcmp(m_sharedString->string, string.c_str()) < 0;
|
|
}
|
|
|
|
bool NzString::operator<=(char character) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return true;
|
|
|
|
if (character == '\0')
|
|
return false;
|
|
|
|
return m_sharedString->string[0] < character || (m_sharedString->string[0] == character && m_sharedString->size == 1);
|
|
}
|
|
|
|
bool NzString::operator<=(const char* string) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return true;
|
|
|
|
if (!string || !string[0])
|
|
return false;
|
|
|
|
return std::strcmp(m_sharedString->string, string) <= 0;
|
|
}
|
|
|
|
bool NzString::operator<=(const std::string& string) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return true;
|
|
|
|
if (string.empty())
|
|
return false;
|
|
|
|
return std::strcmp(m_sharedString->string, string.c_str()) <= 0;
|
|
}
|
|
|
|
bool NzString::operator>(char character) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return false;
|
|
|
|
if (character == '\0')
|
|
return true;
|
|
|
|
return m_sharedString->string[0] > character;
|
|
}
|
|
|
|
bool NzString::operator>(const char* string) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return false;
|
|
|
|
if (!string || !string[0])
|
|
return true;
|
|
|
|
return std::strcmp(m_sharedString->string, string) > 0;
|
|
}
|
|
|
|
bool NzString::operator>(const std::string& string) const
|
|
{
|
|
if (m_sharedString->size == 0)
|
|
return false;
|
|
|
|
if (string.empty())
|
|
return true;
|
|
|
|
return std::strcmp(m_sharedString->string, string.c_str()) > 0;
|
|
}
|
|
|
|
bool NzString::operator>=(char character) const
|
|
{
|
|
if (character == '\0')
|
|
return true;
|
|
|
|
if (m_sharedString->size == 0)
|
|
return false;
|
|
|
|
return m_sharedString->string[0] > character || (m_sharedString->string[0] == character && m_sharedString->size == 1);
|
|
}
|
|
|
|
bool NzString::operator>=(const char* string) const
|
|
{
|
|
if (!string || !string[0])
|
|
return true;
|
|
|
|
if (m_sharedString->size == 0)
|
|
return false;
|
|
|
|
return std::strcmp(m_sharedString->string, string) >= 0;
|
|
}
|
|
|
|
bool NzString::operator>=(const std::string& string) const
|
|
{
|
|
if (string.empty())
|
|
return true;
|
|
|
|
if (m_sharedString->size == 0)
|
|
return false;
|
|
|
|
return std::strcmp(m_sharedString->string, string.c_str()) >= 0;
|
|
}
|
|
|
|
NzString NzString::Boolean(bool boolean)
|
|
{
|
|
unsigned int size = (boolean) ? 4 : 5;
|
|
char* str = new char[size+1];
|
|
std::strcpy(str, (boolean) ? "true" : "false");
|
|
|
|
return NzString(new SharedString(1, size, size, str));
|
|
}
|
|
|
|
int NzString::Compare(const NzString& first, const NzString& second)
|
|
{
|
|
if (first.m_sharedString->size == 0)
|
|
return (second.m_sharedString->size == 0) ? 0 : -1;
|
|
|
|
if (second.m_sharedString->size == 0)
|
|
return 1;
|
|
|
|
return std::strcmp(first.m_sharedString->string, second.m_sharedString->string);
|
|
}
|
|
|
|
NzString NzString::Number(float number)
|
|
{
|
|
std::ostringstream oss;
|
|
oss.precision(NAZARA_CORE_REAL_PRECISION);
|
|
oss << number;
|
|
|
|
return NzString(oss.str());
|
|
}
|
|
|
|
NzString NzString::Number(double number)
|
|
{
|
|
std::ostringstream oss;
|
|
oss.precision(NAZARA_CORE_REAL_PRECISION);
|
|
oss << number;
|
|
|
|
return NzString(oss.str());
|
|
}
|
|
|
|
NzString NzString::Number(long double number)
|
|
{
|
|
std::ostringstream oss;
|
|
oss.precision(NAZARA_CORE_REAL_PRECISION);
|
|
oss << number;
|
|
|
|
return NzString(oss.str());
|
|
}
|
|
|
|
NzString NzString::Number(signed char number, nzUInt8 radix)
|
|
{
|
|
return NzNumberToString(number, radix);
|
|
}
|
|
|
|
NzString NzString::Number(unsigned char number, nzUInt8 radix)
|
|
{
|
|
return NzNumberToString(number, radix);
|
|
}
|
|
|
|
NzString NzString::Number(short number, nzUInt8 radix)
|
|
{
|
|
return NzNumberToString(number, radix);
|
|
}
|
|
|
|
NzString NzString::Number(unsigned short number, nzUInt8 radix)
|
|
{
|
|
return NzNumberToString(number, radix);
|
|
}
|
|
|
|
NzString NzString::Number(int number, nzUInt8 radix)
|
|
{
|
|
return NzNumberToString(number, radix);
|
|
}
|
|
|
|
NzString NzString::Number(unsigned int number, nzUInt8 radix)
|
|
{
|
|
return NzNumberToString(number, radix);
|
|
}
|
|
|
|
NzString NzString::Number(long number, nzUInt8 radix)
|
|
{
|
|
return NzNumberToString(number, radix);
|
|
}
|
|
|
|
NzString NzString::Number(unsigned long number, nzUInt8 radix)
|
|
{
|
|
return NzNumberToString(number, radix);
|
|
}
|
|
|
|
NzString NzString::Number(long long number, nzUInt8 radix)
|
|
{
|
|
return NzNumberToString(number, radix);
|
|
}
|
|
|
|
NzString NzString::Number(unsigned long long number, nzUInt8 radix)
|
|
{
|
|
return NzNumberToString(number, radix);
|
|
}
|
|
|
|
NzString NzString::Pointer(const void* ptr)
|
|
{
|
|
unsigned int size = sizeof(ptr)*2+2;
|
|
char* str = new char[size+1];
|
|
std::sprintf(str, "0x%p", ptr);
|
|
|
|
return NzString(new SharedString(1, size, size, str));
|
|
}
|
|
|
|
NzString NzString::Unicode(char32_t character)
|
|
{
|
|
if (character == '\0')
|
|
return NzString();
|
|
|
|
unsigned int count = 0;
|
|
if (character < 0x80)
|
|
count = 1;
|
|
else if (character < 0x800)
|
|
count = 2;
|
|
else if (character < 0x10000)
|
|
count = 3;
|
|
else
|
|
count = 4;
|
|
|
|
char* str = new char[count+1];
|
|
utf8::append(character, str);
|
|
str[count] = '\0';
|
|
|
|
return NzString(new SharedString(1, count, count, str));
|
|
}
|
|
|
|
NzString NzString::Unicode(const char* u8String)
|
|
{
|
|
return NzString(u8String);
|
|
}
|
|
|
|
NzString NzString::Unicode(const char16_t* u16String)
|
|
{
|
|
if (!u16String || !u16String[0])
|
|
return NzString();
|
|
|
|
const char16_t* ptr = u16String;
|
|
unsigned int count = 0;
|
|
do
|
|
count++;
|
|
while (*++ptr);
|
|
|
|
count *= 2; // On s'assure d'avoir la place suffisante
|
|
|
|
char* str = new char[count+1];
|
|
char* r = utf8::utf16to8(u16String, ptr, str);
|
|
*r = '\0';
|
|
|
|
return NzString(new SharedString(1, count, r-str, str));
|
|
}
|
|
|
|
NzString NzString::Unicode(const char32_t* u32String)
|
|
{
|
|
if (!u32String || !u32String[0])
|
|
return NzString();
|
|
|
|
const char32_t* ptr = u32String;
|
|
unsigned int count = 0;
|
|
do
|
|
{
|
|
char32_t cp = *ptr;
|
|
if (cp < 0x80)
|
|
count += 1;
|
|
else if (cp < 0x800)
|
|
count += 2;
|
|
else if (cp < 0x10000)
|
|
count += 3;
|
|
else
|
|
count += 4;
|
|
}
|
|
while (*++ptr);
|
|
|
|
char* str = new char[count+1];
|
|
char* r = utf8::utf32to8(u32String, ptr, str);
|
|
*r = '\0';
|
|
|
|
return NzString(new SharedString(1, count, count, str));
|
|
}
|
|
|
|
NzString NzString::Unicode(const wchar_t* wString)
|
|
{
|
|
if (!wString || !wString[0])
|
|
return NzString();
|
|
|
|
const wchar_t* ptr = wString;
|
|
unsigned int count = 0;
|
|
do
|
|
{
|
|
char32_t cp = *ptr;
|
|
if (cp < 0x80)
|
|
count += 1;
|
|
else if (cp < 0x800)
|
|
count += 2;
|
|
else if (cp < 0x10000)
|
|
count += 3;
|
|
else
|
|
count += 4;
|
|
}
|
|
while (*++ptr);
|
|
|
|
char* str = new char[count+1];
|
|
char* r = utf8::utf32to8(wString, ptr, str);
|
|
*r = '\0';
|
|
|
|
return NzString(new SharedString(1, count, count, str));
|
|
}
|
|
|
|
std::istream& operator>>(std::istream& is, NzString& str)
|
|
{
|
|
str.Clear();
|
|
|
|
char c;
|
|
do
|
|
{
|
|
is.get(c);
|
|
if (c == '\0')
|
|
break;
|
|
else if (std::isspace(c))
|
|
{
|
|
if (str.IsNull())
|
|
continue;
|
|
else
|
|
break;
|
|
}
|
|
else
|
|
str += c;
|
|
}
|
|
while (true);
|
|
|
|
return is;
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream& os, const NzString& str)
|
|
{
|
|
if (str.IsEmpty())
|
|
return os;
|
|
|
|
return operator<<(os, str.m_sharedString->string);
|
|
}
|
|
|
|
NzString operator+(char character, const NzString& string)
|
|
{
|
|
if (character == '\0')
|
|
return string;
|
|
|
|
if (string.IsEmpty())
|
|
return character;
|
|
|
|
unsigned int totalSize = string.m_sharedString->size+1;
|
|
char* str = new char[totalSize+1];
|
|
str[0] = character;
|
|
std::memcpy(&str[1], string.m_sharedString->string, string.m_sharedString->size+1);
|
|
|
|
return NzString(new NzString::SharedString(1, totalSize, totalSize, str));
|
|
}
|
|
|
|
NzString operator+(const char* string, const NzString& nstring)
|
|
{
|
|
if (!string || !string[0])
|
|
return nstring;
|
|
|
|
if (nstring.IsEmpty())
|
|
return string;
|
|
|
|
unsigned int size = std::strlen(string);
|
|
unsigned int totalSize = size + nstring.m_sharedString->size;
|
|
char* str = new char[totalSize+1];
|
|
std::memcpy(str, string, size);
|
|
std::memcpy(&str[size], nstring.m_sharedString->string, nstring.m_sharedString->size+1);
|
|
|
|
return NzString(new NzString::SharedString(1, totalSize, totalSize, str));
|
|
}
|
|
|
|
NzString operator+(const std::string& string, const NzString& nstring)
|
|
{
|
|
if (string.empty())
|
|
return nstring;
|
|
|
|
if (nstring.m_sharedString->size == 0)
|
|
return string;
|
|
|
|
unsigned int totalSize = string.size() + nstring.m_sharedString->size;
|
|
char* str = new char[totalSize+1];
|
|
std::memcpy(str, string.c_str(), string.size());
|
|
std::memcpy(&str[string.size()], nstring.m_sharedString->string, nstring.m_sharedString->size+1);
|
|
|
|
return NzString(new NzString::SharedString(1, totalSize, totalSize, str));
|
|
}
|
|
|
|
bool operator==(const NzString& first, const NzString& second)
|
|
{
|
|
if (first.m_sharedString->size == 0 || second.m_sharedString->size == 0)
|
|
return first.m_sharedString->size == second.m_sharedString->size;
|
|
|
|
if (first.m_sharedString->size != second.m_sharedString->size)
|
|
return false;
|
|
|
|
return std::strcmp(first.m_sharedString->string, second.m_sharedString->string) == 0;
|
|
}
|
|
|
|
bool operator!=(const NzString& first, const NzString& second)
|
|
{
|
|
return !operator==(first, second);
|
|
}
|
|
|
|
bool operator<(const NzString& first, const NzString& second)
|
|
{
|
|
if (second.m_sharedString->size == 0)
|
|
return false;
|
|
|
|
if (first.m_sharedString->size == 0)
|
|
return true;
|
|
|
|
return std::strcmp(first.m_sharedString->string, second.m_sharedString->string) < 0;
|
|
}
|
|
|
|
bool operator<=(const NzString& first, const NzString& second)
|
|
{
|
|
return !operator<(second, first);
|
|
}
|
|
|
|
bool operator>(const NzString& first, const NzString& second)
|
|
{
|
|
return second < first;
|
|
}
|
|
|
|
bool operator>=(const NzString& first, const NzString& second)
|
|
{
|
|
return !operator<(first, second);
|
|
}
|
|
|
|
bool operator==(char character, const NzString& nstring)
|
|
{
|
|
return nstring == character;
|
|
}
|
|
|
|
bool operator==(const char* string, const NzString& nstring)
|
|
{
|
|
return nstring == string;
|
|
}
|
|
|
|
bool operator==(const std::string& string, const NzString& nstring)
|
|
{
|
|
return nstring == string;
|
|
}
|
|
|
|
bool operator!=(char character, const NzString& nstring)
|
|
{
|
|
return !operator==(character, nstring);
|
|
}
|
|
|
|
bool operator!=(const char* string, const NzString& nstring)
|
|
{
|
|
return !operator==(string, nstring);
|
|
}
|
|
|
|
bool operator!=(const std::string& string, const NzString& nstring)
|
|
{
|
|
return !operator==(string, nstring);
|
|
}
|
|
|
|
bool operator<(char character, const NzString& nstring)
|
|
{
|
|
return nstring > character;
|
|
}
|
|
|
|
bool operator<(const char* string, const NzString& nstring)
|
|
{
|
|
return nstring > string;
|
|
}
|
|
|
|
bool operator<(const std::string& string, const NzString& nstring)
|
|
{
|
|
return nstring > string;
|
|
}
|
|
|
|
bool operator<=(char character, const NzString& nstring)
|
|
{
|
|
return !operator<(nstring, character);
|
|
}
|
|
|
|
bool operator<=(const char* string, const NzString& nstring)
|
|
{
|
|
return !operator<(nstring, string);
|
|
}
|
|
|
|
bool operator<=(const std::string& string, const NzString& nstring)
|
|
{
|
|
return !operator<(nstring, string);
|
|
}
|
|
|
|
bool operator>(char character, const NzString& nstring)
|
|
{
|
|
return nstring < character;
|
|
}
|
|
|
|
bool operator>(const char* string, const NzString& nstring)
|
|
{
|
|
return nstring < string;
|
|
}
|
|
|
|
bool operator>(const std::string& string, const NzString& nstring)
|
|
{
|
|
return nstring < string;
|
|
}
|
|
|
|
bool operator>=(char character, const NzString& nstring)
|
|
{
|
|
return !operator<(character, nstring);
|
|
}
|
|
|
|
bool operator>=(const char* string, const NzString& nstring)
|
|
{
|
|
return !operator<(string, nstring);
|
|
}
|
|
|
|
bool operator>=(const std::string& string, const NzString& nstring)
|
|
{
|
|
return !operator<(string, nstring);
|
|
}
|
|
|
|
void NzString::EnsureOwnership()
|
|
{
|
|
if (m_sharedString == &emptyString)
|
|
return;
|
|
|
|
NazaraLock(m_sharedString->mutex);
|
|
if (m_sharedString->refCount > 1)
|
|
{
|
|
m_sharedString->refCount--;
|
|
|
|
char* string = new char[m_sharedString->capacity+1];
|
|
std::memcpy(string, m_sharedString->string, m_sharedString->size+1);
|
|
|
|
m_sharedString = new SharedString(1, m_sharedString->capacity, m_sharedString->size, string);
|
|
}
|
|
}
|
|
|
|
bool NzString::FillHash(NzHashImpl* hazh) const
|
|
{
|
|
hazh->Append(reinterpret_cast<const nzUInt8*>(m_sharedString->string), m_sharedString->size);
|
|
|
|
return true;
|
|
}
|
|
|
|
void NzString::ReleaseString()
|
|
{
|
|
if (m_sharedString == &emptyString)
|
|
return;
|
|
|
|
NazaraMutexLock(m_sharedString->mutex);
|
|
bool freeSharedString = (--m_sharedString->refCount == 0);
|
|
NazaraMutexUnlock(m_sharedString->mutex);
|
|
|
|
if (freeSharedString)
|
|
{
|
|
delete[] m_sharedString->string;
|
|
delete m_sharedString;
|
|
}
|
|
|
|
m_sharedString = &emptyString;
|
|
}
|
|
|
|
NzString::SharedString NzString::emptyString(0, 0, 0, nullptr);
|
|
const unsigned int NzString::npos(std::numeric_limits<unsigned int>::max());
|
|
|
|
namespace std
|
|
{
|
|
istream& getline(istream& is, NzString& str)
|
|
{
|
|
str.Clear();
|
|
|
|
char c;
|
|
do
|
|
{
|
|
is.get(c);
|
|
if (c != '\n' && c != '\0')
|
|
str += c;
|
|
else
|
|
break;
|
|
}
|
|
while (true);
|
|
|
|
return is;
|
|
}
|
|
|
|
istream& getline(istream& is, NzString& str, char delim)
|
|
{
|
|
str.Clear();
|
|
|
|
char c;
|
|
do
|
|
{
|
|
is.get(c);
|
|
if (c != delim && c != '\0')
|
|
str += c;
|
|
else
|
|
break;
|
|
}
|
|
while (true);
|
|
|
|
return is;
|
|
}
|
|
|
|
void swap(NzString& lhs, NzString& rhs)
|
|
{
|
|
lhs.Swap(rhs);
|
|
}
|
|
}
|