//read DFDATAS/data.df from ICO
//needs -I/source/to/libarc/ and libarc/libarc.a
//wildly untested

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "libarc/mblock.h"
#include "zip.h"
typedef unsigned char ubyte;

static ubyte *print_str(int filenum, ubyte *p, ubyte *name, int maxlen)
{
	int i=0;
	
	do {name[i++] = *p;} while (*p++); // read null then stop
	
	printf("%d. df name: %s\n",filenum+1, name);
	p += maxlen - i;
	
	return p;
}

static ubyte *print_bytes_hex(ubyte *p, int n)
{
	ubyte buf[n];
	int i=0;
	
	memcpy(buf, p, n);
	
	printf("bytes: ");
	for (i = 0; i < n; i++)
		printf("%0.2X ", buf[i]);
	
	printf("\n");
	
	p += n;
	return p;
}

static ubyte *read_int(ubyte *p, unsigned int *i)
{
	*i = p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
	return p+4;
}

typedef struct ih_context {ubyte *buf; size_t size, used;} ih_context;

static long inflate_callback(char *into, long requested, void *v)
{
	ih_context *c = v;
	size_t to_read = requested;
	
	if (c->size == c->used) return 0;
	if ((c->used + requested) > c->size) to_read = c->size - c->used;
	
	memcpy(into, c->buf + c->used, to_read);
	
	c->used += to_read;
	
	return to_read;
}

static void extract_file(FILE *df, ubyte *name, off_t off, size_t size)
{
	ubyte *buf = malloc(size);
	FILE *out = fopen((char*)name, "wb");
	fseek(df, off, SEEK_SET);
	
	if (fread(buf, 1, size, df) != size) {
		printf("read error!\n");
		exit(1);
	}
	
	if (buf[0] == 0xec) {
		printf("trying to decompress...\n");
		ubyte *dbuf = malloc(size);
		long dec_s;
		ih_context c = (ih_context){buf, size, 0};
		
		InflateHandler ih;
		
		ih = open_inflate_handler(inflate_callback, &c);
		
		do {
			dec_s = zip_inflate(ih, (char*)dbuf, size);
			if (dec_s > 0) fwrite(dbuf, 1, dec_s, out);
		} while (dec_s > 0);
		
		close_inflate_handler(ih);
		
		free(dbuf);
		
		fclose(out);
		
		
	} else {
		fwrite(buf, 1, size, out);
		
		fclose(out);
	}
	
	free(buf);
}

static void read_directory(unsigned nfiles, FILE *df)
{
	ubyte dir[0x2000 - 4];
	ubyte *p = dir;
	int i;
	
	fread(dir, 1, 0x2000 - 4, df);
		
	for (i=0; i < nfiles; i++) {
		ubyte name[32];
		unsigned int off, size;
		p = print_str(i, p, name, 32);
		p = read_int(p, &off);
		p = read_int(p, &size);
		printf("offset: %#x, size: %#x\n", off, size);
		extract_file(df, name, off, size);
	}
}

int main(int argc, char *argv[])
{
	if (argc < 2) {
		printf("give DATA.DF as first argument\n");
		return 1;
	}
	
	FILE *df = fopen(argv[1], "rb");
	
	ubyte header[4];
	unsigned nfiles;
	
	fread(header, 1, 4, df);
	read_int(header, &nfiles);
	printf("%d files\n", nfiles);
	
	read_directory(nfiles, df);
	
	return 0;
}
