1*b1cdbd2cSJim Jagielski#**************************************************************
2*b1cdbd2cSJim Jagielski#
3*b1cdbd2cSJim Jagielski#  Licensed to the Apache Software Foundation (ASF) under one
4*b1cdbd2cSJim Jagielski#  or more contributor license agreements.  See the NOTICE file
5*b1cdbd2cSJim Jagielski#  distributed with this work for additional information
6*b1cdbd2cSJim Jagielski#  regarding copyright ownership.  The ASF licenses this file
7*b1cdbd2cSJim Jagielski#  to you under the Apache License, Version 2.0 (the
8*b1cdbd2cSJim Jagielski#  "License"); you may not use this file except in compliance
9*b1cdbd2cSJim Jagielski#  with the License.  You may obtain a copy of the License at
10*b1cdbd2cSJim Jagielski#
11*b1cdbd2cSJim Jagielski#    http://www.apache.org/licenses/LICENSE-2.0
12*b1cdbd2cSJim Jagielski#
13*b1cdbd2cSJim Jagielski#  Unless required by applicable law or agreed to in writing,
14*b1cdbd2cSJim Jagielski#  software distributed under the License is distributed on an
15*b1cdbd2cSJim Jagielski#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*b1cdbd2cSJim Jagielski#  KIND, either express or implied.  See the License for the
17*b1cdbd2cSJim Jagielski#  specific language governing permissions and limitations
18*b1cdbd2cSJim Jagielski#  under the License.
19*b1cdbd2cSJim Jagielski#
20*b1cdbd2cSJim Jagielski#**************************************************************
21*b1cdbd2cSJim Jagielski
22*b1cdbd2cSJim Jagielski
23*b1cdbd2cSJim Jagielski
24*b1cdbd2cSJim Jagielskipackage installer::windows::file;
25*b1cdbd2cSJim Jagielski
26*b1cdbd2cSJim Jagielskiuse Digest::MD5;
27*b1cdbd2cSJim Jagielskiuse installer::existence;
28*b1cdbd2cSJim Jagielskiuse installer::exiter;
29*b1cdbd2cSJim Jagielskiuse installer::files;
30*b1cdbd2cSJim Jagielskiuse installer::globals;
31*b1cdbd2cSJim Jagielskiuse installer::logger;
32*b1cdbd2cSJim Jagielskiuse installer::pathanalyzer;
33*b1cdbd2cSJim Jagielskiuse installer::worker;
34*b1cdbd2cSJim Jagielskiuse installer::windows::font;
35*b1cdbd2cSJim Jagielskiuse installer::windows::idtglobal;
36*b1cdbd2cSJim Jagielskiuse installer::windows::msiglobal;
37*b1cdbd2cSJim Jagielskiuse installer::windows::language;
38*b1cdbd2cSJim Jagielskiuse installer::patch::InstallationSet;
39*b1cdbd2cSJim Jagielskiuse installer::patch::FileSequenceList;
40*b1cdbd2cSJim Jagielskiuse File::Basename;
41*b1cdbd2cSJim Jagielskiuse File::Spec;
42*b1cdbd2cSJim Jagielskiuse strict;
43*b1cdbd2cSJim Jagielski
44*b1cdbd2cSJim Jagielski##########################################################################
45*b1cdbd2cSJim Jagielski# Assigning one cabinet file to each file. This is requrired,
46*b1cdbd2cSJim Jagielski# if cabinet files shall be equivalent to packages.
47*b1cdbd2cSJim Jagielski##########################################################################
48*b1cdbd2cSJim Jagielski
49*b1cdbd2cSJim Jagielskisub assign_cab_to_files
50*b1cdbd2cSJim Jagielski{
51*b1cdbd2cSJim Jagielski	my ( $filesref ) = @_;
52*b1cdbd2cSJim Jagielski
53*b1cdbd2cSJim Jagielski	my $infoline = "";
54*b1cdbd2cSJim Jagielski
55*b1cdbd2cSJim Jagielski	foreach my $file (@$filesref)
56*b1cdbd2cSJim Jagielski	{
57*b1cdbd2cSJim Jagielski		if ( ! exists($file->{'modules'}) )
58*b1cdbd2cSJim Jagielski        {
59*b1cdbd2cSJim Jagielski            installer::exiter::exit_program(
60*b1cdbd2cSJim Jagielski                sprintf("ERROR: No module assignment found for %s", $file->{'gid'}),
61*b1cdbd2cSJim Jagielski                "assign_cab_to_files");
62*b1cdbd2cSJim Jagielski        }
63*b1cdbd2cSJim Jagielski		my $module = $file->{'modules'};
64*b1cdbd2cSJim Jagielski		# If modules contains a list of modules, only taking the first one.
65*b1cdbd2cSJim Jagielski		if ( $module =~ /^\s*(.*?)\,/ ) { $module = $1; }
66*b1cdbd2cSJim Jagielski
67*b1cdbd2cSJim Jagielski		if ( ! exists($installer::globals::allcabinetassigns{$module}) )
68*b1cdbd2cSJim Jagielski        {
69*b1cdbd2cSJim Jagielski            installer::exiter::exit_program(
70*b1cdbd2cSJim Jagielski                sprintf("ERROR: No cabinet file assigned to module \"%s\" %s",
71*b1cdbd2cSJim Jagielski                    $module,
72*b1cdbd2cSJim Jagielski                    $file->{'gid'}),
73*b1cdbd2cSJim Jagielski                "assign_cab_to_files");
74*b1cdbd2cSJim Jagielski        }
75*b1cdbd2cSJim Jagielski		$file->{'assignedcabinetfile'} = $installer::globals::allcabinetassigns{$module};
76*b1cdbd2cSJim Jagielski
77*b1cdbd2cSJim Jagielski		# Counting the files in each cabinet file
78*b1cdbd2cSJim Jagielski		if ( ! exists($installer::globals::cabfilecounter{$file->{'assignedcabinetfile'}}) )
79*b1cdbd2cSJim Jagielski		{
80*b1cdbd2cSJim Jagielski			$installer::globals::cabfilecounter{$file->{'assignedcabinetfile'}} = 1;
81*b1cdbd2cSJim Jagielski		}
82*b1cdbd2cSJim Jagielski		else
83*b1cdbd2cSJim Jagielski		{
84*b1cdbd2cSJim Jagielski			$installer::globals::cabfilecounter{$file->{'assignedcabinetfile'}}++;
85*b1cdbd2cSJim Jagielski		}
86*b1cdbd2cSJim Jagielski	}
87*b1cdbd2cSJim Jagielski
88*b1cdbd2cSJim Jagielski	# assigning startsequencenumbers for each cab file
89*b1cdbd2cSJim Jagielski
90*b1cdbd2cSJim Jagielski    my %count = ();
91*b1cdbd2cSJim Jagielski	my $offset = 1;
92*b1cdbd2cSJim Jagielski	foreach my $cabfile ( sort keys %installer::globals::cabfilecounter )
93*b1cdbd2cSJim Jagielski	{
94*b1cdbd2cSJim Jagielski		my $filecount = $installer::globals::cabfilecounter{$cabfile};
95*b1cdbd2cSJim Jagielski        $count{$cabfile} = $filecount;
96*b1cdbd2cSJim Jagielski		$installer::globals::cabfilecounter{$cabfile} = $offset;
97*b1cdbd2cSJim Jagielski		$offset = $offset + $filecount;
98*b1cdbd2cSJim Jagielski
99*b1cdbd2cSJim Jagielski		$installer::globals::lastsequence{$cabfile} = $offset - 1;
100*b1cdbd2cSJim Jagielski	}
101*b1cdbd2cSJim Jagielski
102*b1cdbd2cSJim Jagielski	# logging the number of files in each cabinet file
103*b1cdbd2cSJim Jagielski
104*b1cdbd2cSJim Jagielski	$installer::logger::Lang->print("\n");
105*b1cdbd2cSJim Jagielski	$installer::logger::Lang->print("Cabinet files:\n");
106*b1cdbd2cSJim Jagielski	foreach my $cabfile (sort keys %installer::globals::cabfilecounter)
107*b1cdbd2cSJim Jagielski	{
108*b1cdbd2cSJim Jagielski		$installer::logger::Lang->printf(
109*b1cdbd2cSJim Jagielski            "%-30s : %4s files, from %4d to %4d\n",
110*b1cdbd2cSJim Jagielski            $cabfile,
111*b1cdbd2cSJim Jagielski            $count{$cabfile},
112*b1cdbd2cSJim Jagielski            $installer::globals::cabfilecounter{$cabfile},
113*b1cdbd2cSJim Jagielski            $installer::globals::lastsequence{$cabfile});
114*b1cdbd2cSJim Jagielski	}
115*b1cdbd2cSJim Jagielski}
116*b1cdbd2cSJim Jagielski
117*b1cdbd2cSJim Jagielski##########################################################################
118*b1cdbd2cSJim Jagielski# Assigning sequencenumbers to files. This is requrired,
119*b1cdbd2cSJim Jagielski# if cabinet files shall be equivalent to packages.
120*b1cdbd2cSJim Jagielski##########################################################################
121*b1cdbd2cSJim Jagielski
122*b1cdbd2cSJim Jagielskisub assign_sequencenumbers_to_files
123*b1cdbd2cSJim Jagielski{
124*b1cdbd2cSJim Jagielski	my ( $filesref ) = @_;
125*b1cdbd2cSJim Jagielski
126*b1cdbd2cSJim Jagielski	my %directaccess = ();
127*b1cdbd2cSJim Jagielski	my %allassigns = ();
128*b1cdbd2cSJim Jagielski
129*b1cdbd2cSJim Jagielski	for ( my $i = 0; $i <= $#{$filesref}; $i++ )
130*b1cdbd2cSJim Jagielski	{
131*b1cdbd2cSJim Jagielski		my $onefile = ${$filesref}[$i];
132*b1cdbd2cSJim Jagielski
133*b1cdbd2cSJim Jagielski		# Keeping order in cabinet files
134*b1cdbd2cSJim Jagielski		# -> collecting all files in one cabinet file
135*b1cdbd2cSJim Jagielski		# -> sorting files and assigning numbers
136*b1cdbd2cSJim Jagielski
137*b1cdbd2cSJim Jagielski		# Saving counter $i for direct access into files array
138*b1cdbd2cSJim Jagielski		# "destination" of the file is a unique identifier ('Name' is not unique!)
139*b1cdbd2cSJim Jagielski		if ( exists($directaccess{$onefile->{'destination'}}) ) { installer::exiter::exit_program("ERROR: 'destination' at file not unique: $onefile->{'destination'}", "assign_sequencenumbers_to_files"); }
140*b1cdbd2cSJim Jagielski		$directaccess{$onefile->{'destination'}} = $i;
141*b1cdbd2cSJim Jagielski
142*b1cdbd2cSJim Jagielski		my $cabfilename = $onefile->{'assignedcabinetfile'};
143*b1cdbd2cSJim Jagielski		# collecting files in cabinet files
144*b1cdbd2cSJim Jagielski		if ( ! exists($allassigns{$cabfilename}) )
145*b1cdbd2cSJim Jagielski		{
146*b1cdbd2cSJim Jagielski			my %onecabfile = ();
147*b1cdbd2cSJim Jagielski			$onecabfile{$onefile->{'destination'}} = 1;
148*b1cdbd2cSJim Jagielski			$allassigns{$cabfilename} = \%onecabfile;
149*b1cdbd2cSJim Jagielski		}
150*b1cdbd2cSJim Jagielski		else
151*b1cdbd2cSJim Jagielski		{
152*b1cdbd2cSJim Jagielski			$allassigns{$cabfilename}->{$onefile->{'destination'}} = 1;
153*b1cdbd2cSJim Jagielski		}
154*b1cdbd2cSJim Jagielski	}
155*b1cdbd2cSJim Jagielski
156*b1cdbd2cSJim Jagielski	# Sorting each hash and assigning numbers
157*b1cdbd2cSJim Jagielski	# The destination of the file determines the sort order, not the filename!
158*b1cdbd2cSJim Jagielski	my $cabfile;
159*b1cdbd2cSJim Jagielski	foreach $cabfile ( sort keys %allassigns )
160*b1cdbd2cSJim Jagielski	{
161*b1cdbd2cSJim Jagielski		my $counter = $installer::globals::cabfilecounter{$cabfile};
162*b1cdbd2cSJim Jagielski		my $dest;
163*b1cdbd2cSJim Jagielski		foreach $dest ( sort keys %{$allassigns{$cabfile}} ) # <- sorting the destination!
164*b1cdbd2cSJim Jagielski		{
165*b1cdbd2cSJim Jagielski			my $directaccessnumber = $directaccess{$dest};
166*b1cdbd2cSJim Jagielski            ${$filesref}[$directaccessnumber]->{'assignedsequencenumber'} = $counter;
167*b1cdbd2cSJim Jagielski			$counter++;
168*b1cdbd2cSJim Jagielski		}
169*b1cdbd2cSJim Jagielski	}
170*b1cdbd2cSJim Jagielski}
171*b1cdbd2cSJim Jagielski
172*b1cdbd2cSJim Jagielski#########################################################
173*b1cdbd2cSJim Jagielski# Create a shorter version of a long component name,
174*b1cdbd2cSJim Jagielski# because maximum length in msi database is 72.
175*b1cdbd2cSJim Jagielski# Attention: In multi msi installation sets, the short
176*b1cdbd2cSJim Jagielski# names have to be unique over all packages, because
177*b1cdbd2cSJim Jagielski# this string is used to create the globally unique id
178*b1cdbd2cSJim Jagielski# -> no resetting of
179*b1cdbd2cSJim Jagielski# %installer::globals::allshortcomponents
180*b1cdbd2cSJim Jagielski# after a package was created.
181*b1cdbd2cSJim Jagielski# Using no counter because of reproducibility.
182*b1cdbd2cSJim Jagielski#########################################################
183*b1cdbd2cSJim Jagielski
184*b1cdbd2cSJim Jagielskisub generate_new_short_componentname
185*b1cdbd2cSJim Jagielski{
186*b1cdbd2cSJim Jagielski	my ($componentname) = @_;
187*b1cdbd2cSJim Jagielski
188*b1cdbd2cSJim Jagielski	my $startversion = substr($componentname, 0, 60); # taking only the first 60 characters
189*b1cdbd2cSJim Jagielski	my $subid = installer::windows::msiglobal::calculate_id($componentname, 9); # taking only the first 9 digits
190*b1cdbd2cSJim Jagielski	my $shortcomponentname = $startversion . "_" . $subid;
191*b1cdbd2cSJim Jagielski
192*b1cdbd2cSJim Jagielski	if ( exists($installer::globals::allshortcomponents{$shortcomponentname}) ) { installer::exiter::exit_program("Failed to create unique component name: \"$shortcomponentname\"", "generate_new_short_componentname"); }
193*b1cdbd2cSJim Jagielski
194*b1cdbd2cSJim Jagielski	$installer::globals::allshortcomponents{$shortcomponentname} = 1;
195*b1cdbd2cSJim Jagielski
196*b1cdbd2cSJim Jagielski	return $shortcomponentname;
197*b1cdbd2cSJim Jagielski}
198*b1cdbd2cSJim Jagielski
199*b1cdbd2cSJim Jagielski###############################################
200*b1cdbd2cSJim Jagielski# Generating the component name from a file
201*b1cdbd2cSJim Jagielski###############################################
202*b1cdbd2cSJim Jagielski
203*b1cdbd2cSJim Jagielskisub get_file_component_name
204*b1cdbd2cSJim Jagielski{
205*b1cdbd2cSJim Jagielski	my ($fileref, $filesref) = @_;
206*b1cdbd2cSJim Jagielski
207*b1cdbd2cSJim Jagielski	my $componentname = "";
208*b1cdbd2cSJim Jagielski
209*b1cdbd2cSJim Jagielski	# Special handling for files with ASSIGNCOMPOMENT
210*b1cdbd2cSJim Jagielski
211*b1cdbd2cSJim Jagielski	my $styles = "";
212*b1cdbd2cSJim Jagielski	if ( $fileref->{'Styles'} ) { $styles = $fileref->{'Styles'}; }
213*b1cdbd2cSJim Jagielski	if ( $styles =~ /\bASSIGNCOMPOMENT\b/ )
214*b1cdbd2cSJim Jagielski	{
215*b1cdbd2cSJim Jagielski		$componentname = get_component_from_assigned_file($fileref->{'AssignComponent'}, $filesref);
216*b1cdbd2cSJim Jagielski	}
217*b1cdbd2cSJim Jagielski	else
218*b1cdbd2cSJim Jagielski	{
219*b1cdbd2cSJim Jagielski		# In this function exists the rule to create components from files
220*b1cdbd2cSJim Jagielski		# Rule:
221*b1cdbd2cSJim Jagielski		# Two files get the same componentid, if:
222*b1cdbd2cSJim Jagielski		# both have the same destination directory.
223*b1cdbd2cSJim Jagielski		# both have the same "gid" -> both were packed in the same zip file
224*b1cdbd2cSJim Jagielski		# All other files are included into different components!
225*b1cdbd2cSJim Jagielski
226*b1cdbd2cSJim Jagielski		# my $componentname = $fileref->{'gid'} . "_" . $fileref->{'Dir'};
227*b1cdbd2cSJim Jagielski
228*b1cdbd2cSJim Jagielski		# $fileref->{'Dir'} is not sufficient! All files in a zip file have the same $fileref->{'Dir'},
229*b1cdbd2cSJim Jagielski		# but can be in different subdirectories.
230*b1cdbd2cSJim Jagielski		# Solution: destination=share\Scripts\beanshell\Capitalise\capitalise.bsh
231*b1cdbd2cSJim Jagielski		# in which the filename (capitalise.bsh) has to be removed and all backslashes (slashes) are
232*b1cdbd2cSJim Jagielski		# converted into underline.
233*b1cdbd2cSJim Jagielski
234*b1cdbd2cSJim Jagielski		my $destination = $fileref->{'destination'};
235*b1cdbd2cSJim Jagielski		installer::pathanalyzer::get_path_from_fullqualifiedname(\$destination);
236*b1cdbd2cSJim Jagielski		$destination =~ s/\s//g;
237*b1cdbd2cSJim Jagielski		$destination =~ s/\\/\_/g;
238*b1cdbd2cSJim Jagielski		$destination =~ s/\//\_/g;
239*b1cdbd2cSJim Jagielski		$destination =~ s/\_\s*$//g;	# removing ending underline
240*b1cdbd2cSJim Jagielski
241*b1cdbd2cSJim Jagielski		$componentname = $fileref->{'gid'} . "__" . $destination;
242*b1cdbd2cSJim Jagielski
243*b1cdbd2cSJim Jagielski		# Files with different languages, need to be packed into different components.
244*b1cdbd2cSJim Jagielski		# Then the installation of the language specific component is determined by a language condition.
245*b1cdbd2cSJim Jagielski
246*b1cdbd2cSJim Jagielski		if ( $fileref->{'ismultilingual'} )
247*b1cdbd2cSJim Jagielski		{
248*b1cdbd2cSJim Jagielski			my $officelanguage = $fileref->{'specificlanguage'};
249*b1cdbd2cSJim Jagielski			$componentname = $componentname . "_" . $officelanguage;
250*b1cdbd2cSJim Jagielski		}
251*b1cdbd2cSJim Jagielski
252*b1cdbd2cSJim Jagielski		$componentname = lc($componentname);	# componentnames always lowercase
253*b1cdbd2cSJim Jagielski
254*b1cdbd2cSJim Jagielski		$componentname =~ s/\-/\_/g;			# converting "-" to "_"
255*b1cdbd2cSJim Jagielski		$componentname =~ s/\./\_/g;			# converting "-" to "_"
256*b1cdbd2cSJim Jagielski
257*b1cdbd2cSJim Jagielski		# Attention: Maximum length for the componentname is 72
258*b1cdbd2cSJim Jagielski		# %installer::globals::allcomponents_in_this_database : resetted for each database
259*b1cdbd2cSJim Jagielski		# %installer::globals::allcomponents : not resetted for each database
260*b1cdbd2cSJim Jagielski		# Component strings must be unique for the complete product, because they are used for
261*b1cdbd2cSJim Jagielski		# the creation of the globally unique identifier.
262*b1cdbd2cSJim Jagielski
263*b1cdbd2cSJim Jagielski		my $fullname = $componentname;  # This can be longer than 72
264*b1cdbd2cSJim Jagielski
265*b1cdbd2cSJim Jagielski		if (( exists($installer::globals::allcomponents{$fullname}) ) && ( ! exists($installer::globals::allcomponents_in_this_database{$fullname}) ))
266*b1cdbd2cSJim Jagielski		{
267*b1cdbd2cSJim Jagielski			# This is not allowed: One component cannot be installed with different packages.
268*b1cdbd2cSJim Jagielski			installer::exiter::exit_program("ERROR: Component \"$fullname\" is already included into another package. This is not allowed.", "get_file_component_name");
269*b1cdbd2cSJim Jagielski		}
270*b1cdbd2cSJim Jagielski
271*b1cdbd2cSJim Jagielski		if ( exists($installer::globals::allcomponents{$fullname}) )
272*b1cdbd2cSJim Jagielski		{
273*b1cdbd2cSJim Jagielski			$componentname = $installer::globals::allcomponents{$fullname};
274*b1cdbd2cSJim Jagielski		}
275*b1cdbd2cSJim Jagielski		else
276*b1cdbd2cSJim Jagielski		{
277*b1cdbd2cSJim Jagielski			if ( length($componentname) > 70 )
278*b1cdbd2cSJim Jagielski			{
279*b1cdbd2cSJim Jagielski				$componentname = generate_new_short_componentname($componentname); # This has to be unique for the complete product, not only one package
280*b1cdbd2cSJim Jagielski			}
281*b1cdbd2cSJim Jagielski
282*b1cdbd2cSJim Jagielski			$installer::globals::allcomponents{$fullname} = $componentname;
283*b1cdbd2cSJim Jagielski			$installer::globals::allcomponents_in_this_database{$fullname} = 1;
284*b1cdbd2cSJim Jagielski		}
285*b1cdbd2cSJim Jagielski
286*b1cdbd2cSJim Jagielski		# $componentname =~ s/gid_file_/g_f_/g;
287*b1cdbd2cSJim Jagielski		# $componentname =~ s/_extra_/_e_/g;
288*b1cdbd2cSJim Jagielski		# $componentname =~ s/_config_/_c_/g;
289*b1cdbd2cSJim Jagielski		# $componentname =~ s/_org_openoffice_/_o_o_/g;
290*b1cdbd2cSJim Jagielski		# $componentname =~ s/_program_/_p_/g;
291*b1cdbd2cSJim Jagielski		# $componentname =~ s/_typedetection_/_td_/g;
292*b1cdbd2cSJim Jagielski		# $componentname =~ s/_linguistic_/_l_/g;
293*b1cdbd2cSJim Jagielski		# $componentname =~ s/_module_/_m_/g;
294*b1cdbd2cSJim Jagielski		# $componentname =~ s/_optional_/_opt_/g;
295*b1cdbd2cSJim Jagielski		# $componentname =~ s/_packages/_pack/g;
296*b1cdbd2cSJim Jagielski		# $componentname =~ s/_menubar/_mb/g;
297*b1cdbd2cSJim Jagielski		# $componentname =~ s/_common_/_cm_/g;
298*b1cdbd2cSJim Jagielski		# $componentname =~ s/_export_/_exp_/g;
299*b1cdbd2cSJim Jagielski		# $componentname =~ s/_table_/_tb_/g;
300*b1cdbd2cSJim Jagielski		# $componentname =~ s/_sofficecfg_/_sc_/g;
301*b1cdbd2cSJim Jagielski		# $componentname =~ s/_soffice_cfg_/_sc_/g;
302*b1cdbd2cSJim Jagielski		# $componentname =~ s/_startmodulecommands_/_smc_/g;
303*b1cdbd2cSJim Jagielski		# $componentname =~ s/_drawimpresscommands_/_dic_/g;
304*b1cdbd2cSJim Jagielski		# $componentname =~ s/_basiccommands_/_bac_/g;
305*b1cdbd2cSJim Jagielski		# $componentname =~ s/_basicidecommands_/_baic_/g;
306*b1cdbd2cSJim Jagielski		# $componentname =~ s/_genericcommands_/_genc_/g;
307*b1cdbd2cSJim Jagielski		# $componentname =~ s/_bibliographycommands_/_bibc_/g;
308*b1cdbd2cSJim Jagielski		# $componentname =~ s/_gentiumbookbasicbolditalic_/_gbbbi_/g;
309*b1cdbd2cSJim Jagielski		# $componentname =~ s/_share_/_s_/g;
310*b1cdbd2cSJim Jagielski		# $componentname =~ s/_extension_/_ext_/g;
311*b1cdbd2cSJim Jagielski		# $componentname =~ s/_extensions_/_exs_/g;
312*b1cdbd2cSJim Jagielski		# $componentname =~ s/_modules_/_ms_/g;
313*b1cdbd2cSJim Jagielski		# $componentname =~ s/_uiconfig_zip_/_ucz_/g;
314*b1cdbd2cSJim Jagielski		# $componentname =~ s/_productivity_/_pr_/g;
315*b1cdbd2cSJim Jagielski		# $componentname =~ s/_wizard_/_wz_/g;
316*b1cdbd2cSJim Jagielski		# $componentname =~ s/_import_/_im_/g;
317*b1cdbd2cSJim Jagielski		# $componentname =~ s/_javascript_/_js_/g;
318*b1cdbd2cSJim Jagielski		# $componentname =~ s/_template_/_tpl_/g;
319*b1cdbd2cSJim Jagielski		# $componentname =~ s/_tplwizletter_/_twl_/g;
320*b1cdbd2cSJim Jagielski		# $componentname =~ s/_beanshell_/_bs_/g;
321*b1cdbd2cSJim Jagielski		# $componentname =~ s/_presentation_/_bs_/g;
322*b1cdbd2cSJim Jagielski		# $componentname =~ s/_columns_/_cls_/g;
323*b1cdbd2cSJim Jagielski		# $componentname =~ s/_python_/_py_/g;
324*b1cdbd2cSJim Jagielski
325*b1cdbd2cSJim Jagielski		# $componentname =~ s/_tools/_ts/g;
326*b1cdbd2cSJim Jagielski		# $componentname =~ s/_transitions/_trs/g;
327*b1cdbd2cSJim Jagielski		# $componentname =~ s/_scriptbinding/_scrb/g;
328*b1cdbd2cSJim Jagielski		# $componentname =~ s/_spreadsheet/_ssh/g;
329*b1cdbd2cSJim Jagielski		# $componentname =~ s/_publisher/_pub/g;
330*b1cdbd2cSJim Jagielski		# $componentname =~ s/_presenter/_pre/g;
331*b1cdbd2cSJim Jagielski		# $componentname =~ s/_registry/_reg/g;
332*b1cdbd2cSJim Jagielski
333*b1cdbd2cSJim Jagielski		# $componentname =~ s/screen/sc/g;
334*b1cdbd2cSJim Jagielski		# $componentname =~ s/wordml/wm/g;
335*b1cdbd2cSJim Jagielski		# $componentname =~ s/openoffice/oo/g;
336*b1cdbd2cSJim Jagielski	}
337*b1cdbd2cSJim Jagielski
338*b1cdbd2cSJim Jagielski	return $componentname;
339*b1cdbd2cSJim Jagielski}
340*b1cdbd2cSJim Jagielski
341*b1cdbd2cSJim Jagielski####################################################################
342*b1cdbd2cSJim Jagielski# Returning the component name for a defined file gid.
343*b1cdbd2cSJim Jagielski# This is necessary for files with flag ASSIGNCOMPOMENT
344*b1cdbd2cSJim Jagielski####################################################################
345*b1cdbd2cSJim Jagielski
346*b1cdbd2cSJim Jagielskisub get_component_from_assigned_file
347*b1cdbd2cSJim Jagielski{
348*b1cdbd2cSJim Jagielski	my ($gid, $filesref) = @_;
349*b1cdbd2cSJim Jagielski
350*b1cdbd2cSJim Jagielski	my $onefile = installer::existence::get_specified_file($filesref, $gid);
351*b1cdbd2cSJim Jagielski	my $componentname = "";
352*b1cdbd2cSJim Jagielski	if ( $onefile->{'componentname'} ) { $componentname = $onefile->{'componentname'}; }
353*b1cdbd2cSJim Jagielski	else { installer::exiter::exit_program("ERROR: No component defined for file: $gid", "get_component_from_assigned_file"); }
354*b1cdbd2cSJim Jagielski
355*b1cdbd2cSJim Jagielski	return $componentname;
356*b1cdbd2cSJim Jagielski}
357*b1cdbd2cSJim Jagielski
358*b1cdbd2cSJim Jagielski####################################################################
359*b1cdbd2cSJim Jagielski# Generating the special filename for the database file File.idt
360*b1cdbd2cSJim Jagielski# Sample: CONTEXTS, CONTEXTS1
361*b1cdbd2cSJim Jagielski# This name has to be unique.
362*b1cdbd2cSJim Jagielski# In most cases this is simply the filename.
363*b1cdbd2cSJim Jagielski####################################################################
364*b1cdbd2cSJim Jagielski
365*b1cdbd2cSJim Jagielskisub generate_unique_filename_for_filetable ($)
366*b1cdbd2cSJim Jagielski{
367*b1cdbd2cSJim Jagielski	my ($oldname) = @_;
368*b1cdbd2cSJim Jagielski
369*b1cdbd2cSJim Jagielski	# This new filename has to be saved into $fileref, because this is needed to find the source.
370*b1cdbd2cSJim Jagielski	# The filename sbasic.idx/OFFSETS is changed to OFFSETS, but OFFSETS is not unique.
371*b1cdbd2cSJim Jagielski	# In this procedure names like OFFSETS5 are produced. And exactly this string has to be added to
372*b1cdbd2cSJim Jagielski	# the array of all files.
373*b1cdbd2cSJim Jagielski
374*b1cdbd2cSJim Jagielski	my $uniquefilename = $oldname;
375*b1cdbd2cSJim Jagielski    if ( ! defined $uniquefilename || $uniquefilename eq "")
376*b1cdbd2cSJim Jagielski    {
377*b1cdbd2cSJim Jagielski        installer::logger::PrintError("file name does not exist or is empty, can not create unique name for it.");
378*b1cdbd2cSJim Jagielski        die;
379*b1cdbd2cSJim Jagielski        return;
380*b1cdbd2cSJim Jagielski    }
381*b1cdbd2cSJim Jagielski
382*b1cdbd2cSJim Jagielski   	# making /registry/schema/org/openoffice/VCL.xcs to VCL.xcs
383*b1cdbd2cSJim Jagielski	installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$uniquefilename);
384*b1cdbd2cSJim Jagielski
385*b1cdbd2cSJim Jagielski	$uniquefilename =~ s/\-/\_/g;		# no "-" allowed
386*b1cdbd2cSJim Jagielski	$uniquefilename =~ s/\@/\_/g;		# no "@" allowed
387*b1cdbd2cSJim Jagielski	$uniquefilename =~ s/\$/\_/g;		# no "$" allowed
388*b1cdbd2cSJim Jagielski	$uniquefilename =~ s/^\s*\./\_/g;		# no "." at the beginning allowed allowed
389*b1cdbd2cSJim Jagielski	$uniquefilename =~ s/^\s*\d/\_d/g;		# no number at the beginning allowed allowed (even file "0.gif", replacing to "_d.gif")
390*b1cdbd2cSJim Jagielski	$uniquefilename =~ s/org_openoffice_/ooo_/g;	# shorten the unique file name
391*b1cdbd2cSJim Jagielski
392*b1cdbd2cSJim Jagielski	my $lcuniquefilename = lc($uniquefilename);	# only lowercase names
393*b1cdbd2cSJim Jagielski
394*b1cdbd2cSJim Jagielski	my $newname = 0;
395*b1cdbd2cSJim Jagielski
396*b1cdbd2cSJim Jagielski	if ( ! exists($installer::globals::alllcuniquefilenames{$lcuniquefilename}))
397*b1cdbd2cSJim Jagielski	{
398*b1cdbd2cSJim Jagielski		$installer::globals::alluniquefilenames{$uniquefilename} = 1;
399*b1cdbd2cSJim Jagielski		$installer::globals::alllcuniquefilenames{$lcuniquefilename} = 1;
400*b1cdbd2cSJim Jagielski		$newname = 1;
401*b1cdbd2cSJim Jagielski	}
402*b1cdbd2cSJim Jagielski
403*b1cdbd2cSJim Jagielski	if ( ! $newname )
404*b1cdbd2cSJim Jagielski	{
405*b1cdbd2cSJim Jagielski		# adding a number until the name is really unique: OFFSETS, OFFSETS1, OFFSETS2, ...
406*b1cdbd2cSJim Jagielski		# But attention: Making "abc.xcu" to "abc1.xcu"
407*b1cdbd2cSJim Jagielski
408*b1cdbd2cSJim Jagielski		my $uniquefilenamebase = $uniquefilename;
409*b1cdbd2cSJim Jagielski
410*b1cdbd2cSJim Jagielski        my $counter = 0;
411*b1cdbd2cSJim Jagielski		do
412*b1cdbd2cSJim Jagielski		{
413*b1cdbd2cSJim Jagielski			$counter++;
414*b1cdbd2cSJim Jagielski
415*b1cdbd2cSJim Jagielski			if ( $uniquefilenamebase =~ /\./ )
416*b1cdbd2cSJim Jagielski			{
417*b1cdbd2cSJim Jagielski				$uniquefilename = $uniquefilenamebase;
418*b1cdbd2cSJim Jagielski				$uniquefilename =~ s/\./$counter\./;
419*b1cdbd2cSJim Jagielski			}
420*b1cdbd2cSJim Jagielski			else
421*b1cdbd2cSJim Jagielski			{
422*b1cdbd2cSJim Jagielski				$uniquefilename = $uniquefilenamebase . $counter;
423*b1cdbd2cSJim Jagielski			}
424*b1cdbd2cSJim Jagielski
425*b1cdbd2cSJim Jagielski			$newname = 0;
426*b1cdbd2cSJim Jagielski			$lcuniquefilename = lc($uniquefilename);	# only lowercase names
427*b1cdbd2cSJim Jagielski
428*b1cdbd2cSJim Jagielski			if ( ! exists($installer::globals::alllcuniquefilenames{$lcuniquefilename}))
429*b1cdbd2cSJim Jagielski			{
430*b1cdbd2cSJim Jagielski				$installer::globals::alluniquefilenames{$uniquefilename} = 1;
431*b1cdbd2cSJim Jagielski				$installer::globals::alllcuniquefilenames{$lcuniquefilename} = 1;
432*b1cdbd2cSJim Jagielski				$newname = 1;
433*b1cdbd2cSJim Jagielski			}
434*b1cdbd2cSJim Jagielski		}
435*b1cdbd2cSJim Jagielski		until ( $newname )
436*b1cdbd2cSJim Jagielski	}
437*b1cdbd2cSJim Jagielski
438*b1cdbd2cSJim Jagielski	return $uniquefilename;
439*b1cdbd2cSJim Jagielski}
440*b1cdbd2cSJim Jagielski
441*b1cdbd2cSJim Jagielski####################################################################
442*b1cdbd2cSJim Jagielski# Generating the special file column for the database file File.idt
443*b1cdbd2cSJim Jagielski# Sample: NAMETR~1.TAB|.nametranslation.table
444*b1cdbd2cSJim Jagielski# The first part has to be 8.3 conform.
445*b1cdbd2cSJim Jagielski####################################################################
446*b1cdbd2cSJim Jagielski
447*b1cdbd2cSJim Jagielskisub generate_filename_for_filetable ($$)
448*b1cdbd2cSJim Jagielski{
449*b1cdbd2cSJim Jagielski	my ($fileref, $shortnamesref) = @_;
450*b1cdbd2cSJim Jagielski
451*b1cdbd2cSJim Jagielski	my $returnstring = "";
452*b1cdbd2cSJim Jagielski
453*b1cdbd2cSJim Jagielski	my $filename = $fileref->{'Name'};
454*b1cdbd2cSJim Jagielski
455*b1cdbd2cSJim Jagielski    # making /registry/schema/org/openoffice/VCL.xcs to VCL.xcs
456*b1cdbd2cSJim Jagielski	installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$filename);
457*b1cdbd2cSJim Jagielski
458*b1cdbd2cSJim Jagielski	my $shortstring = installer::windows::idtglobal::make_eight_three_conform_with_hash($filename, "file", $shortnamesref);
459*b1cdbd2cSJim Jagielski
460*b1cdbd2cSJim Jagielski	if ( $shortstring eq $filename )
461*b1cdbd2cSJim Jagielski    {
462*b1cdbd2cSJim Jagielski        # nothing changed
463*b1cdbd2cSJim Jagielski        $returnstring = $filename;
464*b1cdbd2cSJim Jagielski    }
465*b1cdbd2cSJim Jagielski	else
466*b1cdbd2cSJim Jagielski    {
467*b1cdbd2cSJim Jagielski        $returnstring = $shortstring . "\|" . $filename;
468*b1cdbd2cSJim Jagielski    }
469*b1cdbd2cSJim Jagielski
470*b1cdbd2cSJim Jagielski	return $returnstring;
471*b1cdbd2cSJim Jagielski}
472*b1cdbd2cSJim Jagielski
473*b1cdbd2cSJim Jagielski#########################################
474*b1cdbd2cSJim Jagielski# Returning the filesize of a file
475*b1cdbd2cSJim Jagielski#########################################
476*b1cdbd2cSJim Jagielski
477*b1cdbd2cSJim Jagielskisub get_filesize
478*b1cdbd2cSJim Jagielski{
479*b1cdbd2cSJim Jagielski	my ($fileref) = @_;
480*b1cdbd2cSJim Jagielski
481*b1cdbd2cSJim Jagielski	my $file = $fileref->{'sourcepath'};
482*b1cdbd2cSJim Jagielski
483*b1cdbd2cSJim Jagielski	my $filesize;
484*b1cdbd2cSJim Jagielski
485*b1cdbd2cSJim Jagielski	if ( -f $file )	# test of existence. For instance services.rdb does not always exist
486*b1cdbd2cSJim Jagielski	{
487*b1cdbd2cSJim Jagielski		$filesize = ( -s $file );	# file size can be "0"
488*b1cdbd2cSJim Jagielski	}
489*b1cdbd2cSJim Jagielski	else
490*b1cdbd2cSJim Jagielski	{
491*b1cdbd2cSJim Jagielski		$filesize = -1;
492*b1cdbd2cSJim Jagielski	}
493*b1cdbd2cSJim Jagielski
494*b1cdbd2cSJim Jagielski	return $filesize;
495*b1cdbd2cSJim Jagielski}
496*b1cdbd2cSJim Jagielski
497*b1cdbd2cSJim Jagielski#############################################
498*b1cdbd2cSJim Jagielski# Returning the file version, if required
499*b1cdbd2cSJim Jagielski# Sample: "8.0.1.8976";
500*b1cdbd2cSJim Jagielski#############################################
501*b1cdbd2cSJim Jagielski
502*b1cdbd2cSJim Jagielskisub get_fileversion
503*b1cdbd2cSJim Jagielski{
504*b1cdbd2cSJim Jagielski	my ($onefile, $allvariables) = @_;
505*b1cdbd2cSJim Jagielski
506*b1cdbd2cSJim Jagielski	my $fileversion = "";
507*b1cdbd2cSJim Jagielski
508*b1cdbd2cSJim Jagielski	if ( $allvariables->{'USE_FILEVERSION'} )
509*b1cdbd2cSJim Jagielski	{
510*b1cdbd2cSJim Jagielski		if ( ! $allvariables->{'LIBRARYVERSION'} )
511*b1cdbd2cSJim Jagielski        {
512*b1cdbd2cSJim Jagielski            installer::exiter::exit_program("ERROR: USE_FILEVERSION is set, but not LIBRARYVERSION", "get_fileversion");
513*b1cdbd2cSJim Jagielski        }
514*b1cdbd2cSJim Jagielski		my $libraryversion = $allvariables->{'LIBRARYVERSION'};
515*b1cdbd2cSJim Jagielski		if ( $libraryversion =~ /^\s*(\d+)\.(\d+)\.(\d+)\s*$/ )
516*b1cdbd2cSJim Jagielski		{
517*b1cdbd2cSJim Jagielski			my $major = $1;
518*b1cdbd2cSJim Jagielski			my $minor = $2;
519*b1cdbd2cSJim Jagielski			my $micro = $3;
520*b1cdbd2cSJim Jagielski			my $concat = 100 * $minor + $micro;
521*b1cdbd2cSJim Jagielski			$libraryversion = $major . "\." . $concat;
522*b1cdbd2cSJim Jagielski		}
523*b1cdbd2cSJim Jagielski		my $vendornumber = 0;
524*b1cdbd2cSJim Jagielski		if ( $allvariables->{'VENDORPATCHVERSION'} )
525*b1cdbd2cSJim Jagielski        {
526*b1cdbd2cSJim Jagielski            $vendornumber = $allvariables->{'VENDORPATCHVERSION'};
527*b1cdbd2cSJim Jagielski        }
528*b1cdbd2cSJim Jagielski		$fileversion = $libraryversion . "\." . $installer::globals::buildid . "\." . $vendornumber;
529*b1cdbd2cSJim Jagielski		if ( $onefile->{'FileVersion'} )
530*b1cdbd2cSJim Jagielski        {
531*b1cdbd2cSJim Jagielski            # overriding FileVersion in scp
532*b1cdbd2cSJim Jagielski            $fileversion = $onefile->{'FileVersion'};
533*b1cdbd2cSJim Jagielski        }
534*b1cdbd2cSJim Jagielski	}
535*b1cdbd2cSJim Jagielski
536*b1cdbd2cSJim Jagielski	if ( $installer::globals::prepare_winpatch )
537*b1cdbd2cSJim Jagielski    {
538*b1cdbd2cSJim Jagielski        # Windows patches do not allow this version # -> who says so?
539*b1cdbd2cSJim Jagielski        $fileversion = "";
540*b1cdbd2cSJim Jagielski    }
541*b1cdbd2cSJim Jagielski
542*b1cdbd2cSJim Jagielski	return $fileversion;
543*b1cdbd2cSJim Jagielski}
544*b1cdbd2cSJim Jagielski
545*b1cdbd2cSJim Jagielski
546*b1cdbd2cSJim Jagielski
547*b1cdbd2cSJim Jagielski
548*b1cdbd2cSJim Jagielskisub retrieve_sequence_and_uniquename ($$)
549*b1cdbd2cSJim Jagielski{
550*b1cdbd2cSJim Jagielski    my ($file_list, $source_data) = @_;
551*b1cdbd2cSJim Jagielski
552*b1cdbd2cSJim Jagielski    my @added_files = ();
553*b1cdbd2cSJim Jagielski
554*b1cdbd2cSJim Jagielski    # Read the sequence numbers of the previous version.
555*b1cdbd2cSJim Jagielski    if ($installer::globals::is_release)
556*b1cdbd2cSJim Jagielski    {
557*b1cdbd2cSJim Jagielski        foreach my $file (@$file_list)
558*b1cdbd2cSJim Jagielski        {
559*b1cdbd2cSJim Jagielski            # Use the source path of the file as key to retrieve sequence number and unique name.
560*b1cdbd2cSJim Jagielski            # The source path is the part of the 'destination' without the first part.
561*b1cdbd2cSJim Jagielski            # There is a special case when 'Dir' is PREDEFINED_OSSHELLNEWDIR.
562*b1cdbd2cSJim Jagielski            my $source_path;
563*b1cdbd2cSJim Jagielski            if (defined $file->{'Dir'} && $file->{'Dir'} eq "PREDEFINED_OSSHELLNEWDIR")
564*b1cdbd2cSJim Jagielski            {
565*b1cdbd2cSJim Jagielski                $source_path = $installer::globals::templatefoldername
566*b1cdbd2cSJim Jagielski                    . $installer::globals::separator
567*b1cdbd2cSJim Jagielski                    . $file->{'Name'};
568*b1cdbd2cSJim Jagielski            }
569*b1cdbd2cSJim Jagielski            else
570*b1cdbd2cSJim Jagielski            {
571*b1cdbd2cSJim Jagielski                $source_path = $file->{'destination'};
572*b1cdbd2cSJim Jagielski                $source_path =~ s/^[^\/]+\///;
573*b1cdbd2cSJim Jagielski            }
574*b1cdbd2cSJim Jagielski            my ($sequence, $uniquename) = $source_data->get_sequence_and_unique_name($source_path);
575*b1cdbd2cSJim Jagielski            if (defined $sequence && defined $uniquename)
576*b1cdbd2cSJim Jagielski            {
577*b1cdbd2cSJim Jagielski                $file->{'sequencenumber'} = $sequence;
578*b1cdbd2cSJim Jagielski                $file->{'uniquename'} = $uniquename;
579*b1cdbd2cSJim Jagielski            }
580*b1cdbd2cSJim Jagielski            else
581*b1cdbd2cSJim Jagielski            {
582*b1cdbd2cSJim Jagielski                # No data found in the source release.  File has been added.
583*b1cdbd2cSJim Jagielski                push @added_files, $file;
584*b1cdbd2cSJim Jagielski            }
585*b1cdbd2cSJim Jagielski        }
586*b1cdbd2cSJim Jagielski    }
587*b1cdbd2cSJim Jagielski
588*b1cdbd2cSJim Jagielski    return @added_files;
589*b1cdbd2cSJim Jagielski}
590*b1cdbd2cSJim Jagielski
591*b1cdbd2cSJim Jagielski
592*b1cdbd2cSJim Jagielski
593*b1cdbd2cSJim Jagielski
594*b1cdbd2cSJim Jagielski=head2 assign_mssing_sequence_numbers ($file_list)
595*b1cdbd2cSJim Jagielski
596*b1cdbd2cSJim Jagielski    Assign sequence numbers where still missing.
597*b1cdbd2cSJim Jagielski
598*b1cdbd2cSJim Jagielski    When we are preparing a patch then all files that have no sequence numbers
599*b1cdbd2cSJim Jagielski    at this point are new.  Otherwise no file has a sequence number yet.
600*b1cdbd2cSJim Jagielski
601*b1cdbd2cSJim Jagielski=cut
602*b1cdbd2cSJim Jagielskisub assign_missing_sequence_numbers ($)
603*b1cdbd2cSJim Jagielski{
604*b1cdbd2cSJim Jagielski    my ($file_list) = @_;
605*b1cdbd2cSJim Jagielski
606*b1cdbd2cSJim Jagielski    # First, set up a hash on the sequence numbers that are already in use.
607*b1cdbd2cSJim Jagielski    my %used_sequence_numbers = ();
608*b1cdbd2cSJim Jagielski    foreach my $file (@$file_list)
609*b1cdbd2cSJim Jagielski    {
610*b1cdbd2cSJim Jagielski        next unless defined $file->{'sequencenumber'};
611*b1cdbd2cSJim Jagielski        $used_sequence_numbers{$file->{'sequencenumber'}} = 1;
612*b1cdbd2cSJim Jagielski    }
613*b1cdbd2cSJim Jagielski
614*b1cdbd2cSJim Jagielski    # Assign sequence numbers.  Try consecutive numbers, starting at 1.
615*b1cdbd2cSJim Jagielski    my $current_sequence_number = 1;
616*b1cdbd2cSJim Jagielski    foreach my $file (@$file_list)
617*b1cdbd2cSJim Jagielski    {
618*b1cdbd2cSJim Jagielski        # Skip over all files that already have sequence numbers.
619*b1cdbd2cSJim Jagielski        next if defined $file->{'sequencenumber'};
620*b1cdbd2cSJim Jagielski
621*b1cdbd2cSJim Jagielski        # Find the next available number.
622*b1cdbd2cSJim Jagielski        while (defined $used_sequence_numbers{$current_sequence_number})
623*b1cdbd2cSJim Jagielski        {
624*b1cdbd2cSJim Jagielski            ++$current_sequence_number;
625*b1cdbd2cSJim Jagielski        }
626*b1cdbd2cSJim Jagielski
627*b1cdbd2cSJim Jagielski        # Use the number and mark it as used.
628*b1cdbd2cSJim Jagielski        $file->{'sequencenumber'} = $current_sequence_number;
629*b1cdbd2cSJim Jagielski        $used_sequence_numbers{$current_sequence_number} = 1;
630*b1cdbd2cSJim Jagielski    }
631*b1cdbd2cSJim Jagielski}
632*b1cdbd2cSJim Jagielski
633*b1cdbd2cSJim Jagielski
634*b1cdbd2cSJim Jagielski
635*b1cdbd2cSJim Jagielski
636*b1cdbd2cSJim Jagielskisub create_items_for_missing_files ($$$)
637*b1cdbd2cSJim Jagielski{
638*b1cdbd2cSJim Jagielski    my ($missing_items, $source_msi, $directory_list) = @_;
639*b1cdbd2cSJim Jagielski
640*b1cdbd2cSJim Jagielski    # For creation of the FeatureComponent table (in a later step) we
641*b1cdbd2cSJim Jagielski    # have to provide references from the file to component and
642*b1cdbd2cSJim Jagielski    # modules (ie features).  Note that Each file belongs to exactly
643*b1cdbd2cSJim Jagielski    # one component but one component can belong to multiple features.
644*b1cdbd2cSJim Jagielski    my $component_to_features_map = create_feature_component_map($source_msi);
645*b1cdbd2cSJim Jagielski
646*b1cdbd2cSJim Jagielski    my @new_files = ();
647*b1cdbd2cSJim Jagielski    foreach my $row (@$missing_items)
648*b1cdbd2cSJim Jagielski    {
649*b1cdbd2cSJim Jagielski        $installer::logger::Info->printf("creating new file item for '%s'\n", $row->GetValue('File'));
650*b1cdbd2cSJim Jagielski        my $file_item = create_script_item_for_deleted_file($row, $source_msi, $component_to_features_map);
651*b1cdbd2cSJim Jagielski        push @new_files, $file_item;
652*b1cdbd2cSJim Jagielski    }
653*b1cdbd2cSJim Jagielski
654*b1cdbd2cSJim Jagielski    return @new_files;
655*b1cdbd2cSJim Jagielski}
656*b1cdbd2cSJim Jagielski
657*b1cdbd2cSJim Jagielski
658*b1cdbd2cSJim Jagielski
659*b1cdbd2cSJim Jagielski
660*b1cdbd2cSJim Jagielski=head2 create_script_item_for_deleted_file (($file_row, $source_msi, $component_to_features_map)
661*b1cdbd2cSJim Jagielski
662*b1cdbd2cSJim Jagielski    Create a new script item for a file that was present in the
663*b1cdbd2cSJim Jagielski    previous release but isn't anymore.  Most of the necessary
664*b1cdbd2cSJim Jagielski    information is taken from the 'File' table of the source release.
665*b1cdbd2cSJim Jagielski
666*b1cdbd2cSJim Jagielski    The values of 'sourcepath' and 'cyg_sourcepath' will point to the
667*b1cdbd2cSJim Jagielski    respective file in the unpacked source release.  An alternative
668*b1cdbd2cSJim Jagielski    would be to let them point to an empty file.  That, however, might
669*b1cdbd2cSJim Jagielski    make the patch bigger (diff between identical file contents is
670*b1cdbd2cSJim Jagielski    (almost) empty, diff between file and empty file is the 'inverse'
671*b1cdbd2cSJim Jagielski    of the file).
672*b1cdbd2cSJim Jagielski
673*b1cdbd2cSJim Jagielski=cut
674*b1cdbd2cSJim Jagielski
675*b1cdbd2cSJim Jagielskimy $use_source_files_for_missing_files = 1;
676*b1cdbd2cSJim Jagielski
677*b1cdbd2cSJim Jagielskisub create_script_item_for_deleted_file ($$$)
678*b1cdbd2cSJim Jagielski{
679*b1cdbd2cSJim Jagielski    my ($file_row, $source_msi, $component_to_features_map) = @_;
680*b1cdbd2cSJim Jagielski
681*b1cdbd2cSJim Jagielski    my $uniquename = $file_row->GetValue('File');
682*b1cdbd2cSJim Jagielski
683*b1cdbd2cSJim Jagielski    my $file_map = $source_msi->GetFileMap();
684*b1cdbd2cSJim Jagielski
685*b1cdbd2cSJim Jagielski    my $file_item = $file_map->{$uniquename};
686*b1cdbd2cSJim Jagielski    my $directory_item = $file_item->{'directory'};
687*b1cdbd2cSJim Jagielski    my $source_path = $directory_item->{'full_source_long_name'};
688*b1cdbd2cSJim Jagielski    my $target_path = $directory_item->{'full_target_long_name'};
689*b1cdbd2cSJim Jagielski    my $full_source_name = undef;
690*b1cdbd2cSJim Jagielski    if ($use_source_files_for_missing_files)
691*b1cdbd2cSJim Jagielski    {
692*b1cdbd2cSJim Jagielski        $full_source_name = File::Spec->catfile(
693*b1cdbd2cSJim Jagielski            installer::patch::InstallationSet::GetUnpackedCabPath(
694*b1cdbd2cSJim Jagielski                $source_msi->{'version'},
695*b1cdbd2cSJim Jagielski                $source_msi->{'is_current_version'},
696*b1cdbd2cSJim Jagielski                $source_msi->{'language'},
697*b1cdbd2cSJim Jagielski                $source_msi->{'package_format'},
698*b1cdbd2cSJim Jagielski                $source_msi->{'product_name'}),
699*b1cdbd2cSJim Jagielski            $source_path,
700*b1cdbd2cSJim Jagielski            $file_item->{'long_name'});
701*b1cdbd2cSJim Jagielski    }
702*b1cdbd2cSJim Jagielski    else
703*b1cdbd2cSJim Jagielski    {
704*b1cdbd2cSJim Jagielski        $full_source_name = "/c/tmp/missing/".$uniquename;
705*b1cdbd2cSJim Jagielski        installer::patch::Tools::touch($full_source_name);
706*b1cdbd2cSJim Jagielski    }
707*b1cdbd2cSJim Jagielski    my ($long_name, undef) = installer::patch::Msi::SplitLongShortName($file_row->GetValue("FileName"));
708*b1cdbd2cSJim Jagielski    my $target_name = File::Spec->catfile($target_path, $long_name);
709*b1cdbd2cSJim Jagielski    if ( ! -f $full_source_name)
710*b1cdbd2cSJim Jagielski    {
711*b1cdbd2cSJim Jagielski        installer::logger::PrintError("can not find file '%s' in previous version (tried '%s')\n",
712*b1cdbd2cSJim Jagielski            $uniquename,
713*b1cdbd2cSJim Jagielski            $full_source_name);
714*b1cdbd2cSJim Jagielski        return undef;
715*b1cdbd2cSJim Jagielski    }
716*b1cdbd2cSJim Jagielski    my $cygwin_full_source_name = qx(cygpath -w '$full_source_name');
717*b1cdbd2cSJim Jagielski    my $component_name = $file_row->GetValue('Component_');
718*b1cdbd2cSJim Jagielski    my $module_names = join(",", @{$component_to_features_map->{$component_name}});
719*b1cdbd2cSJim Jagielski    my $sequence_number = $file_row->GetValue('Sequence');
720*b1cdbd2cSJim Jagielski
721*b1cdbd2cSJim Jagielski    return {
722*b1cdbd2cSJim Jagielski        'uniquename' => $uniquename,
723*b1cdbd2cSJim Jagielski        'destination' => $target_name,
724*b1cdbd2cSJim Jagielski        'componentname' => $component_name,
725*b1cdbd2cSJim Jagielski        'modules' => $module_names,
726*b1cdbd2cSJim Jagielski        'UnixRights' => 444,
727*b1cdbd2cSJim Jagielski        'Name' => $long_name,
728*b1cdbd2cSJim Jagielski        'sourcepath' => $full_source_name,
729*b1cdbd2cSJim Jagielski        'cyg_sourcepath' => $cygwin_full_source_name,
730*b1cdbd2cSJim Jagielski        'sequencenumber' => $sequence_number
731*b1cdbd2cSJim Jagielski        };
732*b1cdbd2cSJim Jagielski}
733*b1cdbd2cSJim Jagielski
734*b1cdbd2cSJim Jagielski
735*b1cdbd2cSJim Jagielski
736*b1cdbd2cSJim Jagielski
737*b1cdbd2cSJim Jagielski=head2 create_feature_component_maps($msi)
738*b1cdbd2cSJim Jagielski
739*b1cdbd2cSJim Jagielski    Return a hash map that maps from component names to arrays of
740*b1cdbd2cSJim Jagielski    feature names.  In most cases the array of features contains only
741*b1cdbd2cSJim Jagielski    one element.  But there can be cases where the number is greater.
742*b1cdbd2cSJim Jagielski
743*b1cdbd2cSJim Jagielski=cut
744*b1cdbd2cSJim Jagielskisub create_feature_component_map ($)
745*b1cdbd2cSJim Jagielski{
746*b1cdbd2cSJim Jagielski    my ($msi) = @_;
747*b1cdbd2cSJim Jagielski
748*b1cdbd2cSJim Jagielski    my $component_to_features_map = {};
749*b1cdbd2cSJim Jagielski    my $feature_component_table = $msi->GetTable("FeatureComponents");
750*b1cdbd2cSJim Jagielski    my $feature_column_index = $feature_component_table->GetColumnIndex("Feature_");
751*b1cdbd2cSJim Jagielski    my $component_column_index = $feature_component_table->GetColumnIndex("Component_");
752*b1cdbd2cSJim Jagielski    foreach my $row (@{$feature_component_table->GetAllRows()})
753*b1cdbd2cSJim Jagielski    {
754*b1cdbd2cSJim Jagielski        my $feature = $row->GetValue($feature_column_index);
755*b1cdbd2cSJim Jagielski        my $component = $row->GetValue($component_column_index);
756*b1cdbd2cSJim Jagielski        if ( ! defined $component_to_features_map->{$component})
757*b1cdbd2cSJim Jagielski        {
758*b1cdbd2cSJim Jagielski            $component_to_features_map->{$component} = [$feature];
759*b1cdbd2cSJim Jagielski        }
760*b1cdbd2cSJim Jagielski        else
761*b1cdbd2cSJim Jagielski        {
762*b1cdbd2cSJim Jagielski            push @{$component_to_features_map->{$component}}, $feature;
763*b1cdbd2cSJim Jagielski        }
764*b1cdbd2cSJim Jagielski    }
765*b1cdbd2cSJim Jagielski
766*b1cdbd2cSJim Jagielski    return $component_to_features_map;
767*b1cdbd2cSJim Jagielski}
768*b1cdbd2cSJim Jagielski
769*b1cdbd2cSJim Jagielski
770*b1cdbd2cSJim Jagielski#############################################
771*b1cdbd2cSJim Jagielski# Returning the Windows language of a file
772*b1cdbd2cSJim Jagielski#############################################
773*b1cdbd2cSJim Jagielski
774*b1cdbd2cSJim Jagielskisub get_language_for_file
775*b1cdbd2cSJim Jagielski{
776*b1cdbd2cSJim Jagielski	my ($fileref) = @_;
777*b1cdbd2cSJim Jagielski
778*b1cdbd2cSJim Jagielski	my $language = "";
779*b1cdbd2cSJim Jagielski
780*b1cdbd2cSJim Jagielski	if ( $fileref->{'specificlanguage'} ) { $language = $fileref->{'specificlanguage'}; }
781*b1cdbd2cSJim Jagielski
782*b1cdbd2cSJim Jagielski	if ( $language eq "" )
783*b1cdbd2cSJim Jagielski	{
784*b1cdbd2cSJim Jagielski		$language = 0;  # language independent
785*b1cdbd2cSJim Jagielski		# If this is not a font, the return value should be "0" (Check ICE 60)
786*b1cdbd2cSJim Jagielski		my $styles = "";
787*b1cdbd2cSJim Jagielski		if ( $fileref->{'Styles'} ) { $styles = $fileref->{'Styles'}; }
788*b1cdbd2cSJim Jagielski		if ( $styles =~ /\bFONT\b/ ) { $language = ""; }
789*b1cdbd2cSJim Jagielski	}
790*b1cdbd2cSJim Jagielski	else
791*b1cdbd2cSJim Jagielski	{
792*b1cdbd2cSJim Jagielski		$language = installer::windows::language::get_windows_language($language);
793*b1cdbd2cSJim Jagielski	}
794*b1cdbd2cSJim Jagielski
795*b1cdbd2cSJim Jagielski	return $language;
796*b1cdbd2cSJim Jagielski}
797*b1cdbd2cSJim Jagielski
798*b1cdbd2cSJim Jagielski####################################################################
799*b1cdbd2cSJim Jagielski# Creating a new KeyPath for components in TemplatesFolder.
800*b1cdbd2cSJim Jagielski####################################################################
801*b1cdbd2cSJim Jagielski
802*b1cdbd2cSJim Jagielskisub generate_registry_keypath
803*b1cdbd2cSJim Jagielski{
804*b1cdbd2cSJim Jagielski	my ($onefile) = @_;
805*b1cdbd2cSJim Jagielski
806*b1cdbd2cSJim Jagielski	my $keypath = $onefile->{'Name'};
807*b1cdbd2cSJim Jagielski	$keypath =~ s/\.//g;
808*b1cdbd2cSJim Jagielski	$keypath = lc($keypath);
809*b1cdbd2cSJim Jagielski	$keypath = "userreg_" . $keypath;
810*b1cdbd2cSJim Jagielski
811*b1cdbd2cSJim Jagielski	return $keypath;
812*b1cdbd2cSJim Jagielski}
813*b1cdbd2cSJim Jagielski
814*b1cdbd2cSJim Jagielski
815*b1cdbd2cSJim Jagielski###################################################################
816*b1cdbd2cSJim Jagielski# Collecting further conditions for the component table.
817*b1cdbd2cSJim Jagielski# This is used by multilayer products, to enable installation
818*b1cdbd2cSJim Jagielski# of separate layers.
819*b1cdbd2cSJim Jagielski###################################################################
820*b1cdbd2cSJim Jagielski
821*b1cdbd2cSJim Jagielskisub get_tree_condition_for_component
822*b1cdbd2cSJim Jagielski{
823*b1cdbd2cSJim Jagielski	my ($onefile, $componentname) = @_;
824*b1cdbd2cSJim Jagielski
825*b1cdbd2cSJim Jagielski	if ( $onefile->{'destination'} )
826*b1cdbd2cSJim Jagielski	{
827*b1cdbd2cSJim Jagielski		my $dest = $onefile->{'destination'};
828*b1cdbd2cSJim Jagielski
829*b1cdbd2cSJim Jagielski		# Comparing the destination path with
830*b1cdbd2cSJim Jagielski		# $installer::globals::hostnametreestyles{$hostname} = $treestyle;
831*b1cdbd2cSJim Jagielski		# (-> hostname is the key, the style the value!)
832*b1cdbd2cSJim Jagielski
833*b1cdbd2cSJim Jagielski		foreach my $hostname ( keys %installer::globals::hostnametreestyles )
834*b1cdbd2cSJim Jagielski		{
835*b1cdbd2cSJim Jagielski			if (( $dest eq $hostname ) || ( $dest =~ /^\s*\Q$hostname\E\\/ ))
836*b1cdbd2cSJim Jagielski			{
837*b1cdbd2cSJim Jagielski				# the value is the style
838*b1cdbd2cSJim Jagielski				my $style = $installer::globals::hostnametreestyles{$hostname};
839*b1cdbd2cSJim Jagielski				# the condition is saved in %installer::globals::treestyles
840*b1cdbd2cSJim Jagielski				my $condition = $installer::globals::treestyles{$style};
841*b1cdbd2cSJim Jagielski				# Saving condition to be added in table Property
842*b1cdbd2cSJim Jagielski				$installer::globals::usedtreeconditions{$condition} = 1;
843*b1cdbd2cSJim Jagielski				$condition = $condition . "=1";
844*b1cdbd2cSJim Jagielski				# saving this condition
845*b1cdbd2cSJim Jagielski				$installer::globals::treeconditions{$componentname} = $condition;
846*b1cdbd2cSJim Jagielski
847*b1cdbd2cSJim Jagielski				# saving also at the file, for usage in fileinfo
848*b1cdbd2cSJim Jagielski				$onefile->{'layer'} = $installer::globals::treelayername{$style};
849*b1cdbd2cSJim Jagielski			}
850*b1cdbd2cSJim Jagielski		}
851*b1cdbd2cSJim Jagielski	}
852*b1cdbd2cSJim Jagielski}
853*b1cdbd2cSJim Jagielski
854*b1cdbd2cSJim Jagielski############################################
855*b1cdbd2cSJim Jagielski# Collecting all short names, that are
856*b1cdbd2cSJim Jagielski# already used by the old database
857*b1cdbd2cSJim Jagielski############################################
858*b1cdbd2cSJim Jagielski
859*b1cdbd2cSJim Jagielskisub collect_shortnames_from_old_database
860*b1cdbd2cSJim Jagielski{
861*b1cdbd2cSJim Jagielski	my ($uniquefilenamehashref, $shortnameshashref) = @_;
862*b1cdbd2cSJim Jagielski
863*b1cdbd2cSJim Jagielski	foreach my $key ( keys %{$uniquefilenamehashref} )
864*b1cdbd2cSJim Jagielski	{
865*b1cdbd2cSJim Jagielski		my $value = $uniquefilenamehashref->{$key};  # syntax of $value: ($uniquename;$shortname)
866*b1cdbd2cSJim Jagielski
867*b1cdbd2cSJim Jagielski		if ( $value =~ /^\s*(.*?)\;\s*(.*?)\s*$/ )
868*b1cdbd2cSJim Jagielski		{
869*b1cdbd2cSJim Jagielski			my $shortstring = $2;
870*b1cdbd2cSJim Jagielski			$shortnameshashref->{$shortstring} = 1;	# adding the shortname to the array of all shortnames
871*b1cdbd2cSJim Jagielski		}
872*b1cdbd2cSJim Jagielski	}
873*b1cdbd2cSJim Jagielski}
874*b1cdbd2cSJim Jagielski
875*b1cdbd2cSJim Jagielski
876*b1cdbd2cSJim Jagielskisub process_language_conditions ($)
877*b1cdbd2cSJim Jagielski{
878*b1cdbd2cSJim Jagielski    my ($onefile) = @_;
879*b1cdbd2cSJim Jagielski
880*b1cdbd2cSJim Jagielski    # Collecting all languages specific conditions
881*b1cdbd2cSJim Jagielski    if ( $onefile->{'ismultilingual'} )
882*b1cdbd2cSJim Jagielski    {
883*b1cdbd2cSJim Jagielski        if ( $onefile->{'ComponentCondition'} )
884*b1cdbd2cSJim Jagielski        {
885*b1cdbd2cSJim Jagielski            installer::exiter::exit_program(
886*b1cdbd2cSJim Jagielski                "ERROR: Cannot set language condition. There is already another component condition for file $onefile->{'gid'}: \"$onefile->{'ComponentCondition'}\" !", "create_files_table");
887*b1cdbd2cSJim Jagielski        }
888*b1cdbd2cSJim Jagielski
889*b1cdbd2cSJim Jagielski        if ( $onefile->{'specificlanguage'} eq "" )
890*b1cdbd2cSJim Jagielski        {
891*b1cdbd2cSJim Jagielski            installer::exiter::exit_program(
892*b1cdbd2cSJim Jagielski                "ERROR: There is no specific language for file at language module: $onefile->{'gid'} !", "create_files_table");
893*b1cdbd2cSJim Jagielski        }
894*b1cdbd2cSJim Jagielski        my $locallanguage = $onefile->{'specificlanguage'};
895*b1cdbd2cSJim Jagielski        my $property = "IS" . $onefile->{'windows_language'};
896*b1cdbd2cSJim Jagielski        my $value = 1;
897*b1cdbd2cSJim Jagielski        my $condition = $property . "=" . $value;
898*b1cdbd2cSJim Jagielski
899*b1cdbd2cSJim Jagielski        $onefile->{'ComponentCondition'} = $condition;
900*b1cdbd2cSJim Jagielski
901*b1cdbd2cSJim Jagielski        if ( exists($installer::globals::componentcondition{$onefile->{'componentname'}}))
902*b1cdbd2cSJim Jagielski        {
903*b1cdbd2cSJim Jagielski            if ( $installer::globals::componentcondition{$onefile->{'componentname'}} ne $condition )
904*b1cdbd2cSJim Jagielski            {
905*b1cdbd2cSJim Jagielski                installer::exiter::exit_program(
906*b1cdbd2cSJim Jagielski                    sprintf(
907*b1cdbd2cSJim Jagielski                        "ERROR: There is already another component condition for file %s: \"%s\" and \"%s\" !",
908*b1cdbd2cSJim Jagielski                        $onefile->{'gid'},
909*b1cdbd2cSJim Jagielski                        $installer::globals::componentcondition{$onefile->{'componentname'}},
910*b1cdbd2cSJim Jagielski                        $condition),
911*b1cdbd2cSJim Jagielski                    "create_files_table");
912*b1cdbd2cSJim Jagielski            }
913*b1cdbd2cSJim Jagielski        }
914*b1cdbd2cSJim Jagielski        else
915*b1cdbd2cSJim Jagielski        {
916*b1cdbd2cSJim Jagielski            $installer::globals::componentcondition{$onefile->{'componentname'}} = $condition;
917*b1cdbd2cSJim Jagielski        }
918*b1cdbd2cSJim Jagielski
919*b1cdbd2cSJim Jagielski        # collecting all properties for table Property
920*b1cdbd2cSJim Jagielski        if ( ! exists($installer::globals::languageproperties{$property}) )
921*b1cdbd2cSJim Jagielski        {
922*b1cdbd2cSJim Jagielski            $installer::globals::languageproperties{$property} = $value;
923*b1cdbd2cSJim Jagielski        }
924*b1cdbd2cSJim Jagielski    }
925*b1cdbd2cSJim Jagielski}
926*b1cdbd2cSJim Jagielski
927*b1cdbd2cSJim Jagielski
928*b1cdbd2cSJim Jagielski
929*b1cdbd2cSJim Jagielski
930*b1cdbd2cSJim Jagielskisub has_style ($$)
931*b1cdbd2cSJim Jagielski{
932*b1cdbd2cSJim Jagielski    my ($style_list_string, $style_name) = @_;
933*b1cdbd2cSJim Jagielski
934*b1cdbd2cSJim Jagielski    return 0 unless defined $style_list_string;
935*b1cdbd2cSJim Jagielski    return $style_list_string =~ /\b$style_name\b/ ? 1 : 0;
936*b1cdbd2cSJim Jagielski}
937*b1cdbd2cSJim Jagielski
938*b1cdbd2cSJim Jagielski
939*b1cdbd2cSJim Jagielski
940*b1cdbd2cSJim Jagielski
941*b1cdbd2cSJim Jagielskisub prepare_file_table_creation ($$$)
942*b1cdbd2cSJim Jagielski{
943*b1cdbd2cSJim Jagielski    my ($file_list, $directory_list, $allvariables) = @_;
944*b1cdbd2cSJim Jagielski
945*b1cdbd2cSJim Jagielski    if ( $^O =~ /cygwin/i )
946*b1cdbd2cSJim Jagielski    {
947*b1cdbd2cSJim Jagielski        installer::worker::generate_cygwin_pathes($file_list);
948*b1cdbd2cSJim Jagielski    }
949*b1cdbd2cSJim Jagielski
950*b1cdbd2cSJim Jagielski    # Reset the fields 'sequencenumber' and 'uniquename'. They should not yet exist but better be sure.
951*b1cdbd2cSJim Jagielski    foreach my $file (@$file_list)
952*b1cdbd2cSJim Jagielski    {
953*b1cdbd2cSJim Jagielski        delete $file->{'sequencenumber'};
954*b1cdbd2cSJim Jagielski        delete $file->{'uniquename'};
955*b1cdbd2cSJim Jagielski    }
956*b1cdbd2cSJim Jagielski
957*b1cdbd2cSJim Jagielski    # Create FileSequenceList object for the old sequence data.
958*b1cdbd2cSJim Jagielski    if (defined $installer::globals::source_msi)
959*b1cdbd2cSJim Jagielski    {
960*b1cdbd2cSJim Jagielski        my $previous_sequence_data = new installer::patch::FileSequenceList();
961*b1cdbd2cSJim Jagielski        $previous_sequence_data->SetFromMsi($installer::globals::source_msi);
962*b1cdbd2cSJim Jagielski        my @added_files = retrieve_sequence_and_uniquename($file_list, $previous_sequence_data);
963*b1cdbd2cSJim Jagielski
964*b1cdbd2cSJim Jagielski        # Extract just the unique names.
965*b1cdbd2cSJim Jagielski        my %target_unique_names = map {$_->{'uniquename'} => 1} @$file_list;
966*b1cdbd2cSJim Jagielski        my @removed_items = $previous_sequence_data->get_removed_files(\%target_unique_names);
967*b1cdbd2cSJim Jagielski
968*b1cdbd2cSJim Jagielski        $installer::logger::Lang->printf(
969*b1cdbd2cSJim Jagielski            "there are %d files that have been removed from source and %d files added\n",
970*b1cdbd2cSJim Jagielski            scalar @removed_items,
971*b1cdbd2cSJim Jagielski            scalar @added_files);
972*b1cdbd2cSJim Jagielski
973*b1cdbd2cSJim Jagielski        my $file_map = $installer::globals::source_msi->GetFileMap();
974*b1cdbd2cSJim Jagielski        my $index = 0;
975*b1cdbd2cSJim Jagielski        foreach my $removed_row (@removed_items)
976*b1cdbd2cSJim Jagielski        {
977*b1cdbd2cSJim Jagielski            $installer::logger::Lang->printf("    removed file %d: %s\n",
978*b1cdbd2cSJim Jagielski                ++$index,
979*b1cdbd2cSJim Jagielski                $removed_row->GetValue('File'));
980*b1cdbd2cSJim Jagielski            my $directory = $file_map->{$removed_row->GetValue('File')}->{'directory'};
981*b1cdbd2cSJim Jagielski            while (my ($key,$value) = each %$directory)
982*b1cdbd2cSJim Jagielski            {
983*b1cdbd2cSJim Jagielski                $installer::logger::Lang->printf("        %16s -> %s\n", $key, $value);
984*b1cdbd2cSJim Jagielski            }
985*b1cdbd2cSJim Jagielski        }
986*b1cdbd2cSJim Jagielski        $index = 0;
987*b1cdbd2cSJim Jagielski        foreach my $added_file (@added_files)
988*b1cdbd2cSJim Jagielski        {
989*b1cdbd2cSJim Jagielski            $installer::logger::Lang->printf("    added file %d: %s\n",
990*b1cdbd2cSJim Jagielski                ++$index,
991*b1cdbd2cSJim Jagielski                $added_file->{'uniquename'});
992*b1cdbd2cSJim Jagielski            installer::scriptitems::print_script_item($added_file);
993*b1cdbd2cSJim Jagielski        }
994*b1cdbd2cSJim Jagielski        my @new_files = create_items_for_missing_files(
995*b1cdbd2cSJim Jagielski            \@removed_items,
996*b1cdbd2cSJim Jagielski            $installer::globals::source_msi,
997*b1cdbd2cSJim Jagielski            $directory_list);
998*b1cdbd2cSJim Jagielski        push @$file_list, @new_files;
999*b1cdbd2cSJim Jagielski    }
1000*b1cdbd2cSJim Jagielski    assign_missing_sequence_numbers($file_list);
1001*b1cdbd2cSJim Jagielski
1002*b1cdbd2cSJim Jagielski    foreach my $file (@$file_list)
1003*b1cdbd2cSJim Jagielski	{
1004*b1cdbd2cSJim Jagielski        if ( ! defined $file->{'componentname'})
1005*b1cdbd2cSJim Jagielski        {
1006*b1cdbd2cSJim Jagielski            $file->{'componentname'} = get_file_component_name($file, $file_list);
1007*b1cdbd2cSJim Jagielski        }
1008*b1cdbd2cSJim Jagielski        if ( ! defined $file->{'uniquename'})
1009*b1cdbd2cSJim Jagielski        {
1010*b1cdbd2cSJim Jagielski            $file->{'uniquename'} = generate_unique_filename_for_filetable($file->{'Name'});
1011*b1cdbd2cSJim Jagielski        }
1012*b1cdbd2cSJim Jagielski
1013*b1cdbd2cSJim Jagielski		# Collecting all component conditions
1014*b1cdbd2cSJim Jagielski		if ( $file->{'ComponentCondition'} )
1015*b1cdbd2cSJim Jagielski		{
1016*b1cdbd2cSJim Jagielski			if ( ! exists($installer::globals::componentcondition{$file->{'componentname'}}))
1017*b1cdbd2cSJim Jagielski			{
1018*b1cdbd2cSJim Jagielski				$installer::globals::componentcondition{$file->{'componentname'}}
1019*b1cdbd2cSJim Jagielski                = $file->{'ComponentCondition'};
1020*b1cdbd2cSJim Jagielski			}
1021*b1cdbd2cSJim Jagielski		}
1022*b1cdbd2cSJim Jagielski		# Collecting also all tree conditions for multilayer products
1023*b1cdbd2cSJim Jagielski		get_tree_condition_for_component($file, $file->{'componentname'});
1024*b1cdbd2cSJim Jagielski
1025*b1cdbd2cSJim Jagielski		# Collecting all component names, that have flag VERSION_INDEPENDENT_COMP_ID
1026*b1cdbd2cSJim Jagielski		# This should be all components with constant API, for example URE
1027*b1cdbd2cSJim Jagielski		if (has_style($file->{'Styles'}, "VERSION_INDEPENDENT_COMP_ID"))
1028*b1cdbd2cSJim Jagielski		{
1029*b1cdbd2cSJim Jagielski			$installer::globals::base_independent_components{$file->{'componentname'}} = 1;
1030*b1cdbd2cSJim Jagielski		}
1031*b1cdbd2cSJim Jagielski
1032*b1cdbd2cSJim Jagielski        # Special handling for files in PREDEFINED_OSSHELLNEWDIR. These components
1033*b1cdbd2cSJim Jagielski		# need as KeyPath a RegistryItem in HKCU
1034*b1cdbd2cSJim Jagielski        if ($file->{'needs_user_registry_key'}
1035*b1cdbd2cSJim Jagielski            || (defined $file->{'Dir'} && $file->{'Dir'} =~ /\bPREDEFINED_OSSHELLNEWDIR\b/))
1036*b1cdbd2cSJim Jagielski		{
1037*b1cdbd2cSJim Jagielski			my $keypath = generate_registry_keypath($file);
1038*b1cdbd2cSJim Jagielski			$file->{'userregkeypath'} = $keypath;
1039*b1cdbd2cSJim Jagielski			push(@installer::globals::userregistrycollector, $file);
1040*b1cdbd2cSJim Jagielski			$installer::globals::addeduserregitrykeys = 1;
1041*b1cdbd2cSJim Jagielski		}
1042*b1cdbd2cSJim Jagielski
1043*b1cdbd2cSJim Jagielski		$file->{'windows_language'} = get_language_for_file($file);
1044*b1cdbd2cSJim Jagielski
1045*b1cdbd2cSJim Jagielski        process_language_conditions($file);
1046*b1cdbd2cSJim Jagielski    }
1047*b1cdbd2cSJim Jagielski
1048*b1cdbd2cSJim Jagielski    # The filenames must be collected because of uniqueness
1049*b1cdbd2cSJim Jagielski	# 01-44-~1.DAT, 01-44-~2.DAT, ...
1050*b1cdbd2cSJim Jagielski	my %shortnames = ();
1051*b1cdbd2cSJim Jagielski    foreach my $file (@$file_list)
1052*b1cdbd2cSJim Jagielski    {
1053*b1cdbd2cSJim Jagielski        $file->{'short_name'} = generate_filename_for_filetable($file, \%shortnames);
1054*b1cdbd2cSJim Jagielski    }
1055*b1cdbd2cSJim Jagielski}
1056*b1cdbd2cSJim Jagielski
1057*b1cdbd2cSJim Jagielski
1058*b1cdbd2cSJim Jagielski
1059*b1cdbd2cSJim Jagielski
1060*b1cdbd2cSJim Jagielskisub create_file_table_data ($$)
1061*b1cdbd2cSJim Jagielski{
1062*b1cdbd2cSJim Jagielski    my ($file_list, $allvariables) = @_;
1063*b1cdbd2cSJim Jagielski
1064*b1cdbd2cSJim Jagielski    my @file_table_data = ();
1065*b1cdbd2cSJim Jagielski	foreach my $file (@$file_list)
1066*b1cdbd2cSJim Jagielski	{
1067*b1cdbd2cSJim Jagielski        my $attributes;
1068*b1cdbd2cSJim Jagielski		if (has_style($file->{'Styles'}, "DONT_PACK"))
1069*b1cdbd2cSJim Jagielski        {
1070*b1cdbd2cSJim Jagielski            # Sourcefile is unpacked (msidbFileAttributesNoncompressed).
1071*b1cdbd2cSJim Jagielski            $attributes = "8192";
1072*b1cdbd2cSJim Jagielski        }
1073*b1cdbd2cSJim Jagielski		else
1074*b1cdbd2cSJim Jagielski        {
1075*b1cdbd2cSJim Jagielski            # Sourcefile is packed (msidbFileAttributesCompressed).
1076*b1cdbd2cSJim Jagielski            $attributes = "16384";
1077*b1cdbd2cSJim Jagielski        }
1078*b1cdbd2cSJim Jagielski
1079*b1cdbd2cSJim Jagielski        my $row_data = {
1080*b1cdbd2cSJim Jagielski            'File' => $file->{'uniquename'},
1081*b1cdbd2cSJim Jagielski            'Component_' => $file->{'componentname'},
1082*b1cdbd2cSJim Jagielski            'FileName' => $file->{'short_name'},
1083*b1cdbd2cSJim Jagielski            'FileSize' => get_filesize($file),
1084*b1cdbd2cSJim Jagielski            'Version' => get_fileversion($file, $allvariables),
1085*b1cdbd2cSJim Jagielski            'Language' => $file->{'windows_language'},
1086*b1cdbd2cSJim Jagielski            'Attributes' => $attributes,
1087*b1cdbd2cSJim Jagielski            'Sequence' => $file->{'sequencenumber'}
1088*b1cdbd2cSJim Jagielski            };
1089*b1cdbd2cSJim Jagielski        push @file_table_data, $row_data;
1090*b1cdbd2cSJim Jagielski	}
1091*b1cdbd2cSJim Jagielski
1092*b1cdbd2cSJim Jagielski    return \@file_table_data;
1093*b1cdbd2cSJim Jagielski}
1094*b1cdbd2cSJim Jagielski
1095*b1cdbd2cSJim Jagielski
1096*b1cdbd2cSJim Jagielski
1097*b1cdbd2cSJim Jagielski
1098*b1cdbd2cSJim Jagielskisub collect_components ($)
1099*b1cdbd2cSJim Jagielski{
1100*b1cdbd2cSJim Jagielski    my ($file_list) = @_;
1101*b1cdbd2cSJim Jagielski
1102*b1cdbd2cSJim Jagielski	my %components = ();
1103*b1cdbd2cSJim Jagielski    foreach my $file (@$file_list)
1104*b1cdbd2cSJim Jagielski    {
1105*b1cdbd2cSJim Jagielski        $components{$file->{'componentname'}} = 1;
1106*b1cdbd2cSJim Jagielski    }
1107*b1cdbd2cSJim Jagielski    return keys %components;
1108*b1cdbd2cSJim Jagielski}
1109*b1cdbd2cSJim Jagielski
1110*b1cdbd2cSJim Jagielski
1111*b1cdbd2cSJim Jagielski
1112*b1cdbd2cSJim Jagielski
1113*b1cdbd2cSJim Jagielski=head filter_files($file_list, $allvariables)
1114*b1cdbd2cSJim Jagielski
1115*b1cdbd2cSJim Jagielski    Filter out Java files when not building a Java product.
1116*b1cdbd2cSJim Jagielski
1117*b1cdbd2cSJim Jagielski    Is this still triggered?
1118*b1cdbd2cSJim Jagielski
1119*b1cdbd2cSJim Jagielski=cut
1120*b1cdbd2cSJim Jagielskisub filter_files ($$)
1121*b1cdbd2cSJim Jagielski{
1122*b1cdbd2cSJim Jagielski    my ($file_list, $allvariables) = @_;
1123*b1cdbd2cSJim Jagielski
1124*b1cdbd2cSJim Jagielski    if ($allvariables->{'JAVAPRODUCT'})
1125*b1cdbd2cSJim Jagielski    {
1126*b1cdbd2cSJim Jagielski        return $file_list;
1127*b1cdbd2cSJim Jagielski    }
1128*b1cdbd2cSJim Jagielski    else
1129*b1cdbd2cSJim Jagielski    {
1130*b1cdbd2cSJim Jagielski        my @filtered_files = ();
1131*b1cdbd2cSJim Jagielski        foreach my $file (@$file_list)
1132*b1cdbd2cSJim Jagielski        {
1133*b1cdbd2cSJim Jagielski            if ( ! has_style($file->{'Styles'}, "JAVAFILE"))
1134*b1cdbd2cSJim Jagielski            {
1135*b1cdbd2cSJim Jagielski                push @filtered_files, $file;
1136*b1cdbd2cSJim Jagielski            }
1137*b1cdbd2cSJim Jagielski        }
1138*b1cdbd2cSJim Jagielski        return \@filtered_files;
1139*b1cdbd2cSJim Jagielski    }
1140*b1cdbd2cSJim Jagielski}
1141*b1cdbd2cSJim Jagielski
1142*b1cdbd2cSJim Jagielski
1143*b1cdbd2cSJim Jagielski
1144*b1cdbd2cSJim Jagielski
1145*b1cdbd2cSJim Jagielski# Structure of the files table:
1146*b1cdbd2cSJim Jagielski# File Component_ FileName FileSize Version Language Attributes Sequence
1147*b1cdbd2cSJim Jagielskisub create_file_table ($$)
1148*b1cdbd2cSJim Jagielski{
1149*b1cdbd2cSJim Jagielski    my ($file_table_data, $basedir) = @_;
1150*b1cdbd2cSJim Jagielski
1151*b1cdbd2cSJim Jagielski    # Set up the 'File' table.
1152*b1cdbd2cSJim Jagielski	my @filetable = ();
1153*b1cdbd2cSJim Jagielski	installer::windows::idtglobal::write_idt_header(\@filetable, "file");
1154*b1cdbd2cSJim Jagielski    my @keys = ('File', 'Component_', 'FileName', 'FileSize', 'Version', 'Language', 'Attributes', 'Sequence');
1155*b1cdbd2cSJim Jagielski    my $index = 0;
1156*b1cdbd2cSJim Jagielski    foreach my $row_data (@$file_table_data)
1157*b1cdbd2cSJim Jagielski    {
1158*b1cdbd2cSJim Jagielski        ++$index;
1159*b1cdbd2cSJim Jagielski        my @values = map {$row_data->{$_}} @keys;
1160*b1cdbd2cSJim Jagielski        my $line = join("\t", @values) . "\n";
1161*b1cdbd2cSJim Jagielski		push(@filetable, $line);
1162*b1cdbd2cSJim Jagielski    }
1163*b1cdbd2cSJim Jagielski
1164*b1cdbd2cSJim Jagielski    my $filetablename = $basedir . $installer::globals::separator . "File.idt";
1165*b1cdbd2cSJim Jagielski	installer::files::save_file($filetablename ,\@filetable);
1166*b1cdbd2cSJim Jagielski	$installer::logger::Lang->print("\n");
1167*b1cdbd2cSJim Jagielski	$installer::logger::Lang->printf("Created idt file: %s\n", $filetablename);
1168*b1cdbd2cSJim Jagielski}
1169*b1cdbd2cSJim Jagielski
1170*b1cdbd2cSJim Jagielski
1171*b1cdbd2cSJim Jagielski
1172*b1cdbd2cSJim Jagielski
1173*b1cdbd2cSJim Jagielskisub create_filehash_table ($$)
1174*b1cdbd2cSJim Jagielski{
1175*b1cdbd2cSJim Jagielski    my ($file_list, $basedir) = @_;
1176*b1cdbd2cSJim Jagielski
1177*b1cdbd2cSJim Jagielski    my @filehashtable = ();
1178*b1cdbd2cSJim Jagielski
1179*b1cdbd2cSJim Jagielski    if ( $installer::globals::prepare_winpatch )
1180*b1cdbd2cSJim Jagielski    {
1181*b1cdbd2cSJim Jagielski
1182*b1cdbd2cSJim Jagielski        installer::windows::idtglobal::write_idt_header(\@filehashtable, "filehash");
1183*b1cdbd2cSJim Jagielski
1184*b1cdbd2cSJim Jagielski        foreach my $file (@$file_list)
1185*b1cdbd2cSJim Jagielski        {
1186*b1cdbd2cSJim Jagielski            my $path = $file->{'sourcepath'};
1187*b1cdbd2cSJim Jagielski            if ($^O =~ /cygwin/i)
1188*b1cdbd2cSJim Jagielski            {
1189*b1cdbd2cSJim Jagielski                $path = $file->{'cyg_sourcepath'};
1190*b1cdbd2cSJim Jagielski            }
1191*b1cdbd2cSJim Jagielski
1192*b1cdbd2cSJim Jagielski            open(FILE, $path) or die "ERROR: Can't open $path for creating file hash";
1193*b1cdbd2cSJim Jagielski            binmode(FILE);
1194*b1cdbd2cSJim Jagielski            my $hashinfo = pack("l", 20);
1195*b1cdbd2cSJim Jagielski            $hashinfo .= Digest::MD5->new->addfile(*FILE)->digest;
1196*b1cdbd2cSJim Jagielski
1197*b1cdbd2cSJim Jagielski            my @i = unpack ('x[l]l4', $hashinfo);
1198*b1cdbd2cSJim Jagielski            my $oneline = join("\t",
1199*b1cdbd2cSJim Jagielski                (
1200*b1cdbd2cSJim Jagielski                    $file->{'uniquename'},
1201*b1cdbd2cSJim Jagielski                    "0",
1202*b1cdbd2cSJim Jagielski                    @i
1203*b1cdbd2cSJim Jagielski                ));
1204*b1cdbd2cSJim Jagielski            push (@filehashtable, $oneline . "\n");
1205*b1cdbd2cSJim Jagielski        }
1206*b1cdbd2cSJim Jagielski
1207*b1cdbd2cSJim Jagielski        my $filehashtablename = $basedir . $installer::globals::separator . "MsiFileHash.idt";
1208*b1cdbd2cSJim Jagielski        installer::files::save_file($filehashtablename ,\@filehashtable);
1209*b1cdbd2cSJim Jagielski        $installer::logger::Lang->print("\n");
1210*b1cdbd2cSJim Jagielski        $installer::logger::Lang->printf("Created idt file: %s\n", $filehashtablename);
1211*b1cdbd2cSJim Jagielski    }
1212*b1cdbd2cSJim Jagielski}
1213*b1cdbd2cSJim Jagielski
1214*b1cdbd2cSJim Jagielski
1215*b1cdbd2cSJim Jagielski1;
1216