1 package IO::Compress::Zip ;
6 use Compress::Zlib::Common qw(createSelfTiedObject);
7 use CompressPlugin::Deflate;
8 use CompressPlugin::Identity;
9 use IO::Compress::RawDeflate;
13 our ($VERSION, @ISA, @EXPORT_OK, %EXPORT_TAGS, $ZipError);
15 $VERSION = '2.000_04';
18 @ISA = qw(Exporter IO::Compress::RawDeflate);
19 @EXPORT_OK = qw( $ZipError zip ) ;
20 %EXPORT_TAGS = %IO::Compress::RawDeflate::DEFLATE_CONSTANTS ;
21 push @{ $EXPORT_TAGS{all} }, @EXPORT_OK ;
22 Exporter::export_ok_tags('all');
29 my $obj = createSelfTiedObject($class, \$ZipError);
30 $obj->_create(undef, @_);
35 my $obj = createSelfTiedObject(undef, \$ZipError);
36 return $obj->_def(@_);
45 my ($obj, $errstr, $errno) ;
47 if (*$self->{ZipData}{Store}) {
48 #return CompressPlugin::Deflate::mkCompObject($self, $class, $got)
49 ($obj, $errstr, $errno) = CompressPlugin::Identity::mkCompObject(
51 $got->value('Adler32'),
53 $got->value('Strategy')
57 #return CompressPlugin::Deflate::mkCompObject($self, $class, $got)
58 ($obj, $errstr, $errno) = CompressPlugin::Deflate::mkCompObject(
60 $got->value('Adler32'),
62 $got->value('Strategy')
66 return $self->saveErrorString(undef, $errstr, $errno)
80 $filename = $param->value('Name') || '';
83 $comment = $param->value('Comment') || '';
85 my $extract = $param->value('OS_Code') << 8 + 20 ;
88 my $time = _unixToDosTime($param->value('Time'));
89 *$self->{ZipData}{StartOffset} = *$self->{ZipData}{Offset} ;
91 my $strm = *$self->{ZipData}{Stream} ? 8 : 0 ;
92 my $method = *$self->{ZipData}{Store} ? 0 : 8 ;
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
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
131 *$self->{ZipData}{Offset} += length $hdr ;
133 *$self->{ZipData}{CentralHeader} = $ctl;
142 my $crc32 = *$self->{Compress}->crc32();
143 my $compressedBytes = *$self->{Compress}->compressedBytes();
144 my $uncompressedBytes = *$self->{Compress}->uncompressedBytes();
147 $data .= pack "V", $crc32 ; # CRC32
148 $data .= pack "V", $compressedBytes ; # Compressed Size
149 $data .= pack "V", $uncompressedBytes; # Uncompressed Size
153 if (*$self->{ZipData}{Stream}) {
154 $hdr = pack "V", 0x08074b50 ; # signature
158 $self->writeAt(*$self->{ZipData}{StartOffset} + 14, $data)
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
168 *$self->{ZipData}{Offset} += length($hdr) + $compressedBytes;
169 push @{ *$self->{ZipData}{CentralDir} }, $ctl ;
178 my $entries = @{ *$self->{ZipData}{CentralDir} };
179 my $cd = join '', @{ *$self->{ZipData}{CentralDir} };
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
200 $got->value('CRC32' => 1);
202 if (! $got->parsed('Time') ) {
203 # Modification time defaults to now.
204 $got->value('Time' => time) ;
207 *$self->{ZipData}{Stream} = $got->value('Stream');
208 *$self->{ZipData}{Store} = $got->value('Store');
209 *$self->{ZipData}{StartOffset} = *$self->{ZipData}{Offset} = 0;
218 # return $self->mkHeader(*$self->{Got});
225 use Compress::Zlib::ParseParameters;
226 use Compress::Zlib qw(Z_DEFLATED Z_DEFAULT_COMPRESSION Z_DEFAULT_STRATEGY);
231 $self->getZlibParams(),
233 'Stream' => [1, 1, Parse_boolean, 1],
234 'Store' => [0, 1, Parse_boolean, 0],
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],
244 # 'TextFlag' => [0, 1, Parse_boolean, 0],
245 # 'ExtraField'=> [0, 1, Parse_string, undef],
251 return ('IO::Uncompress::Unzip',
252 \$IO::Uncompress::Unzip::UnzipError);
259 my $filename = shift ;
261 my $defaultTime = (stat($filename))[9] ;
263 $params->value('Name' => $filename)
264 if ! $params->parsed('Name') ;
266 $params->value('Time' => $defaultTime)
267 if ! $params->parsed('Time') ;
273 sub _unixToDosTime # Archive::Zip::Member
276 # TODO - add something to cope with unix time < 1980
277 my ( $sec, $min, $hour, $mday, $mon, $year ) = localtime($time_t);
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 );