* @category Horde
* @copyright 2008-2017 Horde LLC
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package Compress
*/
class Horde_Compress_Rar extends Horde_Compress_Base
{
const BLOCK_START = "\x52\x61\x72\x21\x1a\x07\x00";
/**
*/
public $canDecompress = true;
/**
* Rar compression methods
*
* @var array
*/
protected $_methods = array(
0x30 => 'Store',
0x31 => 'Fastest',
0x32 => 'Fast',
0x33 => 'Normal',
0x34 => 'Good',
0x35 => 'Best'
);
/**
* @return array Info on the compressed file:
*
* 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
*
*
* @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)
);
$year = (($info['Time'] >> 25) & 0x7f) + 80;
$name = substr($data, $position + 25, $info['Length']);
if ($unicode = strpos($name, "\0")) {
$name = substr($name, 0, $unicode);
}
$return_array[] = array(
'name' => $name,
'size' => $info['Unpacked'],
'csize' => $info['Packed'],
'date' => mktime(
(($info['Time'] >> 11) & 0x1f),
(($info['Time'] >> 5) & 0x3f),
(($info['Time'] << 1) & 0x3e),
(($info['Time'] >> 21) & 0x07),
(($info['Time'] >> 16) & 0x1f),
$year < 1900 ? $year + 1900 : $year
),
'method' => $this->_methods[$info['Method']],
'attr' => (($info['Attrib'] & 0x10) ? 'D' : '-') .
(($info['Attrib'] & 0x20) ? 'A' : '-') .
(($info['Attrib'] & 0x03) ? 'S' : '-') .
(($info['Attrib'] & 0x02) ? 'H' : '-') .
(($info['Attrib'] & 0x01) ? '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;
}
}
Horde_Compress-2.2.1/lib/Horde/Compress/Tar.php 0000664 0001750 0001750 00000023751 13150756215 017412 0 ustar jan jan
* @author Michael Slusarz
* @author Jan Schneider
* @category Horde
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package Compress
*/
/**
* This class allows tar files to be read.
*
* @author Michael Cochrane
* @author Michael Slusarz
* @author Jan Schneider
* @category Horde
* @copyright 2002-2017 Horde LLC
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package Compress
*/
class Horde_Compress_Tar extends Horde_Compress_Base
{
/**
*/
public $canCompress = true;
/**
*/
public $canDecompress = true;
/**
* Tar file types.
*
* @var array
*/
protected $_types = array(
0x0 => 'Unix file',
0x30 => 'File',
0x31 => 'Link',
0x32 => 'Symbolic link',
0x33 => 'Character special file',
0x34 => 'Block special file',
0x35 => 'Directory',
0x36 => 'FIFO special file',
0x37 => 'Contiguous file'
);
/**
* Temporary contents for compressing files.
*
* @var resource
*/
protected $_tmp;
/**
* @since Horde_Compress 2.2.0
*
* @param array $data The data to compress. Requires an array of
* arrays. Each subarray should contain these
* fields:
* - data: (string/resource) The data to compress.
* - name: (string) The pathname to the file.
* - time: (integer) [optional] The timestamp to use for the file.
* - spl: (SplFileInfo) [optional] Complete file information.
* @param array $params The parameter array.
* - stream: (boolean) If set, return a stream instead of a string.
* DEFAULT: Return string
*
* @return mixed The TAR file as either a string or a stream resource.
*/
public function compress($data, array $params = array())
{
$this->_tmp = fopen('php://temp', 'r+');
foreach ($data as $file) {
/* Split up long file names. */
$name = str_replace('\\', '/', $file['name']);
$prefix = '';
if (strlen($name) > 99) {
$prefix = $name;
$name = '';
if (strlen($prefix) > 154) {
$name = substr($prefix, 154);
$prefix = substr($prefix, 0, 154);
}
}
/* See if time/date information has been provided. */
$ftime = (isset($file['time'])) ? $file['time'] : null;
/* "Local file header" segment. */
if (is_resource($file['data'])) {
fseek($file['data'], 0, SEEK_END);
$length = ftell($file['data']);
} else {
$length = strlen($file['data']);
}
/* Gather extended information. */
if (isset($file['spl'])) {
$isLink = $file['spl']->isLink();
$link = $isLink ? $this->_getLink($file['spl']) : '';
if (function_exists('posix_getpwuid')) {
$posix = posix_getpwuid($file['spl']->getOwner());
$owner = $posix['name'];
}
if (function_exists('posix_getgrgid')) {
$posix = posix_getgrgid($file['spl']->getGroup());
$group = $posix['name'];
}
} else {
$isLink = false;
$link = $owner = $group = '';
}
/* Header data for the file entries. */
$header =
pack('a99', $name) . "\0" . /* Name. */
$this->_formatNumber($file, 'getPerms') . /* Permissions. */
$this->_formatNumber($file, 'getOwner') . /* Owner ID. */
$this->_formatNumber($file, 'getGroup') . /* Group ID. */
sprintf("%011o\0", $isLink ? 0 : $length) . /* Size. */
sprintf("%011o\0", $ftime) . /* MTime. */
' ' . /* Checksum. */
($isLink ? '1' : '0') . /* Type. */
pack('a99', $link) . "\0" . /* Link target. */
"ustar\0" . "00" . /* Magic marker. */
pack('a31', $owner) . "\0" . /* Owner name. */
pack('a31', $group) . "\0" . /* Group name. */
pack('a16', '') . /* Device numbers. */
pack('a154', $prefix) . "\0"; /* Name prefix. */
$header = pack('a512', $header);
$checksum = array_sum(array_map('ord', str_split($header)));
$header = substr($header, 0, 148)
. sprintf("%06o\0 ", $checksum)
. substr($header, 156);
/* Add this entry to TAR data. */
fwrite($this->_tmp, $header);
/* "File data" segment. */
if (is_resource($file['data'])) {
rewind($file['data']);
stream_copy_to_stream($file['data'], $this->_tmp);
} else {
fwrite($this->_tmp, $file['data']);
}
/* Add 512 byte block padding. */
fwrite($this->_tmp, str_repeat("\0", 512 - ($length % 512)));
}
/* End of archive. */
fwrite($this->_tmp, str_repeat("\0", 1024));
rewind($this->_tmp);
if (empty($params['stream'])) {
$out = stream_get_contents($this->_tmp);
fclose($this->_tmp);
return $out;
}
return $this->_tmp;
}
/**
* Returns the relative path of a symbolic link
*
* @param SplFileInfo $spl An SplFileInfo object.
*
* @return string The relative path of the symbolic link.
*/
protected function _getLink($spl)
{
$ds = DIRECTORY_SEPARATOR;
$from = explode($ds, rtrim($spl->getPathname(), $ds));
$to = explode($ds, rtrim($spl->getRealPath(), $ds));
while (count($from) && count($to) && ($from[0] == $to[0])) {
array_shift($from);
array_shift($to);
}
return str_repeat('..' . $ds, count($from)) . implode($ds, $to);
}
/**
* Formats a number from the file information for the TAR format.
*
* @param array $file A file hash from compress() that may include a
* 'spl' entry with an .
* @param string $method The method of the SplFileInfo object that returns
* the requested number.
*
* @return string The correctly formatted number.
*/
protected function _formatNumber($file, $method)
{
if (isset($file['spl'])) {
return sprintf("%07o\0", $file['spl']->$method());
}
return pack('a8', '');
}
/**
* @return array Tar file data:
*
* 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
*
*
* @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 & 0x040) ? 'r' : '-') .
(($mode & 0x020) ? 'w' : '-') .
(($mode & 0x010) ? 'x' : '-') .
(($mode & 0x004) ? 'r' : '-') .
(($mode & 0x002) ? 'w' : '-') .
(($mode & 0x001) ? 'x' : '-');
}
$return_array[] = $file;
}
}
return $return_array;
}
}
Horde_Compress-2.2.1/lib/Horde/Compress/Tnef.php 0000664 0001750 0001750 00000075706 13150756215 017567 0 ustar jan jan
* Original design by:
* Thomas Boll , Mark Simpson
*
* @author Jan Schneider
* @author Michael Slusarz
* @author Michael J Rubinsky
* @category Horde
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package Compress
*/
/**
* The Horde_Compress_Tnef class allows MS-TNEF data to be displayed.
*
* @author Jan Schneider
* @author Michael Slusarz
* @author Michael J Rubinsky
* @category Horde
* @copyright 2002-2017 Horde LLC
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package Compress
*/
class Horde_Compress_Tnef extends Horde_Compress_Base
{
const PSETID_MEETING = '{6ED8DA90-450B-101B-98DA-00AA003F1305}';
const PSETID_APPOINTMENT = '{00062002-0000-0000-C000-000000000046}';
const PSETID_COMMON = '{00062008-0000-0000-C000-000000000046}';
const PSETID_PUBLIC_STRINGS = '{00020329-0000-0000-C000-000000000046}';
const PSETID_NOTE = '{0006200E-0000-0000-C000-000000000046}';
const PSETID_TASK = '{00062003-0000-0000-C000-000000000046}';
const PSETID_MAPI = '{00020328-0000-0000-C000-000000000046}';
const SIGNATURE = 0x223e9f78;
const LVL_MESSAGE = 0x01;
const LVL_ATTACHMENT = 0x02;
// @deprecated Now lives in Horde_Compress_Tnef_Rtf::
const RTF_COMPRESSED = 0x75465a4c;
const RTF_UNCOMPRESSED = 0x414c454d;
// TNEF specific properties (includes the type).
const AOWNER = 0x60000;
const ASENTFOR = 0x60001;
const AORIGINALMCLASS = 0x70006;
const ASUBJECT = 0x18004;
const ADATESENT = 0x38005;
const ADATERECEIVED = 0x38006;
const AFROM = 0x08000;
const ASTATUS = 0x68007;
const AMCLASS = 0x78008;
const AMESSAGEID = 0x18009;
const APARENTID = 0x1800a;
const ACONVERSATIONID = 0x1800b;
const ABODY = 0x2800c;
const APRIORITY = 0x4800d;
const ATTACHDATA = 0x6800f;
const AFILENAME = 0x18010;
const ATTACHMETAFILE = 0x68011;
const ATTACHCREATEDATE = 0x38012;
const ADATEMODIFIED = 0x38020;
// idAttachRendData
const ARENDDATA = 0x69002;
const AMAPIPROPS = 0x69003;
const ARECIPIENTTABLE = 0x69004;
const AMAPIATTRS = 0x69005;
// @deprecated constants to be removed in H6
const OEMCODEPAGE = 0x69007;
const AVERSION = 0x89006;
const ID_REQUEST_RESP = 0x40009;
const ID_FROM = 0x8000;
const AIDOWNER = 0x50008;
const ID_DATE_START = 0x30006;
const ID_DATE_END = 0x30007;
// All valid MAPI data types.
// @todo These should all be MAPI_TYPE_*
const MAPI_TYPE_UNSPECIFIED = 0x0000;
const MAPI_NULL = 0x0001;
const MAPI_SHORT = 0x0002;
const MAPI_INT = 0x0003;
const MAPI_FLOAT = 0x0004;
const MAPI_DOUBLE = 0x0005;
const MAPI_CURRENCY = 0x0006;
const MAPI_APPTIME = 0x0007;
const MAPI_ERROR = 0x000a;
const MAPI_BOOLEAN = 0x000b;
const MAPI_OBJECT = 0x000d;
const MAPI_INT8BYTE = 0x0014;
const MAPI_STRING = 0x001e;
const MAPI_UNICODE_STRING = 0x001f;
const MAPI_SYSTIME = 0x0040;
const MAPI_CLSID = 0x0048;
const MAPI_BINARY = 0x0102;
// Constants for possible value of MAPI_MEETING_REQUEST_TYPE
const MAPI_MEETING_INITIAL = 0x00000001;
const MAPI_MEETING_FULL_UPDATE = 0x100010000;
const MAPI_MEETING_INFO = 0x00020000;
// pidTag* properties. These should all be renamed in H6 to include pidTag
// in the name to make this clear.
const MAPI_MESSAGE_CLASS = 0x001A;
const MAPI_TAG_SUBJECT_PREFIX = 0x003D;
const MAPI_CONVERSATION_TOPIC = 0x0070;
// pidTagSentRepresentingName
const MAPI_SENT_REP_NAME = 0x0042;
// pidTagSentRepresentingEmail
const MAPI_SENT_REP_EMAIL_ADDR = 0x0065;
// pidTagDisplayTo
const MAPI_DISPLAY_TO = 0x0e04;
// pidTagSentRepresentingSMTPAddress
const MAPI_SENT_REP_SMTP_ADDR = 0x5d02;
// pidTagInReplyTo
const MAPI_IN_REPLY_TO_ID = 0x1042;
const MAPI_CREATION_TIME = 0x3007;
const MAPI_MODIFICATION_TIME = 0x3008;
const MAPI_ATTACH_DATA = 0x3701;
const MAPI_ATTACH_EXTENSION = 0x3703;
const MAPI_ATTACH_LONG_FILENAME = 0x3707;
const MAPI_ATTACH_MIME_TAG = 0x370E;
const MAPI_ORIGINAL_CREATORID = 0x3FF9;
const MAPI_LAST_MODIFIER_NAME = 0x3FFA;
const MAPI_CODEPAGE = 0x3FFD;
const MAPI_SENDER_SMTP = 0x5D01;
// Appointment related.
// This is pidTagStartDate and contains the value of PidLidAppointmentStartWhole
const MAPI_START_DATE = 0x0060; // pidTag
const MAPI_END_DATE = 0x0061; // pidTag
const MAPI_APPOINTMENT_SEQUENCE = 0x8201; // pidLid
const MAPI_BUSY_STATUS = 0x8205; // pidLid
const MAPI_MEETING_REQUEST_TYPE = 0x0026; // pidLid
const MAPI_RESPONSE_REQUESTED = 0x0063; // pidTag
const MAPI_APPOINTMENT_LOCATION = 0x8208; // pidLid
const MAPI_APPOINTMENT_URL = 0x8209; // pidLid
const MAPI_APPOINTMENT_START_WHOLE = 0x820D; // Full datetime of start (FILETIME format)
const MAPI_APPOINTMENT_END_WHOLE = 0x820E; // Full datetime of end (FILETIME format)
const MAPI_APPOINTMENT_DURATION = 0x8213; // pidLid - duration in minutes.
const MAPI_APPOINTMENT_SUBTYPE = 0x8215; // (Boolean - all day event?)
const MAPI_APPOINTMENT_RECUR = 0x8216; // This seems to be a combined property of MAPI_RECURRING, MAPI_RECURRING_TYPE etc...?
const MAPI_APPOINTMENT_STATE_FLAGS = 0x8217; // (bitmap for meeting, received, cancelled?)
const MAPI_RESPONSE_STATUS = 0x8218;
const MAPI_RECURRING = 0x8223;
const MAPI_RECURRENCE_TYPE = 0x8231;
const MAPI_ALL_ATTENDEES = 0x8238; // ALL attendees, required/optional and non-sendable.
const MAPI_TO_ATTENDEES = 0x823B; // All "sendable" attendees that are REQUIRED.
// tz. Not sure when to use STRUCT vs DEFINITION_RECUR. Possible ok to always use STRUCT?
const MAPI_TIMEZONE_STRUCT = 0x8233; // Timezone for recurring mtg?
const MAPI_TIMEZONE_DESCRIPTION = 0x8234; // Description for tz_struct?
const MAPI_START_CLIP_START = 0x8235; // Start datetime in UTC
const MAPI_START_CLIP_END = 0x8236; // End datetime in UTC
const MAPI_CONFERENCING_TYPE = 0x8241;
const MAPI_ORGANIZER_ALIAS = 0x8243; // Supposed to be organizer email, but it seems to be empty?
const MAPI_APPOINTMENT_COUNTER_PROPOSAL = 0x8257; // Boolean
const MAPI_TIMEZONE_START = 0x825E; // Timezone of start_whole
const MAPI_TIMEZONE_END = 0x825F; // Timezone of end_whole
const MAPI_TIMEZONE_DEFINITION_RECUR = 0x8260; // Timezone for use in converting meeting date/time in recurring meeting???
const MAPI_REMINDER_DELTA = 0x8501; // Minutes between start of mtg and overdue.
const MAPI_SIGNAL_TIME = 0x8502; // Initial alarm time.
const MAPI_REMINDER_SIGNAL_TIME = 0x8560; // Time that item becomes overdue.
const MAPI_ENTRY_UID = 0x0003; // pidLidGlobalObjectId, PSETID_MEETING
const MAPI_ENTRY_CLEANID = 0x0023; // pidLidCleanGlobalObjectId, PSETID_MEETING
const MAPI_MEETING_TYPE = 0x0026; // pidLidMeetingType, PSETID_MEETING
const MSG_EDITOR_FORMAT = 0x5909;
const MSG_EDITOR_FORMAT_UNKNOWN = 0;
const MSG_EDITOR_FORMAT_PLAIN = 1;
const MSG_EDITOR_FORMAT_HTML = 2;
const MSG_EDITOR_FORMAT_RTF = 3;
const MAPI_NAMED_TYPE_ID = 0x00;
const MAPI_NAMED_TYPE_STRING = 0x01;
const MAPI_NAMED_TYPE_NONE = 0xff;
const MAPI_MV_FLAG = 0x1000;
const IPM_MEETING_REQUEST = 'IPM.Microsoft Schedule.MtgReq';
const IPM_MEETING_RESPONSE_POS = 'IPM.Microsoft Schedule.MtgRespP';
const IPM_MEETING_RESPONSE_NEG = 'IPM.Microsoft Schedule.MtgRespN';
const IPM_MEETING_RESPONSE_TENT = 'IPM.Microsoft Schedule.MtgRespA';
const IPM_MEETING_REQUEST_CANCELLED = 'IPM.Microsoft Schedule.MtgCncl';
const MAPI_MEETING_RESPONSE_POS = 'IPM.Schedule.Meeting.Resp.Pos';
const MAPI_MEETING_RESPONSE_NEG = 'IPM.Schedule.Meeting.Resp.Neg';
const MAPI_MEETING_RESPONSE_TENT = 'IPM.Schedule.Meeting.Resp.Tent';
const IPM_TASK_REQUEST = 'IPM.TaskRequest';
const IPM_TASK_GUID = 0x8519; // pidLidTaskGlobalId, PSETID_Common
const MAPI_TAG_BODY = 0x1000;
const MAPI_NATIVE_BODY = 0x1016;
const MAPI_TAG_HTML = 0x1013;
const MAPI_TAG_RTF_COMPRESSED = 0x1009;
const RECUR_DAILY = 0x200A;
const RECUR_WEEKLY = 0x200B;
const RECUR_MONTHLY = 0x200C;
const RECUR_YEARLY = 0x200D;
const PATTERN_DAY = 0x0000;
const PATTERN_WEEK = 0x0001;
const PATTERN_MONTH = 0x0002;
const PATTERN_MONTH_END = 0x0004;
const PATTERN_MONTH_NTH = 0x0003;
const RECUR_END_DATE = 0x00002021;
const RECUR_END_N = 0x00002022;
/**
*/
public $canDecompress = true;
/**
* Collection of files contained in the TNEF data.
*
* @var array of Horde_Compress_Tnef_Object objects.
*/
protected $_files = array();
/**
* Collection of embedded TNEF attachments within the outer TNEF file.
*
* @var array of Horde_Compress_Tnef objects.
*/
protected $_attachments = array();
/**
*
* @var Horde_Compress_Tnef_MessageData
*/
protected $_msgInfo;
/**
* The TNEF object currently being decoded.
*
* @var Horde_Compress_Tnef_Object
*/
protected $_currentObject;
/**
* Decompress the TNEF data. For BC reasons we can only return a numerically
* indexed array of object data. For more detailed information, use
* self::getFiles(), self::getAttachements(), and self::getMsgInfo().
*
* @todo Refactor return data for Horde 6.
* @return array The decompressed data.
* @throws Horde_Compress_Exception
*/
public function decompress($data, array $params = array())
{
if ($this->_geti($data, 32) == self::SIGNATURE) {
$this->_logger->debug(sprintf(
'TNEF: Signature: 0x%08X Key: 0x%04X',
self::SIGNATURE,
$this->_geti($data, 16))
);
// Version
$this->_geti($data, 8); // lvl_message
$this->_geti($data, 32); // idTnefVersion
$this->_getx($data, $this->_geti($data, 32));
$this->_geti($data, 16); //checksum
// Codepage
$this->_geti($data, 8);
$this->_geti($data, 32); // idCodepage
$this->_getx($data, $this->_geti($data, 32));
$this->_geti($data, 16); //checksum
$out = array();
$this->_msgInfo = new Horde_Compress_Tnef_MessageData($this->_logger);
while (strlen($data) > 0) {
switch ($this->_geti($data, 8)) {
case self::LVL_MESSAGE:
$this->_logger->debug('DECODING LVL_MESSAGE property.');
$this->_decodeMessageProperty($data);
break;
case self::LVL_ATTACHMENT:
$this->_logger->debug('DECODING LVL_ATTACHMENT property.');
$this->_decodeAttachment($data);
break;
}
}
}
// Add the files. @todo the embedded attachments.
foreach ($this->_files as $object) {
$out[] = $object->toArray();
}
return $out;
}
/**
* Return the collection of files in the TNEF data.
*
* @return array @see self::$_files
*/
public function getFiles()
{
return $this->_files;
}
/**
* Return the collection of embedded attachments.
*
* @return array @see self::$_attachments
*/
public function getAttachments()
{
return $this->_attachments;
}
/**
* Return the message information data.
*
* @return array @see self::$_msgInfo
*/
public function getMsgInfo()
{
return $this->_msgInfo;
}
/**
* Sets the current object being decompressed.
*
* @param Horde_Compress_Tnef_Object $object
*/
public function setCurrentObject(Horde_Compress_Tnef_Object $object)
{
$this->_currentObject = $object;
}
/**
* Extract a set of encapsulated MAPI properties. Normally either embedded
* in an attachment structure, or an idMessageProperty structure.
*
* @param string $data The data string.
* @param array &$attachment_data TODO
*/
protected function _extractMapiAttributes($data)
{
// Number of attributes.
$number = $this->_geti($data, 32);
$this->_logger->debug(sprintf('TNEF: Extracting %d MAPI attributes.', $number));
while ((strlen($data) > 0) && $number--) {
$have_mval = false;
$num_mval = 1;
$value = null;
$attr_type = $this->_geti($data, 16);
$attr_name = $this->_geti($data, 16);
$namespace = false;
// Multivalue attributes.
if (($attr_type & self::MAPI_MV_FLAG) != 0) {
$have_mval = true;
$attr_type = $attr_type & ~self::MAPI_MV_FLAG;
$this->_logger->debug(sprintf(
'TNEF: Multivalue attribute of type: 0x%04X',
$attr_type)
);
}
// Named attributes.
if (($attr_name >= 0x8000) && ($attr_name < 0xFFFE)) {
$namespace = $this->_toNamespaceGUID($this->_getx($data, 16));
// The type of named property, an ID or STRING.
$named_type = $this->_geti($data, 32);
switch ($named_type) {
case self::MAPI_NAMED_TYPE_ID:
$pid = $attr_name;
$attr_name = $this->_geti($data, 32);
$msg = sprintf('TNEF: pid: 0x%X type: 0x%X Named Id: %s 0x%04X', $pid, $attr_type, $namespace, $attr_name);
$this->_logger->debug($msg);
break;
case self::MAPI_NAMED_TYPE_STRING:
// @todo. We haven't needed data from any string named id
// yet, but might be able to just assign the name to
// $attr_name and pass it down to _currentObject for now.
// For H6, look at using some lightweight object to transport
// the name/value to the various objects.
$attr_name = 0x9999;
$id_len = $this->_geti($data, 32);
$data_len = $id_len + ((4 - ($id_len % 4)) % 4);
$name = Horde_String::substr($this->_getx($data, $data_len), 0, $id_len);
$name = trim(Horde_String::convertCharset($name, 'UTF-16LE', 'UTF-8'));
$this->_logger->debug(sprintf('TNEF: Named String Id: %s', $name));
break;
case self::MAPI_NAMED_TYPE_NONE:
continue 2;
break;
default:
$msg = sprintf('TNEF: Unknown NAMED type: pid: 0x%X type: 0x%X Named TYPE: %s 0x%04X', $pid, $attr_type, $namespace, $named_type);
$this->_logger->notice($msg);
continue 2;
}
}
if ($have_mval) {
$num_mval = $this->_geti($data, 32);
$this->_logger->debug(sprintf(
'TNEF: Number of multivalues: %s', $num_mval));
}
switch ($attr_type) {
case self::MAPI_NULL:
case self::MAPI_TYPE_UNSPECIFIED:
break;
case self::MAPI_SHORT:
$value = $this->_geti($data, 16);
// Padding. See MS-OXTNEF 2.1.3.4
// Must always pad to a multiple of 4 bytes.
$this->_geti($data, 16);
break;
case self::MAPI_INT:
case self::MAPI_BOOLEAN:
for ($i = 0; $i < $num_mval; $i++) {
$value = $this->_geti($data, 32);
}
break;
case self::MAPI_FLOAT:
case self::MAPI_ERROR:
$value = $this->_getx($data, 4);
break;
case self::MAPI_DOUBLE:
case self::MAPI_APPTIME:
case self::MAPI_CURRENCY:
case self::MAPI_INT8BYTE:
case self::MAPI_SYSTIME:
$value = $this->_getx($data, 8);
break;
case self::MAPI_CLSID:
$this->_logger->debug('TNEF: CLSID??');
$this->_getx($data, 16);
break;
case self::MAPI_STRING:
case self::MAPI_UNICODE_STRING:
case self::MAPI_BINARY:
case self::MAPI_OBJECT:
$num_vals = ($have_mval) ? $num_mval : $this->_geti($data, 32);
for ($i = 0; $i < $num_vals; $i++) {
$length = $this->_geti($data, 32);
/* Pad to next 4 byte boundary. */
$datalen = $length + ((4 - ($length % 4)) % 4);
/* Read and truncate to length. */
$value = substr($this->_getx($data, $datalen), 0, $length);
}
switch ($attr_type) {
case self::MAPI_UNICODE_STRING:
// MAPI Unicode is UTF-16LE; convert to UTF-8
$value = Horde_String::convertCharset(
$value,
'UTF-16LE',
'UTF-8'
);
break;
}
switch ($attr_type) {
case self::MAPI_STRING:
case self::MAPI_UNICODE_STRING:
// Strings are null-terminated.
$value = substr($value, 0, -1);
break;
}
break;
default:
$msg = sprintf(
'TNEF: Unknown attribute type, "0x%X"',
$attr_type);
throw new Horde_Compress_Exception($msg);
$this->_logger->notice($msg);
}
// @todo Utility method to make this log more readable.
$this->_logger->debug(sprintf('TNEF: Attribute: 0x%X Type: 0x%X', $attr_name, $attr_type));
switch ($attr_name) {
case self::MAPI_TAG_RTF_COMPRESSED:
$this->_logger->debug('TNEF: Found compressed RTF text.');
$rtf = new Horde_Compress_Tnef_Rtf($this->_logger, $value);
$this->_files[] = $rtf;
// Give the currentObject a chance to do something with the RTF
// body. This is used, e.g., in meeting requests to populate
// the description field.
if ($this->_currentObject) {
try {
$this->_currentObject->setMapiAttribute($attr_type, $attr_name, $rtf->toPlain());
} catch (Horde_Compress_Exception $e) {
$this->_logger->err(sprintf('TNEF: Unable to set attribute: %s', $e->getMessage()));
}
}
break;
case self::MAPI_ATTACH_DATA:
$this->_logger->debug('TNEF: Found nested MAPI object. Parsing.');
$this->_getx($value, 16);
$att = new Horde_Compress_Tnef($this->_logger);
$att->setCurrentObject($this->_currentObject);
$att->decompress($value);
$this->_attachments[] = $att;
$this->_logger->debug('TNEF: Completed nested attachment parsing.');
break;
default:
try {
$this->_msgInfo->setMapiAttribute($attr_type, $attr_name, $value);
if ($this->_currentObject) {
$this->_currentObject->setMapiAttribute($attr_type, $attr_name, $value, $namespace);
}
} catch (Horde_Compress_Exception $e) {
$this->_logger->err(sprintf('TNEF: Unable to set attribute: %s', $e->getMessage()));
}
}
}
}
/**
* Decodes all LVL_ATTACHMENT data. Attachment data MUST be at the end of
* TNEF stream. First LVL_ATTACHMENT MUST be ARENDDATA (attAttachRendData).
*
* From MS-OXTNEF:
* ; An attachment is determined/delimited by attAttachRendData, followed by
* ; other encoded attributes, if any, and ending with attAttachment
* ; if there are any encoded properties.
* AttachData = AttachRendData [*AttachAttribute] [AttachProps]
* AttachRendData = attrLevelAttachment idAttachRendData Length Data Checksum
* AttachAttribute = attrLevelAttachment idAttachAttr Length Data Checksum
* AttachProps = attrLevelAttachment idAttachment Length Data Checksum
*
* @param [type] &$data [description]
* @return [type] [description]
*/
protected function _decodeAttachment(&$data)
{
$attribute = $this->_geti($data, 32);
$size = $this->_geti($data, 32);
$value = $this->_getx($data, $size);
$this->_geti($data, 16);
switch ($attribute) {
case self::ARENDDATA:
// This delimits the attachment structure. I.e., every attachment
// MUST begin with idAttachRendData.
$this->_logger->debug('Creating new attachment.');
if (!$this->_currentObject instanceof Horde_Compress_Tnef_VTodo) {
$this->_currentObject = new Horde_Compress_Tnef_File($this->_logger);
$this->_files[] = $this->_currentObject;
}
break;
case self::AFILENAME:
// Strip path.
$value = preg_replace('/.*[\/](.*)$/', '\1', $value);
$value = str_replace("\0", '', $value);
$this->_currentObject->setTnefAttribute($attribute, $value, $size);
break;
case self::ATTACHDATA:
// The attachment itself.
$this->_currentObject->setTnefAttribute($attribute, $value, $size);
break;
case self::AMAPIATTRS:
// idAttachment (Attachment properties)
$this->_extractMapiAttributes($value);
break;
default:
if (!empty($this->_currentObject)) {
$this->_currentObject->setTnefAttribute($attribute, $value, $size);
}
}
}
/**
* Decodes TNEF attributes.
*
* @param [type] &$data [description]
* @return [type] [description]
*/
protected function _decodeMessageProperty(&$data)
{
// This contains the type AND the attribute name. We should only check
// against the name since this is very confusing (everything else is
// checked against just name). Can't change until Horde 6 though since
// the constants would have to change. Also, the type identifiers are
// different between MAPI and TNEF. Of course...
// $type = $this->_geti($data, 16);
// $attribute = $this->_geti($data, 16);
$attribute = $this->_geti($data, 32);
$this->_logger->debug(sprintf('TNEF: Message property 0x%X found.', $attribute));
$value = false;
switch ($attribute) {
case self::AMCLASS:
// Start of a new message.
$message_class = trim($this->_decodeAttribute($data));
$this->_logger->debug(sprintf('TNEF: Message class: %s', $message_class));
switch ($message_class) {
case self::IPM_MEETING_REQUEST :
$this->_currentObject = new Horde_Compress_Tnef_Icalendar($this->_logger);
$this->_currentObject->setMethod('REQUEST', $message_class);
$this->_files[] = $this->_currentObject;
break;
case self::IPM_MEETING_RESPONSE_TENT:
case self::IPM_MEETING_RESPONSE_NEG:
case self::IPM_MEETING_RESPONSE_POS:
$this->_currentObject = new Horde_Compress_Tnef_Icalendar($this->_logger);
$this->_currentObject->setMethod('REPLY', $message_class);
$this->_files[] = $this->_currentObject;
break;
case self::IPM_MEETING_REQUEST_CANCELLED:
$this->_currentObject = new Horde_Compress_Tnef_Icalendar($this->_logger);
$this->_currentObject->setMethod('CANCEL', $message_class);
$this->_files[] = $this->_currentObject;
break;
case self::IPM_TASK_REQUEST:
$this->_currentObject = new Horde_Compress_Tnef_VTodo($this->_logger, null, array('parent' => &$this));
$this->_files[] = $this->_currentObject;
break;
default:
$this->_logger->debug(sprintf('Unknown message class: %s', $message_class));
}
break;
case self::AMAPIPROPS:
$this->_logger->debug('TNEF: Extracting encapsulated message properties (idMsgProps)');
$properties = $this->_decodeAttribute($data);
$this->_extractMapiAttributes($properties);
break;
case self::APRIORITY:
case self::AOWNER:
case self::ARECIPIENTTABLE:
case self::ABODY:
case self::ASTATUS:
case self::ACONVERSATIONID:
case self::APARENTID:
case self::AMESSAGEID:
case self::ASUBJECT:
case self::AORIGINALMCLASS:
$value = $this->_decodeAttribute($data);
break;
case self::ADATERECEIVED:
case self::ADATESENT:
case self::ADATEMODIFIED:
case self::ID_DATE_END:
try {
$value = new Horde_Date(Horde_Mapi::filetimeToUnixtime($this->_decodeAttribute($data)), 'UTC');
} catch (Horde_Mapi_Exception $e) {
throw new Horde_Compress_Exception($e);
} catch (Horde_Date_Exception $e) {
$this->_logger->err(sprintf('TNEF: Unable to parse date string - %s', $e->getMessage()));
}
break;
case self::AFROM:
case self::ASENTFOR:
$msgObj = $this->_decodeAttribute($data);
$display_name = $this->_getx($msgObj, $this->_geti($msgObj, 16));
$email = $this->_getx($msgObj, $this->_geti($msgObj, 16));
$value = $email; // @todo - Do we need to pass display name too?
break;
default:
$size = $this->_geti($data, 32);
$value = $this->_getx($data, $size);
$this->_geti($data, 16); // Checksum.
}
if ($value && $this->_currentObject) {
$this->_currentObject->setTnefAttribute($attribute, $value, (empty($size) ? strlen($value) : $size));
}
}
/**
* Decode a single attribute.
*
* @param string &$data The data string.
*/
protected function _decodeAttribute(&$data)
{
$size = $this->_geti($data, 32);
$value = $this->_getx($data, $size);
$this->_geti($data, 16); // Checksum.
return $value;
}
/**
* Pop specified number of bytes from the buffer.
*
* @param string &$data The data string.
* @param integer $bytes How many bytes to retrieve.
*
* @return @todo these also need to exist in the objects. Need to
* refactor this away by adding a data/stream object
* with getx/geti methods with the data hanled internally.
*/
protected function _getx(&$data, $bytes)
{
$value = null;
if (strlen($data) >= $bytes) {
$value = substr($data, 0, $bytes);
$data = substr_replace($data, '', 0, $bytes);
}
return $value;
}
/**
* Pop specified number of bits from the buffer
*
* @param string &$data The data string.
* @param integer $bits How many bits to retrieve.
*
* @return TODO
*/
protected function _geti(&$data, $bits)
{
$bytes = $bits / 8;
$value = null;
if (strlen($data) >= $bytes) {
$value = ord($data[0]);
if ($bytes >= 2) {
$value += (ord($data[1]) << 8);
}
if ($bytes >= 4) {
$value += (ord($data[2]) << 16) + (ord($data[3]) << 24);
}
$data = substr_replace($data, '', 0, $bytes);
}
return $value;
}
protected function _toNamespaceGUID($value)
{
$guid = unpack("VV/v2v/n4n", $value);
return sprintf("{%08X-%04X-%04X-%04X-%04X%04X%04X}",$guid['V'], $guid['v1'], $guid['v2'],$guid['n1'],$guid['n2'],$guid['n3'],$guid['n4']);
}
}
Horde_Compress-2.2.1/lib/Horde/Compress/Translation.php 0000664 0001750 0001750 00000001772 13150756215 021161 0 ustar jan jan
* @category Horde
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package Compress
*/
/**
* Horde_Compress_Translation is the translation wrapper class for
* horde/Compress.
*
* @author Jan Schneider
* @category Horde
* @copyright 2010-2017 Horde LLC
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package Compress
*/
class Horde_Compress_Translation extends Horde_Translation_Autodetect
{
/**
* The translation domain
*
* @var string
*/
protected static $_domain = 'Horde_Compress';
/**
* The absolute PEAR path to the translations for the default gettext handler.
*
* @var string
*/
protected static $_pearDirectory = '@data_dir@';
}
Horde_Compress-2.2.1/lib/Horde/Compress/Zip.php 0000664 0001750 0001750 00000036643 13150756215 017432 0 ustar jan jan
* http://www.zend.com/codex.php?id=535&single=1
*
* Deins125
* http://www.zend.com/codex.php?id=470&single=1
*
* The ZIP compression date code is partially based on code from
* Peter Listiak
*
* Official ZIP file format: https://support.pkware.com/display/PKZIP/APPNOTE
*
* @author Chuck Hagenbuch
* @author Michael Cochrane
* @author Michael Slusarz
* @category Horde
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package Compress
*/
/**
* The Horde_Compress_zip class allows ZIP files to be created and read.
*
* @author Chuck Hagenbuch
* @author Michael Cochrane
* @author Michael Slusarz
* @category Horde
* @copyright 2000-2017 Horde LLC
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package Compress
*/
class Horde_Compress_Zip extends Horde_Compress_Base
{
/**
* Return file list.
*
* @see decompress().
*/
const ZIP_LIST = 1;
/**
* Return file data.
*
* @see decompress().
*/
const ZIP_DATA = 2;
/**
* Beginning of central directory record.
*/
const CTRL_DIR_HEADER = "\x50\x4b\x01\x02";
/**
* End of central directory record.
*/
const CTRL_DIR_END = "\x50\x4b\x05\x06\x00\x00\x00\x00";
/**
* Beginning of file contents.
*/
const FILE_HEADER = "\x50\x4b\x03\x04";
/**
*/
public $canCompress = true;
/**
*/
public $canDecompress = true;
/**
* ZIP compression methods.
*
* @var array
*/
protected $_methods = array(
0x0 => 'None',
0x1 => 'Shrunk',
0x2 => 'Super Fast',
0x3 => 'Fast',
0x4 => 'Normal',
0x5 => 'Maximum',
0x6 => 'Imploded',
0x8 => 'Deflated'
);
/**
* Temporary data for compressing files.
*
* @var array
*/
protected $_ctrldir;
/**
* Temporary contents for compressing files.
*
* @var resource
*/
protected $_tmp;
/**
* @param array $data The data to compress. Requires an array of
* arrays. Each subarray should contain these
* fields:
* - data: (string/resource) The data to compress.
* - name: (string) The pathname to the file.
* - time: (integer) [optional] The timestamp to use for the file.
* @param array $params The parameter array.
* - stream: (boolean) If set, return a stream instead of a string.
* DEFAULT: Return string
*
* @return mixed The ZIP file as either a string or a stream resource.
*/
public function compress($data, array $params = array())
{
if (!Horde_Util::extensionExists('zlib')) {
throw new Horde_Compress_Exception(
Horde_Compress_Translation::t(
"This server can't compress zip files."
)
);
}
$this->_ctrldir = array();
$this->_tmp = fopen('php://temp', 'r+');
foreach ($data as $val) {
$this->_addToZipFile($val);
}
/* Create the ZIP file. */
$dir = implode('', $this->_ctrldir);
fseek($this->_tmp, 0, SEEK_END);
$offset = ftell($this->_tmp);
fwrite(
$this->_tmp,
$dir . self::CTRL_DIR_END .
/* Total # of entries "on this disk". */
pack('v', count($this->_ctrldir)) .
/* Total # of entries overall. */
pack('v', count($this->_ctrldir)) .
/* Size of central directory. */
pack('V', strlen($dir)) .
/* Offset to start of central dir. */
pack('V', $offset) .
/* ZIP file comment length. */
"\x00\x00"
);
rewind($this->_tmp);
if (empty($params['stream'])) {
$out = stream_get_contents($this->_tmp);
fclose($this->_tmp);
return $out;
}
return $this->_tmp;
}
/**
* @param array $params The parameter array.
* - action: (integer) [REQUIRED] The action to take on the data. Either
* self::ZIP_LIST or self::ZIP_DATA.
* - info: (array) [REQUIRED for ZIP_DATA] The zipfile list.
* - key: (integer) [REQUIRED for ZIP_DATA] The position of the file in
* the archive list.
*
* @return mixed If action is self::ZIP_DATA, the uncompressed data. If
* action is self::ZIP_LIST, an array with the KEY as the
* position in the zipfile and these values:
* - attr: File attributes
* - crc: CRC checksum
* - csize: Compressed file size
* - date: File modification time
* - name: Filename
* - method: Compression method
* - size: Original file size
* - type: File type
* @throws Horde_Compress_Exception
*/
public function decompress($data, array $params = array())
{
if (isset($params['action'])) {
switch ($params['action']) {
case self::ZIP_LIST:
return $this->_getZipInfo($data);
case self::ZIP_DATA:
return $this->_getZipData(
$data, $params['info'], $params['key']
);
}
}
}
/**
* 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) & 0x0f),
(($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'] & 0x01)
? 'text'
: 'binary';
$entries[$name]['attr'] =
(($info['External'] & 0x10) ? 'D' : '-') .
(($info['External'] & 0x20) ? 'A' : '-') .
(($info['External'] & 0x03) ? 'S' : '-') .
(($info['External'] & 0x02) ? 'H' : '-') .
(($info['External'] & 0x01) ? '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 data for a specific archived file.
*
* @param string $data The zip archive contents.
* @param array $info The information array from _getZipInfo().
* @param integer $key The position of the file in the archive.
*
* @return string The file data.
*/
protected function _getZipData($data, $info, $key)
{
if (($info[$key]['_method'] == 0x8) &&
Horde_Util::extensionExists('zlib')) {
/* If the file has been deflated, and zlib is installed,
then inflate the data again. */
return @gzinflate(
substr($data, $info[$key]['_dataStart'], $info[$key]['csize'])
);
} elseif ($info[$key]['_method'] == 0x0) {
/* Files that aren't compressed. */
return substr(
$data, $info[$key]['_dataStart'], $info[$key]['csize']
);
}
return '';
}
/**
* Checks to see if the data is a valid ZIP file.
*
* @param string $data The ZIP file data.
*
* @return boolean True if valid, false if invalid.
*/
public function checkZipData($data)
{
return (strpos($data, self::FILE_HEADER) !== false);
}
/**
* Converts a UNIX timestamp to a 4-byte DOS date and time format (date in
* high 2-bytes, time in low 2-bytes allowing magnitude comparison).
*
* @param integer $unixtime The current UNIX timestamp.
*
* @return integer The current date in a 4-byte DOS format.
*/
protected function _unix2DOSTime($unixtime = null)
{
$timearray = (is_null($unixtime)) ? getdate() : getdate($unixtime);
if ($timearray['year'] < 1980) {
$timearray['year'] = 1980;
$timearray['mon'] = 1;
$timearray['mday'] = 1;
$timearray['hours'] = 0;
$timearray['minutes'] = 0;
$timearray['seconds'] = 0;
}
return (($timearray['year'] - 1980) << 25) |
($timearray['mon'] << 21) |
($timearray['mday'] << 16) |
($timearray['hours'] << 11) |
($timearray['minutes'] << 5) |
($timearray['seconds'] >> 1);
}
/**
* Adds a "file" to the ZIP archive.
*
* @param array $file See self::createZipFile().
*/
protected function _addToZipFile($file)
{
$name = str_replace('\\', '/', $file['name']);
/* See if time/date information has been provided. */
$ftime = (isset($file['time'])) ? $file['time'] : null;
/* Get the hex time. */
$dtime = sprintf('%08s', dechex($this->_unix2DosTime($ftime)));
$hexdtime = chr(hexdec($dtime[6] . $dtime[7])) .
chr(hexdec($dtime[4] . $dtime[5])) .
chr(hexdec($dtime[2] . $dtime[3])) .
chr(hexdec($dtime[0] . $dtime[1]));
/* "Local file header" segment. */
if (is_resource($file['data'])) {
$zdata = fopen('php://temp', 'r+');
$params = new stdClass;
stream_filter_register(
'horde_compress_filter_crc32', 'Horde_Stream_Filter_Crc32'
);
$filter = stream_filter_prepend(
$file['data'],
'horde_compress_filter_crc32',
STREAM_FILTER_READ,
$params
);
$filter2 = stream_filter_append(
$zdata,
'zlib.deflate',
STREAM_FILTER_WRITE
);
rewind($file['data']);
stream_copy_to_stream($file['data'], $zdata);
$crc = $params->crc32;
$unc_len = ftell($file['data']);
stream_filter_remove($filter2);
stream_filter_remove($filter);
fseek($zdata, 0, SEEK_END);
$c_len = ftell($zdata);
} else {
$unc_len = strlen($file['data']);
$crc = crc32($file['data']);
$zdata = gzdeflate($file['data']);
$c_len = strlen($zdata);
}
/* Common data for the two entries. */
$common =
"\x14\x00" . /* Version needed to extract. */
"\x00\x00" . /* General purpose bit flag. */
"\x08\x00" . /* Compression method. */
$hexdtime . /* Last modification time/date. */
pack('V', $crc) . /* CRC 32 information. */
pack('V', $c_len) . /* Compressed filesize. */
pack('V', $unc_len) . /* Uncompressed filesize. */
pack('v', strlen($name)) . /* Length of filename. */
pack('v', 0); /* Extra field length. */
/* Add this entry to zip data. */
fseek($this->_tmp, 0, SEEK_END);
$old_offset = ftell($this->_tmp);
fwrite($this->_tmp,
self::FILE_HEADER . /* Begin creating the ZIP data. */
$common . /* Common data. */
$name
);
/* "File data" segment. */
if (is_resource($zdata)) {
rewind($zdata);
stream_copy_to_stream($zdata, $this->_tmp);
} else {
fwrite($this->_tmp, $zdata);
}
/* Add to central directory record. */
$this->_ctrldir[] =
self::CTRL_DIR_HEADER .
"\x00\x00" . /* Version made by. */
$common . /* Common data. */
pack('v', 0) . /* File comment length. */
pack('v', 0) . /* Disk number start. */
pack('v', 0) . /* Internal file attributes. */
pack('V', 32) . /* External file attributes -
* 'archive' bit set. */
pack('V', $old_offset) . /* Relative offset of local header. */
$name; /* File name. */
}
}
Horde_Compress-2.2.1/lib/Horde/Compress.php 0000664 0001750 0001750 00000003314 13150756215 016655 0 ustar jan jan
* @category Horde
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package Compress
*/
/**
* This class provides an API for various compression techniques that can be
* used by Horde applications.
*
* @author Michael Slusarz
* @category Horde
* @copyright 2003-2017 Horde LLC
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package Compress
*/
class Horde_Compress
{
/**
* Attempts to return a concrete Horde_Compress_Base instance based on
* $driver.
*
* @param string $driver Either a driver name, or the full class name to
* use (class must extend Horde_Compress_Base).
* @param array $params Hash containing any additional configuration
* or parameters a subclass needs.
*
* @return Horde_Compress_Base The newly created concrete instance.
* @throws Horde_Compress_Exception
*/
public static function factory($driver, $params = null)
{
/* Base drivers (in Compress/ directory). */
$class = __CLASS__ . '_' . Horde_String::ucfirst($driver);
if (@class_exists($class)) {
return new $class($params);
}
/* Explicit class name. */
if (@class_exists($driver)) {
return new $driver($params);
}
throw new Horde_Compress_Exception(__CLASS__ . ': Class definition of ' . $driver . ' not found.');
}
}
Horde_Compress-2.2.1/locale/ar/LC_MESSAGES/Horde_Compress.mo 0000664 0001750 0001750 00000000577 13150756215 021451 0 ustar jan jan $ , 8 E 9 Project-Id-Version: Horde_Compress
Report-Msgid-Bugs-To: dev@lists.horde.org
POT-Creation-Date: 2010-10-13 01:27+0200
PO-Revision-Date: 2010-10-13 01:27+0200
Last-Translator: Automatically generated
Language-Team: i18n@lists.horde.org
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Horde_Compress-2.2.1/locale/ar/LC_MESSAGES/Horde_Compress.po 0000664 0001750 0001750 00000002337 13150756215 021450 0 ustar jan jan # Arabic translations for Horde_Compress module.
# Copyright 2010-2017 Horde LLC
# This file is distributed under the same license as the Horde_Compress module.
# Automatically generated, 2010.
#
msgid ""
msgstr ""
"Project-Id-Version: Horde_Compress\n"
"Report-Msgid-Bugs-To: dev@lists.horde.org\n"
"POT-Creation-Date: 2010-10-13 01:27+0200\n"
"PO-Revision-Date: 2010-10-13 01:27+0200\n"
"Last-Translator: Automatically generated\n"
"Language-Team: i18n@lists.horde.org\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: lib/Horde/Compress/Rar.php:54
msgid "Invalid RAR data."
msgstr ""
#: lib/Horde/Compress/Zip.php:197 lib/Horde/Compress/Zip.php:224
#: lib/Horde/Compress/Zip.php:244
msgid "Invalid ZIP data"
msgstr ""
#: lib/Horde/Compress/Dbx.php:128 lib/Horde/Compress/Dbx.php:157
#: lib/Horde/Compress/Dbx.php:238
msgid "Invalid file format"
msgstr ""
#: lib/Horde/Compress/Zip.php:93
msgid "This server can't compress zip files."
msgstr ""
#: lib/Horde/Compress/Gzip.php:42
msgid "This server can't uncompress gzip files."
msgstr ""
#: lib/Horde/Compress/Gzip.php:49 lib/Horde/Compress/Gzip.php:79
#: lib/Horde/Compress/Tar.php:74
msgid "Unable to decompress data."
msgstr ""
Horde_Compress-2.2.1/locale/bg/LC_MESSAGES/Horde_Compress.mo 0000664 0001750 0001750 00000000577 13150756215 021437 0 ustar jan jan $ , 8 E 9 Project-Id-Version: Horde_Compress
Report-Msgid-Bugs-To: dev@lists.horde.org
POT-Creation-Date: 2010-10-13 01:27+0200
PO-Revision-Date: 2010-10-13 01:27+0200
Last-Translator: Automatically generated
Language-Team: i18n@lists.horde.org
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Horde_Compress-2.2.1/locale/bg/LC_MESSAGES/Horde_Compress.po 0000664 0001750 0001750 00000003215 13150756215 021432 0 ustar jan jan # Bulgarian translations for Horde_Compress module.
# Copyright 2010-2017 Horde LLC
# This file is distributed under the same license as the Horde_Compress module.
# Automatically generated, 2010.
#
msgid ""
msgstr ""
"Project-Id-Version: Horde_Compress\n"
"Report-Msgid-Bugs-To: dev@lists.horde.org\n"
"POT-Creation-Date: 2010-10-13 01:27+0200\n"
"PO-Revision-Date: 2010-10-13 01:27+0200\n"
"Last-Translator: Automatically generated\n"
"Language-Team: i18n@lists.horde.org\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: lib/Horde/Compress/Rar.php:54
#, fuzzy
msgid "Invalid RAR data."
msgstr "Изпратените данни са невалидни."
#: lib/Horde/Compress/Zip.php:197 lib/Horde/Compress/Zip.php:224
#: lib/Horde/Compress/Zip.php:244
#, fuzzy
msgid "Invalid ZIP data"
msgstr "Изпратените данни са невалидни."
#: lib/Horde/Compress/Dbx.php:128 lib/Horde/Compress/Dbx.php:157
#: lib/Horde/Compress/Dbx.php:238
msgid "Invalid file format"
msgstr ""
#: lib/Horde/Compress/Zip.php:93
#, fuzzy
msgid "This server can't compress zip files."
msgstr "Този сървър не може да декомпресира zip и gzip файлове."
#: lib/Horde/Compress/Gzip.php:42
#, fuzzy
msgid "This server can't uncompress gzip files."
msgstr "Този сървър не може да декомпресира zip и gzip файлове."
#: lib/Horde/Compress/Gzip.php:49 lib/Horde/Compress/Gzip.php:79
#: lib/Horde/Compress/Tar.php:74
#, fuzzy
msgid "Unable to decompress data."
msgstr "Грешка при отварянето на компресиран архив."
Horde_Compress-2.2.1/locale/bs/LC_MESSAGES/Horde_Compress.mo 0000664 0001750 0001750 00000000577 13150756215 021453 0 ustar jan jan $ , 8 E 9 Project-Id-Version: Horde_Compress
Report-Msgid-Bugs-To: dev@lists.horde.org
POT-Creation-Date: 2010-10-13 01:27+0200
PO-Revision-Date: 2010-10-13 01:27+0200
Last-Translator: Automatically generated
Language-Team: i18n@lists.horde.org
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Horde_Compress-2.2.1/locale/bs/LC_MESSAGES/Horde_Compress.po 0000664 0001750 0001750 00000002367 13150756215 021455 0 ustar jan jan # Bosnian translations for Horde_Compress module.
# Copyright 2010-2017 Horde LLC
# This file is distributed under the same license as the Horde_Compress module.
# Automatically generated, 2010.
#
msgid ""
msgstr ""
"Project-Id-Version: Horde_Compress\n"
"Report-Msgid-Bugs-To: dev@lists.horde.org\n"
"POT-Creation-Date: 2010-10-13 01:27+0200\n"
"PO-Revision-Date: 2010-10-13 01:27+0200\n"
"Last-Translator: Automatically generated\n"
"Language-Team: i18n@lists.horde.org\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: lib/Horde/Compress/Rar.php:54
msgid "Invalid RAR data."
msgstr ""
#: lib/Horde/Compress/Zip.php:197 lib/Horde/Compress/Zip.php:224
#: lib/Horde/Compress/Zip.php:244
msgid "Invalid ZIP data"
msgstr ""
#: lib/Horde/Compress/Dbx.php:128 lib/Horde/Compress/Dbx.php:157
#: lib/Horde/Compress/Dbx.php:238
#, fuzzy
msgid "Invalid file format"
msgstr "Vremenska zona"
#: lib/Horde/Compress/Zip.php:93
msgid "This server can't compress zip files."
msgstr ""
#: lib/Horde/Compress/Gzip.php:42
msgid "This server can't uncompress gzip files."
msgstr ""
#: lib/Horde/Compress/Gzip.php:49 lib/Horde/Compress/Gzip.php:79
#: lib/Horde/Compress/Tar.php:74
msgid "Unable to decompress data."
msgstr ""
Horde_Compress-2.2.1/locale/ca/LC_MESSAGES/Horde_Compress.mo 0000664 0001750 0001750 00000001127 13150756215 021422 0 ustar jan jan <