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