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