1*9f91b7e3SAndre Fischer#**************************************************************
2*9f91b7e3SAndre Fischer#
3*9f91b7e3SAndre Fischer#  Licensed to the Apache Software Foundation (ASF) under one
4*9f91b7e3SAndre Fischer#  or more contributor license agreements.  See the NOTICE file
5*9f91b7e3SAndre Fischer#  distributed with this work for additional information
6*9f91b7e3SAndre Fischer#  regarding copyright ownership.  The ASF licenses this file
7*9f91b7e3SAndre Fischer#  to you under the Apache License, Version 2.0 (the
8*9f91b7e3SAndre Fischer#  "License"); you may not use this file except in compliance
9*9f91b7e3SAndre Fischer#  with the License.  You may obtain a copy of the License at
10*9f91b7e3SAndre Fischer#
11*9f91b7e3SAndre Fischer#    http://www.apache.org/licenses/LICENSE-2.0
12*9f91b7e3SAndre Fischer#
13*9f91b7e3SAndre Fischer#  Unless required by applicable law or agreed to in writing,
14*9f91b7e3SAndre Fischer#  software distributed under the License is distributed on an
15*9f91b7e3SAndre Fischer#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*9f91b7e3SAndre Fischer#  KIND, either express or implied.  See the License for the
17*9f91b7e3SAndre Fischer#  specific language governing permissions and limitations
18*9f91b7e3SAndre Fischer#  under the License.
19*9f91b7e3SAndre Fischer#
20*9f91b7e3SAndre Fischer#**************************************************************
21*9f91b7e3SAndre Fischer
22*9f91b7e3SAndre Fischerpackage installer::patch::MsiTable;
23*9f91b7e3SAndre Fischer
24*9f91b7e3SAndre Fischer=head1 NAME
25*9f91b7e3SAndre Fischer
26*9f91b7e3SAndre Fischer    package installer::patch::MsiTable - Class that represents one table of an Msi file.
27*9f91b7e3SAndre Fischer
28*9f91b7e3SAndre Fischer=cut
29*9f91b7e3SAndre Fischer
30*9f91b7e3SAndre Fischeruse installer::patch::MsiRow;
31*9f91b7e3SAndre Fischer
32*9f91b7e3SAndre Fischeruse strict;
33*9f91b7e3SAndre Fischer
34*9f91b7e3SAndre Fischer=head new ($class, $filename, $table_name)
35*9f91b7e3SAndre Fischer
36*9f91b7e3SAndre Fischer    Create a new MsiTable object from the output of a previous
37*9f91b7e3SAndre Fischer    msidb.exe run.  The table is named $table_name, its data is read
38*9f91b7e3SAndre Fischer    from $filename.
39*9f91b7e3SAndre Fischer
40*9f91b7e3SAndre Fischer=cut
41*9f91b7e3SAndre Fischersub new ($$$)
42*9f91b7e3SAndre Fischer{
43*9f91b7e3SAndre Fischer    my ($class, $filename, $table_name) = @_;
44*9f91b7e3SAndre Fischer
45*9f91b7e3SAndre Fischer    my $self = {
46*9f91b7e3SAndre Fischer        'name' => $table_name,
47*9f91b7e3SAndre Fischer        'filename' => $filename,
48*9f91b7e3SAndre Fischer        'columns' => undef,
49*9f91b7e3SAndre Fischer        'column_specs' => undef,
50*9f91b7e3SAndre Fischer        'codepage' => undef,
51*9f91b7e3SAndre Fischer        'is_valid' => 1,
52*9f91b7e3SAndre Fischer        'is_modified' => 0
53*9f91b7e3SAndre Fischer    };
54*9f91b7e3SAndre Fischer    bless($self, $class);
55*9f91b7e3SAndre Fischer
56*9f91b7e3SAndre Fischer    if (defined $filename &&  -f $filename)
57*9f91b7e3SAndre Fischer    {
58*9f91b7e3SAndre Fischer        $self->ReadFile($filename);
59*9f91b7e3SAndre Fischer    }
60*9f91b7e3SAndre Fischer    return $self;
61*9f91b7e3SAndre Fischer}
62*9f91b7e3SAndre Fischer
63*9f91b7e3SAndre Fischer
64*9f91b7e3SAndre Fischer
65*9f91b7e3SAndre Fischer
66*9f91b7e3SAndre Fischersub SetColumnData ($@)
67*9f91b7e3SAndre Fischer{
68*9f91b7e3SAndre Fischer    my ($self, @data) = @_;
69*9f91b7e3SAndre Fischer
70*9f91b7e3SAndre Fischer    if (((scalar @data) % 2) != 0)
71*9f91b7e3SAndre Fischer    {
72*9f91b7e3SAndre Fischer        installer::logger::PrintError("column data has to have an even number of elements: (<column-name> <data-spec>)+)\n");
73*9f91b7e3SAndre Fischer        $self->{'is_valid'} = 0;
74*9f91b7e3SAndre Fischer        return;
75*9f91b7e3SAndre Fischer    }
76*9f91b7e3SAndre Fischer
77*9f91b7e3SAndre Fischer    $self->{'columns'} = [];
78*9f91b7e3SAndre Fischer    $self->{'column_specs'} = [];
79*9f91b7e3SAndre Fischer    while (scalar @data > 0)
80*9f91b7e3SAndre Fischer    {
81*9f91b7e3SAndre Fischer        my $name = shift @data;
82*9f91b7e3SAndre Fischer        my $spec = shift @data;
83*9f91b7e3SAndre Fischer        push @{$self->{'columns'}}, $name;
84*9f91b7e3SAndre Fischer        push @{$self->{'column_specs'}}, $spec;
85*9f91b7e3SAndre Fischer    }
86*9f91b7e3SAndre Fischer}
87*9f91b7e3SAndre Fischer
88*9f91b7e3SAndre Fischer
89*9f91b7e3SAndre Fischer
90*9f91b7e3SAndre Fischer
91*9f91b7e3SAndre Fischersub SetIndexColumns ($@)
92*9f91b7e3SAndre Fischer{
93*9f91b7e3SAndre Fischer    my ($self, @index_columns) = @_;
94*9f91b7e3SAndre Fischer
95*9f91b7e3SAndre Fischer    $self->{'index_columns'} = [@index_columns];
96*9f91b7e3SAndre Fischer}
97*9f91b7e3SAndre Fischer
98*9f91b7e3SAndre Fischer
99*9f91b7e3SAndre Fischer
100*9f91b7e3SAndre Fischer
101*9f91b7e3SAndre Fischersub SetCodepage ($$)
102*9f91b7e3SAndre Fischer{
103*9f91b7e3SAndre Fischer    my ($self, $codepage) = @_;
104*9f91b7e3SAndre Fischer
105*9f91b7e3SAndre Fischer    $self->{'codepage'} = $codepage;
106*9f91b7e3SAndre Fischer}
107*9f91b7e3SAndre Fischer
108*9f91b7e3SAndre Fischer
109*9f91b7e3SAndre Fischer
110*9f91b7e3SAndre Fischer
111*9f91b7e3SAndre Fischersub IsValid ($)
112*9f91b7e3SAndre Fischer{
113*9f91b7e3SAndre Fischer    my ($self) = @_;
114*9f91b7e3SAndre Fischer    return $self->{'is_valid'};
115*9f91b7e3SAndre Fischer}
116*9f91b7e3SAndre Fischer
117*9f91b7e3SAndre Fischer
118*9f91b7e3SAndre Fischer
119*9f91b7e3SAndre Fischer
120*9f91b7e3SAndre Fischersub Trim ($)
121*9f91b7e3SAndre Fischer{
122*9f91b7e3SAndre Fischer    my $line = shift;
123*9f91b7e3SAndre Fischer
124*9f91b7e3SAndre Fischer    $line =~ s/(^\s+|\s+$)//g;
125*9f91b7e3SAndre Fischer
126*9f91b7e3SAndre Fischer    return $line;
127*9f91b7e3SAndre Fischer}
128*9f91b7e3SAndre Fischer
129*9f91b7e3SAndre Fischer
130*9f91b7e3SAndre Fischer
131*9f91b7e3SAndre Fischer=head2 ReadFile($self, $filename)
132*9f91b7e3SAndre Fischer
133*9f91b7e3SAndre Fischer    Read the content of the table from the specified .idt file.
134*9f91b7e3SAndre Fischer    For each row a MsiRow object is appended to $self->{'rows'}.
135*9f91b7e3SAndre Fischer
136*9f91b7e3SAndre Fischer=cut
137*9f91b7e3SAndre Fischersub ReadFile ($$)
138*9f91b7e3SAndre Fischer{
139*9f91b7e3SAndre Fischer    my ($self, $filename) = @_;
140*9f91b7e3SAndre Fischer
141*9f91b7e3SAndre Fischer    if ( ! (-f $filename && -r $filename))
142*9f91b7e3SAndre Fischer    {
143*9f91b7e3SAndre Fischer        printf STDERR ("can not open idt file %s for reading\n", $filename);
144*9f91b7e3SAndre Fischer        $self->{'is_valid'} = 0;
145*9f91b7e3SAndre Fischer        return;
146*9f91b7e3SAndre Fischer    }
147*9f91b7e3SAndre Fischer
148*9f91b7e3SAndre Fischer    open my $in, "<", $filename;
149*9f91b7e3SAndre Fischer
150*9f91b7e3SAndre Fischer    my $columns = Trim(<$in>);
151*9f91b7e3SAndre Fischer    $self->{'columns'} = [split(/\t/, $columns)];
152*9f91b7e3SAndre Fischer
153*9f91b7e3SAndre Fischer    my $column_specs = Trim(<$in>);
154*9f91b7e3SAndre Fischer    $self->{'column_specs'} = [split(/\t/, $column_specs)];
155*9f91b7e3SAndre Fischer
156*9f91b7e3SAndre Fischer    # Table name, index columns.
157*9f91b7e3SAndre Fischer    my $line = Trim(<$in>);
158*9f91b7e3SAndre Fischer    my @items = split(/\t/, $line);
159*9f91b7e3SAndre Fischer    my $item_count = scalar @items;
160*9f91b7e3SAndre Fischer    if ($item_count>=1 && $items[0] eq $self->{'name'})
161*9f91b7e3SAndre Fischer    {
162*9f91b7e3SAndre Fischer        # No codepage.
163*9f91b7e3SAndre Fischer    }
164*9f91b7e3SAndre Fischer    elsif ($item_count>=2 && $items[1] eq $self->{'name'})
165*9f91b7e3SAndre Fischer    {
166*9f91b7e3SAndre Fischer        $self->{'codepage'} = shift @items;
167*9f91b7e3SAndre Fischer    }
168*9f91b7e3SAndre Fischer    else
169*9f91b7e3SAndre Fischer    {
170*9f91b7e3SAndre Fischer        printf STDERR ("reading wrong table data for table '%s' (got %s)\n", $self->{'name'}, $items[0]);
171*9f91b7e3SAndre Fischer        $self->{'is_valid'} = 0;
172*9f91b7e3SAndre Fischer        return;
173*9f91b7e3SAndre Fischer    }
174*9f91b7e3SAndre Fischer    shift @items;
175*9f91b7e3SAndre Fischer    $self->{'index_columns'} = [@items];
176*9f91b7e3SAndre Fischer    $self->{'index_column_index'} = $self->GetColumnIndex($items[0]);
177*9f91b7e3SAndre Fischer
178*9f91b7e3SAndre Fischer    my $rows = [];
179*9f91b7e3SAndre Fischer    while (<$in>)
180*9f91b7e3SAndre Fischer    {
181*9f91b7e3SAndre Fischer        # Remove all trailing returns and newlines.  Keep trailing spaces and tabs.
182*9f91b7e3SAndre Fischer        s/[\r\n]+$//g;
183*9f91b7e3SAndre Fischer
184*9f91b7e3SAndre Fischer        my @items = split(/\t/, $_);
185*9f91b7e3SAndre Fischer        push @$rows, new installer::patch::MsiRow($self, @items);
186*9f91b7e3SAndre Fischer    }
187*9f91b7e3SAndre Fischer    $self->{'rows'} = $rows;
188*9f91b7e3SAndre Fischer
189*9f91b7e3SAndre Fischer    return $self;
190*9f91b7e3SAndre Fischer}
191*9f91b7e3SAndre Fischer
192*9f91b7e3SAndre Fischer
193*9f91b7e3SAndre Fischer
194*9f91b7e3SAndre Fischer
195*9f91b7e3SAndre Fischer=head WriteFile($self, $filename)
196*9f91b7e3SAndre Fischer
197*9f91b7e3SAndre Fischer    Write a text file containing the current table content.
198*9f91b7e3SAndre Fischer
199*9f91b7e3SAndre Fischer=cut
200*9f91b7e3SAndre Fischersub WriteFile ($$)
201*9f91b7e3SAndre Fischer{
202*9f91b7e3SAndre Fischer    my ($self, $filename) = @_;
203*9f91b7e3SAndre Fischer
204*9f91b7e3SAndre Fischer    open my $out, ">".$self->{'filename'};
205*9f91b7e3SAndre Fischer
206*9f91b7e3SAndre Fischer    print $out join("\t", @{$self->{'columns'}})."\r\n";
207*9f91b7e3SAndre Fischer    print $out join("\t", @{$self->{'column_specs'}})."\r\n";
208*9f91b7e3SAndre Fischer    if (defined $self->{'codepage'})
209*9f91b7e3SAndre Fischer    {
210*9f91b7e3SAndre Fischer        print $out $self->{'codepage'} . "\t";
211*9f91b7e3SAndre Fischer    }
212*9f91b7e3SAndre Fischer    print $out $self->{'name'} . "\t";
213*9f91b7e3SAndre Fischer    print $out join("\t",@{$self->{'index_columns'}})."\r\n";
214*9f91b7e3SAndre Fischer
215*9f91b7e3SAndre Fischer    foreach my $row (@{$self->{'rows'}})
216*9f91b7e3SAndre Fischer    {
217*9f91b7e3SAndre Fischer        print $out $row->Format("\t")."\r\n";
218*9f91b7e3SAndre Fischer    }
219*9f91b7e3SAndre Fischer
220*9f91b7e3SAndre Fischer    close $out;
221*9f91b7e3SAndre Fischer}
222*9f91b7e3SAndre Fischer
223*9f91b7e3SAndre Fischer
224*9f91b7e3SAndre Fischer
225*9f91b7e3SAndre Fischer
226*9f91b7e3SAndre Fischersub UpdateTimestamp ($)
227*9f91b7e3SAndre Fischer{
228*9f91b7e3SAndre Fischer    my $self = shift;
229*9f91b7e3SAndre Fischer
230*9f91b7e3SAndre Fischer    utime(undef,undef, $self->{'filename'});
231*9f91b7e3SAndre Fischer}
232*9f91b7e3SAndre Fischer
233*9f91b7e3SAndre Fischer
234*9f91b7e3SAndre Fischer
235*9f91b7e3SAndre Fischer
236*9f91b7e3SAndre Fischersub GetName ($)
237*9f91b7e3SAndre Fischer{
238*9f91b7e3SAndre Fischer    my $self = shift;
239*9f91b7e3SAndre Fischer
240*9f91b7e3SAndre Fischer    return $self->{'name'};
241*9f91b7e3SAndre Fischer}
242*9f91b7e3SAndre Fischer
243*9f91b7e3SAndre Fischer
244*9f91b7e3SAndre Fischer
245*9f91b7e3SAndre Fischer
246*9f91b7e3SAndre Fischer=head2 GetColumnCount($self)
247*9f91b7e3SAndre Fischer
248*9f91b7e3SAndre Fischer    Return the number of columns in the table.
249*9f91b7e3SAndre Fischer
250*9f91b7e3SAndre Fischer=cut
251*9f91b7e3SAndre Fischersub GetColumnCount ($)
252*9f91b7e3SAndre Fischer{
253*9f91b7e3SAndre Fischer    my ($self) = @_;
254*9f91b7e3SAndre Fischer
255*9f91b7e3SAndre Fischer    return scalar @{$self->{'columns'}};
256*9f91b7e3SAndre Fischer}
257*9f91b7e3SAndre Fischer
258*9f91b7e3SAndre Fischer
259*9f91b7e3SAndre Fischer
260*9f91b7e3SAndre Fischer
261*9f91b7e3SAndre Fischer=head2 GetRowCount($self)
262*9f91b7e3SAndre Fischer
263*9f91b7e3SAndre Fischer    Return the number of rows in the table.
264*9f91b7e3SAndre Fischer
265*9f91b7e3SAndre Fischer=cut
266*9f91b7e3SAndre Fischersub GetRowCount ($)
267*9f91b7e3SAndre Fischer{
268*9f91b7e3SAndre Fischer    my ($self) = @_;
269*9f91b7e3SAndre Fischer
270*9f91b7e3SAndre Fischer    return scalar @{$self->{'rows'}};
271*9f91b7e3SAndre Fischer}
272*9f91b7e3SAndre Fischer
273*9f91b7e3SAndre Fischer
274*9f91b7e3SAndre Fischer
275*9f91b7e3SAndre Fischer
276*9f91b7e3SAndre Fischer=head2 GetColumnIndx($self, $column_name)
277*9f91b7e3SAndre Fischer
278*9f91b7e3SAndre Fischer    Return the 0 based index of the column named $column_name.  Use
279*9f91b7e3SAndre Fischer    this to speed up (slightly) access to column values when accessing
280*9f91b7e3SAndre Fischer    many or all rows of a table.
281*9f91b7e3SAndre Fischer
282*9f91b7e3SAndre Fischer=cut
283*9f91b7e3SAndre Fischersub GetColumnIndex ($$)
284*9f91b7e3SAndre Fischer{
285*9f91b7e3SAndre Fischer    my ($self, $column_name) = @_;
286*9f91b7e3SAndre Fischer
287*9f91b7e3SAndre Fischer    my $index = 0;
288*9f91b7e3SAndre Fischer    foreach my $name (@{$self->{'columns'}})
289*9f91b7e3SAndre Fischer    {
290*9f91b7e3SAndre Fischer        if ($name eq $column_name)
291*9f91b7e3SAndre Fischer        {
292*9f91b7e3SAndre Fischer            return $index;
293*9f91b7e3SAndre Fischer        }
294*9f91b7e3SAndre Fischer        ++$index;
295*9f91b7e3SAndre Fischer    }
296*9f91b7e3SAndre Fischer
297*9f91b7e3SAndre Fischer    printf STDERR ("did not find column %s in %s\n", $column_name, join(" and ", @{$self->{'columns'}}));
298*9f91b7e3SAndre Fischer    return -1;
299*9f91b7e3SAndre Fischer}
300*9f91b7e3SAndre Fischer
301*9f91b7e3SAndre Fischer
302*9f91b7e3SAndre Fischer
303*9f91b7e3SAndre Fischer=head2 GetRowIndex($self, $index_column_index, $index_column_value)
304*9f91b7e3SAndre Fischer
305*9f91b7e3SAndre Fischer    Return the index, starting at 0, of the (first) row that has value $index_column_value
306*9f91b7e3SAndre Fischer    in column with index $index_column_index.
307*9f91b7e3SAndre Fischer
308*9f91b7e3SAndre Fischer    Return -1 if now such row is found.
309*9f91b7e3SAndre Fischer
310*9f91b7e3SAndre Fischer=cut
311*9f91b7e3SAndre Fischersub GetRowIndex ($$$)
312*9f91b7e3SAndre Fischer{
313*9f91b7e3SAndre Fischer    my ($self, $index_column_index, $index_column_value) = @_;
314*9f91b7e3SAndre Fischer
315*9f91b7e3SAndre Fischer    my $rows = $self->{'rows'};
316*9f91b7e3SAndre Fischer    for (my ($row_index,$row_count)=(0,scalar @$rows); $row_index<$row_count; ++$row_index)
317*9f91b7e3SAndre Fischer    {
318*9f91b7e3SAndre Fischer        my $row = $rows->[$row_index];
319*9f91b7e3SAndre Fischer        if ($row->GetValue($index_column_index) eq $index_column_value)
320*9f91b7e3SAndre Fischer        {
321*9f91b7e3SAndre Fischer            return $row_index;
322*9f91b7e3SAndre Fischer        }
323*9f91b7e3SAndre Fischer    }
324*9f91b7e3SAndre Fischer
325*9f91b7e3SAndre Fischer    return -1;
326*9f91b7e3SAndre Fischer}
327*9f91b7e3SAndre Fischer
328*9f91b7e3SAndre Fischer
329*9f91b7e3SAndre Fischer
330*9f91b7e3SAndre Fischer
331*9f91b7e3SAndre Fischer=head2 GetValue($self, $selector_column, $selector_column_value, $value_column)
332*9f91b7e3SAndre Fischer
333*9f91b7e3SAndre Fischer    Find the row in which the $selector_column has value
334*9f91b7e3SAndre Fischer    $selector_column_value and return its value in the $value_column.
335*9f91b7e3SAndre Fischer
336*9f91b7e3SAndre Fischer=cut
337*9f91b7e3SAndre Fischer
338*9f91b7e3SAndre Fischersub GetValue ($$$$)
339*9f91b7e3SAndre Fischer{
340*9f91b7e3SAndre Fischer    my ($self, $selector_column, $selector_column_value, $value_column) = @_;
341*9f91b7e3SAndre Fischer
342*9f91b7e3SAndre Fischer    my $row = $self->GetRow($selector_column, $selector_column_value);
343*9f91b7e3SAndre Fischer    if (defined $row)
344*9f91b7e3SAndre Fischer    {
345*9f91b7e3SAndre Fischer        return $row->GetValue($value_column);
346*9f91b7e3SAndre Fischer    }
347*9f91b7e3SAndre Fischer    else
348*9f91b7e3SAndre Fischer    {
349*9f91b7e3SAndre Fischer        return undef;
350*9f91b7e3SAndre Fischer    }
351*9f91b7e3SAndre Fischer}
352*9f91b7e3SAndre Fischer
353*9f91b7e3SAndre Fischer
354*9f91b7e3SAndre Fischer
355*9f91b7e3SAndre Fischer
356*9f91b7e3SAndre Fischer=head2 GetRow($self, $column, $value)
357*9f91b7e3SAndre Fischer
358*9f91b7e3SAndre Fischer    Return the (first) row which has $value in $column.
359*9f91b7e3SAndre Fischer
360*9f91b7e3SAndre Fischer=cut
361*9f91b7e3SAndre Fischersub GetRow ($$$)
362*9f91b7e3SAndre Fischer{
363*9f91b7e3SAndre Fischer    my ($self, $column, $value) = @_;
364*9f91b7e3SAndre Fischer
365*9f91b7e3SAndre Fischer    my $column_index = $self->GetColumnIndex($column);
366*9f91b7e3SAndre Fischer    if ($column_index<0)
367*9f91b7e3SAndre Fischer    {
368*9f91b7e3SAndre Fischer        printf STDERR "ERROR: unknown column $column in table $self->{'name'}\n";
369*9f91b7e3SAndre Fischer        return undef;
370*9f91b7e3SAndre Fischer    }
371*9f91b7e3SAndre Fischer
372*9f91b7e3SAndre Fischer    foreach my $row (@{$self->{'rows'}})
373*9f91b7e3SAndre Fischer    {
374*9f91b7e3SAndre Fischer        if ($row->GetValue($column_index) eq $value)
375*9f91b7e3SAndre Fischer        {
376*9f91b7e3SAndre Fischer            return $row;
377*9f91b7e3SAndre Fischer        }
378*9f91b7e3SAndre Fischer    }
379*9f91b7e3SAndre Fischer
380*9f91b7e3SAndre Fischer    printf STDERR ("ERROR: did not find row for %s->%s in %s\n",
381*9f91b7e3SAndre Fischer        $column,
382*9f91b7e3SAndre Fischer        $value,
383*9f91b7e3SAndre Fischer        table $self->{'name'});
384*9f91b7e3SAndre Fischer
385*9f91b7e3SAndre Fischer    return undef;
386*9f91b7e3SAndre Fischer}
387*9f91b7e3SAndre Fischer
388*9f91b7e3SAndre Fischer
389*9f91b7e3SAndre Fischer
390*9f91b7e3SAndre Fischer
391*9f91b7e3SAndre Fischer=head2 GetAllRows ($self)
392*9f91b7e3SAndre Fischer
393*9f91b7e3SAndre Fischer    Return the reference to an array that contains all rows of the table.
394*9f91b7e3SAndre Fischer
395*9f91b7e3SAndre Fischer=cut
396*9f91b7e3SAndre Fischer
397*9f91b7e3SAndre Fischersub GetAllRows ($)
398*9f91b7e3SAndre Fischer{
399*9f91b7e3SAndre Fischer    my $self = shift;
400*9f91b7e3SAndre Fischer
401*9f91b7e3SAndre Fischer    return $self->{'rows'};
402*9f91b7e3SAndre Fischer}
403*9f91b7e3SAndre Fischer
404*9f91b7e3SAndre Fischer
405*9f91b7e3SAndre Fischer
406*9f91b7e3SAndre Fischer
407*9f91b7e3SAndre Fischer=head2 SetRow($self, {$key, $value}*)
408*9f91b7e3SAndre Fischer
409*9f91b7e3SAndre Fischer    Replace an existing row.  If no matching row is found then add the row.
410*9f91b7e3SAndre Fischer
411*9f91b7e3SAndre Fischer    The row is defined by a set of key/value pairs.  Their order is defined by the keys (column names)
412*9f91b7e3SAndre Fischer    and their indices as defined in $self->{'columns'}.
413*9f91b7e3SAndre Fischer
414*9f91b7e3SAndre Fischer    Rows are compared by their values of the index column.  By default this is the first element of
415*9f91b7e3SAndre Fischer    $self->{'index_columns'} but is overruled by the last key that starts with a '*'.
416*9f91b7e3SAndre Fischer
417*9f91b7e3SAndre Fischer=cut
418*9f91b7e3SAndre Fischersub SetRow ($@)
419*9f91b7e3SAndre Fischer{
420*9f91b7e3SAndre Fischer    my $self = shift;
421*9f91b7e3SAndre Fischer    my @data = @_;
422*9f91b7e3SAndre Fischer
423*9f91b7e3SAndre Fischer    my @items = ();
424*9f91b7e3SAndre Fischer    my $index_column = $self->{'index_columns'}->[0];
425*9f91b7e3SAndre Fischer
426*9f91b7e3SAndre Fischer    # Key/Value has to have an even number of entries.
427*9f91b7e3SAndre Fischer    MsiTools::Die("invalid arguments given to MsiTable::SetRow()\n") if (scalar @data%2) != 0;
428*9f91b7e3SAndre Fischer
429*9f91b7e3SAndre Fischer    # Find column indices for column names.
430*9f91b7e3SAndre Fischer    while (scalar @data > 0)
431*9f91b7e3SAndre Fischer    {
432*9f91b7e3SAndre Fischer        my $column_name = shift @data;
433*9f91b7e3SAndre Fischer        if ($column_name =~ /^\*(.*)$/)
434*9f91b7e3SAndre Fischer        {
435*9f91b7e3SAndre Fischer            # Column name starts with a '*'.  Use it as index column.
436*9f91b7e3SAndre Fischer            $column_name = $1;
437*9f91b7e3SAndre Fischer            $index_column = $1;
438*9f91b7e3SAndre Fischer        }
439*9f91b7e3SAndre Fischer        my $value = shift @data;
440*9f91b7e3SAndre Fischer        my $column_index = $self->GetColumnIndex($column_name);
441*9f91b7e3SAndre Fischer        $items[$column_index] = $value;
442*9f91b7e3SAndre Fischer    }
443*9f91b7e3SAndre Fischer
444*9f91b7e3SAndre Fischer    my $index_column_index = $self->GetColumnIndex($index_column);
445*9f91b7e3SAndre Fischer    my $row_index = $self->GetRowIndex($index_column_index, $items[$index_column_index]);
446*9f91b7e3SAndre Fischer
447*9f91b7e3SAndre Fischer    if ($row_index < 0)
448*9f91b7e3SAndre Fischer    {
449*9f91b7e3SAndre Fischer        # Row does not yet exist.  Add it.
450*9f91b7e3SAndre Fischer        push @{$self->{'rows'}}, installer::patch::MsiRow->new($self, @items);
451*9f91b7e3SAndre Fischer    }
452*9f91b7e3SAndre Fischer    else
453*9f91b7e3SAndre Fischer    {
454*9f91b7e3SAndre Fischer        # Row does already exist.  Replace it.
455*9f91b7e3SAndre Fischer        $self->{'rows'}->[$row_index] = installer::patch::MsiRow->new($self, @items);
456*9f91b7e3SAndre Fischer    }
457*9f91b7e3SAndre Fischer
458*9f91b7e3SAndre Fischer    $self->MarkAsModified();
459*9f91b7e3SAndre Fischer}
460*9f91b7e3SAndre Fischer
461*9f91b7e3SAndre Fischer
462*9f91b7e3SAndre Fischer
463*9f91b7e3SAndre Fischer
464*9f91b7e3SAndre Fischersub MarkAsModified ($)
465*9f91b7e3SAndre Fischer{
466*9f91b7e3SAndre Fischer    my $self = shift;
467*9f91b7e3SAndre Fischer
468*9f91b7e3SAndre Fischer    $self->{'is_modified'} = 1;
469*9f91b7e3SAndre Fischer}
470*9f91b7e3SAndre Fischer
471*9f91b7e3SAndre Fischer
472*9f91b7e3SAndre Fischer
473*9f91b7e3SAndre Fischer
474*9f91b7e3SAndre Fischersub MarkAsUnmodified ($)
475*9f91b7e3SAndre Fischer{
476*9f91b7e3SAndre Fischer    my $self = shift;
477*9f91b7e3SAndre Fischer
478*9f91b7e3SAndre Fischer    $self->{'is_modified'} = 0;
479*9f91b7e3SAndre Fischer}
480*9f91b7e3SAndre Fischer
481*9f91b7e3SAndre Fischer
482*9f91b7e3SAndre Fischer
483*9f91b7e3SAndre Fischer
484*9f91b7e3SAndre Fischersub IsModified ($)
485*9f91b7e3SAndre Fischer{
486*9f91b7e3SAndre Fischer    my $self = shift;
487*9f91b7e3SAndre Fischer
488*9f91b7e3SAndre Fischer    return $self->{'is_modified'};
489*9f91b7e3SAndre Fischer}
490*9f91b7e3SAndre Fischer
491*9f91b7e3SAndre Fischer
492*9f91b7e3SAndre Fischer1;
493