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