/**************************************************************************** * Genesis Plus 1.2a * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Nintendo Gamecube Zip Support * * Only partial support is included, in that only the first file within the archive * is considered to be a Genesis ROM image. ***************************************************************************/ #include #include #include "shared.h" #include "dvd.h" #include "font.h" #include "diskio.h" #include "vfat.h" extern VFATFS fs; extern FSDIRENTRY f; extern u8 UseSDCARD; /* * PKWare Zip Header - adopted into zip standard */ #define PKZIPID 0x504b0304 #define MAXROM 0x500000 #define ZIPCHUNK 2048 /* * Zip file header definition */ typedef struct { unsigned int zipid __attribute__ ((__packed__)); // 0x04034b50 unsigned short zipversion __attribute__ ((__packed__)); unsigned short zipflags __attribute__ ((__packed__)); unsigned short compressionMethod __attribute__ ((__packed__)); unsigned short lastmodtime __attribute__ ((__packed__)); unsigned short lastmoddate __attribute__ ((__packed__)); unsigned int crc32 __attribute__ ((__packed__)); unsigned int compressedSize __attribute__ ((__packed__)); unsigned int uncompressedSize __attribute__ ((__packed__)); unsigned short filenameLength __attribute__ ((__packed__)); unsigned short extraDataLength __attribute__ ((__packed__)); } PKZIPHEADER; /* * Zip files are stored little endian * Support functions for short and int types */ static inline u32 FLIP32 (u32 b) { unsigned int c; c = (b & 0xff000000) >> 24; c |= (b & 0xff0000) >> 8; c |= (b & 0xff00) << 8; c |= (b & 0xff) << 24; return c; } static inline u16 FLIP16 (u16 b) { u16 c; c = (b & 0xff00) >> 8; c |= (b & 0xff) << 8; return c; } /**************************************************************************** * IsZipFile * * Returns TRUE when PKZIPID is first four characters of buffer ****************************************************************************/ int IsZipFile (char *buffer) { unsigned int *check; check = (unsigned int *) buffer; if (check[0] == PKZIPID) return 1; return 0; } /***************************************************************************** * UnZipBuffer * * It should be noted that there is a limit of 5MB total size for any ROM ******************************************************************************/ int UnZipBuffer (unsigned char *outbuffer, u64 discoffset, int length) { PKZIPHEADER pkzip; int zipoffset = 0; int zipchunk = 0; char out[ZIPCHUNK]; z_stream zs; int res; int bufferoffset = 0; int have = 0; char readbuffer[2048]; char msg[128]; /*** Read Zip Header ***/ if ( UseSDCARD ) { VFAT_fseek(&f, 0, SEEK_SET); VFAT_fread(&f, readbuffer, 2048); } else dvd_read (&readbuffer, 2048, discoffset); /*** Copy PKZip header to local, used as info ***/ memcpy (&pkzip, &readbuffer, sizeof (PKZIPHEADER)); sprintf (msg, "Unzipping %d bytes ... Wait", FLIP32 (pkzip.uncompressedSize)); ShowAction (msg); /*** Prepare the zip stream ***/ memset (&zs, 0, sizeof (z_stream)); zs.zalloc = Z_NULL; zs.zfree = Z_NULL; zs.opaque = Z_NULL; zs.avail_in = 0; zs.next_in = Z_NULL; res = inflateInit2 (&zs, -MAX_WBITS); if (res != Z_OK) return 0; /*** Set ZipChunk for first pass ***/ zipoffset = (sizeof (PKZIPHEADER) + FLIP16 (pkzip.filenameLength) + FLIP16 (pkzip.extraDataLength)); zipchunk = ZIPCHUNK - zipoffset; /*** Now do it! ***/ do { zs.avail_in = zipchunk; zs.next_in = (Bytef *) & readbuffer[zipoffset]; /*** Now inflate until input buffer is exhausted ***/ do { zs.avail_out = ZIPCHUNK; zs.next_out = (Bytef *) & out; res = inflate (&zs, Z_NO_FLUSH); if (res == Z_MEM_ERROR) { inflateEnd (&zs); return 0; } have = ZIPCHUNK - zs.avail_out; if (have) { /*** Copy to normal block buffer ***/ memcpy (&outbuffer[bufferoffset], &out, have); bufferoffset += have; } } while (zs.avail_out == 0); /*** Readup the next 2k block ***/ zipoffset = 0; zipchunk = ZIPCHUNK; discoffset += 2048; if (UseSDCARD) VFAT_fread(&f, readbuffer, 2048); else dvd_read (&readbuffer, 2048, discoffset); } while (res != Z_STREAM_END); inflateEnd (&zs); if ( UseSDCARD ) VFAT_fclose(&f); if (res == Z_STREAM_END) { if (FLIP32 (pkzip.uncompressedSize) == (u32) bufferoffset) return bufferoffset; else return FLIP32 (pkzip.uncompressedSize); } return 0; }