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