| #************************************************************** |
| # |
| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| # |
| #************************************************************** |
| |
| |
| |
| package installer::archivefiles; |
| |
| use Archive::Zip qw( :ERROR_CODES :CONSTANTS ); |
| use installer::converter; |
| use installer::existence; |
| use installer::exiter; |
| use installer::files; |
| use installer::globals; |
| use installer::logger; |
| use installer::pathanalyzer; |
| use installer::systemactions; |
| |
| ################################################################# |
| # Changing the name for files with flag RENAME_TO_LANGUAGE |
| ################################################################# |
| |
| sub put_language_into_name |
| { |
| my ( $oldname, $onelanguage ) = @_; |
| |
| my $newname = ""; |
| |
| my $filename = ""; |
| my $extension = ""; |
| |
| if ( $oldname =~ /en-US/ ) # files, that contain the language in the file name |
| { |
| $newname = $oldname; |
| $newname =~ s/en-US/$onelanguage/; |
| } |
| else # files, that do not contain the language in the file name |
| { |
| if ( $oldname =~ /^\s*(.*)(\..*?)\s*$/ ) # files with extension |
| { |
| $filename = $1; |
| $extension = $2; |
| } |
| else |
| { |
| $filename = $oldname; |
| $extension = ""; |
| } |
| |
| $newname = $1 . "_" . $onelanguage . $2; |
| } |
| |
| return $newname; |
| } |
| |
| ################################################################# |
| # Converting patchfiles string into array |
| ################################################################# |
| |
| sub get_patch_file_list |
| { |
| my ( $patchfilestring ) = @_; |
| |
| $patchfilestring =~ s/^\s*\(?//; |
| $patchfilestring =~ s/\)?\s*$//; |
| $patchfilestring =~ s/^\s*\///; |
| $patchfilestring =~ s/^\s*\\//; |
| |
| my $patchfilesarray = installer::converter::convert_stringlist_into_array_without_linebreak_and_quotes(\$patchfilestring, ","); |
| |
| return $patchfilesarray; |
| } |
| |
| ################################################################# |
| # Reading all executables in the "manifest.xml" |
| ################################################################# |
| |
| sub get_all_executables_from_manifest |
| { |
| my ($unzipdir, $manifestfile, $executable_files_in_extensions) = @_; |
| |
| my $is_executable = 0; |
| |
| for ( my $i = 0; $i <= $#{$manifestfile}; $i++ ) |
| { |
| my $line = ${$manifestfile}[$i]; |
| |
| if ( $line =~ /\"application\/vnd\.sun\.star\.executable\"/ ) { $is_executable = 1; } |
| |
| if (( $line =~ /manifest\:full\-path=\"(.*?)\"/ ) && ( $is_executable )) |
| { |
| my $filename = $unzipdir . $installer::globals::separator . $1; |
| # making only slashes for comparison reasons |
| $filename =~ s/\\/\//g; |
| $executable_files_in_extensions->{$filename} = 1; |
| } |
| |
| if ( $line =~ /\/\>/ ) { $is_executable = 0; } |
| } |
| } |
| |
| ################################################################# |
| # Reading the "manifest.xml" in extensions and determine, if |
| # there are executable files |
| ################################################################# |
| |
| sub collect_all_executable_files_in_extensions |
| { |
| my ($unzipdir, $executable_files_in_extensions) = @_; |
| |
| $unzipdir =~ s/\Q$installer::globals::separator\E\s*$//; |
| |
| my $manifestfilename = $unzipdir . $installer::globals::separator . "META-INF" . $installer::globals::separator . "manifest.xml"; |
| |
| if ( -f $manifestfilename ) |
| { |
| my $manifestfile = installer::files::read_file($manifestfilename); |
| get_all_executables_from_manifest($unzipdir, $manifestfile, $executable_files_in_extensions); |
| } |
| } |
| |
| ################################################################# |
| # Analyzing files with flag ARCHIVE |
| ################################################################# |
| |
| sub resolving_archive_flag |
| { |
| my ($filesarrayref, $additionalpathsref, $languagestringref, $loggingdir) = @_; |
| |
| if ( $installer::globals::debug ) { installer::logger::debuginfo("installer::archivefiles::resolving_archive_flag : $#{$filesarrayref} : $#{$additionalpathsref} : $$languagestringref : $loggingdir"); } |
| |
| my @newallfilesarray = (); |
| |
| my ($systemcall, $returnvalue, $infoline); |
| |
| my $unziplistfile = $loggingdir . "unziplist_" . $installer::globals::build . "_" . $installer::globals::compiler . "_" . $$languagestringref . ".txt"; |
| |
| my $platformunzipdirbase = installer::systemactions::create_directories("zip", $languagestringref); |
| push(@installer::globals::removedirs, $platformunzipdirbase); |
| |
| installer::logger::include_header_into_logfile("Files with flag ARCHIVE:"); |
| |
| my $repeat_unzip = 0; |
| my $maxcounter = 0; |
| |
| for ( my $i = 0; $i <= $#{$filesarrayref}; $i++ ) |
| { |
| if ( $repeat_unzip ) { $i--; } # decreasing the counter |
| |
| my $onefile = ${$filesarrayref}[$i]; |
| my $styles = ""; |
| |
| if ( $onefile->{'Styles'} ) { $styles = $onefile->{'Styles'}; } |
| |
| if ( $styles =~ /\bARCHIVE\b/ ) # copying, unzipping and changing the file list |
| { |
| my $iscommonfile = 0; |
| my $sourcepath = $onefile->{'sourcepath'}; |
| |
| if ( $sourcepath =~ /\Q$installer::globals::separator\E\bcommon$installer::globals::productextension\Q$installer::globals::separator\E/ ) # /common/ or /common.pro/ |
| { |
| $iscommonfile = 1; |
| } |
| |
| my $use_internal_rights = 0; |
| if ( $styles =~ /\bUSE_INTERNAL_RIGHTS\b/ ) { $use_internal_rights = 1; } # using the rights used inside the zip file |
| |
| my $rename_to_language = 0; |
| if ( $styles =~ /\bRENAME_TO_LANGUAGE\b/ ) { $rename_to_language = 1; } # special handling for renamed files (scriptitems.pm) |
| |
| my %executable_files_in_extensions = (); |
| my $set_executable_privileges = 0; # setting privileges for exectables is required for oxt files |
| if ( $onefile->{'Name'} =~ /\.oxt\s*$/ ) { $set_executable_privileges = 1; } |
| |
| # mechanism to select files from an archive files |
| my $select_files = 0; |
| my $selectlistfiles = ""; |
| my @keptfiles = (); |
| if ( $onefile->{'Selectfiles'} ) |
| { |
| $select_files = 1; |
| $selectlistfiles = get_patch_file_list( $onefile->{'Selectfiles'} ); |
| $installer::logging::Lang->printf("Selected file list defined at file: %s :\n", $onefile->{'Name'}); |
| foreach my $line (@$selectlistfiles) |
| { |
| $installer::logging::Lang->printf("\"%s\"\n", $line); |
| } |
| } |
| |
| if ( $onefile->{'Selectfiles'} ) { $onefile->{'Selectfiles'} = ""; } # Selected files list no longer required |
| |
| # mechanism to define patch files inside an archive files |
| my $select_patch_files = 0; |
| my $patchlistfiles = ""; |
| my @keptpatchflags = (); |
| if (( $styles =~ /\bPATCH\b/ ) && ( $onefile->{'Patchfiles'} ) && ( $installer::globals::patch )) |
| { |
| $select_patch_files = 1; # special handling if a Patchlist is defined |
| $patchlistfiles = get_patch_file_list( $onefile->{'Patchfiles'} ); |
| $installer::logger::Lang->printf("Patch file list defined at file: %s :\n", $onefile->{'Name'}); |
| foreach my $line (@$patchlistfiles) |
| { |
| $installer::logger::Lang->printf("\"%s\"\n", $line); |
| } |
| } |
| |
| if ( $onefile->{'Patchfiles'} ) { $onefile->{'Patchfiles'} = ""; } # Patch file list no longer required |
| |
| # creating directories |
| |
| my $onelanguage = $onefile->{'specificlanguage'}; |
| |
| # files without language into directory "00" |
| |
| if ($onelanguage eq "") { $onelanguage = "00"; } |
| |
| my $unzipdir; |
| |
| # if ($iscommonfile) { $unzipdir = $commonunzipdirbase . $installer::globals::separator . $onelanguage . $installer::globals::separator; } |
| # else { $unzipdir = $platformunzipdirbase . $installer::globals::separator . $onelanguage . $installer::globals::separator; } |
| |
| $unzipdir = $platformunzipdirbase . $installer::globals::separator . $onelanguage . $installer::globals::separator; |
| |
| installer::systemactions::create_directory($unzipdir); # creating language specific subdirectories |
| |
| my $onefilename = $onefile->{'Name'}; |
| $onefilename =~ s/\./\_/g; # creating new directory name |
| $onefilename =~ s/\//\_/g; # only because of /letter/fontunxpsprint.zip, the only zip file with path |
| $unzipdir = $unzipdir . $onefilename . $installer::globals::separator; |
| |
| if ( $installer::globals::dounzip ) { installer::systemactions::create_directory($unzipdir); } # creating subdirectories with the names of the zipfiles |
| |
| my $zip = Archive::Zip->new(); |
| if ( $zip->read($sourcepath) != AZ_OK ) |
| { |
| $installer::logger::Lang->printf("ERROR: Could not unzip %s\n", $sourcepath); |
| } |
| |
| my $counter = 0; |
| my $contains_dll = 0; |
| foreach my $member ( $zip->memberNames() ) |
| { |
| $counter++; |
| if ( $member =~ /.dll\s*$/ ) { $contains_dll = 1; } |
| } |
| |
| if (! ( $counter > 0 )) # the zipfile is empty |
| { |
| $installer::logger::Lang->printf("ERROR: Could not unzip %s\n", $sourcepath); |
| } |
| else |
| { |
| if ( $installer::globals::dounzip ) # really unpacking the files |
| { |
| if ( $zip->extractTree("", $unzipdir) != AZ_OK ) |
| { |
| installer::exiter::exit_program("ERROR: can not unzip ".$sourcepath, "resolving_archive_flag"); |
| } |
| |
| if (( $^O =~ /cygwin/i ) && ( $contains_dll )) |
| { |
| # Make dll's executable |
| $systemcall = "cd $unzipdir; find . -name \\*.dll -exec chmod 775 \{\} \\\;"; |
| $returnvalue = system($systemcall); |
| $installer::logger::Lang->printf("Systemcall: %s\n", $systemcall); |
| |
| if ($returnvalue) |
| { |
| $installer::logger::Lang->printf("ERROR: Could not execute \"\"!\n", $systemcall); |
| } |
| } |
| |
| if ( ! $installer::globals::iswindowsbuild ) |
| { |
| # Setting unix rights to "775" for all created directories inside the package |
| |
| $systemcall = "cd $unzipdir; find . -type d -exec chmod 775 \{\} \\\;"; |
| $returnvalue = system($systemcall); |
| $installer::logger::Lang->printf("Systemcall: %s\n", $systemcall); |
| if ($returnvalue) |
| { |
| $installer::logger::Lang->printf("ERROR: Could not execute \"\"!\n", $systemcall); |
| } |
| } |
| |
| # Selecting names of executable files in extensions |
| if ( $set_executable_privileges ) |
| { |
| collect_all_executable_files_in_extensions($unzipdir, \%executable_files_in_extensions); |
| } |
| } |
| |
| my $zipfileref = \@zipfile; |
| my $unziperror = 0; |
| |
| foreach my $zipname ( $zip->memberNames() ) |
| { |
| # Format from Archive:::Zip : |
| # dir1/ |
| # dir1/so7drawing.desktop |
| |
| # some directories and files (from the help) start with "./simpress.idx" |
| |
| $zipname =~ s/^\s*\.\///; |
| |
| if ($installer::globals::iswin and $^O =~ /MSWin/i) { $zipname =~ s/\//\\/g; } |
| |
| if ( $zipname =~ /\Q$installer::globals::separator\E\s*$/ ) # slash or backslash at the end characterizes a directory |
| { |
| $zipname = $zipname . "\n"; |
| push(@{$additionalpathsref}, $zipname); |
| |
| # Also needed here: |
| # Name |
| # Language |
| # ismultilingual |
| # Basedirectory |
| |
| # This is not needed, because the list of all directories for the |
| # epm list file is generated from the destination directories of the |
| # files included in the product! |
| } |
| else |
| { |
| my %newfile = (); |
| %newfile = %{$onefile}; |
| $newfile{'Name'} = $zipname; |
| my $destination = $onefile->{'destination'}; |
| installer::pathanalyzer::get_path_from_fullqualifiedname(\$destination); |
| $newfile{'destination'} = $destination . $zipname; |
| $newfile{'sourcepath'} = $unzipdir . $zipname; |
| $newfile{'zipfilename'} = $onefile->{'Name'}; |
| $newfile{'zipfilesource'} = $onefile->{'sourcepath'}; |
| $newfile{'zipfiledestination'} = $onefile->{'destination'}; |
| |
| if (( $use_internal_rights ) && ( ! $installer::globals::iswin )) |
| { |
| my $value = sprintf("%o", (stat($newfile{'sourcepath'}))[2]); |
| $newfile{'UnixRights'} = substr($value, 3); |
| $installer::logger::Lang->printf( |
| "Setting unix rights for \"%s\" to \"%s\"\n", |
| $newfile{'sourcepath'}, |
| $newfile{'UnixRights'}); |
| } |
| |
| if ( $set_executable_privileges ) |
| { |
| # All paths to executables are saved in the hash %executable_files_in_extensions |
| my $compare_path = $newfile{'sourcepath'}; |
| $compare_path =~ s/\\/\//g; # contains only slashes for comparison reasons |
| if ( exists($executable_files_in_extensions{$compare_path}) ) |
| { |
| $newfile{'UnixRights'} = "775"; |
| $installer::logger::Lang->printf( |
| "Executable in Extension: Setting unix rights for \"%s\" to \"%s\"\n", |
| $newfile{'sourcepath'}, |
| $newfile{'UnixRights'}); |
| } |
| } |
| |
| if ( $select_files ) |
| { |
| if ( ! installer::existence::exists_in_array($zipname,$selectlistfiles) ) |
| { |
| $installer::logger::Lang->printf("Removing from ARCHIVE file %s: %s\n", |
| $onefilename, |
| $zipname); |
| next; # ignoring files, that are not included in $selectlistfiles |
| } |
| else |
| { |
| $installer::logger::Lang->printf("Keeping from ARCHIVE file %s: \n", |
| $onefilename, |
| $zipname); |
| push( @keptfiles, $zipname); # collecting all kept files |
| } |
| } |
| |
| if ( $select_patch_files ) |
| { |
| # Is this file listed in the Patchfile list? |
| # $zipname (filename including path in zip file has to be listed in patchfile list |
| |
| if ( ! installer::existence::exists_in_array($zipname,$patchlistfiles) ) |
| { |
| $newfile{'Styles'} =~ s/\bPATCH\b//; # removing the flag PATCH |
| $newfile{'Styles'} =~ s/\,\s*\,/\,/; |
| $newfile{'Styles'} =~ s/\(\s*\,/\(/; |
| $newfile{'Styles'} =~ s/\,\s*\)/\)/; |
| } |
| else |
| { |
| push( @keptpatchflags, $zipname); # collecting all PATCH flags |
| } |
| } |
| |
| if ( $rename_to_language ) |
| { |
| my $newzipname = put_language_into_name($zipname, $onelanguage); |
| my $oldfilename = $unzipdir . $zipname; |
| my $newfilename = $unzipdir . $newzipname; |
| |
| installer::systemactions::copy_one_file($oldfilename, $newfilename); |
| |
| $newfile{'Name'} = $newzipname; |
| $newfile{'destination'} = $destination . $newzipname; |
| $newfile{'sourcepath'} = $unzipdir . $newzipname; |
| |
| $installer::logger::Lang->printf("RENAME_TO_LANGUAGE: Using %s instead of %s!\n", |
| $newzipname, |
| $zipname); |
| } |
| |
| my $sourcefiletest = $unzipdir . $zipname; |
| if ( ! -f $sourcefiletest ) |
| { |
| $installer::logger::Lang->printf("ATTENTION: Unzip failed for %s!\n", $sourcefiletest); |
| $unziperror = 1; |
| } |
| |
| # only adding the new line into the files array, if not in repeat modus |
| |
| if ( ! $repeat_unzip ) { push(@newallfilesarray, \%newfile); } |
| } |
| } |
| |
| # Comparing the content of @keptfiles and $selectlistfiles |
| # Do all files from the list of selected files are stored in @keptfiles ? |
| # @keptfiles contains only files included in $selectlistfiles. But are all |
| # files from $selectlistfiles included in @keptfiles? |
| |
| if ( $select_files ) |
| { |
| $installer::logger::Lang->printf("SELECTLIST: Number of files in file selection list: %d\n", |
| scalar @$selectlistfiles); |
| $installer::logger::Lang->printf("SELECTLIST: Number of kept files: %d\n", |
| scalar @keptfiles); |
| |
| foreach my $name (@keptfiles) |
| { |
| $installer::logger::Lang->printf("KEPT FILES: %s\n", $name); |
| } |
| |
| foreach my $name (@$selectlistfiles) |
| { |
| if ( ! installer::existence::exists_in_array($name,\@keptfiles) ) |
| { |
| $installer::logger::Lang->printf( |
| "WARNING: %s not included in install set (does not exist in zip file)!\n", |
| $name);; |
| } |
| } |
| } |
| |
| # Comparing the content of @keptpatchflags and $patchlistfiles |
| # Do all files from the patch list have a PATCH flag ? |
| # @keptpatchflags contains only files included in $patchlistfiles. But are all |
| # files from $patchlistfiles included in @keptpatchflags? |
| |
| if ( $select_patch_files ) |
| { |
| $installer::logger::Lang->printf("PATCHLIST: Number of files in patch list: %d\n", |
| scalar @$patchlistfiles); |
| $installer::logger::Lang->printf("PATCHLIST: Number of kept PATCH flags: %d\n", |
| scalar @keptpatchflags); |
| |
| foreach my $flag (@keptpatchflags) |
| { |
| $installer::logger::Lang->printf("KEPT PATCH FLAGS: %s\n", |
| $flag); |
| } |
| |
| foreach my $name (@$patchlistfiles) |
| { |
| if ( ! installer::existence::exists_in_array($name,\@keptpatchflags) ) |
| { |
| $installer::logger::Lang->printf( |
| "WARNING: %s did not keep PATCH flag (does not exist in zip file)!\n", |
| $name); |
| } |
| } |
| } |
| |
| if ( $unziperror ) |
| { |
| installer::logger::print_warning( "Repeating to unpack $sourcepath! \n" ); |
| $installer::logger::Lang->printf("ATTENTION: Repeating to unpack %s!\n", $sourcepath); |
| $repeat_unzip = 1; |
| $maxcounter++; |
| |
| if ( $maxcounter == 5 ) # exiting the program |
| { |
| installer::exiter::exit_program("ERROR: Failed to unzip $sourcepath !", "resolving_archive_flag"); |
| } |
| } |
| else |
| { |
| $installer::logger::Lang->printf("Info: %s unpacked without problems !\n", $sourcepath); |
| $repeat_unzip = 0; |
| $maxcounter = 0; |
| } |
| } |
| } |
| else # nothing to do here, no zipped file (no ARCHIVE flag) |
| { |
| push(@newallfilesarray, $onefile); |
| } |
| } |
| |
| $installer::logger::Lang->print("\n"); |
| |
| return \@newallfilesarray; |
| } |
| |
| |
| 1; |