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