xref: /dokuwiki/vendor/simplepie/simplepie/library/SimplePie/gzdecode.php (revision 59b616ccfd538b2ad784685b41eecdcdcfbf5719)
1*59b616ccSAndreas Gohr<?php
2*59b616ccSAndreas Gohr/**
3*59b616ccSAndreas Gohr * SimplePie
4*59b616ccSAndreas Gohr *
5*59b616ccSAndreas Gohr * A PHP-Based RSS and Atom Feed Framework.
6*59b616ccSAndreas Gohr * Takes the hard work out of managing a complete RSS/Atom solution.
7*59b616ccSAndreas Gohr *
8*59b616ccSAndreas Gohr * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9*59b616ccSAndreas Gohr * All rights reserved.
10*59b616ccSAndreas Gohr *
11*59b616ccSAndreas Gohr * Redistribution and use in source and binary forms, with or without modification, are
12*59b616ccSAndreas Gohr * permitted provided that the following conditions are met:
13*59b616ccSAndreas Gohr *
14*59b616ccSAndreas Gohr * 	* Redistributions of source code must retain the above copyright notice, this list of
15*59b616ccSAndreas Gohr * 	  conditions and the following disclaimer.
16*59b616ccSAndreas Gohr *
17*59b616ccSAndreas Gohr * 	* Redistributions in binary form must reproduce the above copyright notice, this list
18*59b616ccSAndreas Gohr * 	  of conditions and the following disclaimer in the documentation and/or other materials
19*59b616ccSAndreas Gohr * 	  provided with the distribution.
20*59b616ccSAndreas Gohr *
21*59b616ccSAndreas Gohr * 	* Neither the name of the SimplePie Team nor the names of its contributors may be used
22*59b616ccSAndreas Gohr * 	  to endorse or promote products derived from this software without specific prior
23*59b616ccSAndreas Gohr * 	  written permission.
24*59b616ccSAndreas Gohr *
25*59b616ccSAndreas Gohr * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26*59b616ccSAndreas Gohr * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27*59b616ccSAndreas Gohr * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28*59b616ccSAndreas Gohr * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29*59b616ccSAndreas Gohr * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30*59b616ccSAndreas Gohr * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31*59b616ccSAndreas Gohr * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32*59b616ccSAndreas Gohr * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33*59b616ccSAndreas Gohr * POSSIBILITY OF SUCH DAMAGE.
34*59b616ccSAndreas Gohr *
35*59b616ccSAndreas Gohr * @package SimplePie
36*59b616ccSAndreas Gohr * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue
37*59b616ccSAndreas Gohr * @author Ryan Parman
38*59b616ccSAndreas Gohr * @author Geoffrey Sneddon
39*59b616ccSAndreas Gohr * @author Ryan McCue
40*59b616ccSAndreas Gohr * @link http://simplepie.org/ SimplePie
41*59b616ccSAndreas Gohr * @license http://www.opensource.org/licenses/bsd-license.php BSD License
42*59b616ccSAndreas Gohr */
43*59b616ccSAndreas Gohr
44*59b616ccSAndreas Gohr
45*59b616ccSAndreas Gohr/**
46*59b616ccSAndreas Gohr * Decode 'gzip' encoded HTTP data
47*59b616ccSAndreas Gohr *
48*59b616ccSAndreas Gohr * @package SimplePie
49*59b616ccSAndreas Gohr * @subpackage HTTP
50*59b616ccSAndreas Gohr * @link http://www.gzip.org/format.txt
51*59b616ccSAndreas Gohr */
52*59b616ccSAndreas Gohrclass SimplePie_gzdecode
53*59b616ccSAndreas Gohr{
54*59b616ccSAndreas Gohr	/**
55*59b616ccSAndreas Gohr	 * Compressed data
56*59b616ccSAndreas Gohr	 *
57*59b616ccSAndreas Gohr	 * @access private
58*59b616ccSAndreas Gohr	 * @var string
59*59b616ccSAndreas Gohr	 * @see gzdecode::$data
60*59b616ccSAndreas Gohr	 */
61*59b616ccSAndreas Gohr	var $compressed_data;
62*59b616ccSAndreas Gohr
63*59b616ccSAndreas Gohr	/**
64*59b616ccSAndreas Gohr	 * Size of compressed data
65*59b616ccSAndreas Gohr	 *
66*59b616ccSAndreas Gohr	 * @access private
67*59b616ccSAndreas Gohr	 * @var int
68*59b616ccSAndreas Gohr	 */
69*59b616ccSAndreas Gohr	var $compressed_size;
70*59b616ccSAndreas Gohr
71*59b616ccSAndreas Gohr	/**
72*59b616ccSAndreas Gohr	 * Minimum size of a valid gzip string
73*59b616ccSAndreas Gohr	 *
74*59b616ccSAndreas Gohr	 * @access private
75*59b616ccSAndreas Gohr	 * @var int
76*59b616ccSAndreas Gohr	 */
77*59b616ccSAndreas Gohr	var $min_compressed_size = 18;
78*59b616ccSAndreas Gohr
79*59b616ccSAndreas Gohr	/**
80*59b616ccSAndreas Gohr	 * Current position of pointer
81*59b616ccSAndreas Gohr	 *
82*59b616ccSAndreas Gohr	 * @access private
83*59b616ccSAndreas Gohr	 * @var int
84*59b616ccSAndreas Gohr	 */
85*59b616ccSAndreas Gohr	var $position = 0;
86*59b616ccSAndreas Gohr
87*59b616ccSAndreas Gohr	/**
88*59b616ccSAndreas Gohr	 * Flags (FLG)
89*59b616ccSAndreas Gohr	 *
90*59b616ccSAndreas Gohr	 * @access private
91*59b616ccSAndreas Gohr	 * @var int
92*59b616ccSAndreas Gohr	 */
93*59b616ccSAndreas Gohr	var $flags;
94*59b616ccSAndreas Gohr
95*59b616ccSAndreas Gohr	/**
96*59b616ccSAndreas Gohr	 * Uncompressed data
97*59b616ccSAndreas Gohr	 *
98*59b616ccSAndreas Gohr	 * @access public
99*59b616ccSAndreas Gohr	 * @see gzdecode::$compressed_data
100*59b616ccSAndreas Gohr	 * @var string
101*59b616ccSAndreas Gohr	 */
102*59b616ccSAndreas Gohr	var $data;
103*59b616ccSAndreas Gohr
104*59b616ccSAndreas Gohr	/**
105*59b616ccSAndreas Gohr	 * Modified time
106*59b616ccSAndreas Gohr	 *
107*59b616ccSAndreas Gohr	 * @access public
108*59b616ccSAndreas Gohr	 * @var int
109*59b616ccSAndreas Gohr	 */
110*59b616ccSAndreas Gohr	var $MTIME;
111*59b616ccSAndreas Gohr
112*59b616ccSAndreas Gohr	/**
113*59b616ccSAndreas Gohr	 * Extra Flags
114*59b616ccSAndreas Gohr	 *
115*59b616ccSAndreas Gohr	 * @access public
116*59b616ccSAndreas Gohr	 * @var int
117*59b616ccSAndreas Gohr	 */
118*59b616ccSAndreas Gohr	var $XFL;
119*59b616ccSAndreas Gohr
120*59b616ccSAndreas Gohr	/**
121*59b616ccSAndreas Gohr	 * Operating System
122*59b616ccSAndreas Gohr	 *
123*59b616ccSAndreas Gohr	 * @access public
124*59b616ccSAndreas Gohr	 * @var int
125*59b616ccSAndreas Gohr	 */
126*59b616ccSAndreas Gohr	var $OS;
127*59b616ccSAndreas Gohr
128*59b616ccSAndreas Gohr	/**
129*59b616ccSAndreas Gohr	 * Subfield ID 1
130*59b616ccSAndreas Gohr	 *
131*59b616ccSAndreas Gohr	 * @access public
132*59b616ccSAndreas Gohr	 * @see gzdecode::$extra_field
133*59b616ccSAndreas Gohr	 * @see gzdecode::$SI2
134*59b616ccSAndreas Gohr	 * @var string
135*59b616ccSAndreas Gohr	 */
136*59b616ccSAndreas Gohr	var $SI1;
137*59b616ccSAndreas Gohr
138*59b616ccSAndreas Gohr	/**
139*59b616ccSAndreas Gohr	 * Subfield ID 2
140*59b616ccSAndreas Gohr	 *
141*59b616ccSAndreas Gohr	 * @access public
142*59b616ccSAndreas Gohr	 * @see gzdecode::$extra_field
143*59b616ccSAndreas Gohr	 * @see gzdecode::$SI1
144*59b616ccSAndreas Gohr	 * @var string
145*59b616ccSAndreas Gohr	 */
146*59b616ccSAndreas Gohr	var $SI2;
147*59b616ccSAndreas Gohr
148*59b616ccSAndreas Gohr	/**
149*59b616ccSAndreas Gohr	 * Extra field content
150*59b616ccSAndreas Gohr	 *
151*59b616ccSAndreas Gohr	 * @access public
152*59b616ccSAndreas Gohr	 * @see gzdecode::$SI1
153*59b616ccSAndreas Gohr	 * @see gzdecode::$SI2
154*59b616ccSAndreas Gohr	 * @var string
155*59b616ccSAndreas Gohr	 */
156*59b616ccSAndreas Gohr	var $extra_field;
157*59b616ccSAndreas Gohr
158*59b616ccSAndreas Gohr	/**
159*59b616ccSAndreas Gohr	 * Original filename
160*59b616ccSAndreas Gohr	 *
161*59b616ccSAndreas Gohr	 * @access public
162*59b616ccSAndreas Gohr	 * @var string
163*59b616ccSAndreas Gohr	 */
164*59b616ccSAndreas Gohr	var $filename;
165*59b616ccSAndreas Gohr
166*59b616ccSAndreas Gohr	/**
167*59b616ccSAndreas Gohr	 * Human readable comment
168*59b616ccSAndreas Gohr	 *
169*59b616ccSAndreas Gohr	 * @access public
170*59b616ccSAndreas Gohr	 * @var string
171*59b616ccSAndreas Gohr	 */
172*59b616ccSAndreas Gohr	var $comment;
173*59b616ccSAndreas Gohr
174*59b616ccSAndreas Gohr	/**
175*59b616ccSAndreas Gohr	 * Don't allow anything to be set
176*59b616ccSAndreas Gohr	 *
177*59b616ccSAndreas Gohr	 * @param string $name
178*59b616ccSAndreas Gohr	 * @param mixed $value
179*59b616ccSAndreas Gohr	 */
180*59b616ccSAndreas Gohr	public function __set($name, $value)
181*59b616ccSAndreas Gohr	{
182*59b616ccSAndreas Gohr		trigger_error("Cannot write property $name", E_USER_ERROR);
183*59b616ccSAndreas Gohr	}
184*59b616ccSAndreas Gohr
185*59b616ccSAndreas Gohr	/**
186*59b616ccSAndreas Gohr	 * Set the compressed string and related properties
187*59b616ccSAndreas Gohr	 *
188*59b616ccSAndreas Gohr	 * @param string $data
189*59b616ccSAndreas Gohr	 */
190*59b616ccSAndreas Gohr	public function __construct($data)
191*59b616ccSAndreas Gohr	{
192*59b616ccSAndreas Gohr		$this->compressed_data = $data;
193*59b616ccSAndreas Gohr		$this->compressed_size = strlen($data);
194*59b616ccSAndreas Gohr	}
195*59b616ccSAndreas Gohr
196*59b616ccSAndreas Gohr	/**
197*59b616ccSAndreas Gohr	 * Decode the GZIP stream
198*59b616ccSAndreas Gohr	 *
199*59b616ccSAndreas Gohr	 * @return bool Successfulness
200*59b616ccSAndreas Gohr	 */
201*59b616ccSAndreas Gohr	public function parse()
202*59b616ccSAndreas Gohr	{
203*59b616ccSAndreas Gohr		if ($this->compressed_size >= $this->min_compressed_size)
204*59b616ccSAndreas Gohr		{
205*59b616ccSAndreas Gohr			// Check ID1, ID2, and CM
206*59b616ccSAndreas Gohr			if (substr($this->compressed_data, 0, 3) !== "\x1F\x8B\x08")
207*59b616ccSAndreas Gohr			{
208*59b616ccSAndreas Gohr				return false;
209*59b616ccSAndreas Gohr			}
210*59b616ccSAndreas Gohr
211*59b616ccSAndreas Gohr			// Get the FLG (FLaGs)
212*59b616ccSAndreas Gohr			$this->flags = ord($this->compressed_data[3]);
213*59b616ccSAndreas Gohr
214*59b616ccSAndreas Gohr			// FLG bits above (1 << 4) are reserved
215*59b616ccSAndreas Gohr			if ($this->flags > 0x1F)
216*59b616ccSAndreas Gohr			{
217*59b616ccSAndreas Gohr				return false;
218*59b616ccSAndreas Gohr			}
219*59b616ccSAndreas Gohr
220*59b616ccSAndreas Gohr			// Advance the pointer after the above
221*59b616ccSAndreas Gohr			$this->position += 4;
222*59b616ccSAndreas Gohr
223*59b616ccSAndreas Gohr			// MTIME
224*59b616ccSAndreas Gohr			$mtime = substr($this->compressed_data, $this->position, 4);
225*59b616ccSAndreas Gohr			// Reverse the string if we're on a big-endian arch because l is the only signed long and is machine endianness
226*59b616ccSAndreas Gohr			if (current(unpack('S', "\x00\x01")) === 1)
227*59b616ccSAndreas Gohr			{
228*59b616ccSAndreas Gohr				$mtime = strrev($mtime);
229*59b616ccSAndreas Gohr			}
230*59b616ccSAndreas Gohr			$this->MTIME = current(unpack('l', $mtime));
231*59b616ccSAndreas Gohr			$this->position += 4;
232*59b616ccSAndreas Gohr
233*59b616ccSAndreas Gohr			// Get the XFL (eXtra FLags)
234*59b616ccSAndreas Gohr			$this->XFL = ord($this->compressed_data[$this->position++]);
235*59b616ccSAndreas Gohr
236*59b616ccSAndreas Gohr			// Get the OS (Operating System)
237*59b616ccSAndreas Gohr			$this->OS = ord($this->compressed_data[$this->position++]);
238*59b616ccSAndreas Gohr
239*59b616ccSAndreas Gohr			// Parse the FEXTRA
240*59b616ccSAndreas Gohr			if ($this->flags & 4)
241*59b616ccSAndreas Gohr			{
242*59b616ccSAndreas Gohr				// Read subfield IDs
243*59b616ccSAndreas Gohr				$this->SI1 = $this->compressed_data[$this->position++];
244*59b616ccSAndreas Gohr				$this->SI2 = $this->compressed_data[$this->position++];
245*59b616ccSAndreas Gohr
246*59b616ccSAndreas Gohr				// SI2 set to zero is reserved for future use
247*59b616ccSAndreas Gohr				if ($this->SI2 === "\x00")
248*59b616ccSAndreas Gohr				{
249*59b616ccSAndreas Gohr					return false;
250*59b616ccSAndreas Gohr				}
251*59b616ccSAndreas Gohr
252*59b616ccSAndreas Gohr				// Get the length of the extra field
253*59b616ccSAndreas Gohr				$len = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
254*59b616ccSAndreas Gohr				$this->position += 2;
255*59b616ccSAndreas Gohr
256*59b616ccSAndreas Gohr				// Check the length of the string is still valid
257*59b616ccSAndreas Gohr				$this->min_compressed_size += $len + 4;
258*59b616ccSAndreas Gohr				if ($this->compressed_size >= $this->min_compressed_size)
259*59b616ccSAndreas Gohr				{
260*59b616ccSAndreas Gohr					// Set the extra field to the given data
261*59b616ccSAndreas Gohr					$this->extra_field = substr($this->compressed_data, $this->position, $len);
262*59b616ccSAndreas Gohr					$this->position += $len;
263*59b616ccSAndreas Gohr				}
264*59b616ccSAndreas Gohr				else
265*59b616ccSAndreas Gohr				{
266*59b616ccSAndreas Gohr					return false;
267*59b616ccSAndreas Gohr				}
268*59b616ccSAndreas Gohr			}
269*59b616ccSAndreas Gohr
270*59b616ccSAndreas Gohr			// Parse the FNAME
271*59b616ccSAndreas Gohr			if ($this->flags & 8)
272*59b616ccSAndreas Gohr			{
273*59b616ccSAndreas Gohr				// Get the length of the filename
274*59b616ccSAndreas Gohr				$len = strcspn($this->compressed_data, "\x00", $this->position);
275*59b616ccSAndreas Gohr
276*59b616ccSAndreas Gohr				// Check the length of the string is still valid
277*59b616ccSAndreas Gohr				$this->min_compressed_size += $len + 1;
278*59b616ccSAndreas Gohr				if ($this->compressed_size >= $this->min_compressed_size)
279*59b616ccSAndreas Gohr				{
280*59b616ccSAndreas Gohr					// Set the original filename to the given string
281*59b616ccSAndreas Gohr					$this->filename = substr($this->compressed_data, $this->position, $len);
282*59b616ccSAndreas Gohr					$this->position += $len + 1;
283*59b616ccSAndreas Gohr				}
284*59b616ccSAndreas Gohr				else
285*59b616ccSAndreas Gohr				{
286*59b616ccSAndreas Gohr					return false;
287*59b616ccSAndreas Gohr				}
288*59b616ccSAndreas Gohr			}
289*59b616ccSAndreas Gohr
290*59b616ccSAndreas Gohr			// Parse the FCOMMENT
291*59b616ccSAndreas Gohr			if ($this->flags & 16)
292*59b616ccSAndreas Gohr			{
293*59b616ccSAndreas Gohr				// Get the length of the comment
294*59b616ccSAndreas Gohr				$len = strcspn($this->compressed_data, "\x00", $this->position);
295*59b616ccSAndreas Gohr
296*59b616ccSAndreas Gohr				// Check the length of the string is still valid
297*59b616ccSAndreas Gohr				$this->min_compressed_size += $len + 1;
298*59b616ccSAndreas Gohr				if ($this->compressed_size >= $this->min_compressed_size)
299*59b616ccSAndreas Gohr				{
300*59b616ccSAndreas Gohr					// Set the original comment to the given string
301*59b616ccSAndreas Gohr					$this->comment = substr($this->compressed_data, $this->position, $len);
302*59b616ccSAndreas Gohr					$this->position += $len + 1;
303*59b616ccSAndreas Gohr				}
304*59b616ccSAndreas Gohr				else
305*59b616ccSAndreas Gohr				{
306*59b616ccSAndreas Gohr					return false;
307*59b616ccSAndreas Gohr				}
308*59b616ccSAndreas Gohr			}
309*59b616ccSAndreas Gohr
310*59b616ccSAndreas Gohr			// Parse the FHCRC
311*59b616ccSAndreas Gohr			if ($this->flags & 2)
312*59b616ccSAndreas Gohr			{
313*59b616ccSAndreas Gohr				// Check the length of the string is still valid
314*59b616ccSAndreas Gohr				$this->min_compressed_size += $len + 2;
315*59b616ccSAndreas Gohr				if ($this->compressed_size >= $this->min_compressed_size)
316*59b616ccSAndreas Gohr				{
317*59b616ccSAndreas Gohr					// Read the CRC
318*59b616ccSAndreas Gohr					$crc = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
319*59b616ccSAndreas Gohr
320*59b616ccSAndreas Gohr					// Check the CRC matches
321*59b616ccSAndreas Gohr					if ((crc32(substr($this->compressed_data, 0, $this->position)) & 0xFFFF) === $crc)
322*59b616ccSAndreas Gohr					{
323*59b616ccSAndreas Gohr						$this->position += 2;
324*59b616ccSAndreas Gohr					}
325*59b616ccSAndreas Gohr					else
326*59b616ccSAndreas Gohr					{
327*59b616ccSAndreas Gohr						return false;
328*59b616ccSAndreas Gohr					}
329*59b616ccSAndreas Gohr				}
330*59b616ccSAndreas Gohr				else
331*59b616ccSAndreas Gohr				{
332*59b616ccSAndreas Gohr					return false;
333*59b616ccSAndreas Gohr				}
334*59b616ccSAndreas Gohr			}
335*59b616ccSAndreas Gohr
336*59b616ccSAndreas Gohr			// Decompress the actual data
337*59b616ccSAndreas Gohr			if (($this->data = gzinflate(substr($this->compressed_data, $this->position, -8))) === false)
338*59b616ccSAndreas Gohr			{
339*59b616ccSAndreas Gohr				return false;
340*59b616ccSAndreas Gohr			}
341*59b616ccSAndreas Gohr			else
342*59b616ccSAndreas Gohr			{
343*59b616ccSAndreas Gohr				$this->position = $this->compressed_size - 8;
344*59b616ccSAndreas Gohr			}
345*59b616ccSAndreas Gohr
346*59b616ccSAndreas Gohr			// Check CRC of data
347*59b616ccSAndreas Gohr			$crc = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
348*59b616ccSAndreas Gohr			$this->position += 4;
349*59b616ccSAndreas Gohr			/*if (extension_loaded('hash') && sprintf('%u', current(unpack('V', hash('crc32b', $this->data)))) !== sprintf('%u', $crc))
350*59b616ccSAndreas Gohr			{
351*59b616ccSAndreas Gohr				return false;
352*59b616ccSAndreas Gohr			}*/
353*59b616ccSAndreas Gohr
354*59b616ccSAndreas Gohr			// Check ISIZE of data
355*59b616ccSAndreas Gohr			$isize = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
356*59b616ccSAndreas Gohr			$this->position += 4;
357*59b616ccSAndreas Gohr			if (sprintf('%u', strlen($this->data) & 0xFFFFFFFF) !== sprintf('%u', $isize))
358*59b616ccSAndreas Gohr			{
359*59b616ccSAndreas Gohr				return false;
360*59b616ccSAndreas Gohr			}
361*59b616ccSAndreas Gohr
362*59b616ccSAndreas Gohr			// Wow, against all odds, we've actually got a valid gzip string
363*59b616ccSAndreas Gohr			return true;
364*59b616ccSAndreas Gohr		}
365*59b616ccSAndreas Gohr		else
366*59b616ccSAndreas Gohr		{
367*59b616ccSAndreas Gohr			return false;
368*59b616ccSAndreas Gohr		}
369*59b616ccSAndreas Gohr	}
370*59b616ccSAndreas Gohr}
371