xref: /trunk/main/solenv/bin/modules/installer/windows/directory.pm (revision 747164b07d386e56c7c70a1509f0411e0c0b4d3b)
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