summaryrefslogtreecommitdiff
path: root/Master/tlpkg/tlperl/lib/Crypt/OpenPGP/Compressed.pm
blob: 3d9c4fc2b8fb61f0002a25688c778cbbb0bf2b7f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
package Crypt::OpenPGP::Compressed;
use strict;

use Compress::Zlib;
use Crypt::OpenPGP::Buffer;
use Crypt::OpenPGP::Constants qw( DEFAULT_COMPRESS );
use Crypt::OpenPGP::ErrorHandler;
use base qw( Crypt::OpenPGP::ErrorHandler );

use vars qw( %ALG %ALG_BY_NAME );
%ALG = ( 1 => 'ZIP', 2 => 'Zlib' );
%ALG_BY_NAME = map { $ALG{$_} => $_ } keys %ALG;

sub alg {
    return $_[0]->{__alg} if ref($_[0]);
    $ALG{$_[1]} || $_[1];
}

sub alg_id {
    return $_[0]->{__alg_id} if ref($_[0]);
    $ALG_BY_NAME{$_[1]} || $_[1];
}

sub new {
    my $comp = bless { }, shift;
    $comp->init(@_);
}

sub init {
    my $comp = shift;
    my %param = @_;
    if (my $data = $param{Data}) {
        my $alg = $param{Alg} || DEFAULT_COMPRESS;
        $alg = $ALG{$alg} || $alg;
        $comp->{__alg} = $alg;
        $comp->{__alg_id} = $ALG_BY_NAME{$alg};
        my %args;
        if ($comp->{__alg_id} == 1) {
            %args = (-WindowBits => -13, -MemLevel => 8);
        }
        my($d, $status, $compressed);
        ($d, $status) = deflateInit(\%args);
        return (ref $comp)->error("Zlib deflateInit error: $status")
            unless $status == Compress::Zlib::Z_OK();
        {
            my($output, $out);
            ($output, $status) = $d->deflate($data);
            last unless $status == Compress::Zlib::Z_OK();
            ($out, $status) = $d->flush();
            last unless $status == Compress::Zlib::Z_OK();
            $compressed = $output . $out;
        }
        return (ref $comp)->error("Zlib deflation error: $status")
            unless defined $compressed;
        $comp->{data} = $compressed;
    }
    $comp;
}

sub parse {
    my $class = shift;
    my($buf) = @_;
    my $comp = $class->new;
    $comp->{__alg_id} = $buf->get_int8;
    $comp->{__alg} = $ALG{ $comp->{__alg_id} };
    $comp->{data} = $buf->get_bytes($buf->length - $buf->offset);
    $comp;
}

sub save {
    my $comp = shift;
    my $buf = Crypt::OpenPGP::Buffer->new;
    $buf->put_int8($comp->{__alg_id});
    $buf->put_bytes($comp->{data});
    $buf->bytes;
}

sub decompress {
    my $comp = shift;
    my %args;
    if ($comp->{__alg_id} == 1) {
        %args = (-WindowBits => -13);
    }
    my($i, $status, $out);
    ($i, $status) = inflateInit(\%args);
    return $comp->error("Zlib inflateInit error: $status")
        unless $status == Compress::Zlib::Z_OK();
    ($out, $status) = $i->inflate($comp->{data});
    return $comp->error("Zlib inflate error: $status")
        unless defined $out;
    $out;
}

1;
__END__

=head1 NAME

Crypt::OpenPGP::Compressed - Compressed data packets

=head1 SYNOPSIS

    use Crypt::OpenPGP::Compressed;

    my $data = 'serialized openpgp packets';
    my $cdata = Crypt::OpenPGP::Compressed->new( Data => $data );
    my $serialized = $cdata->save;

=head1 DESCRIPTION

I<Crypt::OpenPGP::Compressed> implements compressed data packets,
providing both compression and decompression functionality, for all
supported compression algorithms (C<Zlib> and C<ZIP>). This class
uses I<Compress::Zlib> for all compression/decompression needs for
both algorithms: C<ZIP> is simply C<Zlib> with a different setting
for the I<WindowBits> parameter.

Decompressing a compressed data packet should always yield a stream
of valid PGP packets (which you can then parse using
I<Crypt::OpenPGP::PacketFactory>). Similarly, when compressing a
packet the input data should be a stream of packets.

=head1 USAGE

=head2 Crypt::OpenPGP::Compressed->new( %arg )

Creates a new compressed data packet object and returns that object.
If there are no arguments in I<%arg>, the object is created with an
empty compressed data container; this is used, for example, in
I<parse> (below), to create an empty packet which is then filled with
the data in the buffer.

If you wish to initialize a non-empty object, I<%arg> can contain:

=over 4

=item * Data

A block of octets that make up the data that you wish to compress.
As mentioned above, the data to compress should always be a stream
of valid PGP packets (saved using I<Crypt::OpenPGP::PacketFactory::save>).

This argument is required (for a non-empty object).

=item * Alg

The name (or ID) of a supported PGP compression algorithm. Valid
names are C<Zlib> and C<ZIP>.

This argument is optional; by default I<Crypt::OpenPGP::Compressed> will
use C<ZIP>.

=back

=head2 $cdata->save

Returns the serialized compressed data packet, which consists of
a one-octet compression algorithm ID, followed by the compressed
data.

=head2 Crypt::OpenPGP::Compressed->parse($buffer)

Given I<$buffer>, a I<Crypt::OpenPGP::Buffer> object holding (or with
offset pointing to) a compressed data packet, returns a new
I<Crypt::OpenPGP::Compressed> object, initialized with the data from
the buffer.

=head2 $cdata->decompress

Decompresses the compressed data in the I<Crypt::OpenPGP::Compressed>
object I<$cdata> and returns the decompressed data.

=head1 AUTHOR & COPYRIGHTS

Please see the Crypt::OpenPGP manpage for author, copyright, and
license information.

=cut