Helpers.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
  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 | 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 JsCannotSetProjectionEnqueueCallback: return _u("JsCannotSetProjectionEnqueueCallback");
  349. case JsErrorCannotStartProjection: return _u("JsErrorCannotStartProjection");
  350. case JsErrorInObjectBeforeCollectCallback: return _u("JsErrorInObjectBeforeCollectCallback");
  351. case JsErrorObjectNotInspectable: return _u("JsErrorObjectNotInspectable");
  352. case JsErrorPropertyNotSymbol: return _u("JsErrorPropertyNotSymbol");
  353. case JsErrorPropertyNotString: return _u("JsErrorPropertyNotString");
  354. case JsErrorInvalidContext: return _u("JsErrorInvalidContext");
  355. case JsInvalidModuleHostInfoKind: return _u("JsInvalidModuleHostInfoKind");
  356. case JsErrorModuleParsed: return _u("JsErrorModuleParsed");
  357. // JsErrorCategoryEngine
  358. case JsErrorCategoryEngine: return _u("JsErrorCategoryEngine");
  359. case JsErrorOutOfMemory: return _u("JsErrorOutOfMemory");
  360. case JsErrorBadFPUState: return _u("JsErrorBadFPUState");
  361. // JsErrorCategoryScript
  362. case JsErrorCategoryScript: return _u("JsErrorCategoryScript");
  363. case JsErrorScriptException: return _u("JsErrorScriptException");
  364. case JsErrorScriptCompile: return _u("JsErrorScriptCompile");
  365. case JsErrorScriptTerminated: return _u("JsErrorScriptTerminated");
  366. case JsErrorScriptEvalDisabled: return _u("JsErrorScriptEvalDisabled");
  367. // JsErrorCategoryFatal
  368. case JsErrorCategoryFatal: return _u("JsErrorCategoryFatal");
  369. case JsErrorFatal: return _u("JsErrorFatal");
  370. case JsErrorWrongRuntime: return _u("JsErrorWrongRuntime");
  371. // JsErrorCategoryDiagError
  372. case JsErrorCategoryDiagError: return _u("JsErrorCategoryDiagError");
  373. case JsErrorDiagAlreadyInDebugMode: return _u("JsErrorDiagAlreadyInDebugMode");
  374. case JsErrorDiagNotInDebugMode: return _u("JsErrorDiagNotInDebugMode");
  375. case JsErrorDiagNotAtBreak: return _u("JsErrorDiagNotAtBreak");
  376. case JsErrorDiagInvalidHandle: return _u("JsErrorDiagInvalidHandle");
  377. case JsErrorDiagObjectNotFound: return _u("JsErrorDiagObjectNotFound");
  378. case JsErrorDiagUnableToPerformAction: return _u("JsErrorDiagUnableToPerformAction");
  379. default:
  380. return _u("<unknown>");
  381. break;
  382. }
  383. }
  384. void Helpers::LogError(__in __nullterminated const char16 *msg, ...)
  385. {
  386. va_list args;
  387. va_start(args, msg);
  388. wprintf(_u("ERROR: "));
  389. vfwprintf(stderr, msg, args);
  390. wprintf(_u("\n"));
  391. fflush(stdout);
  392. va_end(args);
  393. }
  394. HRESULT Helpers::LoadBinaryFile(LPCSTR filename, LPCSTR& contents, UINT& lengthBytes, bool printFileOpenError)
  395. {
  396. HRESULT hr = S_OK;
  397. contents = nullptr;
  398. lengthBytes = 0;
  399. size_t result;
  400. FILE * file;
  401. //
  402. // Open the file as a binary file to prevent CRT from handling encoding, line-break conversions,
  403. // etc.
  404. //
  405. if (fopen_s(&file, filename, "rb") != 0)
  406. {
  407. if (printFileOpenError)
  408. {
  409. fprintf(stderr, "Error in opening file '%s' ", filename);
  410. #ifdef _WIN32
  411. DWORD lastError = GetLastError();
  412. char16 wszBuff[MAX_URI_LENGTH];
  413. wszBuff[0] = 0;
  414. if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
  415. nullptr,
  416. lastError,
  417. 0,
  418. wszBuff,
  419. _countof(wszBuff),
  420. nullptr))
  421. {
  422. fwprintf(stderr, _u(": %s"), wszBuff);
  423. }
  424. #endif
  425. fprintf(stderr, "\n");
  426. }
  427. return E_FAIL;
  428. }
  429. // file will not be nullptr if _wfopen_s succeeds
  430. __analysis_assume(file != nullptr);
  431. //
  432. // Determine the file length, in bytes.
  433. //
  434. fseek(file, 0, SEEK_END);
  435. lengthBytes = ftell(file);
  436. fseek(file, 0, SEEK_SET);
  437. contents = (LPCSTR)HeapAlloc(GetProcessHeap(), 0, lengthBytes);
  438. if (nullptr == contents)
  439. {
  440. fwprintf(stderr, _u("out of memory"));
  441. IfFailGo(E_OUTOFMEMORY);
  442. }
  443. //
  444. // Read the entire content as a binary block.
  445. //
  446. result = fread((void*)contents, sizeof(char), lengthBytes, file);
  447. if (result != lengthBytes)
  448. {
  449. fwprintf(stderr, _u("Read error"));
  450. IfFailGo(E_FAIL);
  451. }
  452. Error:
  453. fclose(file);
  454. if (contents && FAILED(hr))
  455. {
  456. HeapFree(GetProcessHeap(), 0, (void*)contents);
  457. contents = nullptr;
  458. }
  459. return hr;
  460. }
  461. void Helpers::TTReportLastIOErrorAsNeeded(BOOL ok, const char* msg)
  462. {
  463. if(!ok)
  464. {
  465. #ifdef _WIN32
  466. DWORD lastError = GetLastError();
  467. LPTSTR pTemp = NULL;
  468. FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, lastError, 0, (LPTSTR)&pTemp, 0, NULL);
  469. fwprintf(stderr, _u("Error is: %s\n"), pTemp);
  470. LocalFree(pTemp);
  471. #else
  472. fprintf(stderr, "Error is: %i %s\n", errno, strerror(errno));
  473. #endif
  474. fprintf(stderr, "Message is: %s\n", msg);
  475. AssertMsg(false, "IO Error!!!");
  476. exit(1);
  477. }
  478. }
  479. //We assume bounded ascii path length for simplicity
  480. #define MAX_TTD_ASCII_PATH_EXT_LENGTH 64
  481. void Helpers::CreateTTDDirectoryAsNeeded(size_t* uriLength, char* uri, const char* asciiDir1, const wchar* asciiDir2)
  482. {
  483. 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)
  484. {
  485. wprintf(_u("We assume bounded MAX_URI_LENGTH for simplicity.\n"));
  486. wprintf(_u("%S, %S, %ls\n"), uri, asciiDir1, asciiDir2);
  487. exit(1);
  488. }
  489. int success = 0;
  490. int extLength = 0;
  491. extLength = sprintf_s(uri + *uriLength, MAX_TTD_ASCII_PATH_EXT_LENGTH, "%s%s", asciiDir1, TTD_HOST_PATH_SEP);
  492. if(extLength == -1 || MAX_URI_LENGTH < (*uriLength) + extLength)
  493. {
  494. wprintf(_u("Failed directory extension 1.\n"));
  495. wprintf(_u("%S, %S, %ls\n"), uri, asciiDir1, asciiDir2);
  496. exit(1);
  497. }
  498. *uriLength += extLength;
  499. success = TTDHostMKDir(uri, *uriLength);
  500. if(success != 0)
  501. {
  502. //we may fail because someone else created the directory -- that is ok
  503. Helpers::TTReportLastIOErrorAsNeeded(errno == EEXIST, "Failed to create directory");
  504. }
  505. char realAsciiDir2[MAX_TTD_ASCII_PATH_EXT_LENGTH];
  506. size_t asciiDir2Length = wcslen(asciiDir2) + 1;
  507. for(size_t i = 0; i < asciiDir2Length; ++i)
  508. {
  509. if(asciiDir2[i] > CHAR_MAX)
  510. {
  511. wprintf(_u("Test directory names can only include ascii chars.\n"));
  512. exit(1);
  513. }
  514. realAsciiDir2[i] = (char)asciiDir2[i];
  515. }
  516. extLength = sprintf_s(uri + *uriLength, MAX_TTD_ASCII_PATH_EXT_LENGTH, "%s%s", realAsciiDir2, TTD_HOST_PATH_SEP);
  517. if(extLength == -1 || MAX_URI_LENGTH < *uriLength + extLength)
  518. {
  519. wprintf(_u("Failed directory create 2.\n"));
  520. wprintf(_u("%S, %S, %ls\n"), uri, asciiDir1, asciiDir2);
  521. exit(1);
  522. }
  523. *uriLength += extLength;
  524. success = TTDHostMKDir(uri, *uriLength);
  525. if(success != 0)
  526. {
  527. //we may fail because someone else created the directory -- that is ok
  528. Helpers::TTReportLastIOErrorAsNeeded(errno == EEXIST, "Failed to create directory");
  529. }
  530. }
  531. void Helpers::GetTTDDirectory(const wchar* curi, size_t* uriLength, char* uri, size_t bufferLength)
  532. {
  533. TTDHostBuildCurrentExeDirectory(uri, uriLength, bufferLength);
  534. Helpers::CreateTTDDirectoryAsNeeded(uriLength, uri, "_ttdlog", curi);
  535. }
  536. JsTTDStreamHandle CALLBACK Helpers::TTCreateStreamCallback(size_t uriLength, const char* uri, size_t asciiNameLength, const char* asciiName, bool read, bool write)
  537. {
  538. AssertMsg((read | write) & (!read | !write), "Read/Write streams not supported yet -- defaulting to read only");
  539. if(uriLength + asciiNameLength + 1 > MAX_URI_LENGTH)
  540. {
  541. wprintf(_u("We assume bounded MAX_URI_LENGTH for simplicity."));
  542. exit(1);
  543. }
  544. char path[MAX_URI_LENGTH];
  545. memset(path, 0, MAX_URI_LENGTH);
  546. memcpy_s(path, MAX_URI_LENGTH, uri, uriLength);
  547. memcpy_s(path + uriLength, MAX_URI_LENGTH - uriLength, asciiName, asciiNameLength);
  548. JsTTDStreamHandle res = TTDHostOpen(uriLength + asciiNameLength, path, write);
  549. if(res == nullptr)
  550. {
  551. fprintf(stderr, "Failed to open file: %s\n", path);
  552. }
  553. Helpers::TTReportLastIOErrorAsNeeded(res != nullptr, "Failed File Open");
  554. return res;
  555. }
  556. bool CALLBACK Helpers::TTReadBytesFromStreamCallback(JsTTDStreamHandle handle, byte* buff, size_t size, size_t* readCount)
  557. {
  558. AssertMsg(handle != nullptr, "Bad file handle.");
  559. if(size > MAXDWORD)
  560. {
  561. *readCount = 0;
  562. return false;
  563. }
  564. BOOL ok = FALSE;
  565. *readCount = TTDHostRead(buff, size, (FILE*)handle);
  566. ok = (*readCount != 0);
  567. Helpers::TTReportLastIOErrorAsNeeded(ok, "Failed Read!!!");
  568. return ok ? true : false;
  569. }
  570. bool CALLBACK Helpers::TTWriteBytesToStreamCallback(JsTTDStreamHandle handle, const byte* buff, size_t size, size_t* writtenCount)
  571. {
  572. AssertMsg(handle != nullptr, "Bad file handle.");
  573. if(size > MAXDWORD)
  574. {
  575. *writtenCount = 0;
  576. return false;
  577. }
  578. BOOL ok = FALSE;
  579. *writtenCount = TTDHostWrite(buff, size, (FILE*)handle);
  580. ok = (*writtenCount == size);
  581. Helpers::TTReportLastIOErrorAsNeeded(ok, "Failed Read!!!");
  582. return ok ? true : false;
  583. }
  584. void CALLBACK Helpers::TTFlushAndCloseStreamCallback(JsTTDStreamHandle handle, bool read, bool write)
  585. {
  586. fflush((FILE*)handle);
  587. fclose((FILE*)handle);
  588. }
  589. void GetBinaryPathWithFileNameA(char *path, const size_t buffer_size, const char* filename)
  590. {
  591. char fullpath[_MAX_PATH];
  592. char drive[_MAX_DRIVE];
  593. char dir[_MAX_DIR];
  594. char modulename[_MAX_PATH];
  595. PlatformAgnostic::SystemInfo::GetBinaryLocation(modulename, _MAX_PATH);
  596. _splitpath_s(modulename, drive, _MAX_DRIVE, dir, _MAX_DIR, nullptr, 0, nullptr, 0);
  597. _makepath_s(fullpath, drive, dir, filename, nullptr);
  598. size_t len = strlen(fullpath);
  599. if (len < buffer_size)
  600. {
  601. memcpy(path, fullpath, len * sizeof(char));
  602. }
  603. else
  604. {
  605. len = 0;
  606. }
  607. path[len] = char(0);
  608. }