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::directory;
29
30use installer::exiter;
31use installer::files;
32use installer::globals;
33use installer::pathanalyzer;
34use installer::windows::idtglobal;
35use installer::windows::msiglobal;
36
37##############################################################
38# Collecting all directory trees in global hash
39##############################################################
40
41sub collectdirectorytrees
42{
43	my ( $directoryref ) = @_;
44
45	for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
46	{
47		my $onedir = ${$directoryref}[$i];
48		my $styles = "";
49		if ( $onedir->{'Styles'} ) { $styles = $onedir->{'Styles'}; }
50
51		if ( $styles ne "" )
52		{
53			foreach my $treestyle ( keys %installer::globals::treestyles )
54			{
55				if ( $styles =~ /\b$treestyle\b/ )
56				{
57					my $hostname = $onedir->{'HostName'};
58					# -> hostname is the key, the style the value!
59					$installer::globals::hostnametreestyles{$hostname} = $treestyle;
60				}
61			}
62		}
63	}
64}
65
66##############################################################
67# Overwriting global programfilesfolder, if required
68##############################################################
69
70sub overwrite_programfilesfolder
71{
72	my ( $allvariables ) = @_;
73
74	if ( $allvariables->{'PROGRAMFILESFOLDERNAME'} )
75	{
76		$installer::globals::programfilesfolder = $allvariables->{'PROGRAMFILESFOLDERNAME'};
77	}
78}
79
80##############################################################
81# Maximum length of directory name is 72.
82# Taking care of underlines, which are the separator.
83##############################################################
84
85sub make_short_dir_version
86{
87	my ($longstring) = @_;
88
89	my $shortstring = "";
90	my $cutlength = 60;
91	my $length = 5; # So the directory can still be recognized
92	my $longstring_save = $longstring;
93
94	# Splitting the string at each "underline" and allowing only $length characters per directory name.
95	# Checking also uniqueness and length.
96
97	my $stringarray = installer::converter::convert_stringlist_into_array_without_newline(\$longstring, "_");
98
99	foreach my $onestring ( @{$stringarray} )
100	{
101		my $partstring = "";
102
103		if ( $onestring =~ /\-/ )
104		{
105			my $localstringarray = installer::converter::convert_stringlist_into_array_without_newline(\$onestring, "-");
106			foreach my $onelocalstring ( @{$localstringarray} )
107			{
108				if ( length($onelocalstring) > $length ) { $onelocalstring = substr($onelocalstring, 0, $length); }
109				$partstring = $partstring . "-" . $onelocalstring;
110			}
111			$partstring =~ s/^\s*\-//;
112		}
113		else
114		{
115			if ( length($onestring) > $length ) { $partstring = substr($onestring, 0, $length); }
116			else { $partstring = $onestring; }
117		}
118
119		$shortstring = $shortstring . "_" . $partstring;
120	}
121
122	$shortstring =~ s/^\s*\_//;
123
124	# Setting unique ID to each directory
125	# No counter allowed, process must be absolute reproducable due to patch creation process.
126
127	# chomp(my $id = `echo $longstring_save | md5sum | sed -e "s/ .*//g"`);  # Very, very slow
128	# my $subid = substr($id, 0, 9); # taking only the first 9 digits
129
130	my $subid = installer::windows::msiglobal::calculate_id($longstring_save, 9); # taking only the first 9 digits
131
132	if ( length($shortstring) > $cutlength ) { $shortstring = substr($shortstring, 0, $cutlength); }
133
134	$shortstring = $shortstring . "_" . $subid;
135
136	return $shortstring;
137}
138
139##############################################################
140# Adding unique directory names to the directory collection
141##############################################################
142
143sub create_unique_directorynames
144{
145	my ($directoryref, $allvariables) = @_;
146
147	$installer::globals::officeinstalldirectoryset = 0;
148
149	my %completedirhashstep1 = ();
150	my %shortdirhash = ();
151	my %shortdirhashreverse = ();
152	my $infoline = "";
153	my $errorcount = 0;
154
155	for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
156	{
157		my $onedir = ${$directoryref}[$i];
158		my $uniquename = $onedir->{'HostName'};
159
160		my $styles = "";
161		if ( $onedir->{'Styles'} ) { $styles = $onedir->{'Styles'}; }
162
163		$uniquename =~ s/^\s*//g;				# removing beginning white spaces
164		$uniquename =~ s/\s*$//g;				# removing ending white spaces
165		$uniquename =~ s/\s//g;					# removing white spaces
166		$uniquename =~ s/\_//g;					# removing existing underlines
167		$uniquename =~ s/\.//g;					# removing dots in directoryname
168		$uniquename =~ s/OpenOffice/OO/g;
169
170		$uniquename =~ s/\Q$installer::globals::separator\E/\_/g;	# replacing slash and backslash with underline
171
172		$uniquename =~ s/_registry/_rgy/g;
173		$uniquename =~ s/_registration/_rgn/g;
174		$uniquename =~ s/_extension/_ext/g;
175		$uniquename =~ s/_frame/_frm/g;
176		$uniquename =~ s/_table/_tbl/g;
177		$uniquename =~ s/_chart/_crt/g;
178
179		# The names after this small changes must still be unique!
180		if ( exists($completedirhashstep1{$uniquename}) ) { installer::exiter::exit_program("ERROR: Error in packaging process. Unallowed modification of directory name, not unique (step 1): \"$uniquename\".", "create_unique_directorynames"); }
181		$completedirhashstep1{$uniquename} = 1;
182
183		# Starting to make unique name for the parent and its directory
184		my $originaluniquename = $uniquename;
185
186		$uniquename = make_short_dir_version($uniquename);
187
188		# Checking if the same directory already exists, but has another short version.
189		if (( exists($shortdirhash{$originaluniquename}) ) && ( $shortdirhash{$originaluniquename} ne $uniquename )) { installer::exiter::exit_program("ERROR: Error in packaging process. Unallowed modification of directory name, not unique (step 2A): \"$uniquename\".", "create_unique_directorynames"); }
190
191		# Also checking vice versa
192		# Checking if the same short directory already exists, but has another long version.
193		if (( exists($shortdirhashreverse{$uniquename}) ) && ( $shortdirhashreverse{$uniquename} ne $originaluniquename )) { installer::exiter::exit_program("ERROR: Error in packaging process. Unallowed modification of directory name, not unique (step 2B): \"$uniquename\".", "create_unique_directorynames"); }
194
195		# Creating assignment from long to short directory names
196		$shortdirhash{$originaluniquename} = $uniquename;
197		$shortdirhashreverse{$uniquename} = $originaluniquename;
198
199		# Important: The unique parent is generated from the string $originaluniquename (with the use of underlines).
200
201		my $uniqueparentname = $originaluniquename;
202		my $keepparent = 1;
203
204		if ( $uniqueparentname =~ /^\s*(.*)\_(.*?)\s*$/ )	# the underline is now the separator
205		{
206			$uniqueparentname = $1;
207			$keepparent = 0;
208		}
209		else
210		{
211			$uniqueparentname = $installer::globals::programfilesfolder;
212			$keepparent = 1;
213		}
214
215		if ( $styles =~ /\bPROGRAMFILESFOLDER\b/ )
216		{
217			$uniqueparentname = $installer::globals::programfilesfolder;
218			$keepparent = 1;
219		}
220		if ( $styles =~ /\bCOMMONFILESFOLDER\b/ )
221		{
222			$uniqueparentname = $installer::globals::commonfilesfolder;
223			$keepparent = 1;
224		}
225		if ( $styles =~ /\bCOMMONAPPDATAFOLDER\b/ )
226		{
227			$uniqueparentname = $installer::globals::commonappdatafolder;
228			$keepparent = 1;
229		}
230		if ( $styles =~ /\bLOCALAPPDATAFOLDER\b/ )
231		{
232			$uniqueparentname = $installer::globals::localappdatafolder;
233			$keepparent = 1;
234		}
235
236		if ( $styles =~ /\bSHAREPOINTPATH\b/ )
237		{
238			$uniqueparentname = "SHAREPOINTPATH";
239			$installer::globals::usesharepointpath = 1;
240			$keepparent = 1;
241		}
242
243		# also setting short directory name for the parent
244
245		my $originaluniqueparentname = $uniqueparentname;
246
247		if ( ! $keepparent )
248		{
249			$uniqueparentname = make_short_dir_version($uniqueparentname);
250		}
251
252		# Again checking if the same directory already exists, but has another short version.
253		if (( exists($shortdirhash{$originaluniqueparentname}) ) && ( $shortdirhash{$originaluniqueparentname} ne $uniqueparentname )) { installer::exiter::exit_program("ERROR: Error in packaging process. Unallowed modification of directory name, not unique (step 3A): \"$uniqueparentname\".", "create_unique_directorynames"); }
254
255		# Also checking vice versa
256		# Checking if the same short directory already exists, but has another long version.
257		if (( exists($shortdirhashreverse{$uniqueparentname}) ) && ( $shortdirhashreverse{$uniqueparentname} ne $originaluniqueparentname )) { installer::exiter::exit_program("ERROR: Error in packaging process. Unallowed modification of directory name, not unique (step 3B): \"$uniqueparentname\".", "create_unique_directorynames"); }
258
259		$shortdirhash{$originaluniqueparentname} = $uniqueparentname;
260		$shortdirhashreverse{$uniqueparentname} = $originaluniqueparentname;
261
262		# Hyphen not allowed in database
263		$uniquename =~ s/\-/\_/g;			# making "-" to "_"
264		$uniqueparentname =~ s/\-/\_/g;		# making "-" to "_"
265
266		# And finally setting the values for the directories
267		$onedir->{'uniquename'} = $uniquename;
268		$onedir->{'uniqueparentname'} = $uniqueparentname;
269
270		# setting the installlocation directory
271		if ( $styles =~ /\bISINSTALLLOCATION\b/ )
272		{
273			if ( $installer::globals::installlocationdirectoryset ) { installer::exiter::exit_program("ERROR: Directory with flag ISINSTALLLOCATION alread set: \"$installer::globals::installlocationdirectory\".", "create_unique_directorynames"); }
274			$installer::globals::installlocationdirectory = $uniquename;
275			$installer::globals::installlocationdirectoryset = 1;
276			if ( $installer::globals::installlocationdirectory =~ /oracle_/i ) { $installer::globals::sundirexists = 1; }
277		}
278
279		# setting the sundirectory
280		if ( $styles =~ /\bSUNDIRECTORY\b/ )
281		{
282			if ( $installer::globals::vendordirectoryset ) { installer::exiter::exit_program("ERROR: Directory with flag SUNDIRECTORY alread set: \"$installer::globals::vendordirectory\".", "create_unique_directorynames"); }
283			$installer::globals::vendordirectory = $uniquename;
284			$installer::globals::vendordirectoryset = 1;
285		}
286	}
287}
288
289#####################################################
290# Adding ":." to selected default directory names
291#####################################################
292
293sub check_sourcedir_addon
294{
295	my ( $onedir, $allvariableshashref ) = @_;
296
297	if (($installer::globals::addchildprojects) ||
298		($installer::globals::patch) ||
299		($installer::globals::languagepack) ||
300		($allvariableshashref->{'CHANGETARGETDIR'}))
301	{
302		my $sourcediraddon = "\:\.";
303		$onedir->{'defaultdir'} = $onedir->{'defaultdir'} . $sourcediraddon;
304	}
305
306}
307
308#####################################################
309# The directory with the style ISINSTALLLOCATION
310# will be replaced by INSTALLLOCATION
311#####################################################
312
313sub set_installlocation_directory
314{
315	my ( $directoryref, $allvariableshashref ) = @_;
316
317	if ( ! $installer::globals::installlocationdirectoryset ) { installer::exiter::exit_program("ERROR: Directory with flag ISINSTALLLOCATION not set!", "set_installlocation_directory"); }
318
319	for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
320	{
321		my $onedir = ${$directoryref}[$i];
322
323		if ( $onedir->{'uniquename'} eq $installer::globals::installlocationdirectory )
324		{
325			$onedir->{'uniquename'} = "INSTALLLOCATION";
326			check_sourcedir_addon($onedir, $allvariableshashref);
327		}
328
329		if ( $onedir->{'uniquename'} eq $installer::globals::vendordirectory )
330		{
331			check_sourcedir_addon($onedir, $allvariableshashref);
332		}
333
334		if ( $onedir->{'uniqueparentname'} eq $installer::globals::installlocationdirectory )
335		{
336			$onedir->{'uniqueparentname'} = "INSTALLLOCATION";
337		}
338	}
339}
340
341#####################################################
342# Getting the name of the top level directory. This
343# can have only one letter
344#####################################################
345
346sub get_last_directory_name
347{
348	my ($completepathref) = @_;
349
350	if ( $$completepathref =~ /^.*[\/\\](.+?)\s*$/ )
351	{
352		$$completepathref = $1;
353	}
354}
355
356#####################################################
357# Creating the defaultdir for the file Director.idt
358#####################################################
359
360sub create_defaultdir_directorynames
361{
362	my ($directoryref, $shortdirnamehashref) = @_;
363
364	my @shortnames = ();
365	if ( $installer::globals::updatedatabase ) { @shortnames = values(%{$shortdirnamehashref}); }
366	elsif ( $installer::globals::prepare_winpatch ) { @shortnames = values(%installer::globals::saved83dirmapping); }
367
368	for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
369	{
370		my $onedir = ${$directoryref}[$i];
371		my $hostname = $onedir->{'HostName'};
372
373		$hostname =~ s/\Q$installer::globals::separator\E\s*$//;
374		get_last_directory_name(\$hostname);
375		# installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$hostname);	# making program/classes to classes
376		my $uniquename = $onedir->{'uniquename'};
377		my $shortstring;
378		if (( $installer::globals::updatedatabase ) && ( exists($shortdirnamehashref->{$uniquename}) ))
379		{
380			$shortstring = $shortdirnamehashref->{$uniquename};
381		}
382		elsif (( $installer::globals::prepare_winpatch ) && ( exists($installer::globals::saved83dirmapping{$uniquename}) ))
383		{
384			$shortstring = $installer::globals::saved83dirmapping{$uniquename};
385		}
386		else
387		{
388			$shortstring = installer::windows::idtglobal::make_eight_three_conform($hostname, "dir", \@shortnames);
389		}
390
391		my $defaultdir;
392
393		if ( $shortstring eq $hostname )
394		{
395			$defaultdir = $hostname;
396		}
397		else
398		{
399			$defaultdir = $shortstring . "|" . $hostname;
400		}
401
402		$onedir->{'defaultdir'} = $defaultdir;
403
404		my $fontdir = "";
405		if ( $onedir->{'Dir'} ) { $fontdir = $onedir->{'Dir'}; }
406
407		my $fontdefaultdir = "";
408		if ( $onedir->{'defaultdir'} ) { $fontdefaultdir = $onedir->{'defaultdir'}; }
409
410		if (( $fontdir eq "PREDEFINED_OSSYSTEMFONTDIR" ) && ( $fontdefaultdir eq $installer::globals::fontsdirhostname ))
411		{
412			$installer::globals::fontsdirname = $onedir->{'defaultdir'};
413			$installer::globals::fontsdirparent = $onedir->{'uniqueparentname'};
414		}
415	}
416}
417
418###############################################
419# Fill content into the directory table
420###############################################
421
422sub create_directorytable_from_collection
423{
424	my ($directorytableref, $directoryref) = @_;
425
426	for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
427	{
428		my $onedir = ${$directoryref}[$i];
429		my $hostname = $onedir->{'HostName'};
430		my $dir = "";
431
432		if ( $onedir->{'Dir'} ) { $dir = $onedir->{'Dir'}; }
433
434		if (( $dir eq "PREDEFINED_PROGDIR" ) && ( $hostname eq "" )) { next; }	# removing files from root directory
435
436		my $oneline = $onedir->{'uniquename'} . "\t" . $onedir->{'uniqueparentname'} . "\t" . $onedir->{'defaultdir'} . "\n";
437
438		push(@{$directorytableref}, $oneline);
439	}
440}
441
442###############################################
443# Defining the root installation structure
444###############################################
445
446sub add_root_directories
447{
448	my ($directorytableref, $allvariableshashref) = @_;
449
450#	my $sourcediraddon = "";
451#	if (($installer::globals::addchildprojects) ||
452#		($installer::globals::patch) ||
453#		($installer::globals::languagepack) ||
454#		($allvariableshashref->{'CHANGETARGETDIR'}))
455#	{
456#		$sourcediraddon = "\:\.";
457#	}
458
459	my $oneline = "";
460
461	if (( ! $installer::globals::patch ) && ( ! $installer::globals::languagepack ) && ( ! $allvariableshashref->{'DONTUSESTARTMENUFOLDER'} ))
462	{
463		my $productname = $allvariableshashref->{'PRODUCTNAME'};
464		my $productversion = $allvariableshashref->{'PRODUCTVERSION'};
465		my $baseproductversion = $productversion;
466
467		if (( $installer::globals::prepare_winpatch ) && ( $allvariableshashref->{'BASEPRODUCTVERSION'} ))
468		{
469			$baseproductversion = $allvariableshashref->{'BASEPRODUCTVERSION'};  # for example "2.0" for OOo
470		}
471
472		my $realproductkey = $productname . " " . $productversion;
473		my $productkey = $productname . " " . $baseproductversion;
474
475		if (( $allvariableshashref->{'POSTVERSIONEXTENSION'} ) && ( ! $allvariableshashref->{'DONTUSEEXTENSIONINDEFAULTDIR'} ))
476		{
477			$productkey = $productkey . " " . $allvariableshashref->{'POSTVERSIONEXTENSION'};
478			$realproductkey = $realproductkey . " " . $allvariableshashref->{'POSTVERSIONEXTENSION'};
479		}
480		if ( $allvariableshashref->{'NOVERSIONINDIRNAME'} )
481		{
482			$productkey = $productname;
483			$realproductkey = $realproductname;
484		}
485		if ( $allvariableshashref->{'NOSPACEINDIRECTORYNAME'} )
486		{
487			$productkey =~ s/\ /\_/g;
488			$realproductkey =~ s/\ /\_/g;
489		}
490
491		my $shortproductkey = installer::windows::idtglobal::make_eight_three_conform($productkey, "dir");		# third parameter not used
492		$shortproductkey =~ s/\s/\_/g;									# changing empty space to underline
493
494		$oneline = "$installer::globals::officemenufolder\t$installer::globals::programmenufolder\t$shortproductkey|$realproductkey\n";
495		push(@{$directorytableref}, $oneline);
496	}
497
498	$oneline = "TARGETDIR\t\tSourceDir\n";
499	push(@{$directorytableref}, $oneline);
500
501	$oneline = "$installer::globals::programfilesfolder\tTARGETDIR\t.\n";
502	push(@{$directorytableref}, $oneline);
503
504	$oneline = "$installer::globals::programmenufolder\tTARGETDIR\t.\n";
505	push(@{$directorytableref}, $oneline);
506
507	$oneline = "$installer::globals::startupfolder\tTARGETDIR\t.\n";
508	push(@{$directorytableref}, $oneline);
509
510	$oneline = "$installer::globals::desktopfolder\tTARGETDIR\t.\n";
511	push(@{$directorytableref}, $oneline);
512
513	$oneline = "$installer::globals::startmenufolder\tTARGETDIR\t.\n";
514	push(@{$directorytableref}, $oneline);
515
516	$oneline = "$installer::globals::commonfilesfolder\tTARGETDIR\t.\n";
517	push(@{$directorytableref}, $oneline);
518
519	$oneline = "$installer::globals::commonappdatafolder\tTARGETDIR\t.\n";
520	push(@{$directorytableref}, $oneline);
521
522	$oneline = "$installer::globals::localappdatafolder\tTARGETDIR\t.\n";
523	push(@{$directorytableref}, $oneline);
524
525	if ( $installer::globals::usesharepointpath )
526	{
527		$oneline = "SHAREPOINTPATH\tTARGETDIR\t.\n";
528		push(@{$directorytableref}, $oneline);
529	}
530
531	$oneline = "$installer::globals::systemfolder\tTARGETDIR\t.\n";
532	push(@{$directorytableref}, $oneline);
533
534	my $localtemplatefoldername = $installer::globals::templatefoldername;
535	my $directorytableentry = $localtemplatefoldername;
536	my $shorttemplatefoldername = installer::windows::idtglobal::make_eight_three_conform($localtemplatefoldername, "dir");
537	if ( $shorttemplatefoldername ne $localtemplatefoldername ) { $directorytableentry = "$shorttemplatefoldername|$localtemplatefoldername"; }
538	$oneline = "$installer::globals::templatefolder\tTARGETDIR\t$directorytableentry\n";
539	push(@{$directorytableref}, $oneline);
540
541	if ( $installer::globals::fontsdirname )
542	{
543		$oneline = "$installer::globals::fontsfolder\t$installer::globals::fontsdirparent\t$installer::globals::fontsfoldername\:$installer::globals::fontsdirname\n";
544	}
545	else
546	{
547		$oneline = "$installer::globals::fontsfolder\tTARGETDIR\t$installer::globals::fontsfoldername\n";
548	}
549
550	push(@{$directorytableref}, $oneline);
551
552}
553
554###############################################
555# Creating the file Director.idt dynamically
556###############################################
557
558sub create_directory_table
559{
560	my ($directoryref, $basedir, $allvariableshashref, $shortdirnamehashref, $loggingdir) = @_;
561
562	# Structure of the directory table:
563	# Directory Directory_Parent DefaultDir
564	# Directory is a unique identifier
565	# Directory_Parent is the unique identifier of the parent
566	# DefaultDir is .:APPLIC~1|Application Data with
567	# Before ":" : [sourcedir]:[destdir] (not programmed yet)
568	# After ":" : 8+3 and not 8+3 the destination directory name
569
570	installer::logger::include_timestamp_into_logfile("Performance Info: Directory Table start");
571
572	my @directorytable = ();
573	my $infoline;
574
575	overwrite_programfilesfolder($allvariableshashref);
576	if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "directoriesforidt_local_1.log", $directoryref); }
577	create_unique_directorynames($directoryref, $allvariableshashref);
578	if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "directoriesforidt_local_1a.log", $directoryref); }
579	create_defaultdir_directorynames($directoryref, $shortdirnamehashref);	# only destdir!
580	if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "directoriesforidt_local_2.log", $directoryref); }
581	set_installlocation_directory($directoryref, $allvariableshashref);
582	if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "directoriesforidt_local_3.log", $directoryref); }
583	installer::windows::idtglobal::write_idt_header(\@directorytable, "directory");
584	add_root_directories(\@directorytable, $allvariableshashref);
585	create_directorytable_from_collection(\@directorytable, $directoryref);
586
587	# Saving the file
588
589	my $directorytablename = $basedir . $installer::globals::separator . "Director.idt";
590	installer::files::save_file($directorytablename ,\@directorytable);
591	$infoline = "Created idt file: $directorytablename\n";
592	push(@installer::globals::logfileinfo, $infoline);
593
594	installer::logger::include_timestamp_into_logfile("Performance Info: Directory Table end");
595
596}
597
5981;
599