#include "RPK.h"

#include <SDL_stdinc.h>

#include <zlib.h>

#include "ExMath.h"
#include "Log.h"
#include "System.h"

RPKFile *RPK_OpenFile(const char *path)
{
	RPKFile *file;

	file = SDL_malloc(sizeof(RPKFile));

	file->data = OS_MapFile(path);
	if (file->data == NULL)
	{
		Msg_Fatal("Unable to open RPAK file '%s'.", path);
		SDL_free(file);
		return NULL;
	}

	file->header = (RPK_Header *)file->data;

	/* Ensure that the file has a valid header */
	if (SDL_memcmp(file->header->header, "RPAK", 4) != 0)
	{
		Msg_Fatal("'%s' does not appear to be a valid RPAK file.", path);
		SDL_free(file);
		return NULL;
	}

	if (file->header->version != RPK_FILE_VERSION)
	{
		Msg_Error("Expected RPAK version %d for '%s' but got %d instead.", RPK_FILE_VERSION, path, file->header->version);
		SDL_free(file);
		return NULL;
	}

	file->entries = (RPK_TOCEntry *)((char*)file->data + sizeof(RPK_Header));

	return file;
}

void RPK_CloseFile(RPKFile *file)
{
	OS_UnmapFile(file->data);
	SDL_free(file);
}

int RPK_GetIndexForName(const RPKFile *rpak, const char *name)
{
	int i;
	for (i = 0; i < rpak->header->numentries; i++)
	{
		if (SDL_strncmp(rpak->entries[i].name, name, RPK_NAME_LENGTH) == 0)
			return i;
	}
	return -1;
}

size_t RPK_GetEntryData(const RPKFile *rpak, const char *name, void **dataOut)
{
	RPK_TOCEntry *entry;
	int index;

	/* Initialize to NULL for now in case of errors later. */
	*dataOut = NULL;

	index = RPK_GetIndexForName(rpak, name);
	if (index == -1)
	{
		Msg_Error("Unable to find RPAK entry with name '%s'\n", name);
		return 0;
	}

	entry = &rpak->entries[index];
	if (rpak->header->flags & RPK_FLAG_COMPRESSED)
	{
		uLongf destLen = entry->origSize;
		Bytef *src = (Bytef*)rpak->data + entry->offset;
		Bytef *dst = SDL_malloc(entry->origSize);

		if (uncompress(dst, &destLen, src, entry->size) != Z_OK)
		{
			Msg_Error("Failed to decompress RPAK data of '%s'", name);
			SDL_free(dst);
			return 0;
		}

		*dataOut = dst;
		return entry->origSize;
	}
	else
	{
		*dataOut = SDL_malloc(entry->size);
		SDL_memcpy(*dataOut, (char*)rpak->data + entry->offset, entry->size);
		return entry->size;
	}
}
