Cemu/src/util/helpers/StringParser.h
2022-08-22 22:21:23 +02:00

252 lines
4.4 KiB
C++

#pragma once
class StringTokenParser
{
public:
StringTokenParser() : m_str(nullptr), m_len(0) {};
StringTokenParser(const char* input, sint32 inputLen) : m_str(input), m_len(inputLen) {};
StringTokenParser(std::string_view str) : m_str(str.data()), m_len((sint32)str.size()) {};
// skip whitespaces at current ptr position
void skipWhitespaces()
{
m_str = _skipWhitespaces(m_str, m_len);
}
// decrease string length as long as there is a whitespace at the end
void trimWhitespaces()
{
while (m_len > 0)
{
const char c = m_str[m_len - 1];
if (c != ' ' && c != '\t')
break;
m_len--;
}
}
bool isEndOfString()
{
return m_len <= 0;
}
sint32 skipToCharacter(const char c)
{
auto str = m_str;
auto len = m_len;
sint32 idx = 0;
while (len > 0)
{
if (*str == c)
{
m_str = str;
m_len = len;
return idx;
}
len--;
str++;
idx++;
}
return -1;
}
bool matchWordI(const char* word)
{
auto str = m_str;
auto length = m_len;
str = _skipWhitespaces(str, length);
for (sint32 i = 0; i <= length; i++)
{
if (word[i] == '\0')
{
m_str = str + i;
m_len = length - i;
return true;
}
if (i == length)
return false;
char c1 = str[i];
char c2 = word[i];
c1 = _toUpperCase(c1);
c2 = _toUpperCase(c2);
if (c1 != c2)
return false;
}
return false;
}
bool compareCharacter(sint32 relativeIndex, const char c)
{
if (relativeIndex >= m_len)
return false;
return m_str[relativeIndex] == c;
}
bool compareCharacterI(sint32 relativeIndex, const char c)
{
if (relativeIndex >= m_len)
return false;
return _toUpperCase(m_str[relativeIndex]) == _toUpperCase(c);
}
void skipCharacters(sint32 count)
{
if (count > m_len)
count = m_len;
m_str += count;
m_len -= count;
}
bool parseU32(uint32& val)
{
auto str = m_str;
auto length = m_len;
str = _skipWhitespaces(str, length);
uint32 value = 0;
sint32 index = 0;
bool isHex = false;
if (length <= 0)
return false;
if (length >= 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
{
isHex = true;
index += 2;
}
else if (str[index] == '0')
{
isHex = true;
index++;
}
if (length <= index)
return false;
if (isHex)
{
sint32 firstDigitIndex = index;
for (; index < length; index++)
{
const char c = str[index];
if (c >= '0' && c <= '9')
{
value *= 0x10;
value += (c - '0');
}
else if (c >= 'a' && c <= 'f')
{
value *= 0x10;
value += (c - 'a' + 10);
}
else if (c >= 'A' && c <= 'F')
{
value *= 0x10;
value += (c - 'A' + 10);
}
else
break;
}
if (index == firstDigitIndex)
return false;
m_str = str + index;
m_len = length - index;
}
else
{
sint32 firstDigitIndex = index;
for (; index < length; index++)
{
const char c = str[index];
if (c >= '0' && c <= '9')
{
value *= 10;
value += (c - '0');
}
else
break;
}
if (index == firstDigitIndex)
return false;
m_str = str + index;
m_len = length - index;
}
val = value;
return true;
}
bool parseSymbolName(const char*& symbolStr, sint32& symbolLength)
{
auto str = m_str;
auto length = m_len;
str = _skipWhitespaces(str, length);
// symbols must start with a letter or _
if (length <= 0)
return false;
if (!(str[0] >= 'a' && str[0] <= 'z') &&
!(str[0] >= 'A' && str[0] <= 'Z') &&
!(str[0] == '_'))
return false;
sint32 idx = 1;
while (idx < length)
{
const char c = str[idx];
if (!(c >= 'a' && c <= 'z') &&
!(c >= 'A' && c <= 'Z') &&
!(c >= '0' && c <= '9') &&
!(c == '_') && !(c == '.'))
break;
idx++;
}
symbolStr = str;
symbolLength = idx;
m_str = str + idx;
m_len = length - idx;
return true;
}
const char* getCurrentPtr()
{
return m_str;
}
sint32 getCurrentLen()
{
return m_len;
}
void storeParserState(StringTokenParser* bak)
{
bak->m_str = m_str;
bak->m_len = m_len;
}
void restoreParserState(const StringTokenParser* bak)
{
m_str = bak->m_str;
m_len = bak->m_len;
}
private:
const char* _skipWhitespaces(const char* str, sint32& length)
{
while (length > 0)
{
if (*str != ' ' && *str != '\t')
break;
str++;
length--;
}
return str;
}
char _toUpperCase(const char c)
{
if (c >= 'a' && c <= 'z')
return c + ('A' - 'a');
return c;
}
private:
const char* m_str;
sint32 m_len;
};