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::prepare_winpatch ) { @shortnames = values(%installer::globals::saved83dirmapping); }
362
363	for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
364	{
365		my $onedir = ${$directoryref}[$i];
366		my $hostname = $onedir->{'HostName'};
367
368		$hostname =~ s/\Q$installer::globals::separator\E\s*$//;
369		get_last_directory_name(\$hostname);
370		# installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$hostname);	# making program/classes to classes
371		my $uniquename = $onedir->{'uniquename'};
372		my $shortstring;
373		if (( $installer::globals::prepare_winpatch ) && ( exists($installer::globals::saved83dirmapping{$uniquename}) ))
374		{
375			$shortstring = $installer::globals::saved83dirmapping{$uniquename};
376		}
377		else
378		{
379			$shortstring = installer::windows::idtglobal::make_eight_three_conform($hostname, "dir", \@shortnames);
380		}
381
382		my $defaultdir;
383
384		if ( $shortstring eq $hostname )
385		{
386			$defaultdir = $hostname;
387		}
388		else
389		{
390			$defaultdir = $shortstring . "|" . $hostname;
391		}
392
393		$onedir->{'defaultdir'} = $defaultdir;
394
395		my $fontdir = "";
396		if ( $onedir->{'Dir'} ) { $fontdir = $onedir->{'Dir'}; }
397
398		my $fontdefaultdir = "";
399		if ( $onedir->{'defaultdir'} ) { $fontdefaultdir = $onedir->{'defaultdir'}; }
400
401		if (( $fontdir eq "PREDEFINED_OSSYSTEMFONTDIR" ) && ( $fontdefaultdir eq $installer::globals::fontsdirhostname ))
402		{
403			$installer::globals::fontsdirname = $onedir->{'defaultdir'};
404			$installer::globals::fontsdirparent = $onedir->{'uniqueparentname'};
405		}
406	}
407}
408
409###############################################
410# Fill content into the directory table
411###############################################
412
413sub create_directorytable_from_collection
414{
415	my ($directorytableref, $directoryref) = @_;
416
417	for ( my $i = 0; $i <= $#{$directoryref}; $i++ )
418	{
419		my $onedir = ${$directoryref}[$i];
420		my $hostname = $onedir->{'HostName'};
421		my $dir = "";
422
423		if ( $onedir->{'Dir'} ) { $dir = $onedir->{'Dir'}; }
424
425		if (( $dir eq "PREDEFINED_PROGDIR" ) && ( $hostname eq "" )) { next; }	# removing files from root directory
426
427		my $oneline = $onedir->{'uniquename'} . "\t" . $onedir->{'uniqueparentname'} . "\t" . $onedir->{'defaultdir'} . "\n";
428
429		push(@{$directorytableref}, $oneline);
430	}
431}
432
433###############################################
434# Defining the root installation structure
435###############################################
436
437sub add_root_directories
438{
439	my ($directorytableref, $allvariableshashref) = @_;
440
441#	my $sourcediraddon = "";
442#	if (($installer::globals::addchildprojects) ||
443#		($installer::globals::patch) ||
444#		($installer::globals::languagepack) ||
445#		($allvariableshashref->{'CHANGETARGETDIR'}))
446#	{
447#		$sourcediraddon = "\:\.";
448#	}
449
450	my $oneline = "";
451
452	if (( ! $installer::globals::patch ) && ( ! $installer::globals::languagepack ) && ( ! $allvariableshashref->{'DONTUSESTARTMENUFOLDER'} ))
453	{
454		my $productname = $allvariableshashref->{'PRODUCTNAME'};
455		my $productversion = $allvariableshashref->{'PRODUCTVERSION'};
456		my $baseproductversion = $productversion;
457
458		if (( $installer::globals::prepare_winpatch ) && ( $allvariableshashref->{'BASEPRODUCTVERSION'} ))
459		{
460			$baseproductversion = $allvariableshashref->{'BASEPRODUCTVERSION'};  # for example "2.0" for OOo
461		}
462
463		my $realproductkey = $productname . " " . $productversion;
464		my $productkey = $productname . " " . $baseproductversion;
465
466		if (( $allvariableshashref->{'POSTVERSIONEXTENSION'} ) && ( ! $allvariableshashref->{'DONTUSEEXTENSIONINDEFAULTDIR'} ))
467		{
468			$productkey = $productkey . " " . $allvariableshashref->{'POSTVERSIONEXTENSION'};
469			$realproductkey = $realproductkey . " " . $allvariableshashref->{'POSTVERSIONEXTENSION'};
470		}
471		if ( $allvariableshashref->{'NOVERSIONINDIRNAME'} )
472		{
473			$productkey = $productname;
474			$realproductkey = $realproductname;
475		}
476		if ( $allvariableshashref->{'NOSPACEINDIRECTORYNAME'} )
477		{
478			$productkey =~ s/\ /\_/g;
479			$realproductkey =~ s/\ /\_/g;
480		}
481
482		my $shortproductkey = installer::windows::idtglobal::make_eight_three_conform($productkey, "dir");		# third parameter not used
483		$shortproductkey =~ s/\s/\_/g;									# changing empty space to underline
484
485		$oneline = "$installer::globals::officemenufolder\t$installer::globals::programmenufolder\t$shortproductkey|$realproductkey\n";
486		push(@{$directorytableref}, $oneline);
487	}
488
489	$oneline = "TARGETDIR\t\tSourceDir\n";
490	push(@{$directorytableref}, $oneline);
491
492	$oneline = "$installer::globals::programfilesfolder\tTARGETDIR\t.\n";
493	push(@{$directorytableref}, $oneline);
494
495	$oneline = "$installer::globals::programmenufolder\tTARGETDIR\t.\n";
496	push(@{$directorytableref}, $oneline);
497
498	$oneline = "$installer::globals::startupfolder\tTARGETDIR\t.\n";
499	push(@{$directorytableref}, $oneline);
500
501	$oneline = "$installer::globals::desktopfolder\tTARGETDIR\t.\n";
502	push(@{$directorytableref}, $oneline);
503
504	$oneline = "$installer::globals::startmenufolder\tTARGETDIR\t.\n";
505	push(@{$directorytableref}, $oneline);
506
507	$oneline = "$installer::globals::commonfilesfolder\tTARGETDIR\t.\n";
508	push(@{$directorytableref}, $oneline);
509
510	$oneline = "$installer::globals::commonappdatafolder\tTARGETDIR\t.\n";
511	push(@{$directorytableref}, $oneline);
512
513	$oneline = "$installer::globals::localappdatafolder\tTARGETDIR\t.\n";
514	push(@{$directorytableref}, $oneline);
515
516	if ( $installer::globals::usesharepointpath )
517	{
518		$oneline = "SHAREPOINTPATH\tTARGETDIR\t.\n";
519		push(@{$directorytableref}, $oneline);
520	}
521
522	$oneline = "$installer::globals::systemfolder\tTARGETDIR\t.\n";
523	push(@{$directorytableref}, $oneline);
524
525	my $localtemplatefoldername = $installer::globals::templatefoldername;
526	my $directorytableentry = $localtemplatefoldername;
527	my $shorttemplatefoldername = installer::windows::idtglobal::make_eight_three_conform($localtemplatefoldername, "dir");
528	if ( $shorttemplatefoldername ne $localtemplatefoldername ) { $directorytableentry = "$shorttemplatefoldername|$localtemplatefoldername"; }
529	$oneline = "$installer::globals::templatefolder\tTARGETDIR\t$directorytableentry\n";
530	push(@{$directorytableref}, $oneline);
531
532	if ( $installer::globals::fontsdirname )
533	{
534		$oneline = "$installer::globals::fontsfolder\t$installer::globals::fontsdirparent\t$installer::globals::fontsfoldername\:$installer::globals::fontsdirname\n";
535	}
536	else
537	{
538		$oneline = "$installer::globals::fontsfolder\tTARGETDIR\t$installer::globals::fontsfoldername\n";
539	}
540
541	push(@{$directorytableref}, $oneline);
542
543}
544
545###############################################
546# Creating the file Director.idt dynamically
547###############################################
548
549sub create_directory_table
550{
551	my ($directoryref, $basedir, $allvariableshashref, $shortdirnamehashref, $loggingdir) = @_;
552
553	# Structure of the directory table:
554	# Directory Directory_Parent DefaultDir
555	# Directory is a unique identifier
556	# Directory_Parent is the unique identifier of the parent
557	# DefaultDir is .:APPLIC~1|Application Data with
558	# Before ":" : [sourcedir]:[destdir] (not programmed yet)
559	# After ":" : 8+3 and not 8+3 the destination directory name
560
561	$installer::logger::Lang->add_timestamp("Performance Info: Directory Table start");
562
563	my @directorytable = ();
564	my $infoline;
565
566	overwrite_programfilesfolder($allvariableshashref);
567	if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "directoriesforidt_local_1.log", $directoryref); }
568	create_unique_directorynames($directoryref, $allvariableshashref);
569	if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "directoriesforidt_local_1a.log", $directoryref); }
570	create_defaultdir_directorynames($directoryref, $shortdirnamehashref);	# only destdir!
571	if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "directoriesforidt_local_2.log", $directoryref); }
572	set_installlocation_directory($directoryref, $allvariableshashref);
573	if ( $installer::globals::globallogging ) { installer::files::save_array_of_hashes($loggingdir . "directoriesforidt_local_3.log", $directoryref); }
574	installer::windows::idtglobal::write_idt_header(\@directorytable, "directory");
575	add_root_directories(\@directorytable, $allvariableshashref);
576	create_directorytable_from_collection(\@directorytable, $directoryref);
577
578	# Saving the file
579
580	my $directorytablename = $basedir . $installer::globals::separator . "Director.idt";
581	installer::files::save_file($directorytablename ,\@directorytable);
582    $installer::logger::Lang->printf("Created idt file: %s\n", $directorytablename);
583
584	$installer::logger::Lang->add_timestamp("Performance Info: Directory Table end");
585}
586
5871;
588