/* SDL - Simple DirectMedia Layer Copyright (C) 1997-2004 Sam Lantinga This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Sam Lantinga slouken@libsdl.org */ #ifdef SAVE_RCSID static char rcsid = "@(#) $Id: SDL_rwops.c,v 1.9 2005/06/24 12:48:38 icculus Exp $"; #endif /* This file provides a general interface for SDL to read and write data sources. It can easily be extended to files, memory, etc. */ #include #include #include #include "SDL_error.h" #include "SDL_rwops.h" /* Functions to read/write stdio file pointers */ static int stdio_seek(SDL_RWops *context, int offset, int whence) { _10000:if (!( fseek(context->hidden.stdio.fp, offset, whence) == 0 )) goto _10030; _10010:return(ftell(context->hidden.stdio.fp)); _10020:goto _10050; _10030:SDL_Error(SDL_EFSEEK); _10040:return(-1); _10050:0; } static int stdio_read(SDL_RWops *context, void *ptr, int size, int maxnum) { size_t nread; _10060:nread = fread(ptr, size, maxnum, context->hidden.stdio.fp); _10070:if (!( nread == 0 && ferror(context->hidden.stdio.fp) )) goto _10090; _10080:SDL_Error(SDL_EFREAD); _10090:return(nread); } static int stdio_write(SDL_RWops *context, const void *ptr, int size, int num) { size_t nwrote; _10100:nwrote = fwrite(ptr, size, num, context->hidden.stdio.fp); _10110:if (!( nwrote == 0 && ferror(context->hidden.stdio.fp) )) goto _10130; _10120:SDL_Error(SDL_EFWRITE); _10130:return(nwrote); } static int stdio_close(SDL_RWops *context) { _10140:if (!( context )) goto _10180; _10150:if (!( context->hidden.stdio.autoclose )) goto _10170; /* WARNING: Check the return value here! */ _10160:fclose(context->hidden.stdio.fp); _10170:free(context); _10180:return(0); } /* Functions to read/write memory pointers */ static int mem_seek(SDL_RWops *context, int offset, int whence) { Uint8 *newpos; _10190:switch (whence) { case SEEK_SET: _10200:newpos = context->hidden.mem.base+offset; _10210:break; case SEEK_CUR: _10220:newpos = context->hidden.mem.here+offset; _10230:break; case SEEK_END: _10240:newpos = context->hidden.mem.stop+offset; _10250:break; _10260:default: SDL_SetError("Unknown value for 'whence'"); _10270:return(-1); } _10280:if (!( newpos < context->hidden.mem.base )) goto _10300; _10290:newpos = context->hidden.mem.base; _10300:if (!( newpos > context->hidden.mem.stop )) goto _10320; _10310:newpos = context->hidden.mem.stop; _10320:context->hidden.mem.here = newpos; _10330:return(context->hidden.mem.here-context->hidden.mem.base); } static int mem_read(SDL_RWops *context, void *ptr, int size, int maxnum) { int total_bytes; int mem_available; _10340:total_bytes = (maxnum * size); _10350:if (!( (maxnum <= 0) || (size <= 0) || ((total_bytes / maxnum) != size) )) goto _10370; _10360:return 0; _10370:mem_available = (context->hidden.mem.stop - context->hidden.mem.here); _10380:if (!(total_bytes > mem_available)) goto _10400; _10390:total_bytes = mem_available; _10400:memcpy(ptr, context->hidden.mem.here, total_bytes); _10410:context->hidden.mem.here += total_bytes; _10420:return (total_bytes / size); } static int mem_write(SDL_RWops *context, const void *ptr, int size, int num) { _10430:if (!( (context->hidden.mem.here + (num*size)) > context->hidden.mem.stop )) goto _10450; _10440:num = (context->hidden.mem.stop-context->hidden.mem.here)/size; _10450:memcpy(context->hidden.mem.here, ptr, num*size); _10460:context->hidden.mem.here += num*size; _10470:return(num); } static int mem_writeconst(SDL_RWops *context, const void *ptr, int size, int num) { _10480:SDL_SetError("Can't write to read-only memory"); _10490:return(-1); } static int mem_close(SDL_RWops *context) { _10500:if (!( context )) goto _10520; _10510:free(context); _10520:return(0); } /* Functions to create SDL_RWops structures from various data sources */ #ifdef WIN32 /* Aggh. You can't (apparently) open a file in an application and read from it in a DLL. */ static int in_sdl = 0; #endif #ifdef macintosh /* * translate unix-style slash-separated filename to mac-style colon-separated * name; return malloced string */ static char *unix_to_mac(const char *file) { int flen = strlen(file); char *path = malloc(flen + 2); const char *src = file; char *dst = path; _10530:if (!(*src == '/')) goto _10560; /* really depends on filesystem layout, hope for the best */ _10540:src++; _10550:goto _10580; /* Check if this is a MacOS path to begin with */ _10560:if(*src != ':') _10570:*dst++ = ':'; /* relative paths begin with ':' */ _10580:if (!(src < file + flen)) goto _10720; const char *end = strchr(src, '/'); int len; _10590:if(!end) _10600:end = file + flen; /* last component */ _10610:len = end - src; _10620:if (!(len == 0 || (len == 1 && src[0] == '.'))) goto _10640; /* remove repeated slashes and . */ _10630:goto _10700; _10640:if (!(len == 2 && src[0] == '.' && src[1] == '.')) goto _10660; /* replace .. with the empty string */ _10650:goto _10680; _10660:memcpy(dst, src, len); _10670:dst += len; _10680:if(end < file + flen) _10690:*dst++ = ':'; _10700:src = end + 1; _10710:goto _10580; _10720:*dst++ = '\0'; _10730:return path; } #endif /* macintosh */ SDL_RWops *SDL_RWFromFile(const char *file, const char *mode) { FILE *fp; SDL_RWops *rwops; _10740:rwops = NULL; #ifdef macintosh { char *mpath = unix_to_mac(file); _10750:fp = fopen(mpath, mode); _10760:free(mpath); } #else _10770:fp = fopen(file, mode); #endif _10780:if ( fp == NULL ) { _10790:SDL_SetError("Couldn't open %s", file); } else { #ifdef WIN32 _10800:in_sdl = 1; _10810:rwops = SDL_RWFromFP(fp, 1); _10820:in_sdl = 0; #else _10830:rwops = SDL_RWFromFP(fp, 1); #endif } _10840:return(rwops); } SDL_RWops *SDL_RWFromFP(FILE *fp, int autoclose) { SDL_RWops *rwops; #ifdef WIN32 _10850:if ( ! in_sdl ) { _10860:SDL_SetError("You can't pass a FILE pointer to a DLL (?)"); /*return(NULL);*/ } #endif _10870:rwops = SDL_AllocRW(); _10880:if (!( rwops != NULL )) goto _10950; _10890:rwops->seek = stdio_seek; _10900:rwops->read = stdio_read; _10910:rwops->write = stdio_write; _10920:rwops->close = stdio_close; _10930:rwops->hidden.stdio.fp = fp; _10940:rwops->hidden.stdio.autoclose = autoclose; _10950:return(rwops); } SDL_RWops *SDL_RWFromMem(void *mem, int size) { SDL_RWops *rwops; _10960:rwops = SDL_AllocRW(); _10970:if (!( rwops != NULL )) goto _11050; _10980:rwops->seek = mem_seek; _10990:rwops->read = mem_read; _11000:rwops->write = mem_write; _11010:rwops->close = mem_close; _11020:rwops->hidden.mem.base = (Uint8 *)mem; _11030:rwops->hidden.mem.here = rwops->hidden.mem.base; _11040:rwops->hidden.mem.stop = rwops->hidden.mem.base+size; _11050:return(rwops); } SDL_RWops *SDL_RWFromConstMem(const void *mem, int size) { SDL_RWops *rwops; _11060:rwops = SDL_AllocRW(); _11070:if (!( rwops != NULL )) goto _11150; _11080:rwops->seek = mem_seek; _11090:rwops->read = mem_read; _11100:rwops->write = mem_writeconst; _11110:rwops->close = mem_close; _11120:rwops->hidden.mem.base = (Uint8 *)mem; _11130:rwops->hidden.mem.here = rwops->hidden.mem.base; _11140:rwops->hidden.mem.stop = rwops->hidden.mem.base+size; _11150:return(rwops); } SDL_RWops *SDL_AllocRW(void) { SDL_RWops *area; _11160:area = (SDL_RWops *)malloc(sizeof *area); _11170:if (!( area == NULL )) goto _11190; _11180:SDL_OutOfMemory(); _11190:return(area); } void SDL_FreeRW(SDL_RWops *area) { _11200:free(area); }