xref: /dokuwiki/vendor/simplepie/simplepie/library/SimplePie/gzdecode.php (revision ab0a890215a63de8e7fa87cabb58ea30949afe42)
159b616ccSAndreas Gohr<?php
259b616ccSAndreas Gohr/**
359b616ccSAndreas Gohr * SimplePie
459b616ccSAndreas Gohr *
559b616ccSAndreas Gohr * A PHP-Based RSS and Atom Feed Framework.
659b616ccSAndreas Gohr * Takes the hard work out of managing a complete RSS/Atom solution.
759b616ccSAndreas Gohr *
8*ab0a8902SAndreas Gohr * Copyright (c) 2004-2016, Ryan Parman, Sam Sneddon, Ryan McCue, and contributors
959b616ccSAndreas Gohr * All rights reserved.
1059b616ccSAndreas Gohr *
1159b616ccSAndreas Gohr * Redistribution and use in source and binary forms, with or without modification, are
1259b616ccSAndreas Gohr * permitted provided that the following conditions are met:
1359b616ccSAndreas Gohr *
1459b616ccSAndreas Gohr * 	* Redistributions of source code must retain the above copyright notice, this list of
1559b616ccSAndreas Gohr * 	  conditions and the following disclaimer.
1659b616ccSAndreas Gohr *
1759b616ccSAndreas Gohr * 	* Redistributions in binary form must reproduce the above copyright notice, this list
1859b616ccSAndreas Gohr * 	  of conditions and the following disclaimer in the documentation and/or other materials
1959b616ccSAndreas Gohr * 	  provided with the distribution.
2059b616ccSAndreas Gohr *
2159b616ccSAndreas Gohr * 	* Neither the name of the SimplePie Team nor the names of its contributors may be used
2259b616ccSAndreas Gohr * 	  to endorse or promote products derived from this software without specific prior
2359b616ccSAndreas Gohr * 	  written permission.
2459b616ccSAndreas Gohr *
2559b616ccSAndreas Gohr * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
2659b616ccSAndreas Gohr * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
2759b616ccSAndreas Gohr * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
2859b616ccSAndreas Gohr * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2959b616ccSAndreas Gohr * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
3059b616ccSAndreas Gohr * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3159b616ccSAndreas Gohr * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
3259b616ccSAndreas Gohr * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3359b616ccSAndreas Gohr * POSSIBILITY OF SUCH DAMAGE.
3459b616ccSAndreas Gohr *
3559b616ccSAndreas Gohr * @package SimplePie
36*ab0a8902SAndreas Gohr * @copyright 2004-2016 Ryan Parman, Sam Sneddon, Ryan McCue
3759b616ccSAndreas Gohr * @author Ryan Parman
38*ab0a8902SAndreas Gohr * @author Sam Sneddon
3959b616ccSAndreas Gohr * @author Ryan McCue
4059b616ccSAndreas Gohr * @link http://simplepie.org/ SimplePie
4159b616ccSAndreas Gohr * @license http://www.opensource.org/licenses/bsd-license.php BSD License
4259b616ccSAndreas Gohr */
4359b616ccSAndreas Gohr
4459b616ccSAndreas Gohr
4559b616ccSAndreas Gohr/**
4659b616ccSAndreas Gohr * Decode 'gzip' encoded HTTP data
4759b616ccSAndreas Gohr *
4859b616ccSAndreas Gohr * @package SimplePie
4959b616ccSAndreas Gohr * @subpackage HTTP
5059b616ccSAndreas Gohr * @link http://www.gzip.org/format.txt
5159b616ccSAndreas Gohr */
5259b616ccSAndreas Gohrclass SimplePie_gzdecode
5359b616ccSAndreas Gohr{
5459b616ccSAndreas Gohr	/**
5559b616ccSAndreas Gohr	 * Compressed data
5659b616ccSAndreas Gohr	 *
5759b616ccSAndreas Gohr	 * @access private
5859b616ccSAndreas Gohr	 * @var string
5959b616ccSAndreas Gohr	 * @see gzdecode::$data
6059b616ccSAndreas Gohr	 */
6159b616ccSAndreas Gohr	var $compressed_data;
6259b616ccSAndreas Gohr
6359b616ccSAndreas Gohr	/**
6459b616ccSAndreas Gohr	 * Size of compressed data
6559b616ccSAndreas Gohr	 *
6659b616ccSAndreas Gohr	 * @access private
6759b616ccSAndreas Gohr	 * @var int
6859b616ccSAndreas Gohr	 */
6959b616ccSAndreas Gohr	var $compressed_size;
7059b616ccSAndreas Gohr
7159b616ccSAndreas Gohr	/**
7259b616ccSAndreas Gohr	 * Minimum size of a valid gzip string
7359b616ccSAndreas Gohr	 *
7459b616ccSAndreas Gohr	 * @access private
7559b616ccSAndreas Gohr	 * @var int
7659b616ccSAndreas Gohr	 */
7759b616ccSAndreas Gohr	var $min_compressed_size = 18;
7859b616ccSAndreas Gohr
7959b616ccSAndreas Gohr	/**
8059b616ccSAndreas Gohr	 * Current position of pointer
8159b616ccSAndreas Gohr	 *
8259b616ccSAndreas Gohr	 * @access private
8359b616ccSAndreas Gohr	 * @var int
8459b616ccSAndreas Gohr	 */
8559b616ccSAndreas Gohr	var $position = 0;
8659b616ccSAndreas Gohr
8759b616ccSAndreas Gohr	/**
8859b616ccSAndreas Gohr	 * Flags (FLG)
8959b616ccSAndreas Gohr	 *
9059b616ccSAndreas Gohr	 * @access private
9159b616ccSAndreas Gohr	 * @var int
9259b616ccSAndreas Gohr	 */
9359b616ccSAndreas Gohr	var $flags;
9459b616ccSAndreas Gohr
9559b616ccSAndreas Gohr	/**
9659b616ccSAndreas Gohr	 * Uncompressed data
9759b616ccSAndreas Gohr	 *
9859b616ccSAndreas Gohr	 * @access public
9959b616ccSAndreas Gohr	 * @see gzdecode::$compressed_data
10059b616ccSAndreas Gohr	 * @var string
10159b616ccSAndreas Gohr	 */
10259b616ccSAndreas Gohr	var $data;
10359b616ccSAndreas Gohr
10459b616ccSAndreas Gohr	/**
10559b616ccSAndreas Gohr	 * Modified time
10659b616ccSAndreas Gohr	 *
10759b616ccSAndreas Gohr	 * @access public
10859b616ccSAndreas Gohr	 * @var int
10959b616ccSAndreas Gohr	 */
11059b616ccSAndreas Gohr	var $MTIME;
11159b616ccSAndreas Gohr
11259b616ccSAndreas Gohr	/**
11359b616ccSAndreas Gohr	 * Extra Flags
11459b616ccSAndreas Gohr	 *
11559b616ccSAndreas Gohr	 * @access public
11659b616ccSAndreas Gohr	 * @var int
11759b616ccSAndreas Gohr	 */
11859b616ccSAndreas Gohr	var $XFL;
11959b616ccSAndreas Gohr
12059b616ccSAndreas Gohr	/**
12159b616ccSAndreas Gohr	 * Operating System
12259b616ccSAndreas Gohr	 *
12359b616ccSAndreas Gohr	 * @access public
12459b616ccSAndreas Gohr	 * @var int
12559b616ccSAndreas Gohr	 */
12659b616ccSAndreas Gohr	var $OS;
12759b616ccSAndreas Gohr
12859b616ccSAndreas Gohr	/**
12959b616ccSAndreas Gohr	 * Subfield ID 1
13059b616ccSAndreas Gohr	 *
13159b616ccSAndreas Gohr	 * @access public
13259b616ccSAndreas Gohr	 * @see gzdecode::$extra_field
13359b616ccSAndreas Gohr	 * @see gzdecode::$SI2
13459b616ccSAndreas Gohr	 * @var string
13559b616ccSAndreas Gohr	 */
13659b616ccSAndreas Gohr	var $SI1;
13759b616ccSAndreas Gohr
13859b616ccSAndreas Gohr	/**
13959b616ccSAndreas Gohr	 * Subfield ID 2
14059b616ccSAndreas Gohr	 *
14159b616ccSAndreas Gohr	 * @access public
14259b616ccSAndreas Gohr	 * @see gzdecode::$extra_field
14359b616ccSAndreas Gohr	 * @see gzdecode::$SI1
14459b616ccSAndreas Gohr	 * @var string
14559b616ccSAndreas Gohr	 */
14659b616ccSAndreas Gohr	var $SI2;
14759b616ccSAndreas Gohr
14859b616ccSAndreas Gohr	/**
14959b616ccSAndreas Gohr	 * Extra field content
15059b616ccSAndreas Gohr	 *
15159b616ccSAndreas Gohr	 * @access public
15259b616ccSAndreas Gohr	 * @see gzdecode::$SI1
15359b616ccSAndreas Gohr	 * @see gzdecode::$SI2
15459b616ccSAndreas Gohr	 * @var string
15559b616ccSAndreas Gohr	 */
15659b616ccSAndreas Gohr	var $extra_field;
15759b616ccSAndreas Gohr
15859b616ccSAndreas Gohr	/**
15959b616ccSAndreas Gohr	 * Original filename
16059b616ccSAndreas Gohr	 *
16159b616ccSAndreas Gohr	 * @access public
16259b616ccSAndreas Gohr	 * @var string
16359b616ccSAndreas Gohr	 */
16459b616ccSAndreas Gohr	var $filename;
16559b616ccSAndreas Gohr
16659b616ccSAndreas Gohr	/**
16759b616ccSAndreas Gohr	 * Human readable comment
16859b616ccSAndreas Gohr	 *
16959b616ccSAndreas Gohr	 * @access public
17059b616ccSAndreas Gohr	 * @var string
17159b616ccSAndreas Gohr	 */
17259b616ccSAndreas Gohr	var $comment;
17359b616ccSAndreas Gohr
17459b616ccSAndreas Gohr	/**
17559b616ccSAndreas Gohr	 * Don't allow anything to be set
17659b616ccSAndreas Gohr	 *
17759b616ccSAndreas Gohr	 * @param string $name
17859b616ccSAndreas Gohr	 * @param mixed $value
17959b616ccSAndreas Gohr	 */
18059b616ccSAndreas Gohr	public function __set($name, $value)
18159b616ccSAndreas Gohr	{
18259b616ccSAndreas Gohr		trigger_error("Cannot write property $name", E_USER_ERROR);
18359b616ccSAndreas Gohr	}
18459b616ccSAndreas Gohr
18559b616ccSAndreas Gohr	/**
18659b616ccSAndreas Gohr	 * Set the compressed string and related properties
18759b616ccSAndreas Gohr	 *
18859b616ccSAndreas Gohr	 * @param string $data
18959b616ccSAndreas Gohr	 */
19059b616ccSAndreas Gohr	public function __construct($data)
19159b616ccSAndreas Gohr	{
19259b616ccSAndreas Gohr		$this->compressed_data = $data;
19359b616ccSAndreas Gohr		$this->compressed_size = strlen($data);
19459b616ccSAndreas Gohr	}
19559b616ccSAndreas Gohr
19659b616ccSAndreas Gohr	/**
19759b616ccSAndreas Gohr	 * Decode the GZIP stream
19859b616ccSAndreas Gohr	 *
19959b616ccSAndreas Gohr	 * @return bool Successfulness
20059b616ccSAndreas Gohr	 */
20159b616ccSAndreas Gohr	public function parse()
20259b616ccSAndreas Gohr	{
20359b616ccSAndreas Gohr		if ($this->compressed_size >= $this->min_compressed_size)
20459b616ccSAndreas Gohr		{
20559b616ccSAndreas Gohr			// Check ID1, ID2, and CM
20659b616ccSAndreas Gohr			if (substr($this->compressed_data, 0, 3) !== "\x1F\x8B\x08")
20759b616ccSAndreas Gohr			{
20859b616ccSAndreas Gohr				return false;
20959b616ccSAndreas Gohr			}
21059b616ccSAndreas Gohr
21159b616ccSAndreas Gohr			// Get the FLG (FLaGs)
21259b616ccSAndreas Gohr			$this->flags = ord($this->compressed_data[3]);
21359b616ccSAndreas Gohr
21459b616ccSAndreas Gohr			// FLG bits above (1 << 4) are reserved
21559b616ccSAndreas Gohr			if ($this->flags > 0x1F)
21659b616ccSAndreas Gohr			{
21759b616ccSAndreas Gohr				return false;
21859b616ccSAndreas Gohr			}
21959b616ccSAndreas Gohr
22059b616ccSAndreas Gohr			// Advance the pointer after the above
22159b616ccSAndreas Gohr			$this->position += 4;
22259b616ccSAndreas Gohr
22359b616ccSAndreas Gohr			// MTIME
22459b616ccSAndreas Gohr			$mtime = substr($this->compressed_data, $this->position, 4);
22559b616ccSAndreas Gohr			// Reverse the string if we're on a big-endian arch because l is the only signed long and is machine endianness
22659b616ccSAndreas Gohr			if (current(unpack('S', "\x00\x01")) === 1)
22759b616ccSAndreas Gohr			{
22859b616ccSAndreas Gohr				$mtime = strrev($mtime);
22959b616ccSAndreas Gohr			}
23059b616ccSAndreas Gohr			$this->MTIME = current(unpack('l', $mtime));
23159b616ccSAndreas Gohr			$this->position += 4;
23259b616ccSAndreas Gohr
23359b616ccSAndreas Gohr			// Get the XFL (eXtra FLags)
23459b616ccSAndreas Gohr			$this->XFL = ord($this->compressed_data[$this->position++]);
23559b616ccSAndreas Gohr
23659b616ccSAndreas Gohr			// Get the OS (Operating System)
23759b616ccSAndreas Gohr			$this->OS = ord($this->compressed_data[$this->position++]);
23859b616ccSAndreas Gohr
23959b616ccSAndreas Gohr			// Parse the FEXTRA
24059b616ccSAndreas Gohr			if ($this->flags & 4)
24159b616ccSAndreas Gohr			{
24259b616ccSAndreas Gohr				// Read subfield IDs
24359b616ccSAndreas Gohr				$this->SI1 = $this->compressed_data[$this->position++];
24459b616ccSAndreas Gohr				$this->SI2 = $this->compressed_data[$this->position++];
24559b616ccSAndreas Gohr
24659b616ccSAndreas Gohr				// SI2 set to zero is reserved for future use
24759b616ccSAndreas Gohr				if ($this->SI2 === "\x00")
24859b616ccSAndreas Gohr				{
24959b616ccSAndreas Gohr					return false;
25059b616ccSAndreas Gohr				}
25159b616ccSAndreas Gohr
25259b616ccSAndreas Gohr				// Get the length of the extra field
25359b616ccSAndreas Gohr				$len = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
25459b616ccSAndreas Gohr				$this->position += 2;
25559b616ccSAndreas Gohr
25659b616ccSAndreas Gohr				// Check the length of the string is still valid
25759b616ccSAndreas Gohr				$this->min_compressed_size += $len + 4;
25859b616ccSAndreas Gohr				if ($this->compressed_size >= $this->min_compressed_size)
25959b616ccSAndreas Gohr				{
26059b616ccSAndreas Gohr					// Set the extra field to the given data
26159b616ccSAndreas Gohr					$this->extra_field = substr($this->compressed_data, $this->position, $len);
26259b616ccSAndreas Gohr					$this->position += $len;
26359b616ccSAndreas Gohr				}
26459b616ccSAndreas Gohr				else
26559b616ccSAndreas Gohr				{
26659b616ccSAndreas Gohr					return false;
26759b616ccSAndreas Gohr				}
26859b616ccSAndreas Gohr			}
26959b616ccSAndreas Gohr
27059b616ccSAndreas Gohr			// Parse the FNAME
27159b616ccSAndreas Gohr			if ($this->flags & 8)
27259b616ccSAndreas Gohr			{
27359b616ccSAndreas Gohr				// Get the length of the filename
27459b616ccSAndreas Gohr				$len = strcspn($this->compressed_data, "\x00", $this->position);
27559b616ccSAndreas Gohr
27659b616ccSAndreas Gohr				// Check the length of the string is still valid
27759b616ccSAndreas Gohr				$this->min_compressed_size += $len + 1;
27859b616ccSAndreas Gohr				if ($this->compressed_size >= $this->min_compressed_size)
27959b616ccSAndreas Gohr				{
28059b616ccSAndreas Gohr					// Set the original filename to the given string
28159b616ccSAndreas Gohr					$this->filename = substr($this->compressed_data, $this->position, $len);
28259b616ccSAndreas Gohr					$this->position += $len + 1;
28359b616ccSAndreas Gohr				}
28459b616ccSAndreas Gohr				else
28559b616ccSAndreas Gohr				{
28659b616ccSAndreas Gohr					return false;
28759b616ccSAndreas Gohr				}
28859b616ccSAndreas Gohr			}
28959b616ccSAndreas Gohr
29059b616ccSAndreas Gohr			// Parse the FCOMMENT
29159b616ccSAndreas Gohr			if ($this->flags & 16)
29259b616ccSAndreas Gohr			{
29359b616ccSAndreas Gohr				// Get the length of the comment
29459b616ccSAndreas Gohr				$len = strcspn($this->compressed_data, "\x00", $this->position);
29559b616ccSAndreas Gohr
29659b616ccSAndreas Gohr				// Check the length of the string is still valid
29759b616ccSAndreas Gohr				$this->min_compressed_size += $len + 1;
29859b616ccSAndreas Gohr				if ($this->compressed_size >= $this->min_compressed_size)
29959b616ccSAndreas Gohr				{
30059b616ccSAndreas Gohr					// Set the original comment to the given string
30159b616ccSAndreas Gohr					$this->comment = substr($this->compressed_data, $this->position, $len);
30259b616ccSAndreas Gohr					$this->position += $len + 1;
30359b616ccSAndreas Gohr				}
30459b616ccSAndreas Gohr				else
30559b616ccSAndreas Gohr				{
30659b616ccSAndreas Gohr					return false;
30759b616ccSAndreas Gohr				}
30859b616ccSAndreas Gohr			}
30959b616ccSAndreas Gohr
31059b616ccSAndreas Gohr			// Parse the FHCRC
31159b616ccSAndreas Gohr			if ($this->flags & 2)
31259b616ccSAndreas Gohr			{
31359b616ccSAndreas Gohr				// Check the length of the string is still valid
31459b616ccSAndreas Gohr				$this->min_compressed_size += $len + 2;
31559b616ccSAndreas Gohr				if ($this->compressed_size >= $this->min_compressed_size)
31659b616ccSAndreas Gohr				{
31759b616ccSAndreas Gohr					// Read the CRC
31859b616ccSAndreas Gohr					$crc = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
31959b616ccSAndreas Gohr
32059b616ccSAndreas Gohr					// Check the CRC matches
32159b616ccSAndreas Gohr					if ((crc32(substr($this->compressed_data, 0, $this->position)) & 0xFFFF) === $crc)
32259b616ccSAndreas Gohr					{
32359b616ccSAndreas Gohr						$this->position += 2;
32459b616ccSAndreas Gohr					}
32559b616ccSAndreas Gohr					else
32659b616ccSAndreas Gohr					{
32759b616ccSAndreas Gohr						return false;
32859b616ccSAndreas Gohr					}
32959b616ccSAndreas Gohr				}
33059b616ccSAndreas Gohr				else
33159b616ccSAndreas Gohr				{
33259b616ccSAndreas Gohr					return false;
33359b616ccSAndreas Gohr				}
33459b616ccSAndreas Gohr			}
33559b616ccSAndreas Gohr
33659b616ccSAndreas Gohr			// Decompress the actual data
33759b616ccSAndreas Gohr			if (($this->data = gzinflate(substr($this->compressed_data, $this->position, -8))) === false)
33859b616ccSAndreas Gohr			{
33959b616ccSAndreas Gohr				return false;
34059b616ccSAndreas Gohr			}
341e43cd7e1SAndreas Gohr
34259b616ccSAndreas Gohr			$this->position = $this->compressed_size - 8;
34359b616ccSAndreas Gohr
34459b616ccSAndreas Gohr			// Check CRC of data
34559b616ccSAndreas Gohr			$crc = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
34659b616ccSAndreas Gohr			$this->position += 4;
34759b616ccSAndreas Gohr			/*if (extension_loaded('hash') && sprintf('%u', current(unpack('V', hash('crc32b', $this->data)))) !== sprintf('%u', $crc))
34859b616ccSAndreas Gohr			{
34959b616ccSAndreas Gohr				return false;
35059b616ccSAndreas Gohr			}*/
35159b616ccSAndreas Gohr
35259b616ccSAndreas Gohr			// Check ISIZE of data
35359b616ccSAndreas Gohr			$isize = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
35459b616ccSAndreas Gohr			$this->position += 4;
35559b616ccSAndreas Gohr			if (sprintf('%u', strlen($this->data) & 0xFFFFFFFF) !== sprintf('%u', $isize))
35659b616ccSAndreas Gohr			{
35759b616ccSAndreas Gohr				return false;
35859b616ccSAndreas Gohr			}
35959b616ccSAndreas Gohr
36059b616ccSAndreas Gohr			// Wow, against all odds, we've actually got a valid gzip string
36159b616ccSAndreas Gohr			return true;
36259b616ccSAndreas Gohr		}
363e43cd7e1SAndreas Gohr
36459b616ccSAndreas Gohr		return false;
36559b616ccSAndreas Gohr	}
36659b616ccSAndreas Gohr}
367