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
34use strict;
35
36##############################################################
37# Returning a globally unique ID (GUID) for a component
38# If the component is new, a unique guid has to be created.
39# If the component already exists, the guid has to be
40# taken from a list component <-> guid
41# Sample for a guid: {B68FD953-3CEF-4489-8269-8726848056E8}
42##############################################################
43
44sub get_component_guid ($)
45{
46	my ($componentname) = @_;
47
48	# At this time only a template
49	my $returnvalue = "\{COMPONENTGUID\}";
50
51	# Returning a ComponentID, that is assigned in scp project
52	if ( exists($installer::globals::componentid{$componentname}) )
53	{
54        $installer::logger::Lang->printf("reusing guid %s for component %s\n",
55            $installer::globals::componentid{$componentname},
56            $componentname);
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 ($component,  $uniquedir);
72
73    foreach my $onefile (@$filesref)
74    {
75        if ($onefile->{'componentname'} eq $componentname)
76        {
77            return get_file_component_directory_for_file($onefile, $dirref);
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		my $found = 0;
139        foreach my $directory (@$dirref)
140		{
141			if ($directory->{'HostName'} eq $destination)
142			{
143				$found = 1;
144                $uniquedir = $directory->{'uniquename'};
145				last;
146			}
147		}
148
149		if ( ! $found)
150		{
151			installer::exiter::exit_program(
152                "ERROR: Did not find destination $destination in directory collection",
153                "get_file_component_directory");
154		}
155
156		if ( $uniquedir eq $installer::globals::officeinstalldirectory )
157		{
158			$uniquedir = "INSTALLLOCATION";
159		}
160	}
161
162	$onefile->{'uniquedirname'} = $uniquedir;		# saving it in the file collection
163
164	return $uniquedir
165}
166
167##############################################################
168# Returning the directory for a registry component.
169# This cannot be a useful value
170##############################################################
171
172sub get_registry_component_directory
173{
174	my $componentdir = "INSTALLLOCATION";
175
176	return $componentdir;
177}
178
179##############################################################
180# Returning the attributes for a file component.
181# Always 8 in this first try?
182##############################################################
183
184sub get_file_component_attributes
185{
186	my ($componentname, $filesref, $allvariables) = @_;
187
188	my $attributes;
189
190	$attributes = 2;
191
192	# special handling for font files
193
194	my $onefile;
195	my $found = 0;
196
197	for ( my $i = 0; $i <= $#{$filesref}; $i++ )
198	{
199		$onefile = 	${$filesref}[$i];
200		my $component = $onefile->{'componentname'};
201
202		if ( $component eq $componentname )
203		{
204			$found = 1;
205			last;
206		}
207	}
208
209	if (!($found))
210	{
211		installer::exiter::exit_program("ERROR: Did not find component in file collection", "get_file_component_attributes");
212	}
213
214	my $localstyles = "";
215
216	if ( $onefile->{'Styles'} ) { $localstyles = $onefile->{'Styles'}; }
217
218	if ( $localstyles =~ /\bFONT\b/ )
219	{
220		$attributes = 8;	# font files will be deinstalled if the ref count is 0
221	}
222
223	if ( $localstyles =~ /\bASSEMBLY\b/ )
224	{
225		$attributes = 0;	# Assembly files cannot run from source
226	}
227
228	if ((defined $onefile->{'Dir'} && $onefile->{'Dir'} =~ /\bPREDEFINED_OSSHELLNEWDIR\b/)
229        || $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	foreach my $oneitem (@$itemsref)
328	{
329		my $component = $oneitem->{'componentname'};
330
331		if ( ! defined $component)
332        {
333            installer::scriptitems::print_script_item($oneitem);
334            installer::logger::PrintError("item in get_component_keypath has no 'componentname'\n");
335            return "";
336        }
337		if ( $component eq $componentname )
338		{
339            my $keypath = $oneitem->{'uniquename'};	# "uniquename", not "Name"
340
341            # Special handling for components in
342            # PREDEFINED_OSSHELLNEWDIR. These components need as
343            # KeyPath a RegistryItem in HKCU
344            if ($oneitem->{'userregkeypath'})
345            {
346                $keypath = $oneitem->{'userregkeypath'};
347            }
348
349            # saving it in the file and registry collection
350            $oneitem->{'keypath'} = $keypath;
351
352            return $keypath
353		}
354	}
355
356    installer::exiter::exit_program(
357        "ERROR: Did not find component in file/registry collection, function get_component_keypath",
358        "get_component_keypath");
359}
360
361###################################################################
362# Creating the file Componen.idt dynamically
363# Content:
364# Component ComponentId Directory_ Attributes Condition KeyPath
365###################################################################
366
367sub	create_component_table ($$$$$$$)
368{
369	my ($filesref,
370        $registryref,
371        $dirref,
372        $allfilecomponentsref,
373        $allregistrycomponents,
374        $basedir,
375        $allvariables)
376        = @_;
377
378	my @componenttable = ();
379
380	my ($oneline, $infoline);
381
382	installer::windows::idtglobal::write_idt_header(\@componenttable, "component");
383
384	# collect_layer_conditions();
385
386
387	# File components
388
389	for ( my $i = 0; $i <= $#{$allfilecomponentsref}; $i++ )
390	{
391		my %onecomponent = ();
392
393		$onecomponent{'name'} = ${$allfilecomponentsref}[$i];
394		$onecomponent{'guid'} = get_component_guid($onecomponent{'name'});
395		$onecomponent{'directory'} = get_file_component_directory($onecomponent{'name'}, $filesref, $dirref);
396		if ( $onecomponent{'directory'} eq "IGNORE_COMP" ) { next; }
397		$onecomponent{'attributes'} = get_file_component_attributes($onecomponent{'name'}, $filesref, $allvariables);
398		$onecomponent{'condition'} = get_file_component_condition($onecomponent{'name'}, $filesref);
399		$onecomponent{'keypath'} = get_component_keypath($onecomponent{'name'}, $filesref);
400
401		$oneline = $onecomponent{'name'} . "\t" . $onecomponent{'guid'} . "\t" . $onecomponent{'directory'} . "\t"
402				. $onecomponent{'attributes'} . "\t" . $onecomponent{'condition'} . "\t" . $onecomponent{'keypath'} . "\n";
403
404		push(@componenttable, $oneline);
405	}
406
407	# Registry components
408
409	for ( my $i = 0; $i <= $#{$allregistrycomponents}; $i++ )
410	{
411		my %onecomponent = ();
412
413		$onecomponent{'name'} = ${$allregistrycomponents}[$i];
414		$onecomponent{'guid'} = get_component_guid($onecomponent{'name'});
415		$onecomponent{'directory'} = get_registry_component_directory();
416		$onecomponent{'attributes'} = get_registry_component_attributes($onecomponent{'name'}, $allvariables);
417		$onecomponent{'condition'} = get_component_condition($onecomponent{'name'});
418		$onecomponent{'keypath'} = get_component_keypath($onecomponent{'name'}, $registryref);
419
420		$oneline = $onecomponent{'name'} . "\t" . $onecomponent{'guid'} . "\t" . $onecomponent{'directory'} . "\t"
421				. $onecomponent{'attributes'} . "\t" . $onecomponent{'condition'} . "\t" . $onecomponent{'keypath'} . "\n";
422
423		push(@componenttable, $oneline);
424	}
425
426	# Saving the file
427
428	my $componenttablename = $basedir . $installer::globals::separator . "Componen.idt";
429	installer::files::save_file($componenttablename ,\@componenttable);
430	$infoline = "Created idt file: $componenttablename\n";
431	$installer::logger::Lang->print($infoline);
432}
433
434####################################################################################
435# Returning a component for a scp module gid.
436# Pairs are saved in the files collector.
437####################################################################################
438
439sub get_component_name_from_modulegid
440{
441	my ($modulegid, $filesref) = @_;
442
443	my $componentname = "";
444
445	for ( my $i = 0; $i <= $#{$filesref}; $i++ )
446	{
447		my $onefile = ${$filesref}[$i];
448
449		if ( $onefile->{'modules'} )
450		{
451			my $filemodules = $onefile->{'modules'};
452			my $filemodulesarrayref = installer::converter::convert_stringlist_into_array_without_newline(\$filemodules, ",");
453
454			if (installer::existence::exists_in_array($modulegid, $filemodulesarrayref))
455			{
456				$componentname = $onefile->{'componentname'};
457				last;
458			}
459		}
460	}
461
462	return $componentname;
463}
464
465####################################################################################
466# Updating the file Environm.idt dynamically
467# Content:
468# Environment Name Value Component_
469####################################################################################
470
471sub set_component_in_environment_table
472{
473	my ($basedir, $filesref) = @_;
474
475	my $infoline = "";
476
477	my $environmentfilename = $basedir . $installer::globals::separator . "Environm.idt";
478
479	if ( -f $environmentfilename )	# only do something, if file exists
480	{
481		my $environmentfile = installer::files::read_file($environmentfilename);
482
483		for ( my $i = 3; $i <= $#{$environmentfile}; $i++ )	# starting in line 4 of Environm.idt
484		{
485			if ( ${$environmentfile}[$i] =~ /^\s*(.*?)\t(.*?)\t(.*?)\t(.*?)\s*$/ )
486			{
487				my $modulegid = $4; # in Environment table a scp module gid can be used as component replacement
488
489				my $componentname = get_component_name_from_modulegid($modulegid, $filesref);
490
491				if ( $componentname )	# only do something if a component could be found
492				{
493					$infoline = "Updated Environment table:\n";
494					$installer::logger::Lang->print($infoline);
495					$infoline = "Old line: ${$environmentfile}[$i]\n";
496					$installer::logger::Lang->print($infoline);
497
498					${$environmentfile}[$i] =~ s/$modulegid/$componentname/;
499
500					$infoline = "New line: ${$environmentfile}[$i]\n";
501					$installer::logger::Lang->print($infoline);
502
503				}
504			}
505		}
506
507		# Saving the file
508
509		installer::files::save_file($environmentfilename ,$environmentfile);
510		$infoline = "Updated idt file: $environmentfilename\n";
511		$installer::logger::Lang->print($infoline);
512
513	}
514}
515
5161;
517