Compression-Util

 view release on metacpan or  search on metacpan

README.md  view on Meta::CPAN


```perl
    my $symbols = ac_decode($bits_fh, \%freq);
    my $symbols = ac_decode($bitstring, \%freq);
```

Performs Arithmetic Coding decoding using the provided frequency table and a string of 1s and 0s. Inverse of `ac_encode()`.

It takes two parameters: `$bitstring`, representing a string of 1s and 0s containing the arithmetic coded data, and `\%freq`, representing the frequency table used for encoding.

The function returns the decoded sequence of symbols.

## adaptive\_ac\_encode

```perl
    my ($bitstring, $alphabet) = adaptive_ac_encode(\@symbols);
```

Performs Adaptive Arithmetic Coding on the provided symbols.

It takes a single parameter, `\@symbols`, representing the symbols to be encoded.

README.md  view on Meta::CPAN


```perl
    my $symbols = adaptive_ac_decode($bits_fh, \@alphabet);
    my $symbols = adaptive_ac_decode($bitstring, \@alphabet);
```

Performs Adaptive Arithmetic Coding decoding using the provided frequency table and a string of 1s and 0s.

It takes two parameters: `$bitstring`, representing a string of 1s and 0s containing the adaptive arithmetic coded data, and `\@alphabet`, representing the array of distinct sorted symbols that appear in the encoded data.

The function returns the decoded sequence of symbols.

## lzw\_encode

```perl
    my $symbols = lzw_encode($string);
```

Performs Lempel-Ziv-Welch (LZW) encoding on the provided string.

It takes a single parameter, `$string`, representing the data to be encoded.

README.md  view on Meta::CPAN

The function returns an array-ref of symbols.

## lzw\_decode

```perl
    my $string = lzw_decode(\@symbols);
```

Performs Lempel-Ziv-Welch (LZW) decoding on the provided symbols. Inverse of `lzw_encode()`.

The function returns the decoded string.

# INTERFACE FOR LOW-LEVEL FUNCTIONS

## crc32

```perl
    my $int32 = crc32($data);
    my $int32 = crc32($data, $prev_crc32);
```

README.md  view on Meta::CPAN

```

Given a string of 1s and 0s, returns back a bitstring of 1s and 0s encoded using variable run-length encoding.

## binary\_vrl\_decode

```perl
    my $bitstring = binary_vrl_decode($bitstring_enc);
```

Given an encoded bitstring, returned by `binary_vrl_encode()`, gives back the decoded string of 1s and 0s.

## bwt\_sort

```perl
    my $indices = bwt_sort($string);
    my $indices = bwt_sort($string, $lookahead_len);
```

Low-level function that sorts the rotations of a given string using the Burrows-Wheeler Transform (BWT) algorithm.

README.md  view on Meta::CPAN

## huffman\_decode

```perl
    my $symbols = huffman_decode($bitstring, $rev_dict);
```

Low-level function that decodes a Huffman-encoded binary string into a sequence of symbols using a provided reverse dictionary.

It takes two parameters: `$bitstring`, representing the Huffman-encoded string of 1s and 0s, as returned by `huffman_encode()`, and `$rev_dict`, representing the reverse dictionary mapping Huffman codes to their corresponding symbols.

The function returns the decoded sequence of symbols as an array-ref.

## lz77\_encode / lz77\_encode\_symbolic

```perl
    my ($literals, $distances, $lengths, $matches) = lz77_encode($string);
    my ($literals, $distances, $lengths, $matches) = lz77_encode(\@symbols);
```

Low-level function that combines LZSS with ideas from the LZ4 method.

The function returns four values:

```perl
    $literals   # array-ref of uncompressed symbols
    $distances  # array-ref of back-reference distances
    $lengths    # array-ref of literal lengths
    $matches    # array-ref of match lengths
```

The output can be decoded with `lz77_decode()` and `lz77_decode_symbolic()`, respectively.

## lz77\_decode / lz77\_decode\_symbolic

```perl
    my $string  = lz77_decode(\@literals, \@distances, \@lengths, \@matches);
    my $symbols = lz77_decode_symbolic(\@literals, \@distances, \@lengths, \@matches);
```

Low-level function that performs decoding using the provided literals, distances, lengths and matches, returned by LZ77 encoding.

README.md  view on Meta::CPAN

```

The function returns three values:

```perl
    $literals   # array-ref of uncompressed symbols
    $distances  # array-ref of back-reference distances
    $lengths    # array-ref of match lengths
```

The output can be decoded with `lzss_decode()` and `lzss_decode_symbolic()`, respectively.

## lzss\_decode / lzss\_decode\_symbolic

    my $string  = lzss_decode(\@literals, \@distances, \@lengths);
    my $symbols = lzss_decode_symbolic(\@literals, \@distances, \@lengths);

Low-level function that decodes the LZSS encoding, using the provided literals, distances, and lengths of matched sub-strings.

Inverse of `lzss_encode()` and `lzss_encode_fast()`.

README.md  view on Meta::CPAN

```perl
    my $data = deflate_extract_block_type_0($fh, \$buffer, \$search_window);
```

Given an input filehandle, it extracts a DEFLATE block of type 0 (uncompressed).

```perl
    my ($buffer, $search_window) = ('', '');
    my $block_type = bits2int_lsb($fh, 2, \$buffer);
    $block_type == 0 or die "Not a block of type 0";
    my $decoded_chunk = deflate_extract_block_type_0($fh, \$buffer, \$search_window);
```

## deflate\_extract\_block\_type\_1

```perl
    my $data = deflate_extract_block_type_1($fh, \$buffer, \$search_window);
```

Given an input filehandle, a bitstring buffer and a search window, it extracts a DEFLATE block of type 1 (fixed prefix-codes).

```perl
    my ($buffer, $search_window) = ('', '');
    my $block_type = bits2int_lsb($fh, 2, \$buffer);
    $block_type == 1 or die "Not a block of type 1";
    my $decoded_chunk = deflate_extract_block_type_1($fh, \$buffer, \$search_window);
```

## deflate\_extract\_block\_type\_2

```perl
    my $data = deflate_extract_block_type_2($fh, \$buffer, \$search_window);
```

Given an input filehandle, a bitstring buffer and a search window, it extracts a DEFLATE block of type 2 (dynamic prefix-codes).

```perl
    my ($buffer, $search_window) = ('', '');
    my $block_type = bits2int_lsb($fh, 2, \$buffer);
    $block_type == 2 or die "Not a block of type 2";
    my $decoded_chunk = deflate_extract_block_type_2($fh, \$buffer, \$search_window);
```

## deflate\_extract\_next\_block

```perl
    my $data = deflate_extract_next_block($fh, \$buffer, \$search_window);
```

Given an input filehandle, a bitstring buffer and a search window, it extracts the next DEFLATE block. The next two bits in the input file-handle (or in the bitstring buffer) must contain the block-type number.

examples/bzip2_decompressor.pl  view on Meta::CPAN


            my @huffman_trees = map { (huffman_from_code_lengths($_))[1] } @trees;

            my $eob = @alphabet + 1;

            my @zrle;
            my $code = '';

            my $sel_idx = 0;
            my $tree    = $huffman_trees[$sels->[$sel_idx]];
            my $decoded = 50;

            while (!eof($fh)) {
                $code .= read_bit($fh, \$buffer);

                if (length($code) > $MaxHuffmanBits) {
                    die "[!] Something went wrong: length of LL code `$code` is > $MaxHuffmanBits.\n";
                }

                if (exists($tree->{$code})) {

                    my $sym = $tree->{$code};

                    if ($sym == $eob) {    # end of block marker
                        say STDERR "EOB detected: $sym";
                        last;
                    }

                    push @zrle, $sym;
                    $code = '';

                    if (--$decoded <= 0) {
                        if (++$sel_idx <= $#$sels) {
                            $tree = $huffman_trees[$sels->[$sel_idx]];
                        }
                        else {
                            die "No more selectors";    # should not happen
                        }
                        $decoded = 50;
                    }
                }
            }

            ##say STDERR "ZRLE: (@zrle)";
            my @mtf = reverse @{zrle_decode([reverse @zrle])};
            ##say STDERR "MTF: (@mtf)";

            my $bwt = symbols2string mtf_decode(\@mtf, \@alphabet);
            ## say "BWT: ($bwt, $bwt_idx)";

lib/Compression/Util.pm  view on Meta::CPAN

            my $t = sprintf('%b', $v - 1);
            $encoded .= join('', '1' x length($t), '0', substr($t, 1));
        }
    }

    return $encoded;
}

sub binary_vrl_decode ($bitstring) {

    my $decoded = '';
    my $bit     = substr($bitstring, 0, 1, '');

    while ($bitstring ne '') {

        $decoded .= $bit;

        my $bl = 0;
        while (substr($bitstring, 0, 1, '') eq '1') {
            ++$bl;
        }

        if ($bl > 0) {
            $decoded .= $bit x oct('0b1' . join('', map { substr($bitstring, 0, 1, '') } 1 .. $bl - 1));
        }

        $bit = ($bit eq '1' ? '0' : '1');
    }

    return $decoded;
}

############################
# Burrows-Wheeler transform
############################

sub bwt_sort ($s, $LOOKAHEAD_LEN = 128) {    # O(n * LOOKAHEAD_LEN) space (fast)
#<<<
    [
     map { $_->[1] } sort {

lib/Compression/Util.pm  view on Meta::CPAN

                $k += $run;
                push @deltas, ($deltas[-1]) x $run;
            }
        }

        if ($k == 0) {
            $len = pop(@deltas);
        }
    }

    my $decoded = \@deltas;
    $decoded = rle4_decode($decoded) if $with_rle4;
    $decoded = accumulate($decoded)  if $with_deltas;
    return $decoded;
}

################################
# Alphabet encoding (from Bzip2)
################################

sub encode_alphabet_256 ($alphabet) {

    my %table;
    @table{@$alphabet} = ();

lib/Compression/Util.pm  view on Meta::CPAN


                my @huffman_trees = map { (huffman_from_code_lengths($_))[1] } @trees;

                my $eob = @alphabet + 1;

                my @zrle;
                my $code = '';

                my $sel_idx = 0;
                my $tree    = $huffman_trees[$sels->[$sel_idx]];
                my $decoded = 50;

                while (!eof($fh)) {
                    $code .= read_bit($fh, \$buffer);

                    if (length($code) > $MaxHuffmanBits) {
                        confess "[!] Something went wrong: length of code `$code` is > $MaxHuffmanBits.";
                    }

                    if (exists($tree->{$code})) {

                        my $sym = $tree->{$code};

                        if ($sym == $eob) {    # end of block marker
                            $VERBOSE && say STDERR "EOB detected: $sym";
                            last;
                        }

                        push @zrle, $sym;
                        $code = '';

                        if (--$decoded <= 0) {
                            if (++$sel_idx <= $#$sels) {
                                $tree = $huffman_trees[$sels->[$sel_idx]];
                            }
                            else {
                                confess "No more selectors";    # should not happen
                            }
                            $decoded = 50;
                        }
                    }
                }

                my @mtf = reverse @{zrle_decode([reverse @zrle])};
                my $bwt = symbols2string mtf_decode(\@mtf, \@alphabet);

                my $rle4 = string2symbols bwt_decode($bwt, $bwt_idx);
                my $data = rle4_decode($rle4);
                my $dec  = symbols2string($data);

lib/Compression/Util.pm  view on Meta::CPAN

        if ($DictID) {
            my $dict_id = bytes2int_lsb($fh, 4);
            $VERBOSE && say STDERR "Dictionary ID: ", $dict_id;
        }

        my $header_checksum = ord(getc($fh));

        # TODO: compute and verify the header checksum
        $VERBOSE && say STDERR "Header checksum: ", $header_checksum;

        my $decoded = '';

        while (!eof($fh)) {

            my $block_size = bytes2int_lsb($fh, 4);

            if ($block_size == 0x00000000) {    # signifies an EndMark
                $VERBOSE && say STDERR "Block size == 0";
                last;
            }

            $VERBOSE && say STDERR "Block size: $block_size";

            if ($block_size >> 31) {
                $VERBOSE && say STDERR "Highest bit set: ", $block_size;
                $block_size &= ((1 << 31) - 1);
                $VERBOSE && say STDERR "Block size: ", $block_size;
                my $uncompressed = '';
                read($fh, $uncompressed, $block_size);
                $decoded .= $uncompressed;
            }
            else {

                my $compressed = '';
                read($fh, $compressed, $block_size);

                while ($compressed ne '') {
                    my $len_byte = ord(substr($compressed, 0, 1, ''));

                    my $literals_length = $len_byte >> 4;

lib/Compression/Util.pm  view on Meta::CPAN


                    ## say STDERR "Total literals length: ", $literals_length;

                    my $literals = '';

                    if ($literals_length > 0) {
                        $literals = substr($compressed, 0, $literals_length, '');
                    }

                    if ($compressed eq '') {    # end of block
                        $decoded .= $literals;
                        last;
                    }

                    my $offset = oct('0b' . reverse unpack('b16', substr($compressed, 0, 2, '')));

                    if ($offset == 0) {
                        confess "Corrupted block";
                    }

                    ## say STDERR "Offset: $offset";

                    if ($match_len == 15) {
                        while (1) {
                            my $byte_len = ord(substr($compressed, 0, 1, ''));
                            $match_len += $byte_len;
                            last if $byte_len != 255;
                        }
                    }

                    $decoded .= $literals;
                    $match_len += 4;

                    ## say STDERR "Total match len: $match_len\n";

                    if ($offset >= $match_len) {    # non-overlapping matches
                        $decoded .= substr($decoded, length($decoded) - $offset, $match_len);
                    }
                    elsif ($offset == 1) {
                        $decoded .= substr($decoded, -1) x $match_len;
                    }
                    else {                          # overlapping matches
                        foreach my $i (1 .. $match_len) {
                            $decoded .= substr($decoded, length($decoded) - $offset, 1);
                        }
                    }
                }
            }

            if ($B_checksum) {
                my $content_checksum = bytes2int_lsb($fh, 4);
                $VERBOSE && say STDERR "Block checksum: $content_checksum";
            }

            if ($B_indep) {    # blocks are independent of each other
                $decompressed .= $decoded;
                $decoded = '';
            }
            elsif (length($decoded) > 2**16) {    # blocks are dependent
                $decompressed .= substr($decoded, 0, -(2**16), '');
            }
        }

        # TODO: compute and verify checksum
        if ($C_checksum) {
            my $content_checksum = bytes2int_lsb($fh, 4);
            $VERBOSE && say STDERR "Content checksum: $content_checksum";
        }

        $decompressed .= $decoded;
    }

    return $decompressed;
}

1;

__END__

=encoding utf-8

lib/Compression/Util.pm  view on Meta::CPAN


=head2 ac_decode

    my $symbols = ac_decode($bits_fh, \%freq);
    my $symbols = ac_decode($bitstring, \%freq);

Performs Arithmetic Coding decoding using the provided frequency table and a string of 1s and 0s. Inverse of C<ac_encode()>.

It takes two parameters: C<$bitstring>, representing a string of 1s and 0s containing the arithmetic coded data, and C<\%freq>, representing the frequency table used for encoding.

The function returns the decoded sequence of symbols.

=head2 adaptive_ac_encode

    my ($bitstring, $alphabet) = adaptive_ac_encode(\@symbols);

Performs Adaptive Arithmetic Coding on the provided symbols.

It takes a single parameter, C<\@symbols>, representing the symbols to be encoded.

The function returns two values: C<$bitstring>, which is a string of 1s and 0s, and C<$alphabet>, which is an array-ref of distinct sorted symbols.

=head2 adaptive_ac_decode

    my $symbols = adaptive_ac_decode($bits_fh, \@alphabet);
    my $symbols = adaptive_ac_decode($bitstring, \@alphabet);

Performs Adaptive Arithmetic Coding decoding using the provided frequency table and a string of 1s and 0s.

It takes two parameters: C<$bitstring>, representing a string of 1s and 0s containing the adaptive arithmetic coded data, and C<\@alphabet>, representing the array of distinct sorted symbols that appear in the encoded data.

The function returns the decoded sequence of symbols.

=head2 lzw_encode

    my $symbols = lzw_encode($string);

Performs Lempel-Ziv-Welch (LZW) encoding on the provided string.

It takes a single parameter, C<$string>, representing the data to be encoded.

The function returns an array-ref of symbols.

=head2 lzw_decode

    my $string = lzw_decode(\@symbols);

Performs Lempel-Ziv-Welch (LZW) decoding on the provided symbols. Inverse of C<lzw_encode()>.

The function returns the decoded string.

=head1 INTERFACE FOR LOW-LEVEL FUNCTIONS

=head2 crc32

    my $int32 = crc32($data);
    my $int32 = crc32($data, $prev_crc32);

Compute the CRC32 checksum of a given string.

lib/Compression/Util.pm  view on Meta::CPAN

=head2 binary_vrl_encode

    my $bitstring_enc = binary_vrl_encode($bitstring);

Given a string of 1s and 0s, returns back a bitstring of 1s and 0s encoded using variable run-length encoding.

=head2 binary_vrl_decode

    my $bitstring = binary_vrl_decode($bitstring_enc);

Given an encoded bitstring, returned by C<binary_vrl_encode()>, gives back the decoded string of 1s and 0s.

=head2 bwt_sort

    my $indices = bwt_sort($string);
    my $indices = bwt_sort($string, $lookahead_len);

Low-level function that sorts the rotations of a given string using the Burrows-Wheeler Transform (BWT) algorithm.

It takes two parameters: C<$string>, which is the input string to be transformed, and C<$LOOKAHEAD_LEN> (optional), representing the length of look-ahead during sorting.

lib/Compression/Util.pm  view on Meta::CPAN

The function returns a concatenated string of 1s and 0s, representing the Huffman-encoded sequence of symbols.

=head2 huffman_decode

    my $symbols = huffman_decode($bitstring, $rev_dict);

Low-level function that decodes a Huffman-encoded binary string into a sequence of symbols using a provided reverse dictionary.

It takes two parameters: C<$bitstring>, representing the Huffman-encoded string of 1s and 0s, as returned by C<huffman_encode()>, and C<$rev_dict>, representing the reverse dictionary mapping Huffman codes to their corresponding symbols.

The function returns the decoded sequence of symbols as an array-ref.

=head2 lz77_encode / lz77_encode_symbolic

    my ($literals, $distances, $lengths, $matches) = lz77_encode($string);
    my ($literals, $distances, $lengths, $matches) = lz77_encode(\@symbols);

Low-level function that combines LZSS with ideas from the LZ4 method.

The function returns four values:

    $literals   # array-ref of uncompressed symbols
    $distances  # array-ref of back-reference distances
    $lengths    # array-ref of literal lengths
    $matches    # array-ref of match lengths

The output can be decoded with C<lz77_decode()> and C<lz77_decode_symbolic()>, respectively.

=head2 lz77_decode / lz77_decode_symbolic

    my $string  = lz77_decode(\@literals, \@distances, \@lengths, \@matches);
    my $symbols = lz77_decode_symbolic(\@literals, \@distances, \@lengths, \@matches);

Low-level function that performs decoding using the provided literals, distances, lengths and matches, returned by LZ77 encoding.

Inverse of C<lz77_encode()> and C<lz77_encode_symbolic()>, respectively.

lib/Compression/Util.pm  view on Meta::CPAN

    max_len         => $LZ_MAX_LEN,
    max_dist        => $LZ_MAX_DIST,
    max_chain_len   => $LZ_MAX_CHAIN_LEN,

The function returns three values:

    $literals   # array-ref of uncompressed symbols
    $distances  # array-ref of back-reference distances
    $lengths    # array-ref of match lengths

The output can be decoded with C<lzss_decode()> and C<lzss_decode_symbolic()>, respectively.

=head2 lzss_decode / lzss_decode_symbolic

    my $string  = lzss_decode(\@literals, \@distances, \@lengths);
    my $symbols = lzss_decode_symbolic(\@literals, \@distances, \@lengths);

Low-level function that decodes the LZSS encoding, using the provided literals, distances, and lengths of matched sub-strings.

Inverse of C<lzss_encode()> and C<lzss_encode_fast()>.

lib/Compression/Util.pm  view on Meta::CPAN


=head2 deflate_extract_block_type_0

    my $data = deflate_extract_block_type_0($fh, \$buffer, \$search_window);

Given an input filehandle, it extracts a DEFLATE block of type 0 (uncompressed).

    my ($buffer, $search_window) = ('', '');
    my $block_type = bits2int_lsb($fh, 2, \$buffer);
    $block_type == 0 or die "Not a block of type 0";
    my $decoded_chunk = deflate_extract_block_type_0($fh, \$buffer, \$search_window);

=head2 deflate_extract_block_type_1

    my $data = deflate_extract_block_type_1($fh, \$buffer, \$search_window);

Given an input filehandle, a bitstring buffer and a search window, it extracts a DEFLATE block of type 1 (fixed prefix-codes).

    my ($buffer, $search_window) = ('', '');
    my $block_type = bits2int_lsb($fh, 2, \$buffer);
    $block_type == 1 or die "Not a block of type 1";
    my $decoded_chunk = deflate_extract_block_type_1($fh, \$buffer, \$search_window);

=head2 deflate_extract_block_type_2

    my $data = deflate_extract_block_type_2($fh, \$buffer, \$search_window);

Given an input filehandle, a bitstring buffer and a search window, it extracts a DEFLATE block of type 2 (dynamic prefix-codes).

    my ($buffer, $search_window) = ('', '');
    my $block_type = bits2int_lsb($fh, 2, \$buffer);
    $block_type == 2 or die "Not a block of type 2";
    my $decoded_chunk = deflate_extract_block_type_2($fh, \$buffer, \$search_window);

=head2 deflate_extract_next_block

    my $data = deflate_extract_next_block($fh, \$buffer, \$search_window);

Given an input filehandle, a bitstring buffer and a search window, it extracts the next DEFLATE block. The next two bits in the input file-handle (or in the bitstring buffer) must contain the block-type number.

=head1 EXPORT

Each function can be exported individually, as:

t/misc.t  view on Meta::CPAN


    is_deeply(\@symbols, \@copy);    # make sure the array has not been modified in-place
}

##################################

{
    my $bitstring = "101000010000000010000000100000000001001100010000000000000010010100000000000000001";

    my $encoded = binary_vrl_encode($bitstring);
    my $decoded = binary_vrl_decode($encoded);

    is($decoded, $bitstring);
    is($encoded, "1000110101110110111010011110001010101100011110101010000111101110");
}

##############################################

{
    my $str = "INEFICIENCIES";

    {
        my $encoded = mtf_encode(string2symbols($str), [ord('A') .. ord('Z')]);
        my $decoded = mtf_decode($encoded, [ord('A') .. ord('Z')]);

        is(join(' ', @$encoded), '8 13 6 7 3 6 1 3 4 3 3 3 18');
        is($str,                 symbols2string($decoded));
    }

    {
        my ($encoded, $alphabet) = mtf_encode(string2symbols($str));
        my $decoded = mtf_decode($encoded, $alphabet);

        is(join(' ', @$encoded), '3 4 3 4 3 4 1 3 4 3 3 3 5');
        is($str,                 symbols2string($decoded));
    }
}

##############################################

{
    my $int1 = int(rand(1 << 5));
    my $int2 = int(rand(1 << 6));
    my $int3 = int(rand(1e6));

t/misc.t  view on Meta::CPAN


# DEFLATE block type 0

{
    my $chunk        = "foobar hello world";
    my $bt0_header   = deflate_create_block_type_0_header($chunk);
    my $block_type_0 = pack('b*', '00') . pack('b*', $bt0_header) . $chunk;

    open my $fh, '<:raw', \$block_type_0;
    my ($buffer, $search_window) = ('', '');
    my $decoded_chunk = deflate_extract_next_block($fh, \$buffer, \$search_window);

    is($chunk,         $decoded_chunk);
    is($search_window, $chunk);
}

# DEFLATE block type 0

{
    my $chunk        = "hello world 12";
    my $bt0_header   = deflate_create_block_type_0_header($chunk);
    my $block_type_0 = pack('b*', $bt0_header) . $chunk;

    my ($buffer, $search_window) = ('', '');
    open my $fh, '<:raw', \$block_type_0;
    my $decoded_chunk = deflate_extract_block_type_0($fh, \$buffer, \$search_window);

    is($chunk, $decoded_chunk);
}

# DEFLATE block type 1

{
    my $chunk = "foobar hello world";

    my ($literals, $distances, $lengths) = lzss_encode($chunk, min_len => 4, max_len => 258, max_dist => 2**15 - 1);

    my $bitstring    = deflate_create_block_type_1($literals, $distances, $lengths);
    my $block_type_1 = pack('b*', $bitstring);
    open my $fh, '<:raw', \$block_type_1;
    my ($buffer, $search_window) = ('', '');
    my $decoded_chunk = deflate_extract_next_block($fh, \$buffer, \$search_window);

    is($chunk,         $decoded_chunk);
    is($search_window, $chunk);
}

# DEFLATE block type 1

{
    my $chunk = "foobar hello world";

    my ($literals, $distances, $lengths) = lzss_encode($chunk, min_len => 4, max_len => 258, max_dist => 2**15 - 1);

    my $bitstring    = deflate_create_block_type_1($literals, $distances, $lengths);
    my $block_type_1 = pack('b*', $bitstring);
    open my $fh, '<:raw', \$block_type_1;

    my ($buffer, $search_window) = ('', '');
    my $block_type = bits2int_lsb($fh, 2, \$buffer);
    is($block_type, 1);

    my $decoded_chunk = deflate_extract_block_type_1($fh, \$buffer, \$search_window);

    is($chunk,         $decoded_chunk);
    is($search_window, $chunk);
}

# DEFLATE block type 2

{
    my $chunk = "foobar hello world";

    my ($literals, $distances, $lengths) = lzss_encode($chunk, min_len => 4, max_len => 258, max_dist => 2**15 - 1);

    my $bitstring    = deflate_create_block_type_2($literals, $distances, $lengths);
    my $block_type_2 = pack('b*', $bitstring);
    open my $fh, '<:raw', \$block_type_2;
    my ($buffer, $search_window) = ('', '');
    my $decoded_chunk = deflate_extract_next_block($fh, \$buffer, \$search_window);

    is($chunk,         $decoded_chunk);
    is($search_window, $chunk);
}

# DEFLATE block type 2

{
    my $chunk = "foobar hello world";

    my ($literals, $distances, $lengths) = lzss_encode($chunk, min_len => 4, max_len => 258, max_dist => 2**15 - 1);

    my $bitstring    = deflate_create_block_type_2($literals, $distances, $lengths);
    my $block_type_2 = pack('b*', $bitstring);
    open my $fh, '<:raw', \$block_type_2;

    my ($buffer, $search_window) = ('', '');
    my $block_type = bits2int_lsb($fh, 2, \$buffer);
    is($block_type, 2);

    my $decoded_chunk = deflate_extract_block_type_2($fh, \$buffer, \$search_window);
    is($decoded_chunk, $chunk);
    is($search_window, $chunk);
}



( run in 0.237 second using v1.01-cache-2.11-cpan-26ccb49234f )