776 lines
15 KiB
C++
776 lines
15 KiB
C++
// File_Extractor 1.0.0. http://www.slack.net/~ant/
|
|
|
|
#include "Data_Reader.h"
|
|
|
|
#include "blargg_endian.h"
|
|
#include <stdio.h>
|
|
#include <errno.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"
|
|
|
|
// Data_Reader
|
|
|
|
blargg_err_t Data_Reader::read( void* p, int n )
|
|
{
|
|
assert( n >= 0 );
|
|
|
|
if ( n < 0 )
|
|
return blargg_err_caller;
|
|
|
|
if ( n <= 0 )
|
|
return blargg_ok;
|
|
|
|
if ( n > remain() )
|
|
return blargg_err_file_eof;
|
|
|
|
blargg_err_t err = read_v( p, n );
|
|
if ( !err )
|
|
remain_ -= n;
|
|
|
|
return err;
|
|
}
|
|
|
|
blargg_err_t Data_Reader::read_avail( void* p, int* n_ )
|
|
{
|
|
assert( *n_ >= 0 );
|
|
|
|
int n = min( (BOOST::uint64_t)(*n_), remain() );
|
|
*n_ = 0;
|
|
|
|
if ( n < 0 )
|
|
return blargg_err_caller;
|
|
|
|
if ( n <= 0 )
|
|
return blargg_ok;
|
|
|
|
blargg_err_t err = read_v( p, n );
|
|
if ( !err )
|
|
{
|
|
remain_ -= n;
|
|
*n_ = n;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
blargg_err_t Data_Reader::read_avail( void* p, long* n )
|
|
{
|
|
int i = STATIC_CAST(int, *n);
|
|
blargg_err_t err = read_avail( p, &i );
|
|
*n = i;
|
|
return err;
|
|
}
|
|
|
|
blargg_err_t Data_Reader::skip_v( int count )
|
|
{
|
|
char buf [512];
|
|
while ( count )
|
|
{
|
|
int n = min( count, (int) sizeof buf );
|
|
count -= n;
|
|
RETURN_ERR( read_v( buf, n ) );
|
|
}
|
|
return blargg_ok;
|
|
}
|
|
|
|
blargg_err_t Data_Reader::skip( int n )
|
|
{
|
|
assert( n >= 0 );
|
|
|
|
if ( n < 0 )
|
|
return blargg_err_caller;
|
|
|
|
if ( n <= 0 )
|
|
return blargg_ok;
|
|
|
|
if ( n > remain() )
|
|
return blargg_err_file_eof;
|
|
|
|
blargg_err_t err = skip_v( n );
|
|
if ( !err )
|
|
remain_ -= n;
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
// File_Reader
|
|
|
|
blargg_err_t File_Reader::seek( BOOST::uint64_t n )
|
|
{
|
|
assert( n >= 0 );
|
|
|
|
if ( n < 0 )
|
|
return blargg_err_caller;
|
|
|
|
if ( n == tell() )
|
|
return blargg_ok;
|
|
|
|
if ( n > size() )
|
|
return blargg_err_file_eof;
|
|
|
|
blargg_err_t err = seek_v( n );
|
|
if ( !err )
|
|
set_tell( n );
|
|
|
|
return err;
|
|
}
|
|
|
|
blargg_err_t File_Reader::skip_v( BOOST::uint64_t n )
|
|
{
|
|
return seek_v( tell() + n );
|
|
}
|
|
|
|
|
|
// Subset_Reader
|
|
|
|
Subset_Reader::Subset_Reader( Data_Reader* dr, BOOST::uint64_t size ) :
|
|
in( dr )
|
|
{
|
|
set_remain( min( size, dr->remain() ) );
|
|
}
|
|
|
|
blargg_err_t Subset_Reader::read_v( void* p, int s )
|
|
{
|
|
return in->read( p, s );
|
|
}
|
|
|
|
|
|
// Remaining_Reader
|
|
|
|
Remaining_Reader::Remaining_Reader( void const* h, int size, Data_Reader* r ) :
|
|
in( r )
|
|
{
|
|
header = h;
|
|
header_remain = size;
|
|
|
|
set_remain( size + r->remain() );
|
|
}
|
|
|
|
blargg_err_t Remaining_Reader::read_v( void* out, int count )
|
|
{
|
|
int first = min( count, header_remain );
|
|
if ( first )
|
|
{
|
|
memcpy( out, header, first );
|
|
header = STATIC_CAST(char const*, header) + first;
|
|
header_remain -= first;
|
|
}
|
|
|
|
return in->read( STATIC_CAST(char*, out) + first, count - first );
|
|
}
|
|
|
|
|
|
// Mem_File_Reader
|
|
|
|
Mem_File_Reader::Mem_File_Reader( const void* p, long s ) :
|
|
begin( STATIC_CAST(const char*, p) )
|
|
{
|
|
set_size( s );
|
|
}
|
|
|
|
blargg_err_t Mem_File_Reader::read_v( void* p, int s )
|
|
{
|
|
memcpy( p, begin + tell(), s );
|
|
return blargg_ok;
|
|
}
|
|
|
|
blargg_err_t Mem_File_Reader::seek_v( int )
|
|
{
|
|
return blargg_ok;
|
|
}
|
|
|
|
|
|
// Callback_Reader
|
|
|
|
Callback_Reader::Callback_Reader( callback_t c, BOOST::uint64_t s, void* d ) :
|
|
callback( c ),
|
|
user_data( d )
|
|
{
|
|
set_remain( s );
|
|
}
|
|
|
|
blargg_err_t Callback_Reader::read_v( void* out, int count )
|
|
{
|
|
return callback( user_data, out, count );
|
|
}
|
|
|
|
|
|
// Callback_File_Reader
|
|
|
|
Callback_File_Reader::Callback_File_Reader( callback_t c, BOOST::uint64_t s, void* d ) :
|
|
callback( c ),
|
|
user_data( d )
|
|
{
|
|
set_size( s );
|
|
}
|
|
|
|
blargg_err_t Callback_File_Reader::read_v( void* out, int count )
|
|
{
|
|
return callback( user_data, out, count, tell() );
|
|
}
|
|
|
|
blargg_err_t Callback_File_Reader::seek_v( int )
|
|
{
|
|
return blargg_ok;
|
|
}
|
|
|
|
static const BOOST::uint8_t mask_tab[6]={0x80,0xE0,0xF0,0xF8,0xFC,0xFE};
|
|
|
|
static const BOOST::uint8_t val_tab[6]={0,0xC0,0xE0,0xF0,0xF8,0xFC};
|
|
|
|
size_t utf8_char_len_from_header( char p_c )
|
|
{
|
|
// what is this?
|
|
// BOOST::uint8_t c = (BOOST::uint8_t)p_c;
|
|
|
|
size_t cnt = 0;
|
|
for(;;)
|
|
{
|
|
if ( ( p_c & mask_tab[cnt] ) == val_tab[cnt] ) break;
|
|
if ( ++cnt >= 6 ) return 0;
|
|
}
|
|
|
|
return cnt + 1;
|
|
}
|
|
|
|
size_t utf8_decode_char( const char *p_utf8, unsigned & wide, size_t mmax )
|
|
{
|
|
const BOOST::uint8_t * utf8 = ( const BOOST::uint8_t* )p_utf8;
|
|
|
|
if ( mmax == 0 )
|
|
{
|
|
wide = 0;
|
|
return 0;
|
|
}
|
|
|
|
if ( utf8[0] < 0x80 )
|
|
{
|
|
wide = utf8[0];
|
|
return utf8[0]>0 ? 1 : 0;
|
|
}
|
|
if ( mmax > 6 ) mmax = 6;
|
|
wide = 0;
|
|
|
|
unsigned res=0;
|
|
unsigned n;
|
|
unsigned cnt=0;
|
|
for(;;)
|
|
{
|
|
if ( ( *utf8 & mask_tab[cnt] ) == val_tab[cnt] ) break;
|
|
if ( ++cnt >= mmax ) return 0;
|
|
}
|
|
cnt++;
|
|
|
|
if ( cnt==2 && !( *utf8 & 0x1E ) ) return 0;
|
|
|
|
if ( cnt == 1 )
|
|
res = *utf8;
|
|
else
|
|
res = ( 0xFF >> ( cnt + 1 ) ) & *utf8;
|
|
|
|
for ( n = 1; n < cnt; n++ )
|
|
{
|
|
if ( ( utf8[n] & 0xC0 ) != 0x80 )
|
|
return 0;
|
|
if ( !res && n == 2 && !( ( utf8[n] & 0x7F ) >> ( 7 - cnt ) ) )
|
|
return 0;
|
|
|
|
res = ( res << 6 ) | ( utf8[n] & 0x3F );
|
|
}
|
|
|
|
wide = res;
|
|
|
|
return cnt;
|
|
}
|
|
|
|
size_t utf8_encode_char( unsigned wide, char * target )
|
|
{
|
|
size_t count;
|
|
|
|
if ( wide < 0x80 )
|
|
count = 1;
|
|
else if ( wide < 0x800 )
|
|
count = 2;
|
|
else if ( wide < 0x10000 )
|
|
count = 3;
|
|
else if ( wide < 0x200000 )
|
|
count = 4;
|
|
else if ( wide < 0x4000000 )
|
|
count = 5;
|
|
else if ( wide <= 0x7FFFFFFF )
|
|
count = 6;
|
|
else
|
|
return 0;
|
|
|
|
if ( target == 0 )
|
|
return count;
|
|
|
|
switch ( count )
|
|
{
|
|
case 6:
|
|
target[5] = 0x80 | ( wide & 0x3F );
|
|
wide = wide >> 6;
|
|
wide |= 0x4000000;
|
|
case 5:
|
|
target[4] = 0x80 | ( wide & 0x3F );
|
|
wide = wide >> 6;
|
|
wide |= 0x200000;
|
|
case 4:
|
|
target[3] = 0x80 | ( wide & 0x3F );
|
|
wide = wide >> 6;
|
|
wide |= 0x10000;
|
|
case 3:
|
|
target[2] = 0x80 | ( wide & 0x3F );
|
|
wide = wide >> 6;
|
|
wide |= 0x800;
|
|
case 2:
|
|
target[1] = 0x80 | ( wide & 0x3F );
|
|
wide = wide >> 6;
|
|
wide |= 0xC0;
|
|
case 1:
|
|
target[0] = wide;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
size_t utf16_encode_char( unsigned cur_wchar, blargg_wchar_t * out )
|
|
{
|
|
if ( cur_wchar < 0x10000 )
|
|
{
|
|
if ( out ) *out = (blargg_wchar_t) cur_wchar; return 1;
|
|
}
|
|
else if ( cur_wchar < ( 1 << 20 ) )
|
|
{
|
|
unsigned c = cur_wchar - 0x10000;
|
|
//MSDN:
|
|
//The first (high) surrogate is a 16-bit code value in the range U+D800 to U+DBFF. The second (low) surrogate is a 16-bit code value in the range U+DC00 to U+DFFF. Using surrogates, Unicode can support over one million characters. For more details about surrogates, refer to The Unicode Standard, version 2.0.
|
|
if ( out )
|
|
{
|
|
out[0] = ( blargg_wchar_t )( 0xD800 | ( 0x3FF & ( c >> 10 ) ) );
|
|
out[1] = ( blargg_wchar_t )( 0xDC00 | ( 0x3FF & c ) ) ;
|
|
}
|
|
return 2;
|
|
}
|
|
else
|
|
{
|
|
if ( out ) *out = '?'; return 1;
|
|
}
|
|
}
|
|
|
|
size_t utf16_decode_char( const blargg_wchar_t * p_source, unsigned * p_out, size_t p_source_length )
|
|
{
|
|
if ( p_source_length == 0 ) return 0;
|
|
else if ( p_source_length == 1 )
|
|
{
|
|
*p_out = p_source[0];
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
size_t retval = 0;
|
|
unsigned decoded = p_source[0];
|
|
if ( decoded != 0 )
|
|
{
|
|
retval = 1;
|
|
if ( ( decoded & 0xFC00 ) == 0xD800 )
|
|
{
|
|
unsigned low = p_source[1];
|
|
if ( ( low & 0xFC00 ) == 0xDC00 )
|
|
{
|
|
decoded = 0x10000 + ( ( ( decoded & 0x3FF ) << 10 ) | ( low & 0x3FF ) );
|
|
retval = 2;
|
|
}
|
|
}
|
|
}
|
|
*p_out = decoded;
|
|
return retval;
|
|
}
|
|
}
|
|
|
|
// Converts wide-character path to UTF-8. Free result with free(). Only supported on Windows.
|
|
char* blargg_to_utf8( const blargg_wchar_t* wpath )
|
|
{
|
|
if ( wpath == NULL )
|
|
return NULL;
|
|
|
|
size_t needed = 0;
|
|
size_t mmax = blargg_wcslen( wpath );
|
|
if ( mmax <= 0 )
|
|
return NULL;
|
|
|
|
size_t ptr = 0;
|
|
while ( ptr < mmax )
|
|
{
|
|
unsigned wide = 0;
|
|
size_t char_len = utf16_decode_char( wpath + ptr, &wide, mmax - ptr );
|
|
if ( !char_len ) break;
|
|
ptr += char_len;
|
|
needed += utf8_encode_char( wide, 0 );
|
|
}
|
|
if ( needed <= 0 )
|
|
return NULL;
|
|
|
|
char* path = (char*) calloc( needed + 1, 1 );
|
|
if ( path == NULL )
|
|
return NULL;
|
|
|
|
ptr = 0;
|
|
size_t actual = 0;
|
|
while ( ptr < mmax && actual < needed )
|
|
{
|
|
unsigned wide = 0;
|
|
size_t char_len = utf16_decode_char( wpath + ptr, &wide, mmax - ptr );
|
|
if ( !char_len ) break;
|
|
ptr += char_len;
|
|
actual += utf8_encode_char( wide, path + actual );
|
|
}
|
|
|
|
if ( actual == 0 )
|
|
{
|
|
free( path );
|
|
return NULL;
|
|
}
|
|
|
|
assert( actual == needed );
|
|
return path;
|
|
}
|
|
|
|
// Converts UTF-8 path to wide-character. Free result with free() Only supported on Windows.
|
|
blargg_wchar_t* blargg_to_wide( const char* path )
|
|
{
|
|
if ( path == NULL )
|
|
return NULL;
|
|
|
|
size_t mmax = strlen( path );
|
|
if ( mmax <= 0 )
|
|
return NULL;
|
|
|
|
size_t needed = 0;
|
|
size_t ptr = 0;
|
|
while ( ptr < mmax )
|
|
{
|
|
unsigned wide = 0;
|
|
size_t char_len = utf8_decode_char( path + ptr, wide, mmax - ptr );
|
|
if ( !char_len ) break;
|
|
ptr += char_len;
|
|
needed += utf16_encode_char( wide, 0 );
|
|
}
|
|
if ( needed <= 0 )
|
|
return NULL;
|
|
|
|
blargg_wchar_t* wpath = (blargg_wchar_t*) calloc( needed + 1, sizeof *wpath );
|
|
if ( wpath == NULL )
|
|
return NULL;
|
|
|
|
ptr = 0;
|
|
size_t actual = 0;
|
|
while ( ptr < mmax && actual < needed )
|
|
{
|
|
unsigned wide = 0;
|
|
size_t char_len = utf8_decode_char( path + ptr, wide, mmax - ptr );
|
|
if ( !char_len ) break;
|
|
ptr += char_len;
|
|
actual += utf16_encode_char( wide, wpath + actual );
|
|
}
|
|
if ( actual == 0 )
|
|
{
|
|
free( wpath );
|
|
return NULL;
|
|
}
|
|
|
|
assert( actual == needed );
|
|
return wpath;
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
|
|
static FILE* blargg_fopen( const char path [], const char mode [] )
|
|
{
|
|
FILE* file = NULL;
|
|
blargg_wchar_t* wmode = NULL;
|
|
blargg_wchar_t* wpath = NULL;
|
|
|
|
wpath = blargg_to_wide( path );
|
|
if ( wpath )
|
|
{
|
|
wmode = blargg_to_wide( mode );
|
|
if ( wmode )
|
|
file = _wfopen( wpath, wmode );
|
|
}
|
|
|
|
// Save and restore errno in case free() clears it
|
|
int saved_errno = errno;
|
|
free( wmode );
|
|
free( wpath );
|
|
errno = saved_errno;
|
|
|
|
return file;
|
|
}
|
|
|
|
#else
|
|
|
|
static inline FILE* blargg_fopen( const char path [], const char mode [] )
|
|
{
|
|
return fopen( path, mode );
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
// Std_File_Reader
|
|
|
|
Std_File_Reader::Std_File_Reader()
|
|
{
|
|
file_ = NULL;
|
|
}
|
|
|
|
Std_File_Reader::~Std_File_Reader()
|
|
{
|
|
close();
|
|
}
|
|
|
|
static blargg_err_t blargg_fopen( FILE** out, const char path [] )
|
|
{
|
|
errno = 0;
|
|
*out = blargg_fopen( path, "rb" );
|
|
if ( !*out )
|
|
{
|
|
#ifdef ENOENT
|
|
if ( errno == ENOENT )
|
|
return blargg_err_file_missing;
|
|
#endif
|
|
#ifdef ENOMEM
|
|
if ( errno == ENOMEM )
|
|
return blargg_err_memory;
|
|
#endif
|
|
return blargg_err_file_read;
|
|
}
|
|
|
|
return blargg_ok;
|
|
}
|
|
|
|
static blargg_err_t blargg_fsize( FILE* f, long* out )
|
|
{
|
|
if ( fseek( f, 0, SEEK_END ) )
|
|
return blargg_err_file_io;
|
|
|
|
*out = ftell( f );
|
|
if ( *out < 0 )
|
|
return blargg_err_file_io;
|
|
|
|
if ( fseek( f, 0, SEEK_SET ) )
|
|
return blargg_err_file_io;
|
|
|
|
return blargg_ok;
|
|
}
|
|
|
|
blargg_err_t Std_File_Reader::open( const char path [] )
|
|
{
|
|
close();
|
|
|
|
FILE* f;
|
|
RETURN_ERR( blargg_fopen( &f, path ) );
|
|
|
|
long s;
|
|
blargg_err_t err = blargg_fsize( f, &s );
|
|
if ( err )
|
|
{
|
|
fclose( f );
|
|
return err;
|
|
}
|
|
|
|
file_ = f;
|
|
set_size( s );
|
|
|
|
return blargg_ok;
|
|
}
|
|
|
|
void Std_File_Reader::make_unbuffered()
|
|
{
|
|
if ( setvbuf( STATIC_CAST(FILE*, file_), NULL, _IONBF, 0 ) )
|
|
check( false ); // shouldn't fail, but OK if it does
|
|
}
|
|
|
|
blargg_err_t Std_File_Reader::read_v( void* p, int s )
|
|
{
|
|
if ( (size_t) s != fread( p, 1, s, STATIC_CAST(FILE*, file_) ) )
|
|
{
|
|
// Data_Reader's wrapper should prevent EOF
|
|
check( !feof( STATIC_CAST(FILE*, file_) ) );
|
|
|
|
return blargg_err_file_io;
|
|
}
|
|
|
|
return blargg_ok;
|
|
}
|
|
|
|
#ifdef __CELLOS_LV2__
|
|
int
|
|
fseeko(FILE *stream, off_t pos, int whence)
|
|
{
|
|
return fseek(stream, (long)pos, whence);
|
|
}
|
|
#endif
|
|
|
|
blargg_err_t Std_File_Reader::seek_v( BOOST::uint64_t n )
|
|
{
|
|
#ifdef _WIN32
|
|
if ( fseek( STATIC_CAST(FILE*, file_), n, SEEK_SET ) )
|
|
#else
|
|
if ( fseeko( STATIC_CAST(FILE*, file_), n, SEEK_SET ) )
|
|
#endif
|
|
{
|
|
// Data_Reader's wrapper should prevent EOF
|
|
check( !feof( STATIC_CAST(FILE*, file_) ) );
|
|
|
|
return blargg_err_file_io;
|
|
}
|
|
|
|
return blargg_ok;
|
|
}
|
|
|
|
void Std_File_Reader::close()
|
|
{
|
|
if ( file_ )
|
|
{
|
|
fclose( STATIC_CAST(FILE*, file_) );
|
|
file_ = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
// Gzip_File_Reader
|
|
|
|
#ifndef __LIBRETRO__
|
|
#ifdef HAVE_ZLIB_H
|
|
|
|
#include "zlib.h"
|
|
|
|
static const char* get_gzip_eof( const char path [], long* eof )
|
|
{
|
|
FILE* file;
|
|
RETURN_ERR( blargg_fopen( &file, path ) );
|
|
|
|
int const h_size = 4;
|
|
unsigned char h [h_size];
|
|
|
|
// read four bytes to ensure that we can seek to -4 later
|
|
if ( fread( h, 1, h_size, file ) != (size_t) h_size || h[0] != 0x1F || h[1] != 0x8B )
|
|
{
|
|
// Not gzipped
|
|
if ( ferror( file ) )
|
|
return blargg_err_file_io;
|
|
|
|
if ( fseek( file, 0, SEEK_END ) )
|
|
return blargg_err_file_io;
|
|
|
|
*eof = ftell( file );
|
|
if ( *eof < 0 )
|
|
return blargg_err_file_io;
|
|
}
|
|
else
|
|
{
|
|
// Gzipped; get uncompressed size from end
|
|
if ( fseek( file, -h_size, SEEK_END ) )
|
|
return blargg_err_file_io;
|
|
|
|
if ( fread( h, 1, h_size, file ) != (size_t) h_size )
|
|
return blargg_err_file_io;
|
|
|
|
*eof = get_le32( h );
|
|
}
|
|
|
|
if ( fclose( file ) )
|
|
check( false );
|
|
|
|
return blargg_ok;
|
|
}
|
|
|
|
Gzip_File_Reader::Gzip_File_Reader()
|
|
{
|
|
file_ = NULL;
|
|
}
|
|
|
|
Gzip_File_Reader::~Gzip_File_Reader()
|
|
{
|
|
close();
|
|
}
|
|
|
|
blargg_err_t Gzip_File_Reader::open( const char path [] )
|
|
{
|
|
close();
|
|
|
|
long s;
|
|
RETURN_ERR( get_gzip_eof( path, &s ) );
|
|
|
|
file_ = gzopen( path, "rb" );
|
|
if ( !file_ )
|
|
return blargg_err_file_read;
|
|
|
|
set_size( s );
|
|
return blargg_ok;
|
|
}
|
|
|
|
static blargg_err_t convert_gz_error( gzFile file )
|
|
{
|
|
int err;
|
|
gzerror( file, &err );
|
|
|
|
switch ( err )
|
|
{
|
|
case Z_STREAM_ERROR: break;
|
|
case Z_DATA_ERROR: return blargg_err_file_corrupt;
|
|
case Z_MEM_ERROR: return blargg_err_memory;
|
|
case Z_BUF_ERROR: break;
|
|
}
|
|
return blargg_err_internal;
|
|
}
|
|
|
|
blargg_err_t Gzip_File_Reader::read_v( void* p, int s )
|
|
{
|
|
int result = gzread( (gzFile) file_, p, s );
|
|
if ( result != s )
|
|
{
|
|
if ( result < 0 )
|
|
return convert_gz_error( (gzFile) file_ );
|
|
|
|
return blargg_err_file_corrupt;
|
|
}
|
|
|
|
return blargg_ok;
|
|
}
|
|
|
|
blargg_err_t Gzip_File_Reader::seek_v( int n )
|
|
{
|
|
if ( gzseek( (gzFile) file_, n, SEEK_SET ) < 0 )
|
|
return convert_gz_error( (gzFile) file_ );
|
|
|
|
return blargg_ok;
|
|
}
|
|
|
|
void Gzip_File_Reader::close()
|
|
{
|
|
if ( file_ )
|
|
{
|
|
if ( gzclose( (gzFile) file_ ) )
|
|
check( false );
|
|
file_ = NULL;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#endif
|