src/file/SDL_rwops.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 10 Aug 2006 14:54:23 +0000
changeset 1978 542c78b6fb12
parent 1895 c121d94672cb
child 2159 dd4753e47ed4
permissions -rw-r--r--
MacOS Classic is no longer supported.
     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 SDL_RWops *
   353 SDL_RWFromFile(const char *file, const char *mode)
   354 {
   355     SDL_RWops *rwops = NULL;
   356 #ifdef HAVE_STDIO_H
   357     FILE *fp = NULL;
   358 #endif
   359     if (!file || !*file || !mode || !*mode) {
   360         SDL_SetError("SDL_RWFromFile(): No file or no mode specified");
   361         return NULL;
   362     }
   363 #if defined(__WIN32__)
   364     rwops = SDL_AllocRW();
   365     if (!rwops)
   366         return NULL;            /* SDL_SetError already setup by SDL_AllocRW() */
   367     rwops->hidden.win32io.h = INVALID_HANDLE_VALUE;
   368     if (win32_file_open(rwops, file, mode)) {
   369         SDL_FreeRW(rwops);
   370         return NULL;
   371     }
   372     rwops->seek = win32_file_seek;
   373     rwops->read = win32_file_read;
   374     rwops->write = win32_file_write;
   375     rwops->close = win32_file_close;
   376 
   377 #elif HAVE_STDIO_H
   378 
   379     fp = fopen(file, mode);
   380     if (fp == NULL) {
   381         SDL_SetError("Couldn't open %s", file);
   382     } else {
   383         rwops = SDL_RWFromFP(fp, 1);
   384     }
   385 #else
   386     SDL_SetError("SDL not compiled with stdio support");
   387 #endif /* !HAVE_STDIO_H */
   388 
   389     return (rwops);
   390 }
   391 
   392 #ifdef HAVE_STDIO_H
   393 SDL_RWops *
   394 SDL_RWFromFP(FILE * fp, int autoclose)
   395 {
   396     SDL_RWops *rwops = NULL;
   397 
   398     rwops = SDL_AllocRW();
   399     if (rwops != NULL) {
   400         rwops->seek = stdio_seek;
   401         rwops->read = stdio_read;
   402         rwops->write = stdio_write;
   403         rwops->close = stdio_close;
   404         rwops->hidden.stdio.fp = fp;
   405         rwops->hidden.stdio.autoclose = autoclose;
   406     }
   407     return (rwops);
   408 }
   409 #endif /* HAVE_STDIO_H */
   410 
   411 SDL_RWops *
   412 SDL_RWFromMem(void *mem, int size)
   413 {
   414     SDL_RWops *rwops;
   415 
   416     rwops = SDL_AllocRW();
   417     if (rwops != NULL) {
   418         rwops->seek = mem_seek;
   419         rwops->read = mem_read;
   420         rwops->write = mem_write;
   421         rwops->close = mem_close;
   422         rwops->hidden.mem.base = (Uint8 *) mem;
   423         rwops->hidden.mem.here = rwops->hidden.mem.base;
   424         rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
   425     }
   426     return (rwops);
   427 }
   428 
   429 SDL_RWops *
   430 SDL_RWFromConstMem(const void *mem, int size)
   431 {
   432     SDL_RWops *rwops;
   433 
   434     rwops = SDL_AllocRW();
   435     if (rwops != NULL) {
   436         rwops->seek = mem_seek;
   437         rwops->read = mem_read;
   438         rwops->write = mem_writeconst;
   439         rwops->close = mem_close;
   440         rwops->hidden.mem.base = (Uint8 *) mem;
   441         rwops->hidden.mem.here = rwops->hidden.mem.base;
   442         rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
   443     }
   444     return (rwops);
   445 }
   446 
   447 SDL_RWops *
   448 SDL_AllocRW(void)
   449 {
   450     SDL_RWops *area;
   451 
   452     area = (SDL_RWops *) SDL_malloc(sizeof *area);
   453     if (area == NULL) {
   454         SDL_OutOfMemory();
   455     }
   456     return (area);
   457 }
   458 
   459 void
   460 SDL_FreeRW(SDL_RWops * area)
   461 {
   462     SDL_free(area);
   463 }
   464 
   465 /* Functions for dynamically reading and writing endian-specific values */
   466 
   467 Uint16
   468 SDL_ReadLE16(SDL_RWops * src)
   469 {
   470     Uint16 value;
   471 
   472     SDL_RWread(src, &value, (sizeof value), 1);
   473     return (SDL_SwapLE16(value));
   474 }
   475 
   476 Uint16
   477 SDL_ReadBE16(SDL_RWops * src)
   478 {
   479     Uint16 value;
   480 
   481     SDL_RWread(src, &value, (sizeof value), 1);
   482     return (SDL_SwapBE16(value));
   483 }
   484 
   485 Uint32
   486 SDL_ReadLE32(SDL_RWops * src)
   487 {
   488     Uint32 value;
   489 
   490     SDL_RWread(src, &value, (sizeof value), 1);
   491     return (SDL_SwapLE32(value));
   492 }
   493 
   494 Uint32
   495 SDL_ReadBE32(SDL_RWops * src)
   496 {
   497     Uint32 value;
   498 
   499     SDL_RWread(src, &value, (sizeof value), 1);
   500     return (SDL_SwapBE32(value));
   501 }
   502 
   503 Uint64
   504 SDL_ReadLE64(SDL_RWops * src)
   505 {
   506     Uint64 value;
   507 
   508     SDL_RWread(src, &value, (sizeof value), 1);
   509     return (SDL_SwapLE64(value));
   510 }
   511 
   512 Uint64
   513 SDL_ReadBE64(SDL_RWops * src)
   514 {
   515     Uint64 value;
   516 
   517     SDL_RWread(src, &value, (sizeof value), 1);
   518     return (SDL_SwapBE64(value));
   519 }
   520 
   521 int
   522 SDL_WriteLE16(SDL_RWops * dst, Uint16 value)
   523 {
   524     value = SDL_SwapLE16(value);
   525     return (SDL_RWwrite(dst, &value, (sizeof value), 1));
   526 }
   527 
   528 int
   529 SDL_WriteBE16(SDL_RWops * dst, Uint16 value)
   530 {
   531     value = SDL_SwapBE16(value);
   532     return (SDL_RWwrite(dst, &value, (sizeof value), 1));
   533 }
   534 
   535 int
   536 SDL_WriteLE32(SDL_RWops * dst, Uint32 value)
   537 {
   538     value = SDL_SwapLE32(value);
   539     return (SDL_RWwrite(dst, &value, (sizeof value), 1));
   540 }
   541 
   542 int
   543 SDL_WriteBE32(SDL_RWops * dst, Uint32 value)
   544 {
   545     value = SDL_SwapBE32(value);
   546     return (SDL_RWwrite(dst, &value, (sizeof value), 1));
   547 }
   548 
   549 int
   550 SDL_WriteLE64(SDL_RWops * dst, Uint64 value)
   551 {
   552     value = SDL_SwapLE64(value);
   553     return (SDL_RWwrite(dst, &value, (sizeof value), 1));
   554 }
   555 
   556 int
   557 SDL_WriteBE64(SDL_RWops * dst, Uint64 value)
   558 {
   559     value = SDL_SwapBE64(value);
   560     return (SDL_RWwrite(dst, &value, (sizeof value), 1));
   561 }
   562 
   563 /* vi: set ts=4 sw=4 expandtab: */