/** * @return array Tar file data: * <pre> * KEY: Position in the array * VALUES: * attr - File attributes * data - Raw file contents * date - File modification time * name - Filename * size - Original file size * type - File type * </pre> * * @throws Horde_Compress_Exception */ public function decompress($data, array $params = array()) { $data_len = strlen($data); $position = 0; $return_array = array(); while ($position < $data_len) { if (version_compare(PHP_VERSION, '5.5', '>=')) { $info = @unpack('Z100filename/Z8mode/Z8uid/Z8gid/Z12size/Z12mtime/Z8checksum/Ctypeflag/Z100link/Z6magic/Z2version/Z32uname/Z32gname/Z8devmajor/Z8devminor', substr($data, $position)); } else { $info = @unpack('a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/Ctypeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor', substr($data, $position)); } if (!$info) { throw new Horde_Compress_Exception(Horde_Compress_Translation::t("Unable to decompress data.")); } $position += 512; $contents = substr($data, $position, octdec($info['size'])); $position += ceil(octdec($info['size']) / 512) * 512; if ($info['filename']) { $file = array('attr' => null, 'data' => null, 'date' => octdec($info['mtime']), 'name' => trim($info['filename']), 'size' => octdec($info['size']), 'type' => isset($this->_types[$info['typeflag']]) ? $this->_types[$info['typeflag']] : null); if ($info['typeflag'] == 0 || $info['typeflag'] == 0x30 || $info['typeflag'] == 0x35) { /* File or folder. */ $file['data'] = $contents; $mode = hexdec(substr($info['mode'], 4, 3)); $file['attr'] = ($info['typeflag'] == 0x35 ? 'd' : '-') . ($mode & 0x400 ? 'r' : '-') . ($mode & 0x200 ? 'w' : '-') . ($mode & 0x100 ? 'x' : '-') . ($mode & 0x40 ? 'r' : '-') . ($mode & 0x20 ? 'w' : '-') . ($mode & 0x10 ? 'x' : '-') . ($mode & 0x4 ? 'r' : '-') . ($mode & 0x2 ? 'w' : '-') . ($mode & 0x1 ? 'x' : '-'); } $return_array[] = $file; } } return $return_array; }
/** * @return array Info on the compressed file: * <pre> * KEY: Position in RAR archive * VALUES: * attr - File attributes * date - File modification time * csize - Compressed file size * method - Compression method * name - Filename * size - Original file size * </pre> * * @throws Horde_Compress_Exception */ public function decompress($data, array $params = array()) { $blockStart = strpos($data, self::BLOCK_START); if ($blockStart === false) { throw new Horde_Compress_Exception(Horde_Compress_Translation::t("Invalid RAR data.")); } $data_len = strlen($data); $position = $blockStart + 7; $return_array = array(); while ($position < $data_len) { if ($position + 7 > $data_len) { throw new Horde_Compress_Exception(Horde_Compress_Translation::t("Invalid RAR data.")); } //$head_crc = substr($data, $position, 2); $head_type = ord(substr($data, $position + 2, 1)); $head_flags = unpack('vFlags', substr($data, $position + 3, 2)); $head_flags = $head_flags['Flags']; $head_size = unpack('vSize', substr($data, $position + 5, 2)); $head_size = $head_size['Size']; $position += 7; $head_size -= 7; switch ($head_type) { case 0x73: /* Archive header */ $position += $head_size; break; case 0x74: /* File Header */ $info = unpack('VPacked/VUnpacked/COS/VCRC32/VTime/CVersion/CMethod/vLength/vAttrib', substr($data, $position)); $return_array[] = array('name' => substr($data, $position + 25, $info['Length']), 'size' => $info['Unpacked'], 'csize' => $info['Packed'], 'date' => mktime($info['Time'] >> 11 & 0x1f, $info['Time'] >> 5 & 0x3f, $info['Time'] << 1 & 0x3e, $info['Time'] >> 21 & 0x7, $info['Time'] >> 16 & 0x1f, ($info['Time'] >> 25 & 0x7f) + 80), 'method' => $this->_methods[$info['Method']], 'attr' => ($info['Attrib'] & 0x10 ? 'D' : '-') . ($info['Attrib'] & 0x20 ? 'A' : '-') . ($info['Attrib'] & 0x3 ? 'S' : '-') . ($info['Attrib'] & 0x2 ? 'H' : '-') . ($info['Attrib'] & 0x1 ? 'R' : '-')); $position += $head_size + $info['Packed']; break; default: if ($head_size == -7) { /* We've already added 7 bytes above. If we remove those * same 7 bytes, we will enter an infinite loop. */ throw new Horde_Compress_Exception(Horde_Compress_Translation::t("Invalid RAR data.")); } $position += $head_size; break; } } return $return_array; }
/** * @return string The uncompressed data. */ public function decompress($data, array $params = array()) { /* If gzip is not compiled into PHP, return now. */ if (!Horde_Util::extensionExists('zlib')) { throw new Horde_Compress_Exception(Horde_Compress_Translation::t("This server can't uncompress gzip files.")); } /* Gzipped File - decompress it first. */ $position = 0; $info = @unpack('CCM/CFLG/VTime/CXFL/COS', substr($data, $position + 2)); if (!$info) { throw new Horde_Compress_Exception(Horde_Compress_Translation::t("Unable to decompress data.")); } $position += 10; if ($info['FLG'] & $this->_flags['FEXTRA']) { $XLEN = unpack('vLength', substr($data, $position + 0, 2)); $XLEN = $XLEN['Length']; $position += $XLEN + 2; } if ($info['FLG'] & $this->_flags['FNAME']) { $filenamePos = strpos($data, "", $position); // Filename // substr($data, $position, $filenamePos - $position); $position = $filenamePos + 1; } if ($info['FLG'] & $this->_flags['FCOMMENT']) { $commentPos = strpos($data, "", $position); // Comment // substr($data, $position, $commentPos - $position); $position = $commentPos + 1; } if ($info['FLG'] & $this->_flags['FHCRC']) { $hcrc = unpack('vCRC', substr($data, $position + 0, 2)); $hcrc = $hcrc['CRC']; $position += 2; } $result = @gzinflate(substr($data, $position, strlen($data) - $position)); if (empty($result)) { throw new Horde_Compress_Exception(Horde_Compress_Translation::t("Unable to decompress data.")); } return $result; }
/** * TODO * * @param string $data TODO * @param integer $position TODO * * @throws Horde_Compress_Exception */ protected function _readIndex($data, $position) { $index_header = unpack('LFilePos/LUnknown1/LPrevIndex/LNextIndex/LCount/LUnknown', substr($data, $position, 24)); if ($index_header['FilePos'] != $position) { throw new Horde_Compress_Exception(Horde_Compress_Translation::t("Invalid file format")); } // Push it into list of processed items. $this->_tmp[$position] = true; if ($index_header['NextIndex'] > 0 && empty($this->_tmp[$index_header['NextIndex']])) { $this->_readIndex($data, $index_header['NextIndex']); } if ($index_header['PrevIndex'] > 0 && empty($this->_tmp[$index_header['PrevIndex']])) { $this->_readIndex($data, $index_header['PrevIndex']); } $position += 24; $icount = $index_header['Count'] >> 8; if ($icount > 0) { $buf = substr($data, $position, 12 * $icount); for ($i = 0; $i < $icount; $i++) { $hdr_buf = substr($buf, $i * 12, 12); $IndexItem = unpack('LHeaderPos/LChildIndex/LUnknown', $hdr_buf); if ($IndexItem['HeaderPos'] > 0) { $mail['info'] = $this->_readMessageInfo($data, $IndexItem['HeaderPos']); $mail['content'] = $this->_readMessage($data, $mail['info']['position']); $this->_mails[] = $mail; } if ($IndexItem['ChildIndex'] > 0 && empty($this->_tmp[$IndexItem['ChildIndex']])) { $this->_readIndex($data, $IndexItem['ChildIndex']); } } } }
/** * Get the list of files/data from the zip archive. * * @param string $data The zipfile data. * * @return array See decompress() for the format. * * @throws Horde_Compress_Exception */ protected function _getZipInfo($data) { $entries = array(); /* Get details from Central directory structure. */ $fhStart = strpos($data, self::CTRL_DIR_HEADER); do { if (strlen($data) < $fhStart + 31) { throw new Horde_Compress_Exception(Horde_Compress_Translation::t("Invalid ZIP data")); } $info = unpack('vMethod/VTime/VCRC32/VCompressed/VUncompressed/vLength', substr($data, $fhStart + 10, 20)); if (!isset($this->_methods[$info['Method']])) { throw new Horde_Compress_Exception(Horde_Compress_Translation::t("Invalid ZIP data")); } $name = substr($data, $fhStart + 46, $info['Length']); $entries[$name] = array('attr' => null, 'crc' => sprintf("%08s", dechex($info['CRC32'])), 'csize' => $info['Compressed'], 'date' => null, '_dataStart' => null, 'name' => $name, 'method' => $this->_methods[$info['Method']], '_method' => $info['Method'], 'size' => $info['Uncompressed'], 'type' => null); $entries[$name]['date'] = mktime($info['Time'] >> 11 & 0x1f, $info['Time'] >> 5 & 0x3f, $info['Time'] << 1 & 0x3e, $info['Time'] >> 21 & 0x7, $info['Time'] >> 16 & 0x1f, ($info['Time'] >> 25 & 0x7f) + 1980); if (strlen($data) < $fhStart + 43) { throw new Horde_Compress_Exception(Horde_Compress_Translation::t("Invalid ZIP data")); } $info = unpack('vInternal/VExternal', substr($data, $fhStart + 36, 6)); $entries[$name]['type'] = $info['Internal'] & 0x1 ? 'text' : 'binary'; $entries[$name]['attr'] = ($info['External'] & 0x10 ? 'D' : '-') . ($info['External'] & 0x20 ? 'A' : '-') . ($info['External'] & 0x3 ? 'S' : '-') . ($info['External'] & 0x2 ? 'H' : '-') . ($info['External'] & 0x1 ? 'R' : '-'); } while (($fhStart = strpos($data, self::CTRL_DIR_HEADER, $fhStart + 46)) !== false); /* Get details from local file header. */ $fhStart = strpos($data, self::FILE_HEADER); $data_len = strlen($data); do { if ($data_len < $fhStart + 34) { throw new Horde_Compress_Exception(Horde_Compress_Translation::t("Invalid ZIP data")); } $info = unpack('vMethod/VTime/VCRC32/VCompressed/VUncompressed/vLength/vExtraLength', substr($data, $fhStart + 8, 25)); $name = substr($data, $fhStart + 30, $info['Length']); if (isset($entries[$name])) { $entries[$name]['_dataStart'] = $fhStart + 30 + $info['Length'] + $info['ExtraLength']; } } while ($data_len > $fhStart + 30 + $info['Length'] && ($fhStart = strpos($data, self::FILE_HEADER, $fhStart + 30 + $info['Length'])) !== false); return array_values($entries); }
/** * Returns the plural translation of a message. * * @param string $singular The singular version to translate. * @param string $plural The plural version to translate. * @param integer $number The number that determines singular vs. plural. * * @return string The string translation, or the original string if no * translation exists. */ public static function ngettext($singular, $plural, $number) { self::$_domain = 'Horde_Compress'; self::$_directory = '@data_dir@' == '@' . 'data_dir' . '@' ? __DIR__ . '/../../../locale' : '@data_dir@/Horde_Compress/locale'; return parent::ngettext($singular, $plural, $number); }