#include "ma_ff8.h" char *CMassFF8::GetIdent( void ) { static char Ident[] = "FI(Final Fantasy 8)"; return Ident; } char *CMassFF8::GetExtension( void ) { static char Ext[] = "fi"; return Ext; } int CMassFF8::CheckFileType( void ) { FILE *f; char str[ FileNameWithPathMaxLen ]; if ( massf == NULL ) return 0; fseek( massf, 0, SEEK_END ); if ( ftell( massf ) % SizeOfFiRec != 0 ) return 0; sprintf( str, "%s%s", MassFilePath, MassFileName ); //check .fs strcpy( fsName, str ); strcat( fsName, ".fs" ); f = fopen( fsName, "rb" ); if ( f == NULL ) return 0; fclose( f ); //check .fl strcpy( flName, str ); strcat( flName, ".fl" ); fl = fopen( flName, "rb" ); if ( fl == NULL ) return 0; fclose( fl ); return 1; } void CMassFF8::GetFileMainInfo( void ) { files_count = 0; if ( massf == NULL ) return; fseek( massf, 0, SEEK_END ); filesize = ftell( massf ); files_count = filesize / SizeOfFiRec; } int CMassFF8::ReadRec( long num ) { if ( massf == NULL ) return 0; if (( (unsigned long)num >= files_count ) && ( num != -1 )) return 0; if (( num == -1 ) && (( ! next_set ) || ((unsigned long)next_rec_num >= files_count )) ) return 0; memset( &FileRec, 0, sizeof( FileRec ) ); fl = fopen( flName, "rb" ); if ( fl == NULL ) return 0; //seek if ( num == -1 ) { if ( fseek( massf, next_rec_pos, SEEK_SET ) != 0 ) { fclose( fl ); return 0; } if ( fseek( fl, next_name_rec_pos, SEEK_SET ) != 0 ) { fclose( fl ); return 0; } pos = next_rec_num; num = next_rec_num; } else { if ( fseek( massf, SizeOfFiRec * num, SEEK_SET ) != 0 ) { fclose( fl ); return 0; } pos = 0; } int i; char c, str[ FileNameWithPathMaxLen ]; //read if ( fread( &fiRec, SizeOfFiRec, 1, massf ) != 1 ) { fclose( fl ); return 0; } //read name from .fl do { i = 0; do { fread( &c, 1, 1, fl ); str[ i++ ] = c; } while ( c != 0xA ); pos++; } while ( pos <= (unsigned long)num ); str[ i-2 ] = 0; //set position of the next next_rec_pos = ftell( massf ); next_name_rec_pos = ftell( fl ); fclose( fl ); if ( num == -1 ) next_rec_num ++; else next_rec_num = num + 1; if ( num + 1 >= (long)files_count ) next_set = false; else next_set = true; //get info FileRec.SetName( &str[7] ); FileRec.offset = fiRec.offset; FileRec.size = fiRec.size; FileRec.flag = fiRec.packed; // if ( fiRec.packed == 1 ) // strcat( FileRec.name, "#" ); return 1; } /* void CMassFF8::SaveNextPos( void ) { save.next_rec_num = next_rec_num; save.next_rec_pos = next_rec_pos; save.next_set = next_set; save.next_name_rec_pos = next_name_rec_pos; } void CMassFF8::LoadNextPos( void ) { next_rec_num = save.next_rec_num; next_rec_pos = save.next_rec_pos; next_set = save.next_set; next_name_rec_pos = save.next_name_rec_pos; } */ unsigned long CMassFF8::Extract( unsigned long offset, unsigned long size, unsigned char *output ) { return 0; /* FILE *fs; unsigned long insize; unsigned long start, end, ctrlpos; unsigned long pos, outpos, i, ofs, sz, src; unsigned char control, ch, ctrlcnt, cha[2], okctrlpos, okoutsize, s; if (( offset != 0 ) && ( offset != ex_last_ofs )) return 0; if ( offset == 0 ) ex_last_pos = 4; //prve 4 bytes su info fs = fopen( fsName, "rb" ); if ( fs == NULL ) return 0; if ( offset + size > FileRec.size ) return 0; //if no compression if ( FileRec.flag == 0 ) { if ( fseek( fs, FileRec.offset + offset, SEEK_SET ) != 0 ) return 0; s = fread( output, 1, size, fs ); } //compression else { //nejde extraktovat po castiach, pretoze v dalsej casti moze byt //odkaz do casti predchadzajucej, odkazy mozu byt az do -4096b ? fseek( fs, FileRec.offset + ex_last_pos, SEEK_SET ); pos = 0; outpos = 0; ctrlcnt = 0; do { if ( ctrlcnt == 0 ) { //uchovam si poziciu, aby som ju mohol vratit ak som nahodou na konci [size] okctrlpos = pos; okoutsize = outpos; fread( &control, 1, 1, fs ); pos ++; ctrlcnt = 8; } if ( outpos >= size ) break; if (( control & 1 ) == 1 ) { fread( &ch, 1, 1, fs ); pos++; output[ outpos++ ] = ch; } else { fread( cha, 2, 1, fs ); pos += 2; sz = ( cha[1] & 0xF ) + 3; ofs = (( cha[1] & 0xF0 ) << 4 ) + cha[0]; src = ( outpos - 18 - ofs ) & 0xFFF; src = outpos - src; if ( outpos + sz > size ) break; memcpy( &output[ outpos ], &output[ src ], sz ); outpos += sz; } control >>= 1; ctrlcnt --; } while ( outpos < size ); if ( ctrlcnt == 0 ) { okctrlpos = pos; okoutsize = outpos; } ex_last_ofds = offset + okoutsize; ex_last_pos += okctrlpos; s = okoutsize; /* memset( output, '?', size ); fseek( fs, FileRec.offset, SEEK_SET ); fread( &insize, 4, 1, fs ); start = offset; if ( start > insize ) start = insize; end = offset + size; if ( end > insize ) end = insize; if ( start != end ) { if ( fseek( fs, FileRec.offset + 4 + start, SEEK_SET ) != 0 ) return 0; if ( fread( output, end - start, 1, fs ) != 1 ) return 0; } } fclose( fs ); return s; */ } int CMassFF8::GetFlags( void ) { return ma_flag_extract_only_whole_file; } int CMassFF8::ExtractWholeFile( FILE *fout ) { #define FF8bufferSize 4096 unsigned char buf[ FF8bufferSize * 3 ]; unsigned long pos, size; FILE *fs; unsigned long bufs; long outpos, ofs, sz, src, i; unsigned char control, ch, ctrlcnt, cha[2]; //open data file fs = fopen( fsName, "rb" ); if ( fs == NULL ) return 0; //if no compression if ( FileRec.flag == 0 ) { if ( fseek( fs, FileRec.offset, SEEK_SET ) != 0 ) return 0; 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; } } //uncompression ... learned from ficedula's doc else { //relative offsets are max 12bits = 4095 bytes, so i have buffer for data // and im uncompressing it there, when its full i write it, so there are allways // at least 4095 bytes for offseting to work fseek( fs, FileRec.offset, SEEK_SET ); fread( buf, 4, 1, fs ); pos = 0; outpos = 0; ctrlcnt = 0; bufs = 0; do { if ( ctrlcnt == 0 ) { //uchovam si poziciu, aby som ju mohol vratit ak som nahodou na konci [size] // okctrlpos = pos; okoutsize = outpos; fread( &control, 1, 1, fs ); pos ++; ctrlcnt = 8; } if (( control & 1 ) == 1 ) { fread( &ch, 1, 1, fs ); pos++; buf[ outpos++ ] = ch; } else { fread( cha, 2, 1, fs ); pos += 2; sz = ( cha[1] & 0xF ) + 3; ofs = (( cha[1] & 0xF0 ) << 4 ) + cha[0]; src = ( outpos - 18 - ofs ) & 0xFFF; src = outpos - src; //if offset goes beyond beginning of file, write out zeroes if ( src < 0 ) { i = -src; if ( sz < i ) i = sz; memset( &buf[ outpos ], 0, i ); outpos += i; //move outpointer sz -= i; //sub zereoes size from rest src += i; //move source } //if copied block goes after current position, copy the same thing again. if ( src + sz > outpos ) { i = 0; while( i < sz ) { buf[ outpos + i ] = buf[ src + i ]; i++; } } else memcpy( &buf[ outpos ], &buf[ src ], sz ); outpos += sz; } if ( outpos > FF8bufferSize * 2 ) { fwrite( buf, FF8bufferSize, 1, fout ); outpos -= FF8bufferSize; //i dont want to overleap copied buffers memcpy( &buf[ 0 ], &buf[ FF8bufferSize ], FF8bufferSize ); memcpy( &buf[ FF8bufferSize ], &buf[ 2*FF8bufferSize ], FF8bufferSize ); bufs++; } control >>= 1; ctrlcnt --; } while ( bufs * FF8bufferSize + outpos < FileRec.size ); fwrite( buf, outpos, 1, fout ); // if ( ctrlcnt == 0 ) { // okctrlpos = pos; okoutsize = outpos; // } // ex_last_ofs = offset + okoutsize; // ex_last_pos += okctrlpos; // s = okoutsize; /* memset( output, '?', size ); fseek( fs, FileRec.offset, SEEK_SET ); fread( &insize, 4, 1, fs ); start = offset; if ( start > insize ) start = insize; end = offset + size; if ( end > insize ) end = insize; if ( start != end ) { if ( fseek( fs, FileRec.offset + 4 + start, SEEK_SET ) != 0 ) return 0; if ( fread( output, end - start, 1, fs ) != 1 ) return 0; } */ } fclose( fs ); return 1; }