1de8cc8edSafresh1#!/usr/bin/perl 2de8cc8edSafresh1 3de8cc8edSafresh1# Streaming zip 4de8cc8edSafresh1 5de8cc8edSafresh1use strict; 6de8cc8edSafresh1use warnings; 7de8cc8edSafresh1 8de8cc8edSafresh1use IO::Compress::Zip qw(zip 9de8cc8edSafresh1 ZIP_CM_STORE 10de8cc8edSafresh1 ZIP_CM_DEFLATE 11*256a93a4Safresh1 ZIP_CM_BZIP2 ) ; 12*256a93a4Safresh1 13de8cc8edSafresh1use Getopt::Long; 14de8cc8edSafresh1 15*256a93a4Safresh1my $VERSION = '1.002'; 16de8cc8edSafresh1 17de8cc8edSafresh1my $compression_method = ZIP_CM_DEFLATE; 18de8cc8edSafresh1my $stream = 0; 19de8cc8edSafresh1my $zipfile = '-'; 20de8cc8edSafresh1my $memberName = '-' ; 21de8cc8edSafresh1my $zip64 = 0 ; 22*256a93a4Safresh1my $level ; 23de8cc8edSafresh1 24de8cc8edSafresh1GetOptions("zip64" => \$zip64, 25de8cc8edSafresh1 "method=s" => \&lookupMethod, 26*256a93a4Safresh1 "0" => sub { $level = 0 }, 27*256a93a4Safresh1 "1" => sub { $level = 1 }, 28*256a93a4Safresh1 "2" => sub { $level = 2 }, 29*256a93a4Safresh1 "3" => sub { $level = 3 }, 30*256a93a4Safresh1 "4" => sub { $level = 4 }, 31*256a93a4Safresh1 "5" => sub { $level = 5 }, 32*256a93a4Safresh1 "6" => sub { $level = 6 }, 33*256a93a4Safresh1 "7" => sub { $level = 7 }, 34*256a93a4Safresh1 "8" => sub { $level = 8 }, 35*256a93a4Safresh1 "9" => sub { $level = 9 }, 36de8cc8edSafresh1 "stream" => \$stream, 37de8cc8edSafresh1 "zipfile=s" => \$zipfile, 38de8cc8edSafresh1 "member-name=s" => \$memberName, 39de8cc8edSafresh1 'version' => sub { print "$VERSION\n"; exit 0 }, 40de8cc8edSafresh1 'help' => \&Usage, 41de8cc8edSafresh1 ) 42de8cc8edSafresh1 or Usage(); 43de8cc8edSafresh1 44de8cc8edSafresh1Usage() 45de8cc8edSafresh1 if @ARGV; 46de8cc8edSafresh1 47*256a93a4Safresh1my @extraOpts = (); 48*256a93a4Safresh1 49*256a93a4Safresh1if ($compression_method == ZIP_CM_DEFLATE && defined $level) 50*256a93a4Safresh1{ 51*256a93a4Safresh1 push @extraOpts, (Level => $level) 52*256a93a4Safresh1} 53de8cc8edSafresh1 54de8cc8edSafresh1zip '-' => $zipfile, 55de8cc8edSafresh1 Name => $memberName, 56de8cc8edSafresh1 Zip64 => $zip64, 57de8cc8edSafresh1 Method => $compression_method, 58*256a93a4Safresh1 Stream => $stream, 59*256a93a4Safresh1 @extraOpts 60de8cc8edSafresh1 or die "Error creating zip file '$zipfile': $\n" ; 61de8cc8edSafresh1 62de8cc8edSafresh1exit 0; 63de8cc8edSafresh1 64de8cc8edSafresh1sub lookupMethod 65de8cc8edSafresh1{ 66de8cc8edSafresh1 my $name = shift; 67de8cc8edSafresh1 my $value = shift ; 68de8cc8edSafresh1 69de8cc8edSafresh1 my %valid = ( store => ZIP_CM_STORE, 70de8cc8edSafresh1 deflate => ZIP_CM_DEFLATE, 71de8cc8edSafresh1 bzip2 => ZIP_CM_BZIP2, 72*256a93a4Safresh1 lzma => 14, 73*256a93a4Safresh1 xz => 95, 74*256a93a4Safresh1 zstd => 93, 75de8cc8edSafresh1 ); 76de8cc8edSafresh1 77de8cc8edSafresh1 my $method = $valid{ lc $value }; 78de8cc8edSafresh1 79de8cc8edSafresh1 Usage("Unknown method '$value'") 80de8cc8edSafresh1 if ! defined $method; 81de8cc8edSafresh1 82*256a93a4Safresh1 installModule("Lzma") 83*256a93a4Safresh1 if $method == 14 ; 84*256a93a4Safresh1 85*256a93a4Safresh1 installModule("Xz") 86*256a93a4Safresh1 if $method == 95 ; 87*256a93a4Safresh1 88*256a93a4Safresh1 installModule("Zstd") 89*256a93a4Safresh1 if $method == 93; 90de8cc8edSafresh1 91de8cc8edSafresh1 $compression_method = $method; 92de8cc8edSafresh1} 93de8cc8edSafresh1 94*256a93a4Safresh1sub installModule 95*256a93a4Safresh1{ 96*256a93a4Safresh1 my $name = shift ; 97*256a93a4Safresh1 98*256a93a4Safresh1 eval " use IO::Compress::$name; use IO::Compress::Adapter::$name ; " ; 99*256a93a4Safresh1 die "Method '$name' needs IO::Compress::$name\n" 100*256a93a4Safresh1 if $@; 101*256a93a4Safresh1} 102*256a93a4Safresh1 103de8cc8edSafresh1sub Usage 104de8cc8edSafresh1{ 105*256a93a4Safresh1 print <<EOM; 106*256a93a4Safresh1Usage: 107*256a93a4Safresh1 producer | streamzip [OPTIONS] | consumer 108*256a93a4Safresh1 producer | streamzip [OPTIONS] -zipfile output.zip 109de8cc8edSafresh1 110de8cc8edSafresh1Stream data from stdin, compress into a Zip container, and stream to stdout. 111de8cc8edSafresh1 112de8cc8edSafresh1OPTIONS 113de8cc8edSafresh1 114*256a93a4Safresh1 -zipfile=F Write zip container to the filename 'F' 115*256a93a4Safresh1 Outputs to stdout if zipfile not specified. 116*256a93a4Safresh1 -member-name=M Set member name to 'M' [Default '-'] 117*256a93a4Safresh1 -0 ... -9 Set compression level for Deflate 118*256a93a4Safresh1 [Default: 6] 119de8cc8edSafresh1 -zip64 Create a Zip64-compliant zip file [Default: No] 120*256a93a4Safresh1 Enable Zip64 if input is greater than 4Gig. 121*256a93a4Safresh1 -stream Force a streamed zip file when 'zipfile' option is also enabled. 122de8cc8edSafresh1 Only applies when 'zipfile' option is used. [Default: No] 123*256a93a4Safresh1 Stream is always enabled when writing to stdout. 124*256a93a4Safresh1 -method=M Compress using method 'M'. 125de8cc8edSafresh1 Valid methods are 126de8cc8edSafresh1 store Store without compression 127de8cc8edSafresh1 deflate Use Deflate compression [Deflault] 128de8cc8edSafresh1 bzip2 Use Bzip2 compression 129de8cc8edSafresh1 lzma Use LZMA compression [needs IO::Compress::Lzma] 130*256a93a4Safresh1 xz Use LZMA compression [needs IO::Compress::Xz] 131*256a93a4Safresh1 zstd Use LZMA compression [needs IO::Compress::Zstd] 132de8cc8edSafresh1 -version Display version number [$VERSION] 133de8cc8edSafresh1 134*256a93a4Safresh1Copyright (c) 2019-2021 Paul Marquess. All rights reserved. 135de8cc8edSafresh1 136de8cc8edSafresh1This program is free software; you can redistribute it and/or 137de8cc8edSafresh1modify it under the same terms as Perl itself. 138de8cc8edSafresh1 139de8cc8edSafresh1EOM 140*256a93a4Safresh1 exit; 141de8cc8edSafresh1} 142de8cc8edSafresh1 143de8cc8edSafresh1 144de8cc8edSafresh1__END__ 145de8cc8edSafresh1=head1 NAME 146de8cc8edSafresh1 147de8cc8edSafresh1streamzip - create a zip file from stdin 148de8cc8edSafresh1 149de8cc8edSafresh1=head1 SYNOPSIS 150de8cc8edSafresh1 151de8cc8edSafresh1 producer | streamzip [opts] | consumer 152de8cc8edSafresh1 producer | streamzip [opts] -zipfile=output.zip 153de8cc8edSafresh1 154de8cc8edSafresh1=head1 DESCRIPTION 155de8cc8edSafresh1 156*256a93a4Safresh1This program will read data from C<stdin>, compress it into a zip container 157*256a93a4Safresh1and, by default, write a I<streamed> zip file to C<stdout>. No temporary 158*256a93a4Safresh1files are created. 159de8cc8edSafresh1 160*256a93a4Safresh1The zip container written to C<stdout> is, by necessity, written in 161*256a93a4Safresh1streaming format. Most programs that read Zip files can cope with a 162*256a93a4Safresh1streamed zip file, but if interoperability is important, and your workflow 163*256a93a4Safresh1allows you to write the zip file directly to disk you can create a 164*256a93a4Safresh1non-streamed zip file using the C<zipfile> option. 165de8cc8edSafresh1 166de8cc8edSafresh1=head2 OPTIONS 167de8cc8edSafresh1 168de8cc8edSafresh1=over 5 169de8cc8edSafresh1 170de8cc8edSafresh1=item -zip64 171de8cc8edSafresh1 172*256a93a4Safresh1Create a Zip64-compliant zip container. Use this option if the input is 173*256a93a4Safresh1greater than 4Gig. 174de8cc8edSafresh1 175de8cc8edSafresh1Default is disabled. 176de8cc8edSafresh1 177de8cc8edSafresh1=item -zipfile=F 178de8cc8edSafresh1 179*256a93a4Safresh1Write zip container to the filename C<F>. 180de8cc8edSafresh1 181*256a93a4Safresh1Use the C<Stream> option to force the creation of a streamed zip file. 182de8cc8edSafresh1 183de8cc8edSafresh1=item -member-name=M 184de8cc8edSafresh1 185de8cc8edSafresh1This option is used to name the "file" in the zip container. 186de8cc8edSafresh1 187de8cc8edSafresh1Default is '-'. 188de8cc8edSafresh1 189de8cc8edSafresh1=item -stream 190de8cc8edSafresh1 191*256a93a4Safresh1Ignored when writing to C<stdout>. 192de8cc8edSafresh1 193*256a93a4Safresh1If the C<zipfile> option is specified, including this option will trigger 194*256a93a4Safresh1the creation of a streamed zip file. 195de8cc8edSafresh1 196*256a93a4Safresh1Default: Always enabled when writing to C<stdout>, otherwise disabled. 197de8cc8edSafresh1 198de8cc8edSafresh1=item -method=M 199de8cc8edSafresh1 200*256a93a4Safresh1Compress using method C<M>. 201de8cc8edSafresh1 202de8cc8edSafresh1Valid method names are 203de8cc8edSafresh1 204de8cc8edSafresh1 * store Store without compression 205de8cc8edSafresh1 * deflate Use Deflate compression [Deflault] 206de8cc8edSafresh1 * bzip2 Use Bzip2 compression 207de8cc8edSafresh1 * lzma Use LZMA compression 208*256a93a4Safresh1 * xz Use xz compression 209*256a93a4Safresh1 * zstd Use Zstandard compression 210de8cc8edSafresh1 211*256a93a4Safresh1Note that Lzma compress needs C<IO::Compress::Lzma> to be installed. 212de8cc8edSafresh1 213*256a93a4Safresh1Note that Zstd compress needs C<IO::Compress::Zstd> to be installed. 214*256a93a4Safresh1 215*256a93a4Safresh1Default is C<deflate>. 216*256a93a4Safresh1 217*256a93a4Safresh1=item -0, -1, -2, -3, -4, -5, -6, -7, -8, -9 218*256a93a4Safresh1 219*256a93a4Safresh1Sets the compression level for C<deflate>. Ignored for all other compression methods. 220*256a93a4Safresh1 221*256a93a4Safresh1C<-0> means no compression and C<-9> for maximum compression. 222*256a93a4Safresh1 223*256a93a4Safresh1Default is 6 224de8cc8edSafresh1 225de8cc8edSafresh1=item -version 226de8cc8edSafresh1 227*256a93a4Safresh1Display version number 228de8cc8edSafresh1 229de8cc8edSafresh1=item -help 230de8cc8edSafresh1 231de8cc8edSafresh1Display help 232de8cc8edSafresh1 233de8cc8edSafresh1=back 234de8cc8edSafresh1 235*256a93a4Safresh1=head2 Examples 236de8cc8edSafresh1 237*256a93a4Safresh1Create a zip file bt reading daa from stdin 238de8cc8edSafresh1 239*256a93a4Safresh1 $ echo Lorem ipsum dolor sit | perl ./bin/streamzip >abcd.zip 240*256a93a4Safresh1 241*256a93a4Safresh1Check the contents of C<abcd,zip> with the standard C<unzip> utility 242*256a93a4Safresh1 243*256a93a4Safresh1 Archive: abcd.zip 244*256a93a4Safresh1 Length Date Time Name 245*256a93a4Safresh1 --------- ---------- ----- ---- 246*256a93a4Safresh1 22 2021-01-08 19:45 - 247*256a93a4Safresh1 --------- ------- 248*256a93a4Safresh1 22 1 file 249*256a93a4Safresh1 250*256a93a4Safresh1Notice how the C<Name> is set to C<->. 251*256a93a4Safresh1That is the default for a few zip utilities whwre the member name is not given. 252*256a93a4Safresh1 253*256a93a4Safresh1If you want to explicitly name the file, use the C<-member-name> option as follows 254*256a93a4Safresh1 255*256a93a4Safresh1 $ echo Lorem ipsum dolor sit | perl ./bin/streamzip -member-name latin >abcd.zip 256*256a93a4Safresh1 257*256a93a4Safresh1 $ unzip -l abcd.zip 258*256a93a4Safresh1 Archive: abcd.zip 259*256a93a4Safresh1 Length Date Time Name 260*256a93a4Safresh1 --------- ---------- ----- ---- 261*256a93a4Safresh1 22 2021-01-08 19:47 latin 262*256a93a4Safresh1 --------- ------- 263*256a93a4Safresh1 22 1 file 264*256a93a4Safresh1 265*256a93a4Safresh1 266*256a93a4Safresh1=head2 When to write a Streamed Zip File 267*256a93a4Safresh1 268*256a93a4Safresh1A Streamed Zip File is useful in situations where you cannot seek 269*256a93a4Safresh1backwards/forwards in the file. 270*256a93a4Safresh1 271*256a93a4Safresh1A good examples is when you are serving dynamic content from a Web Server 272*256a93a4Safresh1straight into a socket without needing to create a temporary zip file in 273*256a93a4Safresh1the filesystsm. 274de8cc8edSafresh1 275de8cc8edSafresh1Similarly if your workfow uses a Linux pipelined commands. 276de8cc8edSafresh1 277de8cc8edSafresh1=head1 SUPPORT 278de8cc8edSafresh1 279de8cc8edSafresh1General feedback/questions/bug reports should be sent to 280de8cc8edSafresh1L<https://github.com/pmqs/IO-Compress/issues> (preferred) or 281de8cc8edSafresh1L<https://rt.cpan.org/Public/Dist/Display.html?Name=IO-Compress>. 282de8cc8edSafresh1 283de8cc8edSafresh1 284de8cc8edSafresh1=head1 AUTHOR 285de8cc8edSafresh1 286de8cc8edSafresh1Paul Marquess F<pmqs@cpan.org>. 287de8cc8edSafresh1 288de8cc8edSafresh1=head1 COPYRIGHT 289de8cc8edSafresh1 290*256a93a4Safresh1Copyright (c) 2019-2021 Paul Marquess. All rights reserved. 291de8cc8edSafresh1 292de8cc8edSafresh1This program is free software; you can redistribute it and/or modify it 293de8cc8edSafresh1under the same terms as Perl itself. 294