diff --git a/src/fex.h b/src/fex.h new file mode 100644 index 00000000..e2bf69b4 --- /dev/null +++ b/src/fex.h @@ -0,0 +1,140 @@ +/* Compressed file archive C interface (also usable from C++) */ + +/* File_Extractor 0.4.3 */ +#ifndef FEX_H +#define FEX_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Error string returned by library functions, or NULL if no error (success). +If function takes fex_err_t* err_out, it sets *err_out to NULL on success, +otherwise error string, or you can pass NULL if you don't care about exact +cause of error (these functions still report error by returning NULL). */ +typedef const char* fex_err_t; + +/* First parameter of most extractor_ functions is a pointer to the +File_Extractor being acted on. */ +typedef struct File_Extractor File_Extractor; + + +/**** Basics ****/ + +/* Opens archive and returns pointer to it, or NULL if error. */ +File_Extractor* fex_open( const char* path, fex_err_t* err_out ); + +/* True if at end of archive. */ +int fex_done( File_Extractor const* ); + +/* Name of current file. */ +const char* fex_name( File_Extractor* ); + +/* Size of current file. */ +long fex_size( File_Extractor const* ); + +/* Extracts n bytes and writes them to *out. Returns error if all n +bytes couldn't be extracted (due to end of file or read error). */ +fex_err_t fex_read( File_Extractor*, void* out, long n ); + +/* Goes to next file in archive (skips directories). */ +fex_err_t fex_next( File_Extractor* ); + +/* Closes archive and frees memory. */ +void fex_close( File_Extractor* ); + + +/**** Advanced ****/ + +/* Goes back to first file in archive. */ +fex_err_t fex_rewind( File_Extractor* ); + +/* Hints to fex_next() that no file extraction will occur, speeding scanning +of some archive types. */ +void fex_scan_only( File_Extractor* ); + +/* Modification date of current file (MS-DOS format). */ +unsigned long fex_dos_date( File_Extractor const* ); + +/* Number of bytes remaining to be read from current file. */ +long fex_remain( File_Extractor const* ); + +/* Reads at most n bytes and returns number actually read, or negative if error. */ +long fex_read_avail( File_Extractor*, void* out, long n ); + +/* Extracts first n bytes and ignores rest. Faster than a normal read since it +doesn't need to read any more data. Must not be called twice in a row. */ +fex_err_t fex_read_once( File_Extractor*, void* out, long n ); + +/* Loads file data into memory (if not already) and returns pointer to it, or +NULL if error. Pointer is valid until fex_next(), fex_rewind(), or fex_close() are +called. Will return same pointer if called more than once. */ +const unsigned char* fex_data( File_Extractor*, fex_err_t* err_out ); + + +/**** Archive types ****/ + +/* fex_type_t is a pointer to this structure. For example, fex_zip_type->extension is +"ZIP" and ex_zip_type->new_fex() is equilvant to 'new Zip_Extractor' (in C++). */ +struct fex_type_t_ +{ + const char* extension; /* file extension/type */ + File_Extractor* (*new_fex)(); +}; + +/* Archive type constants for each supported file type */ +extern struct fex_type_t_ const + fex_7z_type [1], /* .7z (7-zip) */ + fex_gz_type [1], /* .gz (gzip) */ + /*fex_rar_type [1],*/ /* .rar */ + fex_zip_type [1], /* .zip */ + fex_bin_type [1]; /* binary file, possibly gzipped */ +typedef struct fex_type_t_ const* fex_type_t; + +/* Array of supported archive types, with NULL entry at end. */ +fex_type_t const* fex_type_list(); + +/* Type of archive this extractor handles. */ +fex_type_t fex_type( File_Extractor const* ); + + +/******** Advanced opening ********/ + +/* Error returned if file is wrong type */ +extern const char fex_wrong_file_type [29]; + +/* Determines likely archive type based on first four bytes of file. Returns string +containing proper file suffix (i.e. "ZIP", "GZ", etc.) or "" (empty string) if file +header is not recognized. */ +const char* fex_identify_header( void const* header ); + +/* Gets corresponding archive type for file path or extension passed in. Returns NULL +if type isn't recognized. */ +fex_type_t fex_identify_extension( const char* path_or_extension ); + +/* Determines file type based on filename extension, or file header (if extension +isn't recognized). Returns NULL if unrecognized or error. */ +fex_type_t fex_identify_file( const char* path, fex_err_t* err_out ); + +/* Opens archive of specific type and returns pointer to it, or NULL if error. */ +File_Extractor* fex_open_type( fex_type_t, const char* path, fex_err_t* err_out ); + + +/******** User data ********/ + +/* Sets/gets pointer to data you want to associate with this extractor. +You can use this for whatever you want. */ +void fex_set_user_data( File_Extractor*, void* new_user_data ); +void* fex_user_data( File_Extractor const* ); + +/* Registers cleanup function to be called when closing extractor, or NULL to +clear it. Passes user_data (see above) to cleanup function. */ +typedef void (*fex_user_cleanup_t)( void* user_data ); +void fex_set_user_cleanup( File_Extractor*, fex_user_cleanup_t func ); + + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/src/fex_mini.cpp b/src/fex_mini.cpp new file mode 100644 index 00000000..0b61bd5b --- /dev/null +++ b/src/fex_mini.cpp @@ -0,0 +1,222 @@ +// Minimal implementation of fex.h. Supports gzipped files if you have zlib +// available and HAVE_ZLIB_H is defined. + +// File_Extractor 0.4.3. http://www.slack.net/~ant/ + +#include "fex.h" + +#include +#include +#include + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +/* Copyright (C) 2007 Shay Green. This module is free software; you +can redistribute it and/or modify it under the terms of the GNU Lesser +General Public License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. This +module 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 Lesser General Public License for more +details. You should have received a copy of the GNU Lesser General Public +License along with this module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef HAVE_ZLIB_H + #define FILE_GZ( norm, gz ) norm + #define FILE_READ( ptr, size, file ) fread( ptr, 1, size, file ) +#else + #define FILE_GZ( norm, gz ) gz + #define FILE_READ( ptr, size, file ) gzread( file, ptr, size ) + +#include "zlib.h" + +static const char* get_gzip_size( const char* path, long* eof ) +{ + FILE* file = fopen( path, "rb" ); + if ( !file ) + return "Couldn't open file"; + + unsigned char buf [4]; + if ( fread( buf, 2, 1, file ) > 0 && buf [0] == 0x1F && buf [1] == 0x8B ) + { + fseek( file, -4, SEEK_END ); + fread( buf, 4, 1, file ); + *eof = buf [3] * 0x1000000 + buf [2] * 0x10000 + buf [1] * 0x100 + buf [0]; + } + else + { + fseek( file, 0, SEEK_END ); + *eof = ftell( file ); + } + const char* err = (ferror( file ) || feof( file )) ? "Couldn't get file size" : 0; + fclose( file ); + return err; +} +#endif + +const char fex_wrong_file_type [] = "Archive format not supported"; + +struct File_Extractor +{ + FILE_GZ(FILE*,gzFile) file; + int done; + long size; + void* data; // file data read into memory, ot 0 if not read + void* user_data; + fex_user_cleanup_t user_cleanup; + + char* name() const { return (char*) (this + 1); } +}; + +// Always identify as single file extractor +fex_type_t_ const fex_bin_type [1] = {{ "" , 0 }}; +const char* fex_identify_header ( void const* ) { return ""; } +fex_type_t fex_identify_extension( const char* ) { return fex_bin_type; } +fex_type_t fex_identify_file ( const char*, fex_err_t* e ) { if ( e ) *e = 0; return fex_bin_type; } + +static fex_err_t fex_open_( const char* path, File_Extractor** fe_out ) +{ + *fe_out = 0; + + // name + const char* name = strrchr( path, '\\' ); // DOS + if ( !name ) + name = strrchr( path, '/' ); // UNIX + if ( !name ) + name = strrchr( path, ':' ); // Mac + if ( !name ) + name = path; + + // allocate space for struct and name + long name_size = strlen( name ) + 1; + File_Extractor* fe = (File_Extractor*) malloc( sizeof (File_Extractor) + name_size ); + if ( !fe ) return "Out of memory"; + + fe->done = 0; + fe->data = 0; + fe->user_data = 0; + fe->user_cleanup = 0; + memcpy( fe->name(), name, name_size ); + + #ifdef HAVE_ZLIB_H + // get gzip size BEFORE opening file + const char* err = get_gzip_size( path, &fe->size ); + if ( err ) + { + free( fe ); + return err; + } + #endif + + // open file + fe->file = FILE_GZ(fopen,gzopen)( path, "rb" ); + if ( !fe->file ) + { + free( fe ); + return "Couldn't open file"; + } + + // get normal size + #ifndef HAVE_ZLIB_H + fseek( fe->file, 0, SEEK_END ); + fe->size = ftell( fe->file ); + rewind( fe->file ); + #endif + + *fe_out = fe; + return 0; +} + +File_Extractor* fex_open( const char* path, fex_err_t* err_out ) +{ + File_Extractor* fe; + fex_err_t err = fex_open_( path, &fe ); + if ( err_out ) + *err_out = err; + return fe; +} + +File_Extractor* fex_open_type( fex_type_t, const char* path, fex_err_t* err_out ) +{ + return fex_open( path, err_out ); +} + +void* fex_user_data ( File_Extractor const* fe ) { return fe->user_data; } +void fex_set_user_data ( File_Extractor* fe, void* new_user_data ) { fe->user_data = new_user_data; } +void fex_set_user_cleanup ( File_Extractor* fe, fex_user_cleanup_t func ) { fe->user_cleanup = func; } + +fex_type_t fex_type ( File_Extractor const* ) { return fex_bin_type; } +int fex_done ( File_Extractor const* fe ) { return fe->done; } +const char* fex_name ( File_Extractor* fe ) { return fe->name(); } +unsigned long fex_dos_date ( File_Extractor const* ) { return 0; } +long fex_size ( File_Extractor const* fe ) { return fe->size; } +long fex_remain ( File_Extractor const* fe ) { return fe->size - FILE_GZ(ftell,gztell)( fe->file ); } +void fex_scan_only ( File_Extractor* ) { } +fex_err_t fex_read_once ( File_Extractor* fe, void* out, long count ) { return fex_read( fe, out, count ); } +long fex_read_avail ( File_Extractor* fe, void* out, long count ) { return FILE_READ( out, count, fe->file ); } + +fex_err_t fex_read( File_Extractor* fe, void* out, long count ) +{ + if ( count == (long) FILE_READ( out, count, fe->file ) ) + return 0; + + if ( FILE_GZ(feof,gzeof)( fe->file ) ) + return "Unexpected end of file"; + + return "Couldn't read from file"; +} + +fex_err_t fex_next( File_Extractor* fe ) +{ + fe->done = 1; + return 0; +} + +fex_err_t fex_rewind( File_Extractor* fe ) +{ + fe->done = 0; + FILE_GZ(rewind,gzrewind)( fe->file ); + return 0; +} + +static fex_err_t fex_data_( File_Extractor* fe ) +{ + if ( !fe->data ) + { + fe->data = malloc( fe->size ); + if ( !fe->data ) return "Out of memory"; + + fex_err_t err = fex_read( fe, fe->data, fe->size ); + if ( err ) + { + free( fe->data ); + return err; + } + } + return 0; +} + +const unsigned char* fex_data( File_Extractor* fe, fex_err_t* err_out ) +{ + fex_err_t err = fex_data_( fe ); + if ( err_out ) + *err_out = err; + return (const unsigned char*) fe->data; +} + +void fex_close( File_Extractor* fe ) +{ + if ( fe ) + { + free( fe->data ); + FILE_GZ(fclose,gzclose)( fe->file ); + + if ( fe->user_cleanup ) + fe->user_cleanup( fe->user_data ); + + free( fe ); + } +} diff --git a/src/sdl/SDL.cpp b/src/sdl/SDL.cpp index 905ce67e..19bfdc7e 100644 --- a/src/sdl/SDL.cpp +++ b/src/sdl/SDL.cpp @@ -119,10 +119,10 @@ int destHeight = 0; int sensorX = 2047; int sensorY = 2047; -int filter = (int)kStretch1x; +int filter = (int)kStretch2x; u8 *delta = NULL; -int filter_enlarge = 1; +int filter_enlarge = 2; int sdlPrintUsage = 0; int disableMMX = 0; @@ -1007,7 +1007,7 @@ void sdlInitVideo() { } else flags |= SDL_HWSURFACE | SDL_DOUBLEBUF; - surface = SDL_SetVideoMode(destWidth, destHeight, 16, flags); + surface = SDL_SetVideoMode(destWidth, destHeight, 0, flags); if(surface == NULL) { systemMessage(0, "Failed to set video mode"); @@ -1290,7 +1290,7 @@ void sdlPollEvents() case SDL_VIDEORESIZE: if (openGL) { - SDL_SetVideoMode(event.resize.w, event.resize.h, 16, + SDL_SetVideoMode(event.resize.w, event.resize.h, 0, SDL_OPENGL | SDL_RESIZABLE | (fullscreen ? SDL_FULLSCREEN : 0)); sdlOpenGLInit(event.resize.w, event.resize.h); @@ -1790,7 +1790,7 @@ int main(int argc, char **argv) exit(-1); } - utilGetBaseName(szFile, filename); + utilStripDoubleExtension(szFile, filename); char *p = strrchr(filename, '.'); if(p) @@ -1936,7 +1936,7 @@ int main(int argc, char **argv) filterFunction = initFilter((Filter)filter, systemColorDepth, srcWidth); if (!filterFunction) { - fprintf(stderr,"Unable to init filter\n"); + fprintf(stderr,"Unable to init filter '%s'\n", getFilterName((Filter)filter)); exit(-1); } @@ -2077,99 +2077,89 @@ void systemMessage(int num, const char *msg, ...) va_end(valist); } -void systemDrawScreen() +void drawScreenMessage(u8 *screen, int pitch, int x, int y, unsigned int duration) { - renderedFrames++; - - if(!openGL) - SDL_LockSurface(surface); - if(screenMessage) { if(cartridgeType == 1 && gbBorderOn) { gbSgbRenderBorder(); } - if(((systemGetClock() - screenMessageTime) < 3000) && + if(((systemGetClock() - screenMessageTime) < duration) && !disableStatusMessages) { - drawText(pix, srcPitch, 10, srcHeight - 20, + drawText(screen, pitch, x, y, screenMessageBuffer); } else { screenMessage = false; } } +} - if(ifbFunction) { - if(systemColorDepth == 16) - ifbFunction(pix+destWidth+4, destWidth+4, srcWidth, srcHeight); - else - ifbFunction(pix+destWidth*2+4, destWidth*2+4, srcWidth, srcHeight); +void drawSpeed(u8 *screen, int pitch, int x, int y) +{ + char buffer[50]; + if(showSpeed == 1) + sprintf(buffer, "%d%%", systemSpeed); + else + sprintf(buffer, "%3d%%(%d, %d fps)", systemSpeed, + systemFrameSkip, + showRenderedFrames); + if(showSpeedTransparent) + drawTextTransp(screen, pitch, x, y, buffer); + else + drawText(screen, pitch, x, y, buffer); +} + +void systemDrawScreen() +{ + unsigned int destPitch = destWidth * (systemColorDepth >> 3); + u8 *screen; + + renderedFrames++; + + if (openGL) + screen = filterPix; + else { + screen = (u8*)surface->pixels; + SDL_LockSurface(surface); } + if (ifbFunction) + ifbFunction(pix + srcPitch, srcPitch, srcWidth, srcHeight); + + filterFunction(pix + srcPitch, srcPitch, delta, screen, + destPitch, srcWidth, srcHeight); + + drawScreenMessage(screen, destPitch, 10, destHeight - 20, 3000); + + if (showSpeed && fullscreen) + drawSpeed(screen, destPitch, 10, 20); + if (openGL) { - int pitch = srcWidth * 4 + 4; - - filterFunction(pix + pitch, - pitch, - delta, - (u8*)filterPix, - srcWidth * 4 * filter_enlarge, - srcWidth, - srcHeight); - - glPixelStorei(GL_UNPACK_ROW_LENGTH, destWidth); + glPixelStorei(GL_UNPACK_ROW_LENGTH, destWidth); + if (systemColorDepth == 16) glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, destWidth, destHeight, - GL_BGRA, GL_UNSIGNED_BYTE, filterPix); + GL_RGB, GL_UNSIGNED_SHORT_5_6_5, screen); + else + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, destWidth, destHeight, + GL_BGRA, GL_UNSIGNED_BYTE, screen); glBegin(GL_TRIANGLE_STRIP); glTexCoord2f(0.0f, 0.0f); glVertex3i(0, 0, 0); - glTexCoord2f(filter_enlarge * srcWidth / (GLfloat) textureSize, 0.0f); + glTexCoord2f(destWidth / (GLfloat) textureSize, 0.0f); glVertex3i(1, 0, 0); - glTexCoord2f(0.0f, filter_enlarge * srcHeight / (GLfloat) textureSize); + glTexCoord2f(0.0f, destHeight / (GLfloat) textureSize); glVertex3i(0, 1, 0); - glTexCoord2f(filter_enlarge * srcWidth / (GLfloat) textureSize, - filter_enlarge * srcHeight / (GLfloat) textureSize); + glTexCoord2f(destWidth / (GLfloat) textureSize, + destHeight / (GLfloat) textureSize); glVertex3i(1, 1, 0); glEnd(); - SDL_GL_SwapBuffers(); + SDL_GL_SwapBuffers(); } else { - - unsigned int destw = destWidth*((systemColorDepth == 16) ? 2 : 4) / filter_enlarge + 4; - filterFunction(pix+destw, - destw, - delta, - (u8*)surface->pixels, - surface->pitch, - srcWidth, - srcHeight); - - if(showSpeed && fullscreen) { - char buffer[50]; - if(showSpeed == 1) - sprintf(buffer, "%d%%", systemSpeed); - else - sprintf(buffer, "%3d%%(%d, %d fps)", systemSpeed, - systemFrameSkip, - showRenderedFrames); - if(showSpeedTransparent) - drawTextTransp((u8*)surface->pixels, - surface->pitch, - 10, - surface->h-20, - buffer); - else - drawText((u8*)surface->pixels, - surface->pitch, - 10, - surface->h-20, - buffer); + SDL_UnlockSurface(surface); + SDL_Flip(surface); } - SDL_UnlockSurface(surface); - // SDL_UpdateRect(surface, 0, 0, destWidth, destHeight); - SDL_Flip(surface); -} - } bool systemReadJoypads() @@ -2600,7 +2590,6 @@ void systemGbBorderOn() (((i & 0x7c00) >> 10) << systemBlueShift); } } - srcPitch = srcWidth * 2+4; } else { RGB_LOW_BITS_MASK = 0x010101; for(int i = 0; i < 0x10000; i++) { @@ -2608,9 +2597,5 @@ void systemGbBorderOn() (((i & 0x3e0) >> 5) << systemGreenShift) | (((i & 0x7c00) >> 10) << systemBlueShift); } - if(systemColorDepth == 32) - srcPitch = srcWidth*4 + 4; - else - srcPitch = srcWidth*3; } }