xref: /AOO41X/main/solenv/bin/modules/installer/patch/MsiTable.pm (revision 9f91b7e30577a5efd4c1ce7f0c95f4b60745abda)
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::MsiTable;
23c9b362f6SAndre Fischer
24c9b362f6SAndre Fischer=head1 NAME
25c9b362f6SAndre Fischer
26c9b362f6SAndre Fischer    package installer::patch::MsiTable - Class that represents one table of an Msi file.
27c9b362f6SAndre Fischer
28c9b362f6SAndre Fischer=cut
29c9b362f6SAndre Fischer
30c9b362f6SAndre Fischeruse installer::patch::MsiRow;
31c9b362f6SAndre Fischer
32c9b362f6SAndre Fischeruse strict;
33c9b362f6SAndre Fischer
34c9b362f6SAndre Fischer=head new ($class, $filename, $table_name)
35c9b362f6SAndre Fischer
36c9b362f6SAndre Fischer    Create a new MsiTable object from the output of a previous
37c9b362f6SAndre Fischer    msidb.exe run.  The table is named $table_name, its data is read
38c9b362f6SAndre Fischer    from $filename.
39c9b362f6SAndre Fischer
40c9b362f6SAndre Fischer=cut
41c9b362f6SAndre Fischersub new ($$$)
42c9b362f6SAndre Fischer{
43c9b362f6SAndre Fischer    my ($class, $filename, $table_name) = @_;
44c9b362f6SAndre Fischer
45c9b362f6SAndre Fischer    my $self = {
46c9b362f6SAndre 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
53c9b362f6SAndre Fischer    };
54c9b362f6SAndre Fischer    bless($self, $class);
55c9b362f6SAndre Fischer
56*9f91b7e3SAndre Fischer    if (defined $filename &&  -f $filename)
57c9b362f6SAndre Fischer    {
58c9b362f6SAndre Fischer        $self->ReadFile($filename);
59c9b362f6SAndre Fischer    }
60c9b362f6SAndre Fischer    return $self;
61c9b362f6SAndre Fischer}
62c9b362f6SAndre Fischer
63c9b362f6SAndre Fischer
64c9b362f6SAndre Fischer
65c9b362f6SAndre 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
111c9b362f6SAndre Fischersub IsValid ($)
112c9b362f6SAndre Fischer{
113c9b362f6SAndre Fischer    my ($self) = @_;
114c9b362f6SAndre Fischer    return $self->{'is_valid'};
115c9b362f6SAndre Fischer}
116c9b362f6SAndre Fischer
117c9b362f6SAndre Fischer
118c9b362f6SAndre Fischer
119c9b362f6SAndre Fischer
120c9b362f6SAndre Fischersub Trim ($)
121c9b362f6SAndre Fischer{
122c9b362f6SAndre Fischer    my $line = shift;
123c9b362f6SAndre Fischer
124c9b362f6SAndre Fischer    $line =~ s/(^\s+|\s+$)//g;
125c9b362f6SAndre Fischer
126c9b362f6SAndre Fischer    return $line;
127c9b362f6SAndre Fischer}
128c9b362f6SAndre Fischer
129c9b362f6SAndre Fischer
130c9b362f6SAndre Fischer
131c9b362f6SAndre Fischer=head2 ReadFile($self, $filename)
132c9b362f6SAndre Fischer
133c9b362f6SAndre Fischer    Read the content of the table from the specified .idt file.
134c9b362f6SAndre Fischer    For each row a MsiRow object is appended to $self->{'rows'}.
135c9b362f6SAndre Fischer
136c9b362f6SAndre Fischer=cut
137c9b362f6SAndre Fischersub ReadFile ($$)
138c9b362f6SAndre Fischer{
139c9b362f6SAndre Fischer    my ($self, $filename) = @_;
140c9b362f6SAndre Fischer
141c9b362f6SAndre Fischer    if ( ! (-f $filename && -r $filename))
142c9b362f6SAndre Fischer    {
143c9b362f6SAndre Fischer        printf STDERR ("can not open idt file %s for reading\n", $filename);
144c9b362f6SAndre Fischer        $self->{'is_valid'} = 0;
145c9b362f6SAndre Fischer        return;
146c9b362f6SAndre Fischer    }
147c9b362f6SAndre Fischer
148c9b362f6SAndre Fischer    open my $in, "<", $filename;
149c9b362f6SAndre Fischer
150c9b362f6SAndre Fischer    my $columns = Trim(<$in>);
151c9b362f6SAndre Fischer    $self->{'columns'} = [split(/\t/, $columns)];
152c9b362f6SAndre Fischer
153c9b362f6SAndre Fischer    my $column_specs = Trim(<$in>);
154c9b362f6SAndre Fischer    $self->{'column_specs'} = [split(/\t/, $column_specs)];
155c9b362f6SAndre Fischer
156c9b362f6SAndre Fischer    # Table name, index columns.
157c9b362f6SAndre Fischer    my $line = Trim(<$in>);
158c9b362f6SAndre 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'})
165c9b362f6SAndre Fischer    {
166c9b362f6SAndre Fischer        $self->{'codepage'} = shift @items;
167c9b362f6SAndre Fischer    }
168*9f91b7e3SAndre Fischer    else
169c9b362f6SAndre Fischer    {
170*9f91b7e3SAndre Fischer        printf STDERR ("reading wrong table data for table '%s' (got %s)\n", $self->{'name'}, $items[0]);
171c9b362f6SAndre Fischer        $self->{'is_valid'} = 0;
172c9b362f6SAndre Fischer        return;
173c9b362f6SAndre Fischer    }
174*9f91b7e3SAndre Fischer    shift @items;
175c9b362f6SAndre Fischer    $self->{'index_columns'} = [@items];
176c9b362f6SAndre Fischer    $self->{'index_column_index'} = $self->GetColumnIndex($items[0]);
177c9b362f6SAndre Fischer
178c9b362f6SAndre Fischer    my $rows = [];
179c9b362f6SAndre Fischer    while (<$in>)
180c9b362f6SAndre Fischer    {
181c9b362f6SAndre Fischer        # Remove all trailing returns and newlines.  Keep trailing spaces and tabs.
182c9b362f6SAndre Fischer        s/[\r\n]+$//g;
183c9b362f6SAndre Fischer
184c9b362f6SAndre Fischer        my @items = split(/\t/, $_);
185c9b362f6SAndre Fischer        push @$rows, new installer::patch::MsiRow($self, @items);
186c9b362f6SAndre Fischer    }
187c9b362f6SAndre Fischer    $self->{'rows'} = $rows;
188c9b362f6SAndre Fischer
189c9b362f6SAndre Fischer    return $self;
190c9b362f6SAndre Fischer}
191c9b362f6SAndre Fischer
192c9b362f6SAndre Fischer
193c9b362f6SAndre 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
246c9b362f6SAndre Fischer=head2 GetColumnCount($self)
247c9b362f6SAndre Fischer
248c9b362f6SAndre Fischer    Return the number of columns in the table.
249c9b362f6SAndre Fischer
250c9b362f6SAndre Fischer=cut
251c9b362f6SAndre Fischersub GetColumnCount ($)
252c9b362f6SAndre Fischer{
253c9b362f6SAndre Fischer    my ($self) = @_;
254c9b362f6SAndre Fischer
255c9b362f6SAndre Fischer    return scalar @{$self->{'columns'}};
256c9b362f6SAndre Fischer}
257c9b362f6SAndre Fischer
258c9b362f6SAndre Fischer
259c9b362f6SAndre Fischer
260c9b362f6SAndre Fischer
261c9b362f6SAndre Fischer=head2 GetRowCount($self)
262c9b362f6SAndre Fischer
263c9b362f6SAndre Fischer    Return the number of rows in the table.
264c9b362f6SAndre Fischer
265c9b362f6SAndre Fischer=cut
266c9b362f6SAndre Fischersub GetRowCount ($)
267c9b362f6SAndre Fischer{
268c9b362f6SAndre Fischer    my ($self) = @_;
269c9b362f6SAndre Fischer
270c9b362f6SAndre Fischer    return scalar @{$self->{'rows'}};
271c9b362f6SAndre Fischer}
272c9b362f6SAndre Fischer
273c9b362f6SAndre Fischer
274c9b362f6SAndre Fischer
275c9b362f6SAndre Fischer
276c9b362f6SAndre Fischer=head2 GetColumnIndx($self, $column_name)
277c9b362f6SAndre Fischer
278c9b362f6SAndre Fischer    Return the 0 based index of the column named $column_name.  Use
279c9b362f6SAndre Fischer    this to speed up (slightly) access to column values when accessing
280c9b362f6SAndre Fischer    many or all rows of a table.
281c9b362f6SAndre Fischer
282c9b362f6SAndre Fischer=cut
283c9b362f6SAndre Fischersub GetColumnIndex ($$)
284c9b362f6SAndre Fischer{
285c9b362f6SAndre Fischer    my ($self, $column_name) = @_;
286c9b362f6SAndre Fischer
287c9b362f6SAndre Fischer    my $index = 0;
288c9b362f6SAndre Fischer    foreach my $name (@{$self->{'columns'}})
289c9b362f6SAndre Fischer    {
290c9b362f6SAndre Fischer        if ($name eq $column_name)
291c9b362f6SAndre Fischer        {
292c9b362f6SAndre Fischer            return $index;
293c9b362f6SAndre Fischer        }
294c9b362f6SAndre Fischer        ++$index;
295c9b362f6SAndre Fischer    }
296c9b362f6SAndre Fischer
297c9b362f6SAndre Fischer    printf STDERR ("did not find column %s in %s\n", $column_name, join(" and ", @{$self->{'columns'}}));
298c9b362f6SAndre Fischer    return -1;
299c9b362f6SAndre Fischer}
300c9b362f6SAndre Fischer
301c9b362f6SAndre Fischer
302c9b362f6SAndre 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
330c9b362f6SAndre Fischer
331c9b362f6SAndre Fischer=head2 GetValue($self, $selector_column, $selector_column_value, $value_column)
332c9b362f6SAndre Fischer
333c9b362f6SAndre Fischer    Find the row in which the $selector_column has value
334c9b362f6SAndre Fischer    $selector_column_value and return its value in the $value_column.
335c9b362f6SAndre Fischer
336c9b362f6SAndre Fischer=cut
337c9b362f6SAndre Fischer
338c9b362f6SAndre Fischersub GetValue ($$$$)
339c9b362f6SAndre Fischer{
340c9b362f6SAndre Fischer    my ($self, $selector_column, $selector_column_value, $value_column) = @_;
341c9b362f6SAndre Fischer
342c9b362f6SAndre Fischer    my $row = $self->GetRow($selector_column, $selector_column_value);
343c9b362f6SAndre Fischer    if (defined $row)
344c9b362f6SAndre Fischer    {
345c9b362f6SAndre Fischer        return $row->GetValue($value_column);
346c9b362f6SAndre Fischer    }
347c9b362f6SAndre Fischer    else
348c9b362f6SAndre Fischer    {
349c9b362f6SAndre Fischer        return undef;
350c9b362f6SAndre Fischer    }
351c9b362f6SAndre Fischer}
352c9b362f6SAndre Fischer
353c9b362f6SAndre Fischer
354c9b362f6SAndre Fischer
355c9b362f6SAndre Fischer
356c9b362f6SAndre Fischer=head2 GetRow($self, $column, $value)
357c9b362f6SAndre Fischer
358c9b362f6SAndre Fischer    Return the (first) row which has $value in $column.
359c9b362f6SAndre Fischer
360c9b362f6SAndre Fischer=cut
361c9b362f6SAndre Fischersub GetRow ($$$)
362c9b362f6SAndre Fischer{
363c9b362f6SAndre Fischer    my ($self, $column, $value) = @_;
364c9b362f6SAndre Fischer
365c9b362f6SAndre Fischer    my $column_index = $self->GetColumnIndex($column);
366c9b362f6SAndre Fischer    if ($column_index<0)
367c9b362f6SAndre Fischer    {
368c9b362f6SAndre Fischer        printf STDERR "ERROR: unknown column $column in table $self->{'name'}\n";
369c9b362f6SAndre Fischer        return undef;
370c9b362f6SAndre Fischer    }
371c9b362f6SAndre Fischer
372c9b362f6SAndre Fischer    foreach my $row (@{$self->{'rows'}})
373c9b362f6SAndre Fischer    {
374c9b362f6SAndre Fischer        if ($row->GetValue($column_index) eq $value)
375c9b362f6SAndre Fischer        {
376c9b362f6SAndre Fischer            return $row;
377c9b362f6SAndre Fischer        }
378c9b362f6SAndre Fischer    }
379c9b362f6SAndre Fischer
380c9b362f6SAndre Fischer    printf STDERR ("ERROR: did not find row for %s->%s in %s\n",
381c9b362f6SAndre Fischer        $column,
382c9b362f6SAndre Fischer        $value,
383c9b362f6SAndre Fischer        table $self->{'name'});
384c9b362f6SAndre Fischer
385c9b362f6SAndre Fischer    return undef;
386c9b362f6SAndre Fischer}
387c9b362f6SAndre Fischer
388c9b362f6SAndre Fischer
389c9b362f6SAndre Fischer
390c9b362f6SAndre Fischer
391c9b362f6SAndre Fischer=head2 GetAllRows ($self)
392c9b362f6SAndre Fischer
393c9b362f6SAndre Fischer    Return the reference to an array that contains all rows of the table.
394c9b362f6SAndre Fischer
395c9b362f6SAndre Fischer=cut
396c9b362f6SAndre Fischer
397c9b362f6SAndre Fischersub GetAllRows ($)
398c9b362f6SAndre Fischer{
399c9b362f6SAndre Fischer    my $self = shift;
400c9b362f6SAndre Fischer
401c9b362f6SAndre Fischer    return $self->{'rows'};
402c9b362f6SAndre Fischer}
403c9b362f6SAndre Fischer
404c9b362f6SAndre Fischer
405c9b362f6SAndre Fischer
406c9b362f6SAndre 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
491c9b362f6SAndre Fischer
492c9b362f6SAndre Fischer1;
493