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::media;
25
26use installer::exiter;
27use installer::files;
28use installer::globals;
29use installer::windows::idtglobal;
30
31##############################################################
32# Returning the diskid for the media table.
33##############################################################
34
35sub get_media_diskid
36{
37	my ($id) = @_;
38
39	return $id;
40}
41
42##############################################################
43# Returning the lastsequence for the media table.
44##############################################################
45
46sub get_media_lastsequence
47{
48	my ($fileref) = @_;
49
50	return $fileref->{'sequencenumber'};
51}
52
53##############################################################
54# Returning the diskprompt for the media table.
55##############################################################
56
57sub get_media_diskprompt
58{
59	return 1;
60}
61
62##############################################################
63# Returning the cabinet file name for the media table.
64##############################################################
65
66sub get_media_cabinet
67{
68	my ($id) = @_;
69
70	my $number = 1000 + $id;
71	my $filename = "f_" . $number . ".cab";
72
73	if ( $installer::globals::include_cab_in_msi ) { $filename = "\#" . $filename; }
74
75	return $filename;
76}
77
78##############################################################
79# Returning the volumelabel for the media table.
80##############################################################
81
82sub get_media_volumelabel
83{
84	return "DISK1";
85}
86
87##############################################################
88# Returning the source for the media table.
89##############################################################
90
91sub get_media_source
92{
93	return "";
94}
95
96##############################################################
97# Saving the cabinet file name in the files collector.
98# This is useful for making a list to connect the
99# source of each file with the destination cabinet file.
100##############################################################
101
102sub set_cabinetfilename_for_component_in_file_collector
103{
104	my ($cabinetfilename, $filesref, $componentname, $max) = @_;
105
106	for ( my $i = 0; $i <= $max; $i++ )
107	{
108		my $onefile = ${$filesref}[$i];
109		my $component = $onefile->{'componentname'};
110
111		if ( $component eq $componentname )
112		{
113			my $cabinet = "";
114
115			if ( $onefile->{'cabinet'} ) { $cabinet = $onefile->{'cabinet'}; }
116
117			if ( $cabinet eq "" )
118			{
119				$onefile->{'cabinet'} = $cabinetfilename;
120			}
121		}
122	}
123}
124
125#################################################
126# Creating the cab file name dynamically
127#################################################
128
129sub generate_cab_filename_for_some_cabs
130{
131	my ( $allvariables, $id ) = @_;
132
133	my $name = $allvariables->{'PRODUCTNAME'};
134
135	$name = lc($name);
136	$name =~ s/\.//g;
137	$name =~ s/\s//g;
138
139	# possibility to overwrite the name with variable CABFILENAME
140	if ( $allvariables->{'CABFILENAME'} ) { $name = $allvariables->{'CABFILENAME'}; }
141
142	$name = $name . $id . ".cab";
143
144	if ( $installer::globals::include_cab_in_msi ) { $name = "\#" . $name; }
145
146	return $name;
147}
148
149#################################################
150# Creating the cab file name for cab files
151# defined in packages.
152#################################################
153
154sub get_cabfilename
155{
156	my ($name) = @_;
157
158	if ( $installer::globals::include_cab_in_msi ) { $name = "\#" . $name; }
159
160	return $name;
161}
162
163#################################################
164# Creating the cab file name dynamically
165#################################################
166
167sub generate_cab_filename
168{
169	my ( $allvariables ) = @_;
170
171	my $name = $allvariables->{'PRODUCTNAME'};
172
173	$name = lc($name);
174	$name =~ s/\.//g;
175	$name =~ s/\s//g;
176
177	# possibility to overwrite the name with variable CABFILENAME
178	if ( $allvariables->{'CABFILENAME'} ) { $name = $allvariables->{'CABFILENAME'}; }
179
180	$name = $name . ".cab";
181
182	if ( $installer::globals::include_cab_in_msi ) { $name = "\#" . $name; }
183
184	return $name;
185}
186
187sub get_maximum_filenumber
188{
189	my ($allfiles, $maxcabfilenumber) = @_;
190
191	my $maxfile = 0;
192
193	while ( ! ( $allfiles%$maxcabfilenumber == 0 ))
194	{
195		$allfiles++;
196	}
197
198	$maxfile = $allfiles / $maxcabfilenumber;
199
200	$maxfile++;					# for securitry
201
202	return $maxfile;
203}
204
205#################################################################################
206# Setting the last sequence for the cabinet files
207#################################################################################
208
209sub get_last_sequence
210{
211	my ( $cabfilename, $alludpatelastsequences ) = @_;
212
213	my $sequence = 0;
214
215	if (( $installer::globals::updatedatabase ) && ( exists($alludpatelastsequences->{$cabfilename}) ))
216	{
217		$sequence = $alludpatelastsequences->{$cabfilename};
218	}
219	else
220	{
221		$sequence = $installer::globals::lastsequence{$cabfilename};
222	}
223
224	return $sequence;
225}
226
227#################################################################################
228# Creating the file Media.idt dynamically
229# Content:
230# DiskId LastSequence DiskPrompt Cabinet VolumeLabel Source
231# Idea: Every component is packed into each own cab file
232#################################################################################
233
234sub create_media_table
235{
236	my ($filesref, $basedir, $allvariables, $alludpatelastsequences, $allupdatediskids) = @_;
237
238	my @mediatable = ();
239
240	my $diskid = 0;
241
242	installer::windows::idtglobal::write_idt_header(\@mediatable, "media");
243
244	if ( $allvariables->{'INCLUDE_CAB_IN_MSI'} ) { $installer::globals::include_cab_in_msi = 1; }
245
246	if ( $installer::globals::use_packages_for_cabs )
247	{
248		my $cabfile;
249		foreach $cabfile ( sort keys %installer::globals::lastsequence )
250		{
251			my %media = ();
252			$diskid++;
253
254			$media{'DiskId'} = get_media_diskid($diskid);
255			$media{'LastSequence'} = get_last_sequence($cabfile, $alludpatelastsequences);
256			$media{'DiskPrompt'} = get_media_diskprompt();
257			$media{'Cabinet'} = get_cabfilename($cabfile);
258			$media{'VolumeLabel'} = get_media_volumelabel();
259			$media{'Source'} = get_media_source();
260
261			my $oneline = $media{'DiskId'} . "\t" . $media{'LastSequence'} . "\t" . $media{'DiskPrompt'} . "\t"
262						. $media{'Cabinet'} . "\t" . $media{'VolumeLabel'} . "\t" . $media{'Source'} . "\n";
263
264			push(@mediatable, $oneline);
265
266			# Comparing the disk id with the disk id from update database. Both have to be identical. New files have to be added
267			# to the new pff cabinet file. And existing cab files must not be removed.
268			if ( $installer::globals::updatedatabase )
269			{
270				# Comparing lines in new media table with line from media table in udpate database.
271				if ( exists($allupdatediskids->{$media{'Cabinet'}}) )
272				{
273					if ( $media{'DiskId'} != $allupdatediskids->{$media{'Cabinet'}} )
274					{
275						installer::exiter::exit_program("ERROR: Different DiskIDs for cab file \"$media{'Cabinet'}\".\nCurrent installation set: \"$media{'DiskId'}\", but update database used \"$allupdatediskids->{$media{'Cabinet'}}\".\nWere cabinet files removed or added?", "create_media_table");
276					}
277				}
278				else
279				{
280                    $installer::logger::Lang->printf(
281                        "Warning: Could not find cabinet file \"%s}\" in update database. This seems to be an new cabinet file!?\n",
282                        $media{'Cabinet'});
283				}
284			}
285		}
286
287		# one new cabinet file for all files added after the final release
288		if (( $installer::globals::updatedatabase ) && ( $installer::globals::pfffileexists ))
289		{
290			my %media = ();
291			$diskid++;
292
293			$media{'DiskId'} = get_media_diskid($diskid) + $installer::globals::mergemodulenumber;  # Adding mergemodulenumber, because this files are included later
294			$media{'LastSequence'} = $installer::globals::updatesequencecounter;
295			$media{'DiskPrompt'} = get_media_diskprompt();
296			$media{'Cabinet'} = get_cabfilename($installer::globals::pffcabfilename);
297			$media{'VolumeLabel'} = get_media_volumelabel();
298			$media{'Source'} = get_media_source();
299
300			my $oneline = $media{'DiskId'} . "\t" . $media{'LastSequence'} . "\t" . $media{'DiskPrompt'} . "\t"
301						. $media{'Cabinet'} . "\t" . $media{'VolumeLabel'} . "\t" . $media{'Source'} . "\n";
302
303			push(@mediatable, $oneline);
304		}
305
306	}
307	elsif ( $installer::globals::cab_file_per_component )
308	{
309		for ( my $i = 0; $i <= $#{$filesref}; $i++ )
310		{
311			my $onefile = ${$filesref}[$i];
312			my $nextfile = ${$filesref}[$i+1];
313
314			my $filecomponent = "";
315			my $nextcomponent = "";
316
317			if ( $onefile->{'componentname'} ) { $filecomponent = $onefile->{'componentname'}; }
318			if ( $nextfile->{'componentname'} ) { $nextcomponent = $nextfile->{'componentname'}; }
319
320			if ( $filecomponent eq $nextcomponent )
321			{
322				next;		# nothing to do, this is not the last file of a component
323			}
324
325			my %media = ();
326			$diskid++;
327
328			$media{'DiskId'} = get_media_diskid($diskid);
329			$media{'LastSequence'} = get_media_lastsequence($onefile);
330			$media{'DiskPrompt'} = get_media_diskprompt();
331			$media{'Cabinet'} = get_media_cabinet($diskid);
332			$media{'VolumeLabel'} = get_media_volumelabel();
333			$media{'Source'} = get_media_source();
334
335			my $oneline = $media{'DiskId'} . "\t" . $media{'LastSequence'} . "\t" . $media{'DiskPrompt'} . "\t"
336					. $media{'Cabinet'} . "\t" . $media{'VolumeLabel'} . "\t" . $media{'Source'} . "\n";
337
338			push(@mediatable, $oneline);
339
340			$media{'Cabinet'} =~ s/^\s*\#//;	# removing leading hash
341			set_cabinetfilename_for_component_in_file_collector($media{'Cabinet'}, $filesref, $filecomponent, $i);
342		}
343	}
344	elsif ( $installer::globals::fix_number_of_cab_files )
345	{
346		# number of cabfiles
347		my $maxcabfilenumber = $installer::globals::number_of_cabfiles;
348		if ( $allvariables->{'CABFILENUMBER'} ) { $maxcabfilenumber = $allvariables->{'CABFILENUMBER'}; }
349		my $allfiles = $#{$filesref} + 1;
350		my $maxfilenumber = get_maximum_filenumber($allfiles, $maxcabfilenumber);
351		# my $maxfilenumber = 1000;	# maximum 1000 files in each cabinet file
352		my $cabfilenumber = 0;
353		my $cabfull = 0;
354		my $counter = 0;
355
356		# Sorting of files collector files required !
357		# Attention: The order in the cab file is not guaranteed (especially in udpate process)
358
359		for ( my $i = 0; $i <= $#{$filesref}; $i++ )
360		{
361			if (( $counter >= $maxfilenumber ) || ( $i == $#{$filesref} )) { $cabfull = 1; }
362
363			$counter++; 	 # counting the files in the cab file
364
365			my $onefile = ${$filesref}[$i];
366			my $nextfile = ${$filesref}[$i+1];
367
368			my $filecomponent = "";
369			my $nextcomponent = "";
370
371			if ( $onefile->{'componentname'} ) { $filecomponent = $onefile->{'componentname'}; }
372			if ( $nextfile->{'componentname'} ) { $nextcomponent = $nextfile->{'componentname'}; }
373
374			if ( $filecomponent eq $nextcomponent )	# all files of one component have to be in one cab file
375			{
376				next;		# nothing to do, this is not the last file of a component
377			}
378
379			if ( $cabfull )
380			{
381				my %media = ();
382				$cabfilenumber++;
383
384				$media{'DiskId'} = get_media_diskid($cabfilenumber);
385				# $media{'LastSequence'} = get_media_lastsequence($onefile);
386				$media{'LastSequence'} = $i + 1;	# This should be correct, also for unsorted files collectors
387				$media{'DiskPrompt'} = get_media_diskprompt();
388				$media{'Cabinet'} = generate_cab_filename_for_some_cabs($allvariables, $cabfilenumber);
389				$media{'VolumeLabel'} = get_media_volumelabel();
390				$media{'Source'} = get_media_source();
391
392				my $oneline = $media{'DiskId'} . "\t" . $media{'LastSequence'} . "\t" . $media{'DiskPrompt'} . "\t"
393						. $media{'Cabinet'} . "\t" . $media{'VolumeLabel'} . "\t" . $media{'Source'} . "\n";
394
395				push(@mediatable, $oneline);
396
397				# Saving the cabinet file name in the file collector
398
399				$media{'Cabinet'} =~ s/^\s*\#//;	# removing leading hash
400
401				for ( my $j = 0; $j <= $i; $j++ )
402				{
403					my $onefile = ${$filesref}[$j];
404					if ( ! $onefile->{'cabinet'} ) { $onefile->{'cabinet'} = $media{'Cabinet'}; }
405				}
406
407				$cabfull = 0;
408				$counter = 0;
409			}
410		}
411	}
412	elsif ( $installer::globals::one_cab_file )
413	{
414		my %media = ();
415		$diskid++;
416
417		my $maximumfile = $#{$filesref};
418
419		$media{'DiskId'} = get_media_diskid($diskid);
420		# $media{'LastSequence'} = ${$filesref}[$maximumfile]->{'sequencenumber'};	# sequence number of the last file
421		$media{'LastSequence'} = $maximumfile + 1; # This works also for unsorted file collector
422		$media{'DiskPrompt'} = get_media_diskprompt();
423		$media{'Cabinet'} = generate_cab_filename($allvariables);
424		$media{'VolumeLabel'} = get_media_volumelabel();
425		$media{'Source'} = get_media_source();
426
427		my $oneline = $media{'DiskId'} . "\t" . $media{'LastSequence'} . "\t" . $media{'DiskPrompt'} . "\t"
428					. $media{'Cabinet'} . "\t" . $media{'VolumeLabel'} . "\t" . $media{'Source'} . "\n";
429
430		push(@mediatable, $oneline);
431
432		# Saving the cabinet file name in the file collector
433
434		$media{'Cabinet'} =~ s/^\s*\#//;	# removing leading hash
435
436		for ( my $i = 0; $i <= $#{$filesref}; $i++ )
437		{
438			my $onefile = ${$filesref}[$i];
439			$onefile->{'cabinet'} = $media{'Cabinet'};
440		}
441	}
442	else
443	{
444		installer::exiter::exit_program("ERROR: No cab file specification in globals.pm !", "create_media_table");
445	}
446
447	# Saving the file
448
449	my $mediatablename = $basedir . $installer::globals::separator . "Media.idt";
450	installer::files::save_file($mediatablename ,\@mediatable);
451    $installer::logger::Lang->printf("Created idt file: %s\n", $mediatablename);
452}
453
4541;
455