1*c9b362f6SAndre Fischer#************************************************************** 2*c9b362f6SAndre Fischer# 3*c9b362f6SAndre Fischer# Licensed to the Apache Software Foundation (ASF) under one 4*c9b362f6SAndre Fischer# or more contributor license agreements. See the NOTICE file 5*c9b362f6SAndre Fischer# distributed with this work for additional information 6*c9b362f6SAndre Fischer# regarding copyright ownership. The ASF licenses this file 7*c9b362f6SAndre Fischer# to you under the Apache License, Version 2.0 (the 8*c9b362f6SAndre Fischer# "License"); you may not use this file except in compliance 9*c9b362f6SAndre Fischer# with the License. You may obtain a copy of the License at 10*c9b362f6SAndre Fischer# 11*c9b362f6SAndre Fischer# http://www.apache.org/licenses/LICENSE-2.0 12*c9b362f6SAndre Fischer# 13*c9b362f6SAndre Fischer# Unless required by applicable law or agreed to in writing, 14*c9b362f6SAndre Fischer# software distributed under the License is distributed on an 15*c9b362f6SAndre Fischer# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*c9b362f6SAndre Fischer# KIND, either express or implied. See the License for the 17*c9b362f6SAndre Fischer# specific language governing permissions and limitations 18*c9b362f6SAndre Fischer# under the License. 19*c9b362f6SAndre Fischer# 20*c9b362f6SAndre Fischer#************************************************************** 21*c9b362f6SAndre Fischer 22*c9b362f6SAndre Fischerpackage installer::patch::MsiTable; 23*c9b362f6SAndre Fischer 24*c9b362f6SAndre Fischer=head1 NAME 25*c9b362f6SAndre Fischer 26*c9b362f6SAndre Fischer package installer::patch::MsiTable - Class that represents one table of an Msi file. 27*c9b362f6SAndre Fischer 28*c9b362f6SAndre Fischer=cut 29*c9b362f6SAndre Fischer 30*c9b362f6SAndre Fischeruse installer::patch::MsiRow; 31*c9b362f6SAndre Fischer 32*c9b362f6SAndre Fischeruse strict; 33*c9b362f6SAndre Fischer 34*c9b362f6SAndre Fischer=head new ($class, $filename, $table_name) 35*c9b362f6SAndre Fischer 36*c9b362f6SAndre Fischer Create a new MsiTable object from the output of a previous 37*c9b362f6SAndre Fischer msidb.exe run. The table is named $table_name, its data is read 38*c9b362f6SAndre Fischer from $filename. 39*c9b362f6SAndre Fischer 40*c9b362f6SAndre Fischer=cut 41*c9b362f6SAndre Fischersub new ($$$) 42*c9b362f6SAndre Fischer{ 43*c9b362f6SAndre Fischer my ($class, $filename, $table_name) = @_; 44*c9b362f6SAndre Fischer 45*c9b362f6SAndre Fischer my $self = { 46*c9b362f6SAndre Fischer 'name' => $table_name, 47*c9b362f6SAndre Fischer 'is_valid' => 1 48*c9b362f6SAndre Fischer }; 49*c9b362f6SAndre Fischer bless($self, $class); 50*c9b362f6SAndre Fischer 51*c9b362f6SAndre Fischer if ( -f $filename) 52*c9b362f6SAndre Fischer { 53*c9b362f6SAndre Fischer $self->ReadFile($filename); 54*c9b362f6SAndre Fischer } 55*c9b362f6SAndre Fischer return $self; 56*c9b362f6SAndre Fischer} 57*c9b362f6SAndre Fischer 58*c9b362f6SAndre Fischer 59*c9b362f6SAndre Fischer 60*c9b362f6SAndre Fischer 61*c9b362f6SAndre Fischersub IsValid ($) 62*c9b362f6SAndre Fischer{ 63*c9b362f6SAndre Fischer my ($self) = @_; 64*c9b362f6SAndre Fischer return $self->{'is_valid'}; 65*c9b362f6SAndre Fischer} 66*c9b362f6SAndre Fischer 67*c9b362f6SAndre Fischer 68*c9b362f6SAndre Fischer 69*c9b362f6SAndre Fischer 70*c9b362f6SAndre Fischersub Trim ($) 71*c9b362f6SAndre Fischer{ 72*c9b362f6SAndre Fischer my $line = shift; 73*c9b362f6SAndre Fischer 74*c9b362f6SAndre Fischer $line =~ s/(^\s+|\s+$)//g; 75*c9b362f6SAndre Fischer 76*c9b362f6SAndre Fischer return $line; 77*c9b362f6SAndre Fischer} 78*c9b362f6SAndre Fischer 79*c9b362f6SAndre Fischer 80*c9b362f6SAndre Fischer 81*c9b362f6SAndre Fischer=head2 ReadFile($self, $filename) 82*c9b362f6SAndre Fischer 83*c9b362f6SAndre Fischer Read the content of the table from the specified .idt file. 84*c9b362f6SAndre Fischer For each row a MsiRow object is appended to $self->{'rows'}. 85*c9b362f6SAndre Fischer 86*c9b362f6SAndre Fischer=cut 87*c9b362f6SAndre Fischersub ReadFile ($$) 88*c9b362f6SAndre Fischer{ 89*c9b362f6SAndre Fischer my ($self, $filename) = @_; 90*c9b362f6SAndre Fischer 91*c9b362f6SAndre Fischer if ( ! (-f $filename && -r $filename)) 92*c9b362f6SAndre Fischer { 93*c9b362f6SAndre Fischer printf STDERR ("can not open idt file %s for reading\n", $filename); 94*c9b362f6SAndre Fischer $self->{'is_valid'} = 0; 95*c9b362f6SAndre Fischer return; 96*c9b362f6SAndre Fischer } 97*c9b362f6SAndre Fischer 98*c9b362f6SAndre Fischer open my $in, "<", $filename; 99*c9b362f6SAndre Fischer 100*c9b362f6SAndre Fischer my $columns = Trim(<$in>); 101*c9b362f6SAndre Fischer $self->{'columns'} = [split(/\t/, $columns)]; 102*c9b362f6SAndre Fischer 103*c9b362f6SAndre Fischer my $column_specs = Trim(<$in>); 104*c9b362f6SAndre Fischer $self->{'column_specs'} = [split(/\t/, $column_specs)]; 105*c9b362f6SAndre Fischer 106*c9b362f6SAndre Fischer # Table name, index columns. 107*c9b362f6SAndre Fischer my $line = Trim(<$in>); 108*c9b362f6SAndre Fischer my @items = split(/\t/, $line); 109*c9b362f6SAndre Fischer if (scalar @items == 3) 110*c9b362f6SAndre Fischer { 111*c9b362f6SAndre Fischer $self->{'codepage'} = shift @items; 112*c9b362f6SAndre Fischer } 113*c9b362f6SAndre Fischer my $table_name = shift @items; 114*c9b362f6SAndre Fischer if ($table_name ne $self->{'name'}) 115*c9b362f6SAndre Fischer { 116*c9b362f6SAndre Fischer printf STDERR ("reading wrong table data for table '%s' (got %s)\n", $self->{'name'}, $table_name); 117*c9b362f6SAndre Fischer $self->{'is_valid'} = 0; 118*c9b362f6SAndre Fischer return; 119*c9b362f6SAndre Fischer } 120*c9b362f6SAndre Fischer $self->{'index_columns'} = [@items]; 121*c9b362f6SAndre Fischer $self->{'index_column_index'} = $self->GetColumnIndex($items[0]); 122*c9b362f6SAndre Fischer 123*c9b362f6SAndre Fischer my $rows = []; 124*c9b362f6SAndre Fischer while (<$in>) 125*c9b362f6SAndre Fischer { 126*c9b362f6SAndre Fischer # Remove all trailing returns and newlines. Keep trailing spaces and tabs. 127*c9b362f6SAndre Fischer s/[\r\n]+$//g; 128*c9b362f6SAndre Fischer 129*c9b362f6SAndre Fischer my @items = split(/\t/, $_); 130*c9b362f6SAndre Fischer push @$rows, new installer::patch::MsiRow($self, @items); 131*c9b362f6SAndre Fischer } 132*c9b362f6SAndre Fischer $self->{'rows'} = $rows; 133*c9b362f6SAndre Fischer 134*c9b362f6SAndre Fischer return $self; 135*c9b362f6SAndre Fischer} 136*c9b362f6SAndre Fischer 137*c9b362f6SAndre Fischer 138*c9b362f6SAndre Fischer 139*c9b362f6SAndre Fischer=head2 GetColumnCount($self) 140*c9b362f6SAndre Fischer 141*c9b362f6SAndre Fischer Return the number of columns in the table. 142*c9b362f6SAndre Fischer 143*c9b362f6SAndre Fischer=cut 144*c9b362f6SAndre Fischersub GetColumnCount ($) 145*c9b362f6SAndre Fischer{ 146*c9b362f6SAndre Fischer my ($self) = @_; 147*c9b362f6SAndre Fischer 148*c9b362f6SAndre Fischer return scalar @{$self->{'columns'}}; 149*c9b362f6SAndre Fischer} 150*c9b362f6SAndre Fischer 151*c9b362f6SAndre Fischer 152*c9b362f6SAndre Fischer 153*c9b362f6SAndre Fischer 154*c9b362f6SAndre Fischer=head2 GetRowCount($self) 155*c9b362f6SAndre Fischer 156*c9b362f6SAndre Fischer Return the number of rows in the table. 157*c9b362f6SAndre Fischer 158*c9b362f6SAndre Fischer=cut 159*c9b362f6SAndre Fischersub GetRowCount ($) 160*c9b362f6SAndre Fischer{ 161*c9b362f6SAndre Fischer my ($self) = @_; 162*c9b362f6SAndre Fischer 163*c9b362f6SAndre Fischer return scalar @{$self->{'rows'}}; 164*c9b362f6SAndre Fischer} 165*c9b362f6SAndre Fischer 166*c9b362f6SAndre Fischer 167*c9b362f6SAndre Fischer 168*c9b362f6SAndre Fischer 169*c9b362f6SAndre Fischer=head2 GetColumnIndx($self, $column_name) 170*c9b362f6SAndre Fischer 171*c9b362f6SAndre Fischer Return the 0 based index of the column named $column_name. Use 172*c9b362f6SAndre Fischer this to speed up (slightly) access to column values when accessing 173*c9b362f6SAndre Fischer many or all rows of a table. 174*c9b362f6SAndre Fischer 175*c9b362f6SAndre Fischer=cut 176*c9b362f6SAndre Fischersub GetColumnIndex ($$) 177*c9b362f6SAndre Fischer{ 178*c9b362f6SAndre Fischer my ($self, $column_name) = @_; 179*c9b362f6SAndre Fischer 180*c9b362f6SAndre Fischer my $index = 0; 181*c9b362f6SAndre Fischer foreach my $name (@{$self->{'columns'}}) 182*c9b362f6SAndre Fischer { 183*c9b362f6SAndre Fischer if ($name eq $column_name) 184*c9b362f6SAndre Fischer { 185*c9b362f6SAndre Fischer return $index; 186*c9b362f6SAndre Fischer } 187*c9b362f6SAndre Fischer ++$index; 188*c9b362f6SAndre Fischer } 189*c9b362f6SAndre Fischer 190*c9b362f6SAndre Fischer printf STDERR ("did not find column %s in %s\n", $column_name, join(" and ", @{$self->{'columns'}})); 191*c9b362f6SAndre Fischer return -1; 192*c9b362f6SAndre Fischer} 193*c9b362f6SAndre Fischer 194*c9b362f6SAndre Fischer 195*c9b362f6SAndre Fischer 196*c9b362f6SAndre Fischer 197*c9b362f6SAndre Fischer=head2 GetValue($self, $selector_column, $selector_column_value, $value_column) 198*c9b362f6SAndre Fischer 199*c9b362f6SAndre Fischer Find the row in which the $selector_column has value 200*c9b362f6SAndre Fischer $selector_column_value and return its value in the $value_column. 201*c9b362f6SAndre Fischer 202*c9b362f6SAndre Fischer=cut 203*c9b362f6SAndre Fischer 204*c9b362f6SAndre Fischersub GetValue ($$$$) 205*c9b362f6SAndre Fischer{ 206*c9b362f6SAndre Fischer my ($self, $selector_column, $selector_column_value, $value_column) = @_; 207*c9b362f6SAndre Fischer 208*c9b362f6SAndre Fischer my $row = $self->GetRow($selector_column, $selector_column_value); 209*c9b362f6SAndre Fischer if (defined $row) 210*c9b362f6SAndre Fischer { 211*c9b362f6SAndre Fischer return $row->GetValue($value_column); 212*c9b362f6SAndre Fischer } 213*c9b362f6SAndre Fischer else 214*c9b362f6SAndre Fischer { 215*c9b362f6SAndre Fischer return undef; 216*c9b362f6SAndre Fischer } 217*c9b362f6SAndre Fischer} 218*c9b362f6SAndre Fischer 219*c9b362f6SAndre Fischer 220*c9b362f6SAndre Fischer 221*c9b362f6SAndre Fischer 222*c9b362f6SAndre Fischer=head2 GetRow($self, $column, $value) 223*c9b362f6SAndre Fischer 224*c9b362f6SAndre Fischer Return the (first) row which has $value in $column. 225*c9b362f6SAndre Fischer 226*c9b362f6SAndre Fischer=cut 227*c9b362f6SAndre Fischersub GetRow ($$$) 228*c9b362f6SAndre Fischer{ 229*c9b362f6SAndre Fischer my ($self, $column, $value) = @_; 230*c9b362f6SAndre Fischer 231*c9b362f6SAndre Fischer my $column_index = $self->GetColumnIndex($column); 232*c9b362f6SAndre Fischer if ($column_index<0) 233*c9b362f6SAndre Fischer { 234*c9b362f6SAndre Fischer printf STDERR "ERROR: unknown column $column in table $self->{'name'}\n"; 235*c9b362f6SAndre Fischer return undef; 236*c9b362f6SAndre Fischer } 237*c9b362f6SAndre Fischer 238*c9b362f6SAndre Fischer foreach my $row (@{$self->{'rows'}}) 239*c9b362f6SAndre Fischer { 240*c9b362f6SAndre Fischer if ($row->GetValue($column_index) eq $value) 241*c9b362f6SAndre Fischer { 242*c9b362f6SAndre Fischer return $row; 243*c9b362f6SAndre Fischer } 244*c9b362f6SAndre Fischer } 245*c9b362f6SAndre Fischer 246*c9b362f6SAndre Fischer printf STDERR ("ERROR: did not find row for %s->%s in %s\n", 247*c9b362f6SAndre Fischer $column, 248*c9b362f6SAndre Fischer $value, 249*c9b362f6SAndre Fischer table $self->{'name'}); 250*c9b362f6SAndre Fischer 251*c9b362f6SAndre Fischer return undef; 252*c9b362f6SAndre Fischer} 253*c9b362f6SAndre Fischer 254*c9b362f6SAndre Fischer 255*c9b362f6SAndre Fischer 256*c9b362f6SAndre Fischer 257*c9b362f6SAndre Fischer=head2 GetAllRows ($self) 258*c9b362f6SAndre Fischer 259*c9b362f6SAndre Fischer Return the reference to an array that contains all rows of the table. 260*c9b362f6SAndre Fischer 261*c9b362f6SAndre Fischer=cut 262*c9b362f6SAndre Fischer 263*c9b362f6SAndre Fischersub GetAllRows ($) 264*c9b362f6SAndre Fischer{ 265*c9b362f6SAndre Fischer my $self = shift; 266*c9b362f6SAndre Fischer 267*c9b362f6SAndre Fischer return $self->{'rows'}; 268*c9b362f6SAndre Fischer} 269*c9b362f6SAndre Fischer 270*c9b362f6SAndre Fischer 271*c9b362f6SAndre Fischer 272*c9b362f6SAndre Fischer 273*c9b362f6SAndre Fischer 274*c9b362f6SAndre Fischer1; 275