#include "pch.h"
ZString::ZStringData::ZStringData(PCC pcc)
{
m_length = pcc ? strlen(pcc) : 0;
m_pch = new char[m_length + 1];
m_pcc = m_pch;
memcpy(m_pch, pcc ? pcc : "", m_length + 1);
}
ZString::ZStringData::ZStringData(PCC pcc, bool bStatic)
{
ZAssert(bStatic);
m_length = strlen(pcc);
m_pch = NULL;
m_pcc = pcc;
}
ZString::ZStringData::ZStringData(PCC pcc, int length)
{
m_length = length;
m_pch = new char[m_length + 1];
m_pcc = m_pch;
memcpy(m_pch, pcc, m_length);
m_pch[m_length] = 0;
}
ZString::ZStringData::ZStringData(char ch, int length)
{
m_length = length;
m_pch = new char[m_length + 1];
m_pcc = m_pch;
memset(m_pch, ch, m_length);
m_pch[m_length] = 0;
}
ZString::ZStringData::ZStringData(const ZStringData* pdata1, const ZStringData* pdata2) :
m_length(pdata1->GetLength() + pdata2->GetLength())
{
m_pch = new char[m_length + 1];
m_pcc = m_pch;
memcpy(m_pch, pdata1->m_pcc, pdata1->GetLength());
memcpy(m_pch + pdata1->m_length, pdata2->m_pcc, pdata2->GetLength() + 1);
}
ZString::ZStringData::~ZStringData()
{
if (m_pch) {
delete[] m_pch;
}
}
void ZString::ZStringData::Set(int index, char ch)
{
ZAssert(
m_pch != NULL
&& index < m_length
&& GetCount() == 1
);
m_pch[index] = ch;
}
int ZString::ZStringData::Find(const ZStringData* pdata) const
{
int index2;
for(int index = 0; index < m_length - pdata->m_length + 1; index++) {
for (index2 = 0; index2 < pdata->m_length; index2++) {
if (m_pcc[index + index2] != pdata->m_pcc[index2]) {
break;
}
}
if (index2 == pdata->m_length) {
return index;
}
}
return -1;
}
int ZString::ZStringData::ReverseFind(const ZStringData* pdata) const
{
int index2;
for(int index = m_length - pdata->m_length + 1; index >=0 ; index--) {
for (index2 = 0; index2 < pdata->m_length; index2++) {
if (m_pcc[index + index2] != pdata->m_pcc[index2]) {
break;
}
}
if (index2 == pdata->m_length) {
return index;
}
}
return -1;
}
int ZString::ZStringData::Find(char ch, int index) const
{
for(; index < m_length; index++) {
if (m_pcc[index] == ch) {
return index;
}
}
return -1;
}
int ZString::ZStringData::ReverseFind(char ch, int index) const
{
index = m_length - index;
for(; index >= 0; index--) {
if (m_pcc[index] == ch) {
return index;
}
}
return -1;
}
int ZString::ZStringData::FindAny(const ZStringData* pdata, int index) const
{
int length = pdata->GetLength();
for(; index < m_length; index++) {
for (int index2 = 0; index2 < length; index2++) {
if (m_pcc[index] == pdata->m_pcc[index2]) {
return index;
}
}
}
return -1;
}
int ZString::ZStringData::ReverseFindAny(const ZStringData* pdata, int index) const
{
int length = pdata->GetLength();
index = m_length - index;
for(; index >= 0; index--) {
for (int index2 = 0; index2 < length; index2++) {
if (m_pcc[index] == pdata->m_pcc[index2]) {
return index;
}
}
}
return -1;
}
TRef<ZString::ZStringData> ZString::s_pemptyData = new ZString::ZStringData("", true);
ZString::ZString() :
m_pdata(s_pemptyData)
{
}
ZString::ZString(PCC pcc) :
m_pdata(new ZStringData(pcc))
{
}
ZString::ZString(PCC pcc, bool bStatic) :
m_pdata(new ZStringData(pcc, bStatic))
{
}
ZString::ZString(PCC pcc, int length)
{
if (length == 0) {
m_pdata = s_pemptyData;
} else {
m_pdata = new ZStringData(pcc, length);
}
}
ZString::ZString(char ch, int length)
{
if (length == 0) {
m_pdata = s_pemptyData;
} else {
m_pdata = new ZStringData(ch, length);
}
}
ZString::ZString(PCC pcc, int length, bool bStatic)
{
if (length == 0) {
m_pdata = s_pemptyData;
} else {
m_pdata = new ZStringData(pcc, length);
}
}
ZString::ZString(const ZString& str) :
m_pdata(str.m_pdata)
{
}
ZString::ZString(ZStringData* pdata) :
m_pdata(pdata)
{
}
ZString::ZString(int value)
{
char buf[32];
_itoa_s(value,buf,32,10);
m_pdata = new ZStringData(buf);
}
ZString::ZString(float value, int total, int precision)
{
char format[32];
char buf[32];
sprintf_s(format, 32, "%%%d.%df", total, precision);
sprintf_s(buf, 32, format, value);
m_pdata = new ZStringData(buf);
}
ZString::ZString(float value)
{
#ifndef DREAMCAST
char buf[32];
sprintf_s(buf, 32, "%g", value);
m_pdata = new ZStringData(buf);
#else
int decimal, sign;
char *buffer;
buffer = _fcvt( value, 7, &decimal, &sign );
m_pdata = new ZStringData(buffer);
#endif
}
ZString::ZString(bool b)
{
if (b) {
m_pdata = new ZStringData("true");
} else {
m_pdata = new ZStringData("false");
}
}
ZString operator+(const ZString& str1, const ZString& str2)
{
return ZString(new ZString::ZStringData(str1.m_pdata, str2.m_pdata));
}
ZString ZString::GetProfileString(const ZString& strSection, const ZString& strKey)
{
char buf[256];
DWORD dw = ::GetProfileString(strSection, strKey, "", buf, 256);
return ZString(buf, (int)dw);
}
void ZString::UniqueData()
{
if (m_pdata->GetCount() != 1) {
m_pdata = new ZStringData(m_pdata->GetPointer());
}
}
void ZString::SetEmpty()
{
m_pdata = s_pemptyData;
}
void ZString::Set(int index, char ch)
{
if (index < GetLength()) {
if (m_pdata->GetPointer()[index] != ch) {
UniqueData();
m_pdata->Set(index, ch);
}
}
}
ZString& ZString::operator+=(const ZString& str)
{
m_pdata = new ZStringData(m_pdata, str.m_pdata);
return *this;
}
ZString& ZString::operator=(const ZString& str)
{
m_pdata = str.m_pdata;
return *this;
}
void ZString::ReplaceAll(const ZString& str, char ch)
{
UniqueData();
int length = str.GetLength();
for(int index = 0; index < GetLength(); index++) {
for (int index2 = 0; index2 < length; index2++) {
if (m_pdata->GetPointer()[index] == str[index2]) {
m_pdata->Set(index, ch);
break;
}
}
}
}
void ZString::RemoveAll(char chToRemove)
{
int length = GetLength();
char* cbNew = (char*)_alloca(length + 1);
int nLengthNew = 0;
for (int indexOld = 0; indexOld < GetLength(); indexOld++) {
char chCurrent = m_pdata->GetPointer()[indexOld];
if (chCurrent != chToRemove) {
cbNew[nLengthNew] = chCurrent;
++nLengthNew;
}
}
cbNew[nLengthNew] = '\0';
m_pdata = new ZStringData(cbNew, nLengthNew);
}
bool operator==(const ZString& str1, const ZString& str2)
{
return
str1.GetLength() == str2.GetLength()
&& (strncmp(str1, str2, str1.GetLength()) == 0);
}
bool operator==(const ZString& str, PCC pcc)
{
ZAssert(pcc != NULL);
return
str.GetLength() == (int)strlen(pcc)
&& (strncmp(str, pcc, str.GetLength()) == 0);
}
bool operator==(PCC pcc, const ZString& str)
{
ZAssert(pcc != NULL);
return
str.GetLength() == (int)strlen(pcc)
&& (strncmp(str, pcc, str.GetLength()) == 0);
}
bool operator!=(const ZString& str1, const ZString& str2)
{
return
str1.GetLength() != str2.GetLength()
|| (strncmp(str1, str2, str1.GetLength()) != 0);
}
bool operator!=(const ZString& str, PCC pcc)
{
ZAssert(pcc != NULL);
return
str.GetLength() != (int)strlen(pcc)
|| (strncmp(str, pcc, str.GetLength()) != 0);
}
bool operator!=(PCC pcc, const ZString& str)
{
ZAssert(pcc != NULL);
return
str.GetLength() != (int)strlen(pcc)
|| (strncmp(str, pcc, str.GetLength()) != 0);
}
bool operator<(const ZString& str1, const ZString& str2)
{
return strcmp(str1, str2) < 0;
}
bool operator<(const ZString& str, PCC pcc)
{
return strcmp(str, pcc) < 0;
}
bool operator<(PCC pcc, const ZString& str)
{
return strcmp(pcc, str) < 0;
}
int ZString::Find(const ZString& str) const
{
return m_pdata->Find(str.m_pdata);
}
int ZString::ReverseFind(const ZString& str) const
{
return m_pdata->Find(str.m_pdata);
}
int ZString::Find(char ch, int index) const
{
return m_pdata->Find(ch, index);
}
int ZString::ReverseFind(char ch, int index) const
{
return m_pdata->ReverseFind(ch, index);
}
int ZString::FindAny(const ZString& str, int index) const
{
return m_pdata->FindAny(str.m_pdata, index);
}
int ZString::ReverseFindAny(const ZString& str, int index) const
{
return m_pdata->ReverseFindAny(str.m_pdata, index);
}
int ZString::GetInteger() const
{
return atoi(m_pdata->GetPointer());
}
ZString ZString::Left(int index) const
{
return ZString(m_pdata->GetPointer(), index);
}
ZString ZString::Right(int index) const
{
return ZString(m_pdata->GetPointer() + GetLength() - index, index);
}
ZString ZString::Middle(int index, int length) const
{
return ZString(m_pdata->GetPointer() + index, length);
}
ZString ZString::LeftOf(int index) const
{
return Left(GetLength() - index);
}
ZString ZString::RightOf(int index) const
{
int size = GetLength() - index;
if (size > 0) {
return Right(size);
} else {
return ZString();
}
}
ZString ZString::LeftOf(const ZString& str) const
{
int index = FindAny(str);
if (index == -1) {
return str;
} else {
return Left(index);
}
}
ZString ZString::RightOf(const ZString& str) const
{
int index = FindAny(str);
if (index == -1) {
return ZString();
} else {
return Right(GetLength() - index - 1);
}
}
ZString ZString::ToLower() const
{
char* cbResult = (char*)_alloca(GetLength() + 1);
ZToLower(cbResult, (*this));
return cbResult;
}
ZString ZString::ToUpper() const
{
char* cbResult = (char*)_alloca(GetLength() + 1);
ZToUpper(cbResult, (*this));
return cbResult;
}
void ZToLower(char* szDest, PCC szSource)
{
int index;
for (index = 0; szSource[index] != '\0'; ++index) {
char ch = szSource[index];
if (ch >= 'A' && ch <= 'Z')
szDest[index] = (ch - ('A' - 'a'));
else
szDest[index] = ch;
}
szDest[index] = '\0';
}
void ZToUpper(char* szDest, PCC szSource)
{
int index;
for (index = 0; szSource[index] != '\0'; ++index) {
char ch = szSource[index];
if (ch >= 'a' && ch <= 'z')
szDest[index] = (ch - ('a' - 'A'));
else
szDest[index] = ch;
}
szDest[index] = '\0';
}
ZString ZString::GetToken()
{
ZString strToken;
int length = GetLength();
int index;
if (m_pdata->GetPointer()[0] == '"')
{
index = 1;
while (index < length && m_pdata->GetPointer()[index] != '"')
index++;
if (index < length)
strToken = Middle(1, index++ - 1);
else
strToken = *this;
}
else
{
index = 0;
while (index < length && m_pdata->GetPointer()[index] != ' ')
index++;
strToken = Left(index);
}
while (index < length && m_pdata->GetPointer()[index] == ' ')
index++;
*this = Right(length - index);
return strToken;
}
ZString FilenameString::GetExtension() const
{
return RightOf(".");
}
ZString FilenameString::GetName() const
{
int index = Find('.', 0);
if (index == -1) {
return *this;
} else {
return Left(index);
}
}
#ifdef DREAMCAST
const char* g_szDirSep = "\\";
#else
const char* g_szDirSep = "/";
#endif
PathString::PathString(PCC pcc) :
ZString(pcc)
{
#ifdef DREAMCAST
ReplaceAll("/", '\\');
#else
ReplaceAll("\\", '/');
#endif
}
PathString PathString::GetCurrentDirectory()
{
int size = ::GetCurrentDirectory(0, NULL);
char* pch = new char[size];
::GetCurrentDirectory(size, pch);
PathString str(pch);
delete pch;
return str;
}
PathString PathString::GetModulePath()
{
char ch[128];
GetModuleFileNameA(NULL, ch, sizeof(ch) / sizeof(*ch));
return PathString(ch);
}
FilenameString PathString::GetFilename() const
{
int index = ReverseFindAny("/\\:");
if (index == -1) {
return *this;
} else {
return Right(GetLength() - index - 1);
}
}
ZString PathString::GetExtension() const
{
return GetFilename().GetExtension();
}
ZString PathString::GetName() const
{
return GetFilename().GetName();
}
PathString PathString::GetDirectory() const
{
int index = ReverseFindAny("/\\:");
if (index == -1) {
return PathString();
} else {
return Left(index);
}
}
PathString PathString::GetDrive() const
{
char ch0 = (*this)[0];
char ch1 = (*this)[1];
if ( (ch0 == '/' && ch1 == '/')
|| (ch0 == '\\' && ch1 == '\\')
) {
return Left(FindAny("/\\", FindAny("/\\", 2) + 1) - 1);
} else if (ch1 == ':') {
return Left(2);
}
return PathString();
}
PathString PathString::operator+(const PathString& strRelativeArg) const
{
PathString strAbsolute = *this;
ZString strRelative = strRelativeArg;
int length = strRelative.GetLength();
char ch0 = strRelative[0];
char ch1 = length > 0 ? strRelative[1] : 0;
char ch2 = length > 1 ? strRelative[2] : 0;
if (ch0 == '/' || ch0 == '\\') {
if (ch1 == ch0) {
return strRelative;
} else {
return ZString(strAbsolute.GetDrive()) + g_szDirSep + strRelative;
}
} else if (ch1 == ':') {
if (ch2 == '/' || ch2 == '\\') {
return strRelative;
} else {
ZError("Current directory relative paths not supported.");
return strAbsolute;
}
} else {
while (true) {
ch0 = strRelative[0];
if (ch0 == '.') {
int length = strRelative.GetLength();
if (strRelative[1] == '.') {
strAbsolute = strAbsolute.GetDirectory();
strRelative = strRelative.Right(strRelative.GetLength() - 2);
} else {
strRelative = strRelative.Right(strRelative.GetLength() - 1);
}
} else {
int index = strRelative.FindAny("/\\");
if (index == -1) {
index = strRelative.GetLength();
}
char chLast = strAbsolute[strAbsolute.GetLength() - 1];
if (chLast == '/' || chLast == '\\') {
strAbsolute = ZString(strAbsolute) + strRelative.Left(index);
} else {
strAbsolute = ZString(strAbsolute) + g_szDirSep + strRelative.Left(index);
}
strRelative = strRelative.Right(strRelative.GetLength() - index);
}
ch0 = strRelative[0];
if (ch0 == '/' || ch0 == '\\') {
strRelative = strRelative.Right(strRelative.GetLength() - 1);
} else {
return strAbsolute;
}
}
}
}
static const unsigned char vcScramble[256] =
{
0, 26, 45, 66, 155, 83, 137, 133,
71, 158, 4, 128, 124, 106, 59, 32,
244, 2, 100, 193, 42, 25, 228, 76,
110, 116, 72, 163, 214, 97, 61, 11,
75, 225, 33, 10, 48, 60, 14, 8,
101, 67, 179, 7, 82, 69, 165, 152,
222, 6, 44, 23, 35, 246, 180, 120,
129, 248, 105, 55, 24, 173, 112, 234,
9, 171, 99, 27, 28, 54, 22, 135,
102, 51, 113, 18, 3, 29, 80, 191,
169, 107, 46, 73, 31, 218, 177, 34,
176, 186, 93, 36, 153, 147, 178, 160,
148, 43, 182, 84, 154, 141, 164, 77,
233, 136, 12, 103, 156, 50, 58, 223,
118, 209, 13, 119, 204, 188, 52, 41,
21, 189, 241, 151, 192, 172, 104, 57,
38, 131, 5, 91, 181, 64, 219, 39,
205, 130, 63, 94, 109, 81, 254, 255,
174, 220, 142, 161, 162, 132, 211, 49,
202, 249, 123, 114, 95, 78, 140, 74,
86, 115, 251, 15, 1, 65, 62, 231,
125, 194, 201, 40, 143, 30, 159, 96,
145, 245, 200, 56, 17, 199, 183, 16,
134, 229, 121, 87, 149, 235, 122, 92,
37, 166, 157, 215, 144, 213, 126, 89,
187, 53, 232, 212, 19, 20, 175, 210,
207, 168, 150, 203, 216, 197, 252, 68,
247, 70, 117, 138, 146, 224, 139, 190,
253, 90, 185, 238, 111, 196, 206, 167,
108, 85, 226, 221, 208, 243, 170, 195,
236, 240, 242, 79, 184, 237, 239, 47,
217, 250, 230, 98, 88, 198, 127, 227
};
static const unsigned char vcUnscramble[256] =
{
0, 164, 17, 76, 10, 130, 49, 43,
39, 64, 35, 31, 106, 114, 38, 163,
183, 180, 75, 204, 205, 120, 70, 51,
60, 21, 1, 67, 68, 77, 173, 84,
15, 34, 87, 52, 91, 192, 128, 135,
171, 119, 20, 97, 50, 2, 82, 247,
36, 151, 109, 73, 118, 201, 69, 59,
179, 127, 110, 14, 37, 30, 166, 138,
133, 165, 3, 41, 215, 45, 217, 8,
26, 83, 159, 32, 23, 103, 157, 243,
78, 141, 44, 5, 99, 233, 160, 187,
252, 199, 225, 131, 191, 90, 139, 156,
175, 29, 251, 66, 18, 40, 72, 107,
126, 58, 13, 81, 232, 140, 24, 228,
62, 74, 155, 161, 25, 218, 112, 115,
55, 186, 190, 154, 12, 168, 198, 254,
11, 56, 137, 129, 149, 7, 184, 71,
105, 6, 219, 222, 158, 101, 146, 172,
196, 176, 220, 93, 96, 188, 210, 123,
47, 92, 100, 4, 108, 194, 9, 174,
95, 147, 148, 27, 102, 46, 193, 231,
209, 80, 238, 65, 125, 61, 144, 206,
88, 86, 94, 42, 54, 132, 98, 182,
244, 226, 89, 200, 117, 121, 223, 79,
124, 19, 169, 239, 229, 213, 253, 181,
178, 170, 152, 211, 116, 136, 230, 208,
236, 113, 207, 150, 203, 197, 28, 195,
212, 248, 85, 134, 145, 235, 48, 111,
221, 33, 234, 255, 22, 185, 250, 167,
202, 104, 63, 189, 240, 245, 227, 246,
241, 122, 242, 237, 16, 177, 53, 216,
57, 153, 249, 162, 214, 224, 142, 143
};
static unsigned char ScrambleMunge(unsigned char cbStart, unsigned char cbKey)
{
unsigned char c = cbStart;
ZAssert(c != 0);
ZAssert(cbKey != 0);
int n = (int(c) + int(cbKey));
c = (unsigned char)(n - ((n <= 256) ? 1 : 256));
c = vcScramble[c];
c = (c << (cbKey & 7)) | (c >> (8 - (cbKey & 7)));
ZAssert(c != 0);
return c;
}
static unsigned char ScrambleUnmunge(unsigned char cbStart, unsigned char cbKey)
{
unsigned char c = cbStart;
ZAssert(c != 0);
ZAssert(cbKey > 0);
c = (c >> (cbKey & 7)) | (c << (8 - (cbKey & 7)));
c = vcUnscramble[c];
int n = (int(c) - int(cbKey));
c = (unsigned char)(n + ((n >= 0) ? 1 : 256));
ZAssert(c != 0);
return c;
}
const int c_cScrambleRounds = 12;
void ZScramble(char* szDest, PCC szSource, PCC szKey)
{
int length = strlen(szSource);
int lengthKey = strlen(szKey);
memcpy(szDest, szSource, length + 1);
for (int nRound = 0; nRound < c_cScrambleRounds; nRound++)
{
int index;
for (index = 0; index < length; index++)
szDest[index] = (char)(ScrambleMunge((unsigned char)szDest[index],
(unsigned char)szKey[(index + 3*nRound) % lengthKey]));
for (index = 1; index < length; index++)
szDest[index] = (char)(ScrambleMunge((unsigned char)szDest[index],
(unsigned char)szDest[index-1]));
for (index = length - 2; index >= 0; index--)
szDest[index] = (char)(ScrambleMunge((unsigned char)szDest[index],
(unsigned char)szDest[index+1]));
}
}
void ZUnscramble(char* szDest, PCC szSource, PCC szKey)
{
int length = strlen(szSource);
int lengthKey = strlen(szKey);
memcpy(szDest, szSource, length + 1);
for (int nRound = c_cScrambleRounds - 1; nRound >= 0; nRound--)
{
int index;
for (index = 0; index < length - 1; index++)
szDest[index] = (char)(ScrambleUnmunge((unsigned char)szDest[index],
(unsigned char)szDest[index+1]));
for (index = length - 1; index > 0; index--)
szDest[index] = (char)(ScrambleUnmunge((unsigned char)szDest[index],
(unsigned char)szDest[index-1]));
for (index = 0; index < length; index++)
szDest[index] = (char)(ScrambleUnmunge((unsigned char)szDest[index],
(unsigned char)szKey[(index + 3*nRound) % lengthKey]));
}
}
ZString ZString::Scramble(const ZString& strKey) const
{
char* cbResult = (char*)_alloca(GetLength() + 1);
ZScramble(cbResult, (*this), strKey);
return cbResult;
}
ZString ZString::Unscramble(const ZString& strKey) const
{
char* cbResult = (char*)_alloca(GetLength() + 1);
ZUnscramble(cbResult, (*this), strKey);
return cbResult;
}