2
0

Helpers.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "stdafx.h"
  6. #include <sys/stat.h>
  7. #define MAX_URI_LENGTH 512
  8. //TODO: x-plat definitions
  9. #ifdef _WIN32
  10. #define TTD_MAX_FILE_LENGTH MAX_PATH
  11. #define TTD_HOST_PATH_SEP "\\"
  12. #else
  13. #define TTD_MAX_FILE_LENGTH MAX_URI_LENGTH
  14. #define TTD_HOST_PATH_SEP "/"
  15. #endif
  16. void TTDHostBuildCurrentExeDirectory(char* path, size_t* pathLength, size_t bufferLength)
  17. {
  18. char exePath[TTD_MAX_FILE_LENGTH];
  19. PlatformAgnostic::SystemInfo::GetBinaryLocation(exePath, TTD_MAX_FILE_LENGTH);
  20. size_t i = strlen(exePath) - 1;
  21. while (exePath[i] != TTD_HOST_PATH_SEP[0] && i != 0)
  22. {
  23. --i;
  24. }
  25. if (i == 0)
  26. {
  27. fwprintf(stderr, _u("Can't get current exe directory"));
  28. exit(1);
  29. }
  30. if (i + 2 > bufferLength)
  31. {
  32. fwprintf(stderr, _u("Don't overflow path buffer during copy"));
  33. exit(1);
  34. }
  35. memcpy_s(path, bufferLength, exePath, i + 1);
  36. *pathLength = i + 1;
  37. path[*pathLength] = '\0';
  38. }
  39. #ifdef _WIN32
  40. int TTDHostMKDir(const char* path, size_t pathLength)
  41. {
  42. char16 cpath[MAX_PATH];
  43. LPCUTF8 pathbase = (LPCUTF8)path;
  44. if(MAX_PATH <= pathLength) //<= to account for null terminator
  45. {
  46. wprintf(_u("Don't overflow path buffer during conversion"));
  47. exit(1);
  48. }
  49. utf8::DecodeUnitsIntoAndNullTerminate(cpath, pathbase, pathbase + pathLength);
  50. return _wmkdir(cpath);
  51. }
  52. JsTTDStreamHandle TTDHostOpen(size_t pathLength, const char* path, bool isWrite)
  53. {
  54. char16 wpath[MAX_PATH];
  55. LPCUTF8 pathbase = (LPCUTF8)path;
  56. if(MAX_PATH <= pathLength) //<= to account for null terminator
  57. {
  58. wprintf(_u("Don't overflow path buffer during conversion"));
  59. exit(1);
  60. }
  61. utf8::DecodeUnitsIntoAndNullTerminate(wpath, pathbase, pathbase + pathLength);
  62. FILE* res = nullptr;
  63. _wfopen_s(&res, wpath, isWrite ? _u("w+b") : _u("r+b"));
  64. return (JsTTDStreamHandle)res;
  65. }
  66. #define TTDHostRead(buff, size, handle) fread_s(buff, size, 1, size, (FILE*)handle);
  67. #define TTDHostWrite(buff, size, handle) fwrite(buff, 1, size, (FILE*)handle)
  68. #else
  69. int TTDHostMKDir(const char* path, size_t pathLength)
  70. {
  71. return mkdir(path, 0700);
  72. }
  73. JsTTDStreamHandle TTDHostOpen(size_t pathLength, const char* path, bool isWrite)
  74. {
  75. return (JsTTDStreamHandle)fopen(path, isWrite ? "w+b" : "r+b");
  76. }
  77. #define TTDHostRead(buff, size, handle) fread(buff, 1, size, (FILE*)handle)
  78. #define TTDHostWrite(buff, size, handle) fwrite(buff, 1, size, (FILE*)handle)
  79. #endif
  80. int GetPathNameLocation(LPCSTR filename)
  81. {
  82. int filenameLength = (int) strlen(filename);
  83. int pos;
  84. if (filenameLength <= 0)
  85. {
  86. return -1;
  87. }
  88. for (pos = filenameLength - 1; pos >= 0; pos--)
  89. {
  90. char ch = filename[pos];
  91. if (ch == '/' || ch == '\\') break;
  92. }
  93. return pos;
  94. }
  95. inline void pathcpy(char * target, LPCSTR src, uint length)
  96. {
  97. #ifndef _WIN32
  98. for (int i = 0; i < length; i++)
  99. {
  100. if (src[i] == '\\')
  101. {
  102. target[i] = '/';
  103. }
  104. else
  105. {
  106. target[i] = src[i];
  107. }
  108. }
  109. #else
  110. memcpy(target, src, length);
  111. #endif
  112. }
  113. uint ConcatPath(LPCSTR filenameLeft, uint posPathSep, LPCSTR filenameRight, char* buffer, uint bufferLength)
  114. {
  115. int filenameRightLength = (int) strlen(filenameRight);
  116. // [ path[/] ] + [filename] + /0
  117. uint totalLength = posPathSep + filenameRightLength + 1;
  118. if (buffer == nullptr)
  119. {
  120. return totalLength;
  121. }
  122. if (bufferLength < totalLength)
  123. {
  124. fprintf(stderr, "Error: file path is too long.\n");
  125. return (uint)-1;
  126. }
  127. pathcpy(buffer, filenameLeft, posPathSep);
  128. buffer += posPathSep;
  129. pathcpy(buffer, filenameRight, filenameRightLength);
  130. buffer += filenameRightLength;
  131. buffer[0] = char(0);
  132. return totalLength;
  133. }
  134. HRESULT Helpers::LoadScriptFromFile(LPCSTR filenameToLoad, LPCSTR& contents, UINT* lengthBytesOut /*= nullptr*/, std::string* fullPath /*= nullptr*/, bool shouldMute /*=false */)
  135. {
  136. static char sHostApplicationPathBuffer[MAX_URI_LENGTH];
  137. static uint sHostApplicationPathBufferLength = (uint) -1;
  138. char combinedPathBuffer[MAX_URI_LENGTH];
  139. HRESULT hr = S_OK;
  140. BYTE * pRawBytes = nullptr;
  141. BYTE * pRawBytesFromMap = nullptr;
  142. UINT lengthBytes = 0;
  143. contents = nullptr;
  144. FILE * file = NULL;
  145. size_t bufferLength = 0;
  146. LPCSTR filename = fullPath == nullptr ? filenameToLoad : LPCSTR(fullPath->c_str());
  147. if (sHostApplicationPathBufferLength == (uint)-1)
  148. {
  149. // consider incoming filename as the host app and base its' path for others
  150. sHostApplicationPathBufferLength = GetPathNameLocation(filename);
  151. if (sHostApplicationPathBufferLength == -1)
  152. {
  153. // host app has no path info. (it must be located on current folder!)
  154. sHostApplicationPathBufferLength = 0;
  155. }
  156. else
  157. {
  158. sHostApplicationPathBufferLength += 1;
  159. Assert(sHostApplicationPathBufferLength < MAX_URI_LENGTH);
  160. // save host app's path and fix the path separator for platform
  161. pathcpy(sHostApplicationPathBuffer, filename, sHostApplicationPathBufferLength);
  162. }
  163. sHostApplicationPathBuffer[sHostApplicationPathBufferLength] = char(0);
  164. }
  165. else if (filename[0] != '/' && filename[0] != '\\' && fullPath == nullptr) // make sure it's not a full path
  166. {
  167. // concat host path and filename
  168. uint len = ConcatPath(sHostApplicationPathBuffer, sHostApplicationPathBufferLength,
  169. filename, combinedPathBuffer, MAX_URI_LENGTH);
  170. if (len == (uint)-1)
  171. {
  172. hr = E_FAIL;
  173. goto Error;
  174. }
  175. filename = combinedPathBuffer;
  176. }
  177. // check if have it registered
  178. AutoString *data;
  179. if (SourceMap::Find(filenameToLoad, strlen(filenameToLoad), &data) ||
  180. SourceMap::Find(filename, strlen(filename), &data))
  181. {
  182. pRawBytesFromMap = (BYTE*) data->GetString();
  183. lengthBytes = (UINT) data->GetLength();
  184. }
  185. else
  186. {
  187. // Open the file as a binary file to prevent CRT from handling encoding, line-break conversions,
  188. // etc.
  189. if (fopen_s(&file, filename, "rb") != 0)
  190. {
  191. if (!HostConfigFlags::flags.MuteHostErrorMsgIsEnabled && !shouldMute)
  192. {
  193. #ifdef _WIN32
  194. DWORD lastError = GetLastError();
  195. char16 wszBuff[MAX_URI_LENGTH];
  196. fprintf(stderr, "Error in opening file '%s' ", filename);
  197. wszBuff[0] = 0;
  198. if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
  199. nullptr,
  200. lastError,
  201. 0,
  202. wszBuff,
  203. _countof(wszBuff),
  204. nullptr))
  205. {
  206. fwprintf(stderr, _u(": %s"), wszBuff);
  207. }
  208. fwprintf(stderr, _u("\n"));
  209. #elif defined(_POSIX_VERSION)
  210. fprintf(stderr, "Error in opening file: ");
  211. perror(filename);
  212. #endif
  213. }
  214. IfFailGo(E_FAIL);
  215. }
  216. }
  217. if (file != NULL)
  218. {
  219. // Determine the file length, in bytes.
  220. fseek(file, 0, SEEK_END);
  221. lengthBytes = ftell(file);
  222. fseek(file, 0, SEEK_SET);
  223. }
  224. if (lengthBytes != 0)
  225. {
  226. bufferLength = lengthBytes + sizeof(BYTE);
  227. pRawBytes = (LPBYTE)malloc(bufferLength);
  228. }
  229. else
  230. {
  231. bufferLength = 1;
  232. pRawBytes = (LPBYTE)malloc(bufferLength);
  233. }
  234. if (nullptr == pRawBytes)
  235. {
  236. fwprintf(stderr, _u("out of memory"));
  237. IfFailGo(E_OUTOFMEMORY);
  238. }
  239. if (lengthBytes != 0)
  240. {
  241. if (file != NULL)
  242. {
  243. //
  244. // Read the entire content as a binary block.
  245. //
  246. size_t readBytes = fread(pRawBytes, sizeof(BYTE), lengthBytes, file);
  247. if (readBytes < lengthBytes * sizeof(BYTE))
  248. {
  249. IfFailGo(E_FAIL);
  250. }
  251. }
  252. else // from module source register
  253. {
  254. // Q: module source is on persistent memory. Why do we use the copy instead?
  255. // A: if we use the same memory twice, ch doesn't know that during FinalizeCallback free.
  256. // the copy memory will be freed by the finalizer
  257. Assert(pRawBytesFromMap);
  258. memcpy_s(pRawBytes, bufferLength, pRawBytesFromMap, lengthBytes);
  259. }
  260. }
  261. if (pRawBytes)
  262. {
  263. pRawBytes[lengthBytes] = 0; // Null terminate it. Could be UTF16
  264. }
  265. if (file != NULL)
  266. {
  267. //
  268. // Read encoding to make sure it's supported
  269. //
  270. // Warning: The UNICODE buffer for parsing is supposed to be provided by the host.
  271. // This is not a complete read of the encoding. Some encodings like UTF7, UTF1, EBCDIC, SCSU, BOCU could be
  272. // wrongly classified as ANSI
  273. //
  274. #pragma warning(push)
  275. // suppressing prefast warning that "readable size is bufferLength
  276. // bytes but 2 may be read" as bufferLength is clearly > 2 in the code that follows
  277. #pragma warning(disable:6385)
  278. C_ASSERT(sizeof(WCHAR) == 2);
  279. if (bufferLength > 2)
  280. {
  281. __analysis_assume(bufferLength > 2);
  282. #pragma prefast(push)
  283. #pragma prefast(disable:6385, "PREfast incorrectly reports this as an out-of-bound access.");
  284. if ((pRawBytes[0] == 0xFE && pRawBytes[1] == 0xFF) ||
  285. (pRawBytes[0] == 0xFF && pRawBytes[1] == 0xFE) ||
  286. (bufferLength > 4 && pRawBytes[0] == 0x00 && pRawBytes[1] == 0x00 &&
  287. ((pRawBytes[2] == 0xFE && pRawBytes[3] == 0xFF) ||
  288. (pRawBytes[2] == 0xFF && pRawBytes[3] == 0xFE))))
  289. {
  290. // unicode unsupported
  291. fwprintf(stderr, _u("unsupported file encoding. Only ANSI and UTF8 supported"));
  292. IfFailGo(E_UNEXPECTED);
  293. }
  294. #pragma prefast(pop)
  295. }
  296. #pragma warning(pop)
  297. }
  298. contents = reinterpret_cast<LPCSTR>(pRawBytes);
  299. Error:
  300. if (SUCCEEDED(hr))
  301. {
  302. if (lengthBytesOut)
  303. {
  304. *lengthBytesOut = lengthBytes;
  305. }
  306. }
  307. if (file != NULL)
  308. {
  309. fclose(file);
  310. }
  311. if (pRawBytes && reinterpret_cast<LPCSTR>(pRawBytes) != contents)
  312. {
  313. free(pRawBytes);
  314. }
  315. return hr;
  316. }
  317. LPCWSTR Helpers::JsErrorCodeToString(JsErrorCode jsErrorCode)
  318. {
  319. bool hasException = false;
  320. ChakraRTInterface::JsHasException(&hasException);
  321. if (hasException)
  322. {
  323. WScriptJsrt::PrintException("", JsErrorScriptException);
  324. }
  325. switch (jsErrorCode)
  326. {
  327. case JsNoError: return _u("JsNoError");
  328. // JsErrorCategoryUsage
  329. case JsErrorCategoryUsage: return _u("JsErrorCategoryUsage");
  330. case JsErrorInvalidArgument: return _u("JsErrorInvalidArgument");
  331. case JsErrorNullArgument: return _u("JsErrorNullArgument");
  332. case JsErrorNoCurrentContext: return _u("JsErrorNoCurrentContext");
  333. case JsErrorInExceptionState: return _u("JsErrorInExceptionState");
  334. case JsErrorNotImplemented: return _u("JsErrorNotImplemented");
  335. case JsErrorWrongThread: return _u("JsErrorWrongThread");
  336. case JsErrorRuntimeInUse: return _u("JsErrorRuntimeInUse");
  337. case JsErrorBadSerializedScript: return _u("JsErrorBadSerializedScript");
  338. case JsErrorInDisabledState: return _u("JsErrorInDisabledState");
  339. case JsErrorCannotDisableExecution: return _u("JsErrorCannotDisableExecution");
  340. case JsErrorHeapEnumInProgress: return _u("JsErrorHeapEnumInProgress");
  341. case JsErrorArgumentNotObject: return _u("JsErrorArgumentNotObject");
  342. case JsErrorInProfileCallback: return _u("JsErrorInProfileCallback");
  343. case JsErrorInThreadServiceCallback: return _u("JsErrorInThreadServiceCallback");
  344. case JsErrorCannotSerializeDebugScript: return _u("JsErrorCannotSerializeDebugScript");
  345. case JsErrorAlreadyDebuggingContext: return _u("JsErrorAlreadyDebuggingContext");
  346. case JsErrorAlreadyProfilingContext: return _u("JsErrorAlreadyProfilingContext");
  347. case JsErrorIdleNotEnabled: return _u("JsErrorIdleNotEnabled");
  348. case JsErrorInObjectBeforeCollectCallback: return _u("JsErrorInObjectBeforeCollectCallback");
  349. case JsErrorObjectNotInspectable: return _u("JsErrorObjectNotInspectable");
  350. case JsErrorPropertyNotSymbol: return _u("JsErrorPropertyNotSymbol");
  351. case JsErrorPropertyNotString: return _u("JsErrorPropertyNotString");
  352. case JsErrorInvalidContext: return _u("JsErrorInvalidContext");
  353. case JsInvalidModuleHostInfoKind: return _u("JsInvalidModuleHostInfoKind");
  354. case JsErrorModuleParsed: return _u("JsErrorModuleParsed");
  355. // JsErrorCategoryEngine
  356. case JsErrorCategoryEngine: return _u("JsErrorCategoryEngine");
  357. case JsErrorOutOfMemory: return _u("JsErrorOutOfMemory");
  358. case JsErrorBadFPUState: return _u("JsErrorBadFPUState");
  359. // JsErrorCategoryScript
  360. case JsErrorCategoryScript: return _u("JsErrorCategoryScript");
  361. case JsErrorScriptException: return _u("JsErrorScriptException");
  362. case JsErrorScriptCompile: return _u("JsErrorScriptCompile");
  363. case JsErrorScriptTerminated: return _u("JsErrorScriptTerminated");
  364. case JsErrorScriptEvalDisabled: return _u("JsErrorScriptEvalDisabled");
  365. // JsErrorCategoryFatal
  366. case JsErrorCategoryFatal: return _u("JsErrorCategoryFatal");
  367. case JsErrorFatal: return _u("JsErrorFatal");
  368. case JsErrorWrongRuntime: return _u("JsErrorWrongRuntime");
  369. // JsErrorCategoryDiagError
  370. case JsErrorCategoryDiagError: return _u("JsErrorCategoryDiagError");
  371. case JsErrorDiagAlreadyInDebugMode: return _u("JsErrorDiagAlreadyInDebugMode");
  372. case JsErrorDiagNotInDebugMode: return _u("JsErrorDiagNotInDebugMode");
  373. case JsErrorDiagNotAtBreak: return _u("JsErrorDiagNotAtBreak");
  374. case JsErrorDiagInvalidHandle: return _u("JsErrorDiagInvalidHandle");
  375. case JsErrorDiagObjectNotFound: return _u("JsErrorDiagObjectNotFound");
  376. case JsErrorDiagUnableToPerformAction: return _u("JsErrorDiagUnableToPerformAction");
  377. default:
  378. return _u("<unknown>");
  379. break;
  380. }
  381. }
  382. void Helpers::LogError(__in __nullterminated const char16 *msg, ...)
  383. {
  384. va_list args;
  385. va_start(args, msg);
  386. wprintf(_u("ERROR: "));
  387. vfwprintf(stderr, msg, args);
  388. wprintf(_u("\n"));
  389. fflush(stdout);
  390. va_end(args);
  391. }
  392. HRESULT Helpers::LoadBinaryFile(LPCSTR filename, LPCSTR& contents, UINT& lengthBytes, bool printFileOpenError)
  393. {
  394. HRESULT hr = S_OK;
  395. contents = nullptr;
  396. lengthBytes = 0;
  397. size_t result;
  398. FILE * file;
  399. //
  400. // Open the file as a binary file to prevent CRT from handling encoding, line-break conversions,
  401. // etc.
  402. //
  403. if (fopen_s(&file, filename, "rb") != 0)
  404. {
  405. if (printFileOpenError)
  406. {
  407. fprintf(stderr, "Error in opening file '%s' ", filename);
  408. #ifdef _WIN32
  409. DWORD lastError = GetLastError();
  410. char16 wszBuff[MAX_URI_LENGTH];
  411. wszBuff[0] = 0;
  412. if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
  413. nullptr,
  414. lastError,
  415. 0,
  416. wszBuff,
  417. _countof(wszBuff),
  418. nullptr))
  419. {
  420. fwprintf(stderr, _u(": %s"), wszBuff);
  421. }
  422. #endif
  423. fprintf(stderr, "\n");
  424. }
  425. return E_FAIL;
  426. }
  427. // file will not be nullptr if _wfopen_s succeeds
  428. __analysis_assume(file != nullptr);
  429. //
  430. // Determine the file length, in bytes.
  431. //
  432. fseek(file, 0, SEEK_END);
  433. lengthBytes = ftell(file);
  434. fseek(file, 0, SEEK_SET);
  435. contents = (LPCSTR)HeapAlloc(GetProcessHeap(), 0, lengthBytes);
  436. if (nullptr == contents)
  437. {
  438. fwprintf(stderr, _u("out of memory"));
  439. IfFailGo(E_OUTOFMEMORY);
  440. }
  441. //
  442. // Read the entire content as a binary block.
  443. //
  444. result = fread((void*)contents, sizeof(char), lengthBytes, file);
  445. if (result != lengthBytes)
  446. {
  447. fwprintf(stderr, _u("Read error"));
  448. IfFailGo(E_FAIL);
  449. }
  450. Error:
  451. fclose(file);
  452. if (contents && FAILED(hr))
  453. {
  454. HeapFree(GetProcessHeap(), 0, (void*)contents);
  455. contents = nullptr;
  456. }
  457. return hr;
  458. }
  459. void Helpers::TTReportLastIOErrorAsNeeded(BOOL ok, const char* msg)
  460. {
  461. if(!ok)
  462. {
  463. #ifdef _WIN32
  464. DWORD lastError = GetLastError();
  465. LPTSTR pTemp = NULL;
  466. FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, lastError, 0, (LPTSTR)&pTemp, 0, NULL);
  467. fwprintf(stderr, _u("Error is: %s\n"), pTemp);
  468. LocalFree(pTemp);
  469. #else
  470. fprintf(stderr, "Error is: %i %s\n", errno, strerror(errno));
  471. #endif
  472. fprintf(stderr, "Message is: %s\n", msg);
  473. AssertMsg(false, "IO Error!!!");
  474. exit(1);
  475. }
  476. }
  477. //We assume bounded ascii path length for simplicity
  478. #define MAX_TTD_ASCII_PATH_EXT_LENGTH 64
  479. void Helpers::CreateTTDDirectoryAsNeeded(size_t* uriLength, char* uri, const char* asciiDir1, const wchar* asciiDir2)
  480. {
  481. if(*uriLength + strlen(asciiDir1) + wcslen(asciiDir2) + 2 > MAX_URI_LENGTH || strlen(asciiDir1) >= MAX_TTD_ASCII_PATH_EXT_LENGTH || wcslen(asciiDir2) >= MAX_TTD_ASCII_PATH_EXT_LENGTH)
  482. {
  483. wprintf(_u("We assume bounded MAX_URI_LENGTH for simplicity.\n"));
  484. wprintf(_u("%S, %S, %ls\n"), uri, asciiDir1, asciiDir2);
  485. exit(1);
  486. }
  487. int success = 0;
  488. int extLength = 0;
  489. extLength = sprintf_s(uri + *uriLength, MAX_TTD_ASCII_PATH_EXT_LENGTH, "%s%s", asciiDir1, TTD_HOST_PATH_SEP);
  490. if(extLength == -1 || MAX_URI_LENGTH < (*uriLength) + extLength)
  491. {
  492. wprintf(_u("Failed directory extension 1.\n"));
  493. wprintf(_u("%S, %S, %ls\n"), uri, asciiDir1, asciiDir2);
  494. exit(1);
  495. }
  496. *uriLength += extLength;
  497. success = TTDHostMKDir(uri, *uriLength);
  498. if(success != 0)
  499. {
  500. //we may fail because someone else created the directory -- that is ok
  501. Helpers::TTReportLastIOErrorAsNeeded(errno == EEXIST, "Failed to create directory");
  502. }
  503. char realAsciiDir2[MAX_TTD_ASCII_PATH_EXT_LENGTH];
  504. size_t asciiDir2Length = wcslen(asciiDir2) + 1;
  505. for(size_t i = 0; i < asciiDir2Length; ++i)
  506. {
  507. if(asciiDir2[i] > CHAR_MAX)
  508. {
  509. wprintf(_u("Test directory names can only include ascii chars.\n"));
  510. exit(1);
  511. }
  512. realAsciiDir2[i] = (char)asciiDir2[i];
  513. }
  514. extLength = sprintf_s(uri + *uriLength, MAX_TTD_ASCII_PATH_EXT_LENGTH, "%s%s", realAsciiDir2, TTD_HOST_PATH_SEP);
  515. if(extLength == -1 || MAX_URI_LENGTH < *uriLength + extLength)
  516. {
  517. wprintf(_u("Failed directory create 2.\n"));
  518. wprintf(_u("%S, %S, %ls\n"), uri, asciiDir1, asciiDir2);
  519. exit(1);
  520. }
  521. *uriLength += extLength;
  522. success = TTDHostMKDir(uri, *uriLength);
  523. if(success != 0)
  524. {
  525. //we may fail because someone else created the directory -- that is ok
  526. Helpers::TTReportLastIOErrorAsNeeded(errno == EEXIST, "Failed to create directory");
  527. }
  528. }
  529. void Helpers::GetTTDDirectory(const wchar* curi, size_t* uriLength, char* uri, size_t bufferLength)
  530. {
  531. TTDHostBuildCurrentExeDirectory(uri, uriLength, bufferLength);
  532. Helpers::CreateTTDDirectoryAsNeeded(uriLength, uri, "_ttdlog", curi);
  533. }
  534. JsTTDStreamHandle CALLBACK Helpers::TTCreateStreamCallback(size_t uriLength, const char* uri, size_t asciiNameLength, const char* asciiName, bool read, bool write)
  535. {
  536. AssertMsg((read | write) & (!read | !write), "Read/Write streams not supported yet -- defaulting to read only");
  537. if(uriLength + asciiNameLength + 1 > MAX_URI_LENGTH)
  538. {
  539. wprintf(_u("We assume bounded MAX_URI_LENGTH for simplicity."));
  540. exit(1);
  541. }
  542. char path[MAX_URI_LENGTH];
  543. memset(path, 0, MAX_URI_LENGTH);
  544. memcpy_s(path, MAX_URI_LENGTH, uri, uriLength);
  545. memcpy_s(path + uriLength, MAX_URI_LENGTH - uriLength, asciiName, asciiNameLength);
  546. JsTTDStreamHandle res = TTDHostOpen(uriLength + asciiNameLength, path, write);
  547. if(res == nullptr)
  548. {
  549. fprintf(stderr, "Failed to open file: %s\n", path);
  550. }
  551. Helpers::TTReportLastIOErrorAsNeeded(res != nullptr, "Failed File Open");
  552. return res;
  553. }
  554. bool CALLBACK Helpers::TTReadBytesFromStreamCallback(JsTTDStreamHandle handle, byte* buff, size_t size, size_t* readCount)
  555. {
  556. AssertMsg(handle != nullptr, "Bad file handle.");
  557. if(size > MAXDWORD)
  558. {
  559. *readCount = 0;
  560. return false;
  561. }
  562. BOOL ok = FALSE;
  563. *readCount = TTDHostRead(buff, size, (FILE*)handle);
  564. ok = (*readCount != 0);
  565. Helpers::TTReportLastIOErrorAsNeeded(ok, "Failed Read!!!");
  566. return ok ? true : false;
  567. }
  568. bool CALLBACK Helpers::TTWriteBytesToStreamCallback(JsTTDStreamHandle handle, const byte* buff, size_t size, size_t* writtenCount)
  569. {
  570. AssertMsg(handle != nullptr, "Bad file handle.");
  571. if(size > MAXDWORD)
  572. {
  573. *writtenCount = 0;
  574. return false;
  575. }
  576. BOOL ok = FALSE;
  577. *writtenCount = TTDHostWrite(buff, size, (FILE*)handle);
  578. ok = (*writtenCount == size);
  579. Helpers::TTReportLastIOErrorAsNeeded(ok, "Failed Read!!!");
  580. return ok ? true : false;
  581. }
  582. void CALLBACK Helpers::TTFlushAndCloseStreamCallback(JsTTDStreamHandle handle, bool read, bool write)
  583. {
  584. fflush((FILE*)handle);
  585. fclose((FILE*)handle);
  586. }
  587. void GetBinaryPathWithFileNameA(char *path, const size_t buffer_size, const char* filename)
  588. {
  589. char fullpath[_MAX_PATH];
  590. char drive[_MAX_DRIVE];
  591. char dir[_MAX_DIR];
  592. char modulename[_MAX_PATH];
  593. PlatformAgnostic::SystemInfo::GetBinaryLocation(modulename, _MAX_PATH);
  594. _splitpath_s(modulename, drive, _MAX_DRIVE, dir, _MAX_DIR, nullptr, 0, nullptr, 0);
  595. _makepath_s(fullpath, drive, dir, filename, nullptr);
  596. size_t len = strlen(fullpath);
  597. if (len < buffer_size)
  598. {
  599. memcpy(path, fullpath, len * sizeof(char));
  600. }
  601. else
  602. {
  603. len = 0;
  604. }
  605. path[len] = char(0);
  606. }