Spaces:
Sleeping
Sleeping
/** | |
* SimplePie | |
* | |
* A PHP-Based RSS and Atom Feed Framework. | |
* Takes the hard work out of managing a complete RSS/Atom solution. | |
* | |
* Copyright (c) 2004-2016, Ryan Parman, Sam Sneddon, Ryan McCue, and contributors | |
* All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without modification, are | |
* permitted provided that the following conditions are met: | |
* | |
* * Redistributions of source code must retain the above copyright notice, this list of | |
* conditions and the following disclaimer. | |
* | |
* * Redistributions in binary form must reproduce the above copyright notice, this list | |
* of conditions and the following disclaimer in the documentation and/or other materials | |
* provided with the distribution. | |
* | |
* * Neither the name of the SimplePie Team nor the names of its contributors may be used | |
* to endorse or promote products derived from this software without specific prior | |
* written permission. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS | |
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS | |
* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | |
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
* POSSIBILITY OF SUCH DAMAGE. | |
* | |
* @package SimplePie | |
* @copyright 2004-2016 Ryan Parman, Sam Sneddon, Ryan McCue | |
* @author Ryan Parman | |
* @author Sam Sneddon | |
* @author Ryan McCue | |
* @link http://simplepie.org/ SimplePie | |
* @license http://www.opensource.org/licenses/bsd-license.php BSD License | |
*/ | |
/** | |
* Decode 'gzip' encoded HTTP data | |
* | |
* @package SimplePie | |
* @subpackage HTTP | |
* @link http://www.gzip.org/format.txt | |
*/ | |
class SimplePie_gzdecode | |
{ | |
/** | |
* Compressed data | |
* | |
* @access private | |
* @var string | |
* @see gzdecode::$data | |
*/ | |
var $compressed_data; | |
/** | |
* Size of compressed data | |
* | |
* @access private | |
* @var int | |
*/ | |
var $compressed_size; | |
/** | |
* Minimum size of a valid gzip string | |
* | |
* @access private | |
* @var int | |
*/ | |
var $min_compressed_size = 18; | |
/** | |
* Current position of pointer | |
* | |
* @access private | |
* @var int | |
*/ | |
var $position = 0; | |
/** | |
* Flags (FLG) | |
* | |
* @access private | |
* @var int | |
*/ | |
var $flags; | |
/** | |
* Uncompressed data | |
* | |
* @access public | |
* @see gzdecode::$compressed_data | |
* @var string | |
*/ | |
var $data; | |
/** | |
* Modified time | |
* | |
* @access public | |
* @var int | |
*/ | |
var $MTIME; | |
/** | |
* Extra Flags | |
* | |
* @access public | |
* @var int | |
*/ | |
var $XFL; | |
/** | |
* Operating System | |
* | |
* @access public | |
* @var int | |
*/ | |
var $OS; | |
/** | |
* Subfield ID 1 | |
* | |
* @access public | |
* @see gzdecode::$extra_field | |
* @see gzdecode::$SI2 | |
* @var string | |
*/ | |
var $SI1; | |
/** | |
* Subfield ID 2 | |
* | |
* @access public | |
* @see gzdecode::$extra_field | |
* @see gzdecode::$SI1 | |
* @var string | |
*/ | |
var $SI2; | |
/** | |
* Extra field content | |
* | |
* @access public | |
* @see gzdecode::$SI1 | |
* @see gzdecode::$SI2 | |
* @var string | |
*/ | |
var $extra_field; | |
/** | |
* Original filename | |
* | |
* @access public | |
* @var string | |
*/ | |
var $filename; | |
/** | |
* Human readable comment | |
* | |
* @access public | |
* @var string | |
*/ | |
var $comment; | |
/** | |
* Don't allow anything to be set | |
* | |
* @param string $name | |
* @param mixed $value | |
*/ | |
public function __set($name, $value) | |
{ | |
trigger_error("Cannot write property $name", E_USER_ERROR); | |
} | |
/** | |
* Set the compressed string and related properties | |
* | |
* @param string $data | |
*/ | |
public function __construct($data) | |
{ | |
$this->compressed_data = $data; | |
$this->compressed_size = strlen($data); | |
} | |
/** | |
* Decode the GZIP stream | |
* | |
* @return bool Successfulness | |
*/ | |
public function parse() | |
{ | |
if ($this->compressed_size >= $this->min_compressed_size) | |
{ | |
// Check ID1, ID2, and CM | |
if (substr($this->compressed_data, 0, 3) !== "\x1F\x8B\x08") | |
{ | |
return false; | |
} | |
// Get the FLG (FLaGs) | |
$this->flags = ord($this->compressed_data[3]); | |
// FLG bits above (1 << 4) are reserved | |
if ($this->flags > 0x1F) | |
{ | |
return false; | |
} | |
// Advance the pointer after the above | |
$this->position += 4; | |
// MTIME | |
$mtime = substr($this->compressed_data, $this->position, 4); | |
// Reverse the string if we're on a big-endian arch because l is the only signed long and is machine endianness | |
if (current(unpack('S', "\x00\x01")) === 1) | |
{ | |
$mtime = strrev($mtime); | |
} | |
$this->MTIME = current(unpack('l', $mtime)); | |
$this->position += 4; | |
// Get the XFL (eXtra FLags) | |
$this->XFL = ord($this->compressed_data[$this->position++]); | |
// Get the OS (Operating System) | |
$this->OS = ord($this->compressed_data[$this->position++]); | |
// Parse the FEXTRA | |
if ($this->flags & 4) | |
{ | |
// Read subfield IDs | |
$this->SI1 = $this->compressed_data[$this->position++]; | |
$this->SI2 = $this->compressed_data[$this->position++]; | |
// SI2 set to zero is reserved for future use | |
if ($this->SI2 === "\x00") | |
{ | |
return false; | |
} | |
// Get the length of the extra field | |
$len = current(unpack('v', substr($this->compressed_data, $this->position, 2))); | |
$this->position += 2; | |
// Check the length of the string is still valid | |
$this->min_compressed_size += $len + 4; | |
if ($this->compressed_size >= $this->min_compressed_size) | |
{ | |
// Set the extra field to the given data | |
$this->extra_field = substr($this->compressed_data, $this->position, $len); | |
$this->position += $len; | |
} | |
else | |
{ | |
return false; | |
} | |
} | |
// Parse the FNAME | |
if ($this->flags & 8) | |
{ | |
// Get the length of the filename | |
$len = strcspn($this->compressed_data, "\x00", $this->position); | |
// Check the length of the string is still valid | |
$this->min_compressed_size += $len + 1; | |
if ($this->compressed_size >= $this->min_compressed_size) | |
{ | |
// Set the original filename to the given string | |
$this->filename = substr($this->compressed_data, $this->position, $len); | |
$this->position += $len + 1; | |
} | |
else | |
{ | |
return false; | |
} | |
} | |
// Parse the FCOMMENT | |
if ($this->flags & 16) | |
{ | |
// Get the length of the comment | |
$len = strcspn($this->compressed_data, "\x00", $this->position); | |
// Check the length of the string is still valid | |
$this->min_compressed_size += $len + 1; | |
if ($this->compressed_size >= $this->min_compressed_size) | |
{ | |
// Set the original comment to the given string | |
$this->comment = substr($this->compressed_data, $this->position, $len); | |
$this->position += $len + 1; | |
} | |
else | |
{ | |
return false; | |
} | |
} | |
// Parse the FHCRC | |
if ($this->flags & 2) | |
{ | |
// Check the length of the string is still valid | |
$this->min_compressed_size += $len + 2; | |
if ($this->compressed_size >= $this->min_compressed_size) | |
{ | |
// Read the CRC | |
$crc = current(unpack('v', substr($this->compressed_data, $this->position, 2))); | |
// Check the CRC matches | |
if ((crc32(substr($this->compressed_data, 0, $this->position)) & 0xFFFF) === $crc) | |
{ | |
$this->position += 2; | |
} | |
else | |
{ | |
return false; | |
} | |
} | |
else | |
{ | |
return false; | |
} | |
} | |
// Decompress the actual data | |
if (($this->data = gzinflate(substr($this->compressed_data, $this->position, -8))) === false) | |
{ | |
return false; | |
} | |
$this->position = $this->compressed_size - 8; | |
// Check CRC of data | |
$crc = current(unpack('V', substr($this->compressed_data, $this->position, 4))); | |
$this->position += 4; | |
/*if (extension_loaded('hash') && sprintf('%u', current(unpack('V', hash('crc32b', $this->data)))) !== sprintf('%u', $crc)) | |
{ | |
return false; | |
}*/ | |
// Check ISIZE of data | |
$isize = current(unpack('V', substr($this->compressed_data, $this->position, 4))); | |
$this->position += 4; | |
if (sprintf('%u', strlen($this->data) & 0xFFFFFFFF) !== sprintf('%u', $isize)) | |
{ | |
return false; | |
} | |
// Wow, against all odds, we've actually got a valid gzip string | |
return true; | |
} | |
return false; | |
} | |
} | |