/*
    Unmass - unpacker for game archives.
    Copyright (C) 2002-2007  Mirex

    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
*/

#include <malloc.h>

#include "ma.h"
#include "utools.h"

CMassArchive::CMassArchive()
{ 
	massf = NULL; pFileList = NULL; FileListSize = 0;
	files_count = 0; FileRec.set = 0; 
	next_set = false; next_rec_num = 0;
}

//default extract for plain data
//return: bytes read
unsigned long CMassArchive::Extract( unsigned long offset, unsigned long size, unsigned char *output )
{
	if ( massf == NULL )
		return 0;

	if ( offset + size > FileRec.size ) {
		SetErrorStr( "Out of file" );
		return 0;
	}

	//no compression
	if ( fseek( massf, FileRec.offset + offset, SEEK_SET ) != 0 ) {
		SetErrorStr( "Error seeking" );
		return 0;
	}
	
	return fread( output, 1, size, massf );
}

int	CMassArchive::ExtractWholeFile( FILE *fout )
{
/*
	pos = 0; size = FF8bufferSize;
	while ( pos < FileRec.size ) {

		if ( pos + size > FileRec.size )
			size = FileRec.size - pos;
		
		if ( fread( buf, 1, size, fs ) != size )
			return 0;

		if ( fwrite( buf, 1, size, fout ) != size )
			return 0;

		pos += size;
	}*/
	return 0;
}

int CMassArchive::OpenFile( const char *filename )
{
	if ( massf != NULL ) 
		fclose( massf );

	massf = fopen( filename, "rb" );

	files_count = 0; FileRec.set = 0;
	FileListItems = 0;
	next_set = false; next_rec_num = 0;

	strncpy( MassFileNameFull, filename, FileNameWithPathMaxLen - 1 );
	// MassFileNameFull[ FileNameWithPathMaxLen-1 ] = 0;

	int		i, j;

	//find last slash
	i = strlen( MassFileNameFull );
	while (( i > 0 ) && ( MassFileNameFull[ i ] != '\\' ) &&
			( MassFileNameFull[ i ] != '/' ))
		i--;
	if ( i != 0 )
		i++;
	
	// get path from result
	strncpy( MassFilePath, MassFileNameFull, FileNameWithPathMaxLen-1 );
	MassFilePath[ i ] = 0;

	// find out filename and extension from the rest
	strncpy( MassFileName, &MassFileNameFull[ i ], FileNameWithPathMaxLen-1 );
	
	i = strlen( MassFileName );
	while (( i > 0 ) && ( MassFileName[ i ] != '.' ))
		i--;

	if (( i == 0 ) && ( MassFileName[ i ] != '.' ))
		MassFileExt[ 0 ] = 0;
	else
		strncpy( MassFileExt, &MassFileName[ i + 1 ], FileNameWithPathMaxLen-1 );
	MassFileName[ i ] = 0;

	UnmassTools::_strlwr( MassFileName );
	UnmassTools::_strlwr( MassFileExt );

	file_open_for_write = false;

	return ( massf != NULL ) ? 1 : 0;
}

void CMassArchive::CloseFile()
{
	if ( massf != NULL ) 
		fclose( massf ); 
	massf = NULL; 

	if ( pFileList != NULL )
		free( pFileList );
	pFileList = NULL;

	FileListSize = 0;
	files_count = 0;
}

int CMassArchive::ReadRecords( void )
{
	if ( massf == NULL ) {
		SetErrorStr( "File not opened" );
		return 0;
	}

	if ( FileListItems >= files_count ) {
		SetErrorStr( "Already filled" );
		return 0;
	}

	int		res;

	if ( FileListItems == 0 ) {
	
		if ( GrowFileList() == 0 )
			return 0;

		res = ReadRec( 0 );
	}
	else
		res = ReadRec( -1 );

	if ( res == 1 ) {
		FileRec.index = FileListItems;
		pFileList[ FileListItems ] = FileRec;
	} else
		pFileList[ FileListItems ].Reset();

	FileListItems++;

	return res;

}

int CMassArchive::GetRec( long num )
{
	if (( num < 0 ) || ( num >= files_count )) {
		SetErrorStr( "Bad index" );
		return 0;
	}

	FileRec = pFileList[ num ];
	return 1;
}

int	CMassArchive::AddFileData( unsigned long offset, unsigned long size, char* data )
{
	SetErrorStr( "AddFileData:" );

	if ( ! file_open_for_write ) {
		SetErrorStr( "Not open for writing" );
		return 0;
	}

	if (( FileRec.index < 0 ) || ( FileRec.index >= files_count )) {
		SetErrorStr( "Bad index" );
		return 0;
	}

	s_FileRec	*pFR;

	pFR = &pFileList[ FileRec.index ];

	if ( offset + size > pFR->size ) {
		SetErrorStr( "Data out of file" );
		return 0;
	}

	fseek( massf, pFR->offset + offset, SEEK_SET );
	fwrite( data, size, 1, massf );

	return 1;
}

int	CMassArchive::GrowFileList( void )
{
	s_FileRec		*pNewList;
	unsigned long	ul, oldlistsize;

	if ( files_count <= FileListSize )
		return 1;

	oldlistsize = FileListSize;
	if ( FileListSize == 0 )
		FileListSize = 4;
	
	while ( FileListSize < files_count )
		FileListSize *= 2;

	ul = sizeof( FileRec ) * FileListSize;
	pNewList = (s_FileRec*) realloc( pFileList, ul );
	if ( pNewList == NULL ) {
		SetErrorStr( "Not enough memory for new list" );
		FileListSize = oldlistsize;
		return 0;
	}
	pFileList = pNewList;

	return 1;
}

int CMassArchive::ReopenForWriting( void )
{
	SetErrorStr( "ReopenForWriting:" );

	if ( massf == NULL ) {
		SetErrorStr( "File not opened yet" );
		return 0;
	}

	if ( file_open_for_write )
		return 1;

	fclose( massf );

	massf = fopen( MassFileNameFull, "r+b" );

	if ( massf == NULL ) {
		SetErrorStr( "File could not be opened. It might be read-only." );

		massf = fopen( MassFileNameFull, "rb" );
		if ( massf == NULL )
			SetErrorStr( "Could not open file, neither for reading" );
		return 0;
	}

	file_open_for_write = true;

	return 1;
}

