Helpers.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  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*/)
  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 = filenameToLoad;
  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] != '\\') // 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)
  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,
  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. if (nullptr == pRawBytes)
  230. {
  231. fwprintf(stderr, _u("out of memory"));
  232. IfFailGo(E_OUTOFMEMORY);
  233. }
  234. if (file != NULL)
  235. {
  236. //
  237. // Read the entire content as a binary block.
  238. //
  239. size_t readBytes = fread(pRawBytes, sizeof(BYTE), lengthBytes, file);
  240. if (readBytes < lengthBytes * sizeof(BYTE))
  241. {
  242. IfFailGo(E_FAIL);
  243. }
  244. }
  245. else // from module source register
  246. {
  247. // Q: module source is on persistent memory. Why do we use the copy instead?
  248. // A: if we use the same memory twice, ch doesn't know that during FinalizeCallback free.
  249. // the copy memory will be freed by the finalizer
  250. Assert(pRawBytesFromMap);
  251. memcpy_s(pRawBytes, bufferLength, pRawBytesFromMap, lengthBytes);
  252. }
  253. if (pRawBytes)
  254. {
  255. pRawBytes[lengthBytes] = 0; // Null terminate it. Could be UTF16
  256. }
  257. if (file != NULL)
  258. {
  259. //
  260. // Read encoding to make sure it's supported
  261. //
  262. // Warning: The UNICODE buffer for parsing is supposed to be provided by the host.
  263. // This is not a complete read of the encoding. Some encodings like UTF7, UTF1, EBCDIC, SCSU, BOCU could be
  264. // wrongly classified as ANSI
  265. //
  266. #pragma warning(push)
  267. // suppressing prefast warning that "readable size is bufferLength
  268. // bytes but 2 may be read" as bufferLength is clearly > 2 in the code that follows
  269. #pragma warning(disable:6385)
  270. C_ASSERT(sizeof(WCHAR) == 2);
  271. if (bufferLength > 2)
  272. {
  273. __analysis_assume(bufferLength > 2);
  274. #pragma prefast(push)
  275. #pragma prefast(disable:6385, "PREfast incorrectly reports this as an out-of-bound access.");
  276. if ((pRawBytes[0] == 0xFE && pRawBytes[1] == 0xFF) ||
  277. (pRawBytes[0] == 0xFF && pRawBytes[1] == 0xFE) ||
  278. (bufferLength > 4 && pRawBytes[0] == 0x00 && pRawBytes[1] == 0x00 &&
  279. ((pRawBytes[2] == 0xFE && pRawBytes[3] == 0xFF) ||
  280. (pRawBytes[2] == 0xFF && pRawBytes[3] == 0xFE))))
  281. {
  282. // unicode unsupported
  283. fwprintf(stderr, _u("unsupported file encoding. Only ANSI and UTF8 supported"));
  284. IfFailGo(E_UNEXPECTED);
  285. }
  286. #pragma prefast(pop)
  287. }
  288. #pragma warning(pop)
  289. }
  290. contents = reinterpret_cast<LPCSTR>(pRawBytes);
  291. Error:
  292. if (SUCCEEDED(hr))
  293. {
  294. if (lengthBytesOut)
  295. {
  296. *lengthBytesOut = lengthBytes;
  297. }
  298. }
  299. if (file != NULL)
  300. {
  301. fclose(file);
  302. }
  303. if (pRawBytes && reinterpret_cast<LPCSTR>(pRawBytes) != contents)
  304. {
  305. free(pRawBytes);
  306. }
  307. return hr;
  308. }
  309. LPCWSTR Helpers::JsErrorCodeToString(JsErrorCode jsErrorCode)
  310. {
  311. bool hasException = false;
  312. ChakraRTInterface::JsHasException(&hasException);
  313. if (hasException)
  314. {
  315. WScriptJsrt::PrintException("", JsErrorScriptException);
  316. }
  317. switch (jsErrorCode)
  318. {
  319. case JsNoError: return _u("JsNoError");
  320. // JsErrorCategoryUsage
  321. case JsErrorCategoryUsage: return _u("JsErrorCategoryUsage");
  322. case JsErrorInvalidArgument: return _u("JsErrorInvalidArgument");
  323. case JsErrorNullArgument: return _u("JsErrorNullArgument");
  324. case JsErrorNoCurrentContext: return _u("JsErrorNoCurrentContext");
  325. case JsErrorInExceptionState: return _u("JsErrorInExceptionState");
  326. case JsErrorNotImplemented: return _u("JsErrorNotImplemented");
  327. case JsErrorWrongThread: return _u("JsErrorWrongThread");
  328. case JsErrorRuntimeInUse: return _u("JsErrorRuntimeInUse");
  329. case JsErrorBadSerializedScript: return _u("JsErrorBadSerializedScript");
  330. case JsErrorInDisabledState: return _u("JsErrorInDisabledState");
  331. case JsErrorCannotDisableExecution: return _u("JsErrorCannotDisableExecution");
  332. case JsErrorHeapEnumInProgress: return _u("JsErrorHeapEnumInProgress");
  333. case JsErrorArgumentNotObject: return _u("JsErrorArgumentNotObject");
  334. case JsErrorInProfileCallback: return _u("JsErrorInProfileCallback");
  335. case JsErrorInThreadServiceCallback: return _u("JsErrorInThreadServiceCallback");
  336. case JsErrorCannotSerializeDebugScript: return _u("JsErrorCannotSerializeDebugScript");
  337. case JsErrorAlreadyDebuggingContext: return _u("JsErrorAlreadyDebuggingContext");
  338. case JsErrorAlreadyProfilingContext: return _u("JsErrorAlreadyProfilingContext");
  339. case JsErrorIdleNotEnabled: return _u("JsErrorIdleNotEnabled");
  340. case JsCannotSetProjectionEnqueueCallback: return _u("JsCannotSetProjectionEnqueueCallback");
  341. case JsErrorCannotStartProjection: return _u("JsErrorCannotStartProjection");
  342. case JsErrorInObjectBeforeCollectCallback: return _u("JsErrorInObjectBeforeCollectCallback");
  343. case JsErrorObjectNotInspectable: return _u("JsErrorObjectNotInspectable");
  344. case JsErrorPropertyNotSymbol: return _u("JsErrorPropertyNotSymbol");
  345. case JsErrorPropertyNotString: return _u("JsErrorPropertyNotString");
  346. case JsErrorInvalidContext: return _u("JsErrorInvalidContext");
  347. case JsInvalidModuleHostInfoKind: return _u("JsInvalidModuleHostInfoKind");
  348. case JsErrorModuleParsed: return _u("JsErrorModuleParsed");
  349. // JsErrorCategoryEngine
  350. case JsErrorCategoryEngine: return _u("JsErrorCategoryEngine");
  351. case JsErrorOutOfMemory: return _u("JsErrorOutOfMemory");
  352. case JsErrorBadFPUState: return _u("JsErrorBadFPUState");
  353. // JsErrorCategoryScript
  354. case JsErrorCategoryScript: return _u("JsErrorCategoryScript");
  355. case JsErrorScriptException: return _u("JsErrorScriptException");
  356. case JsErrorScriptCompile: return _u("JsErrorScriptCompile");
  357. case JsErrorScriptTerminated: return _u("JsErrorScriptTerminated");
  358. case JsErrorScriptEvalDisabled: return _u("JsErrorScriptEvalDisabled");
  359. // JsErrorCategoryFatal
  360. case JsErrorCategoryFatal: return _u("JsErrorCategoryFatal");
  361. case JsErrorFatal: return _u("JsErrorFatal");
  362. case JsErrorWrongRuntime: return _u("JsErrorWrongRuntime");
  363. // JsErrorCategoryDiagError
  364. case JsErrorCategoryDiagError: return _u("JsErrorCategoryDiagError");
  365. case JsErrorDiagAlreadyInDebugMode: return _u("JsErrorDiagAlreadyInDebugMode");
  366. case JsErrorDiagNotInDebugMode: return _u("JsErrorDiagNotInDebugMode");
  367. case JsErrorDiagNotAtBreak: return _u("JsErrorDiagNotAtBreak");
  368. case JsErrorDiagInvalidHandle: return _u("JsErrorDiagInvalidHandle");
  369. case JsErrorDiagObjectNotFound: return _u("JsErrorDiagObjectNotFound");
  370. case JsErrorDiagUnableToPerformAction: return _u("JsErrorDiagUnableToPerformAction");
  371. default:
  372. return _u("<unknown>");
  373. break;
  374. }
  375. }
  376. void Helpers::LogError(__in __nullterminated const char16 *msg, ...)
  377. {
  378. va_list args;
  379. va_start(args, msg);
  380. wprintf(_u("ERROR: "));
  381. vfwprintf(stderr, msg, args);
  382. wprintf(_u("\n"));
  383. fflush(stdout);
  384. va_end(args);
  385. }
  386. HRESULT Helpers::LoadBinaryFile(LPCSTR filename, LPCSTR& contents, UINT& lengthBytes, bool printFileOpenError)
  387. {
  388. HRESULT hr = S_OK;
  389. contents = nullptr;
  390. lengthBytes = 0;
  391. size_t result;
  392. FILE * file;
  393. //
  394. // Open the file as a binary file to prevent CRT from handling encoding, line-break conversions,
  395. // etc.
  396. //
  397. if (fopen_s(&file, filename, "rb") != 0)
  398. {
  399. if (printFileOpenError)
  400. {
  401. fprintf(stderr, "Error in opening file '%s' ", filename);
  402. #ifdef _WIN32
  403. DWORD lastError = GetLastError();
  404. char16 wszBuff[MAX_URI_LENGTH];
  405. wszBuff[0] = 0;
  406. if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
  407. nullptr,
  408. lastError,
  409. 0,
  410. wszBuff,
  411. _countof(wszBuff),
  412. nullptr))
  413. {
  414. fwprintf(stderr, _u(": %s"), wszBuff);
  415. }
  416. #endif
  417. fprintf(stderr, "\n");
  418. }
  419. return E_FAIL;
  420. }
  421. // file will not be nullptr if _wfopen_s succeeds
  422. __analysis_assume(file != nullptr);
  423. //
  424. // Determine the file length, in bytes.
  425. //
  426. fseek(file, 0, SEEK_END);
  427. lengthBytes = ftell(file);
  428. fseek(file, 0, SEEK_SET);
  429. contents = (LPCSTR)HeapAlloc(GetProcessHeap(), 0, lengthBytes);
  430. if (nullptr == contents)
  431. {
  432. fwprintf(stderr, _u("out of memory"));
  433. IfFailGo(E_OUTOFMEMORY);
  434. }
  435. //
  436. // Read the entire content as a binary block.
  437. //
  438. result = fread((void*)contents, sizeof(char), lengthBytes, file);
  439. if (result != lengthBytes)
  440. {
  441. fwprintf(stderr, _u("Read error"));
  442. IfFailGo(E_FAIL);
  443. }
  444. Error:
  445. fclose(file);
  446. if (contents && FAILED(hr))
  447. {
  448. HeapFree(GetProcessHeap(), 0, (void*)contents);
  449. contents = nullptr;
  450. }
  451. return hr;
  452. }
  453. void Helpers::TTReportLastIOErrorAsNeeded(BOOL ok, const char* msg)
  454. {
  455. if(!ok)
  456. {
  457. #ifdef _WIN32
  458. DWORD lastError = GetLastError();
  459. LPTSTR pTemp = NULL;
  460. FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, NULL, lastError, 0, (LPTSTR)&pTemp, 0, NULL);
  461. fwprintf(stderr, _u("Error is: %s\n"), pTemp);
  462. #else
  463. fprintf(stderr, "Error is: %i %s\n", errno, strerror(errno));
  464. #endif
  465. fprintf(stderr, "Message is: %s\n", msg);
  466. AssertMsg(false, "IO Error!!!");
  467. exit(1);
  468. }
  469. }
  470. //We assume bounded ascii path length for simplicity
  471. #define MAX_TTD_ASCII_PATH_EXT_LENGTH 64
  472. void Helpers::CreateTTDDirectoryAsNeeded(size_t* uriLength, char* uri, const char* asciiDir1, const wchar* asciiDir2)
  473. {
  474. 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)
  475. {
  476. wprintf(_u("We assume bounded MAX_URI_LENGTH for simplicity.\n"));
  477. wprintf(_u("%S, %S, %ls\n"), uri, asciiDir1, asciiDir2);
  478. exit(1);
  479. }
  480. int success = 0;
  481. int extLength = 0;
  482. extLength = sprintf_s(uri + *uriLength, MAX_TTD_ASCII_PATH_EXT_LENGTH, "%s%s", asciiDir1, TTD_HOST_PATH_SEP);
  483. if(extLength == -1 || MAX_URI_LENGTH < (*uriLength) + extLength)
  484. {
  485. wprintf(_u("Failed directory extension 1.\n"));
  486. wprintf(_u("%S, %S, %ls\n"), uri, asciiDir1, asciiDir2);
  487. exit(1);
  488. }
  489. *uriLength += extLength;
  490. success = TTDHostMKDir(uri, *uriLength);
  491. if(success != 0)
  492. {
  493. //we may fail because someone else created the directory -- that is ok
  494. Helpers::TTReportLastIOErrorAsNeeded(errno != ENOENT, "Failed to create directory");
  495. }
  496. char realAsciiDir2[MAX_TTD_ASCII_PATH_EXT_LENGTH];
  497. size_t asciiDir2Length = wcslen(asciiDir2) + 1;
  498. for(size_t i = 0; i < asciiDir2Length; ++i)
  499. {
  500. if(asciiDir2[i] > CHAR_MAX)
  501. {
  502. wprintf(_u("Test directory names can only include ascii chars.\n"));
  503. exit(1);
  504. }
  505. realAsciiDir2[i] = (char)asciiDir2[i];
  506. }
  507. extLength = sprintf_s(uri + *uriLength, MAX_TTD_ASCII_PATH_EXT_LENGTH, "%s%s", realAsciiDir2, TTD_HOST_PATH_SEP);
  508. if(extLength == -1 || MAX_URI_LENGTH < *uriLength + extLength)
  509. {
  510. wprintf(_u("Failed directory create 2.\n"));
  511. wprintf(_u("%S, %S, %ls\n"), uri, asciiDir1, asciiDir2);
  512. exit(1);
  513. }
  514. *uriLength += extLength;
  515. success = TTDHostMKDir(uri, *uriLength);
  516. if(success != 0)
  517. {
  518. //we may fail because someone else created the directory -- that is ok
  519. Helpers::TTReportLastIOErrorAsNeeded(errno != ENOENT, "Failed to create directory");
  520. }
  521. }
  522. void Helpers::GetTTDDirectory(const wchar* curi, size_t* uriLength, char* uri, size_t bufferLength)
  523. {
  524. TTDHostBuildCurrentExeDirectory(uri, uriLength, bufferLength);
  525. Helpers::CreateTTDDirectoryAsNeeded(uriLength, uri, "_ttdlog", curi);
  526. }
  527. JsTTDStreamHandle CALLBACK Helpers::TTCreateStreamCallback(size_t uriLength, const char* uri, size_t asciiNameLength, const char* asciiName, bool read, bool write)
  528. {
  529. AssertMsg((read | write) & (!read | !write), "Read/Write streams not supported yet -- defaulting to read only");
  530. if(uriLength + asciiNameLength + 1 > MAX_URI_LENGTH)
  531. {
  532. wprintf(_u("We assume bounded MAX_URI_LENGTH for simplicity."));
  533. exit(1);
  534. }
  535. char path[MAX_URI_LENGTH];
  536. memset(path, 0, MAX_URI_LENGTH);
  537. memcpy_s(path, MAX_URI_LENGTH, uri, uriLength);
  538. memcpy_s(path + uriLength, MAX_URI_LENGTH - uriLength, asciiName, asciiNameLength);
  539. JsTTDStreamHandle res = TTDHostOpen(uriLength + asciiNameLength, path, write);
  540. if(res == nullptr)
  541. {
  542. fprintf(stderr, "Failed to open file: %s\n", path);
  543. }
  544. Helpers::TTReportLastIOErrorAsNeeded(res != nullptr, "Failed File Open");
  545. return res;
  546. }
  547. bool CALLBACK Helpers::TTReadBytesFromStreamCallback(JsTTDStreamHandle handle, byte* buff, size_t size, size_t* readCount)
  548. {
  549. AssertMsg(handle != nullptr, "Bad file handle.");
  550. if(size > MAXDWORD)
  551. {
  552. *readCount = 0;
  553. return false;
  554. }
  555. BOOL ok = FALSE;
  556. *readCount = TTDHostRead(buff, size, (FILE*)handle);
  557. ok = (*readCount != 0);
  558. Helpers::TTReportLastIOErrorAsNeeded(ok, "Failed Read!!!");
  559. return ok ? true : false;
  560. }
  561. bool CALLBACK Helpers::TTWriteBytesToStreamCallback(JsTTDStreamHandle handle, const byte* buff, size_t size, size_t* writtenCount)
  562. {
  563. AssertMsg(handle != nullptr, "Bad file handle.");
  564. if(size > MAXDWORD)
  565. {
  566. *writtenCount = 0;
  567. return false;
  568. }
  569. BOOL ok = FALSE;
  570. *writtenCount = TTDHostWrite(buff, size, (FILE*)handle);
  571. ok = (*writtenCount == size);
  572. Helpers::TTReportLastIOErrorAsNeeded(ok, "Failed Read!!!");
  573. return ok ? true : false;
  574. }
  575. void CALLBACK Helpers::TTFlushAndCloseStreamCallback(JsTTDStreamHandle handle, bool read, bool write)
  576. {
  577. fflush((FILE*)handle);
  578. fclose((FILE*)handle);
  579. }
  580. void GetBinaryPathWithFileNameA(char *path, const size_t buffer_size, const char* filename)
  581. {
  582. char fullpath[_MAX_PATH];
  583. char drive[_MAX_DRIVE];
  584. char dir[_MAX_DIR];
  585. char modulename[_MAX_PATH];
  586. PlatformAgnostic::SystemInfo::GetBinaryLocation(modulename, _MAX_PATH);
  587. _splitpath_s(modulename, drive, _MAX_DRIVE, dir, _MAX_DIR, nullptr, 0, nullptr, 0);
  588. _makepath_s(fullpath, drive, dir, filename, nullptr);
  589. size_t len = strlen(fullpath);
  590. if (len < buffer_size)
  591. {
  592. memcpy(path, fullpath, len * sizeof(char));
  593. }
  594. else
  595. {
  596. len = 0;
  597. }
  598. path[len] = char(0);
  599. }