Files
Webcam/include/platform/nstring/nstring.cpp

1311 lines
26 KiB
C++

/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include <cstdio>
#include <cctype>
#include <cstring>
#if __PLATFORM_WINDOWS__
#include <cstdarg>
#elif __PLATFORM_NINTENDO_WII__
#include <revolution/os.h>
#elif __PLATFORM_POSIX__
#include <stdarg.h>
#include <stdlib.h>
#endif
#include "nstring/nstring.h"
#include "container/nlist.h"
#include "container/narray.h"
#include "platform_config.h"
#include "alloc/ialloc.h"
using namespace GS;
//------------------------------------------------------------------------------
static char __lowercase(char c)
{
if ((c >= 'A') && (c <= 'Z'))
c = c - 'A' + 'a';
return c;
}
static bool __isValidSymbolCharacter(char c)
{
return (
((c >= 'a') && (c <= 'z')) ||
((c >= 'A') && (c <= 'Z')) ||
((c >= '0') && (c <= '9')) ||
(c == '_')
);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
#if (__PLATFORM_LINUX__ || __PLATFORM_OSX__ || __PLATFORM_IOS__ || __PLATFORM_ANDROID_NDK__)
void strupr(char *s)
{
for (; s[0]; ++s)
if ((s[0] >= 'a') || (s[0] <= 'z'))
s[0] = toupper(s[0]);
}
void strlwr(char *s)
{
for (; s[0]; ++s)
if ((s[0] >= 0x41) || (s[0] <= 0x5A))
s[0] = tolower(s[0]);
}
#endif
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void String::NormalizeEOL(EOLConvention to_eol)
{
switch (to_eol)
{
case EOLUnix:
{
uint invalid_eol_count = 0;
for (char *p = _p.c_ptr(); p[0] && p[1]; ++p)
if ((p[0] == '\r') && (p[1] == '\n'))
{
++invalid_eol_count;
++p;
}
Array <char> _o(Size() - invalid_eol_count + 1); // remove 1 byte per invalid EOL
char *o = _o.c_ptr(), *p = _p.c_ptr();
for ( ; p[0] && p[1]; ++p)
if ((p[0] == '\r') && (p[1] == '\n'))
{
*o++ = '\n';
++p;
}
else
*o++ = p[0];
if (p[0] != 0)
*o++ = *p++;
*o = 0;
_p.Transfer(_o);
}
break;
case EOLWindows:
{
uint invalid_eol_count = 0;
char *p = _p.c_ptr();
for (int n = 0; p[n]; ++n)
if ((p[n] == '\n') && ((n > 0) && (p[n - 1] != '\r')))
++invalid_eol_count;
Array <char> _o(Size() + invalid_eol_count + 1); // add 1 byte per invalid EOL
char *o = _o.c_ptr();
p = _p.c_ptr();
for (int n = 0; p[n]; ++n)
if ((p[n] == '\n') && ((n > 0) && (p[n - 1] != '\r')))
{
*o++ = '\r';
*o++ = '\n';
}
else
*o++ = p[n];
*o = 0;
_p.Transfer(_o);
}
break;
}
Touch();
}
String String::NormalizedEOL(EOLConvention to_eol) const
{
String o(*this);
o.NormalizeEOL(to_eol);
return o;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
uint String::Len() const
{
if (len == -1)
(const_cast <int &> (len)) = _p.IsValid() ? strlen(_p) : 0;
return len;
}
size_t String::Size() const
{
size_t size = 0;
for (char *p = _p; p[0]; ++p)
++size;
return size;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
String String::RewritePatternAll(const char *p, const char *pattern, RewriteFunc &rewrite_func)
{
String out;
forever
{
const char *s, *e;
s = String::LocatePattern(p, pattern, &e);
if (!s)
{
// append reminder
out += String(p, p + String::strlen(p));
break;
}
// append skipped segment
out += String(p, s);
// extract args...
List <String> args;
String source(s, e);
if (!source.Extract(pattern, args))
break;
// ...do rewrite.
out += rewrite_func(source, args);
p = e;
}
return out;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool String::Extract(const char *format, List <String> &arg)
{
arg.Clear();
const char *o = format;
for (const char *i = c_str(); i[0] && o[0]; )
{
if (o[0] == '%')
{
++o;
// get arg value
const char *e = i;
for (; (e[0] != o[0]) && e[0]; ++e);
arg.Add(String(i, e));
i = e;
}
else
{
if (i[0] != o[0])
{
// ignore character mismatch on space
if (i[0] == ' ')
{
++i;
continue;
}
// source format mismatch
return false;
}
++i;
++o;
}
}
return true;
}
const char *String::LocatePattern(const char *s, const char *format, const char **e)
{
for (; s[0]; ++s)
{
const char *o = format;
if (s[0] != o[0])
continue;
const char *i = s;
while (i[0] && o[0])
{
if (o[0] == '%')
{
++o;
for (; (i[0] != o[0]) && i[0]; ++i);
}
else
{
if (i[0] != o[0])
{
// ignore character mismatch on space
if (i[0] == ' ')
{
++i;
continue;
}
// source format mismatch
o = NULL;
break;
}
++i;
++o;
}
}
if (o == NULL)
continue;
if (e)
*e = i;
return s;
}
return NULL;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool String::Compare(const char *s, CaseSensitivity cs) const
{
char *p = _p.c_ptr();
if (!s)
return true;
if (!p)
return false;
if (cs == CaseSensitive)
{
while (*p && *s)
if (*p++ != *s++)
return false;
}
else
{
while (*p && *s)
if (__lowercase(*p++) != __lowercase(*s++))
return false;
}
return p[0] == s[0];
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool String::StartsWith(const char *b, CaseSensitivity cs) const
{
uint b_len = strlen(b);
if (b_len > Len())
return false;
return c_str() ? Left(b_len).Compare(b, cs) : false;
}
bool String::EndsWith(const char *b, CaseSensitivity cs) const
{
uint b_len = strlen(b);
if (b_len > Len())
return false;
return c_str() ? Right(b_len).Compare(b, cs) : false;
}
bool String::Contains(const char *b, CaseSensitivity cs) const
{ return c_str() ? asbool(FindString(b, cs)) : false; }
bool String::Replace(const char *what, const char *by, CaseSensitivity cs)
{
char *sp = _p.c_ptr() ? FindString(what, 0, cs) : NULL;
if (!sp)
return false;
uint what_len = strlen(what),
by_len = strlen(by);
uint final_len = Len() - what_len + by_len;
Array <char> np(final_len + 1, Alloc::StringBuffer);
char *wp = np;
if (np.IsNull())
return false;
memcpy(wp, _p.c_ptr(), sp - _p.c_ptr());
wp += sp - _p;
memcpy(wp, by, by_len);
wp += by_len;
memcpy(wp, sp + what_len, (_p + Len()) - (sp + what_len) + 1);
Clear();
_p = np;
return true;
}
bool String::ReplaceAll(const char **what, const char **by, bool match_whole_word)
{
if (!_p)
return false; // no replace
uint final_len = Len();
Array <char> p_out(Alloc::StringBuffer);
char *_p_out = NULL;
for (uint p = 0; p < 2; ++p)
{
bool has_replacement = false;
for (char *c_p = _p; *c_p; )
{
// Search for a match.
uint n;
for (n = 0; what[n] && by[n]; ++n)
if (!strccmp(c_p, what[n]))
break;
if (what[n] && by[n])
{
// Got a match.
size_t what_len = strlen(what[n]),
by_len = strlen(by[n]);
// Check whole word constraint.
bool do_replace = true;
if (match_whole_word)
{
if ((c_p > _p) && __isValidSymbolCharacter(c_p[-1]))
do_replace = false;
else
if (c_p[what_len] && __isValidSymbolCharacter(c_p[what_len]))
do_replace = false;
}
if (do_replace)
{
if (_p_out)
{
strncpy(_p_out, by[n], by_len);
_p_out += by_len;
}
else
final_len += by_len - what_len;
has_replacement = true;
}
else
if (_p_out)
{
strncpy(_p_out, c_p, what_len);
_p_out += what_len;
}
c_p += what_len;
}
else
{
if (_p_out)
*_p_out++ = *c_p;
++c_p;
}
}
if (!has_replacement)
return false; // no replace
if (!_p_out)
{
p_out.Allocate(final_len + 1);
_p_out = p_out;
}
}
// Commit modified buffer to string.
Clear();
p_out[final_len] = 0;
_p = p_out;
len = final_len;
hash = 0;
return true;
}
bool String::ReplaceAll(const char *what, const char *by, bool match_whole_word)
{
const char *_what[] = { what, NULL }, *_by[] = { by, NULL };
return ReplaceAll(_what, _by, match_whole_word);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
size_t String::Utf8toUtf32(const uchar *utf8, uint *utf32)
{
__ASSERT__(utf8);
__ASSERT__(utf32);
const uchar *p = utf8;
int length = GetUtf8CharSize(utf8);
switch (length)
{
case 4: *utf32 = (*p ^ 0xf0); break;
case 3: *utf32 = (*p ^ 0xe0); break;
case 2: *utf32 = (*p ^ 0xc0); break;
case 1: *utf32 = *p; break;
default:
*utf32 = 0;
break;
}
for (int n = length; n > 1; --n)
{
++p;
*utf32 <<= 6;
*utf32 |= (*p ^ 0x80);
}
return length;
}
size_t String::GetUtf8CharSize(const uchar *utf8)
{
__ASSERT__(utf8);
uchar c = utf8[0] >> 3;
// 6 => 0x7e
// 5 => 0x3e
if (c == 0x1e)
return 4;
c >>= 1;
if (c == 0xe)
return 3;
c >>= 1;
if (c == 0x6)
return 2;
return 1;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
String String::FromUcs2(const ushort *ucs2)
{
Array <char> out(256);
size_t out_count = 0;
for (uint n = 0; ucs2[n]; ++n)
{
wchar_t w = ucs2[n];
if (out_count > (out.GetCount() - 4))
out.Reallocate(out.GetCount() * 2);
if (w <= 0x7f)
out[(int)out_count++] = (char)w;
else if (w <= 0x7ff)
{
out[(int)out_count++] = 0xc0 | ((w >> 6) & 0x1f);
out[(int)out_count++] = 0x80 | (w & 0x3f);
}
else /* if (w <= 0xffff) */
{
out[(int)out_count++] = 0xe0 | ((w >> 12) & 0x0f);
out[(int)out_count++] = 0x80 | ((w >> 6) & 0x3f);
out[(int)out_count++] = 0x80 | (w & 0x3f);
}
/* else if (w <= 0x10ffff)
{
out[out_count++] = 0xf0 | ((w >> 18) & 0x07);
out[out_count++] = 0x80 | ((w >> 12) & 0x3f);
out[out_count++] = 0x80 | ((w >> 6) & 0x3f);
out[out_count++] = 0x80 | (w & 0x3f);
}
else
out[out_count++] = '?'; */
}
return String(out.c_ptr(), out.c_ptr() + out_count);
}
Array <ushort> String::toUcs2() const
{
if (!_p)
return Array <ushort> (Alloc::StringBuffer);
// Get utf-8 character count.
int ccount = 0;
char *p = _p;
for (; p[0]; ++ccount)
p += GetUtf8CharSize((const uchar *)p);
// Allocate array.
Array <ushort> ucs2(ccount + 1, Alloc::StringBuffer);
p = _p;
for (ccount = 0; p[0]; ++ccount)
{
uint utf32;
p += Utf8toUtf32((const uchar *)p, &utf32);
ucs2[ccount] = utf32 & 0xffff;
}
ucs2[ccount] = 0;
return ucs2;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool String::IsAbsolutePath() const
{ return asbool((Len() > 2) && (c_str()[1] == ':')); }
String String::BeautifyFileName(bool allow_spaces) const
{
if (!_p)
return String();
Array <char> p(Len() + 1, Alloc::StringBuffer);
strncpy(p.c_ptr(), c_str(), Len() + 1);
for (uint n = 0; n < Len(); ++n)
{
if (p[n] == ' ')
{
if (!allow_spaces)
p[n] = '_';
}
else
{
if (p[n] == '_')
p[n] = ' ';
else
{
if (n > 0)
{
if ((p[n - 1] == ' ') && (p[n] >= 'a') && (p[n] <= 'z'))
p[n] += 'A' - 'a';
}
else
if ((p[n] >= 'a') && (p[n] <= 'z'))
p[n] += 'A' - 'a';
}
}
}
return String(&p[0]);
}
String String::CutFilePath() const
{
String b = *this;
b.FileCutPath();
return b;
}
String String::CutFileExtension() const
{
String b = *this;
b.FileCutExtension();
return b;
}
String String::CutFileName() const
{
String b = *this;
b.FileCutName();
return b;
}
String String::CleanFilePath() const
{
String b = *this;
b.FileCleanName();
return b;
}
String String::GetFileName() const
{
String b = *this;
b.FileCutPathAndExtension();
return b;
}
String String::GetFileNameAndExtension() const
{
String b = *this;
b.FileCutPath();
return b;
}
String String::GetFilePath() const
{
String b = *this;
b.FileCutName();
return b;
}
String String::GetFileExtension() const
{ return FileGetExtension(c_str()); }
String String::GetSwappedExtension(const char *ext) const
{
String b = *this;
b.FileSwapExtension(ext);
return b;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
int String::Compare(const String &c, const String &n)
{
const char *a = c.c_str(), *b = n.c_str();
if (!a || !b)
return a == b ? 0 : 1;
while (a[0] || b[0])
{
if (!b[0]) return -1;
if (!a[0]) return 1;
if (b[0] < a[0]) return -1;
if (b[0] > a[0]) return 1;
a++;
b++;
}
return 0;
}
String String::Upper() const
{
String s(_p);
if (!s.IsEmpty())
strupr(s._p);
s.Touch();
return s;
}
String String::Lower() const
{
String s(_p);
if (!s.IsEmpty())
strlwr(s._p);
s.Touch();
return s;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
String String::Slice(uint s, uint e) const
{
if (s > Len()) s = Len();
if (e > Len()) e = Len();
return String(_p + s, _p + e);
}
String String::TrimChar(char c)
{
int occurence = 0;
for (char *p = _p; p[0]; p++)
if (p[0] == c)
occurence++;
if (!occurence)
return *this;
// Trim character occurrences.
Array <char> new_string(Len() - occurence + 1, Alloc::StringBuffer);
char *pnew_string = &new_string[0];
for (char *p = _p; p[0]; p++)
if (p[0] != c)
*pnew_string++ = p[0];
pnew_string[0] = 0;
return String(&new_string[0]);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
size_t String::IndexOf(char c, uint p) const
{
for (size_t n = p; n < Len(); ++n)
if (_p[(int)n] == c)
return n;
return (size_t)-1;
}
char *String::FindString(const char *c, uint p, CaseSensitivity cs) const
{
size_t len_c = strlen(c);
if (len_c <= Len())
for (size_t n = p; n <= (Len() - len_c); ++n)
{
size_t i = 0;
switch (cs)
{
case CaseSensitive:
for (; i < len_c; ++i)
if (_p[(int)(n + i)] != c[i])
break;
break;
case CaseInsensitive:
for (; i < len_c; ++i)
if (__lowercase(_p[(int)(n + i)]) != __lowercase(c[i]))
break;
break;
}
if (i == len_c)
return &_p[(int)n]; // match
}
return NULL;
}
String String::Left(uint n) const
{ return String(_p, _p + Types::Min(n, Len())); }
String String::Right(uint n) const
{
const uint l = Len();
return String(_p + Types::Min(n, l), _p + l);
}
String String::Mid(uint p, int n) const
{
uint l = Len();
p = Types::Min(p, l);
int char_left = int(l) - int(p);
n = (n < 0) || (n > char_left) ? char_left : n;
return String(_p + p, _p + p + n);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
String String::Format(const char *format, ...)
{
char static_buffer[4096];
va_list varg;
va_start(varg, format);
vsnprintf(static_buffer, 4095, format, varg);
va_end(varg);
return String(static_buffer);
}
String String::operator + (const char *_ptr) const
{
String _s = *this;
_s += _ptr;
return _s;
}
String String::operator + (const String &s) const
{
String _s = *this;
_s += s.c_str();
return _s;
}
void String::operator += (const char *_ptr)
{
if (!_ptr)
return;
if (_p.IsNull())
*this = _ptr;
else
{
size_t in_len = strlen(_ptr), total_len = Len() + in_len;
if ((total_len + 1) <= _p.GetCount())
{
memcpy(&_p[Len()], _ptr, in_len);
_p[(int)total_len] = 0;
Touch();
}
else
{
Array <char> n_p(total_len + 1, Alloc::StringBuffer);
if (n_p.IsValid())
{
memcpy(&n_p[0], c_str(), Len());
memcpy(&n_p[Len()], _ptr, in_len);
n_p[(int)total_len] = 0;
_p.Transfer(n_p);
Touch();
}
else
Clear();
}
}
}
void String::operator += (float v)
{
char tmp[32];
_snprintf(tmp, 31, "%.4f", v);
*this += tmp;
}
void String::operator += (double v)
{
char tmp[32];
_snprintf(tmp, 31, "%.4f", v);
*this += tmp;
}
void String::operator += (int v)
{
char tmp[32];
_snprintf(tmp, 31, "%d", v);
*this += tmp;
}
void String::operator += (uint v)
{
char tmp[32];
_snprintf(tmp, 31, "%d", (int)v);
*this += tmp;
}
void String::operator += (bool v)
{ *this += v ? "true" : "false"; }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
String &String::operator = (const String &b)
{
if (b.IsEmpty())
Clear();
else
{
Set(b.c_str(), b.c_str() + b.Len());
hash = b.hash;
len = b.len;
}
return *this;
}
String &String::operator = (const char *s)
{
Set(s);
return *this;
}
void String::Set(const char *s, const char *e)
{
// TODO properly handle copying one part of a string to itself.
if (s == _p)
return;
size_t new_len = s ? (e ? e - s : strlen(s)) : 0;
if (new_len > 0)
{
if ((new_len + 1) > _p.GetCount())
{
Clear();
_p.Allocate(new_len + 8); // Note: +8 to help reduce allocator pressure on string concatenation.
}
if (_p.IsValid())
{
memcpy(_p, s, new_len);
_p[(int)new_len] = 0;
Touch();
}
else
Clear();
}
else
Clear();
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
String &String::operator << (const String &v)
{ *this += v; return *this; }
String &String::operator << (const char *v)
{ *this += v; return *this; }
String &String::operator << (float v)
{ *this += v; return *this; }
String &String::operator << (double v)
{ *this += v; return *this; }
String &String::operator << (int v)
{ *this += v; return *this; }
String &String::operator << (uint v)
{ *this += v; return *this; }
String &String::operator << (bool v)
{ *this += v ? "true" : "false"; return *this; }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
int String::atoh(const char *_sr)
{
ushort p = 0, s = 0;
int v = 0;
char str[32];
strncpy(str, _sr, 8);
str[8] = 0;
strlwr(str);
while (str[p])
{
if ((str[p] == 'x') || (str[p] == 'h'))
{
s = (ushort)(p + 1);
break;
}
p++;
}
while (str[s])
{
v *= 16;
if ((str[s] >= '0') && (str[s] <= '9'))
v += str[s] - '0';
else if ((str[s] >= 'a') && (str[s] <= 'f'))
v += str[s] - 'a' + 10;
s++;
}
return v;
}
int String::atoi(const char *p)
{
char sign = 1;
if (p[0] == '-')
{
sign = -1;
p++;
}
int integer = 0;
while ((p[0] >= '0') && (p[0] <= '9'))
{
integer *= 10;
integer += *p++ - '0';
}
return (integer * sign);
}
float String::atof(const char *s, const char *e, bool support_comma)
{
if (!s)
return 0.f;
if (!e)
e = s + strlen(s);
float sign = 1;
if (s == e)
return 0.f;
if (s[0] == '-')
{
sign = -1;
s++;
}
if (s == e)
return -0.f;
float tt = 1.f;
float real = 0.f;
float integer = 0.f;
while ((s < e) && (s[0] != '.') && ((s[0] != ',') || !support_comma))
{
if (s[0] == 'e')
goto exponent;
if ((s[0] < '0') || (s[0] > '9'))
return (float)(integer * sign);
integer *= 10.f;
integer += *s++ - '0';
}
if (s == e)
return (float)(integer * sign);
s++;
while ((s < e) && (s[0] != 'e'))
{
if ((s[0] != '-') && ((s[0] < '0') || (s[0] > '9')))
return sign * (integer + (float)real / tt);
real *= 10.f;
real += *s++ - '0';
tt *= 10.f;
}
if (s == e)
return sign * (integer + real / tt);
exponent:;
s++;
if (s == e)
return (float)(integer * sign);
int expsign = (*s++ == '-') ? -1 : 1;
if (s == e)
return (float)(integer * sign);
uint exp = 0;
float mulexp = 1;
while ((s < e) && (s[0] >= '0') && (s[0] <= '9'))
{
exp *= 10;
exp += *s++ - '0';
}
for (uint expc = 0; expc < exp; expc++)
mulexp *= 10.f;
if (expsign == -1)
return (float)(sign * (integer + (float)real / tt)) / mulexp;
return (float)(sign * (integer + (float)real / tt)) * mulexp;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool String::FileCleanName()
{
if (!_p)
return false;
char *f = _p;
Array <char> n(Len() + 1, Alloc::StringBuffer);
if (n.IsNull())
return false;
// Remove drive letter case under the Windows platform.
#if __PLATFORM_WINDOWS__
if ((Len() > 2) && (f[1] == ':'))
if ((f[0] >= 'A') && (f[0] <= 'Z'))
f[0] += 'a' - 'A';
#endif
// Convert directory separator from backslash to forward slash.
char *c = n;
for (; f[0]; ++f)
if (f[0] == '\\')
f[0] = '/';
// Remove redundant forward slashes.
f = _p;
while (f[0])
{
if (f[0] == '/')
{
f++;
while (f[0] && (f[0] == '/'))
f++;
*c++ = '/';
}
else
*c++ = *f++;
}
c[0] = 0;
// Replace illegal characters.
f = n;
#if __PLATFORM_WINDOWS__
if (!strcmp(f, "file:/"))
f += 6;
#endif
if (f[0] == '@') // Allow internal mount points.
f++;
for (int i = 0; f[i]; )
{
uint char_size = GetUtf8CharSize((const uchar *)&f[i]);
if (char_size == 1)
if (
// Allowed ranges.
!((f[i] >= 'a') && (f[i] <= 'z')) &&
!((f[i] >= 'A') && (f[i] <= 'Z')) &&
!((f[i] >= '0') && (f[i] <= '9')) &&
// Allowed characters.
(f[i] != ' ') && (f[i] != '.') && (f[i] != '_') && (f[i] != '/') &&
(f[i] != '-') && (f[i] != '!') && (f[i] != '+') && (f[i] != '(') &&
(f[i] != ')') && (f[i] != '#') && (f[i] != '\'') && (f[i] != '&')
// Windows drive letter.
#if __PLATFORM_WINDOWS__
&& !((f[i] == ':') && (i == 1))
#endif
)
f[i] = '_';
i += char_size;
}
// Now commit.
Clear();
_p = n;
Touch();
return true;
}
String String::FileGetExtension(const char *path)
{
if (!path)
return "";
int n = (int)strlen(path);
while (path[n] != '.' && (n >= 0))
n--;
return n < 0 ? "" : &path[n + 1];
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
size_t String::strlen(const char *s)
{
size_t n = 0;
if (s)
for ( ; s[n]; ++n);
return n;
}
bool String::strccmp(const char *sa, const char *sb)
{
if (!sa || !sb)
return false;
while (sa[0] && sb[0])
if (*sa++ != *sb++)
return true;
return false;
}
char *String::strfindchar(const char *f, const char c, const char *t)
{
if (t)
while (f[0] && (f[0] != c) && (f < t))
f++;
else
while (f[0] && (f[0] != c))
f++;
return const_cast <char *> (f);
}
void String::rmname(char *s)
{
if (!s)
return;
int n = (int)strlen(s) - 1;
while ((n >= 0) && (s[n] != ':') && (s[n] != '\\') && (s[n] != '/'))
n--;
if (n < 0)
s[0] = 0;
else
if (s[n + 1])
s[n + 1] = 0;
}
void String::rmpath(char *s)
{
String tmp(s);
int n = (int)tmp.Len();
const char *p = tmp.c_str();
if (!p)
return;
while ((n >= 0) && (p[n] != '\\') && (p[n] != '/'))
n--;
if (n < 0)
return;
strcpy(s, &p[n+1]);
}
void String::rmext(char *s)
{
if (!s)
return;
int n = (int)strlen(s) - 1;
while ((n >= 0) && (s[n] != '.'))
{
if ((s[n] == '\\') || (s[n] == '/') || (s[n] == ':'))
break;
n--;
}
if (n < 0)
return;
s[n] = 0;
}
void String::rmpathext(char *s)
{
rmpath(s);
rmext(s);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool String::Allocate(uint size)
{
Touch();
if (!_p.Allocate(size + 1))
return false;
Memory::Set(_p.c_ptr(), 0, _p.GetSize());
return true;
}
void String::Touch()
{
len = -1;
hash = 0;
}
void String::Clear()
{
_p.Free();
Touch();
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool String::equals(const char *s, const uint hash) const
{
if (hash && (hash != Hash()))
return false;
if (_p == s)
return true;
return (_p && !strcmp(s, _p)) ? true : false;
}
bool String::operator == (const String &b) const
{ return b.IsEmpty() ? IsEmpty() : equals(b, b.Hash()); }
bool String::operator == (const char *s) const
{ return s ? equals(s) : IsEmpty(); }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool String::operator != (const String &b) const
{ return !(*this == b); }
bool String::operator != (const char *s) const
{ return !(*this == s); }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void String::operator += (const String &b)
{
if (!b.IsEmpty())
*this += b.c_str();
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
uint String::strhash(const char *s)
{
uint hash = 0;
if (s)
while (s[0])
{
hash = hash * 37 + s[0];
s++;
}
hash |= 1;
return hash;
}
uint String::Hash() const
{
if (hash == 0)
hash = strhash(_p);
return hash;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void String::FileCutPath()
{ rmpath(_p); Touch(); }
void String::FileSwapExtension(const char *ext)
{ rmext(_p); Touch(); *this += ext; }
void String::FileCutExtension()
{ rmext(_p); Touch(); }
void String::FileCutPathAndExtension()
{ rmpathext(_p); Touch(); }
void String::FileCutName()
{ rmname(_p); Touch(); }
//------------------------------------------------------------------------------