PageRenderTime 44ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/xbmc/cores/DllLoader/exports/emu_msvcrt.cpp

http://github.com/xbmc/xbmc
C++ | 2052 lines | 1746 code | 200 blank | 106 comment | 455 complexity | 4005bcd526759532cc8431d37a0e96d4 MD5 | raw file
Possible License(s): GPL-3.0, CC-BY-SA-3.0, LGPL-2.0, 0BSD, Unlicense, GPL-2.0, AGPL-1.0, BSD-3-Clause, LGPL-2.1, LGPL-3.0
  1. /*
  2. * Copyright (C) 2005-2018 Team Kodi
  3. * This file is part of Kodi - https://kodi.tv
  4. *
  5. * SPDX-License-Identifier: GPL-2.0-or-later
  6. * See LICENSES/README.md for more information.
  7. */
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include <stdarg.h>
  11. #include <math.h>
  12. #ifndef TARGET_POSIX
  13. #include <io.h>
  14. #include <direct.h>
  15. #include <process.h>
  16. #include <errno.h>
  17. #else
  18. #if !defined(TARGET_DARWIN) && !defined(TARGET_FREEBSD)
  19. #include <mntent.h>
  20. #endif
  21. #endif
  22. #include <sys/stat.h>
  23. #include <sys/types.h>
  24. #if !defined(TARGET_FREEBSD) && (!defined(TARGET_ANDROID) && defined(__LP64__))
  25. #include <sys/timeb.h>
  26. #endif
  27. #ifdef HAS_DVD_DRIVE
  28. #ifdef TARGET_POSIX
  29. #include <sys/ioctl.h>
  30. #if defined(TARGET_DARWIN)
  31. #include <IOKit/storage/IODVDMediaBSDClient.h>
  32. #elif !defined(TARGET_FREEBSD)
  33. #include <linux/cdrom.h>
  34. #endif
  35. #endif
  36. #endif
  37. #include <fcntl.h>
  38. #include <time.h>
  39. #include <signal.h>
  40. #ifdef TARGET_POSIX
  41. #include "PlatformDefs.h" // for __stat64
  42. #endif
  43. #include "FileItem.h"
  44. #include "ServiceBroker.h"
  45. #include "URL.h"
  46. #include "Util.h"
  47. #include "emu_dummy.h"
  48. #include "emu_msvcrt.h"
  49. #include "filesystem/Directory.h"
  50. #include "filesystem/File.h"
  51. #include "filesystem/SpecialProtocol.h"
  52. #include "settings/Settings.h"
  53. #include "settings/SettingsComponent.h"
  54. #include "threads/SingleLock.h"
  55. #include "util/EmuFileWrapper.h"
  56. #include "utils/log.h"
  57. #ifndef TARGET_POSIX
  58. #include "utils/CharsetConverter.h"
  59. #include "utils/URIUtils.h"
  60. #endif
  61. #if !defined(TARGET_WINDOWS)
  62. #include <dlfcn.h>
  63. #endif
  64. #include "platform/Environment.h"
  65. #include "utils/StringUtils.h"
  66. #include "utils/XTimeUtils.h"
  67. #if defined(TARGET_WINDOWS)
  68. #include "platform/win32/CharsetConverter.h"
  69. #endif
  70. using namespace XFILE;
  71. struct SDirData
  72. {
  73. CFileItemList items;
  74. int curr_index;
  75. struct dirent *last_entry;
  76. SDirData()
  77. {
  78. curr_index = -1;
  79. last_entry = NULL;
  80. }
  81. };
  82. #define MAX_OPEN_DIRS 10
  83. static SDirData vecDirsOpen[MAX_OPEN_DIRS];
  84. bool bVecDirsInited = false;
  85. extern void update_cache_dialog(const char* tmp);
  86. #define EMU_MAX_ENVIRONMENT_ITEMS 100
  87. static char *dll__environ_imp[EMU_MAX_ENVIRONMENT_ITEMS + 1];
  88. extern "C" char **dll__environ;
  89. char **dll__environ = dll__environ_imp;
  90. CCriticalSection dll_cs_environ;
  91. extern "C" void __stdcall init_emu_environ()
  92. {
  93. memset(dll__environ, 0, EMU_MAX_ENVIRONMENT_ITEMS + 1);
  94. // python
  95. #if defined(TARGET_WINDOWS_DESKTOP)
  96. using KODI::PLATFORM::WINDOWS::FromW;
  97. // fill our array with the windows system vars
  98. LPTSTR lpszVariable;
  99. LPTCH lpvEnv = NULL;
  100. lpvEnv = GetEnvironmentStrings();
  101. if (lpvEnv != NULL)
  102. {
  103. lpszVariable = (LPTSTR) lpvEnv;
  104. while (*lpszVariable)
  105. {
  106. dll_putenv(FromW(lpszVariable).c_str());
  107. lpszVariable += lstrlen(lpszVariable) + 1;
  108. }
  109. FreeEnvironmentStrings(lpvEnv);
  110. }
  111. dll_putenv("OS=win32");
  112. #elif defined(TARGET_WINDOWS_STORE)
  113. dll_putenv("OS=win10");
  114. #elif defined(TARGET_DARWIN)
  115. dll_putenv("OS=darwin");
  116. #elif defined(TARGET_POSIX)
  117. dll_putenv("OS=linux");
  118. #else
  119. dll_putenv("OS=unknown");
  120. #endif
  121. // check if we are running as real xbmc.app or just binary
  122. if (!CUtil::GetFrameworksPath(true).empty())
  123. {
  124. // using external python, it's build looking for xxx/lib/python3.7
  125. // so point it to frameworks which is where python3.7 is located
  126. dll_putenv(("PYTHONPATH=" +
  127. CSpecialProtocol::TranslatePath("special://frameworks")).c_str());
  128. dll_putenv(("PYTHONHOME=" +
  129. CSpecialProtocol::TranslatePath("special://frameworks")).c_str());
  130. dll_putenv(("PATH=.;" +
  131. CSpecialProtocol::TranslatePath("special://xbmc") + ";" +
  132. CSpecialProtocol::TranslatePath("special://frameworks")).c_str());
  133. }
  134. else
  135. {
  136. dll_putenv(("PYTHONPATH=" +
  137. CSpecialProtocol::TranslatePath("special://xbmc/system/python/DLLs") + ";" +
  138. CSpecialProtocol::TranslatePath("special://xbmc/system/python/Lib")).c_str());
  139. dll_putenv(("PYTHONHOME=" +
  140. CSpecialProtocol::TranslatePath("special://xbmc/system/python")).c_str());
  141. dll_putenv(("PATH=.;" + CSpecialProtocol::TranslatePath("special://xbmc") + ";" +
  142. CSpecialProtocol::TranslatePath("special://xbmc/system/python")).c_str());
  143. }
  144. #if defined(TARGET_ANDROID)
  145. std::string apkPath = getenv("KODI_ANDROID_APK");
  146. apkPath += "/assets/python3.7";
  147. dll_putenv(("PYTHONHOME=" + apkPath).c_str());
  148. dll_putenv("PYTHONOPTIMIZE=");
  149. dll_putenv("PYTHONNOUSERSITE=1");
  150. dll_putenv("PYTHONPATH=");
  151. #else
  152. dll_putenv("PYTHONOPTIMIZE=1");
  153. #endif
  154. //dll_putenv("PYTHONCASEOK=1");
  155. //dll_putenv("PYTHONDEBUG=1");
  156. //dll_putenv("PYTHONVERBOSE=2"); // "1" for normal verbose, "2" for more verbose ?
  157. //dll_putenv("PYTHONDUMPREFS=1");
  158. //dll_putenv("THREADDEBUG=1");
  159. //dll_putenv("PYTHONMALLOCSTATS=1");
  160. //dll_putenv("PYTHONY2K=1");
  161. dll_putenv("TEMP=special://temp/temp"); // for python tempdir
  162. // libdvdnav
  163. dll_putenv("DVDREAD_NOKEYS=1");
  164. //dll_putenv("DVDREAD_VERBOSE=1");
  165. //dll_putenv("DVDREAD_USE_DIRECT=1");
  166. // libdvdcss
  167. dll_putenv("DVDCSS_METHOD=key");
  168. dll_putenv("DVDCSS_VERBOSE=3");
  169. dll_putenv("DVDCSS_CACHE=special://masterprofile/cache");
  170. }
  171. extern "C" void __stdcall update_emu_environ()
  172. {
  173. const std::shared_ptr<CSettings> settings = CServiceBroker::GetSettingsComponent()->GetSettings();
  174. // Use a proxy, if the GUI was configured as such
  175. if (settings->GetBool(CSettings::SETTING_NETWORK_USEHTTPPROXY)
  176. && !settings->GetString(CSettings::SETTING_NETWORK_HTTPPROXYSERVER).empty()
  177. && settings->GetInt(CSettings::SETTING_NETWORK_HTTPPROXYPORT) > 0
  178. && settings->GetInt(CSettings::SETTING_NETWORK_HTTPPROXYTYPE) == 0)
  179. {
  180. std::string strProxy;
  181. if (!settings->GetString(CSettings::SETTING_NETWORK_HTTPPROXYUSERNAME).empty() &&
  182. !settings->GetString(CSettings::SETTING_NETWORK_HTTPPROXYPASSWORD).empty())
  183. {
  184. strProxy = StringUtils::Format("%s:%s@",
  185. settings->GetString(CSettings::SETTING_NETWORK_HTTPPROXYUSERNAME).c_str(),
  186. settings->GetString(CSettings::SETTING_NETWORK_HTTPPROXYPASSWORD).c_str());
  187. }
  188. strProxy += settings->GetString(CSettings::SETTING_NETWORK_HTTPPROXYSERVER);
  189. strProxy += StringUtils::Format(":%d", settings->GetInt(CSettings::SETTING_NETWORK_HTTPPROXYPORT));
  190. CEnvironment::setenv( "HTTP_PROXY", "http://" + strProxy, true );
  191. CEnvironment::setenv( "HTTPS_PROXY", "http://" + strProxy, true );
  192. }
  193. else
  194. {
  195. // is there a better way to delete an environment variable?
  196. // this works but leaves the variable
  197. dll_putenv( "HTTP_PROXY=" );
  198. dll_putenv( "HTTPS_PROXY=" );
  199. }
  200. }
  201. extern "C" void __stdcall cleanup_emu_environ()
  202. {
  203. for (int i = 0; i < EMU_MAX_ENVIRONMENT_ITEMS; i++)
  204. {
  205. free(dll__environ[i]);
  206. dll__environ[i] = NULL;
  207. }
  208. }
  209. static int convert_fmode(const char* mode)
  210. {
  211. int iMode = O_BINARY;
  212. if (strstr(mode, "r+"))
  213. iMode |= O_RDWR;
  214. else if (strchr(mode, 'r'))
  215. iMode |= _O_RDONLY;
  216. if (strstr(mode, "w+"))
  217. iMode |= O_RDWR | _O_TRUNC;
  218. else if (strchr(mode, 'w'))
  219. iMode |= _O_WRONLY | O_CREAT;
  220. return iMode;
  221. }
  222. #ifdef TARGET_WINDOWS
  223. static void to_finddata64i32(_wfinddata64i32_t *wdata, _finddata64i32_t *data)
  224. {
  225. std::string strname;
  226. g_charsetConverter.wToUTF8(wdata->name, strname);
  227. size_t size = sizeof(data->name) / sizeof(char);
  228. strncpy(data->name, strname.c_str(), size);
  229. if (size)
  230. data->name[size - 1] = '\0';
  231. data->attrib = wdata->attrib;
  232. data->time_create = wdata->time_create;
  233. data->time_access = wdata->time_access;
  234. data->time_write = wdata->time_write;
  235. data->size = wdata->size;
  236. }
  237. static void to_wfinddata64i32(_finddata64i32_t *data, _wfinddata64i32_t *wdata)
  238. {
  239. std::wstring strwname;
  240. g_charsetConverter.utf8ToW(data->name, strwname, false);
  241. size_t size = sizeof(wdata->name) / sizeof(wchar_t);
  242. wcsncpy(wdata->name, strwname.c_str(), size);
  243. if (size)
  244. wdata->name[size - 1] = '\0';
  245. wdata->attrib = data->attrib;
  246. wdata->time_create = data->time_create;
  247. wdata->time_access = data->time_access;
  248. wdata->time_write = data->time_write;
  249. wdata->size = data->size;
  250. }
  251. #endif
  252. extern "C"
  253. {
  254. void dll_sleep(unsigned long imSec) { KODI::TIME::Sleep(imSec); }
  255. // FIXME, XXX, !!!!!!
  256. void dllReleaseAll( )
  257. {
  258. // close all open dirs...
  259. if (bVecDirsInited)
  260. {
  261. for (SDirData& dir : vecDirsOpen)
  262. {
  263. dir.items.Clear();
  264. }
  265. bVecDirsInited = false;
  266. }
  267. }
  268. void* dllmalloc(size_t size)
  269. {
  270. void* pBlock = malloc(size);
  271. if (!pBlock)
  272. {
  273. CLog::Log(LOGFATAL, "malloc {0} bytes failed, crash imminent", size);
  274. }
  275. return pBlock;
  276. }
  277. void dllfree( void* pPtr )
  278. {
  279. free(pPtr);
  280. }
  281. void* dllcalloc(size_t num, size_t size)
  282. {
  283. void* pBlock = calloc(num, size);
  284. if (!pBlock)
  285. {
  286. CLog::Log(LOGFATAL, "calloc {0} bytes failed, crash imminent", size);
  287. }
  288. return pBlock;
  289. }
  290. void* dllrealloc( void *memblock, size_t size )
  291. {
  292. void* pBlock = realloc(memblock, size);
  293. if (!pBlock)
  294. {
  295. CLog::Log(LOGFATAL, "realloc {0} bytes failed, crash imminent", size);
  296. }
  297. return pBlock;
  298. }
  299. void dllexit(int iCode)
  300. {
  301. not_implement("msvcrt.dll fake function exit() called\n"); //warning
  302. }
  303. void dllabort()
  304. {
  305. not_implement("msvcrt.dll fake function abort() called\n"); //warning
  306. }
  307. void* dll__dllonexit(PFV input, PFV ** start, PFV ** end)
  308. {
  309. //ported from WINE code
  310. PFV *tmp;
  311. int len;
  312. if (!start || !*start || !end || !*end)
  313. {
  314. //FIXME("bad table\n");
  315. return NULL;
  316. }
  317. len = (*end - *start);
  318. if (++len <= 0)
  319. return NULL;
  320. tmp = (PFV*) realloc (*start, len * sizeof(tmp) );
  321. if (!tmp)
  322. return NULL;
  323. *start = tmp;
  324. *end = tmp + len;
  325. tmp[len - 1] = input;
  326. return (void *)input;
  327. //wrong handling, this function is used for register functions
  328. //that called before exit use _initterm functions.
  329. //dllReleaseAll( );
  330. //return TRUE;
  331. }
  332. _onexit_t dll_onexit(_onexit_t func)
  333. {
  334. not_implement("msvcrt.dll fake function dll_onexit() called\n");
  335. // register to dll unload list
  336. // return func if successfully added to the dll unload list
  337. return NULL;
  338. }
  339. int dllputs(const char* szLine)
  340. {
  341. if (!szLine[0]) return EOF;
  342. if (szLine[strlen(szLine) - 1] != '\n')
  343. CLog::Log(LOGDEBUG," msg: %s", szLine);
  344. else
  345. CLog::Log(LOGDEBUG, " msg: %s", szLine);
  346. // return a non negative value
  347. return 0;
  348. }
  349. int dllprintf(const char *format, ...)
  350. {
  351. va_list va;
  352. static char tmp[2048];
  353. va_start(va, format);
  354. _vsnprintf(tmp, 2048, format, va);
  355. va_end(va);
  356. tmp[2048 - 1] = 0;
  357. CLog::Log(LOGDEBUG, " msg: %s", tmp);
  358. return strlen(tmp);
  359. }
  360. char *dll_fullpath(char *absPath, const char *relPath, size_t maxLength)
  361. {
  362. unsigned int len = strlen(relPath);
  363. if (len > maxLength && absPath != NULL) return NULL;
  364. // dll has to make sure it uses the correct path for now
  365. if (len > 1 && relPath[1] == ':')
  366. {
  367. if (absPath == NULL) absPath = dll_strdup(relPath);
  368. else
  369. {
  370. strncpy(absPath, relPath, maxLength);
  371. if (maxLength != 0)
  372. absPath[maxLength-1] = '\0';
  373. }
  374. return absPath;
  375. }
  376. if (!strncmp(relPath, "\\Device\\Cdrom0", 14))
  377. {
  378. // needed?
  379. if (absPath == NULL) absPath = strdup(relPath);
  380. else
  381. {
  382. strncpy(absPath, relPath, maxLength);
  383. if (maxLength != 0)
  384. absPath[maxLength-1] = '\0';
  385. }
  386. return absPath;
  387. }
  388. not_implement("msvcrt.dll incomplete function _fullpath(...) called\n"); //warning
  389. return NULL;
  390. }
  391. FILE* dll_popen(const char *command, const char *mode)
  392. {
  393. not_implement("msvcrt.dll fake function _popen(...) called\n"); //warning
  394. return NULL;
  395. }
  396. void *dll_dlopen(const char *filename, int flag)
  397. {
  398. #if !defined(TARGET_WINDOWS)
  399. return dlopen(filename, flag);
  400. #else
  401. return NULL;
  402. #endif
  403. }
  404. int dll_pclose(FILE *stream)
  405. {
  406. not_implement("msvcrt.dll fake function _pclose(...) called\n"); //warning
  407. return 0;
  408. }
  409. FILE* dll_fdopen(int fd, const char* mode)
  410. {
  411. EmuFileObject* o = g_emuFileWrapper.GetFileObjectByDescriptor(fd);
  412. if (o)
  413. {
  414. if(!o->used)
  415. return NULL;
  416. int nmode = convert_fmode(mode);
  417. if( (o->mode & nmode) != nmode)
  418. CLog::Log(LOGWARNING, "dll_fdopen - mode 0x%x differs from fd mode 0x%x", nmode, o->mode);
  419. return reinterpret_cast<FILE*>(o);
  420. }
  421. else if (!IS_STD_DESCRIPTOR(fd))
  422. {
  423. // it might be something else than a file, or the file is not emulated
  424. // let the operating system handle it
  425. return _fdopen(fd, mode);
  426. }
  427. not_implement("msvcrt.dll incomplete function _fdopen(...) called\n");
  428. return NULL;
  429. }
  430. int dll_open(const char* szFileName, int iMode)
  431. {
  432. char str[1024];
  433. int size = sizeof(str);
  434. // move to CFile classes
  435. if (strncmp(szFileName, "\\Device\\Cdrom0", 14) == 0)
  436. {
  437. // replace "\\Device\\Cdrom0" with "D:"
  438. strncpy(str, "D:", size);
  439. if (size)
  440. {
  441. str[size-1] = '\0';
  442. strncat(str, szFileName + 14, size - strlen(str));
  443. }
  444. }
  445. else
  446. {
  447. strncpy(str, szFileName, size);
  448. if (size)
  449. str[size-1] = '\0';
  450. }
  451. CFile* pFile = new CFile();
  452. bool bWrite = false;
  453. if ((iMode & O_RDWR) || (iMode & O_WRONLY))
  454. bWrite = true;
  455. bool bOverwrite=false;
  456. if ((iMode & _O_TRUNC) || (iMode & O_CREAT))
  457. bOverwrite = true;
  458. // currently always overwrites
  459. bool bResult;
  460. // We need to validate the path here as some calls from ie. libdvdnav
  461. // or the python DLLs have malformed slashes on Win32
  462. // (-> E:\test\VIDEO_TS/VIDEO_TS.BUP))
  463. if (bWrite)
  464. bResult = pFile->OpenForWrite(CUtil::ValidatePath(str), bOverwrite);
  465. else
  466. bResult = pFile->Open(CUtil::ValidatePath(str), READ_TRUNCATED);
  467. if (bResult)
  468. {
  469. EmuFileObject* object = g_emuFileWrapper.RegisterFileObject(pFile);
  470. if (object == NULL)
  471. {
  472. pFile->Close();
  473. delete pFile;
  474. return -1;
  475. }
  476. object->mode = iMode;
  477. FILE* f = reinterpret_cast<FILE*>(object);
  478. return g_emuFileWrapper.GetDescriptorByStream(f);
  479. }
  480. delete pFile;
  481. return -1;
  482. }
  483. FILE* dll_freopen(const char *path, const char *mode, FILE *stream)
  484. {
  485. if (g_emuFileWrapper.StreamIsEmulatedFile(stream))
  486. {
  487. dll_fclose(stream);
  488. return dll_fopen(path, mode);
  489. }
  490. // error
  491. // close stream and return NULL
  492. dll_fclose(stream);
  493. return NULL;
  494. }
  495. int dll_read(int fd, void* buffer, unsigned int uiSize)
  496. {
  497. CFile* pFile = g_emuFileWrapper.GetFileXbmcByDescriptor(fd);
  498. if (pFile != NULL)
  499. {
  500. errno = 0;
  501. const ssize_t ret = pFile->Read(buffer, uiSize);
  502. if (ret < 0)
  503. {
  504. const int err = errno; // help compiler to optimize, "errno" can be macro
  505. if (err == 0 ||
  506. (err != EAGAIN && err != EINTR && err != EIO && err != EOVERFLOW && err != EWOULDBLOCK &&
  507. err != ECONNRESET && err != ENOTCONN && err != ETIMEDOUT &&
  508. err != ENOBUFS && err != ENOMEM && err != ENXIO))
  509. errno = EIO; // exact errno is unknown or incorrect, use default error number
  510. return -1;
  511. }
  512. return ret;
  513. }
  514. else if (!IS_STD_DESCRIPTOR(fd))
  515. {
  516. // it might be something else than a file, or the file is not emulated
  517. // let the operating system handle it
  518. return read(fd, buffer, uiSize);
  519. }
  520. CLog::Log(LOGERROR, "%s emulated function failed", __FUNCTION__);
  521. errno = EBADF;
  522. return -1;
  523. }
  524. int dll_write(int fd, const void* buffer, unsigned int uiSize)
  525. {
  526. CFile* pFile = g_emuFileWrapper.GetFileXbmcByDescriptor(fd);
  527. if (pFile != NULL)
  528. {
  529. errno = 0;
  530. const ssize_t ret = pFile->Write(buffer, uiSize);
  531. if (ret < 0)
  532. {
  533. const int err = errno; // help compiler to optimize, "errno" can be macro
  534. if (err == 0 ||
  535. (err != EAGAIN && err != EFBIG && err != EINTR && err != EIO && err != ENOSPC && err != EPIPE && err != EWOULDBLOCK &&
  536. err != ECONNRESET &&
  537. err != ENOBUFS && err != ENXIO &&
  538. err != EACCES && err != ENETDOWN && err != ENETUNREACH))
  539. errno = EIO; // exact errno is unknown or incorrect, use default error number
  540. return -1;
  541. }
  542. return ret;
  543. }
  544. else if (!IS_STD_DESCRIPTOR(fd))
  545. {
  546. // it might be something else than a file, or the file is not emulated
  547. // let the operating system handle it
  548. return write(fd, buffer, uiSize);
  549. }
  550. CLog::Log(LOGERROR, "%s emulated function failed", __FUNCTION__);
  551. errno = EBADF;
  552. return -1;
  553. }
  554. int dll_fstat64(int fd, struct __stat64 *buf)
  555. {
  556. CFile* pFile = g_emuFileWrapper.GetFileXbmcByDescriptor(fd);
  557. if (pFile != NULL)
  558. return pFile->Stat(buf);
  559. else if (IS_STD_DESCRIPTOR(fd))
  560. #if defined(TARGET_WINDOWS)
  561. return _fstat64(fd, buf);
  562. #else
  563. return fstat64(fd, buf);
  564. #endif
  565. CLog::Log(LOGERROR, "%s emulated function failed", __FUNCTION__);
  566. return -1;
  567. }
  568. int dll_close(int fd)
  569. {
  570. CFile* pFile = g_emuFileWrapper.GetFileXbmcByDescriptor(fd);
  571. if (pFile != NULL)
  572. {
  573. g_emuFileWrapper.UnRegisterFileObjectByDescriptor(fd);
  574. pFile->Close();
  575. delete pFile;
  576. return 0;
  577. }
  578. else if (!IS_STD_DESCRIPTOR(fd) && fd >= 0)
  579. {
  580. // it might be something else than a file, or the file is not emulated
  581. // let the operating system handle it
  582. return close(fd);
  583. }
  584. CLog::Log(LOGERROR, "%s emulated function failed", __FUNCTION__);
  585. return -1;
  586. }
  587. __off64_t dll_lseeki64(int fd, __off64_t lPos, int iWhence)
  588. {
  589. CFile* pFile = g_emuFileWrapper.GetFileXbmcByDescriptor(fd);
  590. if (pFile != NULL)
  591. {
  592. lPos = pFile->Seek(lPos, iWhence);
  593. return lPos;
  594. }
  595. else if (!IS_STD_DESCRIPTOR(fd))
  596. {
  597. // it might be something else than a file, or the file is not emulated
  598. // let the operating system handle it
  599. // not supported: return lseeki64(fd, lPos, iWhence);
  600. CLog::Log(LOGWARNING, "msvcrt.dll: dll_lseeki64 called, TODO: add 'int64 -> long' type checking"); //warning
  601. return static_cast<long long>(lseek(fd, (long)lPos, iWhence));
  602. }
  603. CLog::Log(LOGERROR, "%s emulated function failed", __FUNCTION__);
  604. return -1ll;
  605. }
  606. __off_t dll_lseek(int fd, __off_t lPos, int iWhence)
  607. {
  608. if (g_emuFileWrapper.DescriptorIsEmulatedFile(fd))
  609. {
  610. return (__off_t)dll_lseeki64(fd, lPos, iWhence);
  611. }
  612. else if (!IS_STD_DESCRIPTOR(fd))
  613. {
  614. // it might be something else than a file, or the file is not emulated
  615. // let the operating system handle it
  616. return lseek(fd, lPos, iWhence);
  617. }
  618. CLog::Log(LOGERROR, "%s emulated function failed", __FUNCTION__);
  619. return -1;
  620. }
  621. void dll_rewind(FILE* stream)
  622. {
  623. int fd = g_emuFileWrapper.GetDescriptorByStream(stream);
  624. if (fd >= 0)
  625. {
  626. dll_lseeki64(fd, 0, SEEK_SET);
  627. }
  628. else
  629. {
  630. CLog::Log(LOGERROR, "%s emulated function failed", __FUNCTION__);
  631. }
  632. }
  633. //---------------------------------------------------------------------------------------------------------
  634. void dll_flockfile(FILE *stream)
  635. {
  636. int fd = g_emuFileWrapper.GetDescriptorByStream(stream);
  637. if (fd >= 0)
  638. {
  639. g_emuFileWrapper.LockFileObjectByDescriptor(fd);
  640. return;
  641. }
  642. CLog::Log(LOGERROR, "%s emulated function failed", __FUNCTION__);
  643. }
  644. int dll_ftrylockfile(FILE *stream)
  645. {
  646. int fd = g_emuFileWrapper.GetDescriptorByStream(stream);
  647. if (fd >= 0)
  648. {
  649. if (g_emuFileWrapper.TryLockFileObjectByDescriptor(fd))
  650. return 0;
  651. return -1;
  652. }
  653. CLog::Log(LOGERROR, "%s emulated function failed", __FUNCTION__);
  654. return -1;
  655. }
  656. void dll_funlockfile(FILE *stream)
  657. {
  658. int fd = g_emuFileWrapper.GetDescriptorByStream(stream);
  659. if (fd >= 0)
  660. {
  661. g_emuFileWrapper.UnlockFileObjectByDescriptor(fd);
  662. return;
  663. }
  664. CLog::Log(LOGERROR, "%s emulated function failed", __FUNCTION__);
  665. }
  666. int dll_fclose(FILE * stream)
  667. {
  668. int fd = g_emuFileWrapper.GetDescriptorByStream(stream);
  669. if (fd >= 0)
  670. {
  671. return dll_close(fd) == 0 ? 0 : EOF;
  672. }
  673. CLog::Log(LOGERROR, "%s emulated function failed", __FUNCTION__);
  674. return EOF;
  675. }
  676. #ifndef TARGET_POSIX
  677. // should be moved to CFile classes
  678. intptr_t dll_findfirst(const char *file, struct _finddata_t *data)
  679. {
  680. struct _finddata64i32_t data64i32;
  681. intptr_t ret = dll_findfirst64i32(file, &data64i32);
  682. if (ret != -1)
  683. {
  684. int size = sizeof(data->name);
  685. strncpy(data->name, data64i32.name, size);
  686. if (size)
  687. data->name[size - 1] = '\0';
  688. data->size = (_fsize_t)data64i32.size;
  689. data->time_write = (time_t)data64i32.time_write;
  690. data->time_access = (time_t)data64i32.time_access;
  691. }
  692. return ret;
  693. }
  694. intptr_t dll_findfirst64i32(const char *file, struct _finddata64i32_t *data)
  695. {
  696. char str[1024];
  697. int size = sizeof(str);
  698. CURL url(CSpecialProtocol::TranslatePath(file));
  699. if (url.IsLocal())
  700. {
  701. // move to CFile classes
  702. if (strncmp(file, "\\Device\\Cdrom0", 14) == 0)
  703. {
  704. // replace "\\Device\\Cdrom0" with "D:"
  705. strncpy(str, "D:", size);
  706. if (size)
  707. {
  708. str[size - 1] = '\0';
  709. strncat(str, file + 14, size - strlen(str));
  710. }
  711. }
  712. else
  713. {
  714. strncpy(str, file, size);
  715. if (size)
  716. str[size - 1] = '\0';
  717. }
  718. // Make sure the slashes are correct & translate the path
  719. struct _wfinddata64i32_t wdata;
  720. std::wstring strwfile;
  721. g_charsetConverter.utf8ToW(CUtil::ValidatePath(CSpecialProtocol::TranslatePath(str)), strwfile, false);
  722. intptr_t ret = _wfindfirst64i32(strwfile.c_str(), &wdata);
  723. if (ret != -1)
  724. to_finddata64i32(&wdata, data);
  725. return ret;
  726. }
  727. // non-local files. handle through IDirectory-class - only supports '*.bah' or '*.*'
  728. std::string strURL(file);
  729. std::string strMask;
  730. if (url.GetFileName().find("*.*") != std::string::npos)
  731. {
  732. std::string strReplaced = url.GetFileName();
  733. StringUtils::Replace(strReplaced, "*.*","");
  734. url.SetFileName(strReplaced);
  735. }
  736. else if (url.GetFileName().find("*.") != std::string::npos)
  737. {
  738. strMask = URIUtils::GetExtension(url.GetFileName());
  739. url.SetFileName(url.GetFileName().substr(0, url.GetFileName().find("*.")));
  740. }
  741. else if (url.GetFileName().find("*") != std::string::npos)
  742. {
  743. std::string strReplaced = url.GetFileName();
  744. StringUtils::Replace(strReplaced, "*","");
  745. url.SetFileName(strReplaced);
  746. }
  747. int iDirSlot=0; // locate next free directory
  748. while ((iDirSlot < MAX_OPEN_DIRS) && (vecDirsOpen[iDirSlot].curr_index != -1)) iDirSlot++;
  749. if (iDirSlot >= MAX_OPEN_DIRS)
  750. return -1; // no free slots
  751. strURL = url.Get();
  752. bVecDirsInited = true;
  753. vecDirsOpen[iDirSlot].items.Clear();
  754. XFILE::CDirectory::GetDirectory(strURL, vecDirsOpen[iDirSlot].items, strMask, DIR_FLAG_DEFAULTS);
  755. if (vecDirsOpen[iDirSlot].items.Size())
  756. {
  757. int size = sizeof(data->name);
  758. strncpy(data->name,vecDirsOpen[iDirSlot].items[0]->GetLabel().c_str(), size);
  759. if (size)
  760. data->name[size - 1] = '\0';
  761. data->size = static_cast<_fsize_t>(vecDirsOpen[iDirSlot].items[0]->m_dwSize);
  762. data->time_write = 0;
  763. data->time_access = 0;
  764. vecDirsOpen[iDirSlot].curr_index = 0;
  765. return (intptr_t)&vecDirsOpen[iDirSlot];
  766. }
  767. vecDirsOpen[iDirSlot].curr_index = -1;
  768. return -1; // whatever != NULL
  769. }
  770. // should be moved to CFile classes
  771. int dll_findnext(intptr_t f, _finddata_t* data)
  772. {
  773. struct _finddata64i32_t data64i32;
  774. int ret = dll_findnext64i32(f, &data64i32);
  775. if (ret == 0)
  776. {
  777. int size = sizeof(data->name);
  778. strncpy(data->name, data64i32.name, size);
  779. if (size)
  780. data->name[size - 1] = '\0';
  781. data->size = (_fsize_t)data64i32.size;
  782. data->time_write = (time_t)data64i32.time_write;
  783. data->time_access = (time_t)data64i32.time_access;
  784. }
  785. return ret;
  786. }
  787. int dll_findnext64i32(intptr_t f, _finddata64i32_t* data)
  788. {
  789. int found = MAX_OPEN_DIRS;
  790. for (int i = 0; i < MAX_OPEN_DIRS; i++)
  791. {
  792. if (f == (intptr_t)&vecDirsOpen[i] && vecDirsOpen[i].curr_index != -1)
  793. {
  794. found = i;
  795. break;
  796. }
  797. }
  798. if (found >= MAX_OPEN_DIRS)
  799. {
  800. struct _wfinddata64i32_t wdata;
  801. to_wfinddata64i32(data, &wdata);
  802. intptr_t ret = _wfindnext64i32(f, &wdata); // local dir
  803. if (ret != -1)
  804. to_finddata64i32(&wdata, data);
  805. return ret;
  806. }
  807. // we have a valid data struture. get next item!
  808. int iItem = vecDirsOpen[found].curr_index;
  809. if (iItem+1 < vecDirsOpen[found].items.Size()) // we have a winner!
  810. {
  811. int size = sizeof(data->name);
  812. strncpy(data->name,vecDirsOpen[found].items[iItem+1]->GetLabel().c_str(), size);
  813. if (size)
  814. data->name[size - 1] = '\0';
  815. data->size = static_cast<_fsize_t>(vecDirsOpen[found].items[iItem+1]->m_dwSize);
  816. vecDirsOpen[found].curr_index++;
  817. return 0;
  818. }
  819. vecDirsOpen[found].items.Clear();
  820. return -1;
  821. }
  822. int dll_findclose(intptr_t handle)
  823. {
  824. int found = MAX_OPEN_DIRS;
  825. for (int i = 0; i < MAX_OPEN_DIRS; i++)
  826. {
  827. if (handle == (intptr_t)&vecDirsOpen[i] && vecDirsOpen[i].curr_index != -1)
  828. {
  829. found = i;
  830. break;
  831. }
  832. }
  833. if (found >= MAX_OPEN_DIRS)
  834. return _findclose(handle);
  835. vecDirsOpen[found].items.Clear();
  836. vecDirsOpen[found].curr_index = -1;
  837. return 0;
  838. }
  839. void dll__security_error_handler(int code, void *data)
  840. {
  841. //NOTE: __security_error_handler has been removed in VS2005 and up
  842. CLog::Log(LOGERROR, "security_error, code %i", code);
  843. }
  844. #endif
  845. DIR *dll_opendir(const char *file)
  846. {
  847. CURL url(CSpecialProtocol::TranslatePath(file));
  848. if (url.IsLocal())
  849. { // Make sure the slashes are correct & translate the path
  850. return opendir(CUtil::ValidatePath(url.Get().c_str()).c_str());
  851. }
  852. // locate next free directory
  853. int iDirSlot=0;
  854. while ((iDirSlot<MAX_OPEN_DIRS) && (vecDirsOpen[iDirSlot].curr_index != -1)) iDirSlot++;
  855. if (iDirSlot >= MAX_OPEN_DIRS)
  856. {
  857. CLog::Log(LOGDEBUG, "Dll: Max open dirs reached");
  858. return NULL; // no free slots
  859. }
  860. bVecDirsInited = true;
  861. vecDirsOpen[iDirSlot].items.Clear();
  862. if (XFILE::CDirectory::GetDirectory(url.Get(), vecDirsOpen[iDirSlot].items, "", DIR_FLAG_DEFAULTS))
  863. {
  864. vecDirsOpen[iDirSlot].curr_index = 0;
  865. return (DIR *)&vecDirsOpen[iDirSlot];
  866. }
  867. else
  868. return NULL;
  869. }
  870. struct dirent *dll_readdir(DIR *dirp)
  871. {
  872. if (!dirp)
  873. return NULL;
  874. bool emulated(false);
  875. for (const SDirData& dir : vecDirsOpen)
  876. {
  877. if (dirp == (DIR*)&dir)
  878. {
  879. emulated = true;
  880. break;
  881. }
  882. }
  883. if (!emulated)
  884. return readdir(dirp); // local dir
  885. // dirp is actually a SDirData*
  886. SDirData* dirData = reinterpret_cast<SDirData*>(dirp);
  887. if (dirData->last_entry)
  888. free(dirData->last_entry);
  889. struct dirent *entry = NULL;
  890. entry = (dirent*) malloc(sizeof(*entry));
  891. if (dirData->curr_index < dirData->items.Size() + 2)
  892. { // simulate the '.' and '..' dir entries
  893. if (dirData->curr_index == 0)
  894. strncpy(entry->d_name, ".\0", 2);
  895. else if (dirData->curr_index == 1)
  896. strncpy(entry->d_name, "..\0", 3);
  897. else
  898. {
  899. strncpy(entry->d_name, dirData->items[dirData->curr_index - 2]->GetLabel().c_str(), sizeof(entry->d_name));
  900. entry->d_name[sizeof(entry->d_name)-1] = '\0'; // null-terminate any truncated paths
  901. }
  902. dirData->last_entry = entry;
  903. dirData->curr_index++;
  904. return entry;
  905. }
  906. free(entry);
  907. return NULL;
  908. }
  909. int dll_closedir(DIR *dirp)
  910. {
  911. bool emulated(false);
  912. for (const SDirData& dir : vecDirsOpen)
  913. {
  914. if (dirp == (DIR*)&dir)
  915. {
  916. emulated = true;
  917. break;
  918. }
  919. }
  920. if (!emulated)
  921. return closedir(dirp);
  922. SDirData* dirData = reinterpret_cast<SDirData*>(dirp);
  923. dirData->items.Clear();
  924. if (dirData->last_entry)
  925. {
  926. dirData->last_entry = NULL;
  927. }
  928. dirData->curr_index = -1;
  929. return 0;
  930. }
  931. void dll_rewinddir(DIR *dirp)
  932. {
  933. bool emulated(false);
  934. for (const SDirData& dir : vecDirsOpen)
  935. {
  936. if (dirp == (DIR*)&dir)
  937. {
  938. emulated = true;
  939. break;
  940. }
  941. }
  942. if (!emulated)
  943. {
  944. rewinddir(dirp);
  945. return;
  946. }
  947. SDirData* dirData = reinterpret_cast<SDirData*>(dirp);
  948. if (dirData->last_entry)
  949. {
  950. dirData->last_entry = NULL;
  951. }
  952. dirData->curr_index = 0;
  953. }
  954. char* dll_fgets(char* pszString, int num ,FILE * stream)
  955. {
  956. CFile* pFile = g_emuFileWrapper.GetFileXbmcByStream(stream);
  957. if (pFile != NULL)
  958. {
  959. if (pFile->GetPosition() < pFile->GetLength())
  960. {
  961. bool bRead = pFile->ReadString(pszString, num);
  962. if (bRead)
  963. {
  964. return pszString;
  965. }
  966. }
  967. else return NULL; //eof
  968. }
  969. CLog::Log(LOGERROR, "%s emulated function failed", __FUNCTION__);
  970. return NULL;
  971. }
  972. int dll_feof(FILE * stream)
  973. {
  974. CFile* pFile = g_emuFileWrapper.GetFileXbmcByStream(stream);
  975. if (pFile != NULL)
  976. {
  977. if (pFile->GetPosition() < pFile->GetLength()) return 0;
  978. else return 1;
  979. }
  980. CLog::Log(LOGERROR, "%s emulated function failed", __FUNCTION__);
  981. return 1; // eof by default
  982. }
  983. int dll_fread(void * buffer, size_t size, size_t count, FILE * stream)
  984. {
  985. if (size == 0 || count == 0)
  986. return 0;
  987. CFile* pFile = g_emuFileWrapper.GetFileXbmcByStream(stream);
  988. if (pFile != NULL)
  989. {
  990. size_t read = 0;
  991. const size_t bufSize = size * count;
  992. do // fread() must read all data until buffer is filled or eof/error occurs
  993. {
  994. const ssize_t r = pFile->Read(((int8_t*)buffer) + read, bufSize - read);
  995. if (r <= 0)
  996. break;
  997. read += r;
  998. } while (bufSize > read);
  999. return read / size;
  1000. }
  1001. CLog::Log(LOGERROR, "%s emulated function failed", __FUNCTION__);
  1002. return 0;
  1003. }
  1004. int dll_fgetc(FILE* stream)
  1005. {
  1006. if (g_emuFileWrapper.StreamIsEmulatedFile(stream))
  1007. {
  1008. // it is a emulated file
  1009. unsigned char buf;
  1010. if (dll_fread(&buf, 1, 1, stream) <= 0)
  1011. return EOF;
  1012. return (int)buf;
  1013. }
  1014. CLog::Log(LOGERROR, "%s emulated function failed", __FUNCTION__);
  1015. return EOF;
  1016. }
  1017. int dll_getc(FILE* stream)
  1018. {
  1019. if (g_emuFileWrapper.StreamIsEmulatedFile(stream))
  1020. {
  1021. // This routine is normally implemented as a macro with the same result as fgetc().
  1022. return dll_fgetc(stream);
  1023. }
  1024. CLog::Log(LOGERROR, "%s emulated function failed", __FUNCTION__);
  1025. return EOF;
  1026. }
  1027. FILE* dll_fopen(const char* filename, const char* mode)
  1028. {
  1029. FILE* file = NULL;
  1030. #if defined(TARGET_LINUX) && !defined(TARGET_ANDROID)
  1031. if (strcmp(filename, _PATH_MOUNTED) == 0
  1032. || strcmp(filename, _PATH_MNTTAB) == 0)
  1033. {
  1034. CLog::Log(LOGINFO, "%s - something opened the mount file, let's hope it knows what it's doing", __FUNCTION__);
  1035. return fopen(filename, mode);
  1036. }
  1037. #endif
  1038. int fd = dll_open(filename, convert_fmode(mode));
  1039. if (fd >= 0)
  1040. {
  1041. file = g_emuFileWrapper.GetStreamByDescriptor(fd);
  1042. }
  1043. return file;
  1044. }
  1045. int dll_fopen_s(FILE** pFile, const char * filename, const char * mode)
  1046. {
  1047. if (pFile == NULL || filename == NULL || mode == NULL)
  1048. return EINVAL;
  1049. *pFile = dll_fopen(filename, mode);
  1050. if (*pFile == NULL)
  1051. return errno;
  1052. return 0;
  1053. }
  1054. int dll_putc(int c, FILE *stream)
  1055. {
  1056. if (g_emuFileWrapper.StreamIsEmulatedFile(stream) || IS_STD_STREAM(stream))
  1057. {
  1058. return dll_fputc(c, stream);
  1059. }
  1060. return EOF;
  1061. }
  1062. int dll_putchar(int c)
  1063. {
  1064. return dll_putc(c, stdout);
  1065. }
  1066. int dll_fputc(int character, FILE* stream)
  1067. {
  1068. if (IS_STDOUT_STREAM(stream) || IS_STDERR_STREAM(stream) || !IS_VALID_STREAM(stream))
  1069. {
  1070. unsigned char tmp[2] = { (unsigned char)character, 0 };
  1071. dllputs((char *)tmp);
  1072. return character;
  1073. }
  1074. else
  1075. {
  1076. if (g_emuFileWrapper.StreamIsEmulatedFile(stream))
  1077. {
  1078. int fd = g_emuFileWrapper.GetDescriptorByStream(stream);
  1079. if (fd >= 0)
  1080. {
  1081. unsigned char c = (unsigned char)character;
  1082. int iItemsWritten = dll_write(fd, &c, 1);
  1083. if (iItemsWritten == 1)
  1084. return character;
  1085. }
  1086. }
  1087. }
  1088. CLog::Log(LOGERROR, "%s emulated function failed", __FUNCTION__);
  1089. return EOF;
  1090. }
  1091. int dll_fputs(const char * szLine, FILE* stream)
  1092. {
  1093. if (IS_STDOUT_STREAM(stream) || IS_STDERR_STREAM(stream) || !IS_VALID_STREAM(stream))
  1094. {
  1095. dllputs(szLine);
  1096. return 0;
  1097. }
  1098. else
  1099. {
  1100. if (g_emuFileWrapper.StreamIsEmulatedFile(stream))
  1101. {
  1102. size_t len = strlen(szLine);
  1103. return dll_fwrite(static_cast<const void*>(szLine), sizeof(char), len, stream);
  1104. }
  1105. }
  1106. CLog::Log(LOGERROR, "%s emulated function failed", __FUNCTION__);
  1107. return EOF;
  1108. }
  1109. int dll_fseek64(FILE* stream, off64_t offset, int origin)
  1110. {
  1111. int fd = g_emuFileWrapper.GetDescriptorByStream(stream);
  1112. if (fd >= 0)
  1113. {
  1114. if (dll_lseeki64(fd, offset, origin) != -1)
  1115. {
  1116. return 0;
  1117. }
  1118. else return -1;
  1119. }
  1120. CLog::Log(LOGERROR, "%s emulated function failed", __FUNCTION__);
  1121. return -1;
  1122. }
  1123. int dll_fseek(FILE *stream, long offset, int origin)
  1124. {
  1125. return dll_fseek64(stream, offset, origin);
  1126. }
  1127. int dll_ungetc(int c, FILE* stream)
  1128. {
  1129. if (g_emuFileWrapper.StreamIsEmulatedFile(stream))
  1130. {
  1131. // it is a emulated file
  1132. int d;
  1133. if (dll_fseek(stream, -1, SEEK_CUR)!=0)
  1134. return EOF;
  1135. d = dll_fgetc(stream);
  1136. if (d == EOF)
  1137. return EOF;
  1138. dll_fseek(stream, -1, SEEK_CUR);
  1139. if (c != d)
  1140. {
  1141. CLog::Log(LOGWARNING, "%s: c != d", __FUNCTION__);
  1142. d = fputc(c, stream);
  1143. if (d != c)
  1144. CLog::Log(LOGERROR, "%s: Write failed!", __FUNCTION__);
  1145. else
  1146. dll_fseek(stream, -1, SEEK_CUR);
  1147. }
  1148. return d;
  1149. }
  1150. CLog::Log(LOGERROR, "%s emulated function failed", __FUNCTION__);
  1151. return EOF;
  1152. }
  1153. long dll_ftell(FILE *stream)
  1154. {
  1155. return (long)dll_ftell64(stream);
  1156. }
  1157. off64_t dll_ftell64(FILE *stream)
  1158. {
  1159. CFile* pFile = g_emuFileWrapper.GetFileXbmcByStream(stream);
  1160. if (pFile != NULL)
  1161. {
  1162. return (off64_t)pFile->GetPosition();
  1163. }
  1164. CLog::Log(LOGERROR, "%s emulated function failed", __FUNCTION__);
  1165. return -1;
  1166. }
  1167. long dll_tell(int fd)
  1168. {
  1169. CFile* pFile = g_emuFileWrapper.GetFileXbmcByDescriptor(fd);
  1170. if (pFile != NULL)
  1171. {
  1172. return (long)pFile->GetPosition();
  1173. }
  1174. else if (!IS_STD_DESCRIPTOR(fd))
  1175. {
  1176. // it might be something else than a file, or the file is not emulated
  1177. // let the operating system handle it
  1178. #ifndef TARGET_POSIX
  1179. return tell(fd);
  1180. #else
  1181. return lseek(fd, 0, SEEK_CUR);
  1182. #endif
  1183. }
  1184. CLog::Log(LOGERROR, "%s emulated function failed", __FUNCTION__);
  1185. return -1;
  1186. }
  1187. long long dll_telli64(int fd)
  1188. {
  1189. CFile* pFile = g_emuFileWrapper.GetFileXbmcByDescriptor(fd);
  1190. if (pFile != NULL)
  1191. {
  1192. return static_cast<long long>(pFile->GetPosition());
  1193. }
  1194. else if (!IS_STD_DESCRIPTOR(fd))
  1195. {
  1196. // it might be something else than a file, or the file is not emulated
  1197. // let the operating system handle it
  1198. // not supported return telli64(fd);
  1199. CLog::Log(LOGWARNING, "msvcrt.dll: dll_telli64 called, TODO: add 'int64 -> long' type checking"); //warning
  1200. #ifndef TARGET_POSIX
  1201. return static_cast<long long>(tell(fd));
  1202. #elif defined(TARGET_DARWIN) || defined(TARGET_FREEBSD) || defined(TARGET_ANDROID)
  1203. return lseek(fd, 0, SEEK_CUR);
  1204. #else
  1205. return lseek64(fd, 0, SEEK_CUR);
  1206. #endif
  1207. }
  1208. CLog::Log(LOGERROR, "%s emulated function failed", __FUNCTION__);
  1209. return -1;
  1210. }
  1211. size_t dll_fwrite(const void * buffer, size_t size, size_t count, FILE* stream)
  1212. {
  1213. if (size == 0 || count == 0)
  1214. return 0;
  1215. if (IS_STDOUT_STREAM(stream) || IS_STDERR_STREAM(stream) || !IS_VALID_STREAM(stream))
  1216. {
  1217. char* buf = (char*)malloc(size * count + 1);
  1218. if (buf)
  1219. {
  1220. memcpy(buf, buffer, size * count);
  1221. buf[size * count] = 0; // string termination
  1222. CLog::Log(LOGDEBUG, "%s", buf);
  1223. free(buf);
  1224. return count;
  1225. }
  1226. }
  1227. else
  1228. {
  1229. CFile* pFile = g_emuFileWrapper.GetFileXbmcByStream(stream);
  1230. if (pFile != NULL)
  1231. {
  1232. size_t written = 0;
  1233. const size_t bufSize = size * count;
  1234. do // fwrite() must write all data until whole buffer is written or error occurs
  1235. {
  1236. const ssize_t w = pFile->Write(((const int8_t*)buffer) + written, bufSize - written);
  1237. if (w <= 0)
  1238. break;
  1239. written += w;
  1240. } while (bufSize > written);
  1241. return written / size;
  1242. }
  1243. }
  1244. CLog::Log(LOGERROR, "%s emulated function failed", __FUNCTION__);
  1245. return 0;
  1246. }
  1247. int dll_fflush(FILE* stream)
  1248. {
  1249. CFile* pFile = g_emuFileWrapper.GetFileXbmcByStream(stream);
  1250. if (pFile != NULL)
  1251. {
  1252. pFile->Flush();
  1253. return 0;
  1254. }
  1255. // std stream, no need to flush
  1256. return 0;
  1257. }
  1258. int dll_ferror(FILE* stream)
  1259. {
  1260. CFile* pFile = g_emuFileWrapper.GetFileXbmcByStream(stream);
  1261. if (pFile != NULL)
  1262. {
  1263. // unimplemented
  1264. return 0;
  1265. }
  1266. else if (IS_STD_STREAM(stream))
  1267. return 0;
  1268. else
  1269. return ferror(stream);
  1270. }
  1271. int dllvprintf(const char *format, va_list va)
  1272. {
  1273. std::string buffer = StringUtils::FormatV(format, va);
  1274. CLog::Log(LOGDEBUG, " msg: %s", buffer.c_str());
  1275. return buffer.length();
  1276. }
  1277. int dll_vfprintf(FILE *stream, const char *format, va_list va)
  1278. {
  1279. static char tmp[2048];
  1280. if (_vsnprintf(tmp, 2048, format, va) == -1)
  1281. {
  1282. CLog::Log(LOGWARNING, "dll_vfprintf: Data lost due to undersized buffer");
  1283. }
  1284. tmp[2048 - 1] = 0;
  1285. if (IS_STDOUT_STREAM(stream) || IS_STDERR_STREAM(stream) || !IS_VALID_STREAM(stream))
  1286. {
  1287. CLog::Log(LOGINFO, " msg: %s", tmp);
  1288. return strlen(tmp);
  1289. }
  1290. else
  1291. {
  1292. CFile* pFile = g_emuFileWrapper.GetFileXbmcByStream(stream);
  1293. if (pFile != NULL)
  1294. {
  1295. int len = strlen(tmp);
  1296. // replace all '\n' occurences with '\r\n'...
  1297. char tmp2[2048];
  1298. int j = 0;
  1299. for (int i = 0; i < len; i++)
  1300. {
  1301. if (j == 2047)
  1302. { // out of space
  1303. if (i != len-1)
  1304. CLog::Log(LOGWARNING, "dll_fprintf: Data lost due to undersized buffer");
  1305. break;
  1306. }
  1307. if (tmp[i] == '\n' && ((i > 0 && tmp[i-1] != '\r') || i == 0) && j < 2047 - 2)
  1308. { // need to add a \r
  1309. tmp2[j++] = '\r';
  1310. tmp2[j++] = '\n';
  1311. }
  1312. else
  1313. { // just add the character as-is
  1314. tmp2[j++] = tmp[i];
  1315. }
  1316. }
  1317. // terminate string
  1318. tmp2[j] = 0;
  1319. len = strlen(tmp2);
  1320. pFile->Write(tmp2, len);
  1321. return len;
  1322. }
  1323. }
  1324. CLog::Log(LOGERROR, "%s emulated function failed", __FUNCTION__);
  1325. return strlen(tmp);
  1326. }
  1327. int dll_fscanf(FILE* stream, const char* format, ...)
  1328. {
  1329. CLog::Log(LOGERROR, "%s is not implemented", __FUNCTION__);
  1330. return -1;
  1331. }
  1332. int dll_fprintf(FILE* stream, const char* format, ...)
  1333. {
  1334. int res;
  1335. va_list va;
  1336. va_start(va, format);
  1337. res = dll_vfprintf(stream, format, va);
  1338. va_end(va);
  1339. return res;
  1340. }
  1341. int dll_fgetpos(FILE* stream, fpos_t* pos)
  1342. {
  1343. fpos64_t tmpPos;
  1344. int ret;
  1345. ret = dll_fgetpos64(stream, &tmpPos);
  1346. #if !defined(TARGET_POSIX) || defined(TARGET_DARWIN) || defined(TARGET_FREEBSD) || defined(TARGET_ANDROID)
  1347. *pos = (fpos_t)tmpPos;
  1348. #else
  1349. pos->__pos = (off_t)tmpPos.__pos;
  1350. #endif
  1351. return ret;
  1352. }
  1353. int dll_fgetpos64(FILE *stream, fpos64_t *pos)
  1354. {
  1355. CFile* pFile = g_emuFileWrapper.GetFileXbmcByStream(stream);
  1356. if (pFile != NULL)
  1357. {
  1358. #if !defined(TARGET_POSIX) || defined(TARGET_DARWIN) || defined(TARGET_FREEBSD) || defined(TARGET_ANDROID)
  1359. *pos = pFile->GetPosition();
  1360. #else
  1361. pos->__pos = pFile->GetPosition();
  1362. #endif
  1363. return 0;
  1364. }
  1365. CLog::Log(LOGERROR, "%s emulated function failed", __FUNCTION__);
  1366. return EINVAL;
  1367. }
  1368. int dll_fsetpos64(FILE* stream, const fpos64_t* pos)
  1369. {
  1370. int fd = g_emuFileWrapper.GetDescriptorByStream(stream);
  1371. if (fd >= 0)
  1372. {
  1373. #if !defined(TARGET_POSIX) || defined(TARGET_DARWIN) || defined(TARGET_FREEBSD) || defined(TARGET_ANDROID)
  1374. if (dll_lseeki64(fd, *pos, SEEK_SET) >= 0)
  1375. #else
  1376. if (dll_lseeki64(fd, (__off64_t)pos->__pos, SEEK_SET) >= 0)
  1377. #endif
  1378. {
  1379. return 0;
  1380. }
  1381. else
  1382. {
  1383. return EINVAL;
  1384. }
  1385. }
  1386. CLog::Log(LOGERROR, "%s emulated function failed", __FUNCTION__);
  1387. return EINVAL;
  1388. }
  1389. int dll_fsetpos(FILE* stream, const fpos_t* pos)
  1390. {
  1391. int fd = g_emuFileWrapper.GetDescriptorByStream(stream);
  1392. if (fd >= 0)
  1393. {
  1394. fpos64_t tmpPos;
  1395. #if !defined(TARGET_POSIX) || defined(TARGET_DARWIN) || defined(TARGET_FREEBSD) || defined(TARGET_ANDROID)
  1396. tmpPos= *pos;
  1397. #else
  1398. tmpPos.__pos = (off64_t)(pos->__pos);
  1399. #endif
  1400. return dll_fsetpos64(stream, &tmpPos);
  1401. }
  1402. CLog::Log(LOGERROR, "%s emulated function failed", __FUNCTION__);
  1403. return EINVAL;
  1404. }
  1405. int dll_fileno(FILE* stream)
  1406. {
  1407. int fd = g_emuFileWrapper.GetDescriptorByStream(stream);
  1408. if (fd >= 0)
  1409. {
  1410. return fd;
  1411. }
  1412. else if (IS_STDIN_STREAM(stream))
  1413. {
  1414. return 0;
  1415. }
  1416. else if (IS_STDOUT_STREAM(stream))
  1417. {
  1418. return 1;
  1419. }
  1420. else if (IS_STDERR_STREAM(stream))
  1421. {
  1422. return 2;
  1423. }
  1424. else
  1425. {
  1426. return fileno(stream);
  1427. }
  1428. return -1;
  1429. }
  1430. void dll_clearerr(FILE* stream)
  1431. {
  1432. if (g_emuFileWrapper.StreamIsEmulatedFile(stream))
  1433. {
  1434. // not implemented
  1435. }
  1436. }
  1437. char* dll_strdup( const char* str)
  1438. {
  1439. char* pdup;
  1440. pdup = strdup(str);
  1441. return pdup;
  1442. }
  1443. //Critical Section has been fixed in EMUkernel32.cpp
  1444. int dll_initterm(PFV * start, PFV * end) //pncrt.dll
  1445. {
  1446. PFV * temp;
  1447. for (temp = start; temp < end; temp ++)
  1448. if (*temp)
  1449. (*temp)(); //call initial function table.
  1450. return 0;
  1451. }
  1452. //SLOW CODE SHOULD BE REVISED
  1453. int dll_stat(const char *path, struct stat *buffer)
  1454. {
  1455. if (!StringUtils::CompareNoCase(path, "shout://", 8)) // don't stat shoutcast
  1456. return -1;
  1457. if (!StringUtils::CompareNoCase(path, "mms://", 6)) // don't stat mms
  1458. return -1;
  1459. #ifdef TARGET_POSIX
  1460. if (!StringUtils::CompareNoCase(path, "D:") || !StringUtils::CompareNoCase(path, "D:\\"))
  1461. {
  1462. buffer->st_mode = S_IFDIR;
  1463. return 0;
  1464. }
  1465. #endif
  1466. if (!StringUtils::CompareNoCase(path, "\\Device\\Cdrom0") ||
  1467. !StringUtils::CompareNoCase(path, "\\Device\\Cdrom0\\"))
  1468. {
  1469. buffer->st_mode = _S_IFDIR;
  1470. return 0;
  1471. }
  1472. struct __stat64 tStat;
  1473. if (CFile::Stat(path, &tStat) == 0)
  1474. {
  1475. CUtil::Stat64ToStat(buffer, &tStat);
  1476. return 0;
  1477. }
  1478. // errno is set by file.Stat(...)
  1479. return -1;
  1480. }
  1481. int dll_stati64(const char *path, struct _stati64 *buffer)
  1482. {
  1483. struct __stat64 a;
  1484. memset(&a, 0, sizeof(a));
  1485. if(dll_stat64(path, &a) == 0)
  1486. {
  1487. CUtil::Stat64ToStatI64(buffer, &a);
  1488. return 0;
  1489. }
  1490. return -1;
  1491. }
  1492. int dll_stat64(const char *path, struct __stat64 *buffer)
  1493. {
  1494. if (!StringUtils::CompareNoCase(path, "shout://", 8)) // don't stat shoutcast
  1495. return -1;
  1496. if (!StringUtils::CompareNoCase(path, "mms://", 6)) // don't stat mms
  1497. return -1;
  1498. #ifdef TARGET_POSIX
  1499. if (!StringUtils::CompareNoCase(path, "D:") || !StringUtils::CompareNoCase(path, "D:\\"))
  1500. {
  1501. buffer->st_mode = _S_IFDIR;
  1502. return 0;
  1503. }
  1504. #endif
  1505. if (!StringUtils::CompareNoCase(path, "\\Device\\Cdrom0") ||
  1506. !StringUtils::CompareNoCase(path, "\\Device\\Cdrom0\\"))
  1507. {
  1508. buffer->st_mode = _S_IFDIR;
  1509. return 0;
  1510. }
  1511. return CFile::Stat(path, buffer);
  1512. }
  1513. #ifdef TARGET_WINDOWS
  1514. int dll_stat64i32(const char *path, struct _stat64i32 *buffer)
  1515. {
  1516. struct __stat64 a;
  1517. if(dll_stat64(path, &a) == 0)
  1518. {
  1519. CUtil::Stat64ToStat64i32(buffer, &a);
  1520. return 0;
  1521. }
  1522. return -1;
  1523. }
  1524. #endif
  1525. int dll_fstat(int fd, struct stat* buffer)
  1526. {
  1527. CFile* pFile = g_emuFileWrapper.GetFileXbmcByDescriptor(fd);
  1528. if (pFile != NULL)
  1529. {
  1530. struct __stat64 tStat;
  1531. if (pFile->Stat(&tStat) == 0)
  1532. {
  1533. CUtil::Stat64ToStat(buffer, &tStat);
  1534. return 0;
  1535. }
  1536. }
  1537. else if (!IS_STD_DESCRIPTOR(fd))
  1538. {
  1539. return fstat(fd, buffer);
  1540. }
  1541. // fstat on stdin, stdout or stderr should fail
  1542. // this is what python expects
  1543. return -1;
  1544. }
  1545. int dll_fstati64(int fd, struct _stati64 *buffer)
  1546. {
  1547. CFile* pFile = g_emuFileWrapper.GetFileXbmcByDescriptor(fd);
  1548. if (pFile != NULL)
  1549. {
  1550. CLog::Log(LOGINFO, "Stating open file");
  1551. buffer->st_size = pFile->GetLength();
  1552. buffer->st_mode = _S_IFREG;
  1553. return 0;
  1554. }
  1555. else if (!IS_STD_DESCRIPTOR(fd))
  1556. {
  1557. CLog::Log(LOGWARNING, "msvcrt.dll: dll_fstati64 called, TODO: add 'int64 <-> long' type checking"); //warning
  1558. // need to use fstat and convert everything
  1559. struct stat temp;
  1560. int res = fstat(fd, &temp);
  1561. if (res == 0)
  1562. {
  1563. CUtil::StatToStatI64(buffer, &temp);
  1564. }
  1565. return res;
  1566. }
  1567. // fstat on stdin, stdout or stderr should fail
  1568. // this is what python expects
  1569. return -1;
  1570. }
  1571. #ifdef TARGET_WINDOWS
  1572. int dll_fstat64i32(int fd, struct _stat64i32 *buffer)
  1573. {
  1574. CFile* pFile = g_emuFileWrapper.GetFileXbmcByDescriptor(fd);
  1575. if (pFile != NULL)
  1576. {
  1577. struct __stat64 tStat = {};
  1578. if (pFile->Stat(&tStat) == 0)
  1579. {
  1580. CUtil::Stat64ToStat64i32(buffer, &tStat);
  1581. return 0;
  1582. }
  1583. return -1;
  1584. }
  1585. else if (!IS_STD_DESCRIPTOR(fd))
  1586. {
  1587. CLog::Log(LOGWARNING, "msvcrt.dll: dll_fstati64 called, TODO: add 'int64 <-> long' type checking"); //warning
  1588. // need to use fstat and convert everything
  1589. struct __stat64 temp;
  1590. int res = _fstat64(fd, &temp);
  1591. if (res == 0)
  1592. {
  1593. CUtil::Stat64ToStat64i32(buffer, &temp);
  1594. }
  1595. return res;
  1596. }
  1597. // fstat on stdin, stdout or stderr should fail
  1598. // this is what python expects
  1599. return -1;
  1600. }
  1601. #endif
  1602. int dll_setmode ( int handle, int mode )
  1603. {
  1604. not_implement("msvcrt.dll fake function dll_setmode() called\n");
  1605. return -1;
  1606. }
  1607. void dllperror(const char* s)
  1608. {
  1609. if (s)
  1610. {
  1611. CLog::Log(LOGERROR, "perror: %s", s);
  1612. }
  1613. }
  1614. char* dllstrerror(int iErr)
  1615. {
  1616. static char szError[32];
  1617. sprintf(szError, "err:%i", iErr);
  1618. return (char*)szError;
  1619. }
  1620. int dll_mkdir(const char* dir)
  1621. {
  1622. if (!dir) return -1;
  1623. // Make sure the slashes are correct & translate the path
  1624. std::string strPath = CUtil::ValidatePath(CSpecialProtocol::TranslatePath(dir));
  1625. #ifndef TARGET_POSIX
  1626. std::wstring strWPath;
  1627. g_charsetConverter.utf8ToW(strPath, strWPath, false);
  1628. return _wmkdir(strWPath.c_str());
  1629. #else
  1630. return mkdir(strPath.c_str(), 0755);
  1631. #endif
  1632. }
  1633. const char* dll_getcwd(char *buffer, int maxlen)
  1634. {
  1635. not_implement("msvcrt.dll fake function dll_getcwd() called\n");
  1636. return "special://xbmc/";
  1637. }
  1638. int dll_putenv(const char* envstring)
  1639. {
  1640. bool added = false;
  1641. if (envstring != NULL)
  1642. {
  1643. const char *value_start = strchr(envstring, '=');
  1644. if (value_start != NULL)
  1645. {
  1646. char var[64];
  1647. int size = strlen(envstring) + 1;
  1648. char *value = (char*)malloc(size);
  1649. if (!value)
  1650. return -1;
  1651. value[0] = 0;
  1652. memcpy(var, envstring, value_start - envstring);
  1653. var[value_start - envstring] = 0;
  1654. char* temp = var;
  1655. while (*temp)
  1656. {
  1657. *temp = (char)toupper(*temp);
  1658. temp++;
  1659. }
  1660. strncpy(value, value_start + 1, size);
  1661. if (size)
  1662. value[size - 1] = '\0';
  1663. {
  1664. CSingleLock lock(dll_cs_environ);
  1665. char** free_position = NULL;
  1666. for (int i = 0; i < EMU_MAX_ENVIRONMENT_ITEMS && free_position == NULL; i++)
  1667. {
  1668. if (dll__environ[i] != NULL)
  1669. {
  1670. // we only support overwriting the old values
  1671. if (StringUtils::CompareNoCase(dll__environ[i], var, strlen(var)) == 0)
  1672. {
  1673. // free it first
  1674. free(dll__environ[i]);
  1675. dll__environ[i] = NULL;
  1676. free_position = &dll__environ[i];
  1677. }
  1678. }
  1679. else
  1680. {
  1681. free_position = &dll__environ[i];
  1682. }
  1683. }
  1684. if (free_position != NULL)
  1685. {
  1686. // free position, copy value
  1687. size = strlen(var) + strlen(value) + 2;
  1688. *free_position = (char*)malloc(size); // for '=' and 0 termination
  1689. if ((*free_position))
  1690. {
  1691. strncpy(*free_position, var, size);
  1692. (*free_position)[size - 1] = '\0';
  1693. strncat(*free_position, "=", size - strlen(*free_position));
  1694. strncat(*free_position, value, size - strlen(*free_position));
  1695. added = true;
  1696. }
  1697. }
  1698. }
  1699. free(value);
  1700. }
  1701. }
  1702. return added ? 0 : -1;
  1703. }
  1704. char* dll_getenv(const char* szKey)
  1705. {
  1706. char* value = NULL;
  1707. {
  1708. CSingleLock lock(dll_cs_environ);
  1709. update_emu_environ();//apply any changes
  1710. for (int i = 0; i < EMU_MAX_ENVIRONMENT_ITEMS && value == NULL; i++)
  1711. {
  1712. if (dll__environ[i])
  1713. {
  1714. if (StringUtils::CompareNoCase(dll__environ[i], szKey, strlen(szKey)) == 0)
  1715. {
  1716. // found it
  1717. value = dll__environ[i] + strlen(szKey) + 1;
  1718. }
  1719. }
  1720. }
  1721. }
  1722. if (value != NULL)
  1723. {
  1724. return value;
  1725. }
  1726. return NULL;
  1727. }
  1728. int dll_ctype(int i)
  1729. {
  1730. not_implement("msvcrt.dll fake function dll_ctype() called\n");
  1731. return 0;
  1732. }
  1733. int dll_system(const char *command)
  1734. {
  1735. not_implement("msvcrt.dll fake function dll_system() called\n");
  1736. return 0; //system(command);
  1737. }
  1738. void (__cdecl * dll_signal(int sig, void (__cdecl *func)(int)))(int)
  1739. {
  1740. #if defined(TARGET_WINDOWS)
  1741. //vs2008 asserts for known signals, return err for everything unknown to windows.
  1742. if (sig == 5 || sig == 7 || sig == 9 || sig == 10 || sig == 12 || sig == 14 || sig == 18 || sig == 19 || sig == 20)
  1743. return SIG_ERR;
  1744. #endif
  1745. return signal(sig, func);
  1746. }
  1747. int dll_getpid()
  1748. {
  1749. return 1;
  1750. }
  1751. int dll__commit(int fd)
  1752. {
  1753. CFile* pFile = g_emuFileWrapper.GetFileXbmcByDescriptor(fd);
  1754. if (pFile != NULL)
  1755. {
  1756. pFile->Flush();
  1757. return 0;
  1758. }
  1759. else if (!IS_STD_DESCRIPTOR(fd))
  1760. {
  1761. // it might be something else than a file, or the file is not emulated
  1762. // let the operating system handle it
  1763. #ifndef TARGET_POSIX
  1764. return _commit(fd);
  1765. #else
  1766. return fsync(fd);
  1767. #endif
  1768. }
  1769. // std stream, no need to flush
  1770. return 0;
  1771. }
  1772. char*** dll___p__environ()
  1773. {
  1774. static char*** t = &dll__environ;
  1775. return (char***)&t;
  1776. }
  1777. #ifdef TARGET_POSIX
  1778. #if defined(TARGET_ANDROID)
  1779. volatile int * __cdecl dll_errno(void)
  1780. {
  1781. return &errno;
  1782. }
  1783. #else
  1784. int * __cdecl dll_errno(void)
  1785. {
  1786. return &errno;
  1787. }
  1788. #endif
  1789. int __cdecl dll_ioctl(int fd, unsigned long int request, va_list va)
  1790. {
  1791. int ret;
  1792. CFile* pFile = g_emuFileWrapper.GetFileXbmcByDescriptor(fd);
  1793. if (!pFile)
  1794. return -1;
  1795. #if defined(HAS_DVD_DRIVE) && !defined(TARGET_FREEBSD)
  1796. #if !defined(TARGET_DARWIN)
  1797. if(request == DVD_READ_STRUCT || request == DVD_AUTH)
  1798. #else
  1799. if(request == DKIOCDVDSENDKEY || request == DKIOCDVDREPORTKEY || request == DKIOCDVDREADSTRUCTURE)
  1800. #endif
  1801. {
  1802. void *p1 = va_arg(va, void*);
  1803. SNativeIoControl d;
  1804. d.request = request;
  1805. d.param = p1;
  1806. ret = pFile->IoControl(IOCTRL_NATIVE, &d);
  1807. if(ret<0)
  1808. CLog::Log(LOGWARNING, "%s - %ld request failed with error [%d] %s", __FUNCTION__, request, errno, strerror(errno));
  1809. }
  1810. else
  1811. #endif
  1812. {
  1813. CLog::Log(LOGWARNING, "%s - Unknown request type %ld", __FUNCTION__, request);
  1814. ret = -1;
  1815. }
  1816. return ret;
  1817. }
  1818. #endif
  1819. int dll_setvbuf(FILE *stream, char *buf, int type, size_t size)
  1820. {
  1821. CLog::Log(LOGWARNING, "%s - May not be implemented correctly",
  1822. __FUNCTION__);
  1823. return 0;
  1824. }
  1825. struct mntent *dll_getmntent(FILE *fp)
  1826. {
  1827. if (fp == NULL)
  1828. return NULL;
  1829. CFile* pFile = g_emuFileWrapper.GetFileXbmcByStream(fp);
  1830. if (pFile)
  1831. {
  1832. CLog::Log(LOGERROR, "%s - getmntent is not implemented for our virtual filesystem", __FUNCTION__);
  1833. return NULL;
  1834. }
  1835. #if defined(TARGET_LINUX)
  1836. return getmntent(fp);
  1837. #else
  1838. CLog::Log(LOGWARNING, "%s - unimplemented function called", __FUNCTION__);
  1839. return NULL;
  1840. #endif
  1841. }
  1842. // this needs to be wrapped, since dll's have their own file
  1843. // descriptor list, but we always use app's list with our wrappers
  1844. int __cdecl dll_open_osfhandle(intptr_t _OSFileHandle, int _Flags)
  1845. {
  1846. #ifdef TARGET_WINDOWS
  1847. return _open_osfhandle(_OSFileHandle, _Flags);
  1848. #else
  1849. return -1;
  1850. #endif
  1851. }
  1852. }