snes9xgx/source/ngc/unzip.cpp

225 lines
4.3 KiB
C++
Raw Normal View History

/****************************************************************************
2008-08-07 07:19:17 +02:00
* Snes9x 1.50
*
* Nintendo Gamecube Unzip - borrowed from the GPP
*
* softdev July 2006
****************************************************************************/
#include <gccore.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <zlib.h>
#include "dvd.h"
#include "video.h"
2008-08-07 07:19:17 +02:00
#include "menudraw.h"
#include "unzip.h"
/*
* PKWare Zip Header - adopted into zip standard
*/
#define PKZIPID 0x504b0304
#define MAXROM 0x500000
#define ZIPCHUNK 2048
/*
* Zip files are stored little endian
* Support functions for short and int types
*/
u32
FLIP32 (u32 b)
{
2008-08-12 05:25:16 +02:00
unsigned int c;
2008-08-12 05:25:16 +02:00
c = (b & 0xff000000) >> 24;
c |= (b & 0xff0000) >> 8;
c |= (b & 0xff00) << 8;
c |= (b & 0xff) << 24;
2008-08-12 05:25:16 +02:00
return c;
}
u16
FLIP16 (u16 b)
{
2008-08-12 05:25:16 +02:00
u16 c;
2008-08-12 05:25:16 +02:00
c = (b & 0xff00) >> 8;
c |= (b & 0xff) << 8;
2008-08-12 05:25:16 +02:00
return c;
}
/****************************************************************************
* IsZipFile
*
* Returns TRUE when PKZIPID is first four characters of buffer
****************************************************************************/
int
IsZipFile (char *buffer)
{
2008-08-12 05:25:16 +02:00
unsigned int *check;
2008-08-12 05:25:16 +02:00
check = (unsigned int *) buffer;
2008-08-12 05:25:16 +02:00
if (check[0] == PKZIPID)
return 1;
2008-08-12 05:25:16 +02:00
return 0;
}
/*****************************************************************************
* unzip
*
* It should be noted that there is a limit of 5MB total size for any ROM
******************************************************************************/
FILE* fatfile; // FAT
u64 discoffset; // DVD
SMBFILE smbfile; // SMB
2008-08-12 05:25:16 +02:00
int
UnZipBuffer (unsigned char *outbuffer, short where)
{
2008-08-12 05:25:16 +02:00
PKZIPHEADER pkzip;
int zipoffset = 0;
int zipchunk = 0;
char out[ZIPCHUNK];
z_stream zs;
int res;
int bufferoffset = 0;
int readoffset = 0;
2008-08-12 05:25:16 +02:00
int have = 0;
2008-08-14 00:44:59 +02:00
char readbuffer[ZIPCHUNK];
2008-08-12 05:25:16 +02:00
char msg[128];
/*** Read Zip Header ***/
2008-08-12 05:25:16 +02:00
switch (where)
{
case 0: // SD Card
fseek(fatfile, 0, SEEK_SET);
fread (readbuffer, 1, ZIPCHUNK, fatfile);
2008-08-12 05:25:16 +02:00
break;
case 1: // DVD
dvd_read (readbuffer, ZIPCHUNK, discoffset);
2008-08-12 05:25:16 +02:00
break;
case 2: // From SMB
SMB_ReadFile(readbuffer, ZIPCHUNK, 0, smbfile);
2008-08-12 05:25:16 +02:00
break;
}
/*** Copy PKZip header to local, used as info ***/
2008-08-12 05:25:16 +02:00
memcpy (&pkzip, readbuffer, sizeof (PKZIPHEADER));
2008-08-12 05:25:16 +02:00
pkzip.uncompressedSize = FLIP32 (pkzip.uncompressedSize);
2008-08-07 07:19:17 +02:00
2008-08-12 05:25:16 +02:00
sprintf (msg, "Unzipping %d bytes ... Wait",
pkzip.uncompressedSize);
ShowAction (msg);
/*** Prepare the zip stream ***/
2008-08-12 05:25:16 +02:00
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);
2008-08-12 05:25:16 +02:00
if (res != Z_OK)
return 0;
/*** Set ZipChunk for first pass ***/
2008-08-12 05:25:16 +02:00
zipoffset =
(sizeof (PKZIPHEADER) + FLIP16 (pkzip.filenameLength) +
FLIP16 (pkzip.extraDataLength));
zipchunk = ZIPCHUNK - zipoffset;
/*** Now do it! ***/
2008-08-12 05:25:16 +02:00
do
{
2008-08-12 05:25:16 +02:00
zs.avail_in = zipchunk;
zs.next_in = (Bytef *) & readbuffer[zipoffset];
2008-08-12 05:25:16 +02:00
/*** 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)
{
2008-08-14 00:44:59 +02:00
inflateEnd (&zs);
return 0;
2008-08-12 05:25:16 +02:00
}
have = ZIPCHUNK - zs.avail_out;
if (have)
{
2008-08-14 00:44:59 +02:00
/*** Copy to normal block buffer ***/
memcpy (&outbuffer[bufferoffset], &out, have);
bufferoffset += have;
2008-08-12 05:25:16 +02:00
}
}
while (zs.avail_out == 0);
/*** Readup the next 2k block ***/
2008-08-12 05:25:16 +02:00
zipoffset = 0;
zipchunk = ZIPCHUNK;
switch (where)
{
case 0: // SD Card
fread (readbuffer, 1, ZIPCHUNK, fatfile);
2008-08-12 05:25:16 +02:00
break;
case 1: // DVD
readoffset += ZIPCHUNK;
dvd_read (readbuffer, ZIPCHUNK, discoffset+readoffset);
2008-08-12 05:25:16 +02:00
break;
case 2: // From SMB
readoffset += ZIPCHUNK;
SMB_ReadFile(readbuffer, ZIPCHUNK, readoffset, smbfile);
2008-08-12 05:25:16 +02:00
break;
}
}
while (res != Z_STREAM_END);
2008-08-12 05:25:16 +02:00
inflateEnd (&zs);
2008-08-12 05:25:16 +02:00
if (res == Z_STREAM_END)
{
if (pkzip.uncompressedSize == (u32) bufferoffset)
return bufferoffset;
else
return pkzip.uncompressedSize;
}
2008-08-12 05:25:16 +02:00
return 0;
}
// Reading from FAT
int
UnZipFile (unsigned char *outbuffer, FILE* infile)
{
fatfile = infile;
return UnZipBuffer(outbuffer, 0);
}
// Reading from DVD
int
UnZipFile (unsigned char *outbuffer, u64 inoffset)
{
discoffset = inoffset;
return UnZipBuffer(outbuffer, 1);
}
// Reading from SMB
int
UnZipFile (unsigned char *outbuffer, SMBFILE infile)
{
smbfile = infile;
return UnZipBuffer(outbuffer, 2);
}