/* * Sega Model 3 Emulator * Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License Version 2 as published * by the Free Software Foundation. * * This program 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 General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program (license.txt); if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * file.c * * File access and ZIP file support * */ #include "model3.h" #include "file.h" #include "unzip/unzip.h" /* ZLIB */ static unzFile zip_file; /* zip_get_file_size * * Gets the uncompressed size of a file in the ZIP file * Returns the file size or 0 if the file is not found (or the file size is 0) */ static UINT32 zip_get_file_size(const char* file) { unz_file_info file_info; if( unzLocateFile(zip_file, file, 2) != UNZ_OK ) return 0; if( unzGetCurrentFileInfo(zip_file, &file_info, NULL, 0, NULL, 0, NULL, 0) != UNZ_OK ) return 0; return file_info.uncompressed_size; } /* zip_read_file * * Reads the specified file to a buffer * Returns TRUE if successful otherwise FALSE */ static BOOL zip_read_file(const char* file, UINT8* buffer, UINT32 size) { if( unzLocateFile(zip_file, file, 2) != UNZ_OK ) return FALSE; if( unzOpenCurrentFile(zip_file) != UNZ_OK ) return FALSE; if( unzReadCurrentFile(zip_file, buffer, size) < 0 ) { unzCloseCurrentFile(zip_file); return FALSE; } unzCloseCurrentFile(zip_file); return TRUE; } /* zip_find_name_for_crc * * Finds a matching file name for a crc * Returns TRUE if crc was found. The file name is copied to the supplied string pointer. * */ static BOOL zip_find_name_for_crc(UINT32 crc, char* file) { unz_file_info file_info; char filename[4096]; if( unzGoToFirstFile(zip_file) != UNZ_OK ) return FALSE; do { if( unzGetCurrentFileInfo(zip_file, &file_info, filename, sizeof(filename), NULL, 0, NULL, 0) != UNZ_OK ) return FALSE; if( file_info.crc == crc ) { strcpy( file, filename ); return TRUE; } } while( unzGoToNextFile(zip_file) == UNZ_OK ); return FALSE; } /* zip_open * * Opens a zip file. Must be called before any of the above functions ! */ static BOOL zip_open(const char* file) { zip_file = unzOpen(file); if( zip_file == NULL ) return FALSE; return TRUE; } /* zip_close * * Closes the zip file */ static void zip_close(void) { unzClose(zip_file); } /* File access functions */ static BOOL zip_directory = FALSE; static char directory_path[4096]; /* TODO: set_directory and set_directory_zip could be merged together */ /* set_directory * * Sets the current directory * */ BOOL set_directory(char* path, ...) { char string[4096]; va_list l; va_start(l, path); vsprintf(string, path, l); va_end(l); zip_directory = FALSE; strcpy( directory_path, string ); return TRUE; } /* set_directory_zip * * Sets a zip file as current directory * */ BOOL set_directory_zip(char* file, ...) { char string[4096]; va_list l; va_start(l, file); vsprintf(string, file, l); va_end(l); /* Close the old zip file */ zip_close(); if( !zip_open(string) ) return FALSE; zip_directory = TRUE; strcpy( directory_path, string ); return TRUE; } /* get_file_size * * Returns the file size * */ size_t get_file_size(const char* file) { FILE* f; size_t length = 0; char path[4096]; if( zip_directory ) { length = zip_get_file_size(file); } else { sprintf( path, "%s/%s", directory_path, file ); f = fopen( path, "rb" ); if( f == NULL ) return 0; fseek( f, 0, SEEK_END ); length = ftell(f); fclose(f); } return length; } /* read_file * * Reads the content of the file to a buffer * */ BOOL read_file(const char* file, UINT8* buffer, UINT32 size) { FILE* f; char path[4096]; if( zip_directory ) { return zip_read_file( file, buffer, size ); } else { /* Build a full path to file */ strcpy( path, directory_path ); strcat( path, "/" ); strcat( path, file ); f = fopen( path, "rb" ); if( f == NULL ) return FALSE; fseek( f, 0, SEEK_SET ); if( fread(buffer, sizeof(UINT8), size, f) != (size_t)size ) { fclose(f); return FALSE; } fclose(f); } return TRUE; } /* write_file * * Writes the contents of a buffer to a file * */ BOOL write_file(const char* file, UINT8* buffer, UINT32 size) { FILE* f; char path[4096]; /* Whoops. No saving to a zip file :) */ if( zip_directory ) return FALSE; /* Build a full path to file */ strcpy( path, directory_path ); strcat( path, "/" ); strcat( path, file ); f = fopen( path, "wb" ); fseek( f, 0, SEEK_SET ); if( fwrite(buffer, sizeof(UINT8), size, f) != (size_t)size ) { fclose(f); return FALSE; } fclose(f); return TRUE; } /* get_file_size_crc * * Returns the file size of a file specified by crc * */ size_t get_file_size_crc(UINT32 crc) { char file[4096]; /* only zip files supported */ if( !zip_directory ) return 0; if( !zip_find_name_for_crc(crc, file) ) return 0; return zip_get_file_size(file); } /* read_file_crc * * Reads the contents of a file specified by crc * */ BOOL read_file_crc(UINT32 crc, UINT8* buffer, UINT32 size) { char file[4096]; /* only zip files supported */ if( !zip_directory ) return FALSE; if( !zip_find_name_for_crc(crc, file) ) return FALSE; return zip_read_file(file, buffer, size); } /* open_file * * Opens a file * */ FILE* open_file(UINT32 flags, char* file, ...) { char string[4096]; char path[4096]; char mode[3]; char* m = mode; va_list l; /* zip files are not supported this way */ if( zip_directory ) return 0; va_start(l, file); vsprintf(string, file, l); va_end(l); /* Build full path */ if (strlen(directory_path) <= 0) { sprintf(path, "%s", string); } else { sprintf(path, "%s/%s", directory_path, string); } /* Set file access mode */ if( flags & FILE_READ ) sprintf(&m[0], "r"); else sprintf(&m[0], "w"); if( flags & FILE_BINARY ) sprintf(&m[1], "b" ); else sprintf(&m[1], "t" ); m[2] = '\0'; return fopen(path, m); } /* close_file * * Closes the file * */ void close_file(FILE* file) { fclose(file); } /* read_from_file * * Reads n bytes from file to a buffer * */ BOOL read_from_file(FILE* file, UINT8* buffer, UINT32 size) { if( file == NULL ) return FALSE; if( fread(buffer, sizeof(UINT8), size, file) != (size_t)size ) return FALSE; return TRUE; } /* write_to_file * * Writes n bytes to file * */ BOOL write_to_file(FILE* file, UINT8* buffer, UINT32 size) { if( file == NULL ) return FALSE; if( fwrite(buffer, sizeof(UINT8), size, file) != (size_t)size ) return FALSE; return TRUE; } /* get_file_size * * Gets the file size * */ size_t get_open_file_size(FILE *file) { size_t length; int current_pos = ftell(file); fseek(file, 0, SEEK_END); length = ftell(file); fseek(file, current_pos, SEEK_SET); return length; } /* * Load a file to a buffer. */ int load_file(char *path, UINT8 * dest, int size) { FILE * fp; int length; if(path == NULL || dest == NULL) return(-1); if((fp = fopen(path, "rb")) == NULL) return(-1); fseek(fp, 0, SEEK_END); length = ftell(fp); fseek(fp, 0, SEEK_SET); if (length <= 0) return -1; if (fread(dest, 1, size, fp) != (size_t)length) // file size mismatch return -1; return length; } static void word_swap(UINT8 *src, int size) { while (size -= 4) { *((UINT32 *) src) = BSWAP32(*((UINT32 *) src)); src += sizeof(UINT32); } } /* * Save a buffer to a file. */ void save_file(char *path, UINT8 *src, int size, BOOL byte_reversed) { FILE * fp; if (byte_reversed) { word_swap(src, size); } fp = fopen(path, "wb"); if(fp != NULL) { fwrite(src, 1, size, fp); fclose(fp); message(0, "Wrote %s", path); } else { message(0, "Failed to write %s", path); } if (byte_reversed) { word_swap(src, size); } }