mirror of
https://github.com/Oibaf66/uae-wii.git
synced 2024-11-15 07:15:09 +01:00
766 lines
16 KiB
C
766 lines
16 KiB
C
|
/*
|
||
|
* UAE - The Un*x Amiga Emulator
|
||
|
*
|
||
|
* routines to handle compressed file automatically
|
||
|
*
|
||
|
* (c) 1996 Samuel Devulder, Tim Gunn
|
||
|
* 2002-2004 Toni Wilen
|
||
|
*/
|
||
|
|
||
|
#include "sysconfig.h"
|
||
|
#include "sysdeps.h"
|
||
|
|
||
|
#include "options.h"
|
||
|
#include "zfile.h"
|
||
|
#include "unzip.h"
|
||
|
#include "disk.h"
|
||
|
#include "dms/cdata.h"
|
||
|
#include "dms/pfile.h"
|
||
|
#include "gui.h"
|
||
|
#include "crc32.h"
|
||
|
|
||
|
#include <zlib.h>
|
||
|
|
||
|
struct zfile {
|
||
|
char *name;
|
||
|
char *zipname;
|
||
|
FILE *f;
|
||
|
uae_u8 *data;
|
||
|
int size;
|
||
|
int seek;
|
||
|
int deleteafterclose;
|
||
|
struct zfile *next;
|
||
|
};
|
||
|
|
||
|
static struct zfile *zlist = 0;
|
||
|
int is_zlib;
|
||
|
|
||
|
static int zlib_test (void)
|
||
|
{
|
||
|
#if defined WIN32 && !defined __MINGW32__
|
||
|
static int zlibmsg;
|
||
|
if (is_zlib)
|
||
|
return 1;
|
||
|
if (zlibmsg)
|
||
|
return 0;
|
||
|
zlibmsg = 1;
|
||
|
gui_message("zip and gzip support disabled because zlib1.dll is missing");
|
||
|
return 0;
|
||
|
#else
|
||
|
/* On non-Windows platforms, we can safely assume (I think) that if we got this
|
||
|
* far zlib is present - Rich */
|
||
|
return 1;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
static struct zfile *zfile_create (void)
|
||
|
{
|
||
|
struct zfile *z;
|
||
|
|
||
|
z = malloc (sizeof *z);
|
||
|
if (!z)
|
||
|
return 0;
|
||
|
memset (z, 0, sizeof *z);
|
||
|
z->next = zlist;
|
||
|
zlist = z;
|
||
|
return z;
|
||
|
}
|
||
|
|
||
|
static void zfile_free (struct zfile *f)
|
||
|
{
|
||
|
if (f->f)
|
||
|
fclose (f->f);
|
||
|
if (f->deleteafterclose) {
|
||
|
unlink (f->name);
|
||
|
write_log ("deleted temporary file '%s'\n", f->name);
|
||
|
}
|
||
|
free (f->name);
|
||
|
free (f->data);
|
||
|
free (f);
|
||
|
}
|
||
|
|
||
|
void zfile_exit (void)
|
||
|
{
|
||
|
struct zfile *l;
|
||
|
while ((l = zlist)) {
|
||
|
zlist = l->next;
|
||
|
zfile_free (l);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void zfile_fclose (struct zfile *f)
|
||
|
{
|
||
|
struct zfile *pl = NULL;
|
||
|
struct zfile *l = zlist;
|
||
|
struct zfile *nxt = NULL;
|
||
|
|
||
|
if (!f)
|
||
|
return;
|
||
|
while (l != f) {
|
||
|
if (l == 0) {
|
||
|
write_log ("zfile: tried to free already freed filehandle!\n");
|
||
|
return;
|
||
|
}
|
||
|
pl = l;
|
||
|
l = l->next;
|
||
|
}
|
||
|
if (l) nxt = l->next;
|
||
|
zfile_free (f);
|
||
|
if (l == 0)
|
||
|
return;
|
||
|
if(!pl)
|
||
|
zlist = nxt;
|
||
|
else
|
||
|
pl->next = nxt;
|
||
|
}
|
||
|
|
||
|
static uae_u8 exeheader[]={0x00,0x00,0x03,0xf3,0x00,0x00,0x00,0x00};
|
||
|
int zfile_gettype (struct zfile *z)
|
||
|
{
|
||
|
uae_u8 buf[8];
|
||
|
char *ext;
|
||
|
|
||
|
if (!z)
|
||
|
return ZFILE_UNKNOWN;
|
||
|
ext = strrchr (z->name, '.');
|
||
|
if (ext != NULL) {
|
||
|
ext++;
|
||
|
if (strcasecmp (ext, "adf") == 0)
|
||
|
return ZFILE_DISKIMAGE;
|
||
|
if (strcasecmp (ext, "adz") == 0)
|
||
|
return ZFILE_DISKIMAGE;
|
||
|
if (strcasecmp (ext, "roz") == 0)
|
||
|
return ZFILE_ROM;
|
||
|
if (strcasecmp (ext, "ipf") == 0)
|
||
|
return ZFILE_DISKIMAGE;
|
||
|
if (strcasecmp (ext, "fdi") == 0)
|
||
|
return ZFILE_DISKIMAGE;
|
||
|
if (strcasecmp (ext, "uss") == 0)
|
||
|
return ZFILE_STATEFILE;
|
||
|
if (strcasecmp (ext, "dms") == 0)
|
||
|
return ZFILE_DISKIMAGE;
|
||
|
if (strcasecmp (ext, "rom") == 0)
|
||
|
return ZFILE_ROM;
|
||
|
if (strcasecmp (ext, "key") == 0)
|
||
|
return ZFILE_KEY;
|
||
|
if (strcasecmp (ext, "nvr") == 0)
|
||
|
return ZFILE_NVR;
|
||
|
if (strcasecmp (ext, "uae") == 0)
|
||
|
return ZFILE_CONFIGURATION;
|
||
|
}
|
||
|
memset (buf, 0, sizeof (buf));
|
||
|
zfile_fread (buf, 8, 1, z);
|
||
|
zfile_fseek (z, -8, SEEK_CUR);
|
||
|
if (!memcmp (buf, exeheader, sizeof(buf)))
|
||
|
return ZFILE_DISKIMAGE;
|
||
|
return ZFILE_UNKNOWN;
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
#define TMP_PREFIX "uae_"
|
||
|
|
||
|
static struct zfile *createinputfile (struct zfile *z)
|
||
|
{
|
||
|
FILE *f;
|
||
|
struct zfile *z2;
|
||
|
char *name;
|
||
|
|
||
|
z2 = zfile_create ();
|
||
|
if (!z->data) {
|
||
|
z2->name = strdup (z->name);
|
||
|
return z2;
|
||
|
}
|
||
|
name = tempnam (0, TMP_PREFIX);
|
||
|
f = fopen (name, "wb");
|
||
|
if (!f) return 0;
|
||
|
write_log ("created temporary file '%s'\n", name);
|
||
|
fwrite (z->data, z->size, 1, f);
|
||
|
fclose (f);
|
||
|
z2->name = name;
|
||
|
z2->deleteafterclose = 1;
|
||
|
return z2;
|
||
|
}
|
||
|
|
||
|
static struct zfile *createoutputfile (struct zfile *z)
|
||
|
{
|
||
|
struct zfile *z2;
|
||
|
char *name;
|
||
|
|
||
|
name = tempnam (0, TMP_PREFIX);
|
||
|
z2 = zfile_create ();
|
||
|
z2->name = name;
|
||
|
z2->deleteafterclose = 1;
|
||
|
write_log ("allocated temporary file name '%s'\n", name);
|
||
|
return z2;
|
||
|
}
|
||
|
|
||
|
/* we want to delete temporary files as early as possible */
|
||
|
static struct zfile *updateoutputfile (struct zfile *z)
|
||
|
{
|
||
|
struct zfile *z2 = 0;
|
||
|
int size;
|
||
|
FILE *f = fopen (z->name, "rb");
|
||
|
for (;;) {
|
||
|
if (!f)
|
||
|
break;
|
||
|
fseek (f, 0, SEEK_END);
|
||
|
size = ftell (f);
|
||
|
fseek (f, 0, SEEK_SET);
|
||
|
if (!size)
|
||
|
break;
|
||
|
z2 = zfile_fopen_empty (z->name, size);
|
||
|
if (!z2)
|
||
|
break;
|
||
|
fread (z2->data, size, 1, f);
|
||
|
fclose (f);
|
||
|
zfile_fclose (z);
|
||
|
return z2;
|
||
|
}
|
||
|
if (f)
|
||
|
fclose (f);
|
||
|
zfile_fclose (z);
|
||
|
zfile_fclose (z2);
|
||
|
return 0;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static struct zfile *zuncompress (struct zfile *z);
|
||
|
|
||
|
static struct zfile *gunzip (struct zfile *z)
|
||
|
{
|
||
|
uae_u8 header[2 + 1 + 1 + 4 + 1 + 1];
|
||
|
z_stream zs;
|
||
|
int i, size, ret, first;
|
||
|
uae_u8 flags;
|
||
|
long offset;
|
||
|
char name[MAX_DPATH];
|
||
|
uae_u8 buffer[8192];
|
||
|
struct zfile *z2;
|
||
|
uae_u8 b;
|
||
|
|
||
|
if (!zlib_test ())
|
||
|
return z;
|
||
|
strcpy (name, z->name);
|
||
|
memset (&zs, 0, sizeof (zs));
|
||
|
memset (header, 0, sizeof (header));
|
||
|
zfile_fread (header, sizeof (header), 1, z);
|
||
|
flags = header[3];
|
||
|
if (header[0] != 0x1f && header[1] != 0x8b)
|
||
|
return z;
|
||
|
if (flags & 2) /* multipart not supported */
|
||
|
return z;
|
||
|
if (flags & 32) /* encryption not supported */
|
||
|
return z;
|
||
|
if (flags & 4) { /* skip extra field */
|
||
|
zfile_fread (&b, 1, 1, z);
|
||
|
size = b;
|
||
|
zfile_fread (&b, 1, 1, z);
|
||
|
size |= b << 8;
|
||
|
zfile_fseek (z, size + 2, SEEK_CUR);
|
||
|
}
|
||
|
if (flags & 8) { /* get original file name */
|
||
|
i = 0;
|
||
|
do {
|
||
|
zfile_fread (name + i, 1, 1, z);
|
||
|
} while (name[i++]);
|
||
|
}
|
||
|
if (flags & 16) { /* skip comment */
|
||
|
i = 0;
|
||
|
do {
|
||
|
zfile_fread (&b, 1, 1, z);
|
||
|
} while (b);
|
||
|
}
|
||
|
offset = zfile_ftell (z);
|
||
|
zfile_fseek (z, -4, SEEK_END);
|
||
|
zfile_fread (&b, 1, 1, z);
|
||
|
size = b;
|
||
|
zfile_fread (&b, 1, 1, z);
|
||
|
size |= b << 8;
|
||
|
zfile_fread (&b, 1, 1, z);
|
||
|
size |= b << 16;
|
||
|
zfile_fread (&b, 1, 1, z);
|
||
|
size |= b << 24;
|
||
|
if (size < 8 || size > 10000000) /* safety check */
|
||
|
return z;
|
||
|
zfile_fseek (z, offset, SEEK_SET);
|
||
|
z2 = zfile_fopen_empty (name, size);
|
||
|
if (!z2)
|
||
|
return z;
|
||
|
zs.next_out = z2->data;
|
||
|
zs.avail_out = size;
|
||
|
first = 1;
|
||
|
do {
|
||
|
zs.next_in = buffer;
|
||
|
zs.avail_in = sizeof (buffer);
|
||
|
zfile_fread (buffer, sizeof (buffer), 1, z);
|
||
|
if (first) {
|
||
|
if (inflateInit2 (&zs, -MAX_WBITS) != Z_OK)
|
||
|
break;
|
||
|
first = 0;
|
||
|
}
|
||
|
ret = inflate (&zs, 0);
|
||
|
} while (ret == Z_OK);
|
||
|
inflateEnd (&zs);
|
||
|
if (ret != Z_STREAM_END || first != 0) {
|
||
|
zfile_fclose (z2);
|
||
|
return z;
|
||
|
}
|
||
|
zfile_fclose (z);
|
||
|
return z2;
|
||
|
}
|
||
|
|
||
|
|
||
|
static struct zfile *bunzip (const char *decompress, struct zfile *z)
|
||
|
{
|
||
|
return z;
|
||
|
}
|
||
|
|
||
|
static struct zfile *lha (struct zfile *z)
|
||
|
{
|
||
|
return z;
|
||
|
}
|
||
|
|
||
|
static struct zfile *dms (struct zfile *z)
|
||
|
{
|
||
|
int ret;
|
||
|
struct zfile *zo;
|
||
|
|
||
|
zo = zfile_fopen_empty ("zipped.dms", 1760 * 512);
|
||
|
if (!zo) return z;
|
||
|
ret = DMS_Process_File (z, zo, CMD_UNPACK, OPT_VERBOSE, 0, 0);
|
||
|
if (ret == NO_PROBLEM || ret == DMS_FILE_END) {
|
||
|
zfile_fclose (z);
|
||
|
return zo;
|
||
|
}
|
||
|
return z;
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
static struct zfile *dms (struct zfile *z)
|
||
|
{
|
||
|
char cmd[2048];
|
||
|
struct zfile *zi = createinputfile (z);
|
||
|
struct zfile *zo = createoutputfile (z);
|
||
|
if (zi && zo) {
|
||
|
sprintf(cmd, "xdms -q u \"%s\" +\"%s\"", zi->name, zo->name);
|
||
|
execute_command (cmd);
|
||
|
}
|
||
|
zfile_fclose (zi);
|
||
|
zfile_fclose (z);
|
||
|
return updateoutputfile (zo);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static const char *ignoreextensions[] =
|
||
|
{ ".gif", ".jpg", ".png", ".xml", ".pdf", ".txt", 0 };
|
||
|
static const char *diskimageextensions[] =
|
||
|
{ ".adf", ".adz", ".ipf", ".fdi", 0 };
|
||
|
|
||
|
static int isdiskimage (char *name)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
i = 0;
|
||
|
while (diskimageextensions[i]) {
|
||
|
if (strlen (name) > 3 && !strcasecmp (name + strlen (name) - 4, diskimageextensions[i]))
|
||
|
return 1;
|
||
|
i++;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static struct zfile *unzip (struct zfile *z)
|
||
|
{
|
||
|
unzFile uz;
|
||
|
unz_file_info file_info;
|
||
|
char filename_inzip[2048];
|
||
|
struct zfile *zf;
|
||
|
unsigned int err, zipcnt, i, we_have_file = 0;
|
||
|
int select;
|
||
|
char tmphist[MAX_DPATH];
|
||
|
int first = 1;
|
||
|
|
||
|
if (!zlib_test ())
|
||
|
return z;
|
||
|
zf = 0;
|
||
|
uz = unzOpen (z);
|
||
|
if (!uz)
|
||
|
return z;
|
||
|
if (unzGoToFirstFile (uz) != UNZ_OK)
|
||
|
return z;
|
||
|
zipcnt = 1;
|
||
|
tmphist[0] = 0;
|
||
|
for (;;) {
|
||
|
err = unzGetCurrentFileInfo(uz,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0);
|
||
|
if (err != UNZ_OK)
|
||
|
return z;
|
||
|
if (file_info.uncompressed_size > 0) {
|
||
|
i = 0;
|
||
|
while (ignoreextensions[i]) {
|
||
|
if (strlen(filename_inzip) > strlen (ignoreextensions[i]) &&
|
||
|
!strcasecmp (ignoreextensions[i], filename_inzip + strlen (filename_inzip) - strlen (ignoreextensions[i])))
|
||
|
break;
|
||
|
i++;
|
||
|
}
|
||
|
if (!ignoreextensions[i]) {
|
||
|
if (tmphist[0]) {
|
||
|
DISK_history_add (tmphist, -1);
|
||
|
tmphist[0] = 0;
|
||
|
first = 0;
|
||
|
}
|
||
|
if (first) {
|
||
|
if (isdiskimage (filename_inzip))
|
||
|
sprintf (tmphist,"%s/%s", z->name, filename_inzip);
|
||
|
} else {
|
||
|
sprintf (tmphist,"%s/%s", z->name, filename_inzip);
|
||
|
DISK_history_add (tmphist, -1);
|
||
|
tmphist[0] = 0;
|
||
|
}
|
||
|
select = 0;
|
||
|
if (!z->zipname)
|
||
|
select = 1;
|
||
|
if (z->zipname && !strcasecmp (z->zipname, filename_inzip))
|
||
|
select = -1;
|
||
|
if (z->zipname && z->zipname[0] == '#' && atol (z->zipname + 1) == (int)zipcnt)
|
||
|
select = -1;
|
||
|
if (select && !we_have_file) {
|
||
|
unsigned int err = unzOpenCurrentFile (uz);
|
||
|
if (err == UNZ_OK) {
|
||
|
zf = zfile_fopen_empty (filename_inzip, file_info.uncompressed_size);
|
||
|
if (zf) {
|
||
|
err = unzReadCurrentFile (uz, zf->data, file_info.uncompressed_size);
|
||
|
unzCloseCurrentFile (uz);
|
||
|
if (err == 0 || err == file_info.uncompressed_size) {
|
||
|
zf = zuncompress (zf);
|
||
|
if (select < 0 || zfile_gettype (zf)) {
|
||
|
we_have_file = 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (!we_have_file) {
|
||
|
zfile_fclose (zf);
|
||
|
zf = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
zipcnt++;
|
||
|
err = unzGoToNextFile (uz);
|
||
|
if (err != UNZ_OK)
|
||
|
break;
|
||
|
}
|
||
|
if (zf) {
|
||
|
zfile_fclose (z);
|
||
|
z = zf;
|
||
|
}
|
||
|
return z;
|
||
|
}
|
||
|
|
||
|
static struct zfile *zuncompress (struct zfile *z)
|
||
|
{
|
||
|
char *name = z->name;
|
||
|
char *ext = strrchr (name, '.');
|
||
|
uae_u8 header[4];
|
||
|
|
||
|
if (ext != NULL) {
|
||
|
ext++;
|
||
|
if (strcasecmp (ext, "zip") == 0 && zlib_test ())
|
||
|
return unzip (z);
|
||
|
if (strcasecmp (ext, "gz") == 0)
|
||
|
return gunzip (z);
|
||
|
if (strcasecmp (ext, "adz") == 0)
|
||
|
return gunzip (z);
|
||
|
if (strcasecmp (ext, "roz") == 0)
|
||
|
return gunzip (z);
|
||
|
if (strcasecmp (ext, "dms") == 0)
|
||
|
return dms (z);
|
||
|
if (strcasecmp (ext, "lha") == 0
|
||
|
|| strcasecmp (ext, "lzh") == 0)
|
||
|
return lha (z);
|
||
|
memset (header, 0, sizeof (header));
|
||
|
zfile_fseek (z, 0, SEEK_SET);
|
||
|
zfile_fread (header, sizeof (header), 1, z);
|
||
|
zfile_fseek (z, 0, SEEK_SET);
|
||
|
if (header[0] == 0x1f && header[1] == 0x8b)
|
||
|
return gunzip (z);
|
||
|
if (header[0] == 'P' && header[1] == 'K')
|
||
|
return unzip (z);
|
||
|
if (header[0] == 'D' && header[1] == 'M' && header[2] == 'S' && header[3] == '!')
|
||
|
return dms (z);
|
||
|
}
|
||
|
return z;
|
||
|
}
|
||
|
|
||
|
static FILE *openzip (char *name, char *zippath)
|
||
|
{
|
||
|
int i;
|
||
|
char v;
|
||
|
|
||
|
i = strlen (name) - 2;
|
||
|
if (zippath)
|
||
|
zippath[0] = 0;
|
||
|
while (i > 0) {
|
||
|
if ((name[i] == '/' || name[i] == '\\') && i > 4) {
|
||
|
v = name[i];
|
||
|
name[i] = 0;
|
||
|
if (!strcasecmp (name + i - 4, ".zip")) {
|
||
|
FILE *f = fopen (name, "rb");
|
||
|
if (f) {
|
||
|
if (zippath)
|
||
|
strcpy (zippath, name + i + 1);
|
||
|
return f;
|
||
|
}
|
||
|
}
|
||
|
name[i] = v;
|
||
|
}
|
||
|
i--;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#ifdef SINGLEFILE
|
||
|
extern uae_u8 singlefile_data[];
|
||
|
|
||
|
static struct zfile *zfile_opensinglefile (struct zfile *l)
|
||
|
{
|
||
|
uae_u8 *p = singlefile_data;
|
||
|
int size, offset;
|
||
|
char tmp[256], *s;
|
||
|
|
||
|
strcpy (tmp, l->name);
|
||
|
s = tmp + strlen (tmp) - 1;
|
||
|
while (*s != 0 && *s != '/' && *s != '\\') s--;
|
||
|
if (s > tmp)
|
||
|
s++;
|
||
|
write_log("loading from singlefile: '%s'\n", tmp);
|
||
|
while (*p++);
|
||
|
offset = (p[0] << 24)|(p[1] << 16)|(p[2] << 8)|(p[3] << 0);
|
||
|
p += 4;
|
||
|
for (;;) {
|
||
|
size = (p[0] << 24)|(p[1] << 16)|(p[2] << 8)|(p[3] << 0);
|
||
|
if (!size)
|
||
|
break;
|
||
|
if (!strcmpi (tmp, p + 4)) {
|
||
|
l->data = singlefile_data + offset;
|
||
|
l->size = size;
|
||
|
write_log ("found, size %d\n", size);
|
||
|
return l;
|
||
|
}
|
||
|
offset += size;
|
||
|
p += 4;
|
||
|
p += strlen (p) + 1;
|
||
|
}
|
||
|
write_log ("not found\n");
|
||
|
return 0;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
* fopen() for a compressed file
|
||
|
*/
|
||
|
struct zfile *zfile_fopen (const char *name, const char *mode)
|
||
|
{
|
||
|
struct zfile *l;
|
||
|
FILE *f;
|
||
|
char zipname[1000];
|
||
|
|
||
|
if( *name == '\0' )
|
||
|
return NULL;
|
||
|
l = zfile_create ();
|
||
|
l->name = strdup (name);
|
||
|
#ifdef SINGLEFILE
|
||
|
if (zfile_opensinglefile (l))
|
||
|
return l;
|
||
|
#endif
|
||
|
f = openzip (l->name, zipname);
|
||
|
if (f) {
|
||
|
if (strcasecmp (mode, "rb")) {
|
||
|
zfile_fclose (l);
|
||
|
fclose (f);
|
||
|
return 0;
|
||
|
}
|
||
|
l->zipname = strdup (zipname);
|
||
|
}
|
||
|
if (!f) {
|
||
|
f = fopen (name, mode);
|
||
|
if (!f) {
|
||
|
zfile_fclose (l);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
l->f = f;
|
||
|
l = zuncompress (l);
|
||
|
return l;
|
||
|
}
|
||
|
|
||
|
int zfile_exists (const char *name)
|
||
|
{
|
||
|
char fname[2000];
|
||
|
FILE *f;
|
||
|
|
||
|
strcpy (fname, name);
|
||
|
f = openzip (fname, 0);
|
||
|
if (!f)
|
||
|
f = fopen(name,"rb");
|
||
|
if (!f)
|
||
|
return 0;
|
||
|
fclose (f);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int zfile_iscompressed (struct zfile *z)
|
||
|
{
|
||
|
return z->data ? 1 : 0;
|
||
|
}
|
||
|
|
||
|
struct zfile *zfile_fopen_empty (const char *name, int size)
|
||
|
{
|
||
|
struct zfile *l;
|
||
|
l = zfile_create ();
|
||
|
l->name = strdup (name);
|
||
|
l->data = malloc (size);
|
||
|
l->size = size;
|
||
|
memset (l->data, 0, size);
|
||
|
return l;
|
||
|
}
|
||
|
|
||
|
long zfile_ftell (struct zfile *z)
|
||
|
{
|
||
|
if (z->data)
|
||
|
return z->seek;
|
||
|
return ftell (z->f);
|
||
|
}
|
||
|
|
||
|
int zfile_fseek (struct zfile *z, long offset, int mode)
|
||
|
{
|
||
|
if (z->data) {
|
||
|
int old = z->seek;
|
||
|
switch (mode) {
|
||
|
case SEEK_SET:
|
||
|
z->seek = offset;
|
||
|
break;
|
||
|
case SEEK_CUR:
|
||
|
z->seek += offset;
|
||
|
break;
|
||
|
case SEEK_END:
|
||
|
z->seek = z->size - offset;
|
||
|
break;
|
||
|
}
|
||
|
if (z->seek < 0) z->seek = 0;
|
||
|
if (z->seek > z->size) z->seek = z->size;
|
||
|
return old;
|
||
|
}
|
||
|
return fseek (z->f, offset, mode);
|
||
|
}
|
||
|
|
||
|
size_t zfile_fread (void *b, size_t l1, size_t l2, struct zfile *z)
|
||
|
{
|
||
|
long len = l1 * l2;
|
||
|
if (z->data) {
|
||
|
if (z->seek + len > z->size)
|
||
|
len = z->size - z->seek;
|
||
|
memcpy (b, z->data + z->seek, len);
|
||
|
z->seek += len;
|
||
|
return len;
|
||
|
}
|
||
|
return fread (b, l1, l2, z->f);
|
||
|
}
|
||
|
|
||
|
size_t zfile_fwrite (const void *b, size_t l1, size_t l2, struct zfile *z)
|
||
|
{
|
||
|
long len = l1 * l2;
|
||
|
if (z->data) {
|
||
|
if (z->seek + len > z->size)
|
||
|
len = z->size - z->seek;
|
||
|
memcpy (z->data + z->seek, b, len);
|
||
|
z->seek += len;
|
||
|
return len;
|
||
|
}
|
||
|
return fwrite (b, l1, l2, z->f);
|
||
|
}
|
||
|
|
||
|
int zfile_zuncompress (void *dst, int dstsize, struct zfile *src, int srcsize)
|
||
|
{
|
||
|
z_stream zs;
|
||
|
int v;
|
||
|
uae_u8 inbuf[4096];
|
||
|
int incnt;
|
||
|
|
||
|
if (!zlib_test ())
|
||
|
return 0;
|
||
|
memset (&zs, 0, sizeof(zs));
|
||
|
if (inflateInit (&zs) != Z_OK)
|
||
|
return 0;
|
||
|
zs.next_out = dst;
|
||
|
zs.avail_out = dstsize;
|
||
|
incnt = 0;
|
||
|
v = Z_OK;
|
||
|
while (v == Z_OK && zs.avail_out > 0) {
|
||
|
if (zs.avail_in == 0) {
|
||
|
int left = srcsize - incnt;
|
||
|
if (left == 0)
|
||
|
break;
|
||
|
if (left > (int)sizeof (inbuf)) left = sizeof (inbuf);
|
||
|
zs.next_in = inbuf;
|
||
|
zs.avail_in = zfile_fread (inbuf, 1, left, src);
|
||
|
incnt += left;
|
||
|
}
|
||
|
v = inflate (&zs, 0);
|
||
|
}
|
||
|
inflateEnd (&zs);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int zfile_zcompress (struct zfile *f, void *src, int size)
|
||
|
{
|
||
|
int v;
|
||
|
z_stream zs;
|
||
|
uae_u8 outbuf[4096];
|
||
|
|
||
|
#ifdef WIN32
|
||
|
if (!is_zlib)
|
||
|
return 0;
|
||
|
#endif
|
||
|
memset (&zs, 0, sizeof (zs));
|
||
|
if (deflateInit (&zs, Z_DEFAULT_COMPRESSION) != Z_OK)
|
||
|
return 0;
|
||
|
zs.next_in = src;
|
||
|
zs.avail_in = size;
|
||
|
v = Z_OK;
|
||
|
while (v == Z_OK) {
|
||
|
zs.next_out = outbuf;
|
||
|
zs.avail_out = sizeof (outbuf);
|
||
|
v = deflate(&zs, Z_NO_FLUSH | Z_FINISH);
|
||
|
if (sizeof(outbuf) - zs.avail_out > 0)
|
||
|
zfile_fwrite (outbuf, 1, sizeof (outbuf) - zs.avail_out, f);
|
||
|
}
|
||
|
deflateEnd (&zs);
|
||
|
return zs.total_out;
|
||
|
}
|
||
|
|
||
|
uae_u32 zfile_crc32 (struct zfile *f)
|
||
|
{
|
||
|
uae_u8 *p;
|
||
|
int pos, size;
|
||
|
uae_u32 crc;
|
||
|
|
||
|
if (!f)
|
||
|
return 0;
|
||
|
if (f->data)
|
||
|
return get_crc32 (f->data, f->size);
|
||
|
pos = zfile_ftell (f);
|
||
|
zfile_fseek (f, 0, SEEK_END);
|
||
|
size = zfile_ftell (f);
|
||
|
p = xmalloc (size);
|
||
|
if (!p)
|
||
|
return 0;
|
||
|
memset (p, 0, size);
|
||
|
zfile_fseek (f, 0, SEEK_SET);
|
||
|
zfile_fread (p, 1, size, f);
|
||
|
zfile_fseek (f, pos, SEEK_SET);
|
||
|
crc = get_crc32 (p, size);
|
||
|
free (p);
|
||
|
return crc;
|
||
|
}
|