src/file/SDL_rwops.c
author Bob Pendleton <bob@pendleton.com>
Thu, 12 Jul 2007 20:00:50 +0000
changeset 2185 2032348afed1
parent 2179 8b76cc268771
child 2674 f1d07ba2e275
child 2735 204be4fc2726
permissions -rw-r--r--
This code adds support for DirectColor visuals to SDL 1.3. The support uses part of the Xmu library. To ensure that the library is
available and to keep people form having to install yet another library I have added the essential parts of Xmu in
src/video/extensions/XmuStdCmap and an include file in src/video/extensions. The support makes use of standard X11 mechanisms to
create color maps and make sure that an application uses the same color map for each window/visual combination. This should make it
possible for gamma support to be implemented based on a single color map per application.

Hurm... it looks like "make indent" modified a few extra files. Those are getting committed too.
     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: */