summaryrefslogtreecommitdiff
path: root/Runtime/Utilities/Word.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Runtime/Utilities/Word.cpp')
-rw-r--r--Runtime/Utilities/Word.cpp659
1 files changed, 659 insertions, 0 deletions
diff --git a/Runtime/Utilities/Word.cpp b/Runtime/Utilities/Word.cpp
new file mode 100644
index 0000000..2057283
--- /dev/null
+++ b/Runtime/Utilities/Word.cpp
@@ -0,0 +1,659 @@
+#include "UnityPrefix.h"
+#include "Word.h"
+#include <limits.h>
+#include <stdio.h>
+#include "Runtime/Math/FloatConversion.h"
+#include "Annotations.h"
+
+#if !UNITY_EXTERNAL_TOOL
+#include "Runtime/Allocator/LinearAllocator.h"
+#endif
+
+using namespace std;
+
+bool BeginsWithCaseInsensitive (const std::string &s, const std::string &beginsWith)
+{
+ // Note that we don't want to convert the whole s string to lower case, simply because
+ // it might not be very efficient (imagine a string that has, e.g., 2 Mb chars), so we take
+ // only a substring that we need to compare with the given prefix.
+ return BeginsWith(ToLower(s.substr(0, beginsWith.length())), ToLower(beginsWith));
+}
+
+bool BeginsWith (const char* s, const char* beginsWith)
+{
+ return strncmp (s, beginsWith, strlen (beginsWith)) == 0;
+}
+
+
+#if !WEBPLUG
+bool IsStringNumber (const string& s)
+{
+ return IsStringNumber (s.c_str ());
+}
+#endif
+
+
+#if UNITY_EDITOR
+/*
+ Used by SemiNumericCompare:
+ if c[*index] is > '9', returns INT_MAX-265+c[*index] and increases *index by 1.
+ if '0' <= c[*index] <= '9' consumes all numeric characters and returns the numerical value + '0'
+ if c[*index] is < '0' returns (int)c[*index] and increases *index by 1;
+*/
+static int GetSNOrdinal(const char* c, int& index)
+{
+
+ if((unsigned char)c[index] < (unsigned char)'0')
+ return (unsigned char)c[index++];
+ else if ((unsigned char)c[index] > (unsigned char)'9')
+ return (INT_MAX-256) + (unsigned char)ToLower(c[index++]);
+ else
+ {
+ int atoi=0;
+ while (c[index] >= '0' && c[index] <= '9')
+ {
+ atoi = atoi*10 + (c[index++] - '0'); // TODO: clamp at INT_MAX-256
+ }
+ return atoi+'0';
+ }
+}
+
+// Human-like sorting.
+// Sorts strings alphabetically, but with numbers in strings numerically, so "xx11" comes after "xx2".
+int SemiNumericCompare(const char * str1, const char * str2)
+{
+ int i1 = 0;
+ int i2 = 0;
+ int o1, o2;
+
+ while ((o1 = GetSNOrdinal(str1, i1)) == (o2 = GetSNOrdinal(str2, i2)))
+ {
+ if (!o1)
+ return i2-i1; // to make strings like "xx1", "xx01" and "xx001" have a stable sorting (longest string first as in Finder)
+ }
+
+ return(o1 - o2);
+}
+#endif
+
+int StrNICmp(const char * str1, const char * str2, size_t n)
+{
+ const char * p1 = (char *) str1;
+ const char * p2 = (char *) str2;
+ char c1, c2;
+ size_t charsLeft=n;
+
+ if( n <= 0 )
+ return 0;
+
+ while ((c1 = ToLower (*p1)) == (c2 = ToLower (*p2)))
+ {
+ ++p1; ++p2; --charsLeft;
+ if (!charsLeft || !c1)
+ return 0;
+ }
+
+ return(c1 - c2);
+}
+
+int StrICmp(const char * str1, const char * str2)
+{
+ const char * p1 = (char *) str1;
+ const char * p2 = (char *) str2;
+ char c1, c2;
+
+ while ((c1 = ToLower (*p1)) == (c2 = ToLower (*p2)))
+ {
+ p1++; p2++;
+ if (!c1)
+ return 0;
+ }
+
+ return(c1 - c2);
+}
+
+int StrCmp(const char * str1, const char * str2)
+{
+ const char * p1 = (char *) str1;
+ const char * p2 = (char *) str2;
+ char c1, c2;
+
+ while ((c1 = (*p1)) == (c2 = (*p2)))
+ {
+ p1++; p2++;
+ if (!c1)
+ return 0;
+ }
+
+ return(c1 - c2);
+}
+
+
+#if !WEBPLUG
+bool IsStringNumber (const char* s)
+{
+ bool success = false;
+ bool hadPoint = false;
+ long i = 0;
+
+ while (s[i] != '\0')
+ {
+ switch (s[i])
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+
+ success = true;
+
+ break;
+
+ case '.':
+ case ',':
+
+ // Make sure we only have one . or ,
+ if (hadPoint)
+ return false;
+ hadPoint = true;
+
+ break;
+
+ case '+':
+ case '-':
+
+ // + or - are only allowed at the beginning of the string
+ if (i != 0)
+ return false;
+ break;
+
+ default:
+ return false;
+ break;
+ }
+ i++;
+ }
+
+ return success;
+}
+#endif
+
+
+SInt32 StringToInt (char const* s)
+{
+ return atol (s);
+}
+
+template<typename T>
+inline string _ToString (const char* formatString, T value)
+{
+ char buf[255];
+
+ #ifdef WIN32
+ _snprintf
+ #else
+ snprintf
+ #endif
+ (buf, sizeof(buf), formatString, value);
+
+ return string (buf);
+}
+
+string IntToString (SInt32 i)
+{
+ return _ToString ("%i", i);
+}
+
+string UnsignedIntToString (UInt32 i)
+{
+ return _ToString ("%u", i);
+}
+
+string Int64ToString (SInt64 i)
+{
+ return _ToString ("%lli", i);
+}
+
+string UnsignedInt64ToString (UInt64 i)
+{
+ return _ToString ("%llu", i);
+}
+
+string DoubleToString (double i)
+{
+ return _ToString ("%f", i);
+}
+
+string FloatToString (float f, const char* precFormat)
+{
+ char buf[255];
+ if (IsNAN(f))
+ strcpy(buf, "NaN");
+ else if (IsMinusInf(f))
+ strcpy(buf, "-Infinity");
+ else if (IsPlusInf(f))
+ strcpy(buf, "Infinity");
+ else
+ sprintf (buf, precFormat, f);
+ return string (buf);
+}
+
+string SHA1ToString(unsigned char hash[20])
+{
+ char buffer[41];
+ for ( int i=0; i < 20; i++ )
+ sprintf(&buffer[i*2], "%.2x", hash[i]);
+ return std::string(buffer, 40);
+}
+
+string MD5ToString(unsigned char hash[16])
+{
+ char buffer[33];
+ for ( int i=0; i < 16; i++ )
+ sprintf(&buffer[i*2], "%.2x", hash[i]);
+ return std::string(buffer, 32);
+}
+
+// Parses simple float: optional sign, digits, period, digits.
+// No exponent or leading whitespace support.
+// No locale support.
+// We use it to be independent of locale, and because atof() did
+// show up in the shader parsing profile.
+float SimpleStringToFloat (const char* str, int* outLength)
+{
+ const char *p = str;
+
+ // optional sign
+ bool negative = false;
+ switch (*p) {
+ case '-': negative = true; // fall through to increment pointer
+ case '+': p++;
+ }
+
+ double number = 0.0;
+
+ // scan digits
+ while (IsDigit(*p))
+ {
+ number = number * 10.0 + (*p - '0');
+ p++;
+ }
+
+ // optional decimal part
+ if (*p == '.')
+ {
+ p++;
+
+ // scan digits after decimal point
+ double scaler = 0.1;
+ while (IsDigit(*p))
+ {
+ number += (*p - '0') * scaler;
+ scaler *= 0.1;
+ p++;
+ }
+ }
+
+ // apply sign
+ if (negative)
+ number = -number;
+
+ // Do not check for equality with atof() - results
+ // of that are dependent on locale.
+ //DebugAssertIf(!CompareApproximately(number, atof(str)));
+
+ if (outLength)
+ *outLength = (int) (p - str);
+
+ return float(number);
+}
+
+
+void VFormatBuffer (char* buffer, int size, const char* format, va_list ap)
+{
+ va_list zp;
+ va_copy (zp, ap);
+ vsnprintf (buffer, size, format, zp);
+ va_end (zp);
+}
+
+std::string VFormat (const char* format, va_list ap)
+{
+ va_list zp;
+ va_copy (zp, ap);
+ char buffer[1024 * 10];
+ vsnprintf (buffer, 1024 * 10, format, zp);
+ va_end (zp);
+ return buffer;
+}
+
+std::string Format (const char* format, ...)
+{
+ va_list va;
+ va_start (va, format);
+ std::string formatted = VFormat (format, va);
+ va_end (va);
+ return formatted;
+}
+
+#if UNITY_EDITOR || UNITY_FBX_IMPORTER
+bool AsciiToUTF8 (std::string& name)
+{
+ if (name.empty())
+ return true;
+
+ #if UNITY_OSX
+ CFStringRef str = CFStringCreateWithCString (NULL, name.c_str(), kCFStringEncodingASCII);
+ if (str != NULL)
+ {
+ bool res = false;
+
+ char* tempName;
+ ALLOC_TEMP(tempName, char, name.size() * 2);
+ if (CFStringGetCString(str, tempName, name.size() * 2, kCFStringEncodingUTF8))
+ {
+ name = tempName;
+ res = true;
+ }
+ CFRelease(str);
+ return res;
+ }
+
+ return false;
+
+ #elif UNITY_WIN
+
+ bool result = false;
+ int bufferSize = (int) name.size()*4+1;
+ wchar_t* wideBuffer;
+ ALLOC_TEMP(wideBuffer, wchar_t, bufferSize);
+ if( MultiByteToWideChar( CP_ACP, 0, name.c_str(), -1, wideBuffer, bufferSize ) )
+ {
+ char* buffer;
+ ALLOC_TEMP(buffer, char, bufferSize);
+ if( WideCharToMultiByte( CP_UTF8, 0, wideBuffer, -1, buffer, bufferSize, NULL, NULL ) )
+ {
+ name = buffer;
+ result = true;
+ }
+ }
+ return result;
+
+ #elif UNITY_LINUX
+
+ return true; // do nothing for now. Tests should show how much is this
+ // function needed.
+
+ #else
+ #error Unknown platform
+ #endif
+}
+
+std::string StripInvalidIdentifierCharacters (std::string str)
+{
+ for (unsigned int i=0;i<str.size();i++)
+ {
+ char c = str[i];
+ if (c == '~' || c == '&' || c == '%' || c == '|' || c == '$' || c == '<' || c == '>' || c == '/' || c == '\\')
+ str[i] = '_';
+ }
+ return str;
+}
+#endif
+
+void HexStringToBytes (char* str, size_t bytes, void *data)
+{
+ for (size_t i=0; i<bytes; i++)
+ {
+ UInt8 b;
+ char ch = str[2*i+0];
+ if (ch <= '9')
+ b = (ch - '0') << 4;
+ else
+ b = (ch - 'a' + 10) << 4;
+
+ ch = str[2*i+1];
+ if (ch <= '9')
+ b |= (ch - '0');
+ else
+ b |= (ch - 'a' + 10);
+
+ ((UInt8*)data)[i] = b;
+ }
+}
+
+void BytesToHexString (const void *data, size_t bytes, char* str)
+{
+ static const char kHexToLiteral[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+ for (size_t i=0; i<bytes;i++)
+ {
+ UInt8 b = ((UInt8*)data)[i];
+ str[2*i+0] = kHexToLiteral[ b >> 4 ];
+ str[2*i+1] = kHexToLiteral[ b & 0xf ];
+ }
+}
+
+std::string BytesToHexString (const void* data, size_t numBytes)
+{
+ std::string result;
+ result.resize (numBytes * 2);
+ BytesToHexString (data, numBytes, &result[0]);
+ return result;
+}
+
+string FormatBytes(SInt64 b)
+{
+ AssertIf(sizeof(b) != 8);
+
+ if(b < 0)
+ return "Unknown";
+ if (b < 512)
+#if UNITY_64 && UNITY_LINUX
+ return Format("%ld B",b);
+#else
+ return Format("%lld B",b);
+#endif
+ if (b < 512*1024)
+ return Format("%01.1f KB",b / 1024.0);
+
+ b /= 1024;
+ if (b < 512*1024)
+ return Format("%01.1f MB", b / 1024.0);
+
+ b /= 1024;
+ return Format("%01.2f GB",b / 1024.0);
+}
+
+std::string Append (char const* a, std::string const& b)
+{
+ std::string r;
+ size_t asz = strlen (a);
+ r.reserve (asz + b.size ());
+ r.assign (a, asz);
+ r.append (b);
+ return r;
+}
+
+std::string Append (char const* a, char const* b)
+{
+ std::string r;
+ size_t asz = strlen (a);
+ size_t bsz = strlen (b);
+ r.reserve (asz + bsz);
+ r.assign (a, asz);
+ r.append (b, bsz);
+ return r;
+}
+
+std::string Append (std::string const& a, char const* b)
+{
+ std::string r;
+ size_t bsz = strlen(b);
+ r.reserve(a.size() + bsz);
+ r.assign(a);
+ r.append(b, bsz);
+ return r;
+}
+
+#if UNITY_OSX || UNITY_IPHONE
+CFStringRef StringToCFString (const std::string &str)
+{
+ return CFStringCreateWithCString(kCFAllocatorDefault, str.c_str(), kCFStringEncodingUTF8);
+}
+
+std::string CFStringToString (CFStringRef str)
+{
+ std::string output;
+ if (str)
+ {
+ int bufferSize = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8) + 1;
+ char *buf;
+ MALLOC_TEMP( buf, bufferSize );
+ if (CFStringGetCString(str, buf, bufferSize, kCFStringEncodingUTF8))
+ output = buf;
+ }
+ return output;
+}
+#endif
+
+std::string Trim(const std::string &input, const std::string &ws)
+{
+ size_t startpos = input.find_first_not_of(ws); // Find the first character position after excluding leading blank spaces
+ size_t endpos = input.find_last_not_of(ws); // Find the first character position from reverse af
+
+ // if all spaces or empty return an empty string
+ if(( string::npos == startpos ) || ( string::npos == endpos))
+ {
+ return std::string(); // empty string
+ }
+ else
+ {
+ return input.substr( startpos, endpos-startpos+1 );
+ }
+}
+
+
+/*
+ Convert version string of form XX.X.XcXXX to UInt32 in Apple 'vers' representation
+ as described in Tech Note TN1132 (http://developer.apple.com/technotes/tn/pdf/tn1132.pdf)
+ eg.
+ 1.2.0
+ 1.2.1
+ 1.2.1a1
+ 1.2.1b1
+ 1.2.1r12
+ */
+int GetNumericVersion (char const* versionCString)
+{
+ if( (*versionCString)=='\0' )
+ return 0;
+
+ int major=0,minor=0,fix=0,type='r',release=0;
+ const char *spos=versionCString;
+ major = *(spos++) - '0';
+ if (*spos>='0' && *spos < '9')
+ major = major*10 + *(spos++)-'0';
+
+ if (*spos)
+ {
+ if (*spos=='.')
+ {
+ spos++;
+ if(*spos)
+ minor=*(spos++)-'0';
+ }
+ if (*spos)
+ {
+ if (*spos=='.')
+ {
+ spos++;
+ if (*spos)
+ fix=*(spos++)-'0';
+ }
+ if (*spos)
+ {
+ type = *(spos++);
+ if (*spos)
+ {
+ release = *(spos++)-'0';
+ if (*spos)
+ {
+ release = release*10+*(spos++)-'0';
+ if (*spos)
+ {
+ release=release*10+*(spos++)-'0';
+ }
+ }
+ }
+ }
+ }
+ }
+
+ unsigned int version = 0;
+ version |= ((major/10)%10)<<28;
+ version |= (major%10)<<24;
+ version |= (minor%10)<<20;
+ version |= (fix%10)<<16;
+ switch( type )
+ {
+ case 'D':
+ case 'd': version |= 0x2<<12; break;
+ case 'A':
+ case 'a': version |= 0x4<<12; break;
+ case 'B':
+ case 'b': version |= 0x6<<12; break;
+ case 'F':
+ case 'R':
+ case 'f':
+ case 'r': version |= 0x8<<12; break;
+ }
+ version |= ((release / 100)%10)<<8;
+ version |= ((release / 10) %10)<<4;
+ version |= release % 10;
+
+ AssertIf (((int)version) < 0);
+
+ return version;
+}
+
+void Split (const std::string s, char splitChar, std::vector<std::string> &parts)
+{
+ int n = 0, n1 = 0;
+ while ( 1 )
+ {
+ n1 = s.find (splitChar, n);
+ std::string p = s.substr (n, n1-n);
+ if ( p.length () )
+ {
+ parts.push_back (p);
+ }
+ if ( n1 == std::string::npos )
+ break;
+
+ n = n1 + 1;
+ }
+}
+
+void Split (const std::string s, const char* splitChars, std::vector<std::string> &parts)
+{
+ int n = 0, n1 = 0;
+ while ( 1 )
+ {
+ n1 = s.find_first_of (splitChars, n);
+ std::string p = s.substr (n, n1-n);
+ if ( p.length () )
+ {
+ parts.push_back (p);
+ }
+ if ( n1 == std::string::npos )
+ break;
+
+ n = n1 + 1;
+ }
+}