1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420 |
- #include "Common.h"
- #include "util/BumpAllocator.h"
- #include "util/UTF8.h"
- #include "util/String.h"
- //#include "farts.z"
- #include <string.h>
- #include "platform/PlatformHelper.h"
- #ifndef BF_SMALL
- #define STB_SPRINTF_DECORATE(name) BF_stbsp_##name
- #define STB_SPRINTF_IMPLEMENTATION
- #include "third_party/stb/stb_sprintf.h"
- #endif
- extern "C"
- {
- #include "third_party/utf8proc/utf8proc.h"
- }
- #ifdef BF_PLATFORM_WINDOWS
- #include <shellapi.h>
- #include <direct.h>
- #endif
- #pragma warning(disable:4996)
- #pragma comment(lib, "winmm.lib")
- int gBFArgC;
- char** gBFArgV;
- #ifdef BUMPALLOC_ETW_TRACING
- VSHeapTracker::CHeapTracker* Beefy::BumpAllocator::mVSHeapTracker = NULL;
- #pragma comment(lib, "VSCustomNativeHeapEtwProvider.lib")
- #endif
- USING_NS_BF;
- UTF16String Beefy::ToWString(const StringImpl& theString)
- {
- UTF16String aString;
- aString.Reserve(theString.length() + 1);
- for (intptr i = 0; i < theString.length(); ++i)
- aString.Add((unsigned char)theString[i]);
- aString.Add(0);
- return aString;
- }
- // String Beefy::ToString(const UTF16String& theString)
- // {
- // String newString;
- // newString.Reserve((intptr)theString.length());
- // for (int i = 0; i < (int)theString.length(); ++i)
- // {
- // const unsigned int c = (unsigned int)theString[i];
- // newString.Append(char(c & 0xFF));
- // }
- // return newString;
- // }
- String Beefy::ToUpper(const StringImpl& theString)
- {
- String aString = theString;
- for (int i = 0; i < (int)aString.length(); ++i)
- aString[i] = toupper(aString[i]);
- return aString;
- }
- void Beefy::MakeUpper(StringImpl& theString)
- {
- for (int i = 0; i < (int)theString.length(); ++i)
- theString[i] = toupper(theString[i]);
- }
- UTF16String Beefy::ToUpper(const UTF16String& theString)
- {
- UTF16String aString = theString;
- for (int i = 0; i < (int)aString.length(); ++i)
- aString[i] = toupper(aString[i]);
- return aString;
- }
- UTF16String Beefy::ToLower(const UTF16String& theString)
- {
- UTF16String aString = theString;
- for (int i = 0; i < (int)aString.length(); ++i)
- aString[i] = tolower(aString[i]);
- return aString;
- }
- String Beefy::ToLower(const StringImpl& theString)
- {
- String aString = theString;
- for (int i = 0; i < (int)aString.length(); ++i)
- aString[i] = (char)tolower((int)(uint8)aString[i]);
- return aString;
- }
- // UTF16String Beefy::Trim(const UTF16String& theString)
- // {
- // int left = 0;
- // while ((left < (int) theString.length() - 1) && (iswspace(theString[left])))
- // left++;
- //
- // int right = (int)theString.length() - 1;
- // while ((right >= left) && (iswspace(theString[right])))
- // right--;
- //
- // if ((left == 0) && (right == theString.length() - 1))
- // return theString;
- //
- // return theString.substr(left, right - left + 1);
- // }
- String Beefy::Trim(const StringImpl& theString)
- {
- int left = 0;
- while ((left < (int) theString.length() - 1) && (iswspace(theString[left])))
- left++;
- int right = (int)theString.length() - 1;
- while ((right >= left) && (iswspace(theString[right])))
- right--;
- if ((left == 0) && (right == theString.length() - 1))
- return theString;
- return theString.Substring(left, right - left + 1);
- }
- bool Beefy::StrReplace(StringImpl& str, const StringImpl& from, const StringImpl& to)
- {
- str.Replace(from, to);
- return true;
- }
- bool Beefy::StrStartsWith(const StringImpl& str, const StringImpl& subStr)
- {
- if (subStr.length() < str.length())
- return false;
- return strncmp(str.c_str(), subStr.c_str(), subStr.length()) == 0;
- }
- bool Beefy::StrEndsWith(const StringImpl& str, const StringImpl& subStr)
- {
- if (subStr.length() < str.length())
- return false;
- return strncmp(str.c_str() - (str.length() - subStr.length()), subStr.c_str(), subStr.length()) == 0;
- }
- #ifndef BF_SMALL
- String Beefy::SlashString(const StringImpl& str, bool utf8decode, bool utf8encode, bool beefString)
- {
- bool prevEndedInSlashedNum = false;
- String outStr;
- bool noNextHex = false;
- bool lastWasVisibleChar = false;
- for (int idx = 0; idx < (int)str.length(); idx++)
- {
- bool endingInSlashedNum = false;
- char c = str[idx];
- if (noNextHex)
- {
- if (((c >= '0') && (c <= '9')) ||
- ((c >= 'a') && (c <= 'f')) ||
- ((c >= 'A') && (c <= 'F')))
- {
- outStr += "\"\"";
- }
- noNextHex = false;
- }
- bool isVisibleChar = false;
- switch (c)
- {
- case '\0':
- outStr += "\\0";
- endingInSlashedNum = true;
- break;
- case '\a':
- outStr += "\\a";
- break;
- case '\b':
- outStr += "\\b";
- break;
- case '\t':
- outStr += "\\t";
- break;
- case '\n':
- outStr += "\\n";
- break;
- case '\v':
- outStr += "\\v";
- break;
- case '\f':
- outStr += "\\f";
- break;
- case '\r':
- outStr += "\\r";
- break;
- case '\"':
- outStr += "\\\"";
- break;
- case '\\':
- outStr += "\\\\";
- break;
- default:
- {
- if ((c >= '0') && (c <= '9'))
- {
- // Need to break string to allow proper evaluation of slashed string
- if (prevEndedInSlashedNum)
- outStr += "\" \"";
- }
- // May be UTF8 byte. Make sure it's valid before we add it, otherwise write the bytes in direct "\x" style
- if (((uint8)c >= 0x80) && (utf8decode))
- {
- int seqLen = u8_seqlen((char*)&str[idx]);
- if (seqLen > 1)
- {
- if (idx + seqLen <= str.length())
- {
- uint32 c32 = u8_toucs((char*)&str[idx], (int)str.length() - idx);
- bool wantHex = false;
- // Combining mark without previous visible char?
- if ((((c32 >= L'\u0300') && (c32 <= L'\u036F')) || ((c32 >= L'\u1DC0') && (c32 <= L'\u1DFF'))) &&
- (!lastWasVisibleChar))
- wantHex = true;
- utf8proc_category_t cat = utf8proc_category(c32);
- switch (cat)
- {
- case UTF8PROC_CATEGORY_ZS:
- case UTF8PROC_CATEGORY_ZL:
- case UTF8PROC_CATEGORY_ZP:
- case UTF8PROC_CATEGORY_CC:
- case UTF8PROC_CATEGORY_CF:
- case UTF8PROC_CATEGORY_CO:
- wantHex = true;
- break;
- default:
- break;
- }
- if (wantHex)
- {
- if (beefString)
- {
- char tempStr[32];
- sprintf(tempStr, "\\u{%x}", c32);
- outStr += tempStr;
- idx += seqLen - 1;
- continue;
- }
- else
- {
- char tempStr[32];
- sprintf(tempStr, "\\u%04x", c32);
- outStr += tempStr;
- idx += seqLen - 1;
- noNextHex = true;
- continue;
- }
- }
- bool passed = true;
- for (int checkOfs = 0; checkOfs < seqLen - 1; checkOfs++)
- {
- char checkC = str[idx + checkOfs + 1];
- if ((checkC & 0xC0) != 0x80) // Has trailing signature (0x10xxxxxx)?
- passed = false;
- }
- if (passed)
- {
- outStr += c;
- for (int checkOfs = 0; checkOfs < seqLen - 1; checkOfs++)
- {
- char checkC = str[idx + checkOfs + 1];
- outStr += checkC;
- }
- idx += seqLen - 1;
- continue;
- }
- }
- }
- }
- if (((uint8)c >= 0x80) && (utf8encode))
- {
- outStr += (char)(0xC0 | (((uint8)c & 0xFF) >> 6));
- outStr += (char)(0x80 | ((uint8)c & 0x3F));
- isVisibleChar = true;
- continue;
- }
- if (((uint8)c >= 32) && ((uint8)c < 0x80))
- {
- outStr += c;
- isVisibleChar = true;
- }
- else
- {
- char tempStr[32];
- sprintf(tempStr, "\\x%02x", (uint8)c);
- outStr += tempStr;
- endingInSlashedNum = true;
- if (!beefString)
- noNextHex = true;
- }
- }
- break;
- }
- prevEndedInSlashedNum = endingInSlashedNum;
- lastWasVisibleChar = isVisibleChar;
- }
- return outStr;
- }
- #endif
- UTF16String Beefy::UTF8Decode(const StringImpl& theString)
- {
- UTF16String strOut;
- int strLen = 0;
- char* cPtr = (char*)theString.c_str();
- int lenLeft = (int)theString.length();
- while (lenLeft > 0)
- {
- int seqLen = 0;
- uint32 c32 = u8_toucs(cPtr, lenLeft, &seqLen);
- if ((c32 >= 0x10000) && (sizeof(wchar_t) == 2))
- strLen += 2;
- else
- strLen += 1;
- cPtr += seqLen;
- lenLeft -= seqLen;
- }
- strOut.ResizeRaw(strLen + 1);
- strOut[strLen] = 0;
- cPtr = (char*)theString.c_str();
- uint16* wcPtr = strOut.mVals;
- int wcLenLeft = (int)strOut.length() + 1;
- lenLeft = (int)theString.length();
- while (lenLeft > 0)
- {
- int seqLen = 0;
- uint32 c32 = u8_toucs(cPtr, lenLeft, &seqLen);
- if ((c32 >= 0x10000) && (sizeof(wchar_t) == 2))
- {
- *(wcPtr++) = (wchar_t)(((c32 - 0x10000) >> 10) + 0xD800);
- *(wcPtr++) = (wchar_t)(((c32 - 0x10000) & 0x3FF) + 0xDC00);
- wcLenLeft -= 2;
- }
- else
- {
- *(wcPtr++) = (wchar_t)c32;
- wcLenLeft -= 1;
- }
- cPtr += seqLen;
- lenLeft -= seqLen;
- }
- return strOut;
- }
- String Beefy::UTF8Encode(const uint16* theString, int length)
- {
- if (length == 0)
- return String();
- String strOut;
- int utf8Len = 0;
- uint16 utf16hi = 0;
- for (int i = 0; i < length; i++)
- {
- uint16 c = theString[i];
- uint32 c32 = c;
- if ((c >= 0xD800) && (c < 0xDC00))
- {
- utf16hi = (uint16)c;
- continue;
- }
- else if ((c >= 0xDC00) && (c < 0xE000))
- {
- uint16 utf16lo = c;
- c32 = 0x10000 + ((uint32)(utf16hi - 0xD800) << 10) | (uint32)(utf16lo - 0xDC00);
- }
- utf8Len += u8_seqlen(c32);
- }
- strOut.Append('?', utf8Len);
- char* cPtr = (char*)&strOut[0];
- int lenLeft = (int)strOut.length() + 1;
- for (int i = 0; i < length; i++)
- {
- uint16 c = theString[i];
- uint32 c32 = c;
- if ((c >= 0xD800) && (c < 0xDC00))
- {
- utf16hi = (uint16)c;
- continue;
- }
- else if ((c >= 0xDC00) && (c < 0xE000))
- {
- uint16 utf16lo = c;
- c32 = 0x10000 + ((uint32)(utf16hi - 0xD800) << 10) | (uint32)(utf16lo - 0xDC00);
- }
- int len = u8_toutf8(cPtr, lenLeft, c32);
- cPtr += len;
- lenLeft -= len;
- }
- return strOut;
- }
- String Beefy::UTF8Encode(const UTF16String& theString)
- {
- return UTF8Encode((uint16*)theString.c_str(), (int)theString.length());
- }
- UTF16String Beefy::UTF16Decode(const uint16* theString)
- {
- if (sizeof(wchar_t) == 2)
- {
- UTF16String str;
- str.Set((wchar_t*)theString);
- return str;
- }
- else
- {
- UTF16String str;
- int len = 0;
- while (theString[len] != 0)
- len++;
- str.ResizeRaw(len + 1);
- str[len] = 0;
- for (int pos = 0; pos < len; pos++)
- str[pos] = (wchar_t)theString[pos];
- return str;
- }
- }
- static const char gHexChar[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
- String Beefy::FileNameToURI(const StringImpl& fileName)
- {
- #ifdef _WIN32
- String out = "file:///";
- #else
- String out = "file://";
- #endif
- for (int i = 0; i < (int)fileName.length(); i++)
- {
- char c = out[i];
- bool isValid =
- ((c >= '@' && c <= 'Z') ||
- (c >= 'a' && c <= 'z') ||
- (c >= '&' && c < 0x3b) ||
- (c == '!') || (c == '$') || (c == '_') || (c == '=') || (c == '~'));
- if ((((unsigned char)c) >= 0x80) || (!isValid))
- {
- out += '%';
- out += gHexChar[((unsigned char)(c)) >> 4];
- out += gHexChar[((unsigned char)(c)) & 0xf];
- }
- else if (c == '\\')
- out += '/';
- else
- out += c;
- }
- return out;
- }
- static const uint8 cCharTo64b[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0,
- 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 63,
- 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- int64 Beefy::DecodeULEB32(const char*& p)
- {
- uint64 val = 0;
- unsigned shift = 0;
- uint8 charVal;
- do
- {
- charVal = cCharTo64b[(uint8)*(p++)];
- val += uint64(charVal & 0x1f) << shift;
- shift += 5;
- } while ((charVal & 0x20) != 0);
- return val;
- }
- static const char c64bToChar[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
- 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F',
- 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
- 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '_'};
- void Beefy::EncodeULEB32(uint64 value, StringImpl& buffer)
- {
- do
- {
- uint8 byteVal = value & 0x1f;
- value >>= 5;
- if (value != 0)
- byteVal |= 0x20; // Mark this byte to show that more bytes will follow
- buffer.Append(c64bToChar[byteVal]);
- }
- while (value != 0);
- }
- #ifndef BF_SMALL
- void Beefy::ExactMinimalFloatToStr(float f, char* str)
- {
- sprintf(str, "%1.9g", f);
- char* cPtrLast = str;
- while (true)
- {
- char c = cPtrLast[1];
- if ((c == 0) || (c == 'e'))
- break;
- cPtrLast++;
- }
- char* cStrEnd = cPtrLast + 1;
- int baseLen = (int)(cPtrLast - str) + 1;
- if (baseLen < 9)
- return; // Isn't "full" precision
- char removeChar;
- char lastChar = *cPtrLast;
- char secondToLast = cPtrLast[-1];
- if (secondToLast == '9')
- {
- removeChar = '9';
- }
- else if (secondToLast == '0')
- {
- removeChar = '0';
- }
- else
- {
- return; // Not a 'transitional' representation
- }
- do
- {
- *cPtrLast = 0;
- cPtrLast--;
- } while (*cPtrLast == removeChar);
- strcpy(cPtrLast + 1, cStrEnd);
- if (removeChar == '9')
- (*cPtrLast)++;
- // Verify that our pretty representation is equivalent
- float checkF = 0;
- sscanf(str, "%f", &checkF);
- if (f == checkF)
- return;
- // Rollback
- int endLen = (int)strlen(cPtrLast + 1);
- memmove(cStrEnd, cPtrLast + 1, endLen);
- if (removeChar == '9')
- (*cPtrLast)--;
- cPtrLast++;
- while (cPtrLast < cStrEnd - 1)
- {
- *cPtrLast = removeChar;
- cPtrLast++;
- }
- *cPtrLast = lastChar;
- }
- void Beefy::ExactMinimalDoubleToStr(double d, char* str)
- {
- sprintf(str, "%1.17g", d);
- char* cPtrLast = str;
- while (true)
- {
- char c = cPtrLast[1];
- if ((c == 0) || (c == 'e'))
- break;
- cPtrLast++;
- }
- char* cStrEnd = cPtrLast + 1;
- int baseLen = (int)(cPtrLast - str) + 1;
- if (baseLen < 18)
- return; // Isn't "full" precision
- char removeChar;
- char lastChar = *cPtrLast;
- if ((lastChar == '9') || (lastChar == '8'))
- {
- removeChar = '9';
- }
- else if ((lastChar == '1') || (lastChar == '2'))
- {
- removeChar = '0';
- }
- else
- {
- return; // Not a 'transitional' representation
- }
- do
- {
- *cPtrLast = 0;
- cPtrLast--;
- }
- while (*cPtrLast == removeChar);
- strcpy(cPtrLast + 1, cStrEnd);
- if (removeChar == '9')
- (*cPtrLast)++;
- // Verify that our pretty representation is equivalent
- double checkD = 0;
- sscanf(str, "%lf", &checkD);
- if (d == checkD)
- return;
- // Rollback
- int endLen = (int)strlen(cPtrLast + 1);
- memmove(cStrEnd, cPtrLast + 1, endLen);
- if (removeChar == '9')
- (*cPtrLast)--;
- cPtrLast++;
- while (cPtrLast < cStrEnd - 1)
- {
- *cPtrLast = removeChar;
- cPtrLast++;
- }
- *cPtrLast = lastChar;
- }
- #endif
- static char* StbspCallback(char *buf, void *user, int len)
- {
- ((StringImpl*)user)->Append(buf, len);
- return buf;
- }
- //extern "C" int _vsnprintf(char* const _Buffer, size_t const _BufferCount, char const* const _Format, va_list _ArgList, int zz);
- #ifdef BF_SMALL
- String Beefy::vformat(const char* fmt, va_list argPtr)
- {
- // We draw the line at a 1MB string.
- const int maxSize = 1000000;
- //va_list checkArgPtr = argPtr;
- //va_start(checkArgPtr, fmt);
- int argIdx = 0;
- char* newFmt = NULL;
- char tempBuff[2048];
- char* tempBuffPtr = tempBuff;
- for (int i = 0; fmt[i] != 0; i++)
- {
- if (fmt[i] == '%')
- {
- if (fmt[i + 1] == '%')
- {
- i++;
- continue;
- }
- #ifdef BF32
- bool isLongAddr = false;
- #else
- bool isLongAddr = true;
- #endif
- if ((fmt[i + 1] == 'l') && (fmt[i + 2] == '@'))
- {
- isLongAddr = true;
- i++;
- }
- if (fmt[i + 1] == '@')
- {
- if (newFmt == NULL)
- {
- newFmt = (char*)malloc(strlen(fmt) + 1);
- strcpy(newFmt, fmt);
- //newFmt = strdup(fmt);
- }
- newFmt[i + 1] = 's';
- const char*& argValPtr = *(const char**)((intptr*)argPtr + argIdx);
- if (isLongAddr)
- {
- int64 iVal = *(int64*)((intptr*)argPtr + argIdx);
- #ifdef BF32
- argIdx++; // Takes two spots
- #endif
- argValPtr = tempBuffPtr;
- int leftVal = (int)(iVal >> 32);
- if (leftVal != 0)
- {
- sprintf(tempBuffPtr, "%x", leftVal);
- tempBuffPtr += strlen(tempBuffPtr);
- }
- tempBuffPtr[0] = '\'';
- tempBuffPtr++;
- sprintf(tempBuffPtr, "%08x", (int)iVal);
- tempBuffPtr += strlen(tempBuffPtr) + 1;
- }
- else
- {
- int32 iVal = (int32)(intptr)argValPtr;
- argValPtr = tempBuffPtr;
- sprintf(tempBuffPtr, "%08x", iVal);
- tempBuffPtr += strlen(tempBuffPtr) + 1;
- }
- if (newFmt[i] == 'l')
- newFmt[i] = '+';
- }
- else
- {
- //const char*& argValPtr = va_arg(checkArgPtr, const char*);
- }
- argIdx++;
- }
- }
- if (newFmt != NULL)
- {
- Beefy::String retVal = vformat(newFmt, argPtr);
- free(newFmt);
- return retVal;
- }
- // If the string is less than 161 characters,
- // allocate it on the stack because this saves
- // the malloc/free time.
- const int bufSize = 161;
- char stackBuffer[bufSize];
- int attemptedSize = bufSize - 1;
- int numChars = 0;
- #ifdef _WIN32
- numChars = _vsnprintf(stackBuffer, attemptedSize, fmt, argPtr);
- #else
- numChars = vsnprintf(stackBuffer, attemptedSize, fmt, argPtr);
- #endif
- if ((numChars >= 0) && (numChars <= attemptedSize))
- {
- // Needed for case of 160-character printf thing
- stackBuffer[numChars] = '\0';
- // Got it on the first try.
- return String(stackBuffer);
- }
- // Now use the heap.
- char* heapBuffer = NULL;
- while (((numChars == -1) || (numChars > attemptedSize)) &&
- (attemptedSize < maxSize))
- {
- // Try a bigger size
- attemptedSize *= 2;
- heapBuffer = (char*)realloc(heapBuffer, (attemptedSize + 1));
- #ifdef _WIN32
- numChars = _vsnprintf(heapBuffer, attemptedSize, fmt, argPtr);
- #else
- numChars = vsnprintf(heapBuffer, attemptedSize, fmt, argPtr);
- #endif
- }
- if (numChars == -1)
- {
- free(heapBuffer);
- return "";
- }
- heapBuffer[numChars] = 0;
- Beefy::String aResult = Beefy::String(heapBuffer);
- free(heapBuffer);
- return aResult;
- }
- #else
- String Beefy::vformat(const char* fmt, va_list argPtr)
- {
- String str;
- char buf[STB_SPRINTF_MIN];
- BF_stbsp_vsprintfcb(StbspCallback, (void*)&str, buf, fmt, argPtr);
- return str;
- }
- void Beefy::vformat(StringImpl& str, const char* fmt, va_list argPtr)
- {
- char buf[STB_SPRINTF_MIN];
- BF_stbsp_vsprintfcb(StbspCallback, (void*)&str, buf, fmt, argPtr);
- }
- #endif
- String Beefy::StrFormat(const char* fmt ...)
- {
- va_list argList;
- va_start(argList, fmt);
- String aResult = vformat(fmt, argList);
- va_end(argList);
- return aResult;
- }
- String Beefy::IntPtrDynAddrFormat(intptr addr)
- {
- if ((addr & 0xFFFFFFFF00000000LL) == 0)
- return StrFormat("%08X", addr);
- return StrFormat("%p", addr);
- }
- void Beefy::OutputDebugStr(const StringImpl& theString)
- {
- const int maxLen = 0xFFFE;
- if (theString.length() > maxLen)
- {
- OutputDebugStr(theString.Substring(0, maxLen));
- OutputDebugStr(theString.Substring(maxLen));
- return;
- }
- BfpOutput_DebugString(theString.c_str());
- }
- void Beefy::OutputDebugStrF(const char* fmt ...)
- {
- va_list argList;
- va_start(argList, fmt);
- String aResult = vformat(fmt, argList);
- va_end(argList);
- OutputDebugStr(aResult);
- }
- uint8* Beefy::LoadBinaryData(const StringImpl& path, int* size)
- {
- FILE* fP = fopen(path.c_str(), "rb");
- if (fP == NULL)
- return NULL;
- fseek(fP, 0, SEEK_END);
- int aSize = (int32)ftell(fP);
- fseek(fP, 0, SEEK_SET);
- uint8* data = new uint8[aSize];
- int readSize = (int)fread(data, 1, aSize, fP);
- (void)readSize;
- fclose(fP);
- if (size)
- *size = aSize;
- return data;
- }
- char* Beefy::LoadTextData(const StringImpl& path, int* size)
- {
- FILE* fP = fopen(path.c_str(), "rb");
- if (fP == NULL)
- return NULL;
- fseek(fP, 0, SEEK_END);
- int fileSize = (int32)ftell(fP);
- int strLen = fileSize;
- fseek(fP, 0, SEEK_SET);
- uint8 charHeader[3] = {0};
- int readSize = (int)fread(charHeader, 1, 3, fP);
- if ((charHeader[0] == 0xFF) && (charHeader[1] == 0xFE))
- {
- //UTF16 LE
- int dataLen = fileSize - 2;
- char* data = new char[dataLen + 2];
- data[0] = (char)charHeader[2];
- data[dataLen] = 0;
- data[dataLen + 1] = 0;
- int readSize = (int)fread(data + 1, 1, dataLen - 1, fP);
- (void)readSize;
- fclose(fP);
- // UTF16
- UTF16String str;
- str.Set((wchar_t*)data);
- delete [] data;
- String utf8Str = UTF8Encode(str);
- char* utf8Data = new char[utf8Str.length() + 1];
- strLen = (int)utf8Str.length();
- if (size != NULL)
- *size = strLen;
- memcpy(utf8Data, utf8Str.c_str(), strLen);
- return utf8Data;
- }
- else if ((charHeader[0] == 0xEF) && (charHeader[1] == 0xBB) && (charHeader[2] == 0xBF))
- {
- strLen = fileSize - 3;
- char* data = new char[strLen + 1];
- data[strLen] = 0;
- if (size != NULL)
- *size = strLen;
- int readSize = (int)fread(data, 1, strLen, fP);
- (void)readSize;
- fclose(fP);
- return data;
- }
- if (size != NULL)
- *size = strLen;
- char* data = new char[strLen + 1];
- data[strLen] = 0;
- for (int i = 0; i < BF_MIN(3, strLen); i++)
- data[i] = charHeader[i];
- if (strLen > 3)
- {
- int readSize = (int)fread(data + 3, 1, strLen - 3, fP);
- (void)readSize;
- }
- fclose(fP);
- return data;
- }
- bool Beefy::LoadTextData(const StringImpl& path, StringImpl& str)
- {
- int size = 0;
- char* data = LoadTextData(path, &size);
- if (data == NULL)
- return false;
- if ((str.mAllocSizeAndFlags & StringImpl::DynAllocFlag) != 0)
- str.Release();
- str.mPtr = data;
- str.mAllocSizeAndFlags = size | StringImpl::DynAllocFlag | StringImpl::StrPtrFlag;
- str.mLength = size;
- return true;
- }
- #ifdef BF_MINGW
- unsigned long long __cdecl _byteswap_uint64(unsigned long long _Int64)
- {
- #ifdef _WIN64
- unsigned long long retval;
- __asm__ __volatile__ ("bswapq %[retval]" : [retval] "=rm" (retval) : "[retval]" (_Int64));
- return retval;
- #else
- union {
- long long int64part;
- struct {
- unsigned long lowpart;
- unsigned long hipart;
- };
- } retval;
- retval.int64part = _Int64;
- __asm__ __volatile__ ("bswapl %[lowpart]\n"
- "bswapl %[hipart]\n"
- : [lowpart] "=rm" (retval.hipart), [hipart] "=rm" (retval.lowpart) : "[lowpart]" (retval.lowpart), "[hipart]" (retval.hipart));
- return retval.int64part;
- #endif
- }
- #endif
- #ifdef _WIN32
- int64 Beefy::EndianSwap(int64 val)
- {
- return _byteswap_uint64(val);
- }
- #endif
- int32 Beefy::EndianSwap(int val)
- {
- return ((val & 0x000000FF) << 24) | ((val & 0x0000FF00) << 8) |
- ((val & 0x00FF0000) >> 8) | ((val & 0xFF000000) >> 24);
- }
- int16 Beefy::EndianSwap(int16 val)
- {
- return ((val & 0x00FF) << 8) | ((val & 0xFF00) >> 8);
- }
- int32 Beefy::Rand()
- {
- return (rand() & 0xFFFF) | ((rand() & 0x7FFF) << 16);
- }
- int32 Beefy::GetHighestBitSet(int32 n)
- {
- int i = 0;
- for (; n; n = (int)((uint32)n >> 1), i++)
- ; /* empty */
- return i;
- }
- String Beefy::GetFileDir(const StringImpl& path)
- {
- int slashPos = BF_MAX((int)path.LastIndexOf('\\'), (int)path.LastIndexOf('/'));
- if (slashPos == -1)
- return "";
- return path.Substring(0, slashPos);
- }
- String Beefy::GetFileName(const StringImpl& path)
- {
- int slashPos = BF_MAX((int)path.LastIndexOf('\\'), (int)path.LastIndexOf('/'));
- if (slashPos == -1)
- return path;
- return path.Substring(slashPos + 1);
- }
- String Beefy::GetFileExtension(const StringImpl& path)
- {
- int dotPos = (int)path.LastIndexOf('.');
- if (dotPos == -1)
- return path;
- return path.Substring(dotPos);
- }
- static String GetDriveStringTo(String path)
- {
- if ((path.length() >= 2) && (path[1] == ':'))
- return String(path, 0, 2);
- return "";
- }
- String Beefy::GetRelativePath(const StringImpl& fullPath, const StringImpl& curDir)
- {
- String curPath1 = String(curDir);
- String curPath2 = String(fullPath);
- for (int i = 0; i < (int)curPath1.length(); i++)
- if (curPath1[i] == DIR_SEP_CHAR_ALT)
- curPath1[i] = DIR_SEP_CHAR;
- for (int i = 0; i < (int)curPath2.length(); i++)
- if (curPath2[i] == DIR_SEP_CHAR_ALT)
- curPath2[i] = DIR_SEP_CHAR;
- String driveString1 = GetDriveStringTo(curPath1);
- String driveString2 = GetDriveStringTo(curPath2);
- #ifdef _WIN32
- StringImpl::CompareKind compareType = StringImpl::CompareKind_OrdinalIgnoreCase;
- #else
- StringImpl::CompareKind compareType = StringImpl::CompareKind_Ordinal;
- #endif
- // On separate drives?
- if (!driveString1.Equals(driveString2, compareType))
- {
- return fullPath;
- }
- if (driveString1.mLength > 0)
- curPath1.Remove(0, BF_MIN(driveString1.mLength + 1, curPath1.mLength));
- if (driveString2.mLength > 0)
- curPath2.Remove(0, BF_MIN(driveString2.mLength + 1, curPath2.mLength));
- while ((curPath1.mLength > 0) && (curPath2.mLength > 0))
- {
- int slashPos1 = (int)curPath1.IndexOf(DIR_SEP_CHAR);
- if (slashPos1 == -1)
- slashPos1 = curPath1.mLength;
- int slashPos2 = (int)curPath2.IndexOf(DIR_SEP_CHAR);
- if (slashPos2 == -1)
- slashPos2 = curPath2.mLength;
- String section1;
- section1.Append(StringView(curPath1, 0, slashPos1));
- String section2;
- section2.Append(StringView(curPath2, 0, slashPos2));
- if (!section1.Equals(section2, compareType))
- {
- // a/b/c
- // d/e/f
- while (curPath1.mLength > 0)
- {
- slashPos1 = (int)curPath1.IndexOf(DIR_SEP_CHAR);
- if (slashPos1 == -1)
- slashPos1 = curPath1.mLength;
- if (slashPos1 + 1 >= curPath1.mLength)
- curPath1.Clear();
- else
- curPath1.Remove(0, slashPos1 + 1);
- if (DIR_SEP_CHAR == '\\')
- curPath2.Insert(0, "..\\");
- else
- curPath2.Insert(0, "../");
- }
- }
- else
- {
- if (slashPos1 + 1 >= curPath1.mLength)
- curPath1.Clear();
- else
- curPath1.Remove(0, slashPos1 + 1);
- if (slashPos2 + 2 >= curPath2.mLength)
- curPath1 = "";
- else
- curPath2.Remove(0, slashPos2 + 1);
- }
- }
- return curPath2;
- }
- String Beefy::GetAbsPath(const StringImpl& relPathIn, const StringImpl& dir)
- {
- String relPath = relPathIn;
- String driveString = "";
- String newPath;
- newPath = dir;
- for (int i = 0; i < (int)newPath.length(); i++)
- if (newPath[i] == DIR_SEP_CHAR_ALT)
- newPath[i] = DIR_SEP_CHAR;
- for (int i = 0; i < (int)relPath.length(); i++)
- if (relPath[i] == DIR_SEP_CHAR_ALT)
- relPath[i] = DIR_SEP_CHAR;
- if ((relPath.length() >= 2) && (relPath[1] == ':'))
- return relPath;
- char slashChar = DIR_SEP_CHAR;
- if ((newPath.length() >= 2) && (newPath[1] == ':'))
- {
- driveString = newPath.Substring(0, 2);
- newPath = newPath.Substring(2);
- }
- // Append a trailing slash if necessary
- if ((newPath.length() > 0) && (newPath[newPath.length() - 1] != '\\') && (newPath[newPath.length() - 1] != '/'))
- newPath += slashChar;
- int relIdx = 0;
- for (;;)
- {
- if (newPath.length() == 0)
- break;
- int firstSlash = -1;
- for (int32 i = relIdx; i < (int)relPath.length(); i++)
- if ((relPath[i] == '\\') || (relPath[i] == '/'))
- {
- firstSlash = i;
- break;
- }
- if (firstSlash == -1)
- break;
- String chDir = relPath.Substring(relIdx, firstSlash - relIdx);
- relIdx = firstSlash + 1;
- if (chDir == "..")
- {
- int lastDirStart = (int)newPath.length() - 1;
- while ((lastDirStart > 0) && (newPath[lastDirStart - 1] != '\\') && (newPath[lastDirStart - 1] != '/'))
- lastDirStart--;
- String lastDir = newPath.Substring(lastDirStart, newPath.length() - lastDirStart - 1);
- if (lastDir == "..")
- {
- newPath += "..";
- newPath += DIR_SEP_CHAR;
- }
- else
- {
- newPath.RemoveToEnd(lastDirStart);
- }
- }
- else if (chDir == "")
- {
- newPath = DIR_SEP_CHAR;
- break;
- }
- else if (chDir != ".")
- {
- newPath += chDir + slashChar;
- break;
- }
- }
- //newPath = driveString + newPath + tempRelPath;
- newPath = driveString + newPath;
- newPath += relPath.Substring(relIdx);
- return newPath;
- }
- String Beefy::FixPath(const StringImpl& pathIn)
- {
- String path = pathIn;
- for (int i = 0; i < (int)path.length(); i++)
- {
- if (path[i] == DIR_SEP_CHAR_ALT)
- path[i] = DIR_SEP_CHAR;
- if ((i > 0) && (path[i - 1] == '.') && (path[i] == '.'))
- {
- for (int checkIdx = i - 3; checkIdx >= 0; checkIdx--)
- {
- if ((path[checkIdx] == '\\') || (path[checkIdx] == '/'))
- {
- path = path.Substring(0, checkIdx) + path.Substring(i + 1);
- i = checkIdx;
- break;
- }
- }
- }
- }
- return path;
- }
- String Beefy::FixPathAndCase(const StringImpl& pathIn)
- {
- if ((!pathIn.IsEmpty()) && (pathIn[0] == '$'))
- return pathIn;
- String path = FixPath(pathIn);
- #ifdef _WIN32
- for (int i = 0; i < (int)path.length(); ++i)
- path[i] = toupper(path[i]);
- #endif
- return path;
- }
- String Beefy::EnsureEndsInSlash(const StringImpl& dir)
- {
- if ((dir[dir.length() - 1] != '/') && (dir[dir.length() - 1] != '\\'))
- return dir + "/";
- return dir;
- }
- String Beefy::RemoveTrailingSlash(const StringImpl& str)
- {
- if (str.length() != 0)
- {
- char c = str[str.length() - 1];
- if ((c == '\\') || (c == '/'))
- return str.Substring(0, str.length() - 1);
- }
- return str;
- }
- bool Beefy::FileNameEquals(const StringImpl& filePathA, const StringImpl& filePathB)
- {
- #ifdef _WIN32
- if (filePathA.length() != filePathB.length())
- return false;
- const char* aPtr = filePathA.c_str();
- const char* bPtr = filePathB.c_str();
- while (true)
- {
- char a = *(aPtr++);
- char b = *(bPtr++);
- if (a == 0)
- return true;
- if (a == b)
- continue;
- if (a == '/')
- a = '\\';
- if (b == '/')
- b = '\\';
- if (a == b)
- continue;
- if (::toupper(a) == ::toupper(b))
- continue;
- return false;
- }
- #else
- return strcmp(filePathA.c_str(), filePathB.c_str()) == 0;
- #endif
- }
- bool Beefy::RecursiveCreateDirectory(const StringImpl& dirName)
- {
- int slashPos = -1;
- for (int i = (int)dirName.length() - 1; i >= 0; i--)
- {
- char c = dirName[i];
- if ((c == '\\') || (c == '/'))
- {
- slashPos = i;
- break;
- }
- }
- if (slashPos != -1)
- {
- RecursiveCreateDirectory(dirName.Substring(0, slashPos));
- }
- BfpFileResult result;
- BfpDirectory_Create(dirName.c_str(), &result);
- return result == BfpFileResult_Ok;
- }
- bool Beefy::RecursiveDeleteDirectory(const StringImpl& dirPath)
- {
- String findSpec = dirPath + "/*.*";
- bool failed = false;
- BfpFileResult result;
- BfpFindFileData* findFileData = BfpFindFileData_FindFirstFile(findSpec.c_str(), (BfpFindFileFlags)(BfpFindFileFlag_Directories | BfpFindFileFlag_Files), &result);
- if (result == BfpFileResult_Ok)
- {
- while (true)
- {
- Beefy::String fileName;
- BFP_GETSTR_HELPER(fileName, result, BfpFindFileData_GetFileName(findFileData, __STR, __STRLEN, &result));
- String filePath = dirPath + "/" + fileName;
- if ((BfpFindFileData_GetFileAttributes(findFileData) & BfpFileAttribute_Directory) != 0)
- {
- if (!RecursiveDeleteDirectory(filePath))
- failed = true;
- }
- else
- {
- BfpFile_Delete(filePath.c_str(), &result);
- if (result != BfpFileResult_Ok)
- failed = true;
- }
- if (!BfpFindFileData_FindNextFile(findFileData))
- break;
- }
- BfpFindFileData_Release(findFileData);
- }
- else if (result != BfpFileResult_NoResults)
- {
- return false;
- }
- BfpDirectory_Delete(dirPath.c_str(), &result);
- return (result == BfpFileResult_Ok) && (!failed);
- }
- void Beefy::BFFatalError(const char* message, const char* file, int line)
- {
- BFFatalError(String(message), String(file), line);
- }
- bool Beefy::ParseMemorySpan(const StringImpl& str, void*& outPtr, int& outSize, StringImpl* outKey)
- {
- #ifndef BF_SMALL
- static int anonymousIdx = 0;
- if (str.StartsWith("@"))
- {
- int colon = (int)str.IndexOf(':');
- String addrStr = str.Substring(1, colon - 1);
- String lenStr = str.Substring(colon + 1);
- outPtr = (void*)(intptr)strtoll(addrStr.c_str(), NULL, 16);
- outSize = (int)strtol(lenStr.c_str(), NULL, 10);
- if (outKey != NULL)
- {
- int nextColon = (int)str.IndexOf(':', colon + 1);
- if (nextColon > 0)
- {
- *outKey = str.Substring(nextColon + 1);
- }
- else
- {
- int dotPos = (int)str.IndexOf('.', colon + 1);
- *outKey = StrFormat("ANON_%d", anonymousIdx++) + str.Substring(dotPos);
- }
- }
- return true;
- }
- #endif
- return false;
- }
|