2001-01-11 00:56:31 +00:00
|
|
|
#include <limits.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
2002-03-12 23:45:36 +00:00
|
|
|
#include <QF/qendian.h>
|
2001-01-11 00:56:31 +00:00
|
|
|
|
2002-03-12 23:45:36 +00:00
|
|
|
#include "pakfile.h"
|
2001-01-11 00:56:31 +00:00
|
|
|
|
2002-03-12 23:45:36 +00:00
|
|
|
static const char *
|
|
|
|
pack_get_key (void *p, void *unused)
|
|
|
|
{
|
|
|
|
return ((dpackfile_t *) p)->name;
|
|
|
|
}
|
2001-01-11 00:56:31 +00:00
|
|
|
|
|
|
|
pack_t *
|
2002-03-12 23:45:36 +00:00
|
|
|
pack_new (const char *name)
|
2001-01-11 00:56:31 +00:00
|
|
|
{
|
|
|
|
pack_t *pack = calloc (sizeof (*pack), 1);
|
|
|
|
|
|
|
|
if (!pack)
|
|
|
|
return 0;
|
2002-03-12 23:45:36 +00:00
|
|
|
pack->filename = strdup (name);
|
|
|
|
if (!pack->filename) {
|
|
|
|
free (pack);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
pack->file_hash = Hash_NewTable (1021, pack_get_key, 0, 0);
|
|
|
|
if (!pack->file_hash) {
|
|
|
|
free (pack->filename);
|
|
|
|
free (pack);
|
|
|
|
return 0;
|
|
|
|
}
|
2001-01-11 00:56:31 +00:00
|
|
|
return pack;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2002-03-12 23:45:36 +00:00
|
|
|
pack_del (pack_t *pack)
|
2001-01-11 00:56:31 +00:00
|
|
|
{
|
|
|
|
if (pack->files)
|
|
|
|
free (pack->files);
|
|
|
|
if (pack->handle)
|
|
|
|
fclose (pack->handle);
|
2002-03-12 23:45:36 +00:00
|
|
|
if (pack->filename)
|
|
|
|
free (pack->filename);
|
|
|
|
if (pack->file_hash)
|
|
|
|
free (pack->file_hash);
|
2001-01-11 00:56:31 +00:00
|
|
|
free (pack);
|
|
|
|
}
|
|
|
|
|
|
|
|
pack_t *
|
2002-03-12 23:45:36 +00:00
|
|
|
pack_open (const char *name)
|
2001-01-11 00:56:31 +00:00
|
|
|
{
|
2002-03-12 23:45:36 +00:00
|
|
|
pack_t *pack = pack_new (name);
|
|
|
|
int i;
|
2001-01-11 00:56:31 +00:00
|
|
|
|
|
|
|
if (!pack)
|
|
|
|
return 0;
|
|
|
|
pack->handle = fopen (name, "rb");
|
|
|
|
if (!pack->handle) {
|
|
|
|
goto error;
|
|
|
|
}
|
2002-03-18 18:03:26 +00:00
|
|
|
if (fread (&pack->header, 1, sizeof (pack->header), pack->handle)
|
|
|
|
!= sizeof (pack->header)) {
|
2001-01-11 00:56:31 +00:00
|
|
|
fprintf (stderr, "%s: not a pack file", name);
|
|
|
|
goto error;
|
|
|
|
}
|
2002-03-18 18:03:26 +00:00
|
|
|
if (strncmp (pack->header.id, "PACK", 4)) {
|
2001-01-11 00:56:31 +00:00
|
|
|
fprintf (stderr, "%s: not a pack file", name);
|
|
|
|
goto error;
|
|
|
|
}
|
2002-03-12 23:45:36 +00:00
|
|
|
|
2002-03-18 18:03:26 +00:00
|
|
|
pack->header.dirofs = LittleLong (pack->header.dirofs);
|
|
|
|
pack->header.dirlen = LittleLong (pack->header.dirlen);
|
2002-03-12 23:45:36 +00:00
|
|
|
|
2002-03-18 18:03:26 +00:00
|
|
|
pack->numfiles = pack->header.dirlen / sizeof (dpackfile_t);
|
|
|
|
pack->old_numfiles = pack->files_size = pack->numfiles;
|
2001-01-11 00:56:31 +00:00
|
|
|
if (pack->numfiles > MAX_FILES_IN_PACK) {
|
|
|
|
fprintf (stderr, "%s: too many files in pack: %d", name, pack->numfiles);
|
|
|
|
goto error;
|
|
|
|
}
|
2002-03-12 23:45:36 +00:00
|
|
|
pack->files = malloc (pack->files_size * sizeof (dpackfile_t));
|
2001-01-18 00:59:42 +00:00
|
|
|
if (!pack->files) {
|
2001-01-17 22:47:08 +00:00
|
|
|
fprintf (stderr, "out of memory\n");
|
|
|
|
goto error;
|
|
|
|
}
|
2002-03-18 18:03:26 +00:00
|
|
|
fseek (pack->handle, pack->header.dirofs, SEEK_SET);
|
2001-01-17 22:47:08 +00:00
|
|
|
fread (pack->files, pack->numfiles, sizeof (pack->files[0]), pack->handle);
|
2002-03-12 23:45:36 +00:00
|
|
|
|
|
|
|
for (i = 0; i < pack->numfiles; i++) {
|
|
|
|
pack->files[i].filepos = LittleLong (pack->files[i].filepos);
|
|
|
|
pack->files[i].filelen = LittleLong (pack->files[i].filelen);
|
|
|
|
Hash_Add (pack->file_hash, &pack->files[i]);
|
|
|
|
}
|
|
|
|
return pack;
|
2001-01-11 00:56:31 +00:00
|
|
|
error:
|
2002-03-12 23:45:36 +00:00
|
|
|
pack_del (pack);
|
2001-01-11 00:56:31 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2002-03-12 23:45:36 +00:00
|
|
|
|
2002-03-18 18:03:26 +00:00
|
|
|
pack_t *
|
|
|
|
pack_create (const char *name)
|
|
|
|
{
|
|
|
|
pack_t *pack = pack_new (name);
|
|
|
|
|
|
|
|
if (!pack)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
pack->handle = fopen (name, "wb");
|
|
|
|
if (!pack->handle) {
|
|
|
|
pack_del (pack);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
strncpy (pack->header.id, "PACK", sizeof (pack->header.id));
|
|
|
|
|
|
|
|
fwrite (&pack->header, 1, sizeof (pack->header), pack->handle);
|
|
|
|
|
|
|
|
return pack;
|
|
|
|
}
|
|
|
|
|
2002-03-12 23:45:36 +00:00
|
|
|
void
|
|
|
|
pack_close (pack_t *pack)
|
|
|
|
{
|
2002-03-18 18:03:26 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if (pack->modified) {
|
|
|
|
if (pack->numfiles > pack->old_numfiles) {
|
|
|
|
fseek (pack->handle, 0, SEEK_END);
|
|
|
|
pack->header.dirofs = ftell (pack->handle);
|
|
|
|
}
|
|
|
|
for (i = 0; i < pack->numfiles; i++) {
|
|
|
|
pack->files[i].filepos = LittleLong (pack->files[i].filepos);
|
|
|
|
pack->files[i].filelen = LittleLong (pack->files[i].filelen);
|
|
|
|
}
|
|
|
|
fseek (pack->handle, pack->header.dirofs, SEEK_SET);
|
|
|
|
fwrite (pack->files, pack->numfiles,
|
|
|
|
sizeof (pack->files[0]), pack->handle);
|
|
|
|
pack->header.dirlen = pack->numfiles * sizeof (pack->files[0]);
|
|
|
|
pack->header.dirofs = LittleLong (pack->header.dirofs);
|
|
|
|
pack->header.dirlen = LittleLong (pack->numfiles
|
|
|
|
* sizeof (pack->files[0]));
|
|
|
|
fseek (pack->handle, 0, SEEK_SET);
|
|
|
|
fwrite (&pack->header, 1, sizeof (pack->header), pack->handle);
|
|
|
|
|
|
|
|
fseek (pack->handle, 0, SEEK_END);
|
|
|
|
}
|
2002-03-12 23:45:36 +00:00
|
|
|
pack_del (pack);
|
|
|
|
}
|
2002-03-18 18:03:26 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
pack_add (pack_t *pack, const char *filename)
|
|
|
|
{
|
|
|
|
dpackfile_t *pf;
|
|
|
|
FILE *file;
|
|
|
|
char buffer[16384];
|
|
|
|
int bytes;
|
|
|
|
|
|
|
|
pf = Hash_Find (pack->file_hash, filename);
|
|
|
|
if (pf)
|
|
|
|
return -1;
|
|
|
|
if (pack->numfiles == pack->files_size) {
|
|
|
|
dpackfile_t *f;
|
|
|
|
|
|
|
|
if (pack->files_size == MAX_FILES_IN_PACK)
|
|
|
|
return -1;
|
|
|
|
pack->files_size += 64;
|
|
|
|
if (pack->files_size > MAX_FILES_IN_PACK)
|
|
|
|
pack->files_size = MAX_FILES_IN_PACK;
|
|
|
|
|
|
|
|
f = realloc (pack->files, pack->files_size * sizeof (dpackfile_t));
|
|
|
|
if (!f)
|
|
|
|
return -1;
|
|
|
|
pack->files = f;
|
|
|
|
}
|
|
|
|
|
|
|
|
file = fopen (filename, "rb");
|
|
|
|
if (!file)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
pack->modified = 1;
|
|
|
|
|
|
|
|
pf = &pack->files[pack->numfiles++];
|
|
|
|
|
|
|
|
strncpy (pf->name, filename, sizeof (pf->name));
|
|
|
|
pf->name[sizeof (pf->name) - 1] = 0;
|
|
|
|
|
|
|
|
fseek (pack->handle, 0, SEEK_END);
|
|
|
|
pf->filepos = ftell (pack->handle);
|
|
|
|
pf->filelen = 0;
|
|
|
|
while ((bytes = fread (buffer, 1, sizeof (buffer), file))) {
|
|
|
|
fwrite (buffer, 1, bytes, pack->handle);
|
|
|
|
pf->filelen += bytes;
|
|
|
|
}
|
|
|
|
if (pf->filelen & 3) {
|
|
|
|
static char buf[4];
|
|
|
|
fwrite (buf, 1, 4 - (pf->filelen & 3), pack->handle);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|