1<?php
2/**
3 * This file is part of FPDI
4 *
5 * @package   setasign\Fpdi
6 * @copyright Copyright (c) 2019 Setasign - Jan Slabon (https://www.setasign.com)
7 * @license   http://opensource.org/licenses/mit-license The MIT License
8 */
9
10namespace setasign\Fpdi\PdfParser\Filter;
11
12/**
13 * Class for handling zlib/deflate encoded data
14 *
15 * @package setasign\Fpdi\PdfParser\Filter
16 */
17class Flate implements FilterInterface
18{
19    /**
20     * Checks whether the zlib extension is loaded.
21     *
22     * Used for testing purpose.
23     *
24     * @return boolean
25     * @internal
26     */
27    protected function extensionLoaded()
28    {
29        return \extension_loaded('zlib');
30    }
31
32    /**
33     * Decodes a flate compressed string.
34     *
35     * @param string $data The input string
36     * @return string
37     * @throws FlateException
38     */
39    public function decode($data)
40    {
41        if ($this->extensionLoaded()) {
42            $oData = $data;
43            $data = @((\strlen($data) > 0) ? \gzuncompress($data) : '');
44            if ($data === false) {
45                // Try this fallback
46                $tries = 1;
47                while ($tries < 10 && ($data === false || \strlen($data) < (\strlen($oData) - $tries - 1))) {
48                    $data = @(\gzinflate(\substr($oData, $tries)));
49                    $tries++;
50                }
51
52                if ($data === false) {
53                    // let's try if the checksum is CRC32
54                    $fh = fopen('php://temp', 'w+b');
55                    \fwrite($fh, "\x1f\x8b\x08\x00\x00\x00\x00\x00" . $oData);
56                    \stream_filter_append($fh, 'zlib.inflate', \STREAM_FILTER_READ, ['window' => 30]);
57                    \fseek($fh, 0);
58                    $data = \stream_get_contents($fh);
59                    \fclose($fh);
60                }
61
62                if (!$data) {
63                    throw new FlateException(
64                        'Error while decompressing stream.',
65                        FlateException::DECOMPRESS_ERROR
66                    );
67                }
68            }
69        } else {
70            throw new FlateException(
71                'To handle FlateDecode filter, enable zlib support in PHP.',
72                FlateException::NO_ZLIB
73            );
74        }
75
76        return $data;
77    }
78}
79