#!/usr/bin/perl -w use strict; # A small script to convert current-style KOffice tar storages to storages # compatible with KOffice 1.0 and KOffice 1.1(.1) # Note to developers: # Add the PID (in Perl: $$ ) to all fixed temporary directory/file names, # so that this script can be run multiple times at once. # Holds the directory tree my @rootdir; my $tmpdir = "/tmp/kofficeconverter$$" ; print "Using temporary directory... $tmpdir\n"; # Holds the source/dest of the files to fix my @needFixing; # Walk the whole archive and collect information about the files # This creates one array, containing another array for every directory # we found (recursively). Additionally this array holding a directory # holds the name of the directory and the path. sub explore { my($path) = @_; my(@dir); print " Exploring: $path\n"; chdir($path); opendir(DIR, $path) || die "Couldn't open the directory: $!"; my @contents = readdir(DIR); my $i = 0; foreach(@contents) { if($_ eq "." || $_ eq "..") { next; # we're not intersted in . and .. } if(-d $_) { $dir[$i] = [ $_, $path, [ explore($path . '/' . $_) ] ]; chdir($path); # back to the directory where we come from } else { $dir[$i] = $_; } $i = $i + 1; } closedir(DIR); return @dir; } # Dumps the scary datastructure we built sub dumpTree { my(@dir) = @_; foreach(@dir) { if(ref($_) eq 'ARRAY') { print $_->[0], " (", $_->[1], ")\n"; dumpTree(@{$_->[2]}); } else { print $_ . "\n"; } } } # Finds the files where we have to fix part references (->maindoc.xml) sub findCandidates { my($dref, $currentdir, $parentdir) = @_; my @dir = @{$dref}; #print "current: $currentdir, parentdir: $parentdir\n"; foreach(@dir) { if(ref($_) eq 'ARRAY') { #print $_->[0], " (", $_->[1], ")\n"; findCandidates(\@{$_->[2]}, $_->[0], $_->[1]); } else { if($_ =~ m/maindoc\.xml/) { my $source = $parentdir . '/' . $currentdir . "/maindoc.xml"; my $dest = $parentdir . '/' . $currentdir . ".xml"; push(@needFixing, [ $source, $dest ]); } } } } # No need to move around elements of the root directory, these are handled # separately anyway. Therefore we call findCandidates only on subdirs sub findMainDocuments { foreach(@rootdir) { if(ref($_) eq 'ARRAY') { findCandidates(\@{$_->[2]}, $_->[0], $_->[1]); } } } # Factorizes the common regexp code between maindoc.xml and parts sub fixLine { my($line, $prefix) = @_; if($line =~ m/(\s*\[0], length($tmpdir)+1; $prefix =~ m,^(.*?)(maindoc\.xml),; $prefix = "tar:/" . $1; open(SOURCE, "<$item->[0]") || die "Couldn't open the source file: $!\n"; open(DEST, ">$item->[1]") || die "Couldn't open the destination file: $!\n"; while() { print DEST fixLine($_, $prefix); } close(SOURCE); close(DEST); } } # Get rid of the moved files sub removeOldFiles { foreach(@needFixing) { system("rm -rf $_->[0]"); } } # Special case for the main document as we have to use a temporary # file and stuff like that. We only have to fix part references here. sub fixMainDocument { open(SOURCE, "<$tmpdir/maindoc.xml"); open(DEST, ">$tmpdir/tmp.xml"); while() { print DEST fixLine($_, "tar:/"); } close(SOURCE); close(DEST); system("mv $tmpdir/tmp.xml $tmpdir/maindoc.xml"); } ################################################## # The execution starts here ################################################## if($#ARGV != 1) { print "Script to convert current storages to KOffice 1.0/1.1.x compatible ones.\n"; print "Usage: perl fix_storage.pl \n"; exit(1); } # remember where we came from chomp(my $cwd = `pwd`); # clean up properly system("rm -rf $tmpdir"); mkdir $tmpdir || die "Couldn't create tmp directory: $!\n"; print "Trying to detect the type of archive... "; my($mime) = `file -i -z $ARGV[0]`; if($mime =~ m,application/x-tar,) { print "tar.gz\n"; print "Uncompressing the archive...\n"; system("tar -C $tmpdir -xzf $ARGV[0]"); } elsif($mime =~ m,application/x-zip,) { print "zip\n"; print "Uncompressing the archive...\n"; system("unzip -qq -d $tmpdir $ARGV[0]"); } print "Browsing the directory structure...\n"; @rootdir = explore($tmpdir); # debugging #dumpTree(@rootdir); print "Find candidates for moving...\n"; findMainDocuments(); print "Moving and fixing relative links...\n"; fixLinks(); removeOldFiles(); fixMainDocument(); print "Creating the archive...\n"; chdir($tmpdir); system("tar czf tmp$$.tgz *"); chdir ($cwd); system("mv $tmpdir/tmp$$.tgz $ARGV[1]"); print "Cleaning up...\n"; # clean up properly system("rm -rf $tmpdir"); print "Done.\n";