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; 26*9f91b7e3SAndre Fischeruse installer::patch::InstallationSet; 27*9f91b7e3SAndre Fischer 28*9f91b7e3SAndre Fischeruse File::Basename; 29*9f91b7e3SAndre Fischeruse File::Copy; 30*9f91b7e3SAndre 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 40*9f91b7e3SAndre Fischersub FindAndCreate($$$$$) 41*9f91b7e3SAndre Fischer{ 42*9f91b7e3SAndre Fischer my ($class, $version, $is_current_version, $language, $product_name) = @_; 43*9f91b7e3SAndre Fischer 44*9f91b7e3SAndre Fischer my $condensed_version = $version; 45*9f91b7e3SAndre Fischer $condensed_version =~ s/\.//g; 46*9f91b7e3SAndre Fischer 47*9f91b7e3SAndre Fischer # When $version is the current version we have to search the msi at a different place. 48*9f91b7e3SAndre Fischer my $path; 49*9f91b7e3SAndre Fischer my $filename; 50*9f91b7e3SAndre Fischer my $is_current = 0; 51*9f91b7e3SAndre Fischer $path = installer::patch::InstallationSet::GetUnpackedExePath( 52*9f91b7e3SAndre Fischer $version, 53*9f91b7e3SAndre Fischer $is_current_version, 54*9f91b7e3SAndre Fischer $language, 55*9f91b7e3SAndre Fischer "msi", 56*9f91b7e3SAndre Fischer $product_name); 57*9f91b7e3SAndre Fischer 58*9f91b7e3SAndre Fischer # Find the msi in the path.ls . 59*9f91b7e3SAndre Fischer $filename = File::Spec->catfile($path, "openoffice".$condensed_version.".msi"); 60*9f91b7e3SAndre Fischer $is_current = $is_current_version; 61*9f91b7e3SAndre Fischer 62*9f91b7e3SAndre Fischer return $class->new($filename, $version, $is_current, $language, $product_name); 63*9f91b7e3SAndre Fischer} 64c9b362f6SAndre Fischer 65c9b362f6SAndre Fischer 66*9f91b7e3SAndre Fischer 67*9f91b7e3SAndre Fischer 68*9f91b7e3SAndre Fischer 69*9f91b7e3SAndre Fischer 70*9f91b7e3SAndre 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*9f91b7e3SAndre Fischersub new ($$$$$$) 79c9b362f6SAndre Fischer{ 80*9f91b7e3SAndre Fischer my ($class, $filename, $version, $is_current_version, $language, $product_name) = @_; 81c9b362f6SAndre Fischer 82c9b362f6SAndre Fischer if ( ! -f $filename) 83c9b362f6SAndre Fischer { 84*9f91b7e3SAndre Fischer installer::logger::PrintError("can not find the .msi file for version %s and language %s at '%s'\n", 85*9f91b7e3SAndre Fischer $version, 86*9f91b7e3SAndre Fischer $language, 87*9f91b7e3SAndre Fischer $filename); 88c9b362f6SAndre Fischer return undef; 89c9b362f6SAndre Fischer } 90c9b362f6SAndre Fischer 91c9b362f6SAndre Fischer my $self = { 92c9b362f6SAndre Fischer 'filename' => $filename, 93*9f91b7e3SAndre Fischer 'path' => dirname($filename), 94c9b362f6SAndre Fischer 'version' => $version, 95*9f91b7e3SAndre Fischer 'is_current_version' => $is_current_version, 96c9b362f6SAndre Fischer 'language' => $language, 97c9b362f6SAndre Fischer 'package_format' => "msi", 98c9b362f6SAndre Fischer 'product_name' => $product_name, 99c9b362f6SAndre Fischer 'tmpdir' => File::Temp->newdir(CLEANUP => 1), 100c9b362f6SAndre Fischer 'is_valid' => -f $filename 101c9b362f6SAndre Fischer }; 102c9b362f6SAndre Fischer bless($self, $class); 103c9b362f6SAndre Fischer 104c9b362f6SAndre Fischer return $self; 105c9b362f6SAndre Fischer} 106c9b362f6SAndre Fischer 107c9b362f6SAndre Fischer 108c9b362f6SAndre Fischer 109c9b362f6SAndre Fischer 110c9b362f6SAndre Fischersub IsValid ($) 111c9b362f6SAndre Fischer{ 112c9b362f6SAndre Fischer my ($self) = @_; 113c9b362f6SAndre Fischer 114c9b362f6SAndre Fischer return $self->{'is_valid'}; 115c9b362f6SAndre Fischer} 116c9b362f6SAndre Fischer 117c9b362f6SAndre Fischer 118c9b362f6SAndre Fischer 119c9b362f6SAndre Fischer 120*9f91b7e3SAndre Fischer=head2 Commit($self) 121*9f91b7e3SAndre Fischer 122*9f91b7e3SAndre Fischer Write all modified tables back into the databse. 123*9f91b7e3SAndre Fischer 124*9f91b7e3SAndre Fischer=cut 125*9f91b7e3SAndre Fischersub Commit ($) 126*9f91b7e3SAndre Fischer{ 127*9f91b7e3SAndre Fischer my $self = shift; 128*9f91b7e3SAndre Fischer 129*9f91b7e3SAndre Fischer my @tables_to_update = (); 130*9f91b7e3SAndre Fischer foreach my $table (values %{$self->{'tables'}}) 131*9f91b7e3SAndre Fischer { 132*9f91b7e3SAndre Fischer push @tables_to_update,$table if ($table->IsModified()); 133*9f91b7e3SAndre Fischer } 134*9f91b7e3SAndre Fischer 135*9f91b7e3SAndre Fischer if (scalar @tables_to_update > 0) 136*9f91b7e3SAndre Fischer { 137*9f91b7e3SAndre Fischer $installer::logger::Info->printf("writing modified tables to database:\n"); 138*9f91b7e3SAndre Fischer foreach my $table (@tables_to_update) 139*9f91b7e3SAndre Fischer { 140*9f91b7e3SAndre Fischer $installer::logger::Info->printf(" %s\n", $table->GetName()); 141*9f91b7e3SAndre Fischer $self->PutTable($table); 142*9f91b7e3SAndre Fischer } 143*9f91b7e3SAndre Fischer 144*9f91b7e3SAndre Fischer foreach my $table (@tables_to_update) 145*9f91b7e3SAndre Fischer { 146*9f91b7e3SAndre Fischer $table->UpdateTimestamp(); 147*9f91b7e3SAndre Fischer $table->MarkAsUnmodified(); 148*9f91b7e3SAndre Fischer } 149*9f91b7e3SAndre Fischer } 150*9f91b7e3SAndre Fischer} 151*9f91b7e3SAndre Fischer 152*9f91b7e3SAndre Fischer 153*9f91b7e3SAndre Fischer 154*9f91b7e3SAndre Fischer 155c9b362f6SAndre Fischer=head2 GetTable($seld, $table_name) 156c9b362f6SAndre Fischer 157c9b362f6SAndre Fischer Return an MsiTable object for $table_name. Table objects are kept 158c9b362f6SAndre Fischer alive for the life time of the Msi object. Therefore the second 159c9b362f6SAndre Fischer call for the same table is very cheap. 160c9b362f6SAndre Fischer 161c9b362f6SAndre Fischer=cut 162c9b362f6SAndre Fischersub GetTable ($$) 163c9b362f6SAndre Fischer{ 164c9b362f6SAndre Fischer my ($self, $table_name) = @_; 165c9b362f6SAndre Fischer 166c9b362f6SAndre Fischer my $table = $self->{'tables'}->{$table_name}; 167c9b362f6SAndre Fischer if ( ! defined $table) 168c9b362f6SAndre Fischer { 169c9b362f6SAndre Fischer my $table_filename = File::Spec->catfile($self->{'tmpdir'}, $table_name .".idt"); 170c9b362f6SAndre Fischer if ( ! -f $table_filename 171c9b362f6SAndre Fischer || ! EnsureAYoungerThanB($table_filename, $self->{'fullname'})) 172c9b362f6SAndre Fischer { 173c9b362f6SAndre Fischer # Extract table from database to text file on disk. 174c9b362f6SAndre Fischer my $truncated_table_name = length($table_name)>8 ? substr($table_name,0,8) : $table_name; 175c9b362f6SAndre Fischer my $command = join(" ", 176c9b362f6SAndre Fischer "msidb.exe", 177*9f91b7e3SAndre Fischer "-d", installer::patch::Tools::ToEscapedWindowsPath($self->{'filename'}), 178*9f91b7e3SAndre Fischer "-f", installer::patch::Tools::ToEscapedWindowsPath($self->{'tmpdir'}), 179c9b362f6SAndre Fischer "-e", $table_name); 180c9b362f6SAndre Fischer my $result = qx($command); 181c9b362f6SAndre Fischer print $result; 182c9b362f6SAndre Fischer } 183c9b362f6SAndre Fischer 184c9b362f6SAndre Fischer # Read table into memory. 185c9b362f6SAndre Fischer $table = new installer::patch::MsiTable($table_filename, $table_name); 186c9b362f6SAndre Fischer $self->{'tables'}->{$table_name} = $table; 187c9b362f6SAndre Fischer } 188c9b362f6SAndre Fischer 189c9b362f6SAndre Fischer return $table; 190c9b362f6SAndre Fischer} 191c9b362f6SAndre Fischer 192c9b362f6SAndre Fischer 193c9b362f6SAndre Fischer 194c9b362f6SAndre Fischer 195*9f91b7e3SAndre Fischer=head2 PutTable($self, $table) 196*9f91b7e3SAndre Fischer 197*9f91b7e3SAndre Fischer Write the given table back to the databse. 198*9f91b7e3SAndre Fischer 199*9f91b7e3SAndre Fischer=cut 200*9f91b7e3SAndre Fischersub PutTable ($$) 201*9f91b7e3SAndre Fischer{ 202*9f91b7e3SAndre Fischer my ($self, $table) = @_; 203*9f91b7e3SAndre Fischer 204*9f91b7e3SAndre Fischer # Create text file from the current table content. 205*9f91b7e3SAndre Fischer $table->WriteFile(); 206*9f91b7e3SAndre Fischer 207*9f91b7e3SAndre Fischer my $table_name = $table->GetName(); 208*9f91b7e3SAndre Fischer 209*9f91b7e3SAndre Fischer # Store table from text file into database. 210*9f91b7e3SAndre Fischer my $table_filename = $table->{'filename'}; 211*9f91b7e3SAndre Fischer 212*9f91b7e3SAndre Fischer if (length($table_name) > 8) 213*9f91b7e3SAndre Fischer { 214*9f91b7e3SAndre Fischer # The file name of the table data must not be longer than 8 characters (not counting the extension). 215*9f91b7e3SAndre Fischer # The name passed as argument to the -i option may be longer. 216*9f91b7e3SAndre Fischer my $truncated_table_name = substr($table_name,0,8); 217*9f91b7e3SAndre Fischer my $table_truncated_filename = File::Spec->catfile( 218*9f91b7e3SAndre Fischer dirname($table_filename), 219*9f91b7e3SAndre Fischer $truncated_table_name.".idt"); 220*9f91b7e3SAndre Fischer File::Copy::copy($table_filename, $table_truncated_filename) || die("can not create table file with short name"); 221*9f91b7e3SAndre Fischer } 222*9f91b7e3SAndre Fischer 223*9f91b7e3SAndre Fischer my $command = join(" ", 224*9f91b7e3SAndre Fischer "msidb.exe", 225*9f91b7e3SAndre Fischer "-d", installer::patch::Tools::ToEscapedWindowsPath($self->{'filename'}), 226*9f91b7e3SAndre Fischer "-f", installer::patch::Tools::ToEscapedWindowsPath($self->{'tmpdir'}), 227*9f91b7e3SAndre Fischer "-i", $table_name); 228*9f91b7e3SAndre Fischer my $result = system($command); 229*9f91b7e3SAndre Fischer 230*9f91b7e3SAndre Fischer if ($result != 0) 231*9f91b7e3SAndre Fischer { 232*9f91b7e3SAndre Fischer installer::logger::PrintError("writing table '%s' back to database failed", $table_name); 233*9f91b7e3SAndre Fischer # For error messages see http://msdn.microsoft.com/en-us/library/windows/desktop/aa372835%28v=vs.85%29.aspx 234*9f91b7e3SAndre Fischer } 235*9f91b7e3SAndre Fischer} 236*9f91b7e3SAndre Fischer 237*9f91b7e3SAndre Fischer 238*9f91b7e3SAndre Fischer 239*9f91b7e3SAndre Fischer 240c9b362f6SAndre Fischer=head2 EnsureAYoungerThanB ($filename_a, $filename_b) 241c9b362f6SAndre Fischer 242c9b362f6SAndre Fischer Internal function (not a method) that compares to files according 243c9b362f6SAndre Fischer to their last modification times (mtime). 244c9b362f6SAndre Fischer 245c9b362f6SAndre Fischer=cut 246c9b362f6SAndre Fischersub EnsureAYoungerThanB ($$) 247c9b362f6SAndre Fischer{ 248c9b362f6SAndre Fischer my ($filename_a, $filename_b) = @_; 249c9b362f6SAndre Fischer 250c9b362f6SAndre Fischer die("file $filename_a does not exist") unless -f $filename_a; 251c9b362f6SAndre Fischer die("file $filename_b does not exist") unless -f $filename_b; 252c9b362f6SAndre Fischer 253c9b362f6SAndre Fischer my @stat_a = stat($filename_a); 254c9b362f6SAndre Fischer my @stat_b = stat($filename_b); 255c9b362f6SAndre Fischer 256c9b362f6SAndre Fischer if ($stat_a[9] <= $stat_b[9]) 257c9b362f6SAndre Fischer { 258c9b362f6SAndre Fischer return 0; 259c9b362f6SAndre Fischer } 260c9b362f6SAndre Fischer else 261c9b362f6SAndre Fischer { 262c9b362f6SAndre Fischer return 1; 263c9b362f6SAndre Fischer } 264c9b362f6SAndre Fischer} 265c9b362f6SAndre Fischer 266c9b362f6SAndre Fischer 267c9b362f6SAndre Fischer 268c9b362f6SAndre Fischer 269c9b362f6SAndre Fischer=head2 SplitLongShortName($name) 270c9b362f6SAndre Fischer 271c9b362f6SAndre Fischer Split $name (typically from the 'FileName' column in the 'File' 272c9b362f6SAndre Fischer table or 'DefaultDir' column in the 'Directory' table) at the '|' 273c9b362f6SAndre Fischer into short (8.3) and long names. If there is no '|' in $name then 274c9b362f6SAndre Fischer $name is returned as both short and long name. 275c9b362f6SAndre Fischer 276c9b362f6SAndre Fischer Returns long and short name (in this order) as array. 277c9b362f6SAndre Fischer 278c9b362f6SAndre Fischer=cut 279c9b362f6SAndre Fischersub SplitLongShortName ($) 280c9b362f6SAndre Fischer{ 281c9b362f6SAndre Fischer my ($name) = @_; 282c9b362f6SAndre Fischer 283c9b362f6SAndre Fischer if ($name =~ /^([^\|]*)\|(.*)$/) 284c9b362f6SAndre Fischer { 285c9b362f6SAndre Fischer return ($2,$1); 286c9b362f6SAndre Fischer } 287c9b362f6SAndre Fischer else 288c9b362f6SAndre Fischer { 289c9b362f6SAndre Fischer return ($name,$name); 290c9b362f6SAndre Fischer } 291c9b362f6SAndre Fischer} 292c9b362f6SAndre Fischer 293c9b362f6SAndre Fischer 294c9b362f6SAndre Fischer 295c9b362f6SAndre Fischer=head2 SplitTargetSourceLongShortName ($name) 296c9b362f6SAndre Fischer 297c9b362f6SAndre Fischer Split $name first at the ':' into target and source parts and each 298c9b362f6SAndre Fischer of those at the '|'s into long and short parts. Names that follow 299c9b362f6SAndre Fischer this pattern come from the 'DefaultDir' column in the 'Directory' 300c9b362f6SAndre Fischer table. 301c9b362f6SAndre Fischer 302c9b362f6SAndre Fischer=cut 303c9b362f6SAndre Fischersub SplitTargetSourceLongShortName ($) 304c9b362f6SAndre Fischer{ 305c9b362f6SAndre Fischer my ($name) = @_; 306c9b362f6SAndre Fischer 307c9b362f6SAndre Fischer if ($name =~ /^([^:]*):(.*)$/) 308c9b362f6SAndre Fischer { 309c9b362f6SAndre Fischer return (installer::patch::Msi::SplitLongShortName($1), installer::patch::Msi::SplitLongShortName($2)); 310c9b362f6SAndre Fischer } 311c9b362f6SAndre Fischer else 312c9b362f6SAndre Fischer { 313c9b362f6SAndre Fischer my ($long,$short) = installer::patch::Msi::SplitLongShortName($name); 314c9b362f6SAndre Fischer return ($long,$short,$long,$short); 315c9b362f6SAndre Fischer } 316c9b362f6SAndre Fischer} 317c9b362f6SAndre Fischer 318c9b362f6SAndre Fischer 319*9f91b7e3SAndre Fischer=head2 GetDirectoryMap($self) 320c9b362f6SAndre Fischer 321*9f91b7e3SAndre Fischer Return a map that maps directory unique names (column 'Directory' in table 'Directory') 322*9f91b7e3SAndre Fischer to hashes that contains short and long source and target names. 323c9b362f6SAndre Fischer 324c9b362f6SAndre Fischer=cut 325*9f91b7e3SAndre Fischersub GetDirectoryMap ($) 326c9b362f6SAndre Fischer{ 327c9b362f6SAndre Fischer my ($self) = @_; 328c9b362f6SAndre Fischer 329*9f91b7e3SAndre Fischer if (defined $self->{'DirectoryMap'}) 330c9b362f6SAndre Fischer { 331*9f91b7e3SAndre Fischer return $self->{'DirectoryMap'}; 332c9b362f6SAndre Fischer } 333c9b362f6SAndre Fischer 334c9b362f6SAndre Fischer my $directory_table = $self->GetTable("Directory"); 335c9b362f6SAndre Fischer my %dir_map = (); 336c9b362f6SAndre Fischer foreach my $row (@{$directory_table->GetAllRows()}) 337c9b362f6SAndre Fischer { 338*9f91b7e3SAndre Fischer my ($target_long_name, $target_short_name, $source_long_name, $source_short_name) 339c9b362f6SAndre Fischer = installer::patch::Msi::SplitTargetSourceLongShortName($row->GetValue("DefaultDir")); 340*9f91b7e3SAndre Fischer my $unique_name = $row->GetValue("Directory"); 341*9f91b7e3SAndre Fischer $dir_map{$unique_name} = 342*9f91b7e3SAndre Fischer { 343*9f91b7e3SAndre Fischer 'unique_name' => $unique_name, 344c9b362f6SAndre Fischer 'parent' => $row->GetValue("Directory_Parent"), 345*9f91b7e3SAndre Fischer 'default_dir' => $row->GetValue("DefaultDir"), 346*9f91b7e3SAndre Fischer 'source_long_name' => $source_long_name, 347*9f91b7e3SAndre Fischer 'source_short_name' => $source_short_name, 348*9f91b7e3SAndre Fischer 'target_long_name' => $target_long_name, 349*9f91b7e3SAndre Fischer 'target_short_name' => $target_short_name 350*9f91b7e3SAndre Fischer }; 351c9b362f6SAndre Fischer } 352c9b362f6SAndre Fischer 353c9b362f6SAndre Fischer # Set up full names for all directories. 354c9b362f6SAndre Fischer my @todo = map {$_} (keys %dir_map); 355c9b362f6SAndre Fischer while (scalar @todo > 0) 356c9b362f6SAndre Fischer { 357c9b362f6SAndre Fischer my $key = shift @todo; 358c9b362f6SAndre Fischer my $item = $dir_map{$key}; 359c9b362f6SAndre Fischer next if defined $item->{'full_source_name'}; 360c9b362f6SAndre Fischer 361c9b362f6SAndre Fischer if ($item->{'parent'} eq "") 362c9b362f6SAndre Fischer { 363c9b362f6SAndre Fischer # Directory has no parent => full names are the same as the name. 364*9f91b7e3SAndre Fischer $item->{'full_source_long_name'} = $item->{'source_long_name'}; 365*9f91b7e3SAndre Fischer $item->{'full_source_short_name'} = $item->{'source_short_name'}; 366*9f91b7e3SAndre Fischer $item->{'full_target_long_name'} = $item->{'target_long_name'}; 367*9f91b7e3SAndre Fischer $item->{'full_target_short_name'} = $item->{'target_short_name'}; 368c9b362f6SAndre Fischer } 369c9b362f6SAndre Fischer else 370c9b362f6SAndre Fischer { 371c9b362f6SAndre Fischer my $parent = $dir_map{$item->{'parent'}}; 372*9f91b7e3SAndre Fischer if ( defined $parent->{'full_source_long_name'}) 373c9b362f6SAndre Fischer { 374c9b362f6SAndre Fischer # Parent aleady has full names => we can create the full name of the current item. 375*9f91b7e3SAndre Fischer $item->{'full_source_long_name'} 376*9f91b7e3SAndre Fischer = $parent->{'full_source_long_name'} . "/" . $item->{'source_long_name'}; 377*9f91b7e3SAndre Fischer $item->{'full_source_short_name'} 378*9f91b7e3SAndre Fischer = $parent->{'full_source_short_name'} . "/" . $item->{'source_short_name'}; 379*9f91b7e3SAndre Fischer $item->{'full_target_long_name'} 380*9f91b7e3SAndre Fischer = $parent->{'full_target_long_name'} . "/" . $item->{'target_long_name'}; 381*9f91b7e3SAndre Fischer $item->{'full_target_short_name'} 382*9f91b7e3SAndre Fischer = $parent->{'full_target_short_name'} . "/" . $item->{'target_short_name'}; 383c9b362f6SAndre Fischer } 384c9b362f6SAndre Fischer else 385c9b362f6SAndre Fischer { 386c9b362f6SAndre Fischer # Parent has to be processed before the current item can be processed. 387c9b362f6SAndre Fischer # Push both to the head of the list. 388c9b362f6SAndre Fischer unshift @todo, $key; 389c9b362f6SAndre Fischer unshift @todo, $item->{'parent'}; 390c9b362f6SAndre Fischer } 391c9b362f6SAndre Fischer } 392c9b362f6SAndre Fischer } 393c9b362f6SAndre Fischer 394*9f91b7e3SAndre Fischer # Postprocess the path names for cleanup. 395*9f91b7e3SAndre Fischer foreach my $item (values %dir_map) 396c9b362f6SAndre Fischer { 397*9f91b7e3SAndre Fischer foreach my $id ( 398*9f91b7e3SAndre Fischer 'full_source_long_name', 399*9f91b7e3SAndre Fischer 'full_source_short_name', 400*9f91b7e3SAndre Fischer 'full_target_long_name', 401*9f91b7e3SAndre Fischer 'full_target_short_name') 402*9f91b7e3SAndre Fischer { 403*9f91b7e3SAndre Fischer $item->{$id} =~ s/\/(\.\/)+/\//g; 404*9f91b7e3SAndre Fischer $item->{$id} =~ s/^SourceDir\///; 405*9f91b7e3SAndre Fischer $item->{$id} =~ s/^\.$//; 406c9b362f6SAndre Fischer } 407*9f91b7e3SAndre Fischer } 408*9f91b7e3SAndre Fischer 409*9f91b7e3SAndre Fischer $self->{'DirectoryMap'} = \%dir_map; 410*9f91b7e3SAndre Fischer return $self->{'DirectoryMap'}; 411*9f91b7e3SAndre Fischer} 412*9f91b7e3SAndre Fischer 413*9f91b7e3SAndre Fischer 414*9f91b7e3SAndre Fischer 415*9f91b7e3SAndre Fischer 416*9f91b7e3SAndre Fischer=head2 GetFileMap ($) 417*9f91b7e3SAndre Fischer 418*9f91b7e3SAndre Fischer Return a map (hash) that maps the unique name (column 'File' in 419*9f91b7e3SAndre Fischer the 'File' table) to data that is associated with that file, like 420*9f91b7e3SAndre Fischer the directory or component. 421*9f91b7e3SAndre Fischer 422*9f91b7e3SAndre Fischer The map is kept alive for the lifetime of the Msi object. All 423*9f91b7e3SAndre Fischer calls but the first are cheap. 424*9f91b7e3SAndre Fischer 425*9f91b7e3SAndre Fischer=cut 426*9f91b7e3SAndre Fischersub GetFileMap ($) 427*9f91b7e3SAndre Fischer{ 428*9f91b7e3SAndre Fischer my ($self) = @_; 429*9f91b7e3SAndre Fischer 430*9f91b7e3SAndre Fischer if (defined $self->{'FileMap'}) 431*9f91b7e3SAndre Fischer { 432*9f91b7e3SAndre Fischer return $self->{'FileMap'}; 433*9f91b7e3SAndre Fischer } 434*9f91b7e3SAndre Fischer 435*9f91b7e3SAndre Fischer my $file_table = $self->GetTable("File"); 436*9f91b7e3SAndre Fischer my $component_table = $self->GetTable("Component"); 437*9f91b7e3SAndre Fischer my $dir_map = $self->GetDirectoryMap(); 438c9b362f6SAndre Fischer 439c9b362f6SAndre Fischer # Setup a map from component names to directory items. 440*9f91b7e3SAndre Fischer my %component_to_directory_map = 441*9f91b7e3SAndre Fischer map 442*9f91b7e3SAndre Fischer {$_->GetValue('Component') => $_->GetValue('Directory_')} 443*9f91b7e3SAndre Fischer @{$component_table->GetAllRows()}; 444c9b362f6SAndre Fischer 445c9b362f6SAndre Fischer # Finally, create the map from files to directories. 446*9f91b7e3SAndre Fischer my $file_map = {}; 447c9b362f6SAndre Fischer my $file_component_index = $file_table->GetColumnIndex("Component_"); 448c9b362f6SAndre Fischer my $file_file_index = $file_table->GetColumnIndex("File"); 449c9b362f6SAndre Fischer foreach my $file_row (@{$file_table->GetAllRows()}) 450c9b362f6SAndre Fischer { 451c9b362f6SAndre Fischer my $component_name = $file_row->GetValue($file_component_index); 452c9b362f6SAndre Fischer my $directory_name = $component_to_directory_map{$component_name}; 453c9b362f6SAndre Fischer my $unique_name = $file_row->GetValue($file_file_index); 454*9f91b7e3SAndre Fischer $file_map->{$unique_name} = { 455*9f91b7e3SAndre Fischer 'directory' => $dir_map->{$directory_name}, 456*9f91b7e3SAndre Fischer 'component_name' => $component_name 457*9f91b7e3SAndre Fischer }; 458c9b362f6SAndre Fischer } 459c9b362f6SAndre Fischer 460*9f91b7e3SAndre Fischer $self->{'FileMap'} = $file_map; 461*9f91b7e3SAndre Fischer return $file_map; 462c9b362f6SAndre Fischer} 463c9b362f6SAndre Fischer 464c9b362f6SAndre Fischer 465c9b362f6SAndre Fischer1; 466