1#**************************************************************
2#
3#  Licensed to the Apache Software Foundation (ASF) under one
4#  or more contributor license agreements.  See the NOTICE file
5#  distributed with this work for additional information
6#  regarding copyright ownership.  The ASF licenses this file
7#  to you under the Apache License, Version 2.0 (the
8#  "License"); you may not use this file except in compliance
9#  with the License.  You may obtain a copy of the License at
10#
11#    http://www.apache.org/licenses/LICENSE-2.0
12#
13#  Unless required by applicable law or agreed to in writing,
14#  software distributed under the License is distributed on an
15#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16#  KIND, either express or implied.  See the License for the
17#  specific language governing permissions and limitations
18#  under the License.
19#
20#**************************************************************
21
22
23
24package installer::windows::component;
25
26use installer::converter;
27use installer::existence;
28use installer::exiter;
29use installer::files;
30use installer::globals;
31use installer::windows::idtglobal;
32use installer::windows::language;
33
34##############################################################
35# Returning a globally unique ID (GUID) for a component
36# If the component is new, a unique guid has to be created.
37# If the component already exists, the guid has to be
38# taken from a list component <-> guid
39# Sample for a guid: {B68FD953-3CEF-4489-8269-8726848056E8}
40##############################################################
41
42sub get_component_guid
43{
44	my ( $componentname, $componentidhashref ) = @_;
45
46	# At this time only a template
47	my $returnvalue = "\{COMPONENTGUID\}";
48
49	if (( $installer::globals::updatedatabase ) && ( exists($componentidhashref->{$componentname}) ))
50	{
51		$returnvalue = $componentidhashref->{$componentname};
52	}
53
54	# Returning a ComponentID, that is assigned in scp project
55	if ( exists($installer::globals::componentid{$componentname}) )
56	{
57		$returnvalue = "\{" . $installer::globals::componentid{$componentname} . "\}";
58	}
59
60	return $returnvalue;
61}
62
63##############################################################
64# Returning the directory for a file component.
65##############################################################
66
67sub get_file_component_directory
68{
69	my ($componentname, $filesref, $dirref) = @_;
70
71	my ($onefile, $component, $onedir, $hostname, $uniquedir);
72	my $found = 0;
73
74	for ( my $i = 0; $i <= $#{$filesref}; $i++ )
75	{
76		$onefile = 	${$filesref}[$i];
77		$component = $onefile->{'componentname'};
78
79		if ( $component eq $componentname )
80		{
81			$found = 1;
82			last;
83		}
84	}
85
86	if (!($found))
87	{
88		# This component can be ignored, if it exists in a version with extension "_pff" (this was renamed in file::get_sequence_for_file() )
89		my $ignore_this_component = 0;
90		my $origcomponentname = $componentname;
91		my $componentname = $componentname . "_pff";
92
93		for ( my $j = 0; $j <= $#{$filesref}; $j++ )
94		{
95			$onefile = 	${$filesref}[$j];
96			$component = $onefile->{'componentname'};
97
98			if ( $component eq $componentname )
99			{
100				$ignore_this_component = 1;
101				last;
102			}
103		}
104
105		if ( $ignore_this_component ) { return "IGNORE_COMP"; }
106		else { installer::exiter::exit_program("ERROR: Did not find component \"$origcomponentname\" in file collection", "get_file_component_directory"); }
107	}
108
109	my $localstyles = "";
110
111	if ( $onefile->{'Styles'} ) { $localstyles = $onefile->{'Styles'}; }
112
113	if ( $localstyles =~ /\bFONT\b/ )	# special handling for font files
114	{
115		return $installer::globals::fontsfolder;
116	}
117
118	my $destdir = "";
119
120	if ( $onefile->{'Dir'} ) { $destdir = $onefile->{'Dir'}; }
121
122	if ( $destdir =~ /\bPREDEFINED_OSSHELLNEWDIR\b/ )	# special handling for shellnew files
123	{
124		return $installer::globals::templatefolder;
125	}
126
127	my $destination = $onefile->{'destination'};
128
129	installer::pathanalyzer::get_path_from_fullqualifiedname(\$destination);
130
131	$destination =~ s/\Q$installer::globals::separator\E\s*$//;
132
133	# This path has to be defined in the directory collection at "HostName"
134
135	if ($destination eq "")		# files in the installation root
136	{
137		$uniquedir = "INSTALLLOCATION";
138	}
139	else
140	{
141		$found = 0;
142
143		for ( my $i = 0; $i <= $#{$dirref}; $i++ )
144		{
145			$onedir = 	${$dirref}[$i];
146			$hostname = $onedir->{'HostName'};
147
148			if ( $hostname eq $destination )
149			{
150				$found = 1;
151				last;
152			}
153		}
154
155		if (!($found))
156		{
157			installer::exiter::exit_program("ERROR: Did not find destination $destination in directory collection", "get_file_component_directory");
158		}
159
160		$uniquedir = $onedir->{'uniquename'};
161
162		if ( $uniquedir eq $installer::globals::officeinstalldirectory )
163		{
164			$uniquedir = "INSTALLLOCATION";
165		}
166	}
167
168	$onefile->{'uniquedirname'} = $uniquedir;		# saving it in the file collection
169
170	return $uniquedir
171}
172
173##############################################################
174# Returning the directory for a registry component.
175# This cannot be a useful value
176##############################################################
177
178sub get_registry_component_directory
179{
180	my $componentdir = "INSTALLLOCATION";
181
182	return $componentdir;
183}
184
185##############################################################
186# Returning the attributes for a file component.
187# Always 8 in this first try?
188##############################################################
189
190sub get_file_component_attributes
191{
192	my ($componentname, $filesref, $allvariables) = @_;
193
194	my $attributes;
195
196	$attributes = 2;
197
198	# special handling for font files
199
200	my $onefile;
201	my $found = 0;
202
203	for ( my $i = 0; $i <= $#{$filesref}; $i++ )
204	{
205		$onefile = 	${$filesref}[$i];
206		my $component = $onefile->{'componentname'};
207
208		if ( $component eq $componentname )
209		{
210			$found = 1;
211			last;
212		}
213	}
214
215	if (!($found))
216	{
217		installer::exiter::exit_program("ERROR: Did not find component in file collection", "get_file_component_attributes");
218	}
219
220	my $localstyles = "";
221
222	if ( $onefile->{'Styles'} ) { $localstyles = $onefile->{'Styles'}; }
223
224	if ( $localstyles =~ /\bFONT\b/ )
225	{
226		$attributes = 8;	# font files will be deinstalled if the ref count is 0
227	}
228
229	if ( $localstyles =~ /\bASSEMBLY\b/ )
230	{
231		$attributes = 0;	# Assembly files cannot run from source
232	}
233
234	if (( $onefile->{'Dir'} =~ /\bPREDEFINED_OSSHELLNEWDIR\b/ ) || ( $onefile->{'needs_user_registry_key'} ))
235	{
236		$attributes = 4;	# Files in shellnew dir and in non advertised startmenu entries must have user registry key as KeyPath
237	}
238
239	# Adding 256, if this is a 64 bit installation set.
240	if (( $allvariables->{'64BITPRODUCT'} ) && ( $allvariables->{'64BITPRODUCT'} == 1 )) { $attributes = $attributes + 256; }
241
242	return $attributes
243}
244
245##############################################################
246# Returning the attributes for a registry component.
247# Always 4, indicating, the keypath is a defined in
248# table registry
249##############################################################
250
251sub get_registry_component_attributes
252{
253	my ($componentname, $allvariables) = @_;
254
255	my $attributes;
256
257	$attributes = 4;
258
259	# Adding 256, if this is a 64 bit installation set.
260	if (( $allvariables->{'64BITPRODUCT'} ) && ( $allvariables->{'64BITPRODUCT'} == 1 )) { $attributes = $attributes + 256; }
261
262	if ( exists($installer::globals::dontdeletecomponents{$componentname}) ) { $attributes = $attributes + 16; }
263
264	return $attributes
265}
266
267##############################################################
268# Returning the conditions for a component.
269# This is important for language dependent components
270# in multilingual installation sets.
271##############################################################
272
273sub get_file_component_condition
274{
275	my ($componentname, $filesref) = @_;
276
277	my $condition = "";
278
279	if (exists($installer::globals::componentcondition{$componentname}))
280	{
281		$condition = $installer::globals::componentcondition{$componentname};
282	}
283
284	# there can be also tree conditions for multilayer products
285	if (exists($installer::globals::treeconditions{$componentname}))
286	{
287		if ( $condition eq "" )
288		{
289			$condition = $installer::globals::treeconditions{$componentname};
290		}
291		else
292		{
293			$condition = "($condition) And ($installer::globals::treeconditions{$componentname})";
294		}
295	}
296
297	return $condition
298}
299
300##############################################################
301# Returning the conditions for a registry component.
302##############################################################
303
304sub get_component_condition
305{
306	my ($componentname) = @_;
307
308	my $condition;
309
310	$condition = "";	# Always ?
311
312	if (exists($installer::globals::componentcondition{$componentname}))
313	{
314		$condition = $installer::globals::componentcondition{$componentname};
315	}
316
317	return $condition
318}
319
320####################################################################
321# Returning the keypath for a component.
322# This will be the name of the first file/registry, found in the
323# collection $itemsref
324# Attention: This has to be the unique (file)name, not the
325# real filename!
326####################################################################
327
328sub get_component_keypath
329{
330	my ($componentname, $itemsref, $componentidkeypathhashref) = @_;
331
332	my $oneitem;
333	my $found = 0;
334	my $infoline = "";
335
336	for ( my $i = 0; $i <= $#{$itemsref}; $i++ )
337	{
338		$oneitem = 	${$itemsref}[$i];
339		my $component = $oneitem->{'componentname'};
340
341		if ( $component eq $componentname )
342		{
343			$found = 1;
344			last;
345		}
346	}
347
348	if (!($found))
349	{
350		installer::exiter::exit_program("ERROR: Did not find component in file/registry collection, function get_component_keypath", "get_component_keypath");
351	}
352
353	my $keypath = $oneitem->{'uniquename'};	# "uniquename", not "Name"
354
355	# Special handling for updates from existing databases, because KeyPath must not change
356	if (( $installer::globals::updatedatabase ) && ( exists($componentidkeypathhashref->{$componentname}) ))
357	{
358		$keypath = $componentidkeypathhashref->{$componentname};
359		# -> check, if this is a valid key path?!
360		if ( $keypath ne $oneitem->{'uniquename'} )
361		{
362			# Warning: This keypath was changed because of info from old database
363			$infoline = "WARNING: The KeyPath for component \"$componentname\" was changed from \"$oneitem->{'uniquename'}\" to \"$keypath\" because of information from update database";
364			push(@installer::globals::logfileinfo, $infoline);
365		}
366	}
367
368	# Special handling for components in PREDEFINED_OSSHELLNEWDIR. These components
369	# need as KeyPath a RegistryItem in HKCU
370	if ( $oneitem->{'userregkeypath'} ) { $keypath = $oneitem->{'userregkeypath'}; }
371
372	# saving it in the file and registry collection
373	$oneitem->{'keypath'} = $keypath;
374
375	return $keypath
376}
377
378###################################################################
379# Creating the file Componen.idt dynamically
380# Content:
381# Component ComponentId Directory_ Attributes Condition KeyPath
382###################################################################
383
384sub	create_component_table
385{
386	my ($filesref, $registryref, $dirref, $allfilecomponentsref, $allregistrycomponents, $basedir, $componentidhashref, $componentidkeypathhashref, $allvariables) = @_;
387
388	my @componenttable = ();
389
390	my ($oneline, $infoline);
391
392	installer::windows::idtglobal::write_idt_header(\@componenttable, "component");
393
394	# collect_layer_conditions();
395
396
397	# File components
398
399	for ( my $i = 0; $i <= $#{$allfilecomponentsref}; $i++ )
400	{
401		my %onecomponent = ();
402
403		$onecomponent{'name'} = ${$allfilecomponentsref}[$i];
404		$onecomponent{'guid'} = get_component_guid($onecomponent{'name'}, $componentidhashref);
405		$onecomponent{'directory'} = get_file_component_directory($onecomponent{'name'}, $filesref, $dirref);
406		if ( $onecomponent{'directory'} eq "IGNORE_COMP" ) { next; }
407		$onecomponent{'attributes'} = get_file_component_attributes($onecomponent{'name'}, $filesref, $allvariables);
408		$onecomponent{'condition'} = get_file_component_condition($onecomponent{'name'}, $filesref);
409		$onecomponent{'keypath'} = get_component_keypath($onecomponent{'name'}, $filesref, $componentidkeypathhashref);
410
411		$oneline = $onecomponent{'name'} . "\t" . $onecomponent{'guid'} . "\t" . $onecomponent{'directory'} . "\t"
412				. $onecomponent{'attributes'} . "\t" . $onecomponent{'condition'} . "\t" . $onecomponent{'keypath'} . "\n";
413
414		push(@componenttable, $oneline);
415	}
416
417	# Registry components
418
419	for ( my $i = 0; $i <= $#{$allregistrycomponents}; $i++ )
420	{
421		my %onecomponent = ();
422
423		$onecomponent{'name'} = ${$allregistrycomponents}[$i];
424		$onecomponent{'guid'} = get_component_guid($onecomponent{'name'}, $componentidhashref);
425		$onecomponent{'directory'} = get_registry_component_directory();
426		$onecomponent{'attributes'} = get_registry_component_attributes($onecomponent{'name'}, $allvariables);
427		$onecomponent{'condition'} = get_component_condition($onecomponent{'name'});
428		$onecomponent{'keypath'} = get_component_keypath($onecomponent{'name'}, $registryref, $componentidkeypathhashref);
429
430		$oneline = $onecomponent{'name'} . "\t" . $onecomponent{'guid'} . "\t" . $onecomponent{'directory'} . "\t"
431				. $onecomponent{'attributes'} . "\t" . $onecomponent{'condition'} . "\t" . $onecomponent{'keypath'} . "\n";
432
433		push(@componenttable, $oneline);
434	}
435
436	# Saving the file
437
438	my $componenttablename = $basedir . $installer::globals::separator . "Componen.idt";
439	installer::files::save_file($componenttablename ,\@componenttable);
440	$infoline = "Created idt file: $componenttablename\n";
441	push(@installer::globals::logfileinfo, $infoline);
442}
443
444####################################################################################
445# Returning a component for a scp module gid.
446# Pairs are saved in the files collector.
447####################################################################################
448
449sub get_component_name_from_modulegid
450{
451	my ($modulegid, $filesref) = @_;
452
453	my $componentname = "";
454
455	for ( my $i = 0; $i <= $#{$filesref}; $i++ )
456	{
457		my $onefile = ${$filesref}[$i];
458
459		if ( $onefile->{'modules'} )
460		{
461			my $filemodules = $onefile->{'modules'};
462			my $filemodulesarrayref = installer::converter::convert_stringlist_into_array_without_newline(\$filemodules, ",");
463
464			if (installer::existence::exists_in_array($modulegid, $filemodulesarrayref))
465			{
466				$componentname = $onefile->{'componentname'};
467				last;
468			}
469		}
470	}
471
472	return $componentname;
473}
474
475####################################################################################
476# Updating the file Environm.idt dynamically
477# Content:
478# Environment Name Value Component_
479####################################################################################
480
481sub set_component_in_environment_table
482{
483	my ($basedir, $filesref) = @_;
484
485	my $infoline = "";
486
487	my $environmentfilename = $basedir . $installer::globals::separator . "Environm.idt";
488
489	if ( -f $environmentfilename )	# only do something, if file exists
490	{
491		my $environmentfile = installer::files::read_file($environmentfilename);
492
493		for ( my $i = 3; $i <= $#{$environmentfile}; $i++ )	# starting in line 4 of Environm.idt
494		{
495			if ( ${$environmentfile}[$i] =~ /^\s*(.*?)\t(.*?)\t(.*?)\t(.*?)\s*$/ )
496			{
497				my $modulegid = $4; # in Environment table a scp module gid can be used as component replacement
498
499				my $componentname = get_component_name_from_modulegid($modulegid, $filesref);
500
501				if ( $componentname )	# only do something if a component could be found
502				{
503					$infoline = "Updated Environment table:\n";
504					push(@installer::globals::logfileinfo, $infoline);
505					$infoline = "Old line: ${$environmentfile}[$i]\n";
506					push(@installer::globals::logfileinfo, $infoline);
507
508					${$environmentfile}[$i] =~ s/$modulegid/$componentname/;
509
510					$infoline = "New line: ${$environmentfile}[$i]\n";
511					push(@installer::globals::logfileinfo, $infoline);
512
513				}
514			}
515		}
516
517		# Saving the file
518
519		installer::files::save_file($environmentfilename ,$environmentfile);
520		$infoline = "Updated idt file: $environmentfilename\n";
521		push(@installer::globals::logfileinfo, $infoline);
522
523	}
524}
525
5261;