physfs.c
changeset 5 055ddaaabf85
child 7 07d5e6e8259d
equal deleted inserted replaced
4:b8107374195a 5:055ddaaabf85
       
     1 /**
       
     2  * PhysicsFS; a portable, flexible file i/o abstraction.
       
     3  *
       
     4  * Documentation is in physfs.h. It's verbose, honest.  :)
       
     5  *
       
     6  * Please see the file LICENSE in the source's root directory.
       
     7  *
       
     8  *  This file written by Ryan C. Gordon.
       
     9  */
       
    10 
       
    11 #include <stdio.h>
       
    12 #include <stdlib.h>
       
    13 #include <string.h>
       
    14 #include <assert.h>
       
    15 #include "physfs.h"
       
    16 
       
    17 typedef struct __PHYSFS_ERRMSGTYPE__
       
    18 {
       
    19     int tid;
       
    20     int errorAvailable;
       
    21     char errorString[80];
       
    22     struct __PHYSFS_ERRMSGTYPE__ *next;
       
    23 } ErrMsg;
       
    24 
       
    25 /* !!!
       
    26 typedef struct __PHYSFS_READER__
       
    27 {
       
    28     
       
    29 } Reader;
       
    30 */
       
    31 
       
    32 typedef struct __PHYSFS_SEARCHDIRINFO__
       
    33 {
       
    34     char *dirName;
       
    35     Reader *reader;
       
    36     struct __PHYSFS_SEARCHDIRINFO__ *next;
       
    37 } SearchDirInfo;
       
    38 
       
    39 
       
    40 static int initialized = 0;
       
    41 static ErrMsg **errorMessages = NULL;  /* uses list functions. */
       
    42 static char **searchPath = NULL;  /* uses list functions. */
       
    43 static char *baseDir = NULL;
       
    44 static char *writeDir = NULL;
       
    45 
       
    46 static const PHYSFS_ArchiveInfo *supported_types[] =
       
    47 {
       
    48 #if (defined PHYSFS_SUPPORTS_ZIP)
       
    49     { "ZIP", "PkZip/WinZip/Info-Zip compatible" },
       
    50 #endif
       
    51 
       
    52     NULL
       
    53 };
       
    54 
       
    55 
       
    56 /* error messages... */
       
    57 #define ERR_IS_INITIALIZED       "Already initialized"
       
    58 #define ERR_NOT_INITIALIZED      "Not initialized"
       
    59 #define ERR_INVALID_ARGUMENT     "Invalid argument"
       
    60 #define ERR_FILES_OPEN_WRITE     "Files still open for writing"
       
    61 #define ERR_NO_DIR_CREATE        "Failed to create directories"
       
    62 #define ERR_OUT_OF_MEMORY        "Out of memory"
       
    63 #define ERR_NOT_IN_SEARCH_PATH   "No such entry in search path"
       
    64 
       
    65 
       
    66 /* This gets used all over for lessening code clutter. */
       
    67 #define BAIL_IF_MACRO(cond, err, rc) if (cond) { setError(err); return(rc); }
       
    68 
       
    69 
       
    70 static ErrMsg *findErrorForCurrentThread(void)
       
    71 {
       
    72     ErrMsg *i;
       
    73     int tid;
       
    74 
       
    75     if (errorMessages != NULL)
       
    76     {
       
    77         tid = __PHYSFS_platformGetThreadID();
       
    78 
       
    79         for (i = errorMessages; i != NULL; i = i->next)
       
    80         {
       
    81             if (i->tid == tid)
       
    82                 return(i);
       
    83         } /* for */
       
    84     } /* if */
       
    85 
       
    86     return(NULL);   /* no error available. */
       
    87 } /* findErrorForCurrentThread */
       
    88 
       
    89 
       
    90 static void setError(char *str)
       
    91 {
       
    92     ErrMsg *err = findErrorForCurrentThread();
       
    93 
       
    94     if (err == NULL)
       
    95     {
       
    96         err = (ErrMsg *) malloc(sizeof (ErrMsg));
       
    97         if (err == NULL)
       
    98             return;   /* uhh...? */
       
    99 
       
   100         err->next = errorMessages;
       
   101         if (errorMessages == NULL)
       
   102             errorMessages = err;
       
   103 
       
   104         err->tid = __PHYSFS_platformGetThreadID();
       
   105     } /* if */
       
   106 
       
   107     err->errorAvailable = 1;
       
   108     strncpy(err->errorString, str, sizeof (err->errorString));
       
   109     err->errorString[sizeof (err->errorString) - 1] = '\0';
       
   110 } /* setError */
       
   111 
       
   112 
       
   113 const char *PHYSFS_getLastError(void)
       
   114 {
       
   115     ErrMsg *err = findErrorForCurrentThread();
       
   116 
       
   117     if ((err == NULL) || (!err->errorAvailable))
       
   118         return(NULL);
       
   119 
       
   120     err->errorAvailable = 0;
       
   121     return(err->errorString);
       
   122 } /* PHYSFS_getLastError */
       
   123 
       
   124 
       
   125 void PHYSFS_getLinkedVersion(PHYSFS_Version *ver)
       
   126 {
       
   127     if (ver != NULL)
       
   128     {
       
   129         ver->major = PHYSFS_VER_MAJOR;
       
   130         ver->minor = PHYSFS_VER_MINOR;
       
   131         ver->patch = PHYSFS_VER_PATCH;
       
   132     } /* if */
       
   133 } /* PHYSFS_getLinkedVersion */
       
   134 
       
   135 
       
   136 int PHYSFS_init(const char *argv0)
       
   137 {
       
   138     BAIL_IF_MACRO(initialized, ERR_IS_INITIALIZED, 0);
       
   139     BAIL_IF_MACRO(argv0 == NULL, ERR_INVALID_ARGUMENT, 0);
       
   140 
       
   141     baseDir = calculateBaseDir();
       
   142     initialized = 1;
       
   143     return(1);
       
   144 } /* PHYSFS_init */
       
   145 
       
   146 
       
   147 static void freeSearchDir(SearchDirInfo *sdi)
       
   148 {
       
   149     assert(sdi != NULL);
       
   150     freeReader(sdi->reader);
       
   151     free(sdi->dirName);
       
   152     free(sdi);
       
   153 } /* freeSearchDir */
       
   154 
       
   155 
       
   156 static void freeSearchPath(void)
       
   157 {
       
   158     SearchDirInfo *i;
       
   159     SearchDirInfo *next = NULL;
       
   160 
       
   161     if (searchPath != NULL)
       
   162     {
       
   163         for (i = searchPath; i != NULL; i = next)
       
   164         {
       
   165             next = i;
       
   166             freeSearchDir(i);
       
   167         } /* for */
       
   168         searchPath = NULL;
       
   169     } /* if */
       
   170 } /* freeSearchPath */
       
   171 
       
   172 
       
   173 void PHYSFS_deinit(void)
       
   174 {
       
   175     BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0);
       
   176 
       
   177     /* close/cleanup open handles. */
       
   178 
       
   179     if (baseDir != NULL)
       
   180         free(baseDir);
       
   181 
       
   182     PHYSFS_setWriteDir(NULL);
       
   183     freeSearchPath();
       
   184     freeErrorMessages();
       
   185 
       
   186     initialized = 0;
       
   187     return(1);
       
   188 } /* PHYSFS_deinit */
       
   189 
       
   190 
       
   191 const PHYSFS_ArchiveInfo **PHYSFS_supportedArchiveTypes(void)
       
   192 {
       
   193     return(supported_types);
       
   194 } /* PHYSFS_supportedArchiveTypes */
       
   195 
       
   196 
       
   197 void PHYSFS_freeList(void *list)
       
   198 {
       
   199     void **i;
       
   200 
       
   201     for (i = (void **) list; *i != NULL; i++)
       
   202         free(*i);
       
   203 
       
   204     free(list);
       
   205 } /* PHYSFS_freeList */
       
   206 
       
   207 
       
   208 const char *PHYSFS_getDirSeparator(void)
       
   209 {
       
   210     return(__PHYSFS_pathSeparator);
       
   211 } /* PHYSFS_getDirSeparator */
       
   212 
       
   213 
       
   214 char **PHYSFS_getCdRomDirs(void)
       
   215 {
       
   216     return(__PHYSFS_platformDetectAvailableCDs());
       
   217 } /* PHYSFS_getCdRomDirs */
       
   218 
       
   219 
       
   220 const char *PHYSFS_getBaseDir(void)
       
   221 {
       
   222     return(baseDir);   /* this is calculated in PHYSFS_init()... */
       
   223 } /* PHYSFS_getBaseDir */
       
   224 
       
   225 
       
   226 const char *PHYSFS_getUserDir(void)
       
   227 {
       
   228     return(__PHYSFS_platformGetUserDir());
       
   229 } /* PHYSFS_getUserDir */
       
   230 
       
   231 
       
   232 const char *PHYSFS_getWriteDir(void)
       
   233 {
       
   234     return(writeDir);
       
   235 } /* PHYSFS_getWriteDir */
       
   236 
       
   237 
       
   238 int PHYSFS_setWriteDir(const char *newDir)
       
   239 {
       
   240     BAIL_IF_MACRO(openWriteCount > 0, ERR_FILES_OPEN_WRITE, 0);
       
   241 
       
   242     if (writeDir != NULL)
       
   243     {
       
   244         free(writeDir);
       
   245         writeDir = NULL;
       
   246     } /* if */
       
   247 
       
   248     if (newDir == NULL)   /* we're done already! */
       
   249         return(1);
       
   250 
       
   251     BAIL_IF_MACRO(!createDirs_dependent(newDir), ERR_NO_DIR_CREATE, 0);
       
   252 
       
   253     writeDir = malloc(strlen(newDir) + 1);
       
   254     BAIL_IF_MACRO(writeDir == NULL, ERR_OUT_OF_MEMORY, 0);
       
   255 
       
   256     strcpy(writeDir, newDir);
       
   257     return(1);
       
   258 } /* PHYSFS_setWriteDir */
       
   259 
       
   260 
       
   261 int PHYSFS_addToSearchPath(const char *newDir, int appendToPath)
       
   262 {
       
   263     char *str = NULL;
       
   264     SearchDirInfo *sdi = NULL;
       
   265     __PHYSFS_Reader *reader = NULL;
       
   266 
       
   267     BAIL_IF_MACRO(newDir == NULL, ERR_INVALID_ARGUMENT, 0);
       
   268 
       
   269     reader = getReader(newDir); /* This sets the error message. */
       
   270     if (reader == NULL)
       
   271         return(0);
       
   272 
       
   273     sdi = (SearchDirInfo *) malloc(sizeof (SearchDirInfo));
       
   274     BAIL_IF_MACRO(sdi == NULL, ERR_OUT_OF_MEMORY, 0);
       
   275 
       
   276     sdi->dirName = (char *) malloc(strlen(newDir) + 1);
       
   277     if (sdi->dirName == NULL)
       
   278     {
       
   279         free(sdi);
       
   280         freeReader(reader);
       
   281         setError(ERR_OUT_OF_MEMORY);
       
   282         return(0);
       
   283     } /* if */
       
   284 
       
   285     sdi->reader = reader;
       
   286     strcpy(sdi->dirName, newDir);
       
   287 
       
   288     if (appendToPath)
       
   289     {
       
   290         sdi->next = searchPath;
       
   291         searchPath = sdi;
       
   292     } /* if */
       
   293     else
       
   294     {
       
   295         SearchDirInfo *i = searchPath;
       
   296         SearchDirInfo *prev = NULL;
       
   297 
       
   298         sdi->next = NULL;
       
   299         while (i != NULL)
       
   300             prev = i;
       
   301 
       
   302         if (prev == NULL)
       
   303             searchPath = sdi;
       
   304         else
       
   305             prev->next = sdi;
       
   306     } /* else */
       
   307 
       
   308     return(1);
       
   309 } /* PHYSFS_addToSearchPath */
       
   310 
       
   311 
       
   312 int PHYSFS_removeFromSearchPath(const char *oldDir)
       
   313 {
       
   314     SearchDirInfo *i;
       
   315     SearchDirInfo *prev = NULL;
       
   316 
       
   317     BAIL_IF_MACRO(oldDir == NULL, ERR_INVALID_ARGUMENT, 0);
       
   318 
       
   319     for (i = searchPath; i != NULL; i = i->next)
       
   320     {
       
   321         if (strcmp(i->dirName, oldDir) == 0)
       
   322         {
       
   323             if (prev == NULL)
       
   324                 searchPath = i->next;
       
   325             else
       
   326                 prev->next = i->next;
       
   327             freeSearchDir(i);
       
   328             return(1);
       
   329         } /* if */
       
   330         prev = i;
       
   331     } /* for */
       
   332 
       
   333     setError(ERR_NOT_IN_SEARCH_PATH);
       
   334     return(0);
       
   335 } /* PHYSFS_removeFromSearchPath */
       
   336 
       
   337 
       
   338 char **PHYSFS_getSearchPath(void)
       
   339 {
       
   340     int count = 1;
       
   341     int x;
       
   342     SearchDirInfo *i;
       
   343     char **retval;
       
   344 
       
   345     for (i = searchPath; i != NULL; i = i->next)
       
   346         count++;
       
   347 
       
   348     retval = (char **) malloc(sizeof (char *) * count);
       
   349     BAIL_IF_MACRO(!retval, ERR_OUT_OF_MEMORY, NULL);
       
   350     count--;
       
   351     retval[count] = NULL;
       
   352 
       
   353     for (i = searchPath, x = 0; x < count; i = i->next, x++)
       
   354     {
       
   355         retval[x] = (char *) malloc(strlen(i->dirName) + 1);
       
   356         if (retval[x] == NULL)  /* this is friggin' ugly. */
       
   357         {
       
   358             while (x > 0)
       
   359             {
       
   360                 x--;
       
   361                 free(retval[x]);
       
   362             } /* while */
       
   363 
       
   364             free(retval);
       
   365             setError(ERR_OUT_OF_MEMORY);
       
   366             return(NULL);
       
   367         } /* if */
       
   368 
       
   369         strcpy(retval[x], i->dirName);
       
   370     } /* for */
       
   371 
       
   372     return(retval);
       
   373 } /* PHYSFS_getSearchPath */
       
   374 
       
   375 
       
   376 /**
       
   377  * Helper function.
       
   378  *
       
   379  * Set up sane, default paths. The write path will be set to
       
   380  *  "userpath/.appName", which is created if it doesn't exist.
       
   381  *
       
   382  * The above is sufficient to make sure your program's configuration directory
       
   383  *  is separated from other clutter, and platform-independent. The period
       
   384  *  before "mygame" even hides the directory on Unix systems.
       
   385  *
       
   386  *  The search path will be:
       
   387  *
       
   388  *    - The Write Dir (created if it doesn't exist)
       
   389  *    - The Write Dir/appName (created if it doesn't exist)
       
   390  *    - The Base Dir (PHYSFS_getBaseDir())
       
   391  *    - The Base Dir/appName (if it exists)
       
   392  *    - All found CD-ROM paths (optionally)
       
   393  *    - All found CD-ROM paths/appName (optionally, and if they exist)
       
   394  *
       
   395  * These directories are then searched for files ending with the extension
       
   396  *  (archiveExt), which, if they are valid and supported archives, will also
       
   397  *  be added to the search path. If you specified "PKG" for (archiveExt), and
       
   398  *  there's a file named data.PKG in the base dir, it'll be checked. Archives
       
   399  *  can either be appended or prepended to the search path in alphabetical
       
   400  *  order, regardless of which directories they were found in.
       
   401  *
       
   402  * All of this can be accomplished from the application, but this just does it
       
   403  *  all for you. Feel free to add more to the search path manually, too.
       
   404  *
       
   405  *    @param appName Program-specific name of your program, to separate it
       
   406  *                   from other programs using PhysicsFS.
       
   407  *
       
   408  *    @param archiveExt File extention used by your program to specify an
       
   409  *                      archive. For example, Quake 3 uses "pk3", even though
       
   410  *                      they are just zipfiles. Specify NULL to not dig out
       
   411  *                      archives automatically.
       
   412  *
       
   413  *    @param includeCdRoms Non-zero to include CD-ROMs in the search path, and
       
   414  *                         (if (archiveExt) != NULL) search them for archives.
       
   415  *                         This may cause a significant amount of blocking
       
   416  *                         while discs are accessed, and if there are no discs
       
   417  *                         in the drive (or even not mounted on Unix systems),
       
   418  *                         then they may not be made available anyhow. You may
       
   419  *                         want to specify zero and handle the disc setup
       
   420  *                         yourself.
       
   421  *
       
   422  *    @param archivesFirst Non-zero to prepend the archives to the search path.
       
   423  *                          Zero to append them. Ignored if !(archiveExt).
       
   424  */
       
   425 void PHYSFS_setSaneConfig(const char *appName, const char *archiveExt,
       
   426                          int includeCdRoms, int archivesFirst)
       
   427 {
       
   428 } /* PHYSFS_setSaneConfig */
       
   429 
       
   430 
       
   431 /**
       
   432  * Create a directory. This is specified in platform-independent notation in
       
   433  *  relation to the write path. All missing parent directories are also
       
   434  *  created if they don't exist.
       
   435  *
       
   436  * So if you've got the write path set to "C:\mygame\writepath" and call
       
   437  *  PHYSFS_mkdir("downloads/maps") then the directories
       
   438  *  "C:\mygame\writepath\downloads" and "C:\mygame\writepath\downloads\maps"
       
   439  *  will be created if possible. If the creation of "maps" fails after we
       
   440  *  have successfully created "downloads", then the function leaves the
       
   441  *  created directory behind and reports failure.
       
   442  *
       
   443  *   @param dirName New path to create.
       
   444  *  @return nonzero on success, zero on error. Specifics of the error can be
       
   445  *          gleaned from PHYSFS_getLastError().
       
   446  */
       
   447 int PHYSFS_mkdir(const char *dirName)
       
   448 {
       
   449 } /* PHYSFS_mkdir */
       
   450 
       
   451 
       
   452 /**
       
   453  * Delete a file or directory. This is specified in platform-independent
       
   454  *  notation in relation to the write path.
       
   455  *
       
   456  * A directory must be empty before this call can delete it.
       
   457  *
       
   458  * So if you've got the write path set to "C:\mygame\writepath" and call
       
   459  *  PHYSFS_delete("downloads/maps/level1.map") then the file
       
   460  *  "C:\mygame\writepath\downloads\maps\level1.map" is removed from the
       
   461  *  physical filesystem, if it exists and the operating system permits the
       
   462  *  deletion.
       
   463  *
       
   464  * Note that on Unix systems, deleting a file may be successful, but the
       
   465  *  actual file won't be removed until all processes that have an open
       
   466  *  filehandle to it (including your program) close their handles.
       
   467  *
       
   468  *   @param filename Filename to delete.
       
   469  *  @return nonzero on success, zero on error. Specifics of the error can be
       
   470  *          gleaned from PHYSFS_getLastError().
       
   471  */
       
   472 int PHYSFS_delete(const char *filename)
       
   473 {
       
   474 } /* PHYSFS_delete */
       
   475 
       
   476 
       
   477 /**
       
   478  * Enable symbolic links. Some physical filesystems and archives contain
       
   479  *  files that are just pointers to other files. On the physical filesystem,
       
   480  *  opening such a link will (transparently) open the file that is pointed to.
       
   481  *
       
   482  * By default, PhysicsFS will check if a file is really a symlink during open
       
   483  *  calls and fail if it is. Otherwise, the link could take you outside the
       
   484  *  write and search paths, and compromise security.
       
   485  *
       
   486  * If you want to take that risk, call this function with a non-zero parameter.
       
   487  *  Note that this is more for sandboxing a program's scripting language, in
       
   488  *  case untrusted scripts try to compromise the system. Generally speaking,
       
   489  *  a user could very well have a legitimate reason to set up a symlink, so
       
   490  *  unless you feel there's a specific danger in allowing them, you should
       
   491  *  permit them.
       
   492  *
       
   493  * Symbolic link permission can be enabled or disabled at any time, and is
       
   494  *  disabled by default.
       
   495  *
       
   496  *   @param allow nonzero to permit symlinks, zero to deny linking.
       
   497  */
       
   498 void PHYSFS_permitSymbolicLinks(int allow)
       
   499 {
       
   500 } /* PHYSFS_permitSymbolicLinks */
       
   501 
       
   502 
       
   503 /**
       
   504  * Figure out where in the search path a file resides. The file is specified
       
   505  *  in platform-independent notation. The returned filename will be the
       
   506  *  element of the search path where the file was found, which may be a
       
   507  *  directory, or an archive. Even if there are multiple matches in different
       
   508  *  parts of the search path, only the first one found is used, just like
       
   509  *  when opening a file.
       
   510  *
       
   511  * So, if you look for "maps/level1.map", and C:\mygame is in your search
       
   512  *  path and C:\mygame\maps\level1.map exists, then "C:\mygame" is returned.
       
   513  *
       
   514  * If a match is a symbolic link, and you've not explicitly permitted symlinks,
       
   515  *  then it will be ignored, and the search for a match will continue.
       
   516  *
       
   517  *     @param filename file to look for.
       
   518  *    @return READ ONLY string of element of search path containing the
       
   519  *             the file in question. NULL if not found.
       
   520  */
       
   521 const char *PHYSFS_getRealDir(const char *filename)
       
   522 {
       
   523 } /* PHYSFS_getRealDir */
       
   524 
       
   525 
       
   526 
       
   527 /**
       
   528  * Get a file listing of a search path's directory. Matching directories are
       
   529  *  interpolated. That is, if "C:\mypath" is in the search path and contains a
       
   530  *  directory "savegames" that contains "x.sav", "y.sav", and "z.sav", and
       
   531  *  there is also a "C:\userpath" in the search path that has a "savegames"
       
   532  *  subdirectory with "w.sav", then the following code:
       
   533  *
       
   534  * ------------------------------------------------
       
   535  * char **rc = PHYSFS_enumerateFiles("savegames");
       
   536  * char **i;
       
   537  *
       
   538  * for (i = rc; *i != NULL; i++)
       
   539  *     printf("We've got [%s].\n", *i);
       
   540  *
       
   541  * PHYSFS_freeList(rc);
       
   542  * ------------------------------------------------
       
   543  *
       
   544  *  ...will print:
       
   545  *
       
   546  * ------------------------------------------------
       
   547  * We've got [x.sav].
       
   548  * We've got [y.sav].
       
   549  * We've got [z.sav].
       
   550  * We've got [w.sav].
       
   551  * ------------------------------------------------
       
   552  *
       
   553  * Don't forget to call PHYSFS_freeList() with the return value from this
       
   554  *  function when you are done with it.
       
   555  *
       
   556  *    @param path directory in platform-independent notation to enumerate.
       
   557  *   @return Null-terminated array of null-terminated strings.
       
   558  */
       
   559 char **PHYSFS_enumerateFiles(const char *path)
       
   560 {
       
   561 } /* PHYSFS_enumerateFiles */
       
   562 
       
   563 
       
   564 /**
       
   565  * Open a file for writing, in platform-independent notation and in relation
       
   566  *  to the write path as the root of the writable filesystem. The specified
       
   567  *  file is created if it doesn't exist. If it does exist, it is truncated to
       
   568  *  zero bytes, and the writing offset is set to the start.
       
   569  *
       
   570  *   @param filename File to open.
       
   571  *  @return A valid PhysicsFS filehandle on success, NULL on error. Specifics
       
   572  *           of the error can be gleaned from PHYSFS_getLastError().
       
   573  */
       
   574 PHYSFS_file *PHYSFS_openWrite(const char *filename)
       
   575 {
       
   576 } /* PHYSFS_openWrite */
       
   577 
       
   578 
       
   579 /**
       
   580  * Open a file for writing, in platform-independent notation and in relation
       
   581  *  to the write path as the root of the writable filesystem. The specified
       
   582  *  file is created if it doesn't exist. If it does exist, the writing offset
       
   583  *  is set to the end of the file, so the first write will be the byte after
       
   584  *  the end.
       
   585  *
       
   586  *   @param filename File to open.
       
   587  *  @return A valid PhysicsFS filehandle on success, NULL on error. Specifics
       
   588  *           of the error can be gleaned from PHYSFS_getLastError().
       
   589  */
       
   590 PHYSFS_file *PHYSFS_openAppend(const char *filename)
       
   591 {
       
   592 } /* PHYSFS_openAppend */
       
   593 
       
   594 
       
   595 /**
       
   596  * Open a file for reading, in platform-independent notation. The search path
       
   597  *  is checked one at a time until a matching file is found, in which case an
       
   598  *  abstract filehandle is associated with it, and reading may be done.
       
   599  *  The reading offset is set to the first byte of the file.
       
   600  *
       
   601  *   @param filename File to open.
       
   602  *  @return A valid PhysicsFS filehandle on success, NULL on error. Specifics
       
   603  *           of the error can be gleaned from PHYSFS_getLastError().
       
   604  */
       
   605 PHYSFS_file *PHYSFS_openRead(const char *filename)
       
   606 {
       
   607 } /* PHYSFS_openRead */
       
   608 
       
   609 
       
   610 /**
       
   611  * Close a PhysicsFS filehandle. This call is capable of failing if the
       
   612  *  operating system was buffering writes to this file, and (now forced to
       
   613  *  write those changes to physical media) can not store the data for any
       
   614  *  reason. In such a case, the filehandle stays open. A well-written program
       
   615  *  should ALWAYS check the return value from the close call in addition to
       
   616  *  every writing call!
       
   617  *
       
   618  *   @param handle handle returned from PHYSFS_open*().
       
   619  *  @return nonzero on success, zero on error. Specifics of the error can be
       
   620  *          gleaned from PHYSFS_getLastError().
       
   621  */
       
   622 int PHYSFS_close(PHYSFS_file *handle)
       
   623 {
       
   624 } /* PHYSFS_close */
       
   625 
       
   626 
       
   627 /**
       
   628  * Read data from a PhysicsFS filehandle. The file must be opened for reading.
       
   629  *
       
   630  *   @param handle handle returned from PHYSFS_openRead().
       
   631  *   @param buffer buffer to store read data into.
       
   632  *   @param objSize size in bytes of objects being read from (handle).
       
   633  *   @param objCount number of (objSize) objects to read from (handle).
       
   634  *  @return number of objects read. PHYSFS_getLastError() can shed light on
       
   635  *           the reason this might be < (objCount), as can PHYSFS_eof().
       
   636  */
       
   637 int PHYSFS_read(PHYSFS_file *handle, void *buffer,
       
   638                 unsigned int objSize, unsigned int objCount)
       
   639 {
       
   640 } /* PHYSFS_read */
       
   641 
       
   642 
       
   643 /**
       
   644  * Write data to a PhysicsFS filehandle. The file must be opened for writing.
       
   645  *
       
   646  *   @param handle retval from PHYSFS_openWrite() or PHYSFS_openAppend().
       
   647  *   @param buffer buffer to store read data into.
       
   648  *   @param objSize size in bytes of objects being read from (handle).
       
   649  *   @param objCount number of (objSize) objects to read from (handle).
       
   650  *  @return number of objects read. PHYSFS_getLastError() can shed light on
       
   651  *           the reason this might be < (objCount).
       
   652  */
       
   653 int PHYSFS_write(PHYSFS_file *handle, void *buffer,
       
   654                  unsigned int objSize, unsigned int objCount)
       
   655 {
       
   656 } /* PHYSFS_write */
       
   657 
       
   658 
       
   659 /**
       
   660  * Determine if the end of file has been reached in a PhysicsFS filehandle.
       
   661  *
       
   662  *   @param handle handle returned from PHYSFS_openRead().
       
   663  *  @return nonzero if EOF, zero if not.
       
   664  */
       
   665 int PHYSFS_eof(PHYSFS_file *handle)
       
   666 {
       
   667 } /* PHYSFS_eof */
       
   668 
       
   669 
       
   670 /**
       
   671  * Determine current position within a PhysicsFS filehandle.
       
   672  *
       
   673  *   @param handle handle returned from PHYSFS_open*().
       
   674  *  @return offset in bytes from start of file. -1 if error occurred.
       
   675  *           Specifics of the error can be gleaned from PHYSFS_getLastError().
       
   676  */
       
   677 int PHYSFS_tell(PHYSFS_file *handle)
       
   678 {
       
   679 } /* PHYSFS_tell */
       
   680 
       
   681 
       
   682 /**
       
   683  * Seek to a new position within a PhysicsFS filehandle. The next read or write
       
   684  *  will occur at that place. Seeking past the beginning or end of the file is
       
   685  *  not allowed.
       
   686  *
       
   687  *   @param handle handle returned from PHYSFS_open*().
       
   688  *   @param pos number of bytes from start of file to seek to.
       
   689  *  @return nonzero on success, zero on error. Specifics of the error can be
       
   690  *          gleaned from PHYSFS_getLastError().
       
   691  */
       
   692 int PHYSFS_seek(PHYSFS_file *handle, int pos)
       
   693 {
       
   694 } /* PHYSFS_seek */
       
   695 
       
   696 
       
   697 /* end of physfs.h ... */
       
   698