text: /* iowin32.c -- IO base function header for compress/uncompress .zip
       Version 1.1, February 14h, 2010
       part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
  
           Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
  
           Modifications for Zip64 support
           Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
  
       For more info read MiniZip_info.txt
  
  */
  
  #include <stdlib.h>
  
  #include "zlib.h"
  #include "ioapi.h"
  #include "iowin32.h"
  
  #ifndef INVALID_HANDLE_VALUE
  #define INVALID_HANDLE_VALUE (0xFFFFFFFF)
  #endif
  
  #ifndef INVALID_SET_FILE_POINTER
  #define INVALID_SET_FILE_POINTER ((DWORD)-1)
  #endif
  
  
  // see Include/shared/winapifamily.h in the Windows Kit
  #if defined(WINAPI_FAMILY_PARTITION) && (!(defined(IOWIN32_USING_WINRT_API)))
  #if WINAPI_FAMILY_ONE_PARTITION(WINAPI_FAMILY, WINAPI_PARTITION_APP)
  #define IOWIN32_USING_WINRT_API 1
  #endif
  #endif
  
  voidpf  ZCALLBACK win32_open_file_func  OF((voidpf opaque, const char* filename, int mode));
  uLong   ZCALLBACK win32_read_file_func  OF((voidpf opaque, voidpf stream, void* buf, uLong size));
  uLong   ZCALLBACK win32_write_file_func OF((voidpf opaque, voidpf stream, const void* buf, uLong size));
  ZPOS64_T ZCALLBACK win32_tell64_file_func  OF((voidpf opaque, voidpf stream));
  long    ZCALLBACK win32_seek64_file_func  OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin));
  int     ZCALLBACK win32_close_file_func OF((voidpf opaque, voidpf stream));
  int     ZCALLBACK win32_error_file_func OF((voidpf opaque, voidpf stream));
  
  typedef struct
  {
      HANDLE hf;
      int error;
  } WIN32FILE_IOWIN;
  
  
  static void win32_translate_open_mode(int mode,
                                        DWORD* lpdwDesiredAccess,
                                        DWORD* lpdwCreationDisposition,
                                        DWORD* lpdwShareMode,
                                        DWORD* lpdwFlagsAndAttributes)
  {
      *lpdwDesiredAccess = *lpdwShareMode = *lpdwFlagsAndAttributes = *lpdwCreationDisposition = 0;
  
      if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
      {
          *lpdwDesiredAccess = GENERIC_READ;
          *lpdwCreationDisposition = OPEN_EXISTING;
          *lpdwShareMode = FILE_SHARE_READ;
      }
      else if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
      {
          *lpdwDesiredAccess = GENERIC_WRITE | GENERIC_READ;
          *lpdwCreationDisposition = OPEN_EXISTING;
      }
      else if (mode & ZLIB_FILEFUNC_MODE_CREATE)
      {
          *lpdwDesiredAccess = GENERIC_WRITE | GENERIC_READ;
          *lpdwCreationDisposition = CREATE_ALWAYS;
      }
  }
  
  static voidpf win32_build_iowin(HANDLE hFile)
  {
      voidpf ret=NULL;
  
      if ((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))
      {
          WIN32FILE_IOWIN w32fiow;
          w32fiow.hf = hFile;
          w32fiow.error = 0;
          ret = malloc(sizeof(WIN32FILE_IOWIN));
  
          if (ret==NULL)
              CloseHandle(hFile);
          else
              *((WIN32FILE_IOWIN*)ret) = w32fiow;
      }
      return ret;
  }
  
  voidpf ZCALLBACK win32_open64_file_func (voidpf opaque,const void* filename,int mode)
  {
      const char* mode_fopen = NULL;
      DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ;
      HANDLE hFile = NULL;
  
      win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes);
  
  #ifdef IOWIN32_USING_WINRT_API
  #ifdef UNICODE
      if ((filename!=NULL) && (dwDesiredAccess != 0))
          hFile = CreateFile2((LPCTSTR)filename, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL);
  #else
      if ((filename!=NULL) && (dwDesiredAccess != 0))
      {
          WCHAR filenameW[FILENAME_MAX + 0x200 + 1];
          MultiByteToWideChar(CP_ACP,0,(const char*)filename,-1,filenameW,FILENAME_MAX + 0x200);
          hFile = CreateFile2(filenameW, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL);
      }
  #endif
  #else
      if ((filename!=NULL) && (dwDesiredAccess != 0))
          hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL);
  #endif
  
      return win32_build_iowin(hFile);
  }
  
  
  voidpf ZCALLBACK win32_open64_file_funcA (voidpf opaque,const void* filename,int mode)
  {
      const char* mode_fopen = NULL;
      DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ;
      HANDLE hFile = NULL;
  
      win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes);
  
  #ifdef IOWIN32_USING_WINRT_API
      if ((filename!=NULL) && (dwDesiredAccess != 0))
      {
          WCHAR filenameW[FILENAME_MAX + 0x200 + 1];
          MultiByteToWideChar(CP_ACP,0,(const char*)filename,-1,filenameW,FILENAME_MAX + 0x200);
          hFile = CreateFile2(filenameW, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL);
      }
  #else
      if ((filename!=NULL) && (dwDesiredAccess != 0))
          hFile = CreateFileA((LPCSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL);
  #endif
  
      return win32_build_iowin(hFile);
  }
  
  
  voidpf ZCALLBACK win32_open64_file_funcW (voidpf opaque,const void* filename,int mode)
  {
      const char* mode_fopen = NULL;
      DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ;
      HANDLE hFile = NULL;
  
      win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes);
  
  #ifdef IOWIN32_USING_WINRT_API
      if ((filename!=NULL) && (dwDesiredAccess != 0))
          hFile = CreateFile2((LPCWSTR)filename, dwDesiredAccess, dwShareMode, dwCreationDisposition,NULL);
  #else
      if ((filename!=NULL) && (dwDesiredAccess != 0))
          hFile = CreateFileW((LPCWSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL);
  #endif
  
      return win32_build_iowin(hFile);
  }
  
  
  voidpf ZCALLBACK win32_open_file_func (voidpf opaque,const char* filename,int mode)
  {
      const char* mode_fopen = NULL;
      DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ;
      HANDLE hFile = NULL;
  
      win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes);
  
  #ifdef IOWIN32_USING_WINRT_API
  #ifdef UNICODE
      if ((filename!=NULL) && (dwDesiredAccess != 0))
          hFile = CreateFile2((LPCTSTR)filename, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL);
  #else
      if ((filename!=NULL) && (dwDesiredAccess != 0))
      {
          WCHAR filenameW[FILENAME_MAX + 0x200 + 1];
          MultiByteToWideChar(CP_ACP,0,(const char*)filename,-1,filenameW,FILENAME_MAX + 0x200);
          hFile = CreateFile2(filenameW, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL);
      }
  #endif
  #else
      if ((filename!=NULL) && (dwDesiredAccess != 0))
          hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL);
  #endif
  
      return win32_build_iowin(hFile);
  }
  
  
  uLong ZCALLBACK win32_read_file_func (voidpf opaque, voidpf stream, void* buf,uLong size)
  {
      uLong ret=0;
      HANDLE hFile = NULL;
      if (stream!=NULL)
          hFile = ((WIN32FILE_IOWIN*)stream) -> hf;
  
      if (hFile != NULL)
      {
          if (!ReadFile(hFile, buf, size, &ret, NULL))
          {
              DWORD dwErr = GetLastError();
              if (dwErr == ERROR_HANDLE_EOF)
                  dwErr = 0;
              ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr;
          }
      }
  
      return ret;
  }
  
  
  uLong ZCALLBACK win32_write_file_func (voidpf opaque,voidpf stream,const void* buf,uLong size)
  {
      uLong ret=0;
      HANDLE hFile = NULL;
      if (stream!=NULL)
          hFile = ((WIN32FILE_IOWIN*)stream) -> hf;
  
      if (hFile != NULL)
      {
          if (!WriteFile(hFile, buf, size, &ret, NULL))
          {
              DWORD dwErr = GetLastError();
              if (dwErr == ERROR_HANDLE_EOF)
                  dwErr = 0;
              ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr;
          }
      }
  
      return ret;
  }
  
  static BOOL MySetFilePointerEx(HANDLE hFile, LARGE_INTEGER pos, LARGE_INTEGER *newPos,  DWORD dwMoveMethod)
  {
  #ifdef IOWIN32_USING_WINRT_API
      return SetFilePointerEx(hFile, pos, newPos, dwMoveMethod);
  #else
      LONG lHigh = pos.HighPart;
      DWORD dwNewPos = SetFilePointer(hFile, pos.LowPart, &lHigh, dwMoveMethod);
      BOOL fOk = TRUE;
      if (dwNewPos == 0xFFFFFFFF)
          if (GetLastError() != NO_ERROR)
              fOk = FALSE;
      if ((newPos != NULL) && (fOk))
      {
          newPos->LowPart = dwNewPos;
          newPos->HighPart = lHigh;
      }
      return fOk;
  #endif
  }
  
  long ZCALLBACK win32_tell_file_func (voidpf opaque,voidpf stream)
  {
      long ret=-1;
      HANDLE hFile = NULL;
      if (stream!=NULL)
          hFile = ((WIN32FILE_IOWIN*)stream) -> hf;
      if (hFile != NULL)
      {
          LARGE_INTEGER pos;
          pos.QuadPart = 0;
  
          if (!MySetFilePointerEx(hFile, pos, &pos, FILE_CURRENT))
          {
              DWORD dwErr = GetLastError();
              ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr;
              ret = -1;
          }
          else
              ret=(long)pos.LowPart;
      }
      return ret;
  }
  
  ZPOS64_T ZCALLBACK win32_tell64_file_func (voidpf opaque, voidpf stream)
  {
      ZPOS64_T ret= (ZPOS64_T)-1;
      HANDLE hFile = NULL;
      if (stream!=NULL)
          hFile = ((WIN32FILE_IOWIN*)stream)->hf;
  
      if (hFile)
      {
          LARGE_INTEGER pos;
          pos.QuadPart = 0;
  
          if (!MySetFilePointerEx(hFile, pos, &pos, FILE_CURRENT))
          {
              DWORD dwErr = GetLastError();
              ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr;
              ret = (ZPOS64_T)-1;
          }
          else
              ret=pos.QuadPart;
      }
      return ret;
  }
  
  
  long ZCALLBACK win32_seek_file_func (voidpf opaque,voidpf stream,uLong offset,int origin)
  {
      DWORD dwMoveMethod=0xFFFFFFFF;
      HANDLE hFile = NULL;
  
      long ret=-1;
      if (stream!=NULL)
          hFile = ((WIN32FILE_IOWIN*)stream) -> hf;
      switch (origin)
      {
      case ZLIB_FILEFUNC_SEEK_CUR :
          dwMoveMethod = FILE_CURRENT;
          break;
      case ZLIB_FILEFUNC_SEEK_END :
          dwMoveMethod = FILE_END;
          break;
      case ZLIB_FILEFUNC_SEEK_SET :
          dwMoveMethod = FILE_BEGIN;
          break;
      default: return -1;
      }
  
      if (hFile != NULL)
      {
          LARGE_INTEGER pos;
          pos.QuadPart = offset;
          if (!MySetFilePointerEx(hFile, pos, NULL, dwMoveMethod))
          {
              DWORD dwErr = GetLastError();
              ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr;
              ret = -1;
          }
          else
              ret=0;
      }
      return ret;
  }
  
  long ZCALLBACK win32_seek64_file_func (voidpf opaque, voidpf stream,ZPOS64_T offset,int origin)
  {
      DWORD dwMoveMethod=0xFFFFFFFF;
      HANDLE hFile = NULL;
      long ret=-1;
  
      if (stream!=NULL)
          hFile = ((WIN32FILE_IOWIN*)stream)->hf;
  
      switch (origin)
      {
          case ZLIB_FILEFUNC_SEEK_CUR :
              dwMoveMethod = FILE_CURRENT;
              break;
          case ZLIB_FILEFUNC_SEEK_END :
              dwMoveMethod = FILE_END;
              break;
          case ZLIB_FILEFUNC_SEEK_SET :
              dwMoveMethod = FILE_BEGIN;
              break;
          default: return -1;
      }
  
      if (hFile)
      {
          LARGE_INTEGER pos;
          pos.QuadPart = offset;
          if (!MySetFilePointerEx(hFile, pos, NULL, dwMoveMethod))
          {
              DWORD dwErr = GetLastError();
              ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr;
              ret = -1;
          }
          else
              ret=0;
      }
      return ret;
  }
  
  int ZCALLBACK win32_close_file_func (voidpf opaque, voidpf stream)
  {
      int ret=-1;
  
      if (stream!=NULL)
      {
          HANDLE hFile;
          hFile = ((WIN32FILE_IOWIN*)stream) -> hf;
          if (hFile != NULL)
          {
              CloseHandle(hFile);
              ret=0;
          }
          free(stream);
      }
      return ret;
  }
  
  int ZCALLBACK win32_error_file_func (voidpf opaque,voidpf stream)
  {
      int ret=-1;
      if (stream!=NULL)
      {
          ret = ((WIN32FILE_IOWIN*)stream) -> error;
      }
      return ret;
  }
  
  void fill_win32_filefunc (zlib_filefunc_def* pzlib_filefunc_def)
  {
      pzlib_filefunc_def->zopen_file = win32_open_file_func;
      pzlib_filefunc_def->zread_file = win32_read_file_func;
      pzlib_filefunc_def->zwrite_file = win32_write_file_func;
      pzlib_filefunc_def->ztell_file = win32_tell_file_func;
      pzlib_filefunc_def->zseek_file = win32_seek_file_func;
      pzlib_filefunc_def->zclose_file = win32_close_file_func;
      pzlib_filefunc_def->zerror_file = win32_error_file_func;
      pzlib_filefunc_def->opaque = NULL;
  }
  
  void fill_win32_filefunc64(zlib_filefunc64_def* pzlib_filefunc_def)
  {
      pzlib_filefunc_def->zopen64_file = win32_open64_file_func;
      pzlib_filefunc_def->zread_file = win32_read_file_func;
      pzlib_filefunc_def->zwrite_file = win32_write_file_func;
      pzlib_filefunc_def->ztell64_file = win32_tell64_file_func;
      pzlib_filefunc_def->zseek64_file = win32_seek64_file_func;
      pzlib_filefunc_def->zclose_file = win32_close_file_func;
      pzlib_filefunc_def->zerror_file = win32_error_file_func;
      pzlib_filefunc_def->opaque = NULL;
  }
  
  
  void fill_win32_filefunc64A(zlib_filefunc64_def* pzlib_filefunc_def)
  {
      pzlib_filefunc_def->zopen64_file = win32_open64_file_funcA;
      pzlib_filefunc_def->zread_file = win32_read_file_func;
      pzlib_filefunc_def->zwrite_file = win32_write_file_func;
      pzlib_filefunc_def->ztell64_file = win32_tell64_file_func;
      pzlib_filefunc_def->zseek64_file = win32_seek64_file_func;
      pzlib_filefunc_def->zclose_file = win32_close_file_func;
      pzlib_filefunc_def->zerror_file = win32_error_file_func;
      pzlib_filefunc_def->opaque = NULL;
  }
  
  
  void fill_win32_filefunc64W(zlib_filefunc64_def* pzlib_filefunc_def)
  {
      pzlib_filefunc_def->zopen64_file = win32_open64_file_funcW;
      pzlib_filefunc_def->zread_file = win32_read_file_func;
      pzlib_filefunc_def->zwrite_file = win32_write_file_func;
      pzlib_filefunc_def->ztell64_file = win32_tell64_file_func;
      pzlib_filefunc_def->zseek64_file = win32_seek64_file_func;
      pzlib_filefunc_def->zclose_file = win32_close_file_func;
      pzlib_filefunc_def->zerror_file = win32_error_file_func;
      pzlib_filefunc_def->opaque = NULL;
  }
  