2
0

Common.cpp 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420
  1. #include "Common.h"
  2. #include "util/BumpAllocator.h"
  3. #include "util/UTF8.h"
  4. #include "util/String.h"
  5. //#include "farts.z"
  6. #include <string.h>
  7. #include "platform/PlatformHelper.h"
  8. #ifndef BF_SMALL
  9. #define STB_SPRINTF_DECORATE(name) BF_stbsp_##name
  10. #define STB_SPRINTF_IMPLEMENTATION
  11. #include "third_party/stb/stb_sprintf.h"
  12. #endif
  13. extern "C"
  14. {
  15. #include "third_party/utf8proc/utf8proc.h"
  16. }
  17. #ifdef BF_PLATFORM_WINDOWS
  18. #include <shellapi.h>
  19. #include <direct.h>
  20. #endif
  21. #pragma warning(disable:4996)
  22. #pragma comment(lib, "winmm.lib")
  23. int gBFArgC;
  24. char** gBFArgV;
  25. #ifdef BUMPALLOC_ETW_TRACING
  26. VSHeapTracker::CHeapTracker* Beefy::BumpAllocator::mVSHeapTracker = NULL;
  27. #pragma comment(lib, "VSCustomNativeHeapEtwProvider.lib")
  28. #endif
  29. USING_NS_BF;
  30. UTF16String Beefy::ToWString(const StringImpl& theString)
  31. {
  32. UTF16String aString;
  33. aString.Reserve(theString.length() + 1);
  34. for (intptr i = 0; i < theString.length(); ++i)
  35. aString.Add((unsigned char)theString[i]);
  36. aString.Add(0);
  37. return aString;
  38. }
  39. // String Beefy::ToString(const UTF16String& theString)
  40. // {
  41. // String newString;
  42. // newString.Reserve((intptr)theString.length());
  43. // for (int i = 0; i < (int)theString.length(); ++i)
  44. // {
  45. // const unsigned int c = (unsigned int)theString[i];
  46. // newString.Append(char(c & 0xFF));
  47. // }
  48. // return newString;
  49. // }
  50. String Beefy::ToUpper(const StringImpl& theString)
  51. {
  52. String aString = theString;
  53. for (int i = 0; i < (int)aString.length(); ++i)
  54. aString[i] = toupper(aString[i]);
  55. return aString;
  56. }
  57. void Beefy::MakeUpper(StringImpl& theString)
  58. {
  59. for (int i = 0; i < (int)theString.length(); ++i)
  60. theString[i] = toupper(theString[i]);
  61. }
  62. UTF16String Beefy::ToUpper(const UTF16String& theString)
  63. {
  64. UTF16String aString = theString;
  65. for (int i = 0; i < (int)aString.length(); ++i)
  66. aString[i] = toupper(aString[i]);
  67. return aString;
  68. }
  69. UTF16String Beefy::ToLower(const UTF16String& theString)
  70. {
  71. UTF16String aString = theString;
  72. for (int i = 0; i < (int)aString.length(); ++i)
  73. aString[i] = tolower(aString[i]);
  74. return aString;
  75. }
  76. String Beefy::ToLower(const StringImpl& theString)
  77. {
  78. String aString = theString;
  79. for (int i = 0; i < (int)aString.length(); ++i)
  80. aString[i] = (char)tolower((int)(uint8)aString[i]);
  81. return aString;
  82. }
  83. // UTF16String Beefy::Trim(const UTF16String& theString)
  84. // {
  85. // int left = 0;
  86. // while ((left < (int) theString.length() - 1) && (iswspace(theString[left])))
  87. // left++;
  88. //
  89. // int right = (int)theString.length() - 1;
  90. // while ((right >= left) && (iswspace(theString[right])))
  91. // right--;
  92. //
  93. // if ((left == 0) && (right == theString.length() - 1))
  94. // return theString;
  95. //
  96. // return theString.substr(left, right - left + 1);
  97. // }
  98. String Beefy::Trim(const StringImpl& theString)
  99. {
  100. int left = 0;
  101. while ((left < (int) theString.length() - 1) && (iswspace(theString[left])))
  102. left++;
  103. int right = (int)theString.length() - 1;
  104. while ((right >= left) && (iswspace(theString[right])))
  105. right--;
  106. if ((left == 0) && (right == theString.length() - 1))
  107. return theString;
  108. return theString.Substring(left, right - left + 1);
  109. }
  110. bool Beefy::StrReplace(StringImpl& str, const StringImpl& from, const StringImpl& to)
  111. {
  112. str.Replace(from, to);
  113. return true;
  114. }
  115. bool Beefy::StrStartsWith(const StringImpl& str, const StringImpl& subStr)
  116. {
  117. if (subStr.length() < str.length())
  118. return false;
  119. return strncmp(str.c_str(), subStr.c_str(), subStr.length()) == 0;
  120. }
  121. bool Beefy::StrEndsWith(const StringImpl& str, const StringImpl& subStr)
  122. {
  123. if (subStr.length() < str.length())
  124. return false;
  125. return strncmp(str.c_str() - (str.length() - subStr.length()), subStr.c_str(), subStr.length()) == 0;
  126. }
  127. #ifndef BF_SMALL
  128. String Beefy::SlashString(const StringImpl& str, bool utf8decode, bool utf8encode, bool beefString)
  129. {
  130. bool prevEndedInSlashedNum = false;
  131. String outStr;
  132. bool noNextHex = false;
  133. bool lastWasVisibleChar = false;
  134. for (int idx = 0; idx < (int)str.length(); idx++)
  135. {
  136. bool endingInSlashedNum = false;
  137. char c = str[idx];
  138. if (noNextHex)
  139. {
  140. if (((c >= '0') && (c <= '9')) ||
  141. ((c >= 'a') && (c <= 'f')) ||
  142. ((c >= 'A') && (c <= 'F')))
  143. {
  144. outStr += "\"\"";
  145. }
  146. noNextHex = false;
  147. }
  148. bool isVisibleChar = false;
  149. switch (c)
  150. {
  151. case '\0':
  152. outStr += "\\0";
  153. endingInSlashedNum = true;
  154. break;
  155. case '\a':
  156. outStr += "\\a";
  157. break;
  158. case '\b':
  159. outStr += "\\b";
  160. break;
  161. case '\t':
  162. outStr += "\\t";
  163. break;
  164. case '\n':
  165. outStr += "\\n";
  166. break;
  167. case '\v':
  168. outStr += "\\v";
  169. break;
  170. case '\f':
  171. outStr += "\\f";
  172. break;
  173. case '\r':
  174. outStr += "\\r";
  175. break;
  176. case '\"':
  177. outStr += "\\\"";
  178. break;
  179. case '\\':
  180. outStr += "\\\\";
  181. break;
  182. default:
  183. {
  184. if ((c >= '0') && (c <= '9'))
  185. {
  186. // Need to break string to allow proper evaluation of slashed string
  187. if (prevEndedInSlashedNum)
  188. outStr += "\" \"";
  189. }
  190. // May be UTF8 byte. Make sure it's valid before we add it, otherwise write the bytes in direct "\x" style
  191. if (((uint8)c >= 0x80) && (utf8decode))
  192. {
  193. int seqLen = u8_seqlen((char*)&str[idx]);
  194. if (seqLen > 1)
  195. {
  196. if (idx + seqLen <= str.length())
  197. {
  198. uint32 c32 = u8_toucs((char*)&str[idx], (int)str.length() - idx);
  199. bool wantHex = false;
  200. // Combining mark without previous visible char?
  201. if ((((c32 >= L'\u0300') && (c32 <= L'\u036F')) || ((c32 >= L'\u1DC0') && (c32 <= L'\u1DFF'))) &&
  202. (!lastWasVisibleChar))
  203. wantHex = true;
  204. utf8proc_category_t cat = utf8proc_category(c32);
  205. switch (cat)
  206. {
  207. case UTF8PROC_CATEGORY_ZS:
  208. case UTF8PROC_CATEGORY_ZL:
  209. case UTF8PROC_CATEGORY_ZP:
  210. case UTF8PROC_CATEGORY_CC:
  211. case UTF8PROC_CATEGORY_CF:
  212. case UTF8PROC_CATEGORY_CO:
  213. wantHex = true;
  214. break;
  215. default:
  216. break;
  217. }
  218. if (wantHex)
  219. {
  220. if (beefString)
  221. {
  222. char tempStr[32];
  223. sprintf(tempStr, "\\u{%x}", c32);
  224. outStr += tempStr;
  225. idx += seqLen - 1;
  226. continue;
  227. }
  228. else
  229. {
  230. char tempStr[32];
  231. sprintf(tempStr, "\\u%04x", c32);
  232. outStr += tempStr;
  233. idx += seqLen - 1;
  234. noNextHex = true;
  235. continue;
  236. }
  237. }
  238. bool passed = true;
  239. for (int checkOfs = 0; checkOfs < seqLen - 1; checkOfs++)
  240. {
  241. char checkC = str[idx + checkOfs + 1];
  242. if ((checkC & 0xC0) != 0x80) // Has trailing signature (0x10xxxxxx)?
  243. passed = false;
  244. }
  245. if (passed)
  246. {
  247. outStr += c;
  248. for (int checkOfs = 0; checkOfs < seqLen - 1; checkOfs++)
  249. {
  250. char checkC = str[idx + checkOfs + 1];
  251. outStr += checkC;
  252. }
  253. idx += seqLen - 1;
  254. continue;
  255. }
  256. }
  257. }
  258. }
  259. if (((uint8)c >= 0x80) && (utf8encode))
  260. {
  261. outStr += (char)(0xC0 | (((uint8)c & 0xFF) >> 6));
  262. outStr += (char)(0x80 | ((uint8)c & 0x3F));
  263. isVisibleChar = true;
  264. continue;
  265. }
  266. if (((uint8)c >= 32) && ((uint8)c < 0x80))
  267. {
  268. outStr += c;
  269. isVisibleChar = true;
  270. }
  271. else
  272. {
  273. char tempStr[32];
  274. sprintf(tempStr, "\\x%02x", (uint8)c);
  275. outStr += tempStr;
  276. endingInSlashedNum = true;
  277. if (!beefString)
  278. noNextHex = true;
  279. }
  280. }
  281. break;
  282. }
  283. prevEndedInSlashedNum = endingInSlashedNum;
  284. lastWasVisibleChar = isVisibleChar;
  285. }
  286. return outStr;
  287. }
  288. #endif
  289. UTF16String Beefy::UTF8Decode(const StringImpl& theString)
  290. {
  291. UTF16String strOut;
  292. int strLen = 0;
  293. char* cPtr = (char*)theString.c_str();
  294. int lenLeft = (int)theString.length();
  295. while (lenLeft > 0)
  296. {
  297. int seqLen = 0;
  298. uint32 c32 = u8_toucs(cPtr, lenLeft, &seqLen);
  299. if ((c32 >= 0x10000) && (sizeof(wchar_t) == 2))
  300. strLen += 2;
  301. else
  302. strLen += 1;
  303. cPtr += seqLen;
  304. lenLeft -= seqLen;
  305. }
  306. strOut.ResizeRaw(strLen + 1);
  307. strOut[strLen] = 0;
  308. cPtr = (char*)theString.c_str();
  309. uint16* wcPtr = strOut.mVals;
  310. int wcLenLeft = (int)strOut.length() + 1;
  311. lenLeft = (int)theString.length();
  312. while (lenLeft > 0)
  313. {
  314. int seqLen = 0;
  315. uint32 c32 = u8_toucs(cPtr, lenLeft, &seqLen);
  316. if ((c32 >= 0x10000) && (sizeof(wchar_t) == 2))
  317. {
  318. *(wcPtr++) = (wchar_t)(((c32 - 0x10000) >> 10) + 0xD800);
  319. *(wcPtr++) = (wchar_t)(((c32 - 0x10000) & 0x3FF) + 0xDC00);
  320. wcLenLeft -= 2;
  321. }
  322. else
  323. {
  324. *(wcPtr++) = (wchar_t)c32;
  325. wcLenLeft -= 1;
  326. }
  327. cPtr += seqLen;
  328. lenLeft -= seqLen;
  329. }
  330. return strOut;
  331. }
  332. String Beefy::UTF8Encode(const uint16* theString, int length)
  333. {
  334. if (length == 0)
  335. return String();
  336. String strOut;
  337. int utf8Len = 0;
  338. uint16 utf16hi = 0;
  339. for (int i = 0; i < length; i++)
  340. {
  341. uint16 c = theString[i];
  342. uint32 c32 = c;
  343. if ((c >= 0xD800) && (c < 0xDC00))
  344. {
  345. utf16hi = (uint16)c;
  346. continue;
  347. }
  348. else if ((c >= 0xDC00) && (c < 0xE000))
  349. {
  350. uint16 utf16lo = c;
  351. c32 = 0x10000 + ((uint32)(utf16hi - 0xD800) << 10) | (uint32)(utf16lo - 0xDC00);
  352. }
  353. utf8Len += u8_seqlen(c32);
  354. }
  355. strOut.Append('?', utf8Len);
  356. char* cPtr = (char*)&strOut[0];
  357. int lenLeft = (int)strOut.length() + 1;
  358. for (int i = 0; i < length; i++)
  359. {
  360. uint16 c = theString[i];
  361. uint32 c32 = c;
  362. if ((c >= 0xD800) && (c < 0xDC00))
  363. {
  364. utf16hi = (uint16)c;
  365. continue;
  366. }
  367. else if ((c >= 0xDC00) && (c < 0xE000))
  368. {
  369. uint16 utf16lo = c;
  370. c32 = 0x10000 + ((uint32)(utf16hi - 0xD800) << 10) | (uint32)(utf16lo - 0xDC00);
  371. }
  372. int len = u8_toutf8(cPtr, lenLeft, c32);
  373. cPtr += len;
  374. lenLeft -= len;
  375. }
  376. return strOut;
  377. }
  378. String Beefy::UTF8Encode(const UTF16String& theString)
  379. {
  380. return UTF8Encode((uint16*)theString.c_str(), (int)theString.length());
  381. }
  382. UTF16String Beefy::UTF16Decode(const uint16* theString)
  383. {
  384. if (sizeof(wchar_t) == 2)
  385. {
  386. UTF16String str;
  387. str.Set((wchar_t*)theString);
  388. return str;
  389. }
  390. else
  391. {
  392. UTF16String str;
  393. int len = 0;
  394. while (theString[len] != 0)
  395. len++;
  396. str.ResizeRaw(len + 1);
  397. str[len] = 0;
  398. for (int pos = 0; pos < len; pos++)
  399. str[pos] = (wchar_t)theString[pos];
  400. return str;
  401. }
  402. }
  403. static const char gHexChar[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
  404. String Beefy::FileNameToURI(const StringImpl& fileName)
  405. {
  406. #ifdef _WIN32
  407. String out = "file:///";
  408. #else
  409. String out = "file://";
  410. #endif
  411. for (int i = 0; i < (int)fileName.length(); i++)
  412. {
  413. char c = out[i];
  414. bool isValid =
  415. ((c >= '@' && c <= 'Z') ||
  416. (c >= 'a' && c <= 'z') ||
  417. (c >= '&' && c < 0x3b) ||
  418. (c == '!') || (c == '$') || (c == '_') || (c == '=') || (c == '~'));
  419. if ((((unsigned char)c) >= 0x80) || (!isValid))
  420. {
  421. out += '%';
  422. out += gHexChar[((unsigned char)(c)) >> 4];
  423. out += gHexChar[((unsigned char)(c)) & 0xf];
  424. }
  425. else if (c == '\\')
  426. out += '/';
  427. else
  428. out += c;
  429. }
  430. return out;
  431. }
  432. 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,
  433. 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,
  434. 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,
  435. 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,
  436. 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,
  437. 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,
  438. 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,
  439. 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 };
  440. int64 Beefy::DecodeULEB32(const char*& p)
  441. {
  442. uint64 val = 0;
  443. unsigned shift = 0;
  444. uint8 charVal;
  445. do
  446. {
  447. charVal = cCharTo64b[(uint8)*(p++)];
  448. val += uint64(charVal & 0x1f) << shift;
  449. shift += 5;
  450. } while ((charVal & 0x20) != 0);
  451. return val;
  452. }
  453. static const char c64bToChar[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
  454. 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F',
  455. 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
  456. 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '_'};
  457. void Beefy::EncodeULEB32(uint64 value, StringImpl& buffer)
  458. {
  459. do
  460. {
  461. uint8 byteVal = value & 0x1f;
  462. value >>= 5;
  463. if (value != 0)
  464. byteVal |= 0x20; // Mark this byte to show that more bytes will follow
  465. buffer.Append(c64bToChar[byteVal]);
  466. }
  467. while (value != 0);
  468. }
  469. #ifndef BF_SMALL
  470. void Beefy::ExactMinimalFloatToStr(float f, char* str)
  471. {
  472. sprintf(str, "%1.9g", f);
  473. char* cPtrLast = str;
  474. while (true)
  475. {
  476. char c = cPtrLast[1];
  477. if ((c == 0) || (c == 'e'))
  478. break;
  479. cPtrLast++;
  480. }
  481. char* cStrEnd = cPtrLast + 1;
  482. int baseLen = (int)(cPtrLast - str) + 1;
  483. if (baseLen < 9)
  484. return; // Isn't "full" precision
  485. char removeChar;
  486. char lastChar = *cPtrLast;
  487. char secondToLast = cPtrLast[-1];
  488. if (secondToLast == '9')
  489. {
  490. removeChar = '9';
  491. }
  492. else if (secondToLast == '0')
  493. {
  494. removeChar = '0';
  495. }
  496. else
  497. {
  498. return; // Not a 'transitional' representation
  499. }
  500. do
  501. {
  502. *cPtrLast = 0;
  503. cPtrLast--;
  504. } while (*cPtrLast == removeChar);
  505. strcpy(cPtrLast + 1, cStrEnd);
  506. if (removeChar == '9')
  507. (*cPtrLast)++;
  508. // Verify that our pretty representation is equivalent
  509. float checkF = 0;
  510. sscanf(str, "%f", &checkF);
  511. if (f == checkF)
  512. return;
  513. // Rollback
  514. int endLen = (int)strlen(cPtrLast + 1);
  515. memmove(cStrEnd, cPtrLast + 1, endLen);
  516. if (removeChar == '9')
  517. (*cPtrLast)--;
  518. cPtrLast++;
  519. while (cPtrLast < cStrEnd - 1)
  520. {
  521. *cPtrLast = removeChar;
  522. cPtrLast++;
  523. }
  524. *cPtrLast = lastChar;
  525. }
  526. void Beefy::ExactMinimalDoubleToStr(double d, char* str)
  527. {
  528. sprintf(str, "%1.17g", d);
  529. char* cPtrLast = str;
  530. while (true)
  531. {
  532. char c = cPtrLast[1];
  533. if ((c == 0) || (c == 'e'))
  534. break;
  535. cPtrLast++;
  536. }
  537. char* cStrEnd = cPtrLast + 1;
  538. int baseLen = (int)(cPtrLast - str) + 1;
  539. if (baseLen < 18)
  540. return; // Isn't "full" precision
  541. char removeChar;
  542. char lastChar = *cPtrLast;
  543. if ((lastChar == '9') || (lastChar == '8'))
  544. {
  545. removeChar = '9';
  546. }
  547. else if ((lastChar == '1') || (lastChar == '2'))
  548. {
  549. removeChar = '0';
  550. }
  551. else
  552. {
  553. return; // Not a 'transitional' representation
  554. }
  555. do
  556. {
  557. *cPtrLast = 0;
  558. cPtrLast--;
  559. }
  560. while (*cPtrLast == removeChar);
  561. strcpy(cPtrLast + 1, cStrEnd);
  562. if (removeChar == '9')
  563. (*cPtrLast)++;
  564. // Verify that our pretty representation is equivalent
  565. double checkD = 0;
  566. sscanf(str, "%lf", &checkD);
  567. if (d == checkD)
  568. return;
  569. // Rollback
  570. int endLen = (int)strlen(cPtrLast + 1);
  571. memmove(cStrEnd, cPtrLast + 1, endLen);
  572. if (removeChar == '9')
  573. (*cPtrLast)--;
  574. cPtrLast++;
  575. while (cPtrLast < cStrEnd - 1)
  576. {
  577. *cPtrLast = removeChar;
  578. cPtrLast++;
  579. }
  580. *cPtrLast = lastChar;
  581. }
  582. #endif
  583. static char* StbspCallback(char *buf, void *user, int len)
  584. {
  585. ((StringImpl*)user)->Append(buf, len);
  586. return buf;
  587. }
  588. //extern "C" int _vsnprintf(char* const _Buffer, size_t const _BufferCount, char const* const _Format, va_list _ArgList, int zz);
  589. #ifdef BF_SMALL
  590. String Beefy::vformat(const char* fmt, va_list argPtr)
  591. {
  592. // We draw the line at a 1MB string.
  593. const int maxSize = 1000000;
  594. //va_list checkArgPtr = argPtr;
  595. //va_start(checkArgPtr, fmt);
  596. int argIdx = 0;
  597. char* newFmt = NULL;
  598. char tempBuff[2048];
  599. char* tempBuffPtr = tempBuff;
  600. for (int i = 0; fmt[i] != 0; i++)
  601. {
  602. if (fmt[i] == '%')
  603. {
  604. if (fmt[i + 1] == '%')
  605. {
  606. i++;
  607. continue;
  608. }
  609. #ifdef BF32
  610. bool isLongAddr = false;
  611. #else
  612. bool isLongAddr = true;
  613. #endif
  614. if ((fmt[i + 1] == 'l') && (fmt[i + 2] == '@'))
  615. {
  616. isLongAddr = true;
  617. i++;
  618. }
  619. if (fmt[i + 1] == '@')
  620. {
  621. if (newFmt == NULL)
  622. {
  623. newFmt = (char*)malloc(strlen(fmt) + 1);
  624. strcpy(newFmt, fmt);
  625. //newFmt = strdup(fmt);
  626. }
  627. newFmt[i + 1] = 's';
  628. const char*& argValPtr = *(const char**)((intptr*)argPtr + argIdx);
  629. if (isLongAddr)
  630. {
  631. int64 iVal = *(int64*)((intptr*)argPtr + argIdx);
  632. #ifdef BF32
  633. argIdx++; // Takes two spots
  634. #endif
  635. argValPtr = tempBuffPtr;
  636. int leftVal = (int)(iVal >> 32);
  637. if (leftVal != 0)
  638. {
  639. sprintf(tempBuffPtr, "%x", leftVal);
  640. tempBuffPtr += strlen(tempBuffPtr);
  641. }
  642. tempBuffPtr[0] = '\'';
  643. tempBuffPtr++;
  644. sprintf(tempBuffPtr, "%08x", (int)iVal);
  645. tempBuffPtr += strlen(tempBuffPtr) + 1;
  646. }
  647. else
  648. {
  649. int32 iVal = (int32)(intptr)argValPtr;
  650. argValPtr = tempBuffPtr;
  651. sprintf(tempBuffPtr, "%08x", iVal);
  652. tempBuffPtr += strlen(tempBuffPtr) + 1;
  653. }
  654. if (newFmt[i] == 'l')
  655. newFmt[i] = '+';
  656. }
  657. else
  658. {
  659. //const char*& argValPtr = va_arg(checkArgPtr, const char*);
  660. }
  661. argIdx++;
  662. }
  663. }
  664. if (newFmt != NULL)
  665. {
  666. Beefy::String retVal = vformat(newFmt, argPtr);
  667. free(newFmt);
  668. return retVal;
  669. }
  670. // If the string is less than 161 characters,
  671. // allocate it on the stack because this saves
  672. // the malloc/free time.
  673. const int bufSize = 161;
  674. char stackBuffer[bufSize];
  675. int attemptedSize = bufSize - 1;
  676. int numChars = 0;
  677. #ifdef _WIN32
  678. numChars = _vsnprintf(stackBuffer, attemptedSize, fmt, argPtr);
  679. #else
  680. numChars = vsnprintf(stackBuffer, attemptedSize, fmt, argPtr);
  681. #endif
  682. if ((numChars >= 0) && (numChars <= attemptedSize))
  683. {
  684. // Needed for case of 160-character printf thing
  685. stackBuffer[numChars] = '\0';
  686. // Got it on the first try.
  687. return String(stackBuffer);
  688. }
  689. // Now use the heap.
  690. char* heapBuffer = NULL;
  691. while (((numChars == -1) || (numChars > attemptedSize)) &&
  692. (attemptedSize < maxSize))
  693. {
  694. // Try a bigger size
  695. attemptedSize *= 2;
  696. heapBuffer = (char*)realloc(heapBuffer, (attemptedSize + 1));
  697. #ifdef _WIN32
  698. numChars = _vsnprintf(heapBuffer, attemptedSize, fmt, argPtr);
  699. #else
  700. numChars = vsnprintf(heapBuffer, attemptedSize, fmt, argPtr);
  701. #endif
  702. }
  703. if (numChars == -1)
  704. {
  705. free(heapBuffer);
  706. return "";
  707. }
  708. heapBuffer[numChars] = 0;
  709. Beefy::String aResult = Beefy::String(heapBuffer);
  710. free(heapBuffer);
  711. return aResult;
  712. }
  713. #else
  714. String Beefy::vformat(const char* fmt, va_list argPtr)
  715. {
  716. String str;
  717. char buf[STB_SPRINTF_MIN];
  718. BF_stbsp_vsprintfcb(StbspCallback, (void*)&str, buf, fmt, argPtr);
  719. return str;
  720. }
  721. void Beefy::vformat(StringImpl& str, const char* fmt, va_list argPtr)
  722. {
  723. char buf[STB_SPRINTF_MIN];
  724. BF_stbsp_vsprintfcb(StbspCallback, (void*)&str, buf, fmt, argPtr);
  725. }
  726. #endif
  727. String Beefy::StrFormat(const char* fmt ...)
  728. {
  729. va_list argList;
  730. va_start(argList, fmt);
  731. String aResult = vformat(fmt, argList);
  732. va_end(argList);
  733. return aResult;
  734. }
  735. String Beefy::IntPtrDynAddrFormat(intptr addr)
  736. {
  737. if ((addr & 0xFFFFFFFF00000000LL) == 0)
  738. return StrFormat("%08X", addr);
  739. return StrFormat("%p", addr);
  740. }
  741. void Beefy::OutputDebugStr(const StringImpl& theString)
  742. {
  743. const int maxLen = 0xFFFE;
  744. if (theString.length() > maxLen)
  745. {
  746. OutputDebugStr(theString.Substring(0, maxLen));
  747. OutputDebugStr(theString.Substring(maxLen));
  748. return;
  749. }
  750. BfpOutput_DebugString(theString.c_str());
  751. }
  752. void Beefy::OutputDebugStrF(const char* fmt ...)
  753. {
  754. va_list argList;
  755. va_start(argList, fmt);
  756. String aResult = vformat(fmt, argList);
  757. va_end(argList);
  758. OutputDebugStr(aResult);
  759. }
  760. uint8* Beefy::LoadBinaryData(const StringImpl& path, int* size)
  761. {
  762. FILE* fP = fopen(path.c_str(), "rb");
  763. if (fP == NULL)
  764. return NULL;
  765. fseek(fP, 0, SEEK_END);
  766. int aSize = (int32)ftell(fP);
  767. fseek(fP, 0, SEEK_SET);
  768. uint8* data = new uint8[aSize];
  769. int readSize = (int)fread(data, 1, aSize, fP);
  770. (void)readSize;
  771. fclose(fP);
  772. if (size)
  773. *size = aSize;
  774. return data;
  775. }
  776. char* Beefy::LoadTextData(const StringImpl& path, int* size)
  777. {
  778. FILE* fP = fopen(path.c_str(), "rb");
  779. if (fP == NULL)
  780. return NULL;
  781. fseek(fP, 0, SEEK_END);
  782. int fileSize = (int32)ftell(fP);
  783. int strLen = fileSize;
  784. fseek(fP, 0, SEEK_SET);
  785. uint8 charHeader[3] = {0};
  786. int readSize = (int)fread(charHeader, 1, 3, fP);
  787. if ((charHeader[0] == 0xFF) && (charHeader[1] == 0xFE))
  788. {
  789. //UTF16 LE
  790. int dataLen = fileSize - 2;
  791. char* data = new char[dataLen + 2];
  792. data[0] = (char)charHeader[2];
  793. data[dataLen] = 0;
  794. data[dataLen + 1] = 0;
  795. int readSize = (int)fread(data + 1, 1, dataLen - 1, fP);
  796. (void)readSize;
  797. fclose(fP);
  798. // UTF16
  799. UTF16String str;
  800. str.Set((wchar_t*)data);
  801. delete [] data;
  802. String utf8Str = UTF8Encode(str);
  803. char* utf8Data = new char[utf8Str.length() + 1];
  804. strLen = (int)utf8Str.length();
  805. if (size != NULL)
  806. *size = strLen;
  807. memcpy(utf8Data, utf8Str.c_str(), strLen);
  808. return utf8Data;
  809. }
  810. else if ((charHeader[0] == 0xEF) && (charHeader[1] == 0xBB) && (charHeader[2] == 0xBF))
  811. {
  812. strLen = fileSize - 3;
  813. char* data = new char[strLen + 1];
  814. data[strLen] = 0;
  815. if (size != NULL)
  816. *size = strLen;
  817. int readSize = (int)fread(data, 1, strLen, fP);
  818. (void)readSize;
  819. fclose(fP);
  820. return data;
  821. }
  822. if (size != NULL)
  823. *size = strLen;
  824. char* data = new char[strLen + 1];
  825. data[strLen] = 0;
  826. for (int i = 0; i < BF_MIN(3, strLen); i++)
  827. data[i] = charHeader[i];
  828. if (strLen > 3)
  829. {
  830. int readSize = (int)fread(data + 3, 1, strLen - 3, fP);
  831. (void)readSize;
  832. }
  833. fclose(fP);
  834. return data;
  835. }
  836. bool Beefy::LoadTextData(const StringImpl& path, StringImpl& str)
  837. {
  838. int size = 0;
  839. char* data = LoadTextData(path, &size);
  840. if (data == NULL)
  841. return false;
  842. if ((str.mAllocSizeAndFlags & StringImpl::DynAllocFlag) != 0)
  843. str.Release();
  844. str.mPtr = data;
  845. str.mAllocSizeAndFlags = size | StringImpl::DynAllocFlag | StringImpl::StrPtrFlag;
  846. str.mLength = size;
  847. return true;
  848. }
  849. #ifdef BF_MINGW
  850. unsigned long long __cdecl _byteswap_uint64(unsigned long long _Int64)
  851. {
  852. #ifdef _WIN64
  853. unsigned long long retval;
  854. __asm__ __volatile__ ("bswapq %[retval]" : [retval] "=rm" (retval) : "[retval]" (_Int64));
  855. return retval;
  856. #else
  857. union {
  858. long long int64part;
  859. struct {
  860. unsigned long lowpart;
  861. unsigned long hipart;
  862. };
  863. } retval;
  864. retval.int64part = _Int64;
  865. __asm__ __volatile__ ("bswapl %[lowpart]\n"
  866. "bswapl %[hipart]\n"
  867. : [lowpart] "=rm" (retval.hipart), [hipart] "=rm" (retval.lowpart) : "[lowpart]" (retval.lowpart), "[hipart]" (retval.hipart));
  868. return retval.int64part;
  869. #endif
  870. }
  871. #endif
  872. #ifdef _WIN32
  873. int64 Beefy::EndianSwap(int64 val)
  874. {
  875. return _byteswap_uint64(val);
  876. }
  877. #endif
  878. int32 Beefy::EndianSwap(int val)
  879. {
  880. return ((val & 0x000000FF) << 24) | ((val & 0x0000FF00) << 8) |
  881. ((val & 0x00FF0000) >> 8) | ((val & 0xFF000000) >> 24);
  882. }
  883. int16 Beefy::EndianSwap(int16 val)
  884. {
  885. return ((val & 0x00FF) << 8) | ((val & 0xFF00) >> 8);
  886. }
  887. int32 Beefy::Rand()
  888. {
  889. return (rand() & 0xFFFF) | ((rand() & 0x7FFF) << 16);
  890. }
  891. int32 Beefy::GetHighestBitSet(int32 n)
  892. {
  893. int i = 0;
  894. for (; n; n = (int)((uint32)n >> 1), i++)
  895. ; /* empty */
  896. return i;
  897. }
  898. String Beefy::GetFileDir(const StringImpl& path)
  899. {
  900. int slashPos = BF_MAX((int)path.LastIndexOf('\\'), (int)path.LastIndexOf('/'));
  901. if (slashPos == -1)
  902. return "";
  903. return path.Substring(0, slashPos);
  904. }
  905. String Beefy::GetFileName(const StringImpl& path)
  906. {
  907. int slashPos = BF_MAX((int)path.LastIndexOf('\\'), (int)path.LastIndexOf('/'));
  908. if (slashPos == -1)
  909. return path;
  910. return path.Substring(slashPos + 1);
  911. }
  912. String Beefy::GetFileExtension(const StringImpl& path)
  913. {
  914. int dotPos = (int)path.LastIndexOf('.');
  915. if (dotPos == -1)
  916. return path;
  917. return path.Substring(dotPos);
  918. }
  919. static String GetDriveStringTo(String path)
  920. {
  921. if ((path.length() >= 2) && (path[1] == ':'))
  922. return String(path, 0, 2);
  923. return "";
  924. }
  925. String Beefy::GetRelativePath(const StringImpl& fullPath, const StringImpl& curDir)
  926. {
  927. String curPath1 = String(curDir);
  928. String curPath2 = String(fullPath);
  929. for (int i = 0; i < (int)curPath1.length(); i++)
  930. if (curPath1[i] == DIR_SEP_CHAR_ALT)
  931. curPath1[i] = DIR_SEP_CHAR;
  932. for (int i = 0; i < (int)curPath2.length(); i++)
  933. if (curPath2[i] == DIR_SEP_CHAR_ALT)
  934. curPath2[i] = DIR_SEP_CHAR;
  935. String driveString1 = GetDriveStringTo(curPath1);
  936. String driveString2 = GetDriveStringTo(curPath2);
  937. #ifdef _WIN32
  938. StringImpl::CompareKind compareType = StringImpl::CompareKind_OrdinalIgnoreCase;
  939. #else
  940. StringImpl::CompareKind compareType = StringImpl::CompareKind_Ordinal;
  941. #endif
  942. // On separate drives?
  943. if (!driveString1.Equals(driveString2, compareType))
  944. {
  945. return fullPath;
  946. }
  947. if (driveString1.mLength > 0)
  948. curPath1.Remove(0, BF_MIN(driveString1.mLength + 1, curPath1.mLength));
  949. if (driveString2.mLength > 0)
  950. curPath2.Remove(0, BF_MIN(driveString2.mLength + 1, curPath2.mLength));
  951. while ((curPath1.mLength > 0) && (curPath2.mLength > 0))
  952. {
  953. int slashPos1 = (int)curPath1.IndexOf(DIR_SEP_CHAR);
  954. if (slashPos1 == -1)
  955. slashPos1 = curPath1.mLength;
  956. int slashPos2 = (int)curPath2.IndexOf(DIR_SEP_CHAR);
  957. if (slashPos2 == -1)
  958. slashPos2 = curPath2.mLength;
  959. String section1;
  960. section1.Append(StringView(curPath1, 0, slashPos1));
  961. String section2;
  962. section2.Append(StringView(curPath2, 0, slashPos2));
  963. if (!section1.Equals(section2, compareType))
  964. {
  965. // a/b/c
  966. // d/e/f
  967. while (curPath1.mLength > 0)
  968. {
  969. slashPos1 = (int)curPath1.IndexOf(DIR_SEP_CHAR);
  970. if (slashPos1 == -1)
  971. slashPos1 = curPath1.mLength;
  972. if (slashPos1 + 1 >= curPath1.mLength)
  973. curPath1.Clear();
  974. else
  975. curPath1.Remove(0, slashPos1 + 1);
  976. if (DIR_SEP_CHAR == '\\')
  977. curPath2.Insert(0, "..\\");
  978. else
  979. curPath2.Insert(0, "../");
  980. }
  981. }
  982. else
  983. {
  984. if (slashPos1 + 1 >= curPath1.mLength)
  985. curPath1.Clear();
  986. else
  987. curPath1.Remove(0, slashPos1 + 1);
  988. if (slashPos2 + 2 >= curPath2.mLength)
  989. curPath1 = "";
  990. else
  991. curPath2.Remove(0, slashPos2 + 1);
  992. }
  993. }
  994. return curPath2;
  995. }
  996. String Beefy::GetAbsPath(const StringImpl& relPathIn, const StringImpl& dir)
  997. {
  998. String relPath = relPathIn;
  999. String driveString = "";
  1000. String newPath;
  1001. newPath = dir;
  1002. for (int i = 0; i < (int)newPath.length(); i++)
  1003. if (newPath[i] == DIR_SEP_CHAR_ALT)
  1004. newPath[i] = DIR_SEP_CHAR;
  1005. for (int i = 0; i < (int)relPath.length(); i++)
  1006. if (relPath[i] == DIR_SEP_CHAR_ALT)
  1007. relPath[i] = DIR_SEP_CHAR;
  1008. if ((relPath.length() >= 2) && (relPath[1] == ':'))
  1009. return relPath;
  1010. char slashChar = DIR_SEP_CHAR;
  1011. if ((newPath.length() >= 2) && (newPath[1] == ':'))
  1012. {
  1013. driveString = newPath.Substring(0, 2);
  1014. newPath = newPath.Substring(2);
  1015. }
  1016. // Append a trailing slash if necessary
  1017. if ((newPath.length() > 0) && (newPath[newPath.length() - 1] != '\\') && (newPath[newPath.length() - 1] != '/'))
  1018. newPath += slashChar;
  1019. int relIdx = 0;
  1020. for (;;)
  1021. {
  1022. if (newPath.length() == 0)
  1023. break;
  1024. int firstSlash = -1;
  1025. for (int32 i = relIdx; i < (int)relPath.length(); i++)
  1026. if ((relPath[i] == '\\') || (relPath[i] == '/'))
  1027. {
  1028. firstSlash = i;
  1029. break;
  1030. }
  1031. if (firstSlash == -1)
  1032. break;
  1033. String chDir = relPath.Substring(relIdx, firstSlash - relIdx);
  1034. relIdx = firstSlash + 1;
  1035. if (chDir == "..")
  1036. {
  1037. int lastDirStart = (int)newPath.length() - 1;
  1038. while ((lastDirStart > 0) && (newPath[lastDirStart - 1] != '\\') && (newPath[lastDirStart - 1] != '/'))
  1039. lastDirStart--;
  1040. String lastDir = newPath.Substring(lastDirStart, newPath.length() - lastDirStart - 1);
  1041. if (lastDir == "..")
  1042. {
  1043. newPath += "..";
  1044. newPath += DIR_SEP_CHAR;
  1045. }
  1046. else
  1047. {
  1048. newPath.RemoveToEnd(lastDirStart);
  1049. }
  1050. }
  1051. else if (chDir == "")
  1052. {
  1053. newPath = DIR_SEP_CHAR;
  1054. break;
  1055. }
  1056. else if (chDir != ".")
  1057. {
  1058. newPath += chDir + slashChar;
  1059. break;
  1060. }
  1061. }
  1062. //newPath = driveString + newPath + tempRelPath;
  1063. newPath = driveString + newPath;
  1064. newPath += relPath.Substring(relIdx);
  1065. return newPath;
  1066. }
  1067. String Beefy::FixPath(const StringImpl& pathIn)
  1068. {
  1069. String path = pathIn;
  1070. for (int i = 0; i < (int)path.length(); i++)
  1071. {
  1072. if (path[i] == DIR_SEP_CHAR_ALT)
  1073. path[i] = DIR_SEP_CHAR;
  1074. if ((i > 0) && (path[i - 1] == '.') && (path[i] == '.'))
  1075. {
  1076. for (int checkIdx = i - 3; checkIdx >= 0; checkIdx--)
  1077. {
  1078. if ((path[checkIdx] == '\\') || (path[checkIdx] == '/'))
  1079. {
  1080. path = path.Substring(0, checkIdx) + path.Substring(i + 1);
  1081. i = checkIdx;
  1082. break;
  1083. }
  1084. }
  1085. }
  1086. }
  1087. return path;
  1088. }
  1089. String Beefy::FixPathAndCase(const StringImpl& pathIn)
  1090. {
  1091. if ((!pathIn.IsEmpty()) && (pathIn[0] == '$'))
  1092. return pathIn;
  1093. String path = FixPath(pathIn);
  1094. #ifdef _WIN32
  1095. for (int i = 0; i < (int)path.length(); ++i)
  1096. path[i] = toupper(path[i]);
  1097. #endif
  1098. return path;
  1099. }
  1100. String Beefy::EnsureEndsInSlash(const StringImpl& dir)
  1101. {
  1102. if ((dir[dir.length() - 1] != '/') && (dir[dir.length() - 1] != '\\'))
  1103. return dir + "/";
  1104. return dir;
  1105. }
  1106. String Beefy::RemoveTrailingSlash(const StringImpl& str)
  1107. {
  1108. if (str.length() != 0)
  1109. {
  1110. char c = str[str.length() - 1];
  1111. if ((c == '\\') || (c == '/'))
  1112. return str.Substring(0, str.length() - 1);
  1113. }
  1114. return str;
  1115. }
  1116. bool Beefy::FileNameEquals(const StringImpl& filePathA, const StringImpl& filePathB)
  1117. {
  1118. #ifdef _WIN32
  1119. if (filePathA.length() != filePathB.length())
  1120. return false;
  1121. const char* aPtr = filePathA.c_str();
  1122. const char* bPtr = filePathB.c_str();
  1123. while (true)
  1124. {
  1125. char a = *(aPtr++);
  1126. char b = *(bPtr++);
  1127. if (a == 0)
  1128. return true;
  1129. if (a == b)
  1130. continue;
  1131. if (a == '/')
  1132. a = '\\';
  1133. if (b == '/')
  1134. b = '\\';
  1135. if (a == b)
  1136. continue;
  1137. if (::toupper(a) == ::toupper(b))
  1138. continue;
  1139. return false;
  1140. }
  1141. #else
  1142. return strcmp(filePathA.c_str(), filePathB.c_str()) == 0;
  1143. #endif
  1144. }
  1145. bool Beefy::RecursiveCreateDirectory(const StringImpl& dirName)
  1146. {
  1147. int slashPos = -1;
  1148. for (int i = (int)dirName.length() - 1; i >= 0; i--)
  1149. {
  1150. char c = dirName[i];
  1151. if ((c == '\\') || (c == '/'))
  1152. {
  1153. slashPos = i;
  1154. break;
  1155. }
  1156. }
  1157. if (slashPos != -1)
  1158. {
  1159. RecursiveCreateDirectory(dirName.Substring(0, slashPos));
  1160. }
  1161. BfpFileResult result;
  1162. BfpDirectory_Create(dirName.c_str(), &result);
  1163. return result == BfpFileResult_Ok;
  1164. }
  1165. bool Beefy::RecursiveDeleteDirectory(const StringImpl& dirPath)
  1166. {
  1167. String findSpec = dirPath + "/*.*";
  1168. bool failed = false;
  1169. BfpFileResult result;
  1170. BfpFindFileData* findFileData = BfpFindFileData_FindFirstFile(findSpec.c_str(), (BfpFindFileFlags)(BfpFindFileFlag_Directories | BfpFindFileFlag_Files), &result);
  1171. if (result == BfpFileResult_Ok)
  1172. {
  1173. while (true)
  1174. {
  1175. Beefy::String fileName;
  1176. BFP_GETSTR_HELPER(fileName, result, BfpFindFileData_GetFileName(findFileData, __STR, __STRLEN, &result));
  1177. String filePath = dirPath + "/" + fileName;
  1178. if ((BfpFindFileData_GetFileAttributes(findFileData) & BfpFileAttribute_Directory) != 0)
  1179. {
  1180. if (!RecursiveDeleteDirectory(filePath))
  1181. failed = true;
  1182. }
  1183. else
  1184. {
  1185. BfpFile_Delete(filePath.c_str(), &result);
  1186. if (result != BfpFileResult_Ok)
  1187. failed = true;
  1188. }
  1189. if (!BfpFindFileData_FindNextFile(findFileData))
  1190. break;
  1191. }
  1192. BfpFindFileData_Release(findFileData);
  1193. }
  1194. else if (result != BfpFileResult_NoResults)
  1195. {
  1196. return false;
  1197. }
  1198. BfpDirectory_Delete(dirPath.c_str(), &result);
  1199. return (result == BfpFileResult_Ok) && (!failed);
  1200. }
  1201. void Beefy::BFFatalError(const char* message, const char* file, int line)
  1202. {
  1203. BFFatalError(String(message), String(file), line);
  1204. }
  1205. bool Beefy::ParseMemorySpan(const StringImpl& str, void*& outPtr, int& outSize, StringImpl* outKey)
  1206. {
  1207. #ifndef BF_SMALL
  1208. static int anonymousIdx = 0;
  1209. if (str.StartsWith("@"))
  1210. {
  1211. int colon = (int)str.IndexOf(':');
  1212. String addrStr = str.Substring(1, colon - 1);
  1213. String lenStr = str.Substring(colon + 1);
  1214. outPtr = (void*)(intptr)strtoll(addrStr.c_str(), NULL, 16);
  1215. outSize = (int)strtol(lenStr.c_str(), NULL, 10);
  1216. if (outKey != NULL)
  1217. {
  1218. int nextColon = (int)str.IndexOf(':', colon + 1);
  1219. if (nextColon > 0)
  1220. {
  1221. *outKey = str.Substring(nextColon + 1);
  1222. }
  1223. else
  1224. {
  1225. int dotPos = (int)str.IndexOf('.', colon + 1);
  1226. *outKey = StrFormat("ANON_%d", anonymousIdx++) + str.Substring(dotPos);
  1227. }
  1228. }
  1229. return true;
  1230. }
  1231. #endif
  1232. return false;
  1233. }