1c9b362f6SAndre Fischer#************************************************************** 2c9b362f6SAndre Fischer# 3c9b362f6SAndre Fischer# Licensed to the Apache Software Foundation (ASF) under one 4c9b362f6SAndre Fischer# or more contributor license agreements. See the NOTICE file 5c9b362f6SAndre Fischer# distributed with this work for additional information 6c9b362f6SAndre Fischer# regarding copyright ownership. The ASF licenses this file 7c9b362f6SAndre Fischer# to you under the Apache License, Version 2.0 (the 8c9b362f6SAndre Fischer# "License"); you may not use this file except in compliance 9c9b362f6SAndre Fischer# with the License. You may obtain a copy of the License at 10c9b362f6SAndre Fischer# 11c9b362f6SAndre Fischer# http://www.apache.org/licenses/LICENSE-2.0 12c9b362f6SAndre Fischer# 13c9b362f6SAndre Fischer# Unless required by applicable law or agreed to in writing, 14c9b362f6SAndre Fischer# software distributed under the License is distributed on an 15c9b362f6SAndre Fischer# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16c9b362f6SAndre Fischer# KIND, either express or implied. See the License for the 17c9b362f6SAndre Fischer# specific language governing permissions and limitations 18c9b362f6SAndre Fischer# under the License. 19c9b362f6SAndre Fischer# 20c9b362f6SAndre Fischer#************************************************************** 21c9b362f6SAndre Fischer 22c9b362f6SAndre Fischerpackage installer::patch::Msi; 23c9b362f6SAndre Fischer 24c9b362f6SAndre Fischeruse installer::patch::MsiTable; 25c9b362f6SAndre Fischeruse installer::patch::Tools; 269f91b7e3SAndre Fischeruse installer::patch::InstallationSet; 279f91b7e3SAndre Fischer 289f91b7e3SAndre Fischeruse File::Basename; 299f91b7e3SAndre Fischeruse File::Copy; 309f91b7e3SAndre Fischer 31c9b362f6SAndre Fischeruse strict; 32c9b362f6SAndre Fischer 33c9b362f6SAndre Fischer 34c9b362f6SAndre Fischer=head1 NAME 35c9b362f6SAndre Fischer 36c9b362f6SAndre Fischer package installer::patch::Msi - Class represents a single MSI file and gives access to its tables. 37c9b362f6SAndre Fischer 38c9b362f6SAndre Fischer=cut 39c9b362f6SAndre Fischer 409f91b7e3SAndre Fischersub FindAndCreate($$$$$) 419f91b7e3SAndre Fischer{ 429f91b7e3SAndre Fischer my ($class, $version, $is_current_version, $language, $product_name) = @_; 439f91b7e3SAndre Fischer 449f91b7e3SAndre Fischer my $condensed_version = $version; 459f91b7e3SAndre Fischer $condensed_version =~ s/\.//g; 469f91b7e3SAndre Fischer 479f91b7e3SAndre Fischer # When $version is the current version we have to search the msi at a different place. 489f91b7e3SAndre Fischer my $path; 499f91b7e3SAndre Fischer my $filename; 509f91b7e3SAndre Fischer my $is_current = 0; 519f91b7e3SAndre Fischer $path = installer::patch::InstallationSet::GetUnpackedExePath( 529f91b7e3SAndre Fischer $version, 539f91b7e3SAndre Fischer $is_current_version, 54*60b96b8dSAndre Fischer installer::languages::get_normalized_language($language), 559f91b7e3SAndre Fischer "msi", 569f91b7e3SAndre Fischer $product_name); 579f91b7e3SAndre Fischer 589f91b7e3SAndre Fischer # Find the msi in the path.ls . 599f91b7e3SAndre Fischer $filename = File::Spec->catfile($path, "openoffice".$condensed_version.".msi"); 609f91b7e3SAndre Fischer $is_current = $is_current_version; 619f91b7e3SAndre Fischer 629f91b7e3SAndre Fischer return $class->new($filename, $version, $is_current, $language, $product_name); 639f91b7e3SAndre Fischer} 64c9b362f6SAndre Fischer 65c9b362f6SAndre Fischer 669f91b7e3SAndre Fischer 679f91b7e3SAndre Fischer 689f91b7e3SAndre Fischer 699f91b7e3SAndre Fischer 709f91b7e3SAndre Fischer=head2 new($class, $filename, $version, $is_current_version, $language, $product_name) 71c9b362f6SAndre Fischer 72c9b362f6SAndre Fischer Create a new object of the Msi class. The values of $version, $language, and $product_name define 73c9b362f6SAndre Fischer where to look for the msi file. 74c9b362f6SAndre Fischer 75c9b362f6SAndre Fischer If construction fails then IsValid() will return false. 76c9b362f6SAndre Fischer 77c9b362f6SAndre Fischer=cut 78*60b96b8dSAndre Fischer 799f91b7e3SAndre Fischersub new ($$$$$$) 80c9b362f6SAndre Fischer{ 819f91b7e3SAndre Fischer my ($class, $filename, $version, $is_current_version, $language, $product_name) = @_; 82c9b362f6SAndre Fischer 83c9b362f6SAndre Fischer if ( ! -f $filename) 84c9b362f6SAndre Fischer { 859f91b7e3SAndre Fischer installer::logger::PrintError("can not find the .msi file for version %s and language %s at '%s'\n", 869f91b7e3SAndre Fischer $version, 879f91b7e3SAndre Fischer $language, 889f91b7e3SAndre Fischer $filename); 89c9b362f6SAndre Fischer return undef; 90c9b362f6SAndre Fischer } 91c9b362f6SAndre Fischer 92c9b362f6SAndre Fischer my $self = { 93c9b362f6SAndre Fischer 'filename' => $filename, 949f91b7e3SAndre Fischer 'path' => dirname($filename), 95c9b362f6SAndre Fischer 'version' => $version, 969f91b7e3SAndre Fischer 'is_current_version' => $is_current_version, 97c9b362f6SAndre Fischer 'language' => $language, 98c9b362f6SAndre Fischer 'package_format' => "msi", 99c9b362f6SAndre Fischer 'product_name' => $product_name, 100c9b362f6SAndre Fischer 'tmpdir' => File::Temp->newdir(CLEANUP => 1), 101c9b362f6SAndre Fischer 'is_valid' => -f $filename 102c9b362f6SAndre Fischer }; 103c9b362f6SAndre Fischer bless($self, $class); 104c9b362f6SAndre Fischer 105c9b362f6SAndre Fischer return $self; 106c9b362f6SAndre Fischer} 107c9b362f6SAndre Fischer 108c9b362f6SAndre Fischer 109c9b362f6SAndre Fischer 110c9b362f6SAndre Fischer 111c9b362f6SAndre Fischersub IsValid ($) 112c9b362f6SAndre Fischer{ 113c9b362f6SAndre Fischer my ($self) = @_; 114c9b362f6SAndre Fischer 115c9b362f6SAndre Fischer return $self->{'is_valid'}; 116c9b362f6SAndre Fischer} 117c9b362f6SAndre Fischer 118c9b362f6SAndre Fischer 119c9b362f6SAndre Fischer 120c9b362f6SAndre Fischer 1219f91b7e3SAndre Fischer=head2 Commit($self) 1229f91b7e3SAndre Fischer 1239f91b7e3SAndre Fischer Write all modified tables back into the databse. 1249f91b7e3SAndre Fischer 1259f91b7e3SAndre Fischer=cut 126*60b96b8dSAndre Fischer 1279f91b7e3SAndre Fischersub Commit ($) 1289f91b7e3SAndre Fischer{ 1299f91b7e3SAndre Fischer my $self = shift; 1309f91b7e3SAndre Fischer 1319f91b7e3SAndre Fischer my @tables_to_update = (); 1329f91b7e3SAndre Fischer foreach my $table (values %{$self->{'tables'}}) 1339f91b7e3SAndre Fischer { 1349f91b7e3SAndre Fischer push @tables_to_update,$table if ($table->IsModified()); 1359f91b7e3SAndre Fischer } 1369f91b7e3SAndre Fischer 1379f91b7e3SAndre Fischer if (scalar @tables_to_update > 0) 1389f91b7e3SAndre Fischer { 1399f91b7e3SAndre Fischer $installer::logger::Info->printf("writing modified tables to database:\n"); 1409f91b7e3SAndre Fischer foreach my $table (@tables_to_update) 1419f91b7e3SAndre Fischer { 1429f91b7e3SAndre Fischer $installer::logger::Info->printf(" %s\n", $table->GetName()); 1439f91b7e3SAndre Fischer $self->PutTable($table); 1449f91b7e3SAndre Fischer } 1459f91b7e3SAndre Fischer 1469f91b7e3SAndre Fischer foreach my $table (@tables_to_update) 1479f91b7e3SAndre Fischer { 1489f91b7e3SAndre Fischer $table->UpdateTimestamp(); 1499f91b7e3SAndre Fischer $table->MarkAsUnmodified(); 1509f91b7e3SAndre Fischer } 1519f91b7e3SAndre Fischer } 1529f91b7e3SAndre Fischer} 1539f91b7e3SAndre Fischer 1549f91b7e3SAndre Fischer 1559f91b7e3SAndre Fischer 1569f91b7e3SAndre Fischer 157c9b362f6SAndre Fischer=head2 GetTable($seld, $table_name) 158c9b362f6SAndre Fischer 159c9b362f6SAndre Fischer Return an MsiTable object for $table_name. Table objects are kept 160c9b362f6SAndre Fischer alive for the life time of the Msi object. Therefore the second 161c9b362f6SAndre Fischer call for the same table is very cheap. 162c9b362f6SAndre Fischer 163c9b362f6SAndre Fischer=cut 164*60b96b8dSAndre Fischer 165c9b362f6SAndre Fischersub GetTable ($$) 166c9b362f6SAndre Fischer{ 167c9b362f6SAndre Fischer my ($self, $table_name) = @_; 168c9b362f6SAndre Fischer 169c9b362f6SAndre Fischer my $table = $self->{'tables'}->{$table_name}; 170c9b362f6SAndre Fischer if ( ! defined $table) 171c9b362f6SAndre Fischer { 172c9b362f6SAndre Fischer my $table_filename = File::Spec->catfile($self->{'tmpdir'}, $table_name .".idt"); 173c9b362f6SAndre Fischer if ( ! -f $table_filename 174c9b362f6SAndre Fischer || ! EnsureAYoungerThanB($table_filename, $self->{'fullname'})) 175c9b362f6SAndre Fischer { 176c9b362f6SAndre Fischer # Extract table from database to text file on disk. 177c9b362f6SAndre Fischer my $truncated_table_name = length($table_name)>8 ? substr($table_name,0,8) : $table_name; 178c9b362f6SAndre Fischer my $command = join(" ", 179c9b362f6SAndre Fischer "msidb.exe", 1809f91b7e3SAndre Fischer "-d", installer::patch::Tools::ToEscapedWindowsPath($self->{'filename'}), 1819f91b7e3SAndre Fischer "-f", installer::patch::Tools::ToEscapedWindowsPath($self->{'tmpdir'}), 182c9b362f6SAndre Fischer "-e", $table_name); 183c9b362f6SAndre Fischer my $result = qx($command); 184c9b362f6SAndre Fischer print $result; 185c9b362f6SAndre Fischer } 186c9b362f6SAndre Fischer 187c9b362f6SAndre Fischer # Read table into memory. 188c9b362f6SAndre Fischer $table = new installer::patch::MsiTable($table_filename, $table_name); 189c9b362f6SAndre Fischer $self->{'tables'}->{$table_name} = $table; 190c9b362f6SAndre Fischer } 191c9b362f6SAndre Fischer 192c9b362f6SAndre Fischer return $table; 193c9b362f6SAndre Fischer} 194c9b362f6SAndre Fischer 195c9b362f6SAndre Fischer 196c9b362f6SAndre Fischer 197c9b362f6SAndre Fischer 1989f91b7e3SAndre Fischer=head2 PutTable($self, $table) 1999f91b7e3SAndre Fischer 2009f91b7e3SAndre Fischer Write the given table back to the databse. 2019f91b7e3SAndre Fischer 2029f91b7e3SAndre Fischer=cut 203*60b96b8dSAndre Fischer 2049f91b7e3SAndre Fischersub PutTable ($$) 2059f91b7e3SAndre Fischer{ 2069f91b7e3SAndre Fischer my ($self, $table) = @_; 2079f91b7e3SAndre Fischer 2089f91b7e3SAndre Fischer # Create text file from the current table content. 2099f91b7e3SAndre Fischer $table->WriteFile(); 2109f91b7e3SAndre Fischer 2119f91b7e3SAndre Fischer my $table_name = $table->GetName(); 2129f91b7e3SAndre Fischer 2139f91b7e3SAndre Fischer # Store table from text file into database. 2149f91b7e3SAndre Fischer my $table_filename = $table->{'filename'}; 2159f91b7e3SAndre Fischer 2169f91b7e3SAndre Fischer if (length($table_name) > 8) 2179f91b7e3SAndre Fischer { 2189f91b7e3SAndre Fischer # The file name of the table data must not be longer than 8 characters (not counting the extension). 2199f91b7e3SAndre Fischer # The name passed as argument to the -i option may be longer. 2209f91b7e3SAndre Fischer my $truncated_table_name = substr($table_name,0,8); 2219f91b7e3SAndre Fischer my $table_truncated_filename = File::Spec->catfile( 2229f91b7e3SAndre Fischer dirname($table_filename), 2239f91b7e3SAndre Fischer $truncated_table_name.".idt"); 2249f91b7e3SAndre Fischer File::Copy::copy($table_filename, $table_truncated_filename) || die("can not create table file with short name"); 2259f91b7e3SAndre Fischer } 2269f91b7e3SAndre Fischer 2279f91b7e3SAndre Fischer my $command = join(" ", 2289f91b7e3SAndre Fischer "msidb.exe", 2299f91b7e3SAndre Fischer "-d", installer::patch::Tools::ToEscapedWindowsPath($self->{'filename'}), 2309f91b7e3SAndre Fischer "-f", installer::patch::Tools::ToEscapedWindowsPath($self->{'tmpdir'}), 2319f91b7e3SAndre Fischer "-i", $table_name); 2329f91b7e3SAndre Fischer my $result = system($command); 2339f91b7e3SAndre Fischer 2349f91b7e3SAndre Fischer if ($result != 0) 2359f91b7e3SAndre Fischer { 2369f91b7e3SAndre Fischer installer::logger::PrintError("writing table '%s' back to database failed", $table_name); 2379f91b7e3SAndre Fischer # For error messages see http://msdn.microsoft.com/en-us/library/windows/desktop/aa372835%28v=vs.85%29.aspx 2389f91b7e3SAndre Fischer } 2399f91b7e3SAndre Fischer} 2409f91b7e3SAndre Fischer 2419f91b7e3SAndre Fischer 2429f91b7e3SAndre Fischer 2439f91b7e3SAndre Fischer 244c9b362f6SAndre Fischer=head2 EnsureAYoungerThanB ($filename_a, $filename_b) 245c9b362f6SAndre Fischer 246c9b362f6SAndre Fischer Internal function (not a method) that compares to files according 247c9b362f6SAndre Fischer to their last modification times (mtime). 248c9b362f6SAndre Fischer 249c9b362f6SAndre Fischer=cut 250*60b96b8dSAndre Fischer 251c9b362f6SAndre Fischersub EnsureAYoungerThanB ($$) 252c9b362f6SAndre Fischer{ 253c9b362f6SAndre Fischer my ($filename_a, $filename_b) = @_; 254c9b362f6SAndre Fischer 255c9b362f6SAndre Fischer die("file $filename_a does not exist") unless -f $filename_a; 256c9b362f6SAndre Fischer die("file $filename_b does not exist") unless -f $filename_b; 257c9b362f6SAndre Fischer 258c9b362f6SAndre Fischer my @stat_a = stat($filename_a); 259c9b362f6SAndre Fischer my @stat_b = stat($filename_b); 260c9b362f6SAndre Fischer 261c9b362f6SAndre Fischer if ($stat_a[9] <= $stat_b[9]) 262c9b362f6SAndre Fischer { 263c9b362f6SAndre Fischer return 0; 264c9b362f6SAndre Fischer } 265c9b362f6SAndre Fischer else 266c9b362f6SAndre Fischer { 267c9b362f6SAndre Fischer return 1; 268c9b362f6SAndre Fischer } 269c9b362f6SAndre Fischer} 270c9b362f6SAndre Fischer 271c9b362f6SAndre Fischer 272c9b362f6SAndre Fischer 273c9b362f6SAndre Fischer 274c9b362f6SAndre Fischer=head2 SplitLongShortName($name) 275c9b362f6SAndre Fischer 276c9b362f6SAndre Fischer Split $name (typically from the 'FileName' column in the 'File' 277c9b362f6SAndre Fischer table or 'DefaultDir' column in the 'Directory' table) at the '|' 278c9b362f6SAndre Fischer into short (8.3) and long names. If there is no '|' in $name then 279c9b362f6SAndre Fischer $name is returned as both short and long name. 280c9b362f6SAndre Fischer 281c9b362f6SAndre Fischer Returns long and short name (in this order) as array. 282c9b362f6SAndre Fischer 283c9b362f6SAndre Fischer=cut 284*60b96b8dSAndre Fischer 285c9b362f6SAndre Fischersub SplitLongShortName ($) 286c9b362f6SAndre Fischer{ 287c9b362f6SAndre Fischer my ($name) = @_; 288c9b362f6SAndre Fischer 289c9b362f6SAndre Fischer if ($name =~ /^([^\|]*)\|(.*)$/) 290c9b362f6SAndre Fischer { 291c9b362f6SAndre Fischer return ($2,$1); 292c9b362f6SAndre Fischer } 293c9b362f6SAndre Fischer else 294c9b362f6SAndre Fischer { 295c9b362f6SAndre Fischer return ($name,$name); 296c9b362f6SAndre Fischer } 297c9b362f6SAndre Fischer} 298c9b362f6SAndre Fischer 299c9b362f6SAndre Fischer 300c9b362f6SAndre Fischer 301c9b362f6SAndre Fischer=head2 SplitTargetSourceLongShortName ($name) 302c9b362f6SAndre Fischer 303c9b362f6SAndre Fischer Split $name first at the ':' into target and source parts and each 304c9b362f6SAndre Fischer of those at the '|'s into long and short parts. Names that follow 305c9b362f6SAndre Fischer this pattern come from the 'DefaultDir' column in the 'Directory' 306c9b362f6SAndre Fischer table. 307c9b362f6SAndre Fischer 308c9b362f6SAndre Fischer=cut 309*60b96b8dSAndre Fischer 310c9b362f6SAndre Fischersub SplitTargetSourceLongShortName ($) 311c9b362f6SAndre Fischer{ 312c9b362f6SAndre Fischer my ($name) = @_; 313c9b362f6SAndre Fischer 314c9b362f6SAndre Fischer if ($name =~ /^([^:]*):(.*)$/) 315c9b362f6SAndre Fischer { 316c9b362f6SAndre Fischer return (installer::patch::Msi::SplitLongShortName($1), installer::patch::Msi::SplitLongShortName($2)); 317c9b362f6SAndre Fischer } 318c9b362f6SAndre Fischer else 319c9b362f6SAndre Fischer { 320c9b362f6SAndre Fischer my ($long,$short) = installer::patch::Msi::SplitLongShortName($name); 321c9b362f6SAndre Fischer return ($long,$short,$long,$short); 322c9b362f6SAndre Fischer } 323c9b362f6SAndre Fischer} 324c9b362f6SAndre Fischer 325c9b362f6SAndre Fischer 3269f91b7e3SAndre Fischer=head2 GetDirectoryMap($self) 327c9b362f6SAndre Fischer 3289f91b7e3SAndre Fischer Return a map that maps directory unique names (column 'Directory' in table 'Directory') 3299f91b7e3SAndre Fischer to hashes that contains short and long source and target names. 330c9b362f6SAndre Fischer 331c9b362f6SAndre Fischer=cut 332*60b96b8dSAndre Fischer 3339f91b7e3SAndre Fischersub GetDirectoryMap ($) 334c9b362f6SAndre Fischer{ 335c9b362f6SAndre Fischer my ($self) = @_; 336c9b362f6SAndre Fischer 3379f91b7e3SAndre Fischer if (defined $self->{'DirectoryMap'}) 338c9b362f6SAndre Fischer { 3399f91b7e3SAndre Fischer return $self->{'DirectoryMap'}; 340c9b362f6SAndre Fischer } 341c9b362f6SAndre Fischer 342c9b362f6SAndre Fischer my $directory_table = $self->GetTable("Directory"); 343c9b362f6SAndre Fischer my %dir_map = (); 344c9b362f6SAndre Fischer foreach my $row (@{$directory_table->GetAllRows()}) 345c9b362f6SAndre Fischer { 3469f91b7e3SAndre Fischer my ($target_long_name, $target_short_name, $source_long_name, $source_short_name) 347c9b362f6SAndre Fischer = installer::patch::Msi::SplitTargetSourceLongShortName($row->GetValue("DefaultDir")); 3489f91b7e3SAndre Fischer my $unique_name = $row->GetValue("Directory"); 3499f91b7e3SAndre Fischer $dir_map{$unique_name} = 3509f91b7e3SAndre Fischer { 3519f91b7e3SAndre Fischer 'unique_name' => $unique_name, 352c9b362f6SAndre Fischer 'parent' => $row->GetValue("Directory_Parent"), 3539f91b7e3SAndre Fischer 'default_dir' => $row->GetValue("DefaultDir"), 3549f91b7e3SAndre Fischer 'source_long_name' => $source_long_name, 3559f91b7e3SAndre Fischer 'source_short_name' => $source_short_name, 3569f91b7e3SAndre Fischer 'target_long_name' => $target_long_name, 3579f91b7e3SAndre Fischer 'target_short_name' => $target_short_name 3589f91b7e3SAndre Fischer }; 359c9b362f6SAndre Fischer } 360c9b362f6SAndre Fischer 361c9b362f6SAndre Fischer # Set up full names for all directories. 362c9b362f6SAndre Fischer my @todo = map {$_} (keys %dir_map); 363c9b362f6SAndre Fischer while (scalar @todo > 0) 364c9b362f6SAndre Fischer { 365c9b362f6SAndre Fischer my $key = shift @todo; 366c9b362f6SAndre Fischer my $item = $dir_map{$key}; 367c9b362f6SAndre Fischer next if defined $item->{'full_source_name'}; 368c9b362f6SAndre Fischer 369c9b362f6SAndre Fischer if ($item->{'parent'} eq "") 370c9b362f6SAndre Fischer { 371c9b362f6SAndre Fischer # Directory has no parent => full names are the same as the name. 3729f91b7e3SAndre Fischer $item->{'full_source_long_name'} = $item->{'source_long_name'}; 3739f91b7e3SAndre Fischer $item->{'full_source_short_name'} = $item->{'source_short_name'}; 3749f91b7e3SAndre Fischer $item->{'full_target_long_name'} = $item->{'target_long_name'}; 3759f91b7e3SAndre Fischer $item->{'full_target_short_name'} = $item->{'target_short_name'}; 376c9b362f6SAndre Fischer } 377c9b362f6SAndre Fischer else 378c9b362f6SAndre Fischer { 379c9b362f6SAndre Fischer my $parent = $dir_map{$item->{'parent'}}; 3809f91b7e3SAndre Fischer if ( defined $parent->{'full_source_long_name'}) 381c9b362f6SAndre Fischer { 382c9b362f6SAndre Fischer # Parent aleady has full names => we can create the full name of the current item. 3839f91b7e3SAndre Fischer $item->{'full_source_long_name'} 3849f91b7e3SAndre Fischer = $parent->{'full_source_long_name'} . "/" . $item->{'source_long_name'}; 3859f91b7e3SAndre Fischer $item->{'full_source_short_name'} 3869f91b7e3SAndre Fischer = $parent->{'full_source_short_name'} . "/" . $item->{'source_short_name'}; 3879f91b7e3SAndre Fischer $item->{'full_target_long_name'} 3889f91b7e3SAndre Fischer = $parent->{'full_target_long_name'} . "/" . $item->{'target_long_name'}; 3899f91b7e3SAndre Fischer $item->{'full_target_short_name'} 3909f91b7e3SAndre Fischer = $parent->{'full_target_short_name'} . "/" . $item->{'target_short_name'}; 391c9b362f6SAndre Fischer } 392c9b362f6SAndre Fischer else 393c9b362f6SAndre Fischer { 394c9b362f6SAndre Fischer # Parent has to be processed before the current item can be processed. 395c9b362f6SAndre Fischer # Push both to the head of the list. 396c9b362f6SAndre Fischer unshift @todo, $key; 397c9b362f6SAndre Fischer unshift @todo, $item->{'parent'}; 398c9b362f6SAndre Fischer } 399c9b362f6SAndre Fischer } 400c9b362f6SAndre Fischer } 401c9b362f6SAndre Fischer 4029f91b7e3SAndre Fischer # Postprocess the path names for cleanup. 4039f91b7e3SAndre Fischer foreach my $item (values %dir_map) 404c9b362f6SAndre Fischer { 4059f91b7e3SAndre Fischer foreach my $id ( 4069f91b7e3SAndre Fischer 'full_source_long_name', 4079f91b7e3SAndre Fischer 'full_source_short_name', 4089f91b7e3SAndre Fischer 'full_target_long_name', 4099f91b7e3SAndre Fischer 'full_target_short_name') 4109f91b7e3SAndre Fischer { 4119f91b7e3SAndre Fischer $item->{$id} =~ s/\/(\.\/)+/\//g; 4129f91b7e3SAndre Fischer $item->{$id} =~ s/^SourceDir\///; 4139f91b7e3SAndre Fischer $item->{$id} =~ s/^\.$//; 414c9b362f6SAndre Fischer } 4159f91b7e3SAndre Fischer } 4169f91b7e3SAndre Fischer 4179f91b7e3SAndre Fischer $self->{'DirectoryMap'} = \%dir_map; 4189f91b7e3SAndre Fischer return $self->{'DirectoryMap'}; 4199f91b7e3SAndre Fischer} 4209f91b7e3SAndre Fischer 4219f91b7e3SAndre Fischer 4229f91b7e3SAndre Fischer 4239f91b7e3SAndre Fischer 4249f91b7e3SAndre Fischer=head2 GetFileMap ($) 4259f91b7e3SAndre Fischer 4269f91b7e3SAndre Fischer Return a map (hash) that maps the unique name (column 'File' in 4279f91b7e3SAndre Fischer the 'File' table) to data that is associated with that file, like 4289f91b7e3SAndre Fischer the directory or component. 4299f91b7e3SAndre Fischer 4309f91b7e3SAndre Fischer The map is kept alive for the lifetime of the Msi object. All 4319f91b7e3SAndre Fischer calls but the first are cheap. 4329f91b7e3SAndre Fischer 4339f91b7e3SAndre Fischer=cut 434*60b96b8dSAndre Fischer 4359f91b7e3SAndre Fischersub GetFileMap ($) 4369f91b7e3SAndre Fischer{ 4379f91b7e3SAndre Fischer my ($self) = @_; 4389f91b7e3SAndre Fischer 4399f91b7e3SAndre Fischer if (defined $self->{'FileMap'}) 4409f91b7e3SAndre Fischer { 4419f91b7e3SAndre Fischer return $self->{'FileMap'}; 4429f91b7e3SAndre Fischer } 4439f91b7e3SAndre Fischer 4449f91b7e3SAndre Fischer my $file_table = $self->GetTable("File"); 4459f91b7e3SAndre Fischer my $component_table = $self->GetTable("Component"); 4469f91b7e3SAndre Fischer my $dir_map = $self->GetDirectoryMap(); 447c9b362f6SAndre Fischer 448c9b362f6SAndre Fischer # Setup a map from component names to directory items. 4499f91b7e3SAndre Fischer my %component_to_directory_map = 4509f91b7e3SAndre Fischer map 4519f91b7e3SAndre Fischer {$_->GetValue('Component') => $_->GetValue('Directory_')} 4529f91b7e3SAndre Fischer @{$component_table->GetAllRows()}; 453c9b362f6SAndre Fischer 454c9b362f6SAndre Fischer # Finally, create the map from files to directories. 4559f91b7e3SAndre Fischer my $file_map = {}; 456c9b362f6SAndre Fischer my $file_component_index = $file_table->GetColumnIndex("Component_"); 457c9b362f6SAndre Fischer my $file_file_index = $file_table->GetColumnIndex("File"); 458c9b362f6SAndre Fischer foreach my $file_row (@{$file_table->GetAllRows()}) 459c9b362f6SAndre Fischer { 460c9b362f6SAndre Fischer my $component_name = $file_row->GetValue($file_component_index); 461c9b362f6SAndre Fischer my $directory_name = $component_to_directory_map{$component_name}; 462c9b362f6SAndre Fischer my $unique_name = $file_row->GetValue($file_file_index); 4639f91b7e3SAndre Fischer $file_map->{$unique_name} = { 4649f91b7e3SAndre Fischer 'directory' => $dir_map->{$directory_name}, 4659f91b7e3SAndre Fischer 'component_name' => $component_name 4669f91b7e3SAndre Fischer }; 467c9b362f6SAndre Fischer } 468c9b362f6SAndre Fischer 4699f91b7e3SAndre Fischer $self->{'FileMap'} = $file_map; 4709f91b7e3SAndre Fischer return $file_map; 471c9b362f6SAndre Fischer} 472c9b362f6SAndre Fischer 473c9b362f6SAndre Fischer 474c9b362f6SAndre Fischer1; 475