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