#!/usr/bin/perl
if($#ARGV ne 1){
  print "TO update to a single xref table (unix format)\n";
  print "USAGE: uppdf.pl infile.pdf outfile.pdf\n";
}else{
$infile = $ARGV[0];
$outfile = $ARGV[1];
#
open(Lista,"<$infile")||die "Can't open the file";
open(OUT,">$outfile")||die "Can't open the file";
#
##################################
#
#  This is the program that does all the counting
#  if you hack a PDF in a text editor: remove a page, swap 
#  pages, change a bounding box, run this program
#  update the xref table and the startxref address at the
#  end. If there is more than one xref, this program might
#  fail without warning, however, it attempts to construct
#  a single xref table out of multiple tables.
#
@listind = <Lista>;
#
$numberobj = 0;
$size = 0;
#
# the BYTE COUNT starts at one and marks the \n before the obj at hand
#
$count = 0;
$tail = 0;
$body = 1;
#
#
 select(OUT);
 for $i (@listind){
#
#  encountered xref, which is the blur we ignore
#
   if($i =~ /xref/){
     $body = 0;
     $xrefaddress = $count;
   }
   if($body eq 1){
#
#  for every object we store the byte address and the 
#  generation number to write in the xref table at the end.
#
    if($i =~ /(\d+)\s+(\d+)\s+obj/i){
     $objnumber = $1;
     @objgen[$objnumber-1] = $2;
     if($numberobj < $objnumber){
        $numberobj = $objnumber;
     }
     @objaddress[$objnumber-1] = $count;
    }
    $count += length($i);
    print $i;
   }else{
#
#   we store trailer info in the string $trailer. Some
#   info is double (Size, ID, >>), some info is superfluous (Prev).
#
    if($i =~ /trailer/){
      $tail = 1;
    }
#
#   startxref signals the end of the trailer
#
    if($i =~ /startxref/){
    $tail = 0;
    }
#
    if($tail eq 1){
      $i =~ s/trailer//;
      $i =~ s/>>//;
      $i =~ s/<<//;
      $i =~ s/\/Prev\s+\S+//;
      if($i =~ s/(\/Size\s+\S+)//){
            $size = $1;
      }
#
#     the ID is for password protection release
#     and appears in every xref.
#     A wrong or absent ID leads to a password query
#     in acrobat reader.
#
      if($i =~ s/(\/ID\S+)//){
         $id = $1;
      }
      $trailer .= $i;
    }
  }
#
#  the end of an intermediate xref is signalled by a new object
#
  if($i =~ / obj/){
     if($body eq 0){
       print $i;
     }
     $tail = 0;
     $body = 1;
  }
 }
#
#  OK, lets make mister tape drive happy:
#  (using the simplest way to get a 000000nnnn 000nn format)
#
   $trailer =~ s/\n//g;
   $trailer =~ s/\//\n\//g;
   $trailer =~ s/^\n//;
   $id =~ s/\//\n\//;
   $size =~ s/\//\n\//;
#
   print "xref\n";
   print "0 ".($numberobj+1)."\n";
   print "0000000000 65535 f \n";
   for($thisobj = 0; $thisobj < $numberobj; $thisobj++){
      $bigobj = 10000000000 + @objaddress[$thisobj];
      $biggen = 100000 + @objgen[$thisobj];
      print substr($bigobj,1,10)." ";
      print  substr($biggen,1,5)." n \n";
   }
   print "trailer\n\<\<\n".$trailer;
   print "$size";
   print "$id";
   print "\n\>\>\n";
   print "startxref\n";
   print $xrefaddress."\n";
   print "%%EOF\n";
   close(Lista);
  close(OUT);
}
