#!/usr/bin/perl -w
use strict;
my $filename_raw='f45015.zip';
my $debug=0;
{
  my $zip_test='zip_status.txt';
  system('unzip -t '.$filename_raw.' &> '.$zip_test);
#unzip -t f45015.zip
#Archive:  f45015.zip
#warning [f45015.zip]:  1536 extra bytes at beginning or within zipfile
#  (attempting to process anyway)
#file #1:  bad zipfile offset (local header sig):  1536
#  (attempting to re-compensate)
#    testing: 1993-01-a-large_web.jpg   OK
#    testing: 1995-45-a-large_web.jpg   OK
#    testing: 2000-06-a-large_web.jpg   OK
#    testing: 2000-07-a-large_web.jpg   OK
#    testing: 2002-29-a-large_web.jpg
#  error:  invalid compressed data to inflate
#file #6:  bad zipfile offset (local header sig):  214071
#  (attempting to re-compensate)
#    testing: 2005-02-e-large_web.jpg   OK
#At least one error was detected in f45015.zip.
  my $extra_sectors=0;
  my $file_hs=0;
  my $err=0;
  open(IN, '<',$zip_test) or die("Can't open file $zip_test: $!\n");
  while(my $line=<IN>)
  {
    if($line=~/(\d+) extra bytes at beginning or within zipfile/)
    {
      my $extra_bytes=$1;
      print "Can't repair file" if($extra_bytes%512!=0);
      $extra_sectors=int($extra_bytes/512);
    }
    $err=1 if($line=~/error:/);
    if($err)
    {
      if($line=~/file #(\d+):/)
      {
	$file_hs=$1;
      }
    }
  }
  close(IN);
  $file_hs--;
  if($debug>0)
  {
    print "extra_sectors $extra_sectors\n";
    print "file_hs $file_hs\n";
  }
  system('unzip -lv '.$filename_raw.' &> '.$zip_test);
# unzip -lv f45015.zip
#Archive:  f45015.zip
#warning [f45015.zip]:  1536 extra bytes at beginning or within zipfile
#  (attempting to process anyway)
# Length   Method    Size  Ratio   Date   Time   CRC-32    Name
#--------  ------  ------- -----   ----   ----   ------    ----
#   62179  Defl:N    62104   0%  05-09-06 04:35  5aed4c0d  1993-01-a-large_web.jpg
#   37157  Defl:N    37045   0%  05-09-06 04:36  478c0fc8  1995-45-a-large_web.jpg
#   44808  Defl:N    44761   0%  05-09-06 04:34  9fd5a0be  2000-06-a-large_web.jpg
#   28740  Defl:N    27158   6%  05-09-06 04:35  719afc30  2000-07-a-large_web.jpg
#   42629  Defl:N    42578   0%  05-09-06 04:35  460a300d  2002-29-a-large_web.jpg
#   55610  Defl:N    55517   0%  05-09-06 04:35  5e9dd573  2005-02-e-large_web.jpg
#--------          -------  ---                            -------
#  271123           269163   1%                            6 files
#
# 62104+37045+44761+27158=171068 => 334
  my $zip_start=0;
  open(IN, '<',$zip_test) or die("Can't open file $zip_test: $!\n");
  while(my $line=<IN>)
  {
    if($line=~/\d+\s+\S+\s+(\d+)/)
    {
      $zip_start+=$1 if(--$file_hs>0);
    }
  }
  close(IN);
  $zip_start=int($zip_start/512);
  my $zip_end=int((-s $filename_raw)/512);
  if($debug>0)
  {
    print "zip_start $zip_start\n";
    print "zip_end   $zip_end\n";
  }
  open(IN,'<',$filename_raw) or die("Can't open $filename_raw: $!\n");
  {
    my $filename_tmp='test.zip';
    my $err=9;
    my $offset;
    for($offset=$zip_start;$offset<$zip_end && $err!=0;$offset++)
    {
      open(OUT,'>',$filename_tmp) or die("Can't create $filename_tmp: $!\n");
      my $len=1;
      for(my $sector=0;$len>0;$sector++)
      {
	my $buffer;
	if($sector>=$offset && $sector<$offset+$extra_sectors)
	{
	}
	else
	{
	  sysseek(IN,512*$sector,0);
	  $len=sysread(IN,$buffer,512);
	  syswrite(OUT,$buffer);
	}
      }
      close(OUT);
      $err=0;
      system('unzip -t '.$filename_tmp.' > /dev/null 2> '.$zip_test);
      if ($? == -1) {
	print "failed to execute: $!\n";
      }
      elsif ($? & 127) {
	printf "child died with signal %d, %s coredump\n",
	       ($? & 127),  ($? & 128) ? 'with' : 'without';
      }
      else {
	$err=$? >> 8;
      }
      if( -s $zip_test > 0)
      {
	$err=1;
      }
    }
    if($err==0)
    {
      print "Found ".$extra_sectors." extra data 512-bytes block at block ".$offset."\n";
      print "Fixed file is ".$filename_tmp."\n";
    }
  }
  close(IN);
}
