#include <stdio.h>
#include <stdlib.h>

#define IDPAKHEADER		(('K'<<24)+('C'<<16)+('A'<<8)+'P')

typedef struct
{
	char	name[56];
	int		filepos, filelen;
} dpackfile_t;

typedef struct
{
	int		ident;		// == IDPAKHEADER
	int		dirofs;
	int		dirlen;
} dpackheader_t;

#define	MAX_FILES_IN_PACK	4096

#define BUFSIZE	4096
#ifndef MAX
#define MAX(a,b)	(((a)>(b))?(a):(b))
#define MIN(a,b)	(((a)<(b))?(a):(b))
#endif

dpackfile_t	*sel=0;
int selsize=0;
int numsel=0;

int ListOnly=0;

void addsel(dpackfile_t *dir)
{
	if (numsel >= selsize) {
		selsize = selsize ? (selsize * 2) : 256;
		sel = realloc(sel, sizeof(dpackfile_t) * selsize);
		if (!sel) {
			perror("realloc()");
			exit(-1);
		}
	}
	memcpy(&sel[numsel++], dir, sizeof(dpackfile_t));
}

void usage(char *progname)
{
	fprintf(stderr, "Usage: %s [-l] pak-file [file ..]\n",
		progname);
	exit(-1);
}

int unpackfiles(FILE *fp)
{
	FILE *fpout;
	char buf[BUFSIZE];
	int cnt, nr, r;

	for (cnt=0;cnt<numsel;cnt++) {
		/* To do: create directories */
		fpout=fopen(sel[cnt].name, "w");
		if (!fpout) {
			perror(sel[cnt].name);
			continue;
		}
		printf("%-54.54s\n", sel[cnt].name);

		fseek(fp, sel[cnt].filepos, SEEK_SET);
		for (r=0; r<sel[cnt].filelen; r+=nr) {
			nr = fread(buf, 1, MIN(BUFSIZE, (sel[cnt].filelen - r)), fp);
			if (nr < 0) {
				perror(sel[cnt].name);
				break;
			}
			if (nr < 1) {
				fprintf(stderr, "%s: premature end of file\n",
					sel[cnt].name);
				break;
			}
			if (fwrite(buf, 1, nr, fpout)< 1) {
				fprintf(stderr, "%s: write failed, aborting.\n",
					sel[cnt].name);
				fclose(fpout);
				return(-1);
			}
		}
		fclose(fpout);
	}
	return(0);
}

main(int argc, char *argv[])
{
	dpackheader_t hdr;
	dpackfile_t   dir;
	FILE	*fp;
	char	*progname;
	int	cnt, num, nr;
	int	ac;

	progname=argv[0];
	while ((argc>1) && (argv[1][0]=='-')) {
		if (argv[1][1]=='l')
			ListOnly=1;
		else
			usage(progname);

		argc--; argv++;
	}

	if (argc<2)
		usage(progname);

	fp = fopen(argv[1], "r");
	if (!fp) {
		perror(argv[1]);
		exit(-1);
	}

	fread(&hdr, sizeof(hdr), 1, fp);
	fseek(fp, hdr.dirofs, SEEK_SET);
	num = hdr.dirlen / sizeof(dir);
	for (cnt=0; (cnt<num) && (fread(&dir, sizeof(dir), 1, fp)>0); cnt++) {
		for (ac=2; ac<argc; ac++) {
			/* should be replaced with regex */
			if (strstr(dir.name, argv[ac]))
				break;
		}
		if ((argc<3) || (ac<argc)) {
			if (ListOnly)
				printf("%-54.54s\t%d\n", dir.name, dir.filelen);
			else
				addsel(&dir);
		}
	}

	unpackfiles(fp);
	
	fclose(fp);
}
