file.pm (1ba1fd99) file.pm (9f91b7e3)
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

--- 21 unchanged lines hidden (view full) ---

30use installer::globals;
31use installer::logger;
32use installer::pathanalyzer;
33use installer::worker;
34use installer::windows::font;
35use installer::windows::idtglobal;
36use installer::windows::msiglobal;
37use installer::windows::language;
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

--- 21 unchanged lines hidden (view full) ---

30use installer::globals;
31use installer::logger;
32use installer::pathanalyzer;
33use installer::worker;
34use installer::windows::font;
35use installer::windows::idtglobal;
36use installer::windows::msiglobal;
37use installer::windows::language;
38use installer::patch::InstallationSet;
39use installer::patch::FileSequenceList;
40use File::Basename;
41use File::Spec;
42use strict;
38
39##########################################################################
40# Assigning one cabinet file to each file. This is requrired,
41# if cabinet files shall be equivalent to packages.
42##########################################################################
43
44sub assign_cab_to_files
45{

--- 306 unchanged lines hidden (view full) ---

352
353####################################################################
354# Generating the special filename for the database file File.idt
355# Sample: CONTEXTS, CONTEXTS1
356# This name has to be unique.
357# In most cases this is simply the filename.
358####################################################################
359
43
44##########################################################################
45# Assigning one cabinet file to each file. This is requrired,
46# if cabinet files shall be equivalent to packages.
47##########################################################################
48
49sub assign_cab_to_files
50{

--- 306 unchanged lines hidden (view full) ---

357
358####################################################################
359# Generating the special filename for the database file File.idt
360# Sample: CONTEXTS, CONTEXTS1
361# This name has to be unique.
362# In most cases this is simply the filename.
363####################################################################
364
360sub generate_unique_filename_for_filetable ($$)
365sub generate_unique_filename_for_filetable ($)
361{
366{
362 my ($fileref, $component) = @_;
367 my ($oldname) = @_;
363
364 # This new filename has to be saved into $fileref, because this is needed to find the source.
365 # The filename sbasic.idx/OFFSETS is changed to OFFSETS, but OFFSETS is not unique.
366 # In this procedure names like OFFSETS5 are produced. And exactly this string has to be added to
367 # the array of all files.
368
368
369 # This new filename has to be saved into $fileref, because this is needed to find the source.
370 # The filename sbasic.idx/OFFSETS is changed to OFFSETS, but OFFSETS is not unique.
371 # In this procedure names like OFFSETS5 are produced. And exactly this string has to be added to
372 # the array of all files.
373
369 my $uniquefilename = "";
370 my $counter = 0;
374 my $uniquefilename = $oldname;
375 if ( ! defined $uniquefilename || $uniquefilename eq "")
376 {
377 installer::logger::PrintError("file name does not exist or is empty, can not create unique name for it.");
378 die;
379 return;
380 }
371
381
372 if ( $fileref->{'Name'} ) { $uniquefilename = $fileref->{'Name'}; }
373 # making /registry/schema/org/openoffice/VCL.xcs to VCL.xcs
374 installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$uniquefilename);
375
376 $uniquefilename =~ s/\-/\_/g; # no "-" allowed
377 $uniquefilename =~ s/\@/\_/g; # no "@" allowed
378 $uniquefilename =~ s/\$/\_/g; # no "$" allowed
379 $uniquefilename =~ s/^\s*\./\_/g; # no "." at the beginning allowed allowed
380 $uniquefilename =~ s/^\s*\d/\_d/g; # no number at the beginning allowed allowed (even file "0.gif", replacing to "_d.gif")

--- 12 unchanged lines hidden (view full) ---

393
394 if ( ! $newname )
395 {
396 # adding a number until the name is really unique: OFFSETS, OFFSETS1, OFFSETS2, ...
397 # But attention: Making "abc.xcu" to "abc1.xcu"
398
399 my $uniquefilenamebase = $uniquefilename;
400
382 # making /registry/schema/org/openoffice/VCL.xcs to VCL.xcs
383 installer::pathanalyzer::make_absolute_filename_to_relative_filename(\$uniquefilename);
384
385 $uniquefilename =~ s/\-/\_/g; # no "-" allowed
386 $uniquefilename =~ s/\@/\_/g; # no "@" allowed
387 $uniquefilename =~ s/\$/\_/g; # no "$" allowed
388 $uniquefilename =~ s/^\s*\./\_/g; # no "." at the beginning allowed allowed
389 $uniquefilename =~ s/^\s*\d/\_d/g; # no number at the beginning allowed allowed (even file "0.gif", replacing to "_d.gif")

--- 12 unchanged lines hidden (view full) ---

402
403 if ( ! $newname )
404 {
405 # adding a number until the name is really unique: OFFSETS, OFFSETS1, OFFSETS2, ...
406 # But attention: Making "abc.xcu" to "abc1.xcu"
407
408 my $uniquefilenamebase = $uniquefilename;
409
410 my $counter = 0;
401 do
402 {
403 $counter++;
404
405 if ( $uniquefilenamebase =~ /\./ )
406 {
407 $uniquefilename = $uniquefilenamebase;
408 $uniquefilename =~ s/\./$counter\./;

--- 77 unchanged lines hidden (view full) ---

486
487#############################################
488# Returning the file version, if required
489# Sample: "8.0.1.8976";
490#############################################
491
492sub get_fileversion
493{
411 do
412 {
413 $counter++;
414
415 if ( $uniquefilenamebase =~ /\./ )
416 {
417 $uniquefilename = $uniquefilenamebase;
418 $uniquefilename =~ s/\./$counter\./;

--- 77 unchanged lines hidden (view full) ---

496
497#############################################
498# Returning the file version, if required
499# Sample: "8.0.1.8976";
500#############################################
501
502sub get_fileversion
503{
494 my ($onefile, $allvariables, $styles) = @_;
504 my ($onefile, $allvariables) = @_;
495
496 my $fileversion = "";
497
498 if ( $allvariables->{'USE_FILEVERSION'} )
499 {
500 if ( ! $allvariables->{'LIBRARYVERSION'} )
501 {
502 installer::exiter::exit_program("ERROR: USE_FILEVERSION is set, but not LIBRARYVERSION", "get_fileversion");

--- 24 unchanged lines hidden (view full) ---

527 {
528 # Windows patches do not allow this version # -> who says so?
529 $fileversion = "";
530 }
531
532 return $fileversion;
533}
534
505
506 my $fileversion = "";
507
508 if ( $allvariables->{'USE_FILEVERSION'} )
509 {
510 if ( ! $allvariables->{'LIBRARYVERSION'} )
511 {
512 installer::exiter::exit_program("ERROR: USE_FILEVERSION is set, but not LIBRARYVERSION", "get_fileversion");

--- 24 unchanged lines hidden (view full) ---

537 {
538 # Windows patches do not allow this version # -> who says so?
539 $fileversion = "";
540 }
541
542 return $fileversion;
543}
544
545
546
547
548sub retrieve_sequence_and_uniquename ($$)
549{
550 my ($file_list, $source_data) = @_;
551
552 my @added_files = ();
553
554 # Read the sequence numbers of the previous version.
555 if ($installer::globals::is_release)
556 {
557 foreach my $file (@$file_list)
558 {
559 # Use the source path of the file as key to retrieve sequence number and unique name.
560 # The source path is the part of the 'destination' without the first part.
561 # There is a special case when 'Dir' is PREDEFINED_OSSHELLNEWDIR.
562 my $source_path;
563 if (defined $file->{'Dir'} && $file->{'Dir'} eq "PREDEFINED_OSSHELLNEWDIR")
564 {
565 $source_path = $installer::globals::templatefoldername
566 . $installer::globals::separator
567 . $file->{'Name'};
568 }
569 else
570 {
571 $source_path = $file->{'destination'};
572 $source_path =~ s/^[^\/]+\///;
573 }
574 my ($sequence, $uniquename) = $source_data->get_sequence_and_unique_name($source_path);
575 if (defined $sequence && defined $uniquename)
576 {
577 $file->{'sequencenumber'} = $sequence;
578 $file->{'uniquename'} = $uniquename;
579 }
580 else
581 {
582 # No data found in the source release. File has been added.
583 push @added_files, $file;
584 }
585 }
586 }
587
588 return @added_files;
589}
590
591
592
593
594=head2 assign_mssing_sequence_numbers ($file_list)
595
596 Assign sequence numbers where still missing.
597
598 When we are preparing a patch then all files that have no sequence numbers
599 at this point are new. Otherwise no file has a sequence number yet.
600
601=cut
602sub assign_missing_sequence_numbers ($)
603{
604 my ($file_list) = @_;
605
606 # First, set up a hash on the sequence numbers that are already in use.
607 my %used_sequence_numbers = ();
608 foreach my $file (@$file_list)
609 {
610 next unless defined $file->{'sequencenumber'};
611 $used_sequence_numbers{$file->{'sequencenumber'}} = 1;
612 }
613
614 # Assign sequence numbers. Try consecutive numbers, starting at 1.
615 my $current_sequence_number = 1;
616 foreach my $file (@$file_list)
617 {
618 # Skip over all files that already have sequence numbers.
619 next if defined $file->{'sequencenumber'};
620
621 # Find the next available number.
622 while (defined $used_sequence_numbers{$current_sequence_number})
623 {
624 ++$current_sequence_number;
625 }
626
627 # Use the number and mark it as used.
628 $file->{'sequencenumber'} = $current_sequence_number;
629 $used_sequence_numbers{$current_sequence_number} = 1;
630 }
631}
632
633
634
635
636sub create_items_for_missing_files ($$$)
637{
638 my ($missing_items, $msi, $directory_list) = @_;
639
640 # For creation of the FeatureComponent table (in a later step) we
641 # have to provide references from the file to component and
642 # modules (ie features). Note that Each file belongs to exactly
643 # one component but one component can belong to multiple features.
644 my $component_to_features_map = create_feature_component_map($msi);
645
646 my @new_files = ();
647 foreach my $row (@$missing_items)
648 {
649 $installer::logger::Info->printf("creating new file item for '%s'\n", $row->GetValue('File'));
650 my $file_item = create_script_item_for_deleted_file($row, $msi, $component_to_features_map);
651 push @new_files, $file_item;
652 }
653
654 return @new_files;
655}
656
657
658
659
660sub create_script_item_for_deleted_file ($$$)
661{
662 my ($file_row, $msi, $component_to_features_map) = @_;
663
664 my $uniquename = $file_row->GetValue('File');
665
666 my $file_map = $msi->GetFileMap();
667
668 my $directory_item = $file_map->{$uniquename}->{'directory'};
669 my $source_path = $directory_item->{'full_source_long_name'};
670 my $target_path = $directory_item->{'full_target_long_name'};
671 my $full_source_name = File::Spec->catfile(
672 installer::patch::InstallationSet::GetUnpackedCabPath(
673 $msi->{'version'},
674 $msi->{'is_current_version'},
675 $msi->{'language'},
676 $msi->{'package_format'},
677 $msi->{'product_name'}),
678 $source_path,
679 $uniquename);
680 my ($long_name, undef) = installer::patch::Msi::SplitLongShortName($file_row->GetValue("FileName"));
681 my $target_name = File::Spec->catfile($target_path, $long_name);
682 if ( ! -f $full_source_name)
683 {
684 installer::logger::PrintError("can not find file '%s' in previous version (tried '%s')\n",
685 $uniquename,
686 $full_source_name);
687 return undef;
688 }
689 my $cygwin_full_source_name = qx(cygpath -w '$full_source_name');
690 my $component_name = $file_row->GetValue('Component_');
691 my $module_names = join(",", @{$component_to_features_map->{$component_name}});
692 my $sequence_number = $file_row->GetValue('Sequence');
693
694 return {
695 'uniquename' => $uniquename,
696 'destination' => $target_name,
697 'componentname' => $component_name,
698 'modules' => $module_names,
699 'UnixRights' => 444,
700 'Name' => $long_name,
701 'sourcepath' => $full_source_name,
702 'cyg_sourcepath' => $cygwin_full_source_name,
703 'sequencenumber' => $sequence_number
704 };
705}
706
707
708
709
710=head2 create_feature_component_maps($msi)
711
712 Return a hash map that maps from component names to arrays of
713 feature names. In most cases the array of features contains only
714 one element. But there can be cases where the number is greater.
715
716=cut
717sub create_feature_component_map ($)
718{
719 my ($msi) = @_;
720
721 my $component_to_features_map = {};
722 my $feature_component_table = $msi->GetTable("FeatureComponents");
723 my $feature_column_index = $feature_component_table->GetColumnIndex("Feature_");
724 my $component_column_index = $feature_component_table->GetColumnIndex("Component_");
725 foreach my $row (@{$feature_component_table->GetAllRows()})
726 {
727 my $feature = $row->GetValue($feature_column_index);
728 my $component = $row->GetValue($component_column_index);
729 if ( ! defined $component_to_features_map->{$component})
730 {
731 $component_to_features_map->{$component} = [$feature];
732 }
733 else
734 {
735 push @{$component_to_features_map->{$component}}, $feature;
736 }
737 }
738
739 return $component_to_features_map;
740}
741
742
535#############################################
536# Returning the Windows language of a file
537#############################################
538
539sub get_language_for_file
540{
541 my ($fileref) = @_;
542

--- 28 unchanged lines hidden (view full) ---

571 my $keypath = $onefile->{'Name'};
572 $keypath =~ s/\.//g;
573 $keypath = lc($keypath);
574 $keypath = "userreg_" . $keypath;
575
576 return $keypath;
577}
578
743#############################################
744# Returning the Windows language of a file
745#############################################
746
747sub get_language_for_file
748{
749 my ($fileref) = @_;
750

--- 28 unchanged lines hidden (view full) ---

779 my $keypath = $onefile->{'Name'};
780 $keypath =~ s/\.//g;
781 $keypath = lc($keypath);
782 $keypath = "userreg_" . $keypath;
783
784 return $keypath;
785}
786
787
579###################################################################
580# Collecting further conditions for the component table.
581# This is used by multilayer products, to enable installation
582# of separate layers.
583###################################################################
584
585sub get_tree_condition_for_component
586{

--- 44 unchanged lines hidden (view full) ---

631 if ( $value =~ /^\s*(.*?)\;\s*(.*?)\s*$/ )
632 {
633 my $shortstring = $2;
634 $shortnameshashref->{$shortstring} = 1; # adding the shortname to the array of all shortnames
635 }
636 }
637}
638
788###################################################################
789# Collecting further conditions for the component table.
790# This is used by multilayer products, to enable installation
791# of separate layers.
792###################################################################
793
794sub get_tree_condition_for_component
795{

--- 44 unchanged lines hidden (view full) ---

840 if ( $value =~ /^\s*(.*?)\;\s*(.*?)\s*$/ )
841 {
842 my $shortstring = $2;
843 $shortnameshashref->{$shortstring} = 1; # adding the shortname to the array of all shortnames
844 }
845 }
846}
847
639############################################
640# Creating the file File.idt dynamically
641############################################
642
848
643sub create_files_table ($$$$)
849sub process_language_conditions ($)
644{
850{
645 my ($filesref, $allfilecomponentsref, $basedir, $allvariables) = @_;
851 my ($onefile) = @_;
852
853 # Collecting all languages specific conditions
854 if ( $onefile->{'ismultilingual'} )
855 {
856 if ( $onefile->{'ComponentCondition'} )
857 {
858 installer::exiter::exit_program(
859 "ERROR: Cannot set language condition. There is already another component condition for file $onefile->{'gid'}: \"$onefile->{'ComponentCondition'}\" !", "create_files_table");
860 }
646
861
647 $installer::logger::Lang->add_timestamp("Performance Info: File Table start");
862 if ( $onefile->{'specificlanguage'} eq "" )
863 {
864 installer::exiter::exit_program(
865 "ERROR: There is no specific language for file at language module: $onefile->{'gid'} !", "create_files_table");
866 }
867 my $locallanguage = $onefile->{'specificlanguage'};
868 my $property = "IS" . $onefile->{'windows_language'};
869 my $value = 1;
870 my $condition = $property . "=" . $value;
871
872 $onefile->{'ComponentCondition'} = $condition;
648
873
649 # Structure of the files table:
650 # File Component_ FileName FileSize Version Language Attributes Sequence
651 # In this function, all components are created.
652 #
653 # $allfilecomponentsref is empty at the beginning
874 if ( exists($installer::globals::componentcondition{$onefile->{'componentname'}}))
875 {
876 if ( $installer::globals::componentcondition{$onefile->{'componentname'}} ne $condition )
877 {
878 installer::exiter::exit_program(
879 sprintf(
880 "ERROR: There is already another component condition for file %s: \"%s\" and \"%s\" !",
881 $onefile->{'gid'},
882 $installer::globals::componentcondition{$onefile->{'componentname'}},
883 $condition),
884 "create_files_table");
885 }
886 }
887 else
888 {
889 $installer::globals::componentcondition{$onefile->{'componentname'}} = $condition;
890 }
654
891
655 my $infoline;
892 # collecting all properties for table Property
893 if ( ! exists($installer::globals::languageproperties{$property}) )
894 {
895 $installer::globals::languageproperties{$property} = $value;
896 }
897 }
898}
656
899
657 my @allfiles = ();
658 my @filetable = ();
659 my @filehashtable = ();
660 my %allfilecomponents = ();
661 my $counter = 0;
662
900
663 if ( $^O =~ /cygwin/i ) { installer::worker::generate_cygwin_pathes($filesref); }
664
665 # The filenames must be collected because of uniqueness
666 # 01-44-~1.DAT, 01-44-~2.DAT, ...
667 # my @shortnames = ();
668 my %shortnames = ();
669
670 installer::windows::idtglobal::write_idt_header(\@filetable, "file");
671 installer::windows::idtglobal::write_idt_header(\@filehashtable, "filehash");
672
673 for ( my $i = 0; $i <= $#{$filesref}; $i++ )
674 {
675 my %file = ();
676
901
677 my $onefile = ${$filesref}[$i];
678
902
679 my $styles = "";
680 if ( $onefile->{'Styles'} ) { $styles = $onefile->{'Styles'}; }
681 if (( $styles =~ /\bJAVAFILE\b/ ) && ( ! ($allvariables->{'JAVAPRODUCT'} ))) { next; }
903sub has_style ($$)
904{
905 my ($style_list_string, $style_name) = @_;
682
906
683 $file{'Component_'} = get_file_component_name($onefile, $filesref);
684 $file{'File'} = generate_unique_filename_for_filetable($onefile, $file{'Component_'});
685
686 $onefile->{'uniquename'} = $file{'File'};
687 $onefile->{'componentname'} = $file{'Component_'};
907 return 0 unless defined $style_list_string;
908 return $style_list_string =~ /\b$style_name\b/ ? 1 : 0;
909}
688
910
689 # Collecting all components
690 # if (!(installer::existence::exists_in_array($file{'Component_'}, $allfilecomponentsref))) { push(@{$allfilecomponentsref}, $file{'Component_'}); }
691
911
692 if ( ! exists($allfilecomponents{$file{'Component_'}}) ) { $allfilecomponents{$file{'Component_'}} = 1; }
693
912
694 $file{'FileName'} = generate_filename_for_filetable($onefile, \%shortnames);
695
913
696 $file{'FileSize'} = get_filesize($onefile);
914sub prepare_file_table_creation ($$$)
915{
916 my ($file_list, $directory_list, $allvariables) = @_;
917
918 if ( $^O =~ /cygwin/i )
919 {
920 installer::worker::generate_cygwin_pathes($file_list);
921 }
697
922
698 $file{'Version'} = get_fileversion($onefile, $allvariables, $styles);
923 # Reset the fields 'sequencenumber' and 'uniquename'. They should not yet exist but better be sure.
924 foreach my $file (@$file_list)
925 {
926 delete $file->{'sequencenumber'};
927 delete $file->{'uniquename'};
928 }
699
929
700 $file{'Language'} = get_language_for_file($onefile);
701
702 if ( $styles =~ /\bDONT_PACK\b/ ) { $file{'Attributes'} = "8192"; }
703 else { $file{'Attributes'} = "16384"; }
930 # Create FileSequenceList object for the old sequence data.
931 if (defined $installer::globals::source_msi)
932 {
933 my $previous_sequence_data = new installer::patch::FileSequenceList();
934 $previous_sequence_data->SetFromMsi($installer::globals::source_msi);
935 my @added_files = retrieve_sequence_and_uniquename($file_list, $previous_sequence_data);
936
937 # Extract just the unique names.
938 my %target_unique_names = map {$_->{'uniquename'} => 1} @$file_list;
939 my @removed_items = $previous_sequence_data->get_removed_files(\%target_unique_names);
704
940
705 # $file{'Attributes'} = "16384"; # Sourcefile is packed
706 # $file{'Attributes'} = "8192"; # Sourcefile is unpacked
941 $installer::logger::Lang->printf(
942 "there are %d files that have been removed from source and %d files added\n",
943 scalar @removed_items,
944 scalar @added_files);
707
945
708 $installer::globals::insert_file_at_end = 0;
709 $counter++;
710 $file{'Sequence'} = $counter;
946 my $file_map = $installer::globals::source_msi->GetFileMap();
947 my $index = 0;
948 foreach my $removed_row (@removed_items)
949 {
950 $installer::logger::Lang->printf(" removed file %d: %s\n",
951 ++$index,
952 $removed_row->GetValue('File'));
953 my $directory = $file_map->{$removed_row->GetValue('File')}->{'directory'};
954 while (my ($key,$value) = each %$directory)
955 {
956 $installer::logger::Lang->printf(" %16s -> %s\n", $key, $value);
957 }
958 }
959 $index = 0;
960 foreach my $added_file (@added_files)
961 {
962 $installer::logger::Lang->printf(" added file %d: %s\n",
963 ++$index,
964 $added_file->{'uniquename'});
965 installer::scriptitems::print_script_item($added_file);
966 }
967 my @new_files = create_items_for_missing_files(
968 \@removed_items,
969 $installer::globals::source_msi,
970 $directory_list);
971 push @$file_list, @new_files;
972 }
973 assign_missing_sequence_numbers($file_list);
711
974
712 $onefile->{'sequencenumber'} = $file{'Sequence'};
713
714 my $oneline = $file{'File'} . "\t" . $file{'Component_'} . "\t" . $file{'FileName'} . "\t"
715 . $file{'FileSize'} . "\t" . $file{'Version'} . "\t" . $file{'Language'} . "\t"
716 . $file{'Attributes'} . "\t" . $file{'Sequence'} . "\n";
975 foreach my $file (@$file_list)
976 {
977 if ( ! defined $file->{'componentname'})
978 {
979 $file->{'componentname'} = get_file_component_name($file, $file_list);
980 }
981 if ( ! defined $file->{'uniquename'})
982 {
983 $file->{'uniquename'} = generate_unique_filename_for_filetable($file->{'Name'});
984 }
717
985
718 push(@filetable, $oneline);
719
720 if ( ! $installer::globals::insert_file_at_end ) { push(@allfiles, $onefile); }
721
722 # Collecting all component conditions
986 # Collecting all component conditions
723 if ( $onefile->{'ComponentCondition'} )
987 if ( $file->{'ComponentCondition'} )
724 {
988 {
725 if ( ! exists($installer::globals::componentcondition{$file{'Component_'}}))
989 if ( ! exists($installer::globals::componentcondition{$file->{'componentname'}}))
726 {
990 {
727 $installer::globals::componentcondition{$file{'Component_'}} = $onefile->{'ComponentCondition'};
991 $installer::globals::componentcondition{$file->{'componentname'}}
992 = $file->{'ComponentCondition'};
728 }
729 }
993 }
994 }
730
731 # Collecting also all tree conditions for multilayer products
995 # Collecting also all tree conditions for multilayer products
732 get_tree_condition_for_component($onefile, $file{'Component_'});
996 get_tree_condition_for_component($file, $file->{'componentname'});
733
734 # Collecting all component names, that have flag VERSION_INDEPENDENT_COMP_ID
735 # This should be all components with constant API, for example URE
997
998 # Collecting all component names, that have flag VERSION_INDEPENDENT_COMP_ID
999 # This should be all components with constant API, for example URE
736 if ( $styles =~ /\bVERSION_INDEPENDENT_COMP_ID\b/ )
1000 if (has_style($file->{'Styles'}, "VERSION_INDEPENDENT_COMP_ID"))
737 {
1001 {
738 $installer::globals::base_independent_components{$onefile->{'componentname'}} = 1;
1002 $installer::globals::base_independent_components{$file->{'componentname'}} = 1;
739 }
740
1003 }
1004
741 # Collecting all component ids, that are defined at files in scp project (should not be used anymore)
742 if ( $onefile->{'CompID'} )
743 {
744 if ( ! exists($installer::globals::componentid{$onefile->{'componentname'}}))
745 {
746 $installer::globals::componentid{$onefile->{'componentname'}} = $onefile->{'CompID'};
747 }
748 else
749 {
750 if ( $installer::globals::componentid{$onefile->{'componentname'}} ne $onefile->{'CompID'} )
751 {
752 installer::exiter::exit_program("ERROR: There is already a ComponentID for component \"$onefile->{'componentname'}\" : \"$installer::globals::componentid{$onefile->{'componentname'}}\" . File \"$onefile->{'gid'}\" uses \"$onefile->{'CompID'}\" !", "create_files_table");
753 }
754 }
755
756 # Also checking vice versa. Is this ComponentID already used? If yes, is the componentname the same?
757
758 if ( ! exists($installer::globals::comparecomponentname{$onefile->{'CompID'}}))
759 {
760 $installer::globals::comparecomponentname{$onefile->{'CompID'}} = $onefile->{'componentname'};
761 }
762 else
763 {
764 if ( $installer::globals::comparecomponentname{$onefile->{'CompID'}} ne $onefile->{'componentname'} )
765 {
766 installer::exiter::exit_program("ERROR: There is already a component for ComponentID \"$onefile->{'CompID'}\" : \"$installer::globals::comparecomponentname{$onefile->{'CompID'}}\" . File \"$onefile->{'gid'}\" has same component id but is included in component \"$onefile->{'componentname'}\" !", "create_files_table");
767 }
768 }
769 }
770
771 # Collecting all language specific conditions
772 # if ( $onefile->{'haslanguagemodule'} )
773 if ( $onefile->{'ismultilingual'} )
1005 # Special handling for files in PREDEFINED_OSSHELLNEWDIR. These components
1006 # need as KeyPath a RegistryItem in HKCU
1007 if ($file->{'needs_user_registry_key'}
1008 || (defined $file->{'Dir'} && $file->{'Dir'} =~ /\bPREDEFINED_OSSHELLNEWDIR\b/))
774 {
1009 {
775 if ( $onefile->{'ComponentCondition'} ) { installer::exiter::exit_program("ERROR: Cannot set language condition. There is already another component condition for file $onefile->{'gid'}: \"$onefile->{'ComponentCondition'}\" !", "create_files_table"); }
1010 my $keypath = generate_registry_keypath($file);
1011 $file->{'userregkeypath'} = $keypath;
1012 push(@installer::globals::userregistrycollector, $file);
1013 $installer::globals::addeduserregitrykeys = 1;
1014 }
776
1015
777 if ( $onefile->{'specificlanguage'} eq "" ) { installer::exiter::exit_program("ERROR: There is no specific language for file at language module: $onefile->{'gid'} !", "create_files_table"); }
778 my $locallanguage = $onefile->{'specificlanguage'};
779 my $property = "IS" . $file{'Language'};
780 my $value = 1;
781 my $condition = $property . "=" . $value;
782
783 $onefile->{'ComponentCondition'} = $condition;
1016 $file->{'windows_language'} = get_language_for_file($file);
784
1017
785 if ( exists($installer::globals::componentcondition{$file{'Component_'}}))
786 {
787 if ( $installer::globals::componentcondition{$file{'Component_'}} ne $condition ) { installer::exiter::exit_program("ERROR: There is already another component condition for file $onefile->{'gid'}: \"$installer::globals::componentcondition{$file{'Component_'}}\" and \"$condition\" !", "create_files_table"); }
788 }
789 else
790 {
791 $installer::globals::componentcondition{$file{'Component_'}} = $condition;
792 }
1018 process_language_conditions($file);
1019 }
793
1020
794 # collecting all properties for table Property
795 if ( ! exists($installer::globals::languageproperties{$property}) ) { $installer::globals::languageproperties{$property} = $value; }
796 }
1021 # The filenames must be collected because of uniqueness
1022 # 01-44-~1.DAT, 01-44-~2.DAT, ...
1023 my %shortnames = ();
1024 foreach my $file (@$file_list)
1025 {
1026 $file->{'short_name'} = generate_filename_for_filetable($file, \%shortnames);
1027 }
1028}
797
1029
798 if ( $installer::globals::prepare_winpatch )
799 {
800 my $path = $onefile->{'sourcepath'};
801 if ( $^O =~ /cygwin/i ) { $path = $onefile->{'cyg_sourcepath'}; }
802
1030
803 open(FILE, $path) or die "ERROR: Can't open $path for creating file hash";
804 binmode(FILE);
805 my $hashinfo = pack("l", 20);
806 $hashinfo .= Digest::MD5->new->addfile(*FILE)->digest;
807
1031
808 my @i = unpack ('x[l]l4', $hashinfo);
809 $oneline = $file{'File'} . "\t" .
810 "0" . "\t" .
811 $i[0] . "\t" .
812 $i[1] . "\t" .
813 $i[2] . "\t" .
814 $i[3] . "\n";
815 push (@filehashtable, $oneline);
816 }
817
1032
818 # Saving the sequence number in a hash with uniquefilename as key.
819 # This is used for better performance in "save_packorder"
820 $installer::globals::uniquefilenamesequence{$onefile->{'uniquename'}} = $onefile->{'sequencenumber'};
821
822 # Special handling for files in PREDEFINED_OSSHELLNEWDIR. These components
823 # need as KeyPath a RegistryItem in HKCU
824 my $destdir = "";
825 if ( $onefile->{'Dir'} ) { $destdir = $onefile->{'Dir'}; }
1033sub create_file_table_data ($$)
1034{
1035 my ($file_list, $allvariables) = @_;
1036
1037 my @file_table_data = ();
1038 foreach my $file (@$file_list)
1039 {
1040 my $attributes;
1041 if (has_style($file->{'Styles'}, "DONT_PACK"))
1042 {
1043 # Sourcefile is unpacked (msidbFileAttributesNoncompressed).
1044 $attributes = "8192";
1045 }
1046 else
1047 {
1048 # Sourcefile is packed (msidbFileAttributesCompressed).
1049 $attributes = "16384";
1050 }
826
1051
827 if (( $destdir =~ /\bPREDEFINED_OSSHELLNEWDIR\b/ ) || ( $onefile->{'needs_user_registry_key'} ))
828 {
829 my $keypath = generate_registry_keypath($onefile);
830 $onefile->{'userregkeypath'} = $keypath;
831 push(@installer::globals::userregistrycollector, $onefile);
832 $installer::globals::addeduserregitrykeys = 1;
833 }
1052 my $row_data = {
1053 'File' => $file->{'uniquename'},
1054 'Component_' => $file->{'componentname'},
1055 'FileName' => $file->{'short_name'},
1056 'FileSize' => get_filesize($file),
1057 'Version' => get_fileversion($file, $allvariables),
1058 'Language' => $file->{'windows_language'},
1059 'Attributes' => $attributes,
1060 'Sequence' => $file->{'sequencenumber'}
1061 };
1062 push @file_table_data, $row_data;
834 }
835
1063 }
1064
836 # putting content from %allfilecomponents to $allfilecomponentsref for later usage
837 foreach $localkey (keys %allfilecomponents ) { push( @{$allfilecomponentsref}, $localkey); }
1065 return \@file_table_data;
1066}
838
1067
839 my $filetablename = $basedir . $installer::globals::separator . "File.idt";
1068
1069
1070
1071sub collect_components ($)
1072{
1073 my ($file_list) = @_;
1074
1075 my %components = ();
1076 foreach my $file (@$file_list)
1077 {
1078 $components{$file->{'componentname'}} = 1;
1079 }
1080 return keys %components;
1081}
1082
1083
1084
1085
1086=head filter_files($file_list, $allvariables)
1087
1088 Filter out Java files when not building a Java product.
1089
1090 Is this still triggered?
1091
1092=cut
1093sub filter_files ($$)
1094{
1095 my ($file_list, $allvariables) = @_;
1096
1097 if ($allvariables->{'JAVAPRODUCT'})
1098 {
1099 return $file_list;
1100 }
1101 else
1102 {
1103 my @filtered_files = ();
1104 foreach my $file (@$file_list)
1105 {
1106 if ( ! has_style($file->{'Styles'}, "JAVAFILE"))
1107 {
1108 push @filtered_files, $file;
1109 }
1110 }
1111 return \@filtered_files;
1112 }
1113}
1114
1115
1116
1117
1118# Structure of the files table:
1119# File Component_ FileName FileSize Version Language Attributes Sequence
1120sub create_file_table ($$)
1121{
1122 my ($file_table_data, $basedir) = @_;
1123
1124 # Set up the 'File' table.
1125 my @filetable = ();
1126 installer::windows::idtglobal::write_idt_header(\@filetable, "file");
1127 my @keys = ('File', 'Component_', 'FileName', 'FileSize', 'Version', 'Language', 'Attributes', 'Sequence');
1128 my $index = 0;
1129 foreach my $row_data (@$file_table_data)
1130 {
1131 ++$index;
1132 my @values = map {$row_data->{$_}} @keys;
1133 my $line = join("\t", @values) . "\n";
1134 push(@filetable, $line);
1135 }
1136
1137 my $filetablename = $basedir . $installer::globals::separator . "File.idt";
840 installer::files::save_file($filetablename ,\@filetable);
841 $installer::logger::Lang->print("\n");
842 $installer::logger::Lang->printf("Created idt file: %s\n", $filetablename);
1138 installer::files::save_file($filetablename ,\@filetable);
1139 $installer::logger::Lang->print("\n");
1140 $installer::logger::Lang->printf("Created idt file: %s\n", $filetablename);
1141}
843
1142
844 $installer::logger::Lang->add_timestamp("Performance Info: File Table end");
845
846 my $filehashtablename = $basedir . $installer::globals::separator . "MsiFileHash.idt";
847 installer::files::save_file($filehashtablename ,\@filehashtable);
848 $installer::logger::Lang->print("\n");
849 $installer::logger::Lang->printf("Created idt file: %s\n", $filehashtablename);
850
1143
851 # Now the new files can be added to the files collector (only in update packaging processes)
852 if ( $installer::globals::newfilesexist )
853 {
854 foreach my $seq (sort keys %installer::globals::newfilescollector) { push(@allfiles, $installer::globals::newfilescollector{$seq}) }
855 }
856
1144
857 return \@allfiles;
1145
1146sub create_filehash_table ($$)
1147{
1148 my ($file_list, $basedir) = @_;
1149
1150 my @filehashtable = ();
1151
1152 if ( $installer::globals::prepare_winpatch )
1153 {
1154
1155 installer::windows::idtglobal::write_idt_header(\@filehashtable, "filehash");
1156
1157 foreach my $file (@$file_list)
1158 {
1159 my $path = $file->{'sourcepath'};
1160 if ($^O =~ /cygwin/i)
1161 {
1162 $path = $file->{'cyg_sourcepath'};
1163 }
1164
1165 open(FILE, $path) or die "ERROR: Can't open $path for creating file hash";
1166 binmode(FILE);
1167 my $hashinfo = pack("l", 20);
1168 $hashinfo .= Digest::MD5->new->addfile(*FILE)->digest;
1169
1170 my @i = unpack ('x[l]l4', $hashinfo);
1171 my $oneline = join("\t",
1172 (
1173 $file->{'uniquename'},
1174 "0",
1175 @i
1176 ));
1177 push (@filehashtable, $oneline . "\n");
1178 }
1179
1180 my $filehashtablename = $basedir . $installer::globals::separator . "MsiFileHash.idt";
1181 installer::files::save_file($filehashtablename ,\@filehashtable);
1182 $installer::logger::Lang->print("\n");
1183 $installer::logger::Lang->printf("Created idt file: %s\n", $filehashtablename);
1184 }
858}
859
1185}
1186
1187
8601;
11881;