198 lines
4.9 KiB
C++
198 lines
4.9 KiB
C++
// File_Extractor 1.0.0. http://www.slack.net/~ant/
|
|
|
|
#include "blargg_common.h"
|
|
|
|
#if FEX_ENABLE_RAR
|
|
|
|
#include "Rar_Extractor.h"
|
|
|
|
/* Copyright (C) 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"
|
|
|
|
static blargg_err_t init_rar()
|
|
{
|
|
unrar_init();
|
|
return blargg_ok;
|
|
}
|
|
|
|
static File_Extractor* new_rar()
|
|
{
|
|
return BLARGG_NEW Rar_Extractor;
|
|
}
|
|
|
|
fex_type_t_ const fex_rar_type [1] = {{
|
|
".rar",
|
|
&new_rar,
|
|
"RAR archive",
|
|
&init_rar
|
|
}};
|
|
|
|
blargg_err_t Rar_Extractor::convert_err( unrar_err_t err )
|
|
{
|
|
blargg_err_t reader_err = reader.err;
|
|
reader.err = blargg_ok;
|
|
if ( reader_err )
|
|
check( err == unrar_next_err );
|
|
|
|
switch ( err )
|
|
{
|
|
case unrar_ok: return blargg_ok;
|
|
case unrar_err_memory: return blargg_err_memory;
|
|
case unrar_err_open: return blargg_err_file_read;
|
|
case unrar_err_not_arc: return blargg_err_file_type;
|
|
case unrar_err_corrupt: return blargg_err_file_corrupt;
|
|
case unrar_err_io: return blargg_err_file_io;
|
|
case unrar_err_arc_eof: return blargg_err_internal;
|
|
case unrar_err_encrypted: return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "RAR encryption not supported" );
|
|
case unrar_err_segmented: return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "RAR segmentation not supported" );
|
|
case unrar_err_huge: return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "Huge RAR files not supported" );
|
|
case unrar_err_old_algo: return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "Old RAR compression not supported" );
|
|
case unrar_err_new_algo: return BLARGG_ERR( BLARGG_ERR_FILE_FEATURE, "RAR uses unknown newer compression" );
|
|
case unrar_next_err: break;
|
|
default:
|
|
check( false ); // unhandled RAR error
|
|
}
|
|
|
|
if ( reader_err )
|
|
return reader_err;
|
|
|
|
check( false );
|
|
return BLARGG_ERR( BLARGG_ERR_INTERNAL, "RAR archive" );
|
|
}
|
|
|
|
static inline unrar_err_t handle_err( Rar_Extractor::read_callback_t* h, blargg_err_t err )
|
|
{
|
|
if ( !err )
|
|
return unrar_ok;
|
|
|
|
h->err = err;
|
|
return unrar_next_err;
|
|
}
|
|
|
|
extern "C"
|
|
{
|
|
static unrar_err_t my_unrar_read( void* data, void* out, int* count, unrar_pos_t pos )
|
|
{
|
|
// TODO: 64-bit file support
|
|
|
|
Rar_Extractor::read_callback_t* h = STATIC_CAST(Rar_Extractor::read_callback_t*,data);
|
|
if ( h->pos != pos )
|
|
{
|
|
blargg_err_t err = h->in->seek( pos );
|
|
if ( err )
|
|
return handle_err( h, err );
|
|
|
|
h->pos = pos;
|
|
}
|
|
|
|
blargg_err_t err = h->in->read_avail( out, count );
|
|
if ( err )
|
|
return handle_err( h, err );
|
|
|
|
h->pos += *count;
|
|
|
|
return unrar_ok;
|
|
}
|
|
}
|
|
|
|
Rar_Extractor::Rar_Extractor() :
|
|
File_Extractor( fex_rar_type )
|
|
{
|
|
unrar = NULL;
|
|
}
|
|
|
|
Rar_Extractor::~Rar_Extractor()
|
|
{
|
|
close();
|
|
}
|
|
|
|
blargg_err_t Rar_Extractor::open_v()
|
|
{
|
|
reader.pos = 0;
|
|
reader.in = &arc();
|
|
reader.err = blargg_ok;
|
|
|
|
RETURN_ERR( arc().seek( 0 ) );
|
|
RETURN_ERR( convert_err( unrar_open_custom( &unrar, &my_unrar_read, &reader ) ) );
|
|
return skip_unextractables();
|
|
}
|
|
|
|
void Rar_Extractor::close_v()
|
|
{
|
|
unrar_close( unrar );
|
|
|
|
unrar = NULL;
|
|
reader.in = NULL;
|
|
}
|
|
|
|
blargg_err_t Rar_Extractor::skip_unextractables()
|
|
{
|
|
while ( !unrar_done( unrar ) && unrar_try_extract( unrar ) )
|
|
RETURN_ERR( next_raw() );
|
|
|
|
if ( !unrar_done( unrar ) )
|
|
{
|
|
unrar_info_t const* info = unrar_info( unrar );
|
|
|
|
set_name( info->name, (info->name_w && *info->name_w) ? info->name_w : NULL );
|
|
set_info( info->size, info->dos_date, (info->is_crc32 ? info->crc : 0) );
|
|
}
|
|
|
|
return blargg_ok;
|
|
}
|
|
|
|
blargg_err_t Rar_Extractor::next_raw()
|
|
{
|
|
return convert_err( unrar_next( unrar ) );
|
|
}
|
|
|
|
blargg_err_t Rar_Extractor::next_v()
|
|
{
|
|
RETURN_ERR( next_raw() );
|
|
return skip_unextractables();
|
|
}
|
|
|
|
blargg_err_t Rar_Extractor::rewind_v()
|
|
{
|
|
RETURN_ERR( convert_err( unrar_rewind( unrar ) ) );
|
|
return skip_unextractables();
|
|
}
|
|
|
|
fex_pos_t Rar_Extractor::tell_arc_v() const
|
|
{
|
|
return unrar_tell( unrar );
|
|
}
|
|
|
|
blargg_err_t Rar_Extractor::seek_arc_v( fex_pos_t pos )
|
|
{
|
|
RETURN_ERR( convert_err( unrar_seek( unrar, pos ) ) );
|
|
return skip_unextractables();
|
|
}
|
|
|
|
blargg_err_t Rar_Extractor::data_v( void const** out )
|
|
{
|
|
return convert_err( unrar_extract_mem( unrar, out ) );
|
|
}
|
|
|
|
blargg_err_t Rar_Extractor::extract_v( void* out, int count )
|
|
{
|
|
// We can read entire file directly into user buffer
|
|
if ( count == size() )
|
|
return convert_err( unrar_extract( unrar, out, count ) );
|
|
|
|
// This will call data_v() and copy from that buffer for us
|
|
return File_Extractor::extract_v( out, count );
|
|
}
|
|
|
|
#endif
|