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		}
273
274		# setting the sundirectory
275		if ( $styles =~ /\bSUNDIRECTORY\b/ )
276		{
277			if ( $installer::globals::vendordirectoryset ) { installer::exiter::exit_program("ERROR: Directory with flag SUNDIRECTORY alread set: \"$installer::globals::vendordirectory\".", "create_unique_directorynames"); }
278			$installer::globals::vendordirectory = $uniquename;
279			$installer::globals::vendordirectoryset = 1;
280		}
281	}
282}
283
284#####################################################
285# Adding ":." to selected default directory names
286#####################################################
287
288sub check_sourcedir_addon
289{
290	my ( $onedir, $allvariableshashref ) = @_;
291
292	if (($installer::globals::addchildprojects) ||
293		($installer::globals::patch) ||
294		($installer::globals::languagepack) ||
295		($allvariableshashref->{'CHANGETARGETDIR'}))
296	{
297		my $sourcediraddon = "\:\.";
298		$onedir->{'defaultdir'} = $onedir->{'defaultdir'} . $sourcediraddon;
299	}
300
301}
302
303#####################################################
304# The directory with the style ISINSTALLLOCATION
305# will be replaced by INSTALLLOCATION
306#####################################################
307
308sub set_installlocation_directory
309{
310	my ( $directoryref, $allvariableshashref ) = @_;
311
312	if ( ! $installer::globals::installlocationdirectoryset ) { installer::exiter::exit_program("ERROR: Directory with flag ISINSTALLLOCATION not set!", "set_installlocation_directory"); }
313
314	for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
315	{
316		my $onedir = ${$directoryref}[$i];
317
318		if ( $onedir->{'uniquename'} eq $installer::globals::installlocationdirectory )
319		{
320			$onedir->{'uniquename'} = "INSTALLLOCATION";
321			check_sourcedir_addon($onedir, $allvariableshashref);
322		}
323
324		if ( $onedir->{'uniquename'} eq $installer::globals::vendordirectory )
325		{
326			check_sourcedir_addon($onedir, $allvariableshashref);
327		}
328
329		if ( $onedir->{'uniqueparentname'} eq $installer::globals::installlocationdirectory )
330		{
331			$onedir->{'uniqueparentname'} = "INSTALLLOCATION";
332		}
333	}
334}
335
336#####################################################
337# Getting the name of the top level directory. This
338# can have only one letter
339#####################################################
340
341sub get_last_directory_name
342{
343	my ($completepathref) = @_;
344
345	if ( $$completepathref =~ /^.*[\/\\](.+?)\s*$/ )
346	{
347		$$completepathref = $1;
348	}
349}
350
351#####################################################
352# Creating the defaultdir for the file Director.idt
353#####################################################
354
355sub create_defaultdir_directorynames
356{
357	my ($directoryref, $shortdirnamehashref) = @_;
358
359	my @shortnames = ();
360	if ( $installer::globals::prepare_winpatch ) { @shortnames = values(%installer::globals::saved83dirmapping); }
361
362	for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
363	{
364		my $onedir = ${$directoryref}[$i];
365		my $hostname = $onedir->{'HostName'};
366
367		$hostname =~ s/\Q$installer::globals::separator\E\s*$//;
368		get_last_directory_name(\$hostname);
369		# installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$hostname);	# making program/classes to classes
370		my $uniquename = $onedir->{'uniquename'};
371		my $shortstring;
372		if (( $installer::globals::prepare_winpatch ) && ( exists($installer::globals::saved83dirmapping{$uniquename}) ))
373		{
374			$shortstring = $installer::globals::saved83dirmapping{$uniquename};
375		}
376		else
377		{
378			$shortstring = installer::windows::idtglobal::make_eight_three_conform($hostname, "dir", \@shortnames);
379		}
380
381		my $defaultdir;
382
383		if ( $shortstring eq $hostname )
384		{
385			$defaultdir = $hostname;
386		}
387		else
388		{
389			$defaultdir = $shortstring . "|" . $hostname;
390		}
391
392		$onedir->{'defaultdir'} = $defaultdir;
393
394		my $fontdir = "";
395		if ( $onedir->{'Dir'} ) { $fontdir = $onedir->{'Dir'}; }
396
397		my $fontdefaultdir = "";
398		if ( $onedir->{'defaultdir'} ) { $fontdefaultdir = $onedir->{'defaultdir'}; }
399
400		if (( $fontdir eq "PREDEFINED_OSSYSTEMFONTDIR" ) && ( $fontdefaultdir eq $installer::globals::fontsdirhostname ))
401		{
402			$installer::globals::fontsdirname = $onedir->{'defaultdir'};
403			$installer::globals::fontsdirparent = $onedir->{'uniqueparentname'};
404		}
405	}
406}
407
408###############################################
409# Fill content into the directory table
410###############################################
411
412sub create_directorytable_from_collection
413{
414	my ($directorytableref, $directoryref) = @_;
415
416	for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
417	{
418		my $onedir = ${$directoryref}[$i];
419		my $hostname = $onedir->{'HostName'};
420		my $dir = "";
421
422		if ( $onedir->{'Dir'} ) { $dir = $onedir->{'Dir'}; }
423
424		if (( $dir eq "PREDEFINED_PROGDIR" ) && ( $hostname eq "" )) { next; }	# removing files from root directory
425
426		my $oneline = $onedir->{'uniquename'} . "\t" . $onedir->{'uniqueparentname'} . "\t" . $onedir->{'defaultdir'} . "\n";
427
428		push(@{$directorytableref}, $oneline);
429	}
430}
431
432###############################################
433# Defining the root installation structure
434###############################################
435
436sub add_root_directories
437{
438	my ($directorytableref, $allvariableshashref) = @_;
439
440#	my $sourcediraddon = "";
441#	if (($installer::globals::addchildprojects) ||
442#		($installer::globals::patch) ||
443#		($installer::globals::languagepack) ||
444#		($allvariableshashref->{'CHANGETARGETDIR'}))
445#	{
446#		$sourcediraddon = "\:\.";
447#	}
448
449	my $oneline = "";
450
451	if (( ! $installer::globals::patch ) && ( ! $installer::globals::languagepack ) && ( ! $allvariableshashref->{'DONTUSESTARTMENUFOLDER'} ))
452	{
453		my $productname = $allvariableshashref->{'PRODUCTNAME'};
454		my $productversion = $allvariableshashref->{'PRODUCTVERSION'};
455		my $baseproductversion = $productversion;
456
457		if (( $installer::globals::prepare_winpatch ) && ( $allvariableshashref->{'BASEPRODUCTVERSION'} ))
458		{
459			$baseproductversion = $allvariableshashref->{'BASEPRODUCTVERSION'};  # for example "2.0" for OOo
460		}
461
462		my $realproductkey = $productname . " " . $productversion;
463		my $productkey = $productname . " " . $baseproductversion;
464
465		if (( $allvariableshashref->{'POSTVERSIONEXTENSION'} ) && ( ! $allvariableshashref->{'DONTUSEEXTENSIONINDEFAULTDIR'} ))
466		{
467			$productkey = $productkey . " " . $allvariableshashref->{'POSTVERSIONEXTENSION'};
468			$realproductkey = $realproductkey . " " . $allvariableshashref->{'POSTVERSIONEXTENSION'};
469		}
470		if ( $allvariableshashref->{'NOSPACEINDIRECTORYNAME'} )
471		{
472			$productkey =~ s/\ /\_/g;
473			$realproductkey =~ s/\ /\_/g;
474		}
475
476		my $shortproductkey = installer::windows::idtglobal::make_eight_three_conform($productkey, "dir");		# third parameter not used
477		$shortproductkey =~ s/\s/\_/g;									# changing empty space to underline
478
479		$oneline = "$installer::globals::officemenufolder\t$installer::globals::programmenufolder\t$shortproductkey|$realproductkey\n";
480		push(@{$directorytableref}, $oneline);
481	}
482
483	$oneline = "TARGETDIR\t\tSourceDir\n";
484	push(@{$directorytableref}, $oneline);
485
486	$oneline = "$installer::globals::programfilesfolder\tTARGETDIR\t.\n";
487	push(@{$directorytableref}, $oneline);
488
489	$oneline = "$installer::globals::programmenufolder\tTARGETDIR\t.\n";
490	push(@{$directorytableref}, $oneline);
491
492	$oneline = "$installer::globals::startupfolder\tTARGETDIR\t.\n";
493	push(@{$directorytableref}, $oneline);
494
495	$oneline = "$installer::globals::desktopfolder\tTARGETDIR\t.\n";
496	push(@{$directorytableref}, $oneline);
497
498	$oneline = "$installer::globals::startmenufolder\tTARGETDIR\t.\n";
499	push(@{$directorytableref}, $oneline);
500
501	$oneline = "$installer::globals::commonfilesfolder\tTARGETDIR\t.\n";
502	push(@{$directorytableref}, $oneline);
503
504	$oneline = "$installer::globals::commonappdatafolder\tTARGETDIR\t.\n";
505	push(@{$directorytableref}, $oneline);
506
507	$oneline = "$installer::globals::localappdatafolder\tTARGETDIR\t.\n";
508	push(@{$directorytableref}, $oneline);
509
510	if ( $installer::globals::usesharepointpath )
511	{
512		$oneline = "SHAREPOINTPATH\tTARGETDIR\t.\n";
513		push(@{$directorytableref}, $oneline);
514	}
515
516	$oneline = "$installer::globals::systemfolder\tTARGETDIR\t.\n";
517	push(@{$directorytableref}, $oneline);
518
519	my $localtemplatefoldername = $installer::globals::templatefoldername;
520	my $directorytableentry = $localtemplatefoldername;
521	my $shorttemplatefoldername = installer::windows::idtglobal::make_eight_three_conform($localtemplatefoldername, "dir");
522	if ( $shorttemplatefoldername ne $localtemplatefoldername ) { $directorytableentry = "$shorttemplatefoldername|$localtemplatefoldername"; }
523	$oneline = "$installer::globals::templatefolder\tTARGETDIR\t$directorytableentry\n";
524	push(@{$directorytableref}, $oneline);
525
526	if ( $installer::globals::fontsdirname )
527	{
528		$oneline = "$installer::globals::fontsfolder\t$installer::globals::fontsdirparent\t$installer::globals::fontsfoldername\:$installer::globals::fontsdirname\n";
529	}
530	else
531	{
532		$oneline = "$installer::globals::fontsfolder\tTARGETDIR\t$installer::globals::fontsfoldername\n";
533	}
534
535	push(@{$directorytableref}, $oneline);
536
537}
538
539###############################################
540# Creating the file Director.idt dynamically
541###############################################
542
543sub create_directory_table
544{
545	my ($directoryref, $basedir, $allvariableshashref, $shortdirnamehashref, $loggingdir) = @_;
546
547	# Structure of the directory table:
548	# Directory Directory_Parent DefaultDir
549	# Directory is a unique identifier
550	# Directory_Parent is the unique identifier of the parent
551	# DefaultDir is .:APPLIC~1|Application Data with
552	# Before ":" : [sourcedir]:[destdir] (not programmed yet)
553	# After ":" : 8+3 and not 8+3 the destination directory name
554
555	$installer::logger::Lang->add_timestamp("Performance Info: Directory Table start");
556
557	my @directorytable = ();
558	my $infoline;
559
560	overwrite_programfilesfolder($allvariableshashref);
561	if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "directoriesforidt_local_1.log", $directoryref); }
562	create_unique_directorynames($directoryref, $allvariableshashref);
563	if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "directoriesforidt_local_1a.log", $directoryref); }
564	create_defaultdir_directorynames($directoryref, $shortdirnamehashref);	# only destdir!
565	if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "directoriesforidt_local_2.log", $directoryref); }
566	set_installlocation_directory($directoryref, $allvariableshashref);
567	if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "directoriesforidt_local_3.log", $directoryref); }
568	installer::windows::idtglobal::write_idt_header(\@directorytable, "directory");
569	add_root_directories(\@directorytable, $allvariableshashref);
570	create_directorytable_from_collection(\@directorytable, $directoryref);
571
572	# Saving the file
573
574	my $directorytablename = $basedir . $installer::globals::separator . "Director.idt";
575	installer::files::save_file($directorytablename ,\@directorytable);
576    $installer::logger::Lang->printf("Created idt file: %s\n", $directorytablename);
577
578	$installer::logger::Lang->add_timestamp("Performance Info: Directory Table end");
579}
580
5811;
582