2 * PocketPC support routines for PhysicsFS.
4 * Please see the file LICENSE.txt in the source's root directory.
6 * This file written by Ryan C. Gordon.
9 #define __PHYSICSFS_INTERNAL__
10 #include "physfs_platforms.h"
12 #ifdef PHYSFS_PLATFORM_POCKETPC
17 #include "physfs_internal.h"
19 #define INVALID_FILE_ATTRIBUTES 0xFFFFFFFF
20 #define INVALID_SET_FILE_POINTER 0xFFFFFFFF
28 const char *__PHYSFS_platformDirSeparator = "\\";
29 static char *userDir = NULL;
32 * Figure out what the last failing Win32 API call was, and
33 * generate a human-readable string for the error message.
35 * The return value is a static buffer that is overwritten with
36 * each call to this function.
38 static const char *win32strerror(void)
40 static TCHAR msgbuf[255];
44 FORMAT_MESSAGE_FROM_SYSTEM |
45 FORMAT_MESSAGE_IGNORE_INSERTS,
48 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
50 sizeof (msgbuf) / sizeof (TCHAR),
54 /* chop off newlines. */
55 for (ptr = msgbuf; *ptr; ptr++)
57 if ((*ptr == '\n') || (*ptr == '\r'))
64 return((const char *) msgbuf);
68 /* !!! FIXME: need to check all of these for NULLs. */
69 #define UTF8_TO_UNICODE_STACK_MACRO(w_assignto, str) { \
73 const PHYSFS_uint64 len = (PHYSFS_uint64) ((strlen(str) * 4) + 1); \
74 w_assignto = (char *) __PHYSFS_smallAlloc(len); \
75 PHYSFS_uc2fromutf8(str, (PHYSFS_uint16 *) w_assignto, len); \
80 static char *getExePath()
85 TCHAR *retval = (TCHAR*) allocator.Malloc(sizeof (TCHAR) * (MAX_PATH + 1));
87 BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
90 /* !!! FIXME: don't preallocate here? */
91 /* !!! FIXME: use smallAlloc? */
92 buflen = GetModuleFileName(NULL, retval, MAX_PATH + 1);
94 __PHYSFS_setError(win32strerror());
97 retval[buflen] = '\0'; /* does API always null-terminate this? */
99 while( ptr != retval )
101 if( *ptr != _T('\\') )
111 allocator.Free(retval);
112 return(NULL); /* physfs error message will be set, above. */
115 buflen = (buflen * 4) + 1;
116 charretval = (char *) allocator.Malloc(buflen);
117 if (charretval != NULL)
118 PHYSFS_utf8fromucs2((const PHYSFS_uint16 *) retval, charretval, buflen);
119 allocator.Free(retval);
120 return(charretval); /* w00t. */
124 int __PHYSFS_platformInit(void)
126 userDir = getExePath();
127 BAIL_IF_MACRO(userDir == NULL, NULL, 0); /* failed? */
128 return(1); /* always succeed. */
129 } /* __PHYSFS_platformInit */
132 int __PHYSFS_platformDeinit(void)
134 allocator.Free(userDir);
135 return(1); /* always succeed. */
136 } /* __PHYSFS_platformDeinit */
139 void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
141 /* no-op on this platform. */
142 } /* __PHYSFS_platformDetectAvailableCDs */
145 char *__PHYSFS_platformCalcBaseDir(const char *argv0)
147 return(getExePath());
148 } /* __PHYSFS_platformCalcBaseDir */
151 char *__PHYSFS_platformGetUserName(void)
153 BAIL_MACRO(ERR_NOT_IMPLEMENTED, NULL);
154 } /* __PHYSFS_platformGetUserName */
157 char *__PHYSFS_platformGetUserDir(void)
160 BAIL_MACRO(ERR_NOT_IMPLEMENTED, NULL);
161 } /* __PHYSFS_platformGetUserDir */
164 PHYSFS_uint64 __PHYSFS_platformGetThreadID(void)
166 return(1); /* single threaded. */
167 } /* __PHYSFS_platformGetThreadID */
170 int __PHYSFS_platformExists(const char *fname)
173 wchar_t *w_fname = NULL;
175 UTF8_TO_UNICODE_STACK_MACRO(w_fname, fname);
177 retval = (GetFileAttributes(w_fname) != INVALID_FILE_ATTRIBUTES);
178 __PHYSFS_smallFree(w_fname);
181 } /* __PHYSFS_platformExists */
184 int __PHYSFS_platformIsSymLink(const char *fname)
186 BAIL_MACRO(ERR_NOT_IMPLEMENTED, 0);
187 } /* __PHYSFS_platformIsSymlink */
190 int __PHYSFS_platformIsDirectory(const char *fname)
193 wchar_t *w_fname = NULL;
195 UTF8_TO_UNICODE_STACK_MACRO(w_fname, fname);
197 retval = ((GetFileAttributes(w_fname) & FILE_ATTRIBUTE_DIRECTORY) != 0);
198 __PHYSFS_smallFree(w_fname);
201 } /* __PHYSFS_platformIsDirectory */
204 char *__PHYSFS_platformCvtToDependent(const char *prepend,
208 int len = ((prepend) ? strlen(prepend) : 0) +
209 ((append) ? strlen(append) : 0) +
211 char *retval = (char *) allocator.Malloc(len);
214 BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
217 strcpy(retval, prepend);
221 strcat(retval, dirName);
224 strcat(retval, append);
226 for (p = strchr(retval, '/'); p != NULL; p = strchr(p + 1, '/'))
230 } /* __PHYSFS_platformCvtToDependent */
233 static int doEnumCallback(const wchar_t *w_fname)
235 const PHYSFS_uint64 len = (PHYSFS_uint64) ((wcslen(w_fname) * 4) + 1);
236 char *str = (char *) __PHYSFS_smallAlloc(len);
237 PHYSFS_utf8fromucs2((const PHYSFS_uint16 *) w_fname, str, len);
238 callback(callbackdata, origdir, str);
239 __PHYSFS_smallFree(str);
241 } /* doEnumCallback */
244 void __PHYSFS_platformEnumerateFiles(const char *dirname,
246 PHYSFS_EnumFilesCallback callback,
253 wchar_t *w_SearchPath;
254 size_t len = strlen(dirname);
256 /* Allocate a new string for path, maybe '\\', "*", and NULL terminator */
257 SearchPath = (char *) __PHYSFS_smallAlloc(len + 3);
258 BAIL_IF_MACRO(SearchPath == NULL, ERR_OUT_OF_MEMORY, NULL);
260 /* Copy current dirname */
261 strcpy(SearchPath, dirname);
263 /* if there's no '\\' at the end of the path, stick one in there. */
264 if (SearchPath[len - 1] != '\\')
266 SearchPath[len++] = '\\';
267 SearchPath[len] = '\0';
270 /* Append the "*" to the end of the string */
271 strcat(SearchPath, "*");
273 UTF8_TO_UNICODE_STACK_MACRO(w_SearchPath, SearchPath);
274 __PHYSFS_smallFree(SearchPath);
275 dir = FindFirstFile(w_SearchPath, &ent);
276 __PHYSFS_smallFree(w_SearchPath);
278 if (dir == INVALID_HANDLE_VALUE)
283 const char *str = NULL;
285 if (wcscmp(ent.cFileName, L".") == 0)
288 if (wcscmp(ent.cFileName, L"..") == 0)
291 if (!doEnumCallback(ent.cFileName))
293 } while (FindNextFile(dir, &ent) != 0);
296 } /* __PHYSFS_platformEnumerateFiles */
299 char *__PHYSFS_platformCurrentDir(void)
302 } /* __PHYSFS_platformCurrentDir */
305 char *__PHYSFS_platformRealPath(const char *path)
307 char *retval = (char *) allocator.Malloc(strlen(path) + 1);
310 } /* __PHYSFS_platformRealPath */
313 int __PHYSFS_platformMkDir(const char *path)
316 wchar_t *w_path = NULL;
317 UTF8_TO_UNICODE_STACK_MACRO(w_path, path);
320 retval = CreateDirectory(w_path, NULL);
321 __PHYSFS_smallFree(w_fname);
324 } /* __PHYSFS_platformMkDir */
327 static void *doOpen(const char *fname, DWORD mode, DWORD creation, int rdonly)
331 wchar_t *w_fname = NULL;
333 UTF8_TO_UNICODE_STACK_MACRO(w_fname, fname);
334 fileHandle = CreateFile(w_fname, mode, FILE_SHARE_READ | FILE_SHARE_WRITE,
335 NULL, creation, FILE_ATTRIBUTE_NORMAL, NULL);
336 __PHYSFS_smallFree(w_fname);
338 BAIL_IF_MACRO(fileHandle == INVALID_HANDLE_VALUE, win32strerror(), NULL);
340 retval = (winCEfile *) allocator.Malloc(sizeof (winCEfile));
343 CloseHandle(fileHandle);
344 BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
347 retval->readonly = rdonly;
348 retval->handle = fileHandle;
353 void *__PHYSFS_platformOpenRead(const char *filename)
355 return(doOpen(filename, GENERIC_READ, OPEN_EXISTING, 1));
356 } /* __PHYSFS_platformOpenRead */
359 void *__PHYSFS_platformOpenWrite(const char *filename)
361 return(doOpen(filename, GENERIC_WRITE, CREATE_ALWAYS, 0));
362 } /* __PHYSFS_platformOpenWrite */
365 void *__PHYSFS_platformOpenAppend(const char *filename)
367 void *retval = doOpen(filename, GENERIC_WRITE, OPEN_ALWAYS, 0);
370 HANDLE h = ((winCEfile *) retval)->handle;
371 if (SetFilePointer(h, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER)
373 const char *err = win32strerror();
375 allocator.Free(retval);
376 BAIL_MACRO(err, NULL);
382 } /* __PHYSFS_platformOpenAppend */
385 PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer,
386 PHYSFS_uint32 size, PHYSFS_uint32 count)
388 HANDLE Handle = ((winCEfile *) opaque)->handle;
389 DWORD CountOfBytesRead;
390 PHYSFS_sint64 retval;
392 /* Read data from the file */
393 /*!!! - uint32 might be a greater # than DWORD */
394 if (!ReadFile(Handle, buffer, count * size, &CountOfBytesRead, NULL))
400 /* Return the number of "objects" read. */
401 /* !!! - What if not the right amount of bytes was read to make an object? */
402 retval = CountOfBytesRead / size;
407 } /* __PHYSFS_platformRead */
410 PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
411 PHYSFS_uint32 size, PHYSFS_uint32 count)
413 HANDLE Handle = ((winCEfile *) opaque)->handle;
414 DWORD CountOfBytesWritten;
415 PHYSFS_sint64 retval;
417 /* Read data from the file */
418 /*!!! - uint32 might be a greater # than DWORD */
419 if (!WriteFile(Handle, buffer, count * size, &CountOfBytesWritten, NULL))
425 /* Return the number of "objects" read. */
426 /*!!! - What if not the right number of bytes was written? */
427 retval = CountOfBytesWritten / size;
432 } /* __PHYSFS_platformWrite */
435 int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos)
437 HANDLE Handle = ((winCEfile *) opaque)->handle;
441 /* Get the high order 32-bits of the position */
442 //HighOrderPos = HIGHORDER_UINT64(pos);
443 HighOrderPos = (unsigned long)(pos>>32);
445 /*!!! SetFilePointer needs a signed 64-bit value. */
446 /* Move pointer "pos" count from start of file */
447 rc = SetFilePointer(Handle, (unsigned long)(pos&0x00000000ffffffff),
448 &HighOrderPos, FILE_BEGIN);
450 if ((rc == INVALID_SET_FILE_POINTER) && (GetLastError() != NO_ERROR))
452 BAIL_MACRO(win32strerror(), 0);
455 return(1); /* No error occured */
456 } /* __PHYSFS_platformSeek */
459 PHYSFS_sint64 __PHYSFS_platformTell(void *opaque)
461 HANDLE Handle = ((winCEfile *) opaque)->handle;
464 PHYSFS_sint64 retval;
466 /* Get current position */
467 LowPos = SetFilePointer(Handle, 0, &HighPos, FILE_CURRENT);
468 if ((LowPos == INVALID_SET_FILE_POINTER) && (GetLastError() != NO_ERROR))
470 BAIL_MACRO(win32strerror(), 0);
474 /* Combine the high/low order to create the 64-bit position value */
475 retval = (((PHYSFS_uint64) HighPos) << 32) | LowPos;
476 //assert(retval >= 0);
480 } /* __PHYSFS_platformTell */
483 PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque)
485 HANDLE Handle = ((winCEfile *) opaque)->handle;
488 PHYSFS_sint64 retval;
490 SizeLow = GetFileSize(Handle, &SizeHigh);
491 if ((SizeLow == INVALID_SET_FILE_POINTER) && (GetLastError() != NO_ERROR))
493 BAIL_MACRO(win32strerror(), -1);
497 /* Combine the high/low order to create the 64-bit position value */
498 retval = (((PHYSFS_uint64) SizeHigh) << 32) | SizeLow;
499 //assert(retval >= 0);
503 } /* __PHYSFS_platformFileLength */
506 int __PHYSFS_platformEOF(void *opaque)
508 PHYSFS_sint64 FilePosition;
511 /* Get the current position in the file */
512 if ((FilePosition = __PHYSFS_platformTell(opaque)) != 0)
514 /* Non-zero if EOF is equal to the file length */
515 retval = FilePosition == __PHYSFS_platformFileLength(opaque);
519 } /* __PHYSFS_platformEOF */
522 int __PHYSFS_platformFlush(void *opaque)
524 winCEfile *fh = ((winCEfile *) opaque);
526 BAIL_IF_MACRO(!FlushFileBuffers(fh->handle), win32strerror(), 0);
529 } /* __PHYSFS_platformFlush */
532 int __PHYSFS_platformClose(void *opaque)
534 HANDLE Handle = ((winCEfile *) opaque)->handle;
535 BAIL_IF_MACRO(!CloseHandle(Handle), win32strerror(), 0);
536 allocator.Free(opaque);
538 } /* __PHYSFS_platformClose */
541 int __PHYSFS_platformDelete(const char *path)
543 wchar_t *w_path = NULL;
544 UTF8_TO_UNICODE_STACK_MACRO(w_path, path);
546 /* If filename is a folder */
547 if (GetFileAttributes(w_path) == FILE_ATTRIBUTE_DIRECTORY)
549 int retval = !RemoveDirectory(w_path);
550 __PHYSFS_smallFree(w_path);
551 BAIL_IF_MACRO(retval, win32strerror(), 0);
555 int retval = !DeleteFile(w_path);
556 __PHYSFS_smallFree(w_path);
557 BAIL_IF_MACRO(retval, win32strerror(), 0);
560 return(1); /* if you got here, it worked. */
561 } /* __PHYSFS_platformDelete */
565 * !!! FIXME: why aren't we using Critical Sections instead of Mutexes?
566 * !!! FIXME: mutexes on Windows are for cross-process sync. CritSects are
567 * !!! FIXME: mutexes for threads in a single process and are faster.
569 void *__PHYSFS_platformCreateMutex(void)
571 return((void *) CreateMutex(NULL, FALSE, NULL));
572 } /* __PHYSFS_platformCreateMutex */
575 void __PHYSFS_platformDestroyMutex(void *mutex)
577 CloseHandle((HANDLE) mutex);
578 } /* __PHYSFS_platformDestroyMutex */
581 int __PHYSFS_platformGrabMutex(void *mutex)
583 return(WaitForSingleObject((HANDLE) mutex, INFINITE) != WAIT_FAILED);
584 } /* __PHYSFS_platformGrabMutex */
587 void __PHYSFS_platformReleaseMutex(void *mutex)
589 ReleaseMutex((HANDLE) mutex);
590 } /* __PHYSFS_platformReleaseMutex */
593 PHYSFS_sint64 __PHYSFS_platformGetLastModTime(const char *fname)
595 BAIL_MACRO(ERR_NOT_IMPLEMENTED, -1);
596 } /* __PHYSFS_platformGetLastModTime */
599 /* !!! FIXME: Don't use C runtime for allocators? */
600 int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
602 return(0); /* just use malloc() and friends. */
603 } /* __PHYSFS_platformSetDefaultAllocator */
605 #endif /* PHYSFS_PLATFORM_POCKETPC */
607 /* end of pocketpc.c ... */