misc/libphysfs/platform_winrt.cpp
changeset 13881 99b265e0d1d0
parent 13880 5f819b90d479
child 13882 b172a5d40eee
equal deleted inserted replaced
13880:5f819b90d479 13881:99b265e0d1d0
     1 /*
       
     2 * Windows Runtime support routines for PhysicsFS.
       
     3 *
       
     4 * Please see the file LICENSE.txt in the source's root directory.
       
     5 *
       
     6 *  This file is based on "platform_windows.c" by Ryan C. Gordon and Gregory S. Read.
       
     7 *  Windows Runtime-specific additions and changes are made by Martin "T-Bone" Ahrnbom. 
       
     8 *
       
     9 * Instructions for setting up PhysFS in a WinRT Universal 8.1 app in Visual Studio 2013:
       
    10 * (hopefully these instructions will be somewhat valid with Windows 10 Apps as well...)
       
    11 *
       
    12 *  1. In Visual Studio 2013 (or later?), hit File -> New -> Project...
       
    13 *  2. On the left, navigate to Templates -> Visual C++ -> Store Apps -> Universal Apps
       
    14 *  3. In the middle of the window, select "DLL (Universal Apps)"
       
    15 *  4. Near the bottom, give the project a name (like PhysFS-WinRT) and choose a location
       
    16 *  5. In the Solution Explorer (to the right typically), delete all .cpp and .h files in
       
    17 *     PhysFS-WinRT.Shared except targetver.h.
       
    18 *  6. In Windows Explorer, find the "src" folder of the PhysFS source code. Select all files
       
    19 * 	  in the folder (ignore the "lzma" folder, we're not including 7Zip support because it's messy to compile).
       
    20 *	  Drag and drop all of the source files onto PhysFS-WinRT-Shared in Visual Studio.
       
    21 *  7. In Windows Explorer, find the file called "physfs.h". Copy this file into a folder of its own somewhere.
       
    22 *	  I suggest naming that folder "include". This will be your "include" folder for any projects using PhysFS.
       
    23 *  8. In the Solution Explorer, right click on PhysFS-WinRT.Windows and select Properties. Make sure that "Configuration" is set to 
       
    24 *     "All Configurations" and "Platform" is set to "All Platforms" near the top of the window.
       
    25 *  9. On the left, select "Precompiled Headers". Change "Precompiled Header" from "Use (/Yu)" to "Not Using Precompiled Headers".
       
    26 * 10. On the left, navigate to Configuration Properties -> C/C++ -> Preprocessor. In Preprocessor Definitions, add "_CRT_SECURE_NO_WARNINGS"
       
    27 * 11. Hit the OK button.
       
    28 * 12. Repeat steps 8-11 but for PhysFS-WinRT.WindowsPhone.
       
    29 * 13. In the Solution Explorer, find "platform_winrt.cpp" in PhysFS-WinRT.Shared. Right click on it and select "Properties". 
       
    30 * 14. On the left, navigate to Configuration Properties -> C/C++ -> General. On the right, change "Consume Windows Runtime Extensions"
       
    31 *	  from "No" to "Yes (/ZW)". Hit "OK".
       
    32 * 15. Near the top of the Visual Studio window, select BUILD -> Batch Build... Hit "Select All", and then "Build".
       
    33 * 16. Now you have a bunch of .dll and .lib files, as well as an include folder that you can use in your projects!
       
    34 * 17. ???
       
    35 * 18. Profit!
       
    36 */
       
    37 
       
    38 /* !!! FIXME: remove the tabstops from this file. */
       
    39 /* !!! FIXME: maybe just merge this back into platform_windows.c? */
       
    40 
       
    41 #define __PHYSICSFS_INTERNAL__
       
    42 #include "physfs_platforms.h"
       
    43 
       
    44 #ifdef PHYSFS_PLATFORM_WINRT
       
    45 
       
    46 #include "physfs_internal.h"
       
    47 
       
    48 #include <windows.h>
       
    49 #include <errno.h>
       
    50 #include <ctype.h>
       
    51 #include <time.h>
       
    52 
       
    53 #define LOWORDER_UINT64(pos) ((PHYSFS_uint32) (pos & 0xFFFFFFFF))
       
    54 #define HIGHORDER_UINT64(pos) ((PHYSFS_uint32) ((pos >> 32) & 0xFFFFFFFF))
       
    55 
       
    56 
       
    57 /*
       
    58 * Users without the platform SDK don't have this defined.  The original docs
       
    59 *  for SetFilePointer() just said to compare with 0xFFFFFFFF, so this should
       
    60 *  work as desired.
       
    61 */
       
    62 #define PHYSFS_INVALID_SET_FILE_POINTER  0xFFFFFFFF
       
    63 
       
    64 /* just in case... */
       
    65 #define PHYSFS_INVALID_FILE_ATTRIBUTES   0xFFFFFFFF
       
    66 
       
    67 /* Not defined before the Vista SDK. */
       
    68 #define PHYSFS_IO_REPARSE_TAG_SYMLINK    0xA000000C
       
    69 
       
    70 
       
    71 #define UTF8_TO_UNICODE_STACK_MACRO(w_assignto, str) { \
       
    72     if (str == NULL) \
       
    73         w_assignto = NULL; \
       
    74     else { \
       
    75         const PHYSFS_uint64 len = (PHYSFS_uint64) ((strlen(str) + 1) * 2); \
       
    76         w_assignto = (WCHAR *) __PHYSFS_smallAlloc(len); \
       
    77         if (w_assignto != NULL) \
       
    78             PHYSFS_utf8ToUtf16(str, (PHYSFS_uint16 *) w_assignto, len); \
       
    79     } \
       
    80 } \
       
    81 
       
    82 /* Note this counts WCHARs, not codepoints! */
       
    83 static PHYSFS_uint64 wStrLen(const WCHAR *wstr)
       
    84 {
       
    85 	PHYSFS_uint64 len = 0;
       
    86 	while (*(wstr++))
       
    87 		len++;
       
    88 	return len;
       
    89 } /* wStrLen */
       
    90 
       
    91 /* !!! FIXME: do we really need readonly? If not, do we need this struct? */
       
    92 typedef struct
       
    93 {
       
    94 	HANDLE handle;
       
    95 	int readonly;
       
    96 } WinApiFile;
       
    97 
       
    98 static HANDLE detectCDThreadHandle = NULL;
       
    99 static HWND detectCDHwnd = 0;
       
   100 static volatile int initialDiscDetectionComplete = 0;
       
   101 static volatile DWORD drivesWithMediaBitmap = 0;
       
   102 
       
   103 
       
   104 static PHYSFS_ErrorCode errcodeFromWinApiError(const DWORD err)
       
   105 {
       
   106 	/*
       
   107 	* win32 error codes are sort of a tricky thing; Microsoft intentionally
       
   108 	*  doesn't list which ones a given API might trigger, there are several
       
   109 	*  with overlapping and unclear meanings...and there's 16 thousand of
       
   110 	*  them in Windows 7. It looks like the ones we care about are in the
       
   111 	*  first 500, but I can't say this list is perfect; we might miss
       
   112 	*  important values or misinterpret others.
       
   113 	*
       
   114 	* Don't treat this list as anything other than a work in progress.
       
   115 	*/
       
   116 	switch (err)
       
   117 	{
       
   118 	case ERROR_SUCCESS: return PHYSFS_ERR_OK;
       
   119 	case ERROR_ACCESS_DENIED: return PHYSFS_ERR_PERMISSION;
       
   120 	case ERROR_NETWORK_ACCESS_DENIED: return PHYSFS_ERR_PERMISSION;
       
   121 	case ERROR_NOT_READY: return PHYSFS_ERR_IO;
       
   122 	case ERROR_CRC: return PHYSFS_ERR_IO;
       
   123 	case ERROR_SEEK: return PHYSFS_ERR_IO;
       
   124 	case ERROR_SECTOR_NOT_FOUND: return PHYSFS_ERR_IO;
       
   125 	case ERROR_NOT_DOS_DISK: return PHYSFS_ERR_IO;
       
   126 	case ERROR_WRITE_FAULT: return PHYSFS_ERR_IO;
       
   127 	case ERROR_READ_FAULT: return PHYSFS_ERR_IO;
       
   128 	case ERROR_DEV_NOT_EXIST: return PHYSFS_ERR_IO;
       
   129 		/* !!! FIXME: ?? case ELOOP: return PHYSFS_ERR_SYMLINK_LOOP; */
       
   130 	case ERROR_BUFFER_OVERFLOW: return PHYSFS_ERR_BAD_FILENAME;
       
   131 	case ERROR_INVALID_NAME: return PHYSFS_ERR_BAD_FILENAME;
       
   132 	case ERROR_BAD_PATHNAME: return PHYSFS_ERR_BAD_FILENAME;
       
   133 	case ERROR_DIRECTORY: return PHYSFS_ERR_BAD_FILENAME;
       
   134 	case ERROR_FILE_NOT_FOUND: return PHYSFS_ERR_NOT_FOUND;
       
   135 	case ERROR_PATH_NOT_FOUND: return PHYSFS_ERR_NOT_FOUND;
       
   136 	case ERROR_DELETE_PENDING: return PHYSFS_ERR_NOT_FOUND;
       
   137 	case ERROR_INVALID_DRIVE: return PHYSFS_ERR_NOT_FOUND;
       
   138 	case ERROR_HANDLE_DISK_FULL: return PHYSFS_ERR_NO_SPACE;
       
   139 	case ERROR_DISK_FULL: return PHYSFS_ERR_NO_SPACE;
       
   140 		/* !!! FIXME: ?? case ENOTDIR: return PHYSFS_ERR_NOT_FOUND; */
       
   141 		/* !!! FIXME: ?? case EISDIR: return PHYSFS_ERR_NOT_A_FILE; */
       
   142 	case ERROR_WRITE_PROTECT: return PHYSFS_ERR_READ_ONLY;
       
   143 	case ERROR_LOCK_VIOLATION: return PHYSFS_ERR_BUSY;
       
   144 	case ERROR_SHARING_VIOLATION: return PHYSFS_ERR_BUSY;
       
   145 	case ERROR_CURRENT_DIRECTORY: return PHYSFS_ERR_BUSY;
       
   146 	case ERROR_DRIVE_LOCKED: return PHYSFS_ERR_BUSY;
       
   147 	case ERROR_PATH_BUSY: return PHYSFS_ERR_BUSY;
       
   148 	case ERROR_BUSY: return PHYSFS_ERR_BUSY;
       
   149 	case ERROR_NOT_ENOUGH_MEMORY: return PHYSFS_ERR_OUT_OF_MEMORY;
       
   150 	case ERROR_OUTOFMEMORY: return PHYSFS_ERR_OUT_OF_MEMORY;
       
   151 	case ERROR_DIR_NOT_EMPTY: return PHYSFS_ERR_DIR_NOT_EMPTY;
       
   152 	default: return PHYSFS_ERR_OS_ERROR;
       
   153 	} /* switch */
       
   154 } /* errcodeFromWinApiError */
       
   155 
       
   156 static inline PHYSFS_ErrorCode errcodeFromWinApi(void)
       
   157 {
       
   158 	return errcodeFromWinApiError(GetLastError());
       
   159 } /* errcodeFromWinApi */
       
   160 
       
   161 
       
   162 typedef BOOL(WINAPI *fnSTEM)(DWORD, LPDWORD b);
       
   163 
       
   164 static DWORD pollDiscDrives(void)
       
   165 {
       
   166 	// We don't do discs
       
   167 	return 0;
       
   168 } /* pollDiscDrives */
       
   169 
       
   170 
       
   171 static LRESULT CALLBACK detectCDWndProc(HWND hwnd, UINT msg,
       
   172 	WPARAM wp, LPARAM lparam)
       
   173 {
       
   174 	return FALSE;
       
   175 } /* detectCDWndProc */
       
   176 
       
   177 
       
   178 static DWORD WINAPI detectCDThread(LPVOID lpParameter)
       
   179 {
       
   180 	return 0;
       
   181 } /* detectCDThread */
       
   182 
       
   183 
       
   184 void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
       
   185 {
       
   186 	return;
       
   187 } /* __PHYSFS_platformDetectAvailableCDs */
       
   188 
       
   189 
       
   190 static char *unicodeToUtf8Heap(const WCHAR *w_str)
       
   191 {
       
   192 	char *retval = NULL;
       
   193 	if (w_str != NULL)
       
   194 	{
       
   195 		void *ptr = NULL;
       
   196 		const PHYSFS_uint64 len = (wStrLen(w_str) * 4) + 1;
       
   197 		retval = (char*)allocator.Malloc(len);
       
   198 		BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
       
   199 		PHYSFS_utf8FromUtf16((const PHYSFS_uint16 *)w_str, retval, len);
       
   200 		ptr = allocator.Realloc(retval, strlen(retval) + 1); /* shrink. */
       
   201 		if (ptr != NULL)
       
   202 			retval = (char *)ptr;
       
   203 	} /* if */
       
   204 	return retval;
       
   205 } /* unicodeToUtf8Heap */
       
   206 
       
   207 char *__PHYSFS_platformCalcBaseDir(const char *argv0)
       
   208 {
       
   209 	const wchar_t* path = Windows::ApplicationModel::Package::Current->InstalledLocation->Path->Data();
       
   210 	wchar_t path2[1024];
       
   211 	wcscpy_s(path2, path);
       
   212 	wcscat_s(path2, L"\\");
       
   213 	return unicodeToUtf8Heap(path2);
       
   214 
       
   215 } /* __PHYSFS_platformCalcBaseDir */
       
   216 
       
   217 
       
   218 char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
       
   219 {
       
   220 	const wchar_t* path = Windows::Storage::ApplicationData::Current->LocalFolder->Path->Data();
       
   221 	wchar_t path2[1024];
       
   222 	wcscpy_s(path2, path);
       
   223 	wcscat_s(path2, L"\\");
       
   224 	return unicodeToUtf8Heap(path2);
       
   225 } /* __PHYSFS_platformCalcPrefDir */
       
   226 
       
   227 
       
   228 char *__PHYSFS_platformCalcUserDir(void)
       
   229 {
       
   230 	return __PHYSFS_platformCalcPrefDir(NULL, NULL);
       
   231 } /* __PHYSFS_platformCalcUserDir */
       
   232 
       
   233 
       
   234 void *__PHYSFS_platformGetThreadID(void)
       
   235 {
       
   236 	return ((void *)((size_t)GetCurrentThreadId()));
       
   237 } /* __PHYSFS_platformGetThreadID */
       
   238 
       
   239 
       
   240 static int isSymlinkAttrs(const DWORD attr, const DWORD tag)
       
   241 {
       
   242 	return ((attr & FILE_ATTRIBUTE_REPARSE_POINT) &&
       
   243 		(tag == PHYSFS_IO_REPARSE_TAG_SYMLINK));
       
   244 } /* isSymlinkAttrs */
       
   245 
       
   246 
       
   247 void __PHYSFS_platformEnumerateFiles(const char *dirname,
       
   248 	PHYSFS_EnumFilesCallback callback,
       
   249 	const char *origdir,
       
   250 	void *callbackdata)
       
   251 {
       
   252 
       
   253 	HANDLE dir = INVALID_HANDLE_VALUE;
       
   254 	WIN32_FIND_DATAW entw;
       
   255 	size_t len = strlen(dirname);
       
   256 	char *searchPath = NULL;
       
   257 	WCHAR *wSearchPath = NULL;
       
   258 
       
   259 	/* Allocate a new string for path, maybe '\\', "*", and NULL terminator */
       
   260 	searchPath = (char *)__PHYSFS_smallAlloc(len + 3);
       
   261 	if (searchPath == NULL)
       
   262 		return;
       
   263 
       
   264 	/* Copy current dirname */
       
   265 	strcpy(searchPath, dirname);
       
   266 
       
   267 	/* if there's no '\\' at the end of the path, stick one in there. */
       
   268 	if (searchPath[len - 1] != '\\')
       
   269 	{
       
   270 		searchPath[len++] = '\\';
       
   271 		searchPath[len] = '\0';
       
   272 	} /* if */
       
   273 
       
   274 	/* Append the "*" to the end of the string */
       
   275 	strcat(searchPath, "*");
       
   276 
       
   277 	UTF8_TO_UNICODE_STACK_MACRO(wSearchPath, searchPath);
       
   278 	if (!wSearchPath)
       
   279 		return;  /* oh well. */
       
   280 
       
   281 	//dir = FindFirstFileW(wSearchPath, &entw);
       
   282 	dir = FindFirstFileExW(wSearchPath, FindExInfoStandard, &entw, FindExSearchNameMatch, NULL, 0);
       
   283 
       
   284 	__PHYSFS_smallFree(wSearchPath);
       
   285 	__PHYSFS_smallFree(searchPath);
       
   286 	if (dir == INVALID_HANDLE_VALUE)
       
   287 		return;
       
   288 
       
   289 	do
       
   290 	{
       
   291 		const DWORD attr = entw.dwFileAttributes;
       
   292 		const DWORD tag = entw.dwReserved0;
       
   293 		const WCHAR *fn = entw.cFileName;
       
   294 		char *utf8;
       
   295 
       
   296 		if ((fn[0] == '.') && (fn[1] == '\0'))
       
   297 			continue;
       
   298 		if ((fn[0] == '.') && (fn[1] == '.') && (fn[2] == '\0'))
       
   299 			continue;
       
   300 
       
   301 		utf8 = unicodeToUtf8Heap(fn);
       
   302 		if (utf8 != NULL)
       
   303 		{
       
   304 			callback(callbackdata, origdir, utf8);
       
   305 			allocator.Free(utf8);
       
   306 		} /* if */
       
   307 	} while (FindNextFileW(dir, &entw) != 0);
       
   308 
       
   309 	FindClose(dir);
       
   310 } /* __PHYSFS_platformEnumerateFiles */
       
   311 
       
   312 
       
   313 int __PHYSFS_platformMkDir(const char *path)
       
   314 {
       
   315 	WCHAR *wpath;
       
   316 	DWORD rc;
       
   317 	UTF8_TO_UNICODE_STACK_MACRO(wpath, path);
       
   318 	rc = CreateDirectoryW(wpath, NULL);
       
   319 	__PHYSFS_smallFree(wpath);
       
   320 	BAIL_IF_MACRO(rc == 0, errcodeFromWinApi(), 0);
       
   321 	return 1;
       
   322 } /* __PHYSFS_platformMkDir */
       
   323 
       
   324 
       
   325 int __PHYSFS_platformInit(void)
       
   326 {
       
   327 	return 1;  /* It's all good */
       
   328 } /* __PHYSFS_platformInit */
       
   329 
       
   330 
       
   331 int __PHYSFS_platformDeinit(void)
       
   332 {
       
   333 	return 1; /* It's all good */
       
   334 } /* __PHYSFS_platformDeinit */
       
   335 
       
   336 
       
   337 static void *doOpen(const char *fname, DWORD mode, DWORD creation, int rdonly)
       
   338 {
       
   339 	HANDLE fileh;
       
   340 	WinApiFile *retval;
       
   341 	WCHAR *wfname;
       
   342 
       
   343 	UTF8_TO_UNICODE_STACK_MACRO(wfname, fname);
       
   344 	BAIL_IF_MACRO(!wfname, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
       
   345 	//fileh = CreateFileW(wfname, mode, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, creation, FILE_ATTRIBUTE_NORMAL, NULL);
       
   346 	fileh = CreateFile2(wfname, mode, FILE_SHARE_READ | FILE_SHARE_WRITE, creation, NULL);
       
   347 	__PHYSFS_smallFree(wfname);
       
   348 
       
   349 	BAIL_IF_MACRO(fileh == INVALID_HANDLE_VALUE, errcodeFromWinApi(), NULL);
       
   350 
       
   351 	retval = (WinApiFile *)allocator.Malloc(sizeof(WinApiFile));
       
   352 	if (!retval)
       
   353 	{
       
   354 		CloseHandle(fileh);
       
   355 		BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
       
   356 	} /* if */
       
   357 
       
   358 	retval->readonly = rdonly;
       
   359 	retval->handle = fileh;
       
   360 	return retval;
       
   361 } /* doOpen */
       
   362 
       
   363 
       
   364 void *__PHYSFS_platformOpenRead(const char *filename)
       
   365 {
       
   366 	return doOpen(filename, GENERIC_READ, OPEN_EXISTING, 1);
       
   367 } /* __PHYSFS_platformOpenRead */
       
   368 
       
   369 
       
   370 void *__PHYSFS_platformOpenWrite(const char *filename)
       
   371 {
       
   372 	return doOpen(filename, GENERIC_WRITE, CREATE_ALWAYS, 0);
       
   373 } /* __PHYSFS_platformOpenWrite */
       
   374 
       
   375 
       
   376 void *__PHYSFS_platformOpenAppend(const char *filename)
       
   377 {
       
   378 	void *retval = doOpen(filename, GENERIC_WRITE, OPEN_ALWAYS, 0);
       
   379 	if (retval != NULL)
       
   380 	{
       
   381 		HANDLE h = ((WinApiFile *)retval)->handle;
       
   382 		//DWORD rc = SetFilePointer(h, 0, NULL, FILE_END);
       
   383 		const LARGE_INTEGER zero = { 0 };
       
   384 		DWORD rc = SetFilePointerEx(h, zero, NULL, FILE_END);
       
   385 		if (rc == PHYSFS_INVALID_SET_FILE_POINTER)
       
   386 		{
       
   387 			const PHYSFS_ErrorCode err = errcodeFromWinApi();
       
   388 			CloseHandle(h);
       
   389 			allocator.Free(retval);
       
   390 			BAIL_MACRO(err, NULL);
       
   391 		} /* if */
       
   392 	} /* if */
       
   393 
       
   394 	return retval;
       
   395 } /* __PHYSFS_platformOpenAppend */
       
   396 
       
   397 
       
   398 PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buf, PHYSFS_uint64 len)
       
   399 {
       
   400 	HANDLE Handle = ((WinApiFile *)opaque)->handle;
       
   401 	PHYSFS_sint64 totalRead = 0;
       
   402 
       
   403 	if (!__PHYSFS_ui64FitsAddressSpace(len))
       
   404 		BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, -1);
       
   405 
       
   406 	while (len > 0)
       
   407 	{
       
   408 		const DWORD thislen = (len > 0xFFFFFFFF) ? 0xFFFFFFFF : (DWORD)len;
       
   409 		DWORD numRead = 0;
       
   410 		if (!ReadFile(Handle, buf, thislen, &numRead, NULL))
       
   411 			BAIL_MACRO(errcodeFromWinApi(), -1);
       
   412 		len -= (PHYSFS_uint64)numRead;
       
   413 		totalRead += (PHYSFS_sint64)numRead;
       
   414 		if (numRead != thislen)
       
   415 			break;
       
   416 	} /* while */
       
   417 	
       
   418 	return totalRead;
       
   419 } /* __PHYSFS_platformRead */
       
   420 
       
   421 
       
   422 PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
       
   423 	PHYSFS_uint64 len)
       
   424 {
       
   425 	HANDLE Handle = ((WinApiFile *)opaque)->handle;
       
   426 	PHYSFS_sint64 totalWritten = 0;
       
   427 
       
   428 	if (!__PHYSFS_ui64FitsAddressSpace(len))
       
   429 		BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, -1);
       
   430 
       
   431 	while (len > 0)
       
   432 	{
       
   433 		const DWORD thislen = (len > 0xFFFFFFFF) ? 0xFFFFFFFF : (DWORD)len;
       
   434 		DWORD numWritten = 0;
       
   435 		if (!WriteFile(Handle, buffer, thislen, &numWritten, NULL))
       
   436 			BAIL_MACRO(errcodeFromWinApi(), -1);
       
   437 		len -= (PHYSFS_uint64)numWritten;
       
   438 		totalWritten += (PHYSFS_sint64)numWritten;
       
   439 		if (numWritten != thislen)
       
   440 			break;
       
   441 	} /* while */
       
   442 
       
   443 	return totalWritten;
       
   444 } /* __PHYSFS_platformWrite */
       
   445 
       
   446 
       
   447 int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos)
       
   448 {
       
   449 	HANDLE Handle = ((WinApiFile *)opaque)->handle;
       
   450 	BOOL rc;
       
   451 
       
   452 	LARGE_INTEGER li;
       
   453 	li.LowPart = LOWORDER_UINT64(pos);
       
   454 	li.HighPart = HIGHORDER_UINT64(pos);
       
   455 
       
   456 	rc = SetFilePointerEx(Handle, li, NULL, FILE_BEGIN);
       
   457 
       
   458 	if (!rc && (GetLastError() != NO_ERROR))
       
   459 	{
       
   460 		BAIL_MACRO(errcodeFromWinApi(), 0);
       
   461 	} /* if */
       
   462 
       
   463 	return 1;  /* No error occured */
       
   464 } /* __PHYSFS_platformSeek */
       
   465 
       
   466 
       
   467 PHYSFS_sint64 __PHYSFS_platformTell(void *opaque)
       
   468 {
       
   469 	HANDLE Handle = ((WinApiFile *)opaque)->handle;
       
   470 	PHYSFS_sint64 retval;
       
   471 	BOOL rc;
       
   472 
       
   473 	LARGE_INTEGER zero;
       
   474 	zero.QuadPart = 0;
       
   475 	LARGE_INTEGER out;
       
   476 
       
   477 	rc = SetFilePointerEx(Handle, zero, &out, FILE_CURRENT);
       
   478 	if (!rc)
       
   479 	{
       
   480 		BAIL_MACRO(errcodeFromWinApi(), -1);
       
   481 	} /* if */
       
   482 	else
       
   483 	{
       
   484 		retval = out.QuadPart;
       
   485 		assert(retval >= 0);
       
   486 	} /* else */
       
   487 
       
   488 	return retval;
       
   489 } /* __PHYSFS_platformTell */
       
   490 
       
   491 
       
   492 PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque)
       
   493 {
       
   494 	HANDLE Handle = ((WinApiFile *)opaque)->handle;
       
   495 	PHYSFS_sint64 retval;
       
   496 
       
   497 	FILE_STANDARD_INFO file_info = { 0 };
       
   498 	const BOOL res = GetFileInformationByHandleEx(Handle, FileStandardInfo, &file_info, sizeof(file_info));
       
   499 	if (res) {
       
   500 		retval = file_info.EndOfFile.QuadPart;
       
   501 		assert(retval >= 0);
       
   502 	}
       
   503 	else {
       
   504 		PHYSFS_setErrorCode(PHYSFS_ERR_NOT_FOUND);
       
   505 	}
       
   506 
       
   507 	
       
   508 	return retval;
       
   509 } /* __PHYSFS_platformFileLength */
       
   510 
       
   511 
       
   512 int __PHYSFS_platformFlush(void *opaque)
       
   513 {
       
   514 	WinApiFile *fh = ((WinApiFile *)opaque);
       
   515 	if (!fh->readonly)
       
   516 		BAIL_IF_MACRO(!FlushFileBuffers(fh->handle), errcodeFromWinApi(), 0);
       
   517 
       
   518 	return 1;
       
   519 } /* __PHYSFS_platformFlush */
       
   520 
       
   521 
       
   522 void __PHYSFS_platformClose(void *opaque)
       
   523 {
       
   524 	HANDLE Handle = ((WinApiFile *)opaque)->handle;
       
   525 	(void)CloseHandle(Handle); /* ignore errors. You should have flushed! */
       
   526 	allocator.Free(opaque);
       
   527 } /* __PHYSFS_platformClose */
       
   528 
       
   529 
       
   530 static int doPlatformDelete(LPWSTR wpath)
       
   531 {
       
   532 	//const int isdir = (GetFileAttributesW(wpath) & FILE_ATTRIBUTE_DIRECTORY);
       
   533 	int isdir = 0;
       
   534 	WIN32_FILE_ATTRIBUTE_DATA file_info;
       
   535 	const BOOL res = GetFileAttributesEx(wpath, GetFileExInfoStandard, &file_info);
       
   536 	if (res) {
       
   537 		isdir = (file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
       
   538 	}
       
   539 
       
   540 	const BOOL rc = (isdir) ? RemoveDirectoryW(wpath) : DeleteFileW(wpath);
       
   541 	BAIL_IF_MACRO(!rc, errcodeFromWinApi(), 0);
       
   542 	return 1;   /* if you made it here, it worked. */
       
   543 } /* doPlatformDelete */
       
   544 
       
   545 
       
   546 int __PHYSFS_platformDelete(const char *path)
       
   547 {
       
   548 	int retval = 0;
       
   549 	LPWSTR wpath = NULL;
       
   550 	UTF8_TO_UNICODE_STACK_MACRO(wpath, path);
       
   551 	BAIL_IF_MACRO(!wpath, PHYSFS_ERR_OUT_OF_MEMORY, 0);
       
   552 	retval = doPlatformDelete(wpath);
       
   553 	__PHYSFS_smallFree(wpath);
       
   554 	return retval;
       
   555 } /* __PHYSFS_platformDelete */
       
   556 
       
   557 
       
   558 void *__PHYSFS_platformCreateMutex(void)
       
   559 {
       
   560 	LPCRITICAL_SECTION lpcs;
       
   561 	lpcs = (LPCRITICAL_SECTION)allocator.Malloc(sizeof(CRITICAL_SECTION));
       
   562 	BAIL_IF_MACRO(!lpcs, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
       
   563 	//InitializeCriticalSection(lpcs);
       
   564 	InitializeCriticalSectionEx(lpcs, 2000, 0);
       
   565 	return lpcs;
       
   566 } /* __PHYSFS_platformCreateMutex */
       
   567 
       
   568 
       
   569 void __PHYSFS_platformDestroyMutex(void *mutex)
       
   570 {
       
   571 	DeleteCriticalSection((LPCRITICAL_SECTION)mutex);
       
   572 	allocator.Free(mutex);
       
   573 } /* __PHYSFS_platformDestroyMutex */
       
   574 
       
   575 
       
   576 int __PHYSFS_platformGrabMutex(void *mutex)
       
   577 {
       
   578 	EnterCriticalSection((LPCRITICAL_SECTION)mutex);
       
   579 	return 1;
       
   580 } /* __PHYSFS_platformGrabMutex */
       
   581 
       
   582 
       
   583 void __PHYSFS_platformReleaseMutex(void *mutex)
       
   584 {
       
   585 	LeaveCriticalSection((LPCRITICAL_SECTION)mutex);
       
   586 } /* __PHYSFS_platformReleaseMutex */
       
   587 
       
   588 
       
   589 static PHYSFS_sint64 FileTimeToPhysfsTime(const FILETIME *ft)
       
   590 {
       
   591 	SYSTEMTIME st_utc;
       
   592 	SYSTEMTIME st_localtz;
       
   593 	TIME_ZONE_INFORMATION tzi;
       
   594 	DWORD tzid;
       
   595 	PHYSFS_sint64 retval;
       
   596 	struct tm tm;
       
   597 	BOOL rc;
       
   598 
       
   599 	BAIL_IF_MACRO(!FileTimeToSystemTime(ft, &st_utc), errcodeFromWinApi(), -1);
       
   600 	tzid = GetTimeZoneInformation(&tzi);
       
   601 	BAIL_IF_MACRO(tzid == TIME_ZONE_ID_INVALID, errcodeFromWinApi(), -1);
       
   602 	rc = SystemTimeToTzSpecificLocalTime(&tzi, &st_utc, &st_localtz);
       
   603 	BAIL_IF_MACRO(!rc, errcodeFromWinApi(), -1);
       
   604 
       
   605 	/* Convert to a format that mktime() can grok... */
       
   606 	tm.tm_sec = st_localtz.wSecond;
       
   607 	tm.tm_min = st_localtz.wMinute;
       
   608 	tm.tm_hour = st_localtz.wHour;
       
   609 	tm.tm_mday = st_localtz.wDay;
       
   610 	tm.tm_mon = st_localtz.wMonth - 1;
       
   611 	tm.tm_year = st_localtz.wYear - 1900;
       
   612 	tm.tm_wday = -1 /*st_localtz.wDayOfWeek*/;
       
   613 	tm.tm_yday = -1;
       
   614 	tm.tm_isdst = -1;
       
   615 
       
   616 	/* Convert to a format PhysicsFS can grok... */
       
   617 	retval = (PHYSFS_sint64)mktime(&tm);
       
   618 	BAIL_IF_MACRO(retval == -1, PHYSFS_ERR_OS_ERROR, -1);
       
   619 	return retval;
       
   620 } /* FileTimeToPhysfsTime */
       
   621 
       
   622 
       
   623 int __PHYSFS_platformStat(const char *filename, PHYSFS_Stat *st)
       
   624 {
       
   625 	WIN32_FILE_ATTRIBUTE_DATA winstat;
       
   626 	WCHAR *wstr = NULL;
       
   627 	DWORD err = 0;
       
   628 	BOOL rc = 0;
       
   629 
       
   630 	UTF8_TO_UNICODE_STACK_MACRO(wstr, filename);
       
   631 	BAIL_IF_MACRO(!wstr, PHYSFS_ERR_OUT_OF_MEMORY, 0);
       
   632 	rc = GetFileAttributesExW(wstr, GetFileExInfoStandard, &winstat);
       
   633 	err = (!rc) ? GetLastError() : 0;
       
   634 	__PHYSFS_smallFree(wstr);
       
   635 	BAIL_IF_MACRO(!rc, errcodeFromWinApiError(err), 0);
       
   636 
       
   637 	st->modtime = FileTimeToPhysfsTime(&winstat.ftLastWriteTime);
       
   638 	st->accesstime = FileTimeToPhysfsTime(&winstat.ftLastAccessTime);
       
   639 	st->createtime = FileTimeToPhysfsTime(&winstat.ftCreationTime);
       
   640 
       
   641 	if (winstat.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
       
   642 	{
       
   643 		st->filetype = PHYSFS_FILETYPE_DIRECTORY;
       
   644 		st->filesize = 0;
       
   645 	} /* if */
       
   646 
       
   647 	else if (winstat.dwFileAttributes & (FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_DEVICE))
       
   648 	{
       
   649 		/* !!! FIXME: what are reparse points? */
       
   650 		st->filetype = PHYSFS_FILETYPE_OTHER;
       
   651 		/* !!! FIXME: don't rely on this */
       
   652 		st->filesize = 0;
       
   653 	} /* else if */
       
   654 
       
   655 	/* !!! FIXME: check for symlinks on Vista. */
       
   656 
       
   657 	else
       
   658 	{
       
   659 		st->filetype = PHYSFS_FILETYPE_REGULAR;
       
   660 		st->filesize = (((PHYSFS_uint64)winstat.nFileSizeHigh) << 32) | winstat.nFileSizeLow;
       
   661 	} /* else */
       
   662 
       
   663 	st->readonly = ((winstat.dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0);
       
   664 
       
   665 	return 1;
       
   666 } /* __PHYSFS_platformStat */
       
   667 
       
   668 
       
   669 /* !!! FIXME: Don't use C runtime for allocators? */
       
   670 int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
       
   671 {
       
   672 	return 0;  /* just use malloc() and friends. */
       
   673 } /* __PHYSFS_platformSetDefaultAllocator */
       
   674 
       
   675 
       
   676 #endif /* PHYSFS_PLATFORM_WINRT */