src/file/SDL_rwops.c
author Holmes Futrell <hfutrell@umail.ucsb.edu>
Mon, 18 Aug 2008 19:39:08 +0000
branchgsoc2008_iphone
changeset 2467 058e1f140ff3
parent 2185 2032348afed1
child 2674 f1d07ba2e275
child 2735 204be4fc2726
permissions -rw-r--r--
Fixed problem where creating the view passed NULL as the context for setting current context ... needed to actually pass the context.
     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 #ifdef __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 #define READAHEAD_BUFFER_SIZE	1024
    47 
    48 static int SDLCALL
    49 win32_file_open(SDL_RWops * context, const char *filename, const char *mode)
    50 {
    51 #ifndef _WIN32_WCE
    52     UINT old_error_mode;
    53 #endif
    54     HANDLE h;
    55     DWORD r_right, w_right;
    56     DWORD must_exist, truncate;
    57     int a_mode;
    58 
    59     if (!context)
    60         return -1;              /* failed (invalid call) */
    61 
    62     context->hidden.win32io.h = INVALID_HANDLE_VALUE;   /* mark this as unusable */
    63     context->hidden.win32io.buffer.data = NULL;
    64     context->hidden.win32io.buffer.size = 0;
    65     context->hidden.win32io.buffer.left = 0;
    66 
    67     /* "r" = reading, file must exist */
    68     /* "w" = writing, truncate existing, file may not exist */
    69     /* "r+"= reading or writing, file must exist            */
    70     /* "a" = writing, append file may not exist             */
    71     /* "a+"= append + read, file may not exist              */
    72     /* "w+" = read, write, truncate. file may not exist    */
    73 
    74     must_exist = (SDL_strchr(mode, 'r') != NULL) ? OPEN_EXISTING : 0;
    75     truncate = (SDL_strchr(mode, 'w') != NULL) ? CREATE_ALWAYS : 0;
    76     r_right = (SDL_strchr(mode, '+') != NULL
    77                || must_exist) ? GENERIC_READ : 0;
    78     a_mode = (SDL_strchr(mode, 'a') != NULL) ? OPEN_ALWAYS : 0;
    79     w_right = (a_mode || SDL_strchr(mode, '+')
    80                || truncate) ? GENERIC_WRITE : 0;
    81 
    82     if (!r_right && !w_right)   /* inconsistent mode */
    83         return -1;              /* failed (invalid call) */
    84 
    85     context->hidden.win32io.buffer.data =
    86         (char *) SDL_malloc(READAHEAD_BUFFER_SIZE);
    87     if (!context->hidden.win32io.buffer.data) {
    88         SDL_OutOfMemory();
    89         return -1;
    90     }
    91 #ifdef _WIN32_WCE
    92     {
    93         size_t size = SDL_strlen(filename) + 1;
    94         wchar_t *filenameW = SDL_stack_alloc(wchar_t, size);
    95 
    96         if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, filenameW, size) ==
    97             0) {
    98             SDL_stack_free(filenameW);
    99             SDL_free(context->hidden.win32io.buffer.data);
   100             context->hidden.win32io.buffer.data = NULL;
   101             SDL_SetError("Unable to convert filename to Unicode");
   102             return -1;
   103         }
   104         h = CreateFile(filenameW, (w_right | r_right),
   105                        (w_right) ? 0 : FILE_SHARE_READ, NULL,
   106                        (must_exist | truncate | a_mode),
   107                        FILE_ATTRIBUTE_NORMAL, NULL);
   108         SDL_stack_free(filenameW);
   109     }
   110 #else
   111     /* Do not open a dialog box if failure */
   112     old_error_mode =
   113         SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
   114 
   115     h = CreateFile(filename, (w_right | r_right),
   116                    (w_right) ? 0 : FILE_SHARE_READ, NULL,
   117                    (must_exist | truncate | a_mode), FILE_ATTRIBUTE_NORMAL,
   118                    NULL);
   119 
   120     /* restore old behaviour */
   121     SetErrorMode(old_error_mode);
   122 #endif /* _WIN32_WCE */
   123 
   124     if (h == INVALID_HANDLE_VALUE) {
   125         SDL_free(context->hidden.win32io.buffer.data);
   126         context->hidden.win32io.buffer.data = NULL;
   127         SDL_SetError("Couldn't open %s", filename);
   128         return -2;              /* failed (CreateFile) */
   129     }
   130     context->hidden.win32io.h = h;
   131     context->hidden.win32io.append = a_mode ? SDL_TRUE : SDL_FALSE;
   132 
   133     return 0;                   /* ok */
   134 }
   135 static long SDLCALL
   136 win32_file_seek(SDL_RWops * context, long offset, int whence)
   137 {
   138     DWORD win32whence;
   139     long file_pos;
   140 
   141     if (!context || context->hidden.win32io.h == INVALID_HANDLE_VALUE) {
   142         SDL_SetError("win32_file_seek: invalid context/file not opened");
   143         return -1;
   144     }
   145 
   146     /* FIXME: We may be able to satisfy the seek within buffered data */
   147     if (whence == RW_SEEK_CUR && context->hidden.win32io.buffer.left) {
   148         offset -= context->hidden.win32io.buffer.left;
   149     }
   150     context->hidden.win32io.buffer.left = 0;
   151 
   152     switch (whence) {
   153     case RW_SEEK_SET:
   154         win32whence = FILE_BEGIN;
   155         break;
   156     case RW_SEEK_CUR:
   157         win32whence = FILE_CURRENT;
   158         break;
   159     case RW_SEEK_END:
   160         win32whence = FILE_END;
   161         break;
   162     default:
   163         SDL_SetError("win32_file_seek: Unknown value for 'whence'");
   164         return -1;
   165     }
   166 
   167     file_pos =
   168         SetFilePointer(context->hidden.win32io.h, offset, NULL, win32whence);
   169 
   170     if (file_pos != INVALID_SET_FILE_POINTER)
   171         return file_pos;        /* success */
   172 
   173     SDL_Error(SDL_EFSEEK);
   174     return -1;                  /* error */
   175 }
   176 static size_t SDLCALL
   177 win32_file_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
   178 {
   179     size_t total_need;
   180     size_t total_read = 0;
   181     size_t read_ahead;
   182     DWORD byte_read;
   183 
   184     total_need = size * maxnum;
   185 
   186     if (!context || context->hidden.win32io.h == INVALID_HANDLE_VALUE
   187         || !total_need)
   188         return 0;
   189 
   190     if (context->hidden.win32io.buffer.left > 0) {
   191         void *data = (char *) context->hidden.win32io.buffer.data +
   192             context->hidden.win32io.buffer.size -
   193             context->hidden.win32io.buffer.left;
   194         read_ahead =
   195             SDL_min(total_need, (size_t) context->hidden.win32io.buffer.left);
   196         SDL_memcpy(ptr, data, read_ahead);
   197         context->hidden.win32io.buffer.left -= read_ahead;
   198 
   199         if (read_ahead == total_need) {
   200             return maxnum;
   201         }
   202         ptr = (char *) ptr + read_ahead;
   203         total_need -= read_ahead;
   204         total_read += read_ahead;
   205     }
   206 
   207     if (total_need < READAHEAD_BUFFER_SIZE) {
   208         if (!ReadFile
   209             (context->hidden.win32io.h, context->hidden.win32io.buffer.data,
   210              READAHEAD_BUFFER_SIZE, &byte_read, NULL)) {
   211             SDL_Error(SDL_EFREAD);
   212             return 0;
   213         }
   214         read_ahead = SDL_min(total_need, (int) byte_read);
   215         SDL_memcpy(ptr, context->hidden.win32io.buffer.data, read_ahead);
   216         context->hidden.win32io.buffer.size = byte_read;
   217         context->hidden.win32io.buffer.left = byte_read - read_ahead;
   218         total_read += read_ahead;
   219     } else {
   220         if (!ReadFile
   221             (context->hidden.win32io.h, ptr, total_need, &byte_read, NULL)) {
   222             SDL_Error(SDL_EFREAD);
   223             return 0;
   224         }
   225         total_read += byte_read;
   226     }
   227     return (total_read / size);
   228 }
   229 static size_t SDLCALL
   230 win32_file_write(SDL_RWops * context, const void *ptr, size_t size,
   231                  size_t num)
   232 {
   233 
   234     size_t total_bytes;
   235     DWORD byte_written, nwritten;
   236 
   237     total_bytes = size * num;
   238 
   239     if (!context || context->hidden.win32io.h == INVALID_HANDLE_VALUE
   240         || total_bytes <= 0 || !size)
   241         return 0;
   242 
   243     if (context->hidden.win32io.buffer.left) {
   244         SetFilePointer(context->hidden.win32io.h,
   245                        -context->hidden.win32io.buffer.left, NULL,
   246                        FILE_CURRENT);
   247         context->hidden.win32io.buffer.left = 0;
   248     }
   249 
   250     /* if in append mode, we must go to the EOF before write */
   251     if (context->hidden.win32io.append) {
   252         if (SetFilePointer(context->hidden.win32io.h, 0L, NULL, FILE_END) ==
   253             INVALID_SET_FILE_POINTER) {
   254             SDL_Error(SDL_EFWRITE);
   255             return 0;
   256         }
   257     }
   258 
   259     if (!WriteFile
   260         (context->hidden.win32io.h, ptr, total_bytes, &byte_written, NULL)) {
   261         SDL_Error(SDL_EFWRITE);
   262         return 0;
   263     }
   264 
   265     nwritten = byte_written / size;
   266     return nwritten;
   267 }
   268 static int SDLCALL
   269 win32_file_close(SDL_RWops * context)
   270 {
   271 
   272     if (context) {
   273         if (context->hidden.win32io.h != INVALID_HANDLE_VALUE) {
   274             CloseHandle(context->hidden.win32io.h);
   275             context->hidden.win32io.h = INVALID_HANDLE_VALUE;   /* to be sure */
   276         }
   277         if (context->hidden.win32io.buffer.data) {
   278             SDL_free(context->hidden.win32io.buffer.data);
   279             context->hidden.win32io.buffer.data = NULL;
   280         }
   281         SDL_FreeRW(context);
   282     }
   283     return (0);
   284 }
   285 #endif /* __WIN32__ */
   286 
   287 #ifdef HAVE_STDIO_H
   288 
   289 /* Functions to read/write stdio file pointers */
   290 
   291 static long SDLCALL
   292 stdio_seek(SDL_RWops * context, long offset, int whence)
   293 {
   294     if (fseek(context->hidden.stdio.fp, offset, whence) == 0) {
   295         return (ftell(context->hidden.stdio.fp));
   296     } else {
   297         SDL_Error(SDL_EFSEEK);
   298         return (-1);
   299     }
   300 }
   301 static size_t SDLCALL
   302 stdio_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
   303 {
   304     size_t nread;
   305 
   306     nread = fread(ptr, size, maxnum, context->hidden.stdio.fp);
   307     if (nread == 0 && ferror(context->hidden.stdio.fp)) {
   308         SDL_Error(SDL_EFREAD);
   309     }
   310     return (nread);
   311 }
   312 static size_t SDLCALL
   313 stdio_write(SDL_RWops * context, const void *ptr, size_t size, size_t num)
   314 {
   315     size_t nwrote;
   316 
   317     nwrote = fwrite(ptr, size, num, context->hidden.stdio.fp);
   318     if (nwrote == 0 && ferror(context->hidden.stdio.fp)) {
   319         SDL_Error(SDL_EFWRITE);
   320     }
   321     return (nwrote);
   322 }
   323 static int SDLCALL
   324 stdio_close(SDL_RWops * context)
   325 {
   326     int status = 0;
   327     if (context) {
   328         if (context->hidden.stdio.autoclose) {
   329             /* WARNING:  Check the return value here! */
   330             if (fclose(context->hidden.stdio.fp) != 0) {
   331                 SDL_Error(SDL_EFWRITE);
   332                 status = -1;
   333             }
   334         }
   335         SDL_FreeRW(context);
   336     }
   337     return status;
   338 }
   339 #endif /* !HAVE_STDIO_H */
   340 
   341 /* Functions to read/write memory pointers */
   342 
   343 static long SDLCALL
   344 mem_seek(SDL_RWops * context, long offset, int whence)
   345 {
   346     Uint8 *newpos;
   347 
   348     switch (whence) {
   349     case RW_SEEK_SET:
   350         newpos = context->hidden.mem.base + offset;
   351         break;
   352     case RW_SEEK_CUR:
   353         newpos = context->hidden.mem.here + offset;
   354         break;
   355     case RW_SEEK_END:
   356         newpos = context->hidden.mem.stop + offset;
   357         break;
   358     default:
   359         SDL_SetError("Unknown value for 'whence'");
   360         return (-1);
   361     }
   362     if (newpos < context->hidden.mem.base) {
   363         newpos = context->hidden.mem.base;
   364     }
   365     if (newpos > context->hidden.mem.stop) {
   366         newpos = context->hidden.mem.stop;
   367     }
   368     context->hidden.mem.here = newpos;
   369     return (context->hidden.mem.here - context->hidden.mem.base);
   370 }
   371 static size_t SDLCALL
   372 mem_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
   373 {
   374     size_t total_bytes;
   375     size_t mem_available;
   376 
   377     total_bytes = (maxnum * size);
   378     if ((maxnum <= 0) || (size <= 0)
   379         || ((total_bytes / maxnum) != (size_t) size)) {
   380         return 0;
   381     }
   382 
   383     mem_available = (context->hidden.mem.stop - context->hidden.mem.here);
   384     if (total_bytes > mem_available) {
   385         total_bytes = mem_available;
   386     }
   387 
   388     SDL_memcpy(ptr, context->hidden.mem.here, total_bytes);
   389     context->hidden.mem.here += total_bytes;
   390 
   391     return (total_bytes / size);
   392 }
   393 static size_t SDLCALL
   394 mem_write(SDL_RWops * context, const void *ptr, size_t size, size_t num)
   395 {
   396     if ((context->hidden.mem.here + (num * size)) > context->hidden.mem.stop) {
   397         num = (context->hidden.mem.stop - context->hidden.mem.here) / size;
   398     }
   399     SDL_memcpy(context->hidden.mem.here, ptr, num * size);
   400     context->hidden.mem.here += num * size;
   401     return (num);
   402 }
   403 static size_t SDLCALL
   404 mem_writeconst(SDL_RWops * context, const void *ptr, size_t size, size_t num)
   405 {
   406     SDL_SetError("Can't write to read-only memory");
   407     return (-1);
   408 }
   409 static int SDLCALL
   410 mem_close(SDL_RWops * context)
   411 {
   412     if (context) {
   413         SDL_FreeRW(context);
   414     }
   415     return (0);
   416 }
   417 
   418 
   419 /* Functions to create SDL_RWops structures from various data sources */
   420 
   421 SDL_RWops *
   422 SDL_RWFromFile(const char *file, const char *mode)
   423 {
   424     SDL_RWops *rwops = NULL;
   425 #ifdef HAVE_STDIO_H
   426     FILE *fp = NULL;
   427 #endif
   428     if (!file || !*file || !mode || !*mode) {
   429         SDL_SetError("SDL_RWFromFile(): No file or no mode specified");
   430         return NULL;
   431     }
   432 #if defined(__WIN32__)
   433     rwops = SDL_AllocRW();
   434     if (!rwops)
   435         return NULL;            /* SDL_SetError already setup by SDL_AllocRW() */
   436     if (win32_file_open(rwops, file, mode) < 0) {
   437         SDL_FreeRW(rwops);
   438         return NULL;
   439     }
   440     rwops->seek = win32_file_seek;
   441     rwops->read = win32_file_read;
   442     rwops->write = win32_file_write;
   443     rwops->close = win32_file_close;
   444 
   445 #elif HAVE_STDIO_H
   446 
   447     fp = fopen(file, mode);
   448     if (fp == NULL) {
   449         SDL_SetError("Couldn't open %s", file);
   450     } else {
   451         rwops = SDL_RWFromFP(fp, 1);
   452     }
   453 #else
   454     SDL_SetError("SDL not compiled with stdio support");
   455 #endif /* !HAVE_STDIO_H */
   456 
   457     return (rwops);
   458 }
   459 
   460 #ifdef HAVE_STDIO_H
   461 SDL_RWops *
   462 SDL_RWFromFP(FILE * fp, SDL_bool autoclose)
   463 {
   464     SDL_RWops *rwops = NULL;
   465 
   466     rwops = SDL_AllocRW();
   467     if (rwops != NULL) {
   468         rwops->seek = stdio_seek;
   469         rwops->read = stdio_read;
   470         rwops->write = stdio_write;
   471         rwops->close = stdio_close;
   472         rwops->hidden.stdio.fp = fp;
   473         rwops->hidden.stdio.autoclose = autoclose;
   474     }
   475     return (rwops);
   476 }
   477 #endif /* HAVE_STDIO_H */
   478 
   479 SDL_RWops *
   480 SDL_RWFromMem(void *mem, int size)
   481 {
   482     SDL_RWops *rwops;
   483 
   484     rwops = SDL_AllocRW();
   485     if (rwops != NULL) {
   486         rwops->seek = mem_seek;
   487         rwops->read = mem_read;
   488         rwops->write = mem_write;
   489         rwops->close = mem_close;
   490         rwops->hidden.mem.base = (Uint8 *) mem;
   491         rwops->hidden.mem.here = rwops->hidden.mem.base;
   492         rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
   493     }
   494     return (rwops);
   495 }
   496 
   497 SDL_RWops *
   498 SDL_RWFromConstMem(const void *mem, int size)
   499 {
   500     SDL_RWops *rwops;
   501 
   502     rwops = SDL_AllocRW();
   503     if (rwops != NULL) {
   504         rwops->seek = mem_seek;
   505         rwops->read = mem_read;
   506         rwops->write = mem_writeconst;
   507         rwops->close = mem_close;
   508         rwops->hidden.mem.base = (Uint8 *) mem;
   509         rwops->hidden.mem.here = rwops->hidden.mem.base;
   510         rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
   511     }
   512     return (rwops);
   513 }
   514 
   515 SDL_RWops *
   516 SDL_AllocRW(void)
   517 {
   518     SDL_RWops *area;
   519 
   520     area = (SDL_RWops *) SDL_malloc(sizeof *area);
   521     if (area == NULL) {
   522         SDL_OutOfMemory();
   523     }
   524     return (area);
   525 }
   526 
   527 void
   528 SDL_FreeRW(SDL_RWops * area)
   529 {
   530     SDL_free(area);
   531 }
   532 
   533 /* Functions for dynamically reading and writing endian-specific values */
   534 
   535 Uint16
   536 SDL_ReadLE16(SDL_RWops * src)
   537 {
   538     Uint16 value;
   539 
   540     SDL_RWread(src, &value, (sizeof value), 1);
   541     return (SDL_SwapLE16(value));
   542 }
   543 
   544 Uint16
   545 SDL_ReadBE16(SDL_RWops * src)
   546 {
   547     Uint16 value;
   548 
   549     SDL_RWread(src, &value, (sizeof value), 1);
   550     return (SDL_SwapBE16(value));
   551 }
   552 
   553 Uint32
   554 SDL_ReadLE32(SDL_RWops * src)
   555 {
   556     Uint32 value;
   557 
   558     SDL_RWread(src, &value, (sizeof value), 1);
   559     return (SDL_SwapLE32(value));
   560 }
   561 
   562 Uint32
   563 SDL_ReadBE32(SDL_RWops * src)
   564 {
   565     Uint32 value;
   566 
   567     SDL_RWread(src, &value, (sizeof value), 1);
   568     return (SDL_SwapBE32(value));
   569 }
   570 
   571 Uint64
   572 SDL_ReadLE64(SDL_RWops * src)
   573 {
   574     Uint64 value;
   575 
   576     SDL_RWread(src, &value, (sizeof value), 1);
   577     return (SDL_SwapLE64(value));
   578 }
   579 
   580 Uint64
   581 SDL_ReadBE64(SDL_RWops * src)
   582 {
   583     Uint64 value;
   584 
   585     SDL_RWread(src, &value, (sizeof value), 1);
   586     return (SDL_SwapBE64(value));
   587 }
   588 
   589 int
   590 SDL_WriteLE16(SDL_RWops * dst, Uint16 value)
   591 {
   592     value = SDL_SwapLE16(value);
   593     return (SDL_RWwrite(dst, &value, (sizeof value), 1));
   594 }
   595 
   596 int
   597 SDL_WriteBE16(SDL_RWops * dst, Uint16 value)
   598 {
   599     value = SDL_SwapBE16(value);
   600     return (SDL_RWwrite(dst, &value, (sizeof value), 1));
   601 }
   602 
   603 int
   604 SDL_WriteLE32(SDL_RWops * dst, Uint32 value)
   605 {
   606     value = SDL_SwapLE32(value);
   607     return (SDL_RWwrite(dst, &value, (sizeof value), 1));
   608 }
   609 
   610 int
   611 SDL_WriteBE32(SDL_RWops * dst, Uint32 value)
   612 {
   613     value = SDL_SwapBE32(value);
   614     return (SDL_RWwrite(dst, &value, (sizeof value), 1));
   615 }
   616 
   617 int
   618 SDL_WriteLE64(SDL_RWops * dst, Uint64 value)
   619 {
   620     value = SDL_SwapLE64(value);
   621     return (SDL_RWwrite(dst, &value, (sizeof value), 1));
   622 }
   623 
   624 int
   625 SDL_WriteBE64(SDL_RWops * dst, Uint64 value)
   626 {
   627     value = SDL_SwapBE64(value);
   628     return (SDL_RWwrite(dst, &value, (sizeof value), 1));
   629 }
   630 
   631 /* vi: set ts=4 sw=4 expandtab: */