mirror of https://github.com/bsnes-emu/bsnes.git
342 lines
5.7 KiB
C++
342 lines
5.7 KiB
C++
|
// File_Extractor 1.0.0. http://www.slack.net/~ant/
|
||
|
|
||
|
#include "File_Extractor.h"
|
||
|
|
||
|
/* Copyright (C) 2005-2009 Shay Green. This module is free software; you
|
||
|
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||
|
General Public License as published by the Free Software Foundation; either
|
||
|
version 2.1 of the License, or (at your option) any later version. This
|
||
|
module 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 Lesser General Public License for more
|
||
|
details. You should have received a copy of the GNU Lesser General Public
|
||
|
License along with this module; if not, write to the Free Software Foundation,
|
||
|
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||
|
|
||
|
#include "blargg_source.h"
|
||
|
|
||
|
File_Extractor::fex_t( fex_type_t t ) :
|
||
|
type_( t )
|
||
|
{
|
||
|
own_file_ = NULL;
|
||
|
|
||
|
close_();
|
||
|
}
|
||
|
|
||
|
// Open
|
||
|
|
||
|
blargg_err_t File_Extractor::set_path( const char* path )
|
||
|
{
|
||
|
if ( !path )
|
||
|
path = "";
|
||
|
|
||
|
RETURN_ERR( path_.resize( strlen( path ) + 1 ) );
|
||
|
memcpy( path_.begin(), path, path_.size() );
|
||
|
return blargg_ok;
|
||
|
}
|
||
|
|
||
|
blargg_err_t File_Extractor::open( const char path [] )
|
||
|
{
|
||
|
close();
|
||
|
|
||
|
RETURN_ERR( set_path( path ) );
|
||
|
|
||
|
blargg_err_t err = open_path_v();
|
||
|
if ( err )
|
||
|
close();
|
||
|
else
|
||
|
opened_ = true;
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
blargg_err_t File_Extractor::open_path_v()
|
||
|
{
|
||
|
RETURN_ERR( open_arc_file() );
|
||
|
|
||
|
return open_v();
|
||
|
}
|
||
|
|
||
|
inline
|
||
|
static void make_unbuffered( Std_File_Reader* r )
|
||
|
{
|
||
|
r->make_unbuffered();
|
||
|
}
|
||
|
|
||
|
inline
|
||
|
static void make_unbuffered( void* )
|
||
|
{ }
|
||
|
|
||
|
blargg_err_t File_Extractor::open_arc_file( bool unbuffered )
|
||
|
{
|
||
|
if ( reader_ )
|
||
|
return blargg_ok;
|
||
|
|
||
|
FEX_FILE_READER* in = BLARGG_NEW FEX_FILE_READER;
|
||
|
CHECK_ALLOC( in );
|
||
|
|
||
|
blargg_err_t err = in->open( arc_path() );
|
||
|
if ( err )
|
||
|
{
|
||
|
delete in;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
reader_ = in;
|
||
|
own_file();
|
||
|
if ( unbuffered )
|
||
|
make_unbuffered( in );
|
||
|
}
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
blargg_err_t File_Extractor::open( File_Reader* input, const char* path )
|
||
|
{
|
||
|
close();
|
||
|
|
||
|
RETURN_ERR( set_path( path ) );
|
||
|
|
||
|
RETURN_ERR( input->seek( 0 ) );
|
||
|
|
||
|
reader_ = input;
|
||
|
blargg_err_t err = open_v();
|
||
|
if ( err )
|
||
|
close();
|
||
|
else
|
||
|
opened_ = true;
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
// Close
|
||
|
|
||
|
void File_Extractor::close()
|
||
|
{
|
||
|
close_v();
|
||
|
close_();
|
||
|
}
|
||
|
|
||
|
void File_Extractor::close_()
|
||
|
{
|
||
|
delete own_file_;
|
||
|
own_file_ = NULL;
|
||
|
|
||
|
tell_ = 0;
|
||
|
reader_ = NULL;
|
||
|
opened_ = false;
|
||
|
|
||
|
path_.clear();
|
||
|
clear_file();
|
||
|
}
|
||
|
|
||
|
File_Extractor::~fex_t()
|
||
|
{
|
||
|
check( !opened() ); // fails if derived destructor didn't call close()
|
||
|
|
||
|
delete own_file_;
|
||
|
}
|
||
|
|
||
|
// Scanning
|
||
|
|
||
|
void File_Extractor::clear_file()
|
||
|
{
|
||
|
name_ = NULL;
|
||
|
wname_ = NULL;
|
||
|
done_ = true;
|
||
|
stat_called = false;
|
||
|
data_ptr_ = NULL;
|
||
|
|
||
|
set_info( 0 );
|
||
|
own_data_.clear();
|
||
|
clear_file_v();
|
||
|
}
|
||
|
|
||
|
void File_Extractor::set_name( const char new_name [], const wchar_t* new_wname )
|
||
|
{
|
||
|
name_ = new_name;
|
||
|
wname_ = new_wname;
|
||
|
done_ = false;
|
||
|
}
|
||
|
|
||
|
void File_Extractor::set_info( int new_size, unsigned date, unsigned crc )
|
||
|
{
|
||
|
size_ = new_size;
|
||
|
date_ = (date != 0xFFFFFFFF ? date : 0);
|
||
|
crc32_ = crc;
|
||
|
set_remain( new_size );
|
||
|
}
|
||
|
|
||
|
blargg_err_t File_Extractor::next_()
|
||
|
{
|
||
|
tell_++;
|
||
|
clear_file();
|
||
|
|
||
|
blargg_err_t err = next_v();
|
||
|
if ( err )
|
||
|
clear_file();
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
blargg_err_t File_Extractor::next()
|
||
|
{
|
||
|
assert( !done() );
|
||
|
return next_();
|
||
|
}
|
||
|
|
||
|
blargg_err_t File_Extractor::rewind()
|
||
|
{
|
||
|
assert( opened() );
|
||
|
|
||
|
tell_ = 0;
|
||
|
clear_file();
|
||
|
|
||
|
blargg_err_t err = rewind_v();
|
||
|
if ( err )
|
||
|
clear_file();
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
blargg_err_t File_Extractor::stat()
|
||
|
{
|
||
|
assert( !done() );
|
||
|
|
||
|
if ( !stat_called )
|
||
|
{
|
||
|
RETURN_ERR( stat_v() );
|
||
|
stat_called = true;
|
||
|
}
|
||
|
return blargg_ok;
|
||
|
}
|
||
|
|
||
|
// Tell/seek
|
||
|
|
||
|
int const pos_offset = 1;
|
||
|
|
||
|
fex_pos_t File_Extractor::tell_arc() const
|
||
|
{
|
||
|
assert( opened() );
|
||
|
|
||
|
fex_pos_t pos = tell_arc_v();
|
||
|
assert( pos >= 0 );
|
||
|
|
||
|
return pos + pos_offset;
|
||
|
}
|
||
|
|
||
|
blargg_err_t File_Extractor::seek_arc( fex_pos_t pos )
|
||
|
{
|
||
|
assert( opened() );
|
||
|
assert( pos != 0 );
|
||
|
|
||
|
clear_file();
|
||
|
|
||
|
blargg_err_t err = seek_arc_v( pos - pos_offset );
|
||
|
if ( err )
|
||
|
clear_file();
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
fex_pos_t File_Extractor::tell_arc_v() const
|
||
|
{
|
||
|
return tell_;
|
||
|
}
|
||
|
|
||
|
blargg_err_t File_Extractor::seek_arc_v( fex_pos_t pos )
|
||
|
{
|
||
|
// >= because seeking to current file should always reset read pointer etc.
|
||
|
if ( tell_ >= pos )
|
||
|
RETURN_ERR( rewind() );
|
||
|
|
||
|
while ( tell_ < pos )
|
||
|
{
|
||
|
RETURN_ERR( next_() );
|
||
|
|
||
|
if ( done() )
|
||
|
{
|
||
|
assert( false );
|
||
|
return blargg_err_caller;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
assert( tell_ == pos );
|
||
|
|
||
|
return blargg_ok;
|
||
|
}
|
||
|
|
||
|
// Extraction
|
||
|
|
||
|
blargg_err_t File_Extractor::rewind_file()
|
||
|
{
|
||
|
RETURN_ERR( stat() );
|
||
|
|
||
|
if ( tell() > 0 )
|
||
|
{
|
||
|
if ( data_ptr_ )
|
||
|
{
|
||
|
set_remain( size() );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
RETURN_ERR( seek_arc( tell_arc() ) );
|
||
|
RETURN_ERR( stat() );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return blargg_ok;
|
||
|
}
|
||
|
|
||
|
blargg_err_t File_Extractor::data( const void** data_out )
|
||
|
{
|
||
|
assert( !done() );
|
||
|
|
||
|
*data_out = NULL;
|
||
|
if ( !data_ptr_ )
|
||
|
{
|
||
|
int old_tell = tell();
|
||
|
|
||
|
RETURN_ERR( rewind_file() );
|
||
|
|
||
|
void const* ptr;
|
||
|
RETURN_ERR( data_v( &ptr ) );
|
||
|
data_ptr_ = ptr;
|
||
|
|
||
|
// Now that data is in memory, we can seek by simply setting remain
|
||
|
set_remain( size() - old_tell );
|
||
|
}
|
||
|
|
||
|
*data_out = data_ptr_;
|
||
|
return blargg_ok;
|
||
|
}
|
||
|
|
||
|
blargg_err_t File_Extractor::data_v( void const** out )
|
||
|
{
|
||
|
RETURN_ERR( own_data_.resize( size() ) );
|
||
|
*out = own_data_.begin();
|
||
|
|
||
|
blargg_err_t err = extract_v( own_data_.begin(), own_data_.size() );
|
||
|
if ( err )
|
||
|
own_data_.clear();
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
blargg_err_t File_Extractor::extract_v( void* out, int count )
|
||
|
{
|
||
|
void const* p;
|
||
|
RETURN_ERR( data( &p ) );
|
||
|
memcpy( out, STATIC_CAST(char const*,p) + (size() - remain()), count );
|
||
|
|
||
|
return blargg_ok;
|
||
|
}
|
||
|
|
||
|
blargg_err_t File_Extractor::read_v( void* out, int count )
|
||
|
{
|
||
|
if ( data_ptr_ )
|
||
|
return File_Extractor::extract_v( out, count );
|
||
|
|
||
|
return extract_v( out, count );
|
||
|
}
|