xref: /trunk/main/solenv/bin/modules/installer/windows/msiglobal.pm (revision 4483d2e8c50e6ab05bc9c49c7af9c6b38e11e72f)
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::msiglobal;
25
26use Cwd;
27use Digest::MD5;
28use installer::converter;
29use installer::exiter;
30use installer::files;
31use installer::globals;
32use installer::logger;
33use installer::pathanalyzer;
34use installer::remover;
35use installer::scriptitems;
36use installer::systemactions;
37use installer::worker;
38use installer::windows::idtglobal;
39use installer::windows::language;
40
41###########################################################################
42# Generating the header of the ddf file.
43# The usage of ddf files is needed, because makecab.exe can only include
44# one sourcefile into a cab file
45###########################################################################
46
47sub write_ddf_file_header
48{
49    my ($ddffileref, $cabinetfile, $installdir) = @_;
50
51    my $oneline;
52
53    $oneline = ".Set CabinetName1=" . $cabinetfile . "\n";
54    push(@{$ddffileref} ,$oneline);
55    $oneline = ".Set ReservePerCabinetSize=128\n";  # This reserves space for a digital signature.
56    push(@{$ddffileref} ,$oneline);
57    $oneline = ".Set MaxDiskSize=2147483648\n";     # This allows the .cab file to get a size of 2 GB.
58    push(@{$ddffileref} ,$oneline);
59    $oneline = ".Set CompressionType=LZX\n";
60    push(@{$ddffileref} ,$oneline);
61    $oneline = ".Set Compress=ON\n";
62    push(@{$ddffileref} ,$oneline);
63    $oneline = ".Set CompressionLevel=$installer::globals::cabfilecompressionlevel\n";
64    push(@{$ddffileref} ,$oneline);
65    $oneline = ".Set Cabinet=ON\n";
66    push(@{$ddffileref} ,$oneline);
67    $oneline = ".Set DiskDirectoryTemplate=" . $installdir . "\n";
68    push(@{$ddffileref} ,$oneline);
69}
70
71##########################################################################
72# Lines in ddf files must not contain more than 256 characters
73##########################################################################
74
75sub check_ddf_file
76{
77    my ( $ddffile, $ddffilename ) = @_;
78
79    my $maxlength = 0;
80    my $maxline = 0;
81    my $linelength = 0;
82    my $linenumber = 0;
83
84    for ( my $i = 0; $i <= $#{$ddffile}; $i++ )
85    {
86        my $oneline = ${$ddffile}[$i];
87
88        $linelength = length($oneline);
89        $linenumber = $i + 1;
90
91        if ( $linelength > 256 )
92        {
93            installer::exiter::exit_program("ERROR \"$ddffilename\" line $linenumber: Lines in ddf files must not contain more than 256 characters!", "check_ddf_file");
94        }
95
96        if ( $linelength > $maxlength )
97        {
98            $maxlength = $linelength;
99            $maxline = $linenumber;
100        }
101    }
102
103    my $infoline = "Check of ddf file \"$ddffilename\": Maximum length \"$maxlength\" in line \"$maxline\" (allowed line length: 256 characters)\n";
104    $installer::logger::Lang->print($infoline);
105}
106
107##########################################################################
108# Lines in ddf files must not be longer than 256 characters.
109# Therefore it can be useful to use relative pathes. Then it is
110# necessary to change into temp directory before calling
111# makecab.exe.
112##########################################################################
113
114sub make_relative_ddf_path
115{
116    my ( $sourcepath ) = @_;
117
118    my $windowstemppath = $installer::globals::temppath;
119
120    if ( $^O =~ /cygwin/i )
121    {
122        $windowstemppath = $installer::globals::cyg_temppath;
123    }
124
125    $sourcepath =~ s/\Q$windowstemppath\E//;
126    $sourcepath =~ s/^\\//;
127
128    return $sourcepath;
129}
130
131##########################################################################
132# Returning the order of the sequences in the files array.
133##########################################################################
134
135sub get_sequenceorder
136{
137    my ($filesref) = @_;
138
139    my %order = ();
140
141    for ( my $i = 0; $i <= $#{$filesref}; $i++ )
142    {
143        my $onefile = ${$filesref}[$i];
144        if ( ! $onefile->{'assignedsequencenumber'} ) { installer::exiter::exit_program("ERROR: No sequence number assigned to $onefile->{'gid'} ($onefile->{'uniquename'})!", "get_sequenceorder"); }
145        $order{$onefile->{'assignedsequencenumber'}} = $i;
146    }
147
148    return \%order;
149}
150
151##########################################################################
152# Generation the list, in which the source of the files is connected
153# with the cabinet destination file. Because more than one file needs
154# to be included into a cab file, this has to be done via ddf files.
155##########################################################################
156
157sub generate_cab_file_list
158{
159    my ($filesref, $installdir, $ddfdir, $allvariables) = @_;
160
161    my @cabfilelist = ();
162
163    installer::logger::include_header_into_logfile("Generating ddf files");
164
165    $installer::logger::Lang->add_timestamp("Performance Info: ddf file generation start");
166
167    if ( $^O =~ /cygwin/i ) { installer::worker::generate_cygwin_pathes($filesref); }
168
169    if ( $installer::globals::fix_number_of_cab_files )
170    {
171        for ( my $i = 0; $i <= $#{$filesref}; $i++ )
172        {
173            my $onefile = ${$filesref}[$i];
174            my $cabinetfile = $onefile->{'cabinet'};
175            my $sourcepath =  $onefile->{'sourcepath'};
176            if ( $^O =~ /cygwin/i ) { $sourcepath = $onefile->{'cyg_sourcepath'}; }
177            my $uniquename =  $onefile->{'uniquename'};
178
179            my $styles = "";
180            my $doinclude = 1;
181            if ( $onefile->{'Styles'} ) { $styles = $onefile->{'Styles'}; };
182            if ( $styles =~ /\bDONT_PACK\b/ ) { $doinclude = 0; }
183
184
185            # to avoid lines with more than 256 characters, it can be useful to use relative pathes
186            if ( $allvariables->{'RELATIVE_PATHES_IN_DDF'} ) { $sourcepath = make_relative_ddf_path($sourcepath); }
187
188            # all files with the same cabinetfile are directly behind each other in the files collector
189
190            my @ddffile = ();
191
192            write_ddf_file_header(\@ddffile, $cabinetfile, $installdir);
193
194            my $ddfline = "\"" . $sourcepath . "\"" . " " . $uniquename . "\n";
195            if ( $doinclude ) { push(@ddffile, $ddfline); }
196
197            my $nextfile = ${$filesref}[$i+1];
198            my $nextcabinetfile = "";
199
200            if ( $nextfile->{'cabinet'} ) { $nextcabinetfile = $nextfile->{'cabinet'}; }
201
202            while ( $nextcabinetfile eq $cabinetfile )
203            {
204                $sourcepath =  $nextfile->{'sourcepath'};
205                if ( $^O =~ /cygwin/i ) { $sourcepath = $nextfile->{'cyg_sourcepath'}; }
206                # to avoid lines with more than 256 characters, it can be useful to use relative pathes
207                if ( $allvariables->{'RELATIVE_PATHES_IN_DDF'} ) { $sourcepath = make_relative_ddf_path($sourcepath); }
208                $uniquename =  $nextfile->{'uniquename'};
209                my $localdoinclude = 1;
210                my $nextfilestyles = "";
211                if ( $nextfile->{'Styles'} ) { $nextfilestyles = $nextfile->{'Styles'}; }
212                if ( $nextfilestyles =~ /\bDONT_PACK\b/ ) { $localdoinclude = 0; }
213                $ddfline = "\"" . $sourcepath . "\"" . " " . $uniquename . "\n";
214                if ( $localdoinclude ) { push(@ddffile, $ddfline); }
215                $i++;                                           # increasing the counter!
216                $nextfile = ${$filesref}[$i+1];
217                if ( $nextfile ) { $nextcabinetfile = $nextfile->{'cabinet'}; }
218                else { $nextcabinetfile = "_lastfile_"; }
219            }
220
221            # creating the DDF file
222
223            my $ddffilename = $cabinetfile;
224            $ddffilename =~ s/.cab/.ddf/;
225            $ddfdir =~ s/\Q$installer::globals::separator\E\s*$//;
226            $ddffilename = $ddfdir . $installer::globals::separator . $ddffilename;
227
228            installer::files::save_file($ddffilename ,\@ddffile);
229            my $infoline = "Created ddf file: $ddffilename\n";
230            $installer::logger::Lang->print($infoline);
231
232            # lines in ddf files must not be longer than 256 characters
233            check_ddf_file(\@ddffile, $ddffilename);
234
235            # Writing the makecab system call
236
237            my $oneline = "makecab.exe /V3 /F " . $ddffilename . " 2\>\&1 |" . "\n";
238
239            push(@cabfilelist, $oneline);
240
241            # collecting all ddf files
242            push(@installer::globals::allddffiles, $ddffilename);
243        }
244    }
245    elsif ( $installer::globals::one_cab_file )
246    {
247        my @ddffile = ();
248
249        my $cabinetfile = "";
250
251        for ( my $i = 0; $i <= $#{$filesref}; $i++ )
252        {
253            my $onefile = ${$filesref}[$i];
254            $cabinetfile = $onefile->{'cabinet'};
255            my $sourcepath =  $onefile->{'sourcepath'};
256            if ( $^O =~ /cygwin/i ) { $sourcepath = $onefile->{'cyg_sourcepath'}; }
257            my $uniquename =  $onefile->{'uniquename'};
258
259            # to avoid lines with more than 256 characters, it can be useful to use relative pathes
260            if ( $allvariables->{'RELATIVE_PATHES_IN_DDF'} ) { $sourcepath = make_relative_ddf_path($sourcepath); }
261
262            if ( $i == 0 ) { write_ddf_file_header(\@ddffile, $cabinetfile, $installdir); }
263
264            my $styles = "";
265            my $doinclude = 1;
266            if ( $onefile->{'Styles'} ) { $styles = $onefile->{'Styles'}; };
267            if ( $styles =~ /\bDONT_PACK\b/ ) { $doinclude = 0; }
268
269            my $ddfline = "\"" . $sourcepath . "\"" . " " . $uniquename . "\n";
270            if ( $doinclude ) { push(@ddffile, $ddfline); }
271        }
272
273        # creating the DDF file
274
275        my $ddffilename = $cabinetfile;
276        $ddffilename =~ s/.cab/.ddf/;
277        $ddfdir =~ s/[\/\\]\s*$//;
278        $ddffilename = $ddfdir . $installer::globals::separator . $ddffilename;
279
280        installer::files::save_file($ddffilename ,\@ddffile);
281        my $infoline = "Created ddf file: $ddffilename\n";
282        $installer::logger::Lang->print($infoline);
283
284        # lines in ddf files must not be longer than 256 characters
285        check_ddf_file(\@ddffile, $ddffilename);
286
287        # Writing the makecab system call
288
289        my $oneline = "makecab.exe /F " . $ddffilename . "\n";
290
291        push(@cabfilelist, $oneline);
292
293        # collecting all ddf files
294        push(@installer::globals::allddffiles, $ddffilename);
295    }
296    else
297    {
298        installer::exiter::exit_program("ERROR: No cab file specification in globals.pm !", "create_media_table");
299    }
300
301    $installer::logger::Lang->add_timestamp("Performance Info: ddf file generation end");
302
303    return \@cabfilelist;   # contains all system calls for packaging process
304}
305
306########################################################################
307# Returning the file sequence of a specified file.
308########################################################################
309
310sub get_file_sequence
311{
312    my ($filesref, $uniquefilename) = @_;
313
314    my $sequence = "";
315    my $found_sequence = 0;
316
317    for ( my $i = 0; $i <= $#{$filesref}; $i++ )
318    {
319        my $onefile = ${$filesref}[$i];
320        my $uniquename = $onefile->{'uniquename'};
321
322        if ( $uniquename eq $uniquefilename )
323        {
324            $sequence = $onefile->{'sequencenumber'};
325            $found_sequence = 1;
326            last;
327        }
328    }
329
330    if ( ! $found_sequence ) { installer::exiter::exit_program("ERROR: No sequence found for $uniquefilename !", "get_file_sequence"); }
331
332    return $sequence;
333}
334
335########################################################################
336# For update and patch reasons the pack order needs to be saved.
337# The pack order is saved in the ddf files; the names and locations
338# of the ddf files are saved in @installer::globals::allddffiles.
339# The outputfile "packorder.txt" can be saved in
340# $installer::globals::infodirectory .
341########################################################################
342
343sub save_packorder
344{
345    installer::logger::include_header_into_logfile("Saving pack order");
346
347    $installer::logger::Lang->add_timestamp("Performance Info: saving pack order start");
348
349    my $packorderfilename = "packorder.txt";
350    $packorderfilename = $installer::globals::infodirectory . $installer::globals::separator . $packorderfilename;
351
352    my @packorder = ();
353
354    my $headerline = "\# Syntax\: Filetable_Sequence Cabinetfilename Physical_FileName Unique_FileName\n\n";
355    push(@packorder, $headerline);
356
357    for ( my $i = 0; $i <= $#installer::globals::allddffiles; $i++ )
358    {
359        my $ddffilename = $installer::globals::allddffiles[$i];
360        my $ddffile = installer::files::read_file($ddffilename);
361        my $cabinetfile = "";
362
363        for ( my $j = 0; $j <= $#{$ddffile}; $j++ )
364        {
365            my $oneline = ${$ddffile}[$j];
366
367            # Getting the Cabinet file name
368
369            if ( $oneline =~ /^\s*\.Set\s+CabinetName.*\=(.*?)\s*$/ ) { $cabinetfile = $1; }
370            if ( $oneline =~ /^\s*\.Set\s+/ ) { next; }
371
372            if ( $oneline =~ /^\s*\"(.*?)\"\s+(.*?)\s*$/ )
373            {
374                my $sourcefile = $1;
375                my $uniquefilename = $2;
376
377                installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$sourcefile);
378
379                # Using the hash created in create_files_table for performance reasons to get the sequence number
380                my $filesequence = "";
381                if ( exists($installer::globals::uniquefilenamesequence{$uniquefilename}) ) { $filesequence = $installer::globals::uniquefilenamesequence{$uniquefilename}; }
382                else { installer::exiter::exit_program("ERROR: No sequence number value for $uniquefilename !", "save_packorder"); }
383
384                my $line = $filesequence . "\t" . $cabinetfile . "\t" . $sourcefile . "\t" . $uniquefilename . "\n";
385                push(@packorder, $line);
386            }
387        }
388    }
389
390    installer::files::save_file($packorderfilename ,\@packorder);
391
392    $installer::logger::Lang->add_timestamp("Performance Info: saving pack order end");
393}
394
395#################################################################
396# Returning the name of the msi database
397#################################################################
398
399sub get_msidatabasename
400{
401    my ($allvariableshashref, $language) = @_;
402
403    my $databasename = $allvariableshashref->{'PRODUCTNAME'} . $allvariableshashref->{'PRODUCTVERSION'};
404    $databasename = lc($databasename);
405    $databasename =~ s/\.//g;
406    $databasename =~ s/\-//g;
407    $databasename =~ s/\s//g;
408
409    # possibility to overwrite the name with variable DATABASENAME
410    if ( $allvariableshashref->{'DATABASENAME'} )
411    {
412        $databasename = $allvariableshashref->{'DATABASENAME'};
413    }
414
415    if ( $language )
416    {
417        if (!($language eq ""))
418        {
419            $databasename .= "_$language";
420        }
421    }
422
423    $databasename .= ".msi";
424
425    return $databasename;
426}
427
428#################################################################
429# Creating the msi database
430# This works only on Windows
431#################################################################
432
433sub create_msi_database
434{
435    my ($idtdirbase ,$msifilename) = @_;
436
437    # -f : path containing the idt files
438    # -d : msi database, including path
439    # -c : create database
440    # -i : include the following tables ("*" includes all available tables)
441
442    my $msidb = "msidb.exe";    # Has to be in the path
443    my $extraslash = "";        # Has to be set for non-ActiveState perl
444
445    installer::logger::include_header_into_logfile("Creating msi database");
446
447    $idtdirbase = installer::converter::make_path_conform($idtdirbase);
448
449    $msifilename = installer::converter::make_path_conform($msifilename);
450
451    if ( $^O =~ /cygwin/i ) {
452        # msidb.exe really wants backslashes. (And double escaping because system() expands the string.)
453        $idtdirbase =~ s/\//\\\\/g;
454        $msifilename =~ s/\//\\\\/g;
455        $extraslash = "\\";
456    }
457    my $systemcall = $msidb . " -f " . $idtdirbase . " -d " . $msifilename . " -c " . "-i " . $extraslash . "*";
458
459    my $returnvalue = system($systemcall);
460
461    my $infoline = "Systemcall: $systemcall\n";
462    $installer::logger::Lang->print($infoline);
463
464    if ($returnvalue)
465    {
466        $infoline = "ERROR: Could not execute $msidb!\n";
467        $installer::logger::Lang->print($infoline);
468    }
469    else
470    {
471        $infoline = "Success: Executed $msidb successfully!\n";
472        $installer::logger::Lang->print($infoline);
473    }
474}
475
476#####################################################################
477# Returning the value from sis.mlf for Summary Information Stream
478#####################################################################
479
480sub get_value_from_sis_lng
481{
482    my ($language, $languagefile, $searchstring) = @_;
483
484    my $language_block = installer::windows::idtglobal::get_language_block_from_language_file($searchstring, $languagefile);
485    my $newstring = installer::windows::idtglobal::get_language_string_from_language_block($language_block, $language, $searchstring);
486    $newstring = "\"" . $newstring . "\"";
487
488    return $newstring;
489}
490
491#################################################################
492# Returning the msi version for the Summary Information Stream
493#################################################################
494
495sub get_msiversion_for_sis
496{
497    my $msiversion = "200";
498    return $msiversion;
499}
500
501#################################################################
502# Returning the word count for the Summary Information Stream
503#################################################################
504
505sub get_wordcount_for_sis
506{
507    my $wordcount = "0";
508    return $wordcount;
509}
510
511#################################################################
512# Returning the codepage for the Summary Information Stream
513#################################################################
514
515sub get_codepage_for_sis
516{
517    my ( $language ) = @_;
518
519    my $codepage = installer::windows::language::get_windows_encoding($language);
520
521    # Codepage 65001 does not work in Summary Information Stream
522    if ( $codepage == 65001 ) { $codepage = 0; }
523
524    # my $codepage = "1252";    # determine dynamically in a function
525    # my $codepage = "65001";       # UTF-8
526    return $codepage;
527}
528
529#################################################################
530# Returning the template for the Summary Information Stream
531#################################################################
532
533sub get_template_for_sis
534{
535    my ( $language, $allvariables ) = @_;
536
537    my $windowslanguage = installer::windows::language::get_windows_language($language);
538
539    my $architecture = "Intel";
540
541    # Adding 256, if this is a 64 bit installation set.
542    if (( $allvariables->{'64BITPRODUCT'} ) && ( $allvariables->{'64BITPRODUCT'} == 1 )) { $architecture = "x64"; }
543
544    my $value = "\"" . $architecture . ";" . $windowslanguage;  # adding the Windows language
545
546    $value = $value . "\"";                     # adding ending '"'
547
548    return $value ;
549}
550
551#################################################################
552# Returning the PackageCode for the Summary Information Stream
553#################################################################
554
555sub get_packagecode_for_sis
556{
557    # always generating a new package code for each package
558
559    my $guidref = get_guid_list(1, 1);  # only one GUID shall be generated
560
561    ${$guidref}[0] =~ s/\s*$//;     # removing ending spaces
562
563    my $guid = "\{" . ${$guidref}[0] . "\}";
564
565    my $infoline = "PackageCode: $guid\n";
566    $installer::logger::Lang->print($infoline);
567
568    return $guid;
569}
570
571#################################################################
572# Returning the title for the Summary Information Stream
573#################################################################
574
575sub get_title_for_sis
576{
577    my ( $language, $languagefile, $searchstring ) = @_;
578
579    my $title = get_value_from_sis_lng($language, $languagefile, $searchstring );
580
581    return $title;
582}
583
584#################################################################
585# Returning the author for the Summary Information Stream
586#################################################################
587
588sub get_author_for_sis
589{
590    my $author = $installer::globals::longmanufacturer;
591
592    $author = "\"" . $author . "\"";
593
594    return $author;
595}
596
597#################################################################
598# Returning the subject for the Summary Information Stream
599#################################################################
600
601sub get_subject_for_sis
602{
603    my ( $allvariableshashref ) = @_;
604
605    my $subject = $allvariableshashref->{'PRODUCTNAME'} . " " . $allvariableshashref->{'PRODUCTVERSION'};
606
607    $subject = "\"" . $subject . "\"";
608
609    return $subject;
610}
611
612#################################################################
613# Returning the comment for the Summary Information Stream
614#################################################################
615
616sub get_comment_for_sis
617{
618    my ( $language, $languagefile, $searchstring ) = @_;
619
620    my $comment = get_value_from_sis_lng($language, $languagefile, $searchstring );
621
622    return $comment;
623}
624
625#################################################################
626# Returning the keywords for the Summary Information Stream
627#################################################################
628
629sub get_keywords_for_sis
630{
631    my ( $language, $languagefile, $searchstring ) = @_;
632
633    my $keywords = get_value_from_sis_lng($language, $languagefile, $searchstring );
634
635    return $keywords;
636}
637
638######################################################################
639# Returning the application name for the Summary Information Stream
640######################################################################
641
642sub get_appname_for_sis
643{
644    my ( $language, $languagefile, $searchstring ) = @_;
645
646    my $appname = get_value_from_sis_lng($language, $languagefile, $searchstring );
647
648    return $appname;
649}
650
651######################################################################
652# Returning the security for the Summary Information Stream
653######################################################################
654
655sub get_security_for_sis
656{
657    my $security = "0";
658    return $security;
659}
660
661#################################################################
662# Writing the Summary information stream into the msi database
663# This works only on Windows
664#################################################################
665
666sub write_summary_into_msi_database
667{
668    my ($msifilename, $language, $languagefile, $allvariableshashref) = @_;
669
670    # -g : requrired msi version
671    # -c : codepage
672    # -p : template
673
674    installer::logger::include_header_into_logfile("Writing summary information stream");
675
676    my $msiinfo = "msiinfo.exe";    # Has to be in the path
677
678    my $sislanguage = "en-US";  # title, comment, keyword and appname alway in english
679
680    my $msiversion = get_msiversion_for_sis();
681    my $codepage = get_codepage_for_sis($language);
682    my $template = get_template_for_sis($language, $allvariableshashref);
683    my $guid = get_packagecode_for_sis();
684    my $title = get_title_for_sis($sislanguage,$languagefile, "OOO_SIS_TITLE");
685    my $author = get_author_for_sis();
686    my $subject = get_subject_for_sis($allvariableshashref);
687    my $comment = get_comment_for_sis($sislanguage,$languagefile, "OOO_SIS_COMMENT");
688    my $keywords = get_keywords_for_sis($sislanguage,$languagefile, "OOO_SIS_KEYWORDS");
689    my $appname = get_appname_for_sis($sislanguage,$languagefile, "OOO_SIS_APPNAME");
690    my $security = get_security_for_sis();
691    my $wordcount = get_wordcount_for_sis();
692
693    $msifilename = installer::converter::make_path_conform($msifilename);
694
695    my $systemcall = $msiinfo . " " . $msifilename . " -g " . $msiversion . " -c " . $codepage
696                    . " -p " . $template . " -v " . $guid . " -t " . $title . " -a " . $author
697                    . " -j " . $subject . " -o " . $comment . " -k " . $keywords . " -n " . $appname
698                    . " -u " . $security . " -w " . $wordcount;
699
700    my $returnvalue = system($systemcall);
701
702    my $infoline = "Systemcall: $systemcall\n";
703    $installer::logger::Lang->print($infoline);
704
705    if ($returnvalue)
706    {
707        $infoline = "ERROR: Could not execute $msiinfo!\n";
708        $installer::logger::Lang->print($infoline);
709    }
710    else
711    {
712        $infoline = "Success: Executed $msiinfo successfully!\n";
713        $installer::logger::Lang->print($infoline);
714    }
715}
716
717#########################################################################
718# For more than one language in the installation set:
719# Use one database and create Transformations for all other languages
720#########################################################################
721
722sub create_transforms
723{
724    my ($languagesarray, $defaultlanguage, $installdir, $allvariableshashref) = @_;
725
726    installer::logger::include_header_into_logfile("Creating Transforms");
727
728    my $msitran = "msitran.exe";    # Has to be in the path
729
730    $installdir = installer::converter::make_path_conform($installdir);
731
732    # Syntax for creating a transformation
733    # msitran.exe -g <baseDB> <referenceDB> <transformfile> [<errorhandling>}
734
735    my $basedbname = get_msidatabasename($allvariableshashref, $defaultlanguage);
736    $basedbname = $installdir . $installer::globals::separator . $basedbname;
737
738    my $errorhandling = "f";    # Suppress "change codepage" error
739
740    # Iterating over all files
741
742    foreach ( @{$languagesarray} )
743    {
744        my $onelanguage = $_;
745
746        if ( $onelanguage eq $defaultlanguage ) { next; }
747
748        my $referencedbname = get_msidatabasename($allvariableshashref, $onelanguage);
749        $referencedbname = $installdir . $installer::globals::separator . $referencedbname;
750
751        my $transformfile = $installdir . $installer::globals::separator . "trans_" . $onelanguage . ".mst";
752
753        my $systemcall = $msitran . " " . " -g " . $basedbname . " " . $referencedbname . " " . $transformfile . " " . $errorhandling;
754
755        my $returnvalue = system($systemcall);
756
757        my $infoline = "Systemcall: $systemcall\n";
758        $installer::logger::Lang->print($infoline);
759
760        # Problem: msitran.exe in version 4.0 always returns "1", even if no failure occured.
761        # Therefore it has to be checked, if this is version 4.0. If yes, if the mst file
762        # exists and if it is larger than 0 bytes. If this is true, then no error occured.
763        # File Version of msitran.exe: 4.0.6000.16384 has checksum: "b66190a70145a57773ec769e16777b29".
764        # Same for msitran.exe from wntmsci12: "aa25d3445b94ffde8ef0c1efb77a56b8"
765
766        if ($returnvalue)
767        {
768            $infoline = "WARNING: Returnvalue of $msitran is not 0. Checking version of $msitran!\n";
769            $installer::logger::Lang->print($infoline);
770
771            open(FILE, "<$installer::globals::msitranpath") or die "ERROR: Can't open $installer::globals::msitranpath for creating file hash";
772            binmode(FILE);
773            my $digest = Digest::MD5->new->addfile(*FILE)->hexdigest;
774            close(FILE);
775
776            my @problemchecksums = ("b66190a70145a57773ec769e16777b29", "aa25d3445b94ffde8ef0c1efb77a56b8");
777            my $isproblemchecksum = 0;
778
779            foreach my $problemchecksum ( @problemchecksums )
780            {
781                $infoline = "Checksum of problematic MsiTran.exe: $problemchecksum\n";
782                $installer::logger::Lang->print($infoline);
783                $infoline = "Checksum of used MsiTran.exe: $digest\n";
784                $installer::logger::Lang->print($infoline);
785                if ( $digest eq $problemchecksum ) { $isproblemchecksum = 1; }
786            }
787
788            if ( $isproblemchecksum )
789            {
790                # Check existence of mst
791                if ( -f $transformfile )
792                {
793                    $infoline = "File $transformfile exists.\n";
794                    $installer::logger::Lang->print($infoline);
795                    my $filesize = ( -s $transformfile );
796                    $infoline = "Size of $transformfile: $filesize\n";
797                    $installer::logger::Lang->print($infoline);
798
799                    if ( $filesize > 0 )
800                    {
801                        $infoline = "Info: Returnvalue $returnvalue of $msitran is no problem :-) .\n";
802                        $installer::logger::Lang->print($infoline);
803                        $returnvalue = 0; # reset the error
804                    }
805                    else
806                    {
807                        $infoline = "Filesize indicates that an error occured.\n";
808                        $installer::logger::Lang->print($infoline);
809                    }
810                }
811                else
812                {
813                    $infoline = "File $transformfile does not exist -> An error occured.\n";
814                    $installer::logger::Lang->print($infoline);
815                }
816            }
817            else
818            {
819                $infoline = "This is not a problematic version of msitran.exe. Therefore the error is not caused by problematic msitran.exe.\n";
820                $installer::logger::Lang->print($infoline);
821            }
822        }
823
824        if ($returnvalue)
825        {
826            $infoline = "ERROR: Could not execute $msitran!\n";
827            $installer::logger::Lang->print($infoline);
828        }
829        else
830        {
831            $infoline = "Success: Executed $msitran successfully!\n";
832            $installer::logger::Lang->print($infoline);
833        }
834
835        # The reference database can be deleted
836
837        my $result = unlink($referencedbname);
838        # $result contains the number of deleted files
839
840        if ( $result == 0 )
841        {
842            $infoline = "ERROR: Could not remove file $$referencedbname !\n";
843            $installer::logger::Lang->print($infoline);
844            installer::exiter::exit_program($infoline, "create_transforms");
845        }
846    }
847}
848
849#########################################################################
850# The default language msi database does not need to contain
851# the language in the database name. Therefore the file
852# is renamed. Example: "openofficeorg20_01.msi" to "openofficeorg20.msi"
853#########################################################################
854
855sub rename_msi_database_in_installset
856{
857    my ($defaultlanguage, $installdir, $allvariableshashref) = @_;
858
859    installer::logger::include_header_into_logfile("Renaming msi database");
860
861    my $olddatabasename = get_msidatabasename($allvariableshashref, $defaultlanguage);
862    $olddatabasename = $installdir . $installer::globals::separator . $olddatabasename;
863
864    my $newdatabasename = get_msidatabasename($allvariableshashref);
865
866    $installer::globals::shortmsidatabasename = $newdatabasename;
867
868    $newdatabasename = $installdir . $installer::globals::separator . $newdatabasename;
869
870    installer::systemactions::rename_one_file($olddatabasename, $newdatabasename);
871
872    $installer::globals::msidatabasename = $newdatabasename;
873}
874
875#########################################################################
876# Adding the language to the name of the msi databasename,
877# if this is required (ADDLANGUAGEINDATABASENAME)
878#########################################################################
879
880sub add_language_to_msi_database
881{
882    my ($defaultlanguage, $installdir, $allvariables) = @_;
883
884    my $languagestring = $defaultlanguage;
885    if ( $allvariables->{'USELANGUAGECODE'} ) { $languagestring = installer::windows::language::get_windows_language($defaultlanguage); }
886    my $newdatabasename = $installer::globals::shortmsidatabasename;
887    $newdatabasename =~ s/\.msi\s*$/_$languagestring\.msi/;
888    $installer::globals::shortmsidatabasename = $newdatabasename;
889    $newdatabasename = $installdir . $installer::globals::separator . $newdatabasename;
890
891    my $olddatabasename = $installer::globals::msidatabasename;
892
893    installer::systemactions::rename_one_file($olddatabasename, $newdatabasename);
894
895    $installer::globals::msidatabasename = $newdatabasename;
896}
897
898##########################################################################
899# Writing the databasename into the setup.ini.
900##########################################################################
901
902sub put_databasename_into_setupini
903{
904    my ($setupinifile, $allvariableshashref) = @_;
905
906    my $databasename = get_msidatabasename($allvariableshashref);
907    my $line = "database=" . $databasename . "\n";
908
909    push(@{$setupinifile}, $line);
910}
911
912##########################################################################
913# Writing the required msi version into setup.ini
914##########################################################################
915
916sub put_msiversion_into_setupini
917{
918    my ($setupinifile) = @_;
919
920    my $msiversion = "2.0";
921    my $line = "msiversion=" . $msiversion . "\n";
922
923    push(@{$setupinifile}, $line);
924}
925
926##########################################################################
927# Writing the productname into setup.ini
928##########################################################################
929
930sub put_productname_into_setupini
931{
932    my ($setupinifile, $allvariableshashref) = @_;
933
934    my $productname = $allvariableshashref->{'PRODUCTNAME'};
935    my $line = "productname=" . $productname . "\n";
936
937    push(@{$setupinifile}, $line);
938}
939
940##########################################################################
941# Writing the productcode into setup.ini
942##########################################################################
943
944sub put_productcode_into_setupini
945{
946    my ($setupinifile) = @_;
947
948    my $productcode = $installer::globals::productcode;
949    my $line = "productcode=" . $productcode . "\n";
950
951    push(@{$setupinifile}, $line);
952}
953
954##########################################################################
955# Writing the ProductVersion from Property table into setup.ini
956##########################################################################
957
958sub put_productversion_into_setupini
959{
960    my ($setupinifile) = @_;
961
962    my $line = "productversion=" . $installer::globals::msiproductversion . "\n";
963    push(@{$setupinifile}, $line);
964}
965
966##########################################################################
967# Writing the key for Minor Upgrades into setup.ini
968##########################################################################
969
970sub put_upgradekey_into_setupini
971{
972    my ($setupinifile) = @_;
973
974    if ( $installer::globals::minorupgradekey ne "" )
975    {
976        my $line = "upgradekey=" . $installer::globals::minorupgradekey . "\n";
977        push(@{$setupinifile}, $line);
978    }
979}
980
981##########################################################################
982# Writing the number of languages into setup.ini
983##########################################################################
984
985sub put_languagecount_into_setupini
986{
987    my ($setupinifile, $languagesarray) = @_;
988
989    my $languagecount = $#{$languagesarray} + 1;
990    my $line = "count=" . $languagecount . "\n";
991
992    push(@{$setupinifile}, $line);
993}
994
995##########################################################################
996# Writing the defaultlanguage into setup.ini
997##########################################################################
998
999sub put_defaultlanguage_into_setupini
1000{
1001    my ($setupinifile, $defaultlanguage) = @_;
1002
1003    my $windowslanguage = installer::windows::language::get_windows_language($defaultlanguage);
1004    my $line = "default=" . $windowslanguage . "\n";
1005    push(@{$setupinifile}, $line);
1006}
1007
1008##########################################################################
1009# Writing the information about transformations into setup.ini
1010##########################################################################
1011
1012sub put_transforms_into_setupini
1013{
1014    my ($setupinifile, $onelanguage, $counter) = @_;
1015
1016    my $windowslanguage = installer::windows::language::get_windows_language($onelanguage);
1017    my $transformfilename = "trans_" . $onelanguage . ".mst";
1018
1019    my $line = "lang" . $counter . "=" . $windowslanguage . "," . $transformfilename . "\n";
1020
1021    push(@{$setupinifile}, $line);
1022}
1023
1024###################################################
1025# Including Windows line ends in ini files
1026# Profiles on Windows shall have \r\n line ends
1027###################################################
1028
1029sub include_windows_lineends
1030{
1031    my ($onefile) = @_;
1032
1033    for ( my $i = 0; $i <= $#{$onefile}; $i++ )
1034    {
1035        ${$onefile}[$i] =~ s/\r?\n$/\r\n/;
1036    }
1037}
1038
1039##########################################################################
1040# Generation the file setup.ini, that is used by the loader setup.exe.
1041##########################################################################
1042
1043sub create_setup_ini
1044{
1045    my ($languagesarray, $defaultlanguage, $installdir, $allvariableshashref) = @_;
1046
1047    installer::logger::include_header_into_logfile("Creating setup.ini");
1048
1049    my $setupinifilename = $installdir . $installer::globals::separator . "setup.ini";
1050
1051    my @setupinifile = ();
1052    my $setupinifile = \@setupinifile;
1053
1054    my $line = "\[setup\]\n";
1055    push(@setupinifile, $line);
1056
1057    put_databasename_into_setupini($setupinifile, $allvariableshashref);
1058    put_msiversion_into_setupini($setupinifile);
1059    put_productname_into_setupini($setupinifile, $allvariableshashref);
1060    put_productcode_into_setupini($setupinifile);
1061    put_productversion_into_setupini($setupinifile);
1062    put_upgradekey_into_setupini($setupinifile);
1063
1064    $line = "\[languages\]\n";
1065    push(@setupinifile, $line);
1066
1067    put_languagecount_into_setupini($setupinifile, $languagesarray);
1068    put_defaultlanguage_into_setupini($setupinifile, $defaultlanguage);
1069
1070    if ( $#{$languagesarray} > 0 )  # writing the transforms information
1071    {
1072        my $counter = 1;
1073
1074        for ( my $i = 0; $i <= $#{$languagesarray}; $i++ )
1075        {
1076            if ( ${$languagesarray}[$i] eq $defaultlanguage ) { next; }
1077
1078            put_transforms_into_setupini($setupinifile, ${$languagesarray}[$i], $counter);
1079            $counter++;
1080        }
1081    }
1082
1083    if ( $installer::globals::iswin && $installer::globals::plat =~ /cygwin/i)      # Windows line ends only for Cygwin
1084    {
1085        include_windows_lineends($setupinifile);
1086    }
1087
1088    installer::files::save_file($setupinifilename, $setupinifile);
1089
1090    $infoline = "Generated file $setupinifilename !\n";
1091    $installer::logger::Lang->print($infoline);
1092}
1093
1094#################################################################
1095# Copying the files defined as ScpActions into the
1096# installation set.
1097#################################################################
1098
1099sub copy_scpactions_into_installset
1100{
1101    my ($defaultlanguage, $installdir, $allscpactions) = @_;
1102
1103    installer::logger::include_header_into_logfile("Copying ScpAction files into installation set");
1104
1105    for ( my $i = 0; $i <= $#{$allscpactions}; $i++ )
1106    {
1107        my $onescpaction = ${$allscpactions}[$i];
1108
1109        if ( $onescpaction->{'Name'} eq "loader.exe" ) { next; }    # do not copy this ScpAction loader
1110
1111        # only copying language independent files or files with the correct language (the defaultlanguage)
1112
1113        my $filelanguage = $onescpaction->{'specificlanguage'};
1114
1115        if ( ($filelanguage eq $defaultlanguage) || ($filelanguage eq "") )
1116        {
1117            my $sourcefile = $onescpaction->{'sourcepath'};
1118            my $destfile = $installdir . $installer::globals::separator . $onescpaction->{'DestinationName'};
1119
1120            installer::systemactions::copy_one_file($sourcefile, $destfile);
1121        }
1122    }
1123}
1124
1125#################################################################
1126# Copying the files for the Windows installer into the
1127# installation set (setup.exe).
1128#################################################################
1129
1130sub copy_windows_installer_files_into_installset
1131{
1132    my ($installdir, $includepatharrayref, $allvariables) = @_;
1133
1134    installer::logger::include_header_into_logfile("Copying Windows installer files into installation set");
1135
1136    @copyfile = ();
1137    push(@copyfile, "loader2.exe");
1138
1139    if ( $allvariables->{'NOLOADERREQUIRED'} ) { @copyfile = (); }
1140
1141    for ( my $i = 0; $i <= $#copyfile; $i++ )
1142    {
1143        my $filename = $copyfile[$i];
1144        my $sourcefileref = installer::scriptitems::get_sourcepath_from_filename_and_includepath(\$filename, $includepatharrayref, 1);
1145
1146        if ( ! -f $$sourcefileref ) { installer::exiter::exit_program("ERROR: msi file not found: $$sourcefileref !", "copy_windows_installer_files_into_installset"); }
1147
1148        my $destfile;
1149        if ( $copyfile[$i] eq "loader2.exe" ) { $destfile = "setup.exe"; }  # renaming the loader
1150        else { $destfile = $copyfile[$i]; }
1151
1152        $destfile = $installdir . $installer::globals::separator . $destfile;
1153
1154        installer::systemactions::copy_one_file($$sourcefileref, $destfile);
1155    }
1156}
1157
1158#################################################################
1159# Copying the child projects into the
1160# installation set
1161#################################################################
1162
1163sub copy_child_projects_into_installset
1164{
1165    my ($installdir, $allvariables) = @_;
1166
1167    my $sourcefile = "";
1168    my $destdir = "";
1169
1170    # adding Java
1171
1172    if ( $allvariables->{'JAVAPRODUCT'} )
1173    {
1174        $sourcefile = $installer::globals::javafile->{'sourcepath'};
1175        $destdir = $installdir . $installer::globals::separator . $installer::globals::javafile->{'Subdir'};
1176        if ( ! -d $destdir) { installer::systemactions::create_directory($destdir); }
1177        installer::systemactions::copy_one_file($sourcefile, $destdir);
1178    }
1179
1180    if ( $allvariables->{'UREPRODUCT'} )
1181    {
1182        $sourcefile = $installer::globals::urefile->{'sourcepath'};
1183        $destdir = $installdir . $installer::globals::separator . $installer::globals::urefile->{'Subdir'};
1184        if ( ! -d $destdir) { installer::systemactions::create_directory($destdir); }
1185        installer::systemactions::copy_one_file($sourcefile, $destdir);
1186    }
1187}
1188
1189#################################################################
1190# Getting a list of GUID using uuidgen.exe.
1191# This works only on Windows
1192#################################################################
1193
1194sub get_guid_list
1195{
1196    my ($number, $log) = @_;
1197
1198    if ( $log ) { installer::logger::include_header_into_logfile("Generating $number GUID"); }
1199
1200    my $uuidgen = "uuidgen.exe";        # Has to be in the path
1201
1202    # "-c" for uppercase output
1203
1204    # my $systemcall = "$uuidgen -n$number -c |";
1205    my $systemcall = "$uuidgen -n$number |";
1206    open (UUIDGEN, "$systemcall" ) or die("uuidgen is missing.");
1207    my @uuidlist = <UUIDGEN>;
1208    close (UUIDGEN);
1209
1210    my $infoline = "Systemcall: $systemcall\n";
1211    if ( $log ) { $installer::logger::Lang->print($infoline); }
1212
1213    my $comparenumber = $#uuidlist + 1;
1214
1215    if ( $comparenumber == $number )
1216    {
1217        $infoline = "Success: Executed $uuidgen successfully!\n";
1218        if ( $log ) { $installer::logger::Lang->print($infoline); }
1219    }
1220    else
1221    {
1222        $infoline = "ERROR: Could not execute $uuidgen successfully!\n";
1223        if ( $log ) { $installer::logger::Lang->print($infoline); }
1224    }
1225
1226    # uppercase, no longer "-c", because this is only supported in uuidgen.exe v.1.01
1227    for ( my $i = 0; $i <= $#uuidlist; $i++ ) { $uuidlist[$i] = uc($uuidlist[$i]); }
1228
1229    return \@uuidlist;
1230}
1231
1232#################################################################
1233# Calculating a GUID with a string using md5.
1234#################################################################
1235
1236sub calculate_guid
1237{
1238    my ( $string ) = @_;
1239
1240    my $guid = "";
1241
1242    my $md5 = Digest::MD5->new;
1243    $md5->add($string);
1244    my $digest = $md5->hexdigest;
1245    $digest = uc($digest);
1246
1247    # my $id = pack("A32", $digest);
1248    my ($first, $second, $third, $fourth, $fifth) = unpack ('A8 A4 A4 A4 A12', $digest);
1249    $guid = "$first-$second-$third-$fourth-$fifth";
1250
1251    return $guid;
1252}
1253
1254#################################################################
1255# Calculating a ID with a string using md5 (very fast).
1256#################################################################
1257
1258sub calculate_id
1259{
1260    my ( $string, $length ) = @_;
1261
1262    my $id = "";
1263
1264    my $md5 = Digest::MD5->new;
1265    $md5->add($string);
1266    my $digest = lc($md5->hexdigest);
1267    $id = substr($digest, 0, $length);
1268
1269    return $id;
1270}
1271
1272#################################################################
1273# Filling the component hash with the values of the
1274# component file.
1275#################################################################
1276
1277sub fill_component_hash
1278{
1279    my ($componentfile) = @_;
1280
1281    my %components = ();
1282
1283    for ( my $i = 0; $i <= $#{$componentfile}; $i++ )
1284    {
1285        my $line = ${$componentfile}[$i];
1286
1287        if ( $line =~ /^\s*(.*?)\t(.*?)\s*$/ )
1288        {
1289            my $key = $1;
1290            my $value = $2;
1291
1292            $components{$key} = $value;
1293        }
1294    }
1295
1296    return \%components;
1297}
1298
1299#################################################################
1300# Creating a new component file, if new guids were generated.
1301#################################################################
1302
1303sub create_new_component_file
1304{
1305    my ($componenthash) = @_;
1306
1307    my @componentfile = ();
1308
1309    my $key;
1310
1311    foreach $key (keys %{$componenthash})
1312    {
1313        my $value = $componenthash->{$key};
1314        my $input = "$key\t$value\n";
1315        push(@componentfile ,$input);
1316    }
1317
1318    return \@componentfile;
1319}
1320
1321#################################################################
1322# Filling real component GUID into the component table.
1323# This works only on Windows
1324#################################################################
1325
1326sub set_uuid_into_component_table
1327{
1328    my ($idtdirbase, $allvariables) = @_;
1329
1330    my $componenttablename  = $idtdirbase . $installer::globals::separator . "Componen.idt";
1331
1332    my $componenttable = installer::files::read_file($componenttablename);
1333
1334    # For update and patch reasons (small update) the GUID of an existing component must not change!
1335    # The collection of component GUIDs is saved in the directory $installer::globals::idttemplatepath in the file "components.txt"
1336
1337    my $infoline = "";
1338    my $counter = 0;
1339    # my $componentfile = installer::files::read_file($installer::globals::componentfilename);
1340    # my $componenthash = fill_component_hash($componentfile);
1341
1342    for ( my $i = 3; $i <= $#{$componenttable}; $i++ )  # ignoring the first three lines
1343    {
1344        my $oneline = ${$componenttable}[$i];
1345        my $componentname = "";
1346        if ( $oneline =~ /^\s*(\S+?)\t/ ) { $componentname = $1; }
1347
1348        my $uuid = "";
1349
1350    #   if ( $componenthash->{$componentname} )
1351    #   {
1352    #       $uuid = $componenthash->{$componentname};
1353    #   }
1354    #   else
1355    #   {
1356
1357            if ( exists($installer::globals::calculated_component_guids{$componentname}))
1358            {
1359                $uuid = $installer::globals::calculated_component_guids{$componentname};
1360            }
1361            else
1362            {
1363                # Calculating new GUID with the help of the component name.
1364                my $useooobaseversion = 1;
1365                if ( exists($installer::globals::base_independent_components{$componentname})) { $useooobaseversion = 0; }
1366                my $sourcestring = $componentname;
1367
1368                if ( $useooobaseversion )
1369                {
1370                    if ( ! exists($allvariables->{'OOOBASEVERSION'}) ) { installer::exiter::exit_program("ERROR: Could not find variable \"OOOBASEVERSION\" (required value for GUID creation)!", "set_uuid_into_component_table"); }
1371                    $sourcestring = $sourcestring . "_" . $allvariables->{'OOOBASEVERSION'};
1372                }
1373                $uuid = calculate_guid($sourcestring);
1374                $counter++;
1375
1376                # checking, if there is a conflict with an already created guid
1377                if ( exists($installer::globals::allcalculated_guids{$uuid}) ) { installer::exiter::exit_program("ERROR: \"$uuid\" was already created before!", "set_uuid_into_component_table"); }
1378                $installer::globals::allcalculated_guids{$uuid} = 1;
1379                $installer::globals::calculated_component_guids{$componentname} = $uuid;
1380
1381                # Setting new uuid
1382                # $componenthash->{$componentname} = $uuid;
1383
1384                # Setting flag
1385                # $installer::globals::created_new_component_guid = 1;  # this is very important!
1386            }
1387    #   }
1388
1389        ${$componenttable}[$i] =~ s/COMPONENTGUID/$uuid/;
1390    }
1391
1392    installer::files::save_file($componenttablename, $componenttable);
1393
1394#   if ( $installer::globals::created_new_component_guid )
1395#   {
1396#       # create new component file!
1397#       $componentfile = create_new_component_file($componenthash);
1398#       installer::worker::sort_array($componentfile);
1399#
1400#       # To avoid conflict the components file cannot be saved at the same place
1401#       # All important data have to be saved in the directory: $installer::globals::infodirectory
1402#       my $localcomponentfilename = $installer::globals::componentfilename;
1403#       installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$localcomponentfilename);
1404#       $localcomponentfilename = $installer::globals::infodirectory . $installer::globals::separator . $localcomponentfilename;
1405#       installer::files::save_file($localcomponentfilename, $componentfile);
1406#
1407#       # installer::files::save_file($installer::globals::componentfilename, $componentfile);  # version using new file in solver
1408#
1409#       $infoline = "COMPONENTCODES: Created $counter new GUIDs for components ! \n";
1410#       $installer::logger::Lang->print($infoline);
1411#   }
1412#   else
1413#   {
1414#       $infoline = "SUCCESS COMPONENTCODES: All component codes exist! \n";
1415#       $installer::logger::Lang->print($infoline);
1416#   }
1417
1418}
1419
1420#########################################################################
1421# Adding final 64 properties into msi database, if required.
1422# RegLocator : +16 in type column to search in 64 bit registry.
1423# All conditions: "VersionNT" -> "VersionNT64" (several tables).
1424# Already done: "+256" in Attributes column of table "Component".
1425# Still following: Setting "x64" instead of "Intel" in Summary
1426# Information Stream of msi database in "get_template_for_sis".
1427#########################################################################
1428
1429sub prepare_64bit_database
1430{
1431    my ($basedir, $allvariables) = @_;
1432
1433    my $infoline = "";
1434
1435    if (( $allvariables->{'64BITPRODUCT'} ) && ( $allvariables->{'64BITPRODUCT'} == 1 ))
1436    {
1437        # 1. Beginning with table "RegLocat.idt". Adding "16" to the type.
1438
1439        my $reglocatfile = "";
1440        my $reglocatfilename = $basedir . $installer::globals::separator . "RegLocat.idt";
1441
1442        if ( -f $reglocatfilename )
1443        {
1444            my $saving_required = 0;
1445            $reglocatfile = installer::files::read_file($reglocatfilename);
1446
1447            for ( my $i = 3; $i <= $#{$reglocatfile}; $i++ )    # ignoring the first three lines
1448            {
1449                my $oneline = ${$reglocatfile}[$i];
1450
1451                if ( $oneline =~ /^\s*\#/ ) { next; }   # this is a comment line
1452                if ( $oneline =~ /^\s*$/ ) { next; }
1453
1454                if ( $oneline =~ /^\s*(.*?)\t(.*?)\t(.*?)\t(.*?)\t(\d+)\s*$/ )
1455                {
1456                    # Syntax: Signature_ Root Key Name Type
1457                    my $sig = $1;
1458                    my $root = $2;
1459                    my $key = $3;
1460                    my $name = $4;
1461                    my $type = $5;
1462
1463                    $type = $type + 16;
1464
1465                    my $newline = $sig . "\t" . $root . "\t" . $key . "\t" . $name . "\t" . $type . "\n";
1466                    ${$reglocatfile}[$i] = $newline;
1467
1468                    $saving_required = 1;
1469                }
1470            }
1471
1472            if ( $saving_required )
1473            {
1474                # Saving the files
1475                installer::files::save_file($reglocatfilename ,$reglocatfile);
1476                $infoline = "Making idt file 64 bit conform: $reglocatfilename\n";
1477                $installer::logger::Lang->print($infoline);
1478            }
1479        }
1480
1481        # 2. Replacing all occurences of "VersionNT" by "VersionNT64"
1482
1483        my @versionnt_files = ("Componen.idt", "InstallE.idt", "InstallU.idt", "LaunchCo.idt");
1484
1485        foreach my $onefile ( @versionnt_files )
1486        {
1487            my $fullfilename = $basedir . $installer::globals::separator . $onefile;
1488
1489            if ( -f $fullfilename )
1490            {
1491                my $saving_required = 0;
1492                $filecontent = installer::files::read_file($fullfilename);
1493
1494                for ( my $i = 3; $i <= $#{$filecontent}; $i++ )     # ignoring the first three lines
1495                {
1496                    my $oneline = ${$filecontent}[$i];
1497
1498                    if ( $oneline =~ /\bVersionNT\b/ )
1499                    {
1500                        ${$filecontent}[$i] =~ s/\bVersionNT\b/VersionNT64/g;
1501                        $saving_required = 1;
1502                    }
1503                }
1504
1505                if ( $saving_required )
1506                {
1507                    # Saving the files
1508                    installer::files::save_file($fullfilename ,$filecontent);
1509                    $infoline = "Making idt file 64 bit conform: $fullfilename\n";
1510                    $installer::logger::Lang->print($infoline);
1511                }
1512            }
1513        }
1514    }
1515
1516}
1517
1518#################################################################
1519# Include all cab files into the msi database.
1520# This works only on Windows
1521#################################################################
1522
1523sub include_cabs_into_msi
1524{
1525    my ($installdir) = @_;
1526
1527    installer::logger::include_header_into_logfile("Including cabs into msi database");
1528
1529    my $from = cwd();
1530    my $to = $installdir;
1531
1532    chdir($to);
1533
1534    my $infoline = "Changing into directory: $to";
1535    $installer::logger::Lang->print($infoline);
1536
1537    my $msidb = "msidb.exe";    # Has to be in the path
1538    my $extraslash = "";        # Has to be set for non-ActiveState perl
1539
1540    my $msifilename = $installer::globals::msidatabasename;
1541
1542    $msifilename = installer::converter::make_path_conform($msifilename);
1543
1544    # msidb.exe really wants backslashes. (And double escaping because system() expands the string.)
1545    $msifilename =~ s/\//\\\\/g;
1546    $extraslash = "\\";
1547
1548    my $allcabfiles = installer::systemactions::find_file_with_file_extension("cab", $installdir);
1549
1550    for ( my $i = 0; $i <= $#{$allcabfiles}; $i++ )
1551    {
1552        my $systemcall = $msidb . " -d " . $msifilename . " -a " . ${$allcabfiles}[$i];
1553
1554        my $returnvalue = system($systemcall);
1555
1556        $infoline = "Systemcall: $systemcall\n";
1557        $installer::logger::Lang->print($infoline);
1558
1559        if ($returnvalue)
1560        {
1561            $infoline = "ERROR: Could not execute $systemcall !\n";
1562            $installer::logger::Lang->print($infoline);
1563        }
1564        else
1565        {
1566            $infoline = "Success: Executed $systemcall successfully!\n";
1567            $installer::logger::Lang->print($infoline);
1568        }
1569
1570        # deleting the cab file
1571
1572        unlink(${$allcabfiles}[$i]);
1573
1574        $infoline = "Deleted cab file: ${$allcabfiles}[$i]\n";
1575        $installer::logger::Lang->print($infoline);
1576    }
1577
1578    $infoline = "Changing back into directory: $from";
1579    $installer::logger::Lang->print($infoline);
1580
1581    chdir($from);
1582}
1583
1584#################################################################
1585# Executing the created batch file to pack all files.
1586# This works only on Windows
1587#################################################################
1588
1589sub execute_packaging
1590{
1591    my ($localpackjobref, $loggingdir, $allvariables) = @_;
1592
1593    installer::logger::include_header_into_logfile("Packaging process");
1594
1595    $installer::logger::Lang->add_timestamp("Performance Info: Execute packaging start");
1596
1597    my $infoline = "";
1598    my $from = cwd();
1599    my $to = $loggingdir;
1600
1601    chdir($to);
1602    $infoline = "chdir: $to \n";
1603    $installer::logger::Lang->print($infoline);
1604
1605    # if the ddf file contains relative pathes, it is necessary to change into the temp directory
1606    if ( $allvariables->{'RELATIVE_PATHES_IN_DDF'} )
1607    {
1608        $to = $installer::globals::temppath;
1609        chdir($to);
1610        $infoline = "chdir: $to \n";
1611        $installer::logger::Lang->print($infoline);
1612    }
1613
1614    # changing the tmp directory, because makecab.exe generates temporary cab files
1615    my $origtemppath = "";
1616    if ( $ENV{'TMP'} ) { $origtemppath = $ENV{'TMP'}; }
1617    $ENV{'TMP'} = $installer::globals::temppath;    # setting TMP to the new unique directory!
1618
1619    my $maxmakecabcalls = 3;
1620    my $allmakecabcalls = $#{$localpackjobref} + 1;
1621
1622    for ( my $i = 0; $i <= $#{$localpackjobref}; $i++ )
1623    {
1624        my $systemcall = ${$localpackjobref}[$i];
1625
1626        my $callscounter = $i + 1;
1627
1628        $installer::logger::Info->printf("... makecab.exe (%s/%s) ... \n", $callscounter, $allmakecabcalls);
1629
1630        # my $returnvalue = system($systemcall);
1631
1632        for ( my $n = 1; $n <= $maxmakecabcalls; $n++ )
1633        {
1634            my @ddfoutput = ();
1635
1636            $infoline = "Systemcall: $systemcall";
1637            $installer::logger::Lang->print($infoline);
1638
1639            open (DDF, "$systemcall");
1640            while (<DDF>) {push(@ddfoutput, $_); }
1641            close (DDF);
1642
1643            my $returnvalue = $?;   # $? contains the return value of the systemcall
1644
1645            if ($returnvalue)
1646            {
1647                if ( $n < $maxmakecabcalls )
1648                {
1649                    $installer::logger::Info->printf("makecab_error (Try %s): Trying again\n", $n);
1650                    $installer::logger::Lang->printf("makecab_error (Try %s): Trying again\n", $n);
1651                }
1652                else
1653                {
1654                    $installer::logger::Info->printf("ERROR (Try %s): Abort packing \n", $n);
1655                    $installer::logger::Lang->printf("ERROR (Try %s): Abort packing \n", $n);
1656                }
1657
1658                for ( my $m = 0; $m <= $#ddfoutput; $m++ )
1659                {
1660                    if ( $ddfoutput[$m] =~ /(ERROR\:.*?)\s*$/ )
1661                    {
1662                        $infoline = $1 . "\n";
1663                        if ( $n < $maxmakecabcalls )
1664                        {
1665                            $infoline =~ s/ERROR\:/makecab_error\:/i;
1666                        }
1667                        $installer::logger::Info->print($infoline);
1668                        $installer::logger::Lang->print($infoline);
1669                    }
1670                }
1671
1672                if ( $n == $maxmakecabcalls ) { installer::exiter::exit_program("ERROR: \"$systemcall\"!", "execute_packaging"); }
1673            }
1674            else
1675            {
1676                $infoline = "Success (Try $n): $systemcall";
1677                $installer::logger::Lang->print($infoline);
1678                last;
1679            }
1680        }
1681    }
1682
1683    $installer::logger::Lang->add_timestamp("Performance Info: Execute packaging end");
1684
1685    # setting back to the original tmp directory
1686    $ENV{'TMP'} = $origtemppath;
1687
1688    chdir($from);
1689    $infoline = "chdir: $from \n";
1690    $installer::logger::Lang->print($infoline);
1691}
1692
1693###############################################################
1694# Setting the global variables ProductCode and the UpgradeCode
1695###############################################################
1696
1697sub set_global_code_variables
1698{
1699    my ( $languagesref, $languagestringref, $allvariableshashref, $alloldproperties ) = @_;
1700
1701    # In the msi template directory a files "codes.txt" has to exist, in which the ProductCode
1702    # and the UpgradeCode for the product are defined.
1703    # The name "codes.txt" can be overwritten in Product definition with CODEFILENAME .
1704    # Default $installer::globals::codefilename is defined in parameter.pm.
1705
1706    if ( $allvariableshashref->{'CODEFILENAME'} )
1707    {
1708        $installer::globals::codefilename = $installer::globals::idttemplatepath  . $installer::globals::separator . $allvariableshashref->{'CODEFILENAME'};
1709        installer::files::check_file($installer::globals::codefilename);
1710    }
1711
1712    my $infoline = "Using Codes file: $installer::globals::codefilename \n";
1713    $installer::logger::Lang->print($infoline);
1714
1715    my $codefile = installer::files::read_file($installer::globals::codefilename);
1716
1717    my $isopensource = 0;
1718    if ( $allvariableshashref->{'OPENSOURCE'} ) { $isopensource = $allvariableshashref->{'OPENSOURCE'}; }
1719
1720    my $onelanguage = "";
1721
1722    if ( $#{$languagesref} > 0 )    # more than one language
1723    {
1724        if (( $installer::globals::added_english ) && ( $#{$languagesref} == 1 )) # only multilingual because of added English
1725        {
1726            $onelanguage = ${$languagesref}[1];  # setting the first language, that is not english
1727        }
1728        else
1729        {
1730            if (( ${$languagesref}[1] =~ /jp/ ) ||
1731                ( ${$languagesref}[1] =~ /ko/ ) ||
1732                ( ${$languagesref}[1] =~ /zh/ ))
1733            {
1734                $onelanguage = "multiasia";
1735            }
1736            else
1737            {
1738                $onelanguage = "multiwestern";
1739            }
1740        }
1741    }
1742    else    # only one language
1743    {
1744        $onelanguage = ${$languagesref}[0];
1745    }
1746
1747    # ProductCode must not change, if Windows patches shall be applied
1748    if ( $installer::globals::prepare_winpatch )
1749    {
1750        # ProductCode has to be specified in each language
1751        my $searchstring = "PRODUCTCODE";
1752        my $codeblock = installer::windows::idtglobal::get_language_block_from_language_file($searchstring, $codefile);
1753        $installer::globals::productcode = installer::windows::idtglobal::get_code_from_code_block($codeblock, $onelanguage);
1754    } else {
1755        my $guidref = get_guid_list(1, 1);  # only one GUID shall be generated
1756        ${$guidref}[0] =~ s/\s*$//;     # removing ending spaces
1757        $installer::globals::productcode = "\{" . ${$guidref}[0] . "\}";
1758    }
1759
1760    if ( $installer::globals::patch ) # patch upgrade codes are defined in soffice.lst
1761    {
1762        if ( $allvariableshashref->{'PATCHUPGRADECODE'} ) { $installer::globals::upgradecode = $allvariableshashref->{'PATCHUPGRADECODE'}; }
1763        else { installer::exiter::exit_program("ERROR: PATCHUPGRADECODE not defined in list file!", "set_global_code_variables"); }
1764    }
1765    else
1766    {
1767        # UpgradeCode can take english as default, if not defined in specified language
1768
1769        $searchstring = "UPGRADECODE";  # searching in the codes.txt file
1770        $codeblock = installer::windows::idtglobal::get_language_block_from_language_file($searchstring, $codefile);
1771        $installer::globals::upgradecode = installer::windows::idtglobal::get_language_string_from_language_block($codeblock, $onelanguage, "");
1772    }
1773
1774    # if (( $installer::globals::productcode eq "" ) && ( ! $isopensource )) { installer::exiter::exit_program("ERROR: ProductCode for language $onelanguage not defined in $installer::globals::codefilename !", "set_global_code_variables"); }
1775    if ( $installer::globals::upgradecode eq "" ) { installer::exiter::exit_program("ERROR: UpgradeCode not defined in $installer::globals::codefilename !", "set_global_code_variables"); }
1776
1777    $infoline = "Setting ProductCode to: $installer::globals::productcode \n";
1778    $installer::logger::Lang->print($infoline);
1779    $infoline = "Setting UpgradeCode to: $installer::globals::upgradecode \n";
1780    $installer::logger::Lang->print($infoline);
1781
1782    # Adding both variables into the variables array
1783
1784    $allvariableshashref->{'PRODUCTCODE'} = $installer::globals::productcode;
1785    $allvariableshashref->{'UPGRADECODE'} = $installer::globals::upgradecode;
1786
1787    $infoline = "Defined variable PRODUCTCODE: $installer::globals::productcode \n";
1788    $installer::logger::Lang->print($infoline);
1789
1790    $infoline = "Defined variable UPGRADECODE: $installer::globals::upgradecode \n";
1791    $installer::logger::Lang->print($infoline);
1792
1793}
1794
1795###############################################################
1796# Setting the product version used in property table and
1797# upgrade table. Saving in global variable $msiproductversion
1798###############################################################
1799
1800sub set_msiproductversion
1801{
1802    my ( $allvariables ) = @_;
1803
1804    my $productversion = $allvariables->{'PRODUCTVERSION'};
1805
1806    if (( $productversion =~ /^\s*\d+\s*$/ ) && ( $productversion > 255 )) { $productversion = $productversion%256; }
1807
1808    if ( $productversion =~ /^\s*(\d+)\.(\d+)\.(\d+)\s*$/ )
1809    {
1810        $productversion = $1 . "\." . $2 . $3 . "\." . $installer::globals::buildid;
1811    }
1812    elsif  ( $productversion =~ /^\s*(\d+)\.(\d+)\s*$/ )
1813    {
1814        $productversion = $1 . "\." . $2 . "\." . $installer::globals::buildid;
1815    }
1816    else
1817    {
1818        my $productminor = "00";
1819        if (( $allvariables->{'PACKAGEVERSION'} ) && ( $allvariables->{'PACKAGEVERSION'} ne "" ))
1820        {
1821            if ( $allvariables->{'PACKAGEVERSION'} =~ /^\s*(\d+)\.(\d+)\.(\d+)\s*$/ ) { $productminor = $2; }
1822        }
1823
1824        $productversion = $productversion . "\." . $productminor . "\." . $installer::globals::buildid;
1825    }
1826
1827    $installer::globals::msiproductversion = $productversion;
1828
1829    # Setting $installer::globals::msimajorproductversion, to differ between old version in upgrade table
1830
1831    if ( $installer::globals::msiproductversion =~ /^\s*(\d+)\./ )
1832    {
1833        my $major = $1;
1834        $installer::globals::msimajorproductversion = $major . "\.0\.0";
1835    }
1836}
1837
1838#################################################################################
1839# Including the msi product version into the bootstrap.ini, Windows only
1840#################################################################################
1841
1842sub put_msiproductversion_into_bootstrapfile
1843{
1844    my ($filesref) = @_;
1845
1846    for ( my $i = 0; $i <= $#{$filesref}; $i++ )
1847    {
1848        my $onefile = ${$filesref}[$i];
1849
1850        if ( $onefile->{'gid'} eq "gid_Profile_Version_Ini" )
1851        {
1852            my $file = installer::files::read_file($onefile->{'sourcepath'});
1853
1854            for ( my $j = 0; $j <= $#{$file}; $j++ )
1855            {
1856                ${$file}[$j] =~ s/\<msiproductversion\>/$installer::globals::msiproductversion/;
1857            }
1858
1859            installer::files::save_file($onefile->{'sourcepath'}, $file);
1860
1861            last;
1862        }
1863    }
1864}
1865
1866####################################################################################
1867# Updating the file Property.idt dynamically
1868# Content:
1869# Property Value
1870####################################################################################
1871
1872sub update_reglocat_table
1873{
1874    my ($basedir, $allvariables) = @_;
1875
1876    my $reglocatfilename = $basedir . $installer::globals::separator . "RegLocat.idt";
1877
1878    # Only do something, if this file exists
1879
1880    if ( -f $reglocatfilename )
1881    {
1882        my $reglocatfile = installer::files::read_file($reglocatfilename);
1883
1884        my $layername = "";
1885        if ( $allvariables->{'REGISTRYLAYERNAME'} )
1886        {
1887            $layername = $allvariables->{'REGISTRYLAYERNAME'};
1888        }
1889        else
1890        {
1891            for ( my $i = 0; $i <= $#{$reglocatfile}; $i++ )
1892            {
1893                if ( ${$reglocatfile}[$i] =~ /\bLAYERNAMETEMPLATE\b/ )
1894                {
1895                    installer::exiter::exit_program("ERROR: Variable \"REGISTRYLAYERNAME\" has to be defined", "update_reglocat_table");
1896                }
1897            }
1898        }
1899
1900        if ( $layername ne "" )
1901        {
1902            # Updating the layername in
1903
1904            for ( my $i = 0; $i <= $#{$reglocatfile}; $i++ )
1905            {
1906                ${$reglocatfile}[$i] =~ s/\bLAYERNAMETEMPLATE\b/$layername/;
1907            }
1908
1909            # Saving the file
1910            installer::files::save_file($reglocatfilename ,$reglocatfile);
1911            my $infoline = "Updated idt file: $reglocatfilename\n";
1912            $installer::logger::Lang->print($infoline);
1913        }
1914    }
1915}
1916
1917
1918
1919####################################################################################
1920# Updating the file RemoveRe.idt dynamically (RemoveRegistry.idt)
1921# The name of the component has to be replaced.
1922####################################################################################
1923
1924sub update_removere_table
1925{
1926    my ($basedir) = @_;
1927
1928    my $removeregistryfilename = $basedir . $installer::globals::separator . "RemoveRe.idt";
1929
1930    # Only do something, if this file exists
1931
1932    if ( -f $removeregistryfilename )
1933    {
1934        my $removeregistryfile = installer::files::read_file($removeregistryfilename);
1935
1936        for ( my $i = 0; $i <= $#{$removeregistryfile}; $i++ )
1937        {
1938            for ( my $i = 0; $i <= $#{$removeregistryfile}; $i++ )
1939            {
1940                ${$removeregistryfile}[$i] =~ s/\bREGISTRYROOTCOMPONENT\b/$installer::globals::registryrootcomponent/;
1941            }
1942        }
1943
1944        # Saving the file
1945        installer::files::save_file($removeregistryfilename ,$removeregistryfile);
1946        my $infoline = "Updated idt file: $removeregistryfilename \n";
1947        $installer::logger::Lang->print($infoline);
1948    }
1949}
1950
1951##########################################################################
1952# Reading saved mappings in Files.idt and Director.idt.
1953# This is required, if installation sets shall be created,
1954# that can be used for creation of msp files.
1955##########################################################################
1956
1957sub read_saved_mappings
1958{
1959    installer::logger::include_header_into_logfile("Reading saved mappings from older installation sets:");
1960
1961    $installer::logger::Lang->add_timestamp("Performance Info: Reading saved mappings start");
1962
1963    if ( $installer::globals::previous_idt_dir )
1964    {
1965        my @errorlines = ();
1966        my $errorstring = "";
1967        my $error_occured = 0;
1968        my $file_error_occured = 0;
1969        my $dir_error = 0;
1970
1971        my $idtdir = $installer::globals::previous_idt_dir;
1972        $idtdir =~ s/\Q$installer::globals::separator\E\s*$//;
1973
1974        # Reading File.idt
1975
1976        my $idtfile = $idtdir . $installer::globals::separator . "File.idt";
1977        $installer::logger::Global->print("\n");
1978        $installer::logger::Global->printf("Analyzing file: %s\n", $idtfile);
1979        if ( ! -f $idtfile )
1980        {
1981            $installer::logger::Global->printf("Warning: File %s does not exist!\n", $idtfile);
1982        }
1983
1984        my $n = 0;
1985        open (F, "<$idtfile") || installer::exiter::exit_program("ERROR: Cannot open file $idtfile for reading", "read_saved_mappings");
1986        <F>; <F>; <F>;
1987        while (<F>)
1988        {
1989            m/^([^\t]+)\t([^\t]+)\t((.*)\|)?([^\t]*)/;
1990            print "OUT1: \$1: $1, \$2: $2, \$3: $3, \$4: $4, \$5: $5\n";
1991            next if ("$1" eq "$5") && (!defined($3));
1992            my $lc1 = lc($1);
1993
1994            if ( exists($installer::globals::savedmapping{"$2/$5"}))
1995            {
1996                if ( ! $file_error_occured )
1997                {
1998                    $errorstring = "\nErrors in $idtfile: \n";
1999                    push(@errorlines, $errorstring);
2000                }
2001                $errorstring = "Duplicate savedmapping{" . "$2/$5}\n";
2002                push(@errorlines, $errorstring);
2003                $error_occured = 1;
2004                $file_error_occured = 1;
2005            }
2006
2007            if ( exists($installer::globals::savedrevmapping{$lc1}))
2008            {
2009                if ( ! $file_error_occured )
2010                {
2011                    $errorstring = "\nErrors in $idtfile: \n";
2012                    push(@errorlines, $errorstring);
2013                }
2014                $errorstring = "Duplicate savedrevmapping{" . "$lc1}\n";
2015                push(@errorlines, $errorstring);
2016                $error_occured = 1;
2017                $file_error_occured = 1;
2018            }
2019
2020            my $shortname = $4 || '';
2021
2022            # Don't reuse illegal 8.3 mappings that we used to generate in 2.0.4
2023            if (index($shortname, '.') > 8 ||
2024                (index($shortname, '.') == -1 && length($shortname) > 8))
2025            {
2026                $shortname = '';
2027            }
2028
2029            if (( $shortname ne '' ) && ( index($shortname, '~') > 0 ) && ( exists($installer::globals::savedrev83mapping{$shortname}) ))
2030            {
2031                if ( ! $file_error_occured )
2032                {
2033                    $errorstring = "\nErrors in $idtfile: \n";
2034                    push(@errorlines, $errorstring);
2035                }
2036                $errorstring = "Duplicate savedrev83mapping{" . "$shortname}\n";
2037                push(@errorlines, $errorstring);
2038                $error_occured = 1;
2039                $file_error_occured = 1;
2040            }
2041
2042            $installer::globals::savedmapping{"$2/$5"} = "$1;$shortname";
2043            $installer::globals::savedrevmapping{lc($1)} = "$2/$5";
2044            $installer::globals::savedrev83mapping{$shortname} = "$2/$5" if $shortname ne '';
2045            $n++;
2046        }
2047
2048        close (F);
2049
2050        $installer::logger::Global->printf("Read %s old file table key or 8.3 name mappings from %s\n",
2051            $n, $idtfile);
2052
2053        # Reading Director.idt
2054
2055        $idtfile = $idtdir . $installer::globals::separator . "Director.idt";
2056        $installer::logger::Global->print("\n");
2057        $installer::logger::Global->printf("Analyzing file %s\n", $idtfile);
2058        if ( ! -f $idtfile )
2059        {
2060            $installer::logger::Global->printf("Warning: File %s does not exist!\n", $idtfile);
2061        }
2062
2063        $n = 0;
2064        open (F, "<$idtfile") || installer::exiter::exit_program("ERROR: Cannot open file $idtfile for reading", "read_saved_mappings");
2065        <F>; <F>; <F>;
2066        while (<F>)
2067        {
2068            m/^([^\t]+)\t([^\t]+)\t(([^~]+~\d.*)\|)?([^\t]*)/;
2069            next if (!defined($3));
2070            my $lc1 = lc($1);
2071
2072            print "OUT2: \$1: $1, \$2: $2, \$3: $3\n";
2073
2074            if ( exists($installer::globals::saved83dirmapping{$1}) )
2075            {
2076                if ( ! $dir_error_occured )
2077                {
2078                    $errorstring = "\nErrors in $idtfile: \n";
2079                    push(@errorlines, $errorstring);
2080                }
2081                $errorstring = "Duplicate saved83dirmapping{" . "$1}\n";
2082                push(@errorlines, $errorstring);
2083                $error_occured = 1;
2084                $dir_error_occured = 1;
2085            }
2086
2087            $installer::globals::saved83dirmapping{$1} = $4;
2088            $n++;
2089        }
2090        close (F);
2091
2092        $installer::logger::Global->printf("Read %s old directory 8.3 name mappings from %s\n",
2093            $n, $idtfile);
2094
2095        # Analyzing errors
2096
2097        if ( $error_occured )
2098        {
2099            for my $line (@errorlines)
2100            {
2101                $installer::logger::Info->print($line);
2102                $installer::logger::Global->print($line);
2103            }
2104            installer::exiter::exit_program("ERROR: Duplicate entries in saved mappings!", "read_saved_mappings");
2105        }
2106    } else {
2107        installer::exiter::exit_program("ERROR: Windows patch shall be prepared, but environment variable PREVIOUS_IDT_DIR is not set!", "read_saved_mappings");
2108    }
2109
2110    $installer::logger::Lang->add_timestamp("Performance Info: Reading saved mappings end");
2111}
2112
21131;
2114
2115