// Misc functions outside the core interface #include "unrar.h" #include "rar.hpp" #include // This source code is a heavily modified version based on the unrar package. // It may not be used to develop a RAR (WinRAR) compatible archiver. // See unrar/license.txt for copyright and licensing. void unrar_init() { if (CRCTab[1]==0) InitCRC(); Unpack::init_tables(); } struct unrar_extract_mem_t { char* out; char* end; }; extern "C" { static unrar_err_t extract_write( void* user_data, const void* in, int count ) { unrar_extract_mem_t* p = (unrar_extract_mem_t*) user_data; unrar_pos_t remain = p->end - p->out; if ( remain > 0 ) { if ( count > remain ) count = remain; memcpy( p->out, in, count ); p->out += count; } return unrar_ok; } } unrar_err_t unrar_extract( unrar_t* p, void* out, unrar_pos_t size ) { assert( !unrar_done( p ) ); unrar_extract_mem_t m; m.out = (char*) out; m.end = m.out + size; return unrar_extract_custom( p, &extract_write, &m ); } inline static bool is_entire_file( const unrar_t* p, const void* in, int count ) { return (count == p->Arc.NewLhd.UnpSize && p->Unp && in == p->Unp->window_wrptr()); } extern "C" { static unrar_err_t extract_mem( void* data, void const* in, int count ) { unrar_t* p = (unrar_t*) data; // We might have pointer to entire file if ( !p->data_ && is_entire_file( p, in, count ) ) { p->data_ = in; return unrar_ok; } // We don't have it, so allocate memory to read entire file into if ( !p->own_data_ ) { assert( !p->data_ ); unrar_pos_t size = unrar_info( p )->size; p->own_data_ = malloc( size ? size : 1 ); if ( !p->own_data_ ) return unrar_err_memory; p->data_ = p->own_data_; } memcpy( (void*) p->data_, in, count ); p->data_ = (char*) p->data_ + count; return unrar_ok; } } unrar_err_t unrar_extract_mem( unrar_t* p, void const** out ) { assert( !unrar_done( p ) ); *out = NULL; if ( !p->data_ ) { unrar_err_t err = unrar_extract_custom( p, &extract_mem, p ); if ( err ) return err; } *out = (p->own_data_ ? p->own_data_ : p->data_); return unrar_ok; } const char* unrar_err_str( unrar_err_t err ) { switch ( err ) { case unrar_ok: return ""; case unrar_err_memory: return "out of memory"; case unrar_err_open: return "couldn't open RAR archive"; case unrar_err_not_arc: return "not a RAR archive"; case unrar_err_corrupt: return "RAR archive is corrupt"; case unrar_err_io: return "couldn't read/write"; case unrar_err_arc_eof: return "unexpected end of archive"; case unrar_err_encrypted: return "encryption not supported"; case unrar_err_segmented: return "segmentation not supported"; case unrar_err_huge: return "huge (2GB+) archives are not supported"; case unrar_err_old_algo: return "compressed using older algorithm than supported"; case unrar_err_new_algo: return "compressed using newer algorithm than supported"; } assert( false ); return "problem with RAR"; } int ComprDataIO::Read( void* p, int n ) { unrar_err_t err = user_read( user_read_data, p, &n, Tell_ ); if ( err ) ReportError( err ); Tell_ += n; if ( Tell_ < 0 ) ReportError( unrar_err_huge ); return n; } void ComprDataIO::UnpWrite( byte* out, uint count ) { if ( !SkipUnpCRC ) { if ( write_error == unrar_ok ) write_error = user_write( user_write_data, out, count ); if ( OldFormat ) UnpFileCRC = OldCRC( (ushort) UnpFileCRC, out, count ); else UnpFileCRC = CRC( UnpFileCRC, out, count ); } } int ComprDataIO::UnpRead( byte* out, uint count ) { if ( count <= 0 ) return 0; if ( count > (uint) UnpPackedSize ) count = UnpPackedSize; int result = Read( out, count ); UnpPackedSize -= result; return result; }