mirror of
https://github.com/TerryCavanagh/VVVVVV.git
synced 2024-06-26 06:28:30 +02:00
next_split_s() could potentially commit out-of-bounds indexing if the amount of source data was bigger than the destination data. This is because the size of the source data passed in includes the null terminator, so if 1 byte is not subtracted from it, then after it passes through the VVV_min(), it will index 1 past the end of the passed buffer when null-terminating it. In contrast, the other argument of the VVV_min() does not need 1 subtracted from it, because that length does not include a null terminator (next_split() returns the length of the substring, after all; not the length of the substring plus 1). (The VVV_min() here also shortens the range of values to the size of an int, but we'll probably make size_t versions anyway; plus who really cares about supporting massively-sized buffers bigger than 2 billion bytes in length? That just doesn't make sense.)
338 lines
5.5 KiB
C++
338 lines
5.5 KiB
C++
#define HELP_DEFINITION
|
|
#include "UtilityClass.h"
|
|
|
|
#include <SDL.h>
|
|
#include <sstream>
|
|
|
|
#include "Maths.h"
|
|
|
|
static const char* GCChar(const SDL_GameControllerButton button)
|
|
{
|
|
switch (button)
|
|
{
|
|
case SDL_CONTROLLER_BUTTON_A:
|
|
return "A";
|
|
case SDL_CONTROLLER_BUTTON_B:
|
|
return "B";
|
|
case SDL_CONTROLLER_BUTTON_X:
|
|
return "X";
|
|
case SDL_CONTROLLER_BUTTON_Y:
|
|
return "Y";
|
|
case SDL_CONTROLLER_BUTTON_BACK:
|
|
return "BACK";
|
|
case SDL_CONTROLLER_BUTTON_GUIDE:
|
|
return "GUIDE";
|
|
case SDL_CONTROLLER_BUTTON_START:
|
|
return "START";
|
|
case SDL_CONTROLLER_BUTTON_LEFTSTICK:
|
|
return "L3";
|
|
case SDL_CONTROLLER_BUTTON_RIGHTSTICK:
|
|
return "R3";
|
|
case SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
|
|
return "LB";
|
|
case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
|
|
return "RB";
|
|
default:
|
|
SDL_assert(0 && "Unhandled button!");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
int ss_toi(const std::string& str)
|
|
{
|
|
int retval = 0;
|
|
bool negative = false;
|
|
static const int radix = 10;
|
|
|
|
for (size_t i = 0; i < str.size(); ++i)
|
|
{
|
|
const char chr = str[i];
|
|
|
|
if (i == 0 && chr == '-')
|
|
{
|
|
negative = true;
|
|
continue;
|
|
}
|
|
|
|
if (SDL_isdigit(chr))
|
|
{
|
|
retval *= radix;
|
|
retval += chr - '0';
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (negative)
|
|
{
|
|
return -retval;
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
bool next_split(
|
|
size_t* start,
|
|
size_t* len,
|
|
const char* str,
|
|
const char delim
|
|
) {
|
|
size_t idx = 0;
|
|
*len = 0;
|
|
|
|
if (str[idx] == '\0')
|
|
{
|
|
return false;
|
|
}
|
|
|
|
while (true)
|
|
{
|
|
if (str[idx] == delim)
|
|
{
|
|
*start += 1;
|
|
return true;
|
|
}
|
|
else if (str[idx] == '\0')
|
|
{
|
|
return true;
|
|
}
|
|
|
|
idx += 1;
|
|
*start += 1;
|
|
*len += 1;
|
|
}
|
|
}
|
|
|
|
bool next_split_s(
|
|
char buffer[],
|
|
const size_t buffer_size,
|
|
size_t* start,
|
|
const char* str,
|
|
const char delim
|
|
) {
|
|
size_t len = 0;
|
|
const size_t prev_start = *start;
|
|
|
|
const bool retval = next_split(start, &len, &str[*start], delim);
|
|
|
|
if (retval)
|
|
{
|
|
/* Using SDL_strlcpy() here results in calling SDL_strlen() */
|
|
/* on the whole string, which results in a visible freeze */
|
|
/* if it's a very large string */
|
|
const size_t length = VVV_min(buffer_size - 1, len);
|
|
SDL_memcpy(buffer, &str[prev_start], length);
|
|
buffer[length] = '\0';
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
UtilityClass::UtilityClass() :
|
|
glow(0),
|
|
glowdir(0)
|
|
{
|
|
for (size_t i = 0; i < SDL_arraysize(splitseconds); i++)
|
|
{
|
|
splitseconds[i] = (i * 100) / 30;
|
|
}
|
|
|
|
slowsine = 0;
|
|
}
|
|
|
|
std::string UtilityClass::String( int _v )
|
|
{
|
|
std::ostringstream os;
|
|
os << _v;
|
|
return(os.str());
|
|
}
|
|
|
|
int UtilityClass::Int(const char* str, int fallback /*= 0*/)
|
|
{
|
|
if (!is_number(str))
|
|
{
|
|
return fallback;
|
|
}
|
|
|
|
return (int) SDL_strtol(str, NULL, 0);
|
|
}
|
|
|
|
std::string UtilityClass::GCString(const std::vector<SDL_GameControllerButton>& buttons)
|
|
{
|
|
std::string retval = "";
|
|
for (size_t i = 0; i < buttons.size(); i += 1)
|
|
{
|
|
retval += GCChar(buttons[i]);
|
|
if ((i + 1) < buttons.size())
|
|
{
|
|
retval += ",";
|
|
}
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
std::string UtilityClass::twodigits( int t )
|
|
{
|
|
if (t < 10)
|
|
{
|
|
return "0" + String(t);
|
|
}
|
|
if (t >= 100)
|
|
{
|
|
return "??";
|
|
}
|
|
return String(t);
|
|
}
|
|
|
|
std::string UtilityClass::timestring( int t )
|
|
{
|
|
//given a time t in frames, return a time in seconds
|
|
std::string tempstring = "";
|
|
int temp = (t - (t % 30)) / 30;
|
|
if (temp < 60) //less than one minute
|
|
{
|
|
t = t % 30;
|
|
tempstring = String(temp) + ":" + twodigits(splitseconds[t]);
|
|
}
|
|
else
|
|
{
|
|
int temp2 = (temp - (temp % 60)) / 60;
|
|
temp = temp % 60;
|
|
t = t % 30;
|
|
tempstring = String(temp2) + ":" + twodigits(temp) + ":" + twodigits(splitseconds[t]);
|
|
}
|
|
return tempstring;
|
|
}
|
|
|
|
std::string UtilityClass::number( int _t )
|
|
{
|
|
static const std::string ones_place[] = {"One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine"};
|
|
static const std::string tens_place[] = {"Ten", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"};
|
|
static const std::string teens[] = {"Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"};
|
|
|
|
if (_t < 0)
|
|
{
|
|
return "???";
|
|
}
|
|
else if (_t > 100)
|
|
{
|
|
return "Lots";
|
|
}
|
|
else if (_t == 0)
|
|
{
|
|
return "Zero";
|
|
}
|
|
else if (_t == 100)
|
|
{
|
|
return "One Hundred";
|
|
}
|
|
else if (_t >= 1 && _t <= 9)
|
|
{
|
|
return ones_place[_t-1];
|
|
}
|
|
else if (_t >= 11 && _t <= 19)
|
|
{
|
|
return teens[_t-11];
|
|
}
|
|
else if (_t % 10 == 0)
|
|
{
|
|
return tens_place[(_t/10)-1];
|
|
}
|
|
else
|
|
{
|
|
return tens_place[(_t/10)-1] + " " + ones_place[(_t%10)-1];
|
|
}
|
|
}
|
|
|
|
bool UtilityClass::intersects( SDL_Rect A, SDL_Rect B )
|
|
{
|
|
return (SDL_HasIntersection(&A, &B) == SDL_TRUE);
|
|
}
|
|
|
|
void UtilityClass::updateglow()
|
|
{
|
|
slowsine++;
|
|
if (slowsine >= 64) slowsine = 0;
|
|
|
|
if (glowdir == 0) {
|
|
glow+=2;
|
|
if (glow >= 62) glowdir = 1;
|
|
}else {
|
|
glow-=2;
|
|
if (glow < 2) glowdir = 0;
|
|
}
|
|
}
|
|
|
|
bool is_number(const char* str)
|
|
{
|
|
if (!SDL_isdigit(str[0]) && str[0] != '-')
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (str[0] == '-' && str[1] == '\0')
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (size_t i = 1; str[i] != '\0'; ++i)
|
|
{
|
|
if (!SDL_isdigit(str[i]))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool VVV_isxdigit(const unsigned char digit)
|
|
{
|
|
return (digit >= 'a' && digit <= 'f')
|
|
|| (digit >= 'A' && digit <= 'F')
|
|
|| SDL_isdigit(digit);
|
|
}
|
|
|
|
bool is_positive_num(const char* str, const bool hex)
|
|
{
|
|
if (str[0] == '\0')
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (size_t i = 0; str[i] != '\0'; ++i)
|
|
{
|
|
if (hex)
|
|
{
|
|
if (!VVV_isxdigit(str[i]))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!SDL_isdigit(str[i]))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool endsWith(const std::string& str, const std::string& suffix)
|
|
{
|
|
if (str.size() < suffix.size())
|
|
{
|
|
return false;
|
|
}
|
|
return str.compare(
|
|
str.size() - suffix.size(),
|
|
suffix.size(),
|
|
suffix
|
|
) == 0;
|
|
}
|