PageRenderTime 174ms CodeModel.GetById 17ms app.highlight 144ms RepoModel.GetById 1ms 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

Large files files are truncated, but you can click here to view the full file

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

Large files files are truncated, but you can click here to view the full file