/* 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 #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; }