src/file/SDL_rwops.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 28 May 2006 13:04:16 +0000
branchSDL-1.3
changeset 1662 782fd950bd46
parent 1659 14717b52abc0
child 1668 4da1ee79c9af
permissions -rw-r--r--
Revamp of the video system in progress - adding support for multiple displays, multiple windows, and a full video mode selection API.

WARNING: None of the video drivers have been updated for the new API yet! The API is still under design and very fluid.

The code is now run through a consistent indent format:
indent -i4 -nut -nsc -br -ce

The headers are being converted to automatically generate doxygen documentation.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 /* This file provides a general interface for SDL to read and write
    25    data sources.  It can easily be extended to files, memory, etc.
    26 */
    27 
    28 #include "SDL_endian.h"
    29 #include "SDL_rwops.h"
    30 
    31 
    32 #if defined(__WIN32__)
    33 
    34 /* Functions to read/write Win32 API file pointers */
    35 /* Will not use it on WinCE because stdio is buffered, it means
    36    faster, and all stdio functions anyway are embedded in coredll.dll - 
    37    the main wince dll*/
    38 
    39 #define WINDOWS_LEAN_AND_MEAN
    40 #include <windows.h>
    41 
    42 #ifndef INVALID_SET_FILE_POINTER
    43 #define INVALID_SET_FILE_POINTER 0xFFFFFFFF
    44 #endif
    45 
    46 static int SDLCALL
    47 win32_file_open (SDL_RWops * context, const char *filename, const char *mode)
    48 {
    49 #ifndef _WIN32_WCE
    50     UINT old_error_mode;
    51 #endif
    52     HANDLE h;
    53     DWORD r_right, w_right;
    54     DWORD must_exist, truncate;
    55     int a_mode;
    56 
    57     if (!context)
    58         return -1;
    59 
    60     context->hidden.win32io.h = INVALID_HANDLE_VALUE;   /* mark this as unusable */
    61 
    62     /* "r" = reading, file must exist */
    63     /* "w" = writing, truncate existing, file may not exist */
    64     /* "r+"= reading or writing, file must exist            */
    65     /* "a" = writing, append file may not exist             */
    66     /* "a+"= append + read, file may not exist              */
    67     /* "w+" = read, write, truncate. file may not exist    */
    68 
    69     must_exist = (SDL_strchr (mode, 'r') != NULL) ? OPEN_EXISTING : 0;
    70     truncate = (SDL_strchr (mode, 'w') != NULL) ? CREATE_ALWAYS : 0;
    71     r_right = (SDL_strchr (mode, '+') != NULL
    72                || must_exist) ? GENERIC_READ : 0;
    73     a_mode = (SDL_strchr (mode, 'a') != NULL) ? OPEN_ALWAYS : 0;
    74     w_right = (a_mode || SDL_strchr (mode, '+')
    75                || truncate) ? GENERIC_WRITE : 0;
    76 
    77     if (!r_right && !w_right)   /* inconsistent mode */
    78         return -1;              /* failed (invalid call) */
    79 
    80 #ifdef _WIN32_WCE
    81     {
    82         size_t size = SDL_strlen (filename) + 1;
    83         wchar_t *filenameW = SDL_stack_alloc (wchar_t, size);
    84 
    85         if (MultiByteToWideChar (CP_UTF8, 0, filename, -1, filenameW, size) ==
    86             0) {
    87             SDL_SetError ("Unable to convert filename to Unicode");
    88             SDL_stack_free (filenameW);
    89             return -1;
    90         }
    91         h = CreateFile (filenameW, (w_right | r_right),
    92                         (w_right) ? 0 : FILE_SHARE_READ, NULL,
    93                         (must_exist | truncate | a_mode),
    94                         FILE_ATTRIBUTE_NORMAL, NULL);
    95         SDL_stack_free (filenameW);
    96     }
    97 #else
    98     /* Do not open a dialog box if failure */
    99     old_error_mode =
   100         SetErrorMode (SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
   101 
   102     h = CreateFile (filename, (w_right | r_right),
   103                     (w_right) ? 0 : FILE_SHARE_READ, NULL,
   104                     (must_exist | truncate | a_mode), FILE_ATTRIBUTE_NORMAL,
   105                     NULL);
   106 
   107     /* restore old behaviour */
   108     SetErrorMode (old_error_mode);
   109 #endif /* _WIN32_WCE */
   110 
   111     if (h == INVALID_HANDLE_VALUE) {
   112         SDL_SetError ("Couldn't open %s", filename);
   113         return -2;              /* failed (CreateFile) */
   114     }
   115     context->hidden.win32io.h = h;
   116     context->hidden.win32io.append = a_mode;
   117 
   118     return 0;                   /* ok */
   119 }
   120 static int SDLCALL
   121 win32_file_seek (SDL_RWops * context, int offset, int whence)
   122 {
   123     DWORD win32whence;
   124     int file_pos;
   125 
   126     if (!context || context->hidden.win32io.h == INVALID_HANDLE_VALUE) {
   127         SDL_SetError ("win32_file_seek: invalid context/file not opened");
   128         return -1;
   129     }
   130 
   131     switch (whence) {
   132     case RW_SEEK_SET:
   133         win32whence = FILE_BEGIN;
   134         break;
   135     case RW_SEEK_CUR:
   136         win32whence = FILE_CURRENT;
   137         break;
   138     case RW_SEEK_END:
   139         win32whence = FILE_END;
   140         break;
   141     default:
   142         SDL_SetError ("win32_file_seek: Unknown value for 'whence'");
   143         return -1;
   144     }
   145 
   146     file_pos =
   147         SetFilePointer (context->hidden.win32io.h, offset, NULL, win32whence);
   148 
   149     if (file_pos != INVALID_SET_FILE_POINTER)
   150         return file_pos;        /* success */
   151 
   152     SDL_Error (SDL_EFSEEK);
   153     return -1;                  /* error */
   154 }
   155 static int SDLCALL
   156 win32_file_read (SDL_RWops * context, void *ptr, int size, int maxnum)
   157 {
   158 
   159     int total_bytes;
   160     DWORD byte_read, nread;
   161 
   162     total_bytes = size * maxnum;
   163 
   164     if (!context || context->hidden.win32io.h == INVALID_HANDLE_VALUE
   165         || total_bytes <= 0 || !size)
   166         return 0;
   167 
   168     if (!ReadFile
   169         (context->hidden.win32io.h, ptr, total_bytes, &byte_read, NULL)) {
   170         SDL_Error (SDL_EFREAD);
   171         return 0;
   172     }
   173     nread = byte_read / size;
   174     return nread;
   175 }
   176 static int SDLCALL
   177 win32_file_write (SDL_RWops * context, const void *ptr, int size, int num)
   178 {
   179 
   180     int total_bytes;
   181     DWORD byte_written, nwritten;
   182 
   183     total_bytes = size * num;
   184 
   185     if (!context || context->hidden.win32io.h == INVALID_HANDLE_VALUE
   186         || total_bytes <= 0 || !size)
   187         return 0;
   188 
   189     /* if in append mode, we must go to the EOF before write */
   190     if (context->hidden.win32io.append) {
   191         if (SetFilePointer (context->hidden.win32io.h, 0L, NULL, FILE_END)
   192             == INVALID_SET_FILE_POINTER) {
   193             SDL_Error (SDL_EFWRITE);
   194             return 0;
   195         }
   196     }
   197 
   198     if (!WriteFile
   199         (context->hidden.win32io.h, ptr, total_bytes, &byte_written, NULL)) {
   200         SDL_Error (SDL_EFWRITE);
   201         return 0;
   202     }
   203 
   204     nwritten = byte_written / size;
   205     return nwritten;
   206 }
   207 static int SDLCALL
   208 win32_file_close (SDL_RWops * context)
   209 {
   210 
   211     if (context) {
   212         if (context->hidden.win32io.h != INVALID_HANDLE_VALUE) {
   213             CloseHandle (context->hidden.win32io.h);
   214             context->hidden.win32io.h = INVALID_HANDLE_VALUE;   /* to be sure */
   215         }
   216         SDL_FreeRW (context);
   217     }
   218     return (0);
   219 }
   220 #endif /* __WIN32__ */
   221 
   222 #ifdef HAVE_STDIO_H
   223 
   224 /* Functions to read/write stdio file pointers */
   225 
   226 static int SDLCALL
   227 stdio_seek (SDL_RWops * context, int offset, int whence)
   228 {
   229     if (fseek (context->hidden.stdio.fp, offset, whence) == 0) {
   230         return (ftell (context->hidden.stdio.fp));
   231     } else {
   232         SDL_Error (SDL_EFSEEK);
   233         return (-1);
   234     }
   235 }
   236 static int SDLCALL
   237 stdio_read (SDL_RWops * context, void *ptr, int size, int maxnum)
   238 {
   239     size_t nread;
   240 
   241     nread = fread (ptr, size, maxnum, context->hidden.stdio.fp);
   242     if (nread == 0 && ferror (context->hidden.stdio.fp)) {
   243         SDL_Error (SDL_EFREAD);
   244     }
   245     return (nread);
   246 }
   247 static int SDLCALL
   248 stdio_write (SDL_RWops * context, const void *ptr, int size, int num)
   249 {
   250     size_t nwrote;
   251 
   252     nwrote = fwrite (ptr, size, num, context->hidden.stdio.fp);
   253     if (nwrote == 0 && ferror (context->hidden.stdio.fp)) {
   254         SDL_Error (SDL_EFWRITE);
   255     }
   256     return (nwrote);
   257 }
   258 static int SDLCALL
   259 stdio_close (SDL_RWops * context)
   260 {
   261     if (context) {
   262         if (context->hidden.stdio.autoclose) {
   263             /* WARNING:  Check the return value here! */
   264             fclose (context->hidden.stdio.fp);
   265         }
   266         SDL_FreeRW (context);
   267     }
   268     return (0);
   269 }
   270 #endif /* !HAVE_STDIO_H */
   271 
   272 /* Functions to read/write memory pointers */
   273 
   274 static int SDLCALL
   275 mem_seek (SDL_RWops * context, int offset, int whence)
   276 {
   277     Uint8 *newpos;
   278 
   279     switch (whence) {
   280     case RW_SEEK_SET:
   281         newpos = context->hidden.mem.base + offset;
   282         break;
   283     case RW_SEEK_CUR:
   284         newpos = context->hidden.mem.here + offset;
   285         break;
   286     case RW_SEEK_END:
   287         newpos = context->hidden.mem.stop + offset;
   288         break;
   289     default:
   290         SDL_SetError ("Unknown value for 'whence'");
   291         return (-1);
   292     }
   293     if (newpos < context->hidden.mem.base) {
   294         newpos = context->hidden.mem.base;
   295     }
   296     if (newpos > context->hidden.mem.stop) {
   297         newpos = context->hidden.mem.stop;
   298     }
   299     context->hidden.mem.here = newpos;
   300     return (context->hidden.mem.here - context->hidden.mem.base);
   301 }
   302 static int SDLCALL
   303 mem_read (SDL_RWops * context, void *ptr, int size, int maxnum)
   304 {
   305     size_t total_bytes;
   306     size_t mem_available;
   307 
   308     total_bytes = (maxnum * size);
   309     if ((maxnum <= 0) || (size <= 0)
   310         || ((total_bytes / maxnum) != (size_t) size)) {
   311         return 0;
   312     }
   313 
   314     mem_available = (context->hidden.mem.stop - context->hidden.mem.here);
   315     if (total_bytes > mem_available) {
   316         total_bytes = mem_available;
   317     }
   318 
   319     SDL_memcpy (ptr, context->hidden.mem.here, total_bytes);
   320     context->hidden.mem.here += total_bytes;
   321 
   322     return (total_bytes / size);
   323 }
   324 static int SDLCALL
   325 mem_write (SDL_RWops * context, const void *ptr, int size, int num)
   326 {
   327     if ((context->hidden.mem.here + (num * size)) > context->hidden.mem.stop) {
   328         num = (context->hidden.mem.stop - context->hidden.mem.here) / size;
   329     }
   330     SDL_memcpy (context->hidden.mem.here, ptr, num * size);
   331     context->hidden.mem.here += num * size;
   332     return (num);
   333 }
   334 static int SDLCALL
   335 mem_writeconst (SDL_RWops * context, const void *ptr, int size, int num)
   336 {
   337     SDL_SetError ("Can't write to read-only memory");
   338     return (-1);
   339 }
   340 static int SDLCALL
   341 mem_close (SDL_RWops * context)
   342 {
   343     if (context) {
   344         SDL_FreeRW (context);
   345     }
   346     return (0);
   347 }
   348 
   349 
   350 /* Functions to create SDL_RWops structures from various data sources */
   351 
   352 #ifdef __MACOS__
   353 /*
   354  * translate unix-style slash-separated filename to mac-style colon-separated
   355  * name; return malloced string
   356  */
   357 static char *
   358 unix_to_mac (const char *file)
   359 {
   360     int flen = SDL_strlen (file);
   361     char *path = SDL_malloc (flen + 2);
   362     const char *src = file;
   363     char *dst = path;
   364     if (*src == '/') {
   365         /* really depends on filesystem layout, hope for the best */
   366         src++;
   367     } else {
   368         /* Check if this is a MacOS path to begin with */
   369         if (*src != ':')
   370             *dst++ = ':';       /* relative paths begin with ':' */
   371     }
   372     while (src < file + flen) {
   373         const char *end = SDL_strchr (src, '/');
   374         int len;
   375         if (!end)
   376             end = file + flen;  /* last component */
   377         len = end - src;
   378         if (len == 0 || (len == 1 && src[0] == '.')) {
   379             /* remove repeated slashes and . */
   380         } else {
   381             if (len == 2 && src[0] == '.' && src[1] == '.') {
   382                 /* replace .. with the empty string */
   383             } else {
   384                 SDL_memcpy (dst, src, len);
   385                 dst += len;
   386             }
   387             if (end < file + flen)
   388                 *dst++ = ':';
   389         }
   390         src = end + 1;
   391     }
   392     *dst++ = '\0';
   393     return path;
   394 }
   395 #endif /* __MACOS__ */
   396 
   397 SDL_RWops *
   398 SDL_RWFromFile (const char *file, const char *mode)
   399 {
   400     SDL_RWops *rwops = NULL;
   401 #ifdef HAVE_STDIO_H
   402     FILE *fp = NULL;
   403 #endif
   404     if (!file || !*file || !mode || !*mode) {
   405         SDL_SetError ("SDL_RWFromFile(): No file or no mode specified");
   406         return NULL;
   407     }
   408 #if defined(__WIN32__)
   409     rwops = SDL_AllocRW ();
   410     if (!rwops)
   411         return NULL;            /* SDL_SetError already setup by SDL_AllocRW() */
   412     rwops->hidden.win32io.h = INVALID_HANDLE_VALUE;
   413     if (win32_file_open (rwops, file, mode)) {
   414         SDL_FreeRW (rwops);
   415         return NULL;
   416     }
   417     rwops->seek = win32_file_seek;
   418     rwops->read = win32_file_read;
   419     rwops->write = win32_file_write;
   420     rwops->close = win32_file_close;
   421 
   422 #elif HAVE_STDIO_H
   423 
   424 #ifdef __MACOS__
   425     {
   426         char *mpath = unix_to_mac (file);
   427         fp = fopen (mpath, mode);
   428         SDL_free (mpath);
   429     }
   430 #else
   431     fp = fopen (file, mode);
   432 #endif
   433     if (fp == NULL) {
   434         SDL_SetError ("Couldn't open %s", file);
   435     } else {
   436         rwops = SDL_RWFromFP (fp, 1);
   437     }
   438 #else
   439     SDL_SetError ("SDL not compiled with stdio support");
   440 #endif /* !HAVE_STDIO_H */
   441 
   442     return (rwops);
   443 }
   444 
   445 #ifdef HAVE_STDIO_H
   446 SDL_RWops *
   447 SDL_RWFromFP (FILE * fp, int autoclose)
   448 {
   449     SDL_RWops *rwops = NULL;
   450 
   451     rwops = SDL_AllocRW ();
   452     if (rwops != NULL) {
   453         rwops->seek = stdio_seek;
   454         rwops->read = stdio_read;
   455         rwops->write = stdio_write;
   456         rwops->close = stdio_close;
   457         rwops->hidden.stdio.fp = fp;
   458         rwops->hidden.stdio.autoclose = autoclose;
   459     }
   460     return (rwops);
   461 }
   462 #endif /* HAVE_STDIO_H */
   463 
   464 SDL_RWops *
   465 SDL_RWFromMem (void *mem, int size)
   466 {
   467     SDL_RWops *rwops;
   468 
   469     rwops = SDL_AllocRW ();
   470     if (rwops != NULL) {
   471         rwops->seek = mem_seek;
   472         rwops->read = mem_read;
   473         rwops->write = mem_write;
   474         rwops->close = mem_close;
   475         rwops->hidden.mem.base = (Uint8 *) mem;
   476         rwops->hidden.mem.here = rwops->hidden.mem.base;
   477         rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
   478     }
   479     return (rwops);
   480 }
   481 
   482 SDL_RWops *
   483 SDL_RWFromConstMem (const void *mem, int size)
   484 {
   485     SDL_RWops *rwops;
   486 
   487     rwops = SDL_AllocRW ();
   488     if (rwops != NULL) {
   489         rwops->seek = mem_seek;
   490         rwops->read = mem_read;
   491         rwops->write = mem_writeconst;
   492         rwops->close = mem_close;
   493         rwops->hidden.mem.base = (Uint8 *) mem;
   494         rwops->hidden.mem.here = rwops->hidden.mem.base;
   495         rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
   496     }
   497     return (rwops);
   498 }
   499 
   500 SDL_RWops *
   501 SDL_AllocRW (void)
   502 {
   503     SDL_RWops *area;
   504 
   505     area = (SDL_RWops *) SDL_malloc (sizeof *area);
   506     if (area == NULL) {
   507         SDL_OutOfMemory ();
   508     }
   509     return (area);
   510 }
   511 
   512 void
   513 SDL_FreeRW (SDL_RWops * area)
   514 {
   515     SDL_free (area);
   516 }
   517 
   518 /* Functions for dynamically reading and writing endian-specific values */
   519 
   520 Uint16
   521 SDL_ReadLE16 (SDL_RWops * src)
   522 {
   523     Uint16 value;
   524 
   525     SDL_RWread (src, &value, (sizeof value), 1);
   526     return (SDL_SwapLE16 (value));
   527 }
   528 
   529 Uint16
   530 SDL_ReadBE16 (SDL_RWops * src)
   531 {
   532     Uint16 value;
   533 
   534     SDL_RWread (src, &value, (sizeof value), 1);
   535     return (SDL_SwapBE16 (value));
   536 }
   537 
   538 Uint32
   539 SDL_ReadLE32 (SDL_RWops * src)
   540 {
   541     Uint32 value;
   542 
   543     SDL_RWread (src, &value, (sizeof value), 1);
   544     return (SDL_SwapLE32 (value));
   545 }
   546 
   547 Uint32
   548 SDL_ReadBE32 (SDL_RWops * src)
   549 {
   550     Uint32 value;
   551 
   552     SDL_RWread (src, &value, (sizeof value), 1);
   553     return (SDL_SwapBE32 (value));
   554 }
   555 
   556 Uint64
   557 SDL_ReadLE64 (SDL_RWops * src)
   558 {
   559     Uint64 value;
   560 
   561     SDL_RWread (src, &value, (sizeof value), 1);
   562     return (SDL_SwapLE64 (value));
   563 }
   564 
   565 Uint64
   566 SDL_ReadBE64 (SDL_RWops * src)
   567 {
   568     Uint64 value;
   569 
   570     SDL_RWread (src, &value, (sizeof value), 1);
   571     return (SDL_SwapBE64 (value));
   572 }
   573 
   574 int
   575 SDL_WriteLE16 (SDL_RWops * dst, Uint16 value)
   576 {
   577     value = SDL_SwapLE16 (value);
   578     return (SDL_RWwrite (dst, &value, (sizeof value), 1));
   579 }
   580 
   581 int
   582 SDL_WriteBE16 (SDL_RWops * dst, Uint16 value)
   583 {
   584     value = SDL_SwapBE16 (value);
   585     return (SDL_RWwrite (dst, &value, (sizeof value), 1));
   586 }
   587 
   588 int
   589 SDL_WriteLE32 (SDL_RWops * dst, Uint32 value)
   590 {
   591     value = SDL_SwapLE32 (value);
   592     return (SDL_RWwrite (dst, &value, (sizeof value), 1));
   593 }
   594 
   595 int
   596 SDL_WriteBE32 (SDL_RWops * dst, Uint32 value)
   597 {
   598     value = SDL_SwapBE32 (value);
   599     return (SDL_RWwrite (dst, &value, (sizeof value), 1));
   600 }
   601 
   602 int
   603 SDL_WriteLE64 (SDL_RWops * dst, Uint64 value)
   604 {
   605     value = SDL_SwapLE64 (value);
   606     return (SDL_RWwrite (dst, &value, (sizeof value), 1));
   607 }
   608 
   609 int
   610 SDL_WriteBE64 (SDL_RWops * dst, Uint64 value)
   611 {
   612     value = SDL_SwapBE64 (value);
   613     return (SDL_RWwrite (dst, &value, (sizeof value), 1));
   614 }
   615 
   616 /* vi: set ts=4 sw=4 expandtab: */