/*  Copyright (C) 1996-1997  Id Software, Inc.

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

    See file, 'COPYING', for details.
*/

// wad2lib.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>

// #include <sys/file.h>
#include <stdarg.h>

#ifdef NeXT
  #include <libc.h>
#endif
#include "cmdlib.h"
#include "wadlib.h"

/*
============================================================================

                                                        WAD READING

============================================================================
*/

lumpinfo_t *lumpinfo; // location of each lump on disk
int numlumps;

wadinfo_t	header;
FILE		*wadhandle;

/*
====================
W_OpenWad
====================
*/
void
W_OpenWad( char *filename ) {
	lumpinfo_t	*lump_p;
	unsigned	i;
	int length;

	//
	// open the file and add to directory
	//
	wadhandle = SafeOpenRead( filename );
	SafeRead( wadhandle, &header, sizeof( header ));

	if( strncmp( header.identification, "WAD2", 4 ))
		Error( "Wad file %s doesn't have WAD2 id\n", filename );

	header.numlumps = LittleLong( header.numlumps );
	header.infotableofs = LittleLong( header.infotableofs );

	numlumps = header.numlumps;

	length = numlumps * sizeof( lumpinfo_t );
	lumpinfo = malloc( length );
	lump_p = lumpinfo;

	fseek( wadhandle, header.infotableofs, SEEK_SET );
	SafeRead( wadhandle, lumpinfo, length );

	//
	// Fill in lumpinfo
	//

	for( i = 0; i < numlumps; i++, lump_p++ ) {
		lump_p->filepos = LittleLong( lump_p->filepos );
		lump_p->size = LittleLong( lump_p->size );
	}
}

void
CleanupName( char *in, char *out ) {
	int i;

	for( i = 0; i < sizeof(((lumpinfo_t *) 0 )->name ); i++ ) {
		if( !in[ i ] )
			break;

		out[ i ] = toupper( in[ i ] );
	}

	for(; i < sizeof(((lumpinfo_t *) 0 )->name ); i++ )
		out[ i ] = 0;
}

/*
====================
W_CheckNumForName

Returns -1 if name not found
====================
*/
int
W_CheckNumForName( char *name ) {
	char	cleanname[ 16 ];
	int	v1, v2, v3, v4;
	int	i;
	lumpinfo_t *lump_p;

	CleanupName( name, cleanname );

	// make the name into four integers for easy compares

	v1 = *(int *) cleanname;
	v2 = *(int *) &cleanname[ 4 ];
	v3 = *(int *) &cleanname[ 8 ];
	v4 = *(int *) &cleanname[ 12 ];

	// find it

	lump_p = lumpinfo;
	for( i = 0; i < numlumps; i++, lump_p++ ) {
		if( *(int *) lump_p->name == v1
		    && *(int *) &lump_p->name[ 4 ] == v2
		    && *(int *) &lump_p->name[ 8 ] == v3
		    && *(int *) &lump_p->name[ 12 ] == v4 )
			return i;
	}

	return -1;
}

/*
====================
W_GetNumForName

Calls W_CheckNumForName, but bombs out if not found
====================
*/
int
W_GetNumForName( char *name ) {
	int i;

	i = W_CheckNumForName( name );
	if( i != -1 )
		return i;

	Error( "W_GetNumForName: %s not found!", name );
	return -1;
}

/*
====================
W_LumpLength

Returns the buffer size needed to load the given lump
====================
*/
int
W_LumpLength( int lump ) {
	if( lump >= numlumps )
		Error( "W_LumpLength: %i >= numlumps", lump );
	return lumpinfo[ lump ].size;
}

/*
====================
W_ReadLumpNum

Loads the lump into the given buffer, which must be >= W_LumpLength()
====================
*/
void
W_ReadLumpNum( int lump, void *dest ) {
	lumpinfo_t *l;

	if( lump >= numlumps )
		Error( "W_ReadLump: %i >= numlumps", lump );
	l = lumpinfo + lump;

	fseek( wadhandle, l->filepos, SEEK_SET );
	SafeRead( wadhandle, dest, l->size );
}

/*
====================
W_LoadLumpNum
====================
*/
void *
W_LoadLumpNum( int lump ) {
	void *buf;

	if((unsigned) lump >= numlumps )
		Error( "W_CacheLumpNum: %i >= numlumps", lump );

	buf = malloc( W_LumpLength( lump ));
	W_ReadLumpNum( lump, buf );

	return buf;
}

/*
====================
W_LoadLumpName
====================
*/
void *
W_LoadLumpName( char *name ) {
	return W_LoadLumpNum( W_GetNumForName( name ));
}

/*
===============================================================================

                                                WAD CREATION

===============================================================================
*/

FILE *outwad;

lumpinfo_t outinfo[ 4096 ];
int outlumps;

short	(*wadshort) ( short l );
int	(*wadlong) ( int l );

/*
===============
NewWad
===============
*/

void
NewWad( char *pathname, qboolean bigendien ) {
	outwad = SafeOpenWrite( pathname );
	fseek( outwad, sizeof( wadinfo_t ), SEEK_SET );
	memset( outinfo, 0, sizeof( outinfo ));

	if( bigendien ) {
		wadshort = BigShort;
		wadlong = BigLong;
	}
	else {
		wadshort = LittleShort;
		wadlong = LittleLong;
	}

	outlumps = 0;
}

/*
===============
AddLump
===============
*/

void
AddLump( char *name, void *buffer, int length, int type, int compress ) {
	lumpinfo_t *info;
	int ofs;

	info = &outinfo[ outlumps ];
	outlumps++;

	memset( info, 0, sizeof( info ));

	strcpy( info->name, name );
	strupr( info->name );

	ofs = ftell( outwad );
	info->filepos = wadlong( ofs );
	info->size = info->disksize = wadlong( length );
	info->type = type;
	info->compression = compress;

	// FIXME: do compression

	SafeWrite( outwad, buffer, length );
}

/*
===============
WriteWad
===============
*/

void
WriteWad( void ) {
	wadinfo_t header;
	int ofs;

	// write the lumpingo
	ofs = ftell( outwad );

	SafeWrite( outwad, outinfo, outlumps * sizeof( lumpinfo_t ));

	// write the header

	// a program will be able to tell the ednieness of a wad by the id
	header.identification[ 0 ] = 'W';
	header.identification[ 1 ] = 'A';
	header.identification[ 2 ] = 'D';
	header.identification[ 3 ] = '2';

	header.numlumps = wadlong( outlumps );
	header.infotableofs = wadlong( ofs );

	fseek( outwad, 0, SEEK_SET );
	SafeWrite( outwad, &header, sizeof( header ));
	fclose( outwad );
}

