#!/usr/bin/perl

# ipd2tgz version 0.1

# Copyright (C) 2008, ashley willis <barry@venamous.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License in the COPYING file at the
# root directory of this project for more details.

# converts file <BASENAME>.ipd to <BASENAME>.tar.gz, in the format of
# barrybackup.

# NOTES for yet-to-be tgz2ipd:
# dbRecordLength  = computed
# dbVersion       = second part of name
# dbRecordHandler = (last dbRecordHandler) + (# of records in last db) + 1
# recordID        = first part of name

$BINARY  = 0;		# must be 0

$VERBOSE         = 0;	# optional
$DBID            = 1;	# must be 1
$DBRECORDLENGTH  = 1;	# must be 1
$DBRECORDHANDLER = 1;	# must be 1
$FIELDLENGTH     = 0;	# optional

if ($VERBOSE) {
  $DBID            = 1;
  $DBRECORDLENGTH  = 1;
  $DBRECORDHANDLER = 1;
  $FIELDLENGTH     = 1;
}

foreach $file (@ARGV) {
  open(IN, "$file");
  $tmpdir = "$0-$$";
  $tmpdir =~ s/^.*\//\/tmp\//;
  print "$tmpdir\n";
  mkdir($tmpdir);

  # overall header = 42 bytes
  read(IN, $header, 38);
  unless ($header =~ /^Inter\@ctive Pager Backup\/Restore File\n$/) {
    print STDERR "Not a valid IPD file: $file\n";
    next;
  }
  read(IN, $ipdVersion, 1);
  unless ($ipdVersion =~ //) {
    print STDERR"Unknown IPD version: " . Bin2dec($ipdVersion) . "\n";
    next;
  }
  read(IN, $numberOfDBs, 2);
  read(IN, $separator, 1);	# ==  
  unless ($separator =~ / /) {
    print STDERR "Unknown error 1: Invalid separator\n";
    next;
  }
  $numberOfDBsTXT = bin2dec($numberOfDBs);

  # get database names
  undef @dbnames;
  for ($db = 1; $db <= $numberOfDBsTXT; $db++) {
    read(IN, $dbNameLength, 2);
    $dbNameLengthTXT = Bin2dec($dbNameLength);
    read(IN, $dbName, $dbNameLengthTXT);
    unless ($dbName =~ s/ $//) {
      print STDERR "Unknown error 2: Invalid dbName end\n";
      next;
    }
    $dbNames[$db-1] = $dbName;
  }

  # parse the database entries
  while(read(IN, $dbID, 2)) {
    undef $dbIDTXT, $dbRecordLength, $dbRecordLengthTXT, $dbVersion,
          $dbRecordHandler, $recordID, $fieldLength, $fieldLengthTXT,
          $fieldType, $fieldData;
    $dbIDTXT = Bin2dec(reverse($dbID));
    read(IN, $dbRecordLength, 4);
    $dbRecordLengthTXT = Bin2dec($dbRecordLength);
    read(IN, $dbVersion, 1);
    read(IN, $dbRecordHandler, 2);
    read(IN, $recordID, 4);

    $recordIDTXT = unpack ("H*", reverse($recordID));
    $recordIDTXT =~ s/^0+//;
    (!$recordIDTXT) and $recordIDTXT = "0";
    $dbVersionTXT = unpack ("H*", reverse($dbVersion));
    $dbVersionTXT =~ s/^0+//;
    (!$dbVersionTXT) and $dbVersionTXT = "0";
    $newfile = "$recordIDTXT $dbVersionTXT";
    mkdir("$tmpdir/$dbNames[$dbIDTXT]");
    ($dirs =~ /\"$dbNames[$dbIDTXT]\" /) or $dirs .= "\"$dbNames[$dbIDTXT]\" ";
    open(OUT,">>$tmpdir/$dbNames[$dbIDTXT]/$newfile");
    $c = 7;
    while($c < $dbRecordLengthTXT) {
      read(IN, $fieldLength, 2);
      $fieldLengthTXT = Bin2dec($fieldLength);
      read(IN, $fieldType, 1);
      read(IN, $fieldData, $fieldLengthTXT);
      $c += 3 + $fieldLengthTXT;
      print OUT "$fieldLength$fieldType$fieldData";
    }
    close(OUT);
  }
  $tgz = $file;
  $tgz =~ s/\.ipd$/\.tar.gz/;
  `tar zcf "$tgz" -C $tmpdir $dirs`;
  `rm -rf $tmpdir`;
}

sub bin2dec() {
  return hex(unpack ("H*", $_[0]));
}

sub Bin2dec() {
  return hex(unpack ("H*", reverse($_[0])));
}
