Compress::Zlib becomes zlib agnostic
[p5sagit/p5-mst-13.2.git] / ext / Compress / Zlib / lib / IO / Compress / Zip.pm
CommitLineData
1a6a8453 1package IO::Compress::Zip ;
2
3use strict ;
4use warnings;
5
6use Compress::Zlib::Common qw(createSelfTiedObject);
7use CompressPlugin::Deflate;
8use CompressPlugin::Identity;
9use IO::Compress::RawDeflate;
10
11require Exporter ;
12
13our ($VERSION, @ISA, @EXPORT_OK, %EXPORT_TAGS, $ZipError);
14
15$VERSION = '2.000_04';
16$ZipError = '';
17
18@ISA = qw(Exporter IO::Compress::RawDeflate);
19@EXPORT_OK = qw( $ZipError zip ) ;
20%EXPORT_TAGS = %IO::Compress::RawDeflate::DEFLATE_CONSTANTS ;
21push @{ $EXPORT_TAGS{all} }, @EXPORT_OK ;
22Exporter::export_ok_tags('all');
23
24
25sub new
26{
27 my $class = shift ;
28
29 my $obj = createSelfTiedObject($class, \$ZipError);
30 $obj->_create(undef, @_);
31}
32
33sub zip
34{
35 my $obj = createSelfTiedObject(undef, \$ZipError);
36 return $obj->_def(@_);
37}
38
39sub mkComp
40{
41 my $self = shift ;
42 my $class = shift ;
43 my $got = shift ;
44
45 my ($obj, $errstr, $errno) ;
46
47 if (*$self->{ZipData}{Store}) {
48 #return CompressPlugin::Deflate::mkCompObject($self, $class, $got)
49 ($obj, $errstr, $errno) = CompressPlugin::Identity::mkCompObject(
50 $got->value('CRC32'),
51 $got->value('Adler32'),
52 $got->value('Level'),
53 $got->value('Strategy')
54 );
55 }
56 else {
57 #return CompressPlugin::Deflate::mkCompObject($self, $class, $got)
58 ($obj, $errstr, $errno) = CompressPlugin::Deflate::mkCompObject(
59 $got->value('CRC32'),
60 $got->value('Adler32'),
61 $got->value('Level'),
62 $got->value('Strategy')
63 );
64 }
65
66 return $self->saveErrorString(undef, $errstr, $errno)
67 if ! defined $obj;
68
69 return $obj;
70}
71
72
73
74sub mkHeader
75{
76 my $self = shift;
77 my $param = shift ;
78
79 my $filename = '';
80 $filename = $param->value('Name') || '';
81
82 my $comment = '';
83 $comment = $param->value('Comment') || '';
84
85 my $extract = $param->value('OS_Code') << 8 + 20 ;
86 my $hdr = '';
87
88 my $time = _unixToDosTime($param->value('Time'));
89 *$self->{ZipData}{StartOffset} = *$self->{ZipData}{Offset} ;
90
91 my $strm = *$self->{ZipData}{Stream} ? 8 : 0 ;
92 my $method = *$self->{ZipData}{Store} ? 0 : 8 ;
93
94 $hdr .= pack "V", 0x04034b50 ; # signature
95 $hdr .= pack 'v', $extract ; # extract Version & OS
96 $hdr .= pack 'v', $strm ; # general purpose flag (set streaming mode)
97 $hdr .= pack 'v', $method ; # compression method (deflate)
98 $hdr .= pack 'V', $time ; # last mod date/time
99 $hdr .= pack 'V', 0 ; # crc32 - 0 when streaming
100 $hdr .= pack 'V', 0 ; # compressed length - 0 when streaming
101 $hdr .= pack 'V', 0 ; # uncompressed length - 0 when streaming
102 $hdr .= pack 'v', length $filename ; # filename length
103 $hdr .= pack 'v', 0 ; # extra length
104
105 $hdr .= $filename ;
106
107
108 my $ctl = '';
109
110 $ctl .= pack "V", 0x02014b50 ; # signature
111 $ctl .= pack 'v', $extract ; # version made by
112 $ctl .= pack 'v', $extract ; # extract Version
113 $ctl .= pack 'v', $strm ; # general purpose flag (streaming mode)
114 $ctl .= pack 'v', $method ; # compression method (deflate)
115 $ctl .= pack 'V', $time ; # last mod date/time
116 $ctl .= pack 'V', 0 ; # crc32
117 $ctl .= pack 'V', 0 ; # compressed length
118 $ctl .= pack 'V', 0 ; # uncompressed length
119 $ctl .= pack 'v', length $filename ; # filename length
120 $ctl .= pack 'v', 0 ; # extra length
121 $ctl .= pack 'v', length $comment ; # file comment length
122 $ctl .= pack 'v', 0 ; # disk number start
123 $ctl .= pack 'v', 0 ; # internal file attributes
124 $ctl .= pack 'V', 0 ; # external file attributes
125 $ctl .= pack 'V', *$self->{ZipData}{Offset} ; # offset to local header
126
127 $ctl .= $filename ;
128 #$ctl .= $extra ;
129 $ctl .= $comment ;
130
131 *$self->{ZipData}{Offset} += length $hdr ;
132
133 *$self->{ZipData}{CentralHeader} = $ctl;
134
135 return $hdr;
136}
137
138sub mkTrailer
139{
140 my $self = shift ;
141
142 my $crc32 = *$self->{Compress}->crc32();
143 my $compressedBytes = *$self->{Compress}->compressedBytes();
144 my $uncompressedBytes = *$self->{Compress}->uncompressedBytes();
145
146 my $data ;
147 $data .= pack "V", $crc32 ; # CRC32
148 $data .= pack "V", $compressedBytes ; # Compressed Size
149 $data .= pack "V", $uncompressedBytes; # Uncompressed Size
150
151 my $hdr = '';
152
153 if (*$self->{ZipData}{Stream}) {
154 $hdr = pack "V", 0x08074b50 ; # signature
155 $hdr .= $data ;
156 }
157 else {
158 $self->writeAt(*$self->{ZipData}{StartOffset} + 14, $data)
159 or return undef;
160 }
161
162 my $ctl = *$self->{ZipData}{CentralHeader} ;
163 substr($ctl, 16, 12) = $data ;
164 #substr($ctl, 16, 4) = pack "V", $crc32 ; # CRC32
165 #substr($ctl, 20, 4) = pack "V", $compressedBytes ; # Compressed Size
166 #substr($ctl, 24, 4) = pack "V", $uncompressedBytes ; # Uncompressed Size
167
168 *$self->{ZipData}{Offset} += length($hdr) + $compressedBytes;
169 push @{ *$self->{ZipData}{CentralDir} }, $ctl ;
170
171 return $hdr;
172}
173
174sub mkFinalTrailer
175{
176 my $self = shift ;
177
178 my $entries = @{ *$self->{ZipData}{CentralDir} };
179 my $cd = join '', @{ *$self->{ZipData}{CentralDir} };
180
181 my $ecd = '';
182 $ecd .= pack "V", 0x06054b50 ; # signature
183 $ecd .= pack 'v', 0 ; # number of disk
184 $ecd .= pack 'v', 0 ; # number if disk with central dir
185 $ecd .= pack 'v', $entries ; # entries in central dir on this disk
186 $ecd .= pack 'v', $entries ; # entries in central dir
187 $ecd .= pack 'V', length $cd ; # size of central dir
188 $ecd .= pack 'V', *$self->{ZipData}{Offset} ; # offset to start central dir
189 $ecd .= pack 'v', 0 ; # zipfile comment length
190 #$ecd .= $comment;
191
192 return $cd . $ecd ;
193}
194
195sub ckParams
196{
197 my $self = shift ;
198 my $got = shift;
199
200 $got->value('CRC32' => 1);
201
202 if (! $got->parsed('Time') ) {
203 # Modification time defaults to now.
204 $got->value('Time' => time) ;
205 }
206
207 *$self->{ZipData}{Stream} = $got->value('Stream');
208 *$self->{ZipData}{Store} = $got->value('Store');
209 *$self->{ZipData}{StartOffset} = *$self->{ZipData}{Offset} = 0;
210
211 return 1 ;
212}
213
214#sub newHeader
215#{
216# my $self = shift ;
217#
218# return $self->mkHeader(*$self->{Got});
219#}
220
221sub getExtraParams
222{
223 my $self = shift ;
224
225 use Compress::Zlib::ParseParameters;
226 use Compress::Zlib qw(Z_DEFLATED Z_DEFAULT_COMPRESSION Z_DEFAULT_STRATEGY);
227
228
229 return (
230 # zlib behaviour
231 $self->getZlibParams(),
232
233 'Stream' => [1, 1, Parse_boolean, 1],
234 'Store' => [0, 1, Parse_boolean, 0],
235
236# # Zip header fields
237# 'Minimal' => [0, 1, Parse_boolean, 0],
238 'Comment' => [0, 1, Parse_any, undef],
239 'ZipComment'=> [0, 1, Parse_any, undef],
240 'Name' => [0, 1, Parse_any, undef],
241 'Time' => [0, 1, Parse_any, undef],
242 'OS_Code' => [0, 1, Parse_unsigned, $Compress::Zlib::gzip_os_code],
243
244# 'TextFlag' => [0, 1, Parse_boolean, 0],
245# 'ExtraField'=> [0, 1, Parse_string, undef],
246 );
247}
248
249sub getInverseClass
250{
251 return ('IO::Uncompress::Unzip',
252 \$IO::Uncompress::Unzip::UnzipError);
253}
254
255sub getFileInfo
256{
257 my $self = shift ;
258 my $params = shift;
259 my $filename = shift ;
260
261 my $defaultTime = (stat($filename))[9] ;
262
263 $params->value('Name' => $filename)
264 if ! $params->parsed('Name') ;
265
266 $params->value('Time' => $defaultTime)
267 if ! $params->parsed('Time') ;
268
269
270}
271
272# from Archive::Zip
273sub _unixToDosTime # Archive::Zip::Member
274{
275 my $time_t = shift;
276 # TODO - add something to cope with unix time < 1980
277 my ( $sec, $min, $hour, $mday, $mon, $year ) = localtime($time_t);
278 my $dt = 0;
279 $dt += ( $sec >> 1 );
280 $dt += ( $min << 5 );
281 $dt += ( $hour << 11 );
282 $dt += ( $mday << 16 );
283 $dt += ( ( $mon + 1 ) << 21 );
284 $dt += ( ( $year - 80 ) << 25 );
285 return $dt;
286}
287
2881;
289
290__END__