summaryrefslogtreecommitdiffstats
path: root/byte_repair.cc
diff options
context:
space:
mode:
Diffstat (limited to 'byte_repair.cc')
-rw-r--r--byte_repair.cc91
1 files changed, 62 insertions, 29 deletions
diff --git a/byte_repair.cc b/byte_repair.cc
index d6b1782..1591394 100644
--- a/byte_repair.cc
+++ b/byte_repair.cc
@@ -58,6 +58,19 @@ bool gross_damage( const uint8_t * const mbuffer, const long msize )
}
+// Return value: 0 = errors remain, 6 = repaired pos
+int repair_nonzero( uint8_t * const mbuffer, const long msize )
+ {
+ mbuffer[6] = 0;
+ const Lzip_header & header = *(Lzip_header *)mbuffer;
+ const unsigned dictionary_size = header.dictionary_size();
+ if( !isvalid_ds( dictionary_size ) ) return 0;
+ LZ_mtester mtester( mbuffer, msize, dictionary_size );
+ if( mtester.test_member() == 0 ) return 6;
+ return 0;
+ }
+
+
// Return value: 0 = no change, 5 = repaired pos
int repair_dictionary_size( uint8_t * const mbuffer, const long msize )
{
@@ -155,6 +168,15 @@ long repair_member( uint8_t * const mbuffer, const long long mpos,
} // end namespace
+bool safe_seek( const int fd, const long long pos,
+ const std::string & filename )
+ {
+ if( lseek( fd, pos, SEEK_SET ) == pos ) return true;
+ show_file_error( filename.c_str(), "Seek error", errno );
+ return false;
+ }
+
+
long seek_write( const int fd, const uint8_t * const buf, const long size,
const long long pos )
{
@@ -165,16 +187,16 @@ long seek_write( const int fd, const uint8_t * const buf, const long size,
uint8_t * read_member( const int infd, const long long mpos,
- const long long msize, const char * const filename )
+ const long long msize, const std::string & filename )
{
if( msize <= 0 || msize > LONG_MAX )
- { show_file_error( filename,
+ { show_file_error( filename.c_str(),
"Input file contains member larger than LONG_MAX." ); return 0; }
if( !safe_seek( infd, mpos, filename ) ) return 0;
uint8_t * const buffer = new uint8_t[msize];
if( readblock( infd, buffer, msize ) != msize )
- { show_file_error( filename, read_error_msg, errno );
+ { show_file_error( filename.c_str(), read_error_msg, errno );
delete[] buffer; return 0; }
return buffer;
}
@@ -206,8 +228,10 @@ int byte_repair( const std::string & input_filename,
const long long msize = lzip_index.mblock( i ).size();
if( !safe_seek( infd, mpos, filename ) ) cleanup_and_fail( 1 );
long long failure_pos = 0;
- if( test_member_from_file( infd, msize, &failure_pos ) == 0 ) continue;
- if( failure_pos < Lzip_header::size ) // End Of File
+ bool nonzero = false;
+ const int ret = test_member_from_file( infd, msize, &failure_pos, &nonzero );
+ if( ret == 0 && !nonzero ) continue;
+ if( ret != 0 && failure_pos < Lzip_header::size ) // End Of File
{ show_error( "Can't repair error in input file." );
cleanup_and_fail( 2 ); }
if( failure_pos >= msize - 8 ) failure_pos = msize - 8 - 1;
@@ -218,14 +242,17 @@ int byte_repair( const std::string & input_filename,
i + 1, lzip_index.members(), mpos + failure_pos );
std::fflush( stdout );
}
- uint8_t * const mbuffer = read_member( infd, mpos, msize, filename );
+ uint8_t * const mbuffer = read_member( infd, mpos, msize, input_filename );
if( !mbuffer ) cleanup_and_fail( 1 );
const Lzip_header & header = *(const Lzip_header *)mbuffer;
const unsigned dictionary_size = header.dictionary_size();
long pos = 0;
+ if( !nonzero && mbuffer[6] != 0 ) nonzero = true; // bad DS
if( !gross_damage( mbuffer, msize ) )
{
- pos = repair_dictionary_size( mbuffer, msize );
+ if( nonzero ) pos = repair_nonzero( mbuffer, msize );
+ if( pos == 0 )
+ pos = repair_dictionary_size( mbuffer, msize );
if( pos == 0 )
pos = repair_member( mbuffer, mpos, msize, header.size + 1,
header.size + 6, dictionary_size, terminator );
@@ -243,12 +270,14 @@ int byte_repair( const std::string & input_filename,
if( !safe_seek( infd, 0, filename ) ) return 1;
set_signal_handler();
if( !open_outstream( true, true, false, true, to_file ) ) return 1;
- if( !copy_file( infd, outfd ) ) // copy whole file
- cleanup_and_fail( 1 );
+ if( !copy_file( infd, outfd, input_filename, output_filename ) )
+ cleanup_and_fail( 1 ); // copy whole file
}
- if( seek_write( outfd, mbuffer + pos, 1, mpos + pos ) != 1 )
- { show_error( "Error writing output file", errno );
- cleanup_and_fail( 1 ); }
+ if( ( nonzero && pos != 6 &&
+ seek_write( outfd, mbuffer + 6, 1, mpos + 6 ) != 1 ) ||
+ seek_write( outfd, mbuffer + pos, 1, mpos + pos ) != 1 )
+ { show_file_error( printable_name( output_filename, false ),
+ write_error_msg, errno ); cleanup_and_fail( 1 ); }
}
delete[] mbuffer;
if( pos == 0 )
@@ -272,24 +301,24 @@ int byte_repair( const std::string & input_filename,
}
-int debug_delay( const char * const input_filename,
+int debug_delay( const std::string & input_filename,
const Cl_options & cl_opts, Block range,
const char terminator )
{
+ const char * const filename = input_filename.c_str();
struct stat in_stats; // not used
- const int infd = open_instream( input_filename, &in_stats, false, true );
+ const int infd = open_instream( filename, &in_stats, false, true );
if( infd < 0 ) return 1;
const Lzip_index lzip_index( infd, cl_opts );
if( lzip_index.retval() != 0 )
- { show_file_error( input_filename, lzip_index.error().c_str() );
+ { show_file_error( filename, lzip_index.error().c_str() );
return lzip_index.retval(); }
if( range.end() > lzip_index.cdata_size() )
range.size( std::max( 0LL, lzip_index.cdata_size() - range.pos() ) );
if( range.size() <= 0 )
- { show_file_error( input_filename, "Nothing to do; range is empty." );
- return 0; }
+ { show_file_error( filename, "Nothing to do; range is empty." ); return 0; }
for( long i = 0; i < lzip_index.members(); ++i )
{
@@ -355,24 +384,25 @@ int debug_delay( const char * const input_filename,
}
-int debug_byte_repair( const char * const input_filename,
+int debug_byte_repair( const std::string & input_filename,
const Cl_options & cl_opts, const Bad_byte & bad_byte,
const char terminator )
{
+ const char * const filename = input_filename.c_str();
struct stat in_stats; // not used
- const int infd = open_instream( input_filename, &in_stats, false, true );
+ const int infd = open_instream( filename, &in_stats, false, true );
if( infd < 0 ) return 1;
const Lzip_index lzip_index( infd, cl_opts );
if( lzip_index.retval() != 0 )
- { show_file_error( input_filename, lzip_index.error().c_str() );
+ { show_file_error( filename, lzip_index.error().c_str() );
return lzip_index.retval(); }
long idx = 0;
for( ; idx < lzip_index.members(); ++idx )
if( lzip_index.mblock( idx ).includes( bad_byte.pos ) ) break;
if( idx >= lzip_index.members() )
- { show_file_error( input_filename, "Nothing to do; byte is beyond EOF." );
+ { show_file_error( filename, "Nothing to do; byte is beyond EOF." );
return 0; }
const long long mpos = lzip_index.mblock( idx ).pos();
@@ -392,11 +422,12 @@ int debug_byte_repair( const char * const input_filename,
if( !mbuffer ) return 1;
const Lzip_header & header = *(const Lzip_header *)mbuffer;
const unsigned dictionary_size = header.dictionary_size();
- const uint8_t good_value = mbuffer[bad_byte.pos-mpos];
+ const long long bad_pos = bad_byte.pos - mpos;
+ const uint8_t good_value = mbuffer[bad_pos];
const uint8_t bad_value = bad_byte( good_value );
- mbuffer[bad_byte.pos-mpos] = bad_value;
+ mbuffer[bad_pos] = bad_value;
long failure_pos = 0;
- if( bad_byte.pos != 5 || isvalid_ds( header.dictionary_size() ) )
+ if( bad_pos != 5 || isvalid_ds( header.dictionary_size() ) )
{
LZ_mtester mtester( mbuffer, msize, header.dictionary_size() );
if( mtester.test_member() == 0 && mtester.finished() )
@@ -420,6 +451,8 @@ int debug_byte_repair( const char * const input_filename,
if( failure_pos >= msize ) failure_pos = msize - 1;
long pos = repair_dictionary_size( mbuffer, msize );
if( pos == 0 )
+ if( mbuffer[6] != 0 ) pos = repair_nonzero( mbuffer, msize );
+ if( pos == 0 )
pos = repair_member( mbuffer, mpos, msize, header.size + 1,
header.size + 6, dictionary_size, terminator );
if( pos == 0 )
@@ -441,21 +474,21 @@ int debug_byte_repair( const char * const input_filename,
(Packet sizes are a fractionary number of bytes. The packet and marker
sizes shown by option -X are the number of extra bytes required to decode
the packet, not counting the data present in the range decoder before and
- after the decoding. The max marker size of a 'Sync Flush marker' does not
- include the 5 bytes read by rdec.load).
+ after the decoding.
if bad_byte.pos >= cdata_size, bad_byte is ignored.
*/
-int debug_decompress( const char * const input_filename,
+int debug_decompress( const std::string & input_filename,
const Cl_options & cl_opts, const Bad_byte & bad_byte,
const bool show_packets )
{
+ const char * const filename = input_filename.c_str();
struct stat in_stats;
- const int infd = open_instream( input_filename, &in_stats, false, true );
+ const int infd = open_instream( filename, &in_stats, false, true );
if( infd < 0 ) return 1;
const Lzip_index lzip_index( infd, cl_opts );
if( lzip_index.retval() != 0 )
- { show_file_error( input_filename, lzip_index.error().c_str() );
+ { show_file_error( filename, lzip_index.error().c_str() );
return lzip_index.retval(); }
outfd = show_packets ? -1 : STDOUT_FILENO;