diff --git a/lib/import/zipimportstorage.inc.php b/lib/import/zipimportstorage.inc.php
index 7844cc0..073f356 100644
--- a/lib/import/zipimportstorage.inc.php
+++ b/lib/import/zipimportstorage.inc.php
@@ -7,71 +7,140 @@
* KnowledgeTree Open Source Edition
* Document Management Made Simple
* Copyright (C) 2004 - 2007 The Jam Warehouse Software (Pty) Limited
- *
+ *
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 3 as published by the
* Free Software Foundation.
- *
+ *
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
- *
+ *
* You can contact The Jam Warehouse Software (Pty) Limited, Unit 1, Tramber Place,
* Blake Street, Observatory, 7925 South Africa. or email info@knowledgetree.com.
- *
+ *
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
- *
+ *
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "Powered by
- * KnowledgeTree" logo and retain the original copyright notice. If the display of the
+ * KnowledgeTree" logo and retain the original copyright notice. If the display of the
* logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices
- * must display the words "Powered by KnowledgeTree" and retain the original
- * copyright notice.
+ * must display the words "Powered by KnowledgeTree" and retain the original
+ * copyright notice.
* Contributor( s): ______________________________________
*/
require_once(KT_LIB_DIR . '/filelike/fsfilelike.inc.php');
require_once(KT_LIB_DIR . '/import/fsimportstorage.inc.php');
+require_once('File/Archive.php');
+
class KTZipImportStorage extends KTFSImportStorage {
- function KTZipImportStorage($sZipPath) {
- $this->sZipPath = $sZipPath;
+
+ /**
+ * The archive extension.
+ * @var string
+ */
+ var $sExtension = 'zip';
+
+ var $sZipPath = '';
+
+ var $sBasePath = '';
+
+ var $aFile = array();
+
+ var $allowed_extensions = array('tgz', 'tar', 'gz', 'gzip', 'zip', 'deb', 'ar');
+
+ function KTZipImportStorage($sFilesName) {
+ $this->aFile = $_FILES[$sFilesName];
+ $this->sZipPath = $this->aFile['tmp_name'];
+
+ // Check the bzip2 lib functions are available
+ if(function_exists('bzopen')){
+ $this->allowed_extensions = array_merge($this->allowed_extensions, array('bz2', 'bzip2', 'tbz'));
+ }
+ }
+
+ function CheckFormat(){
+ // Get the file extension
+ $aFilename = explode('.', $this->aFile['name']);
+ $cnt = count($aFilename);
+ $sExtension = $aFilename[$cnt - 1];
+
+ // check if its in the list of supported extensions
+ if(!in_array($sExtension, $this->allowed_extensions)){
+ return false;
+ }
+
+ $this->sExtension = (!empty($sExtension)) ? $sExtension : 'zip';
+
+ // Check if the archive is a .tar.gz or .tar.bz, etc
+ if($cnt > 2){
+ if($aFilename[$cnt-2] == 'tar'){
+ switch($this->sExtension){
+ case 'gz':
+ $this->sExtension = 'tgz';
+ break;
+ case 'bz2':
+ $this->sExtension = 'tbz';
+ break;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ function getFormats(){
+ return implode(', ', $this->allowed_extensions);
}
function init() {
$oKTConfig =& KTConfig::getSingleton();
- $sBasedir = $oKTConfig->get("urls/tmpDirectory");
-
- $sTmpPath = tempnam($sBasedir, 'zipimportstorage');
+ $sBasedir = $oKTConfig->get("urls/tmpDirectory");
+
+ $sTmpPath = tempnam($sBasedir, 'archiveimportstorage');
if ($sTmpPath === false) {
- return PEAR::raiseError(_kt("Could not create temporary directory for zip storage"));
+ return PEAR::raiseError(_kt("Could not create temporary directory for archive storage"));
}
if (!file_exists($this->sZipPath)) {
- return PEAR::raiseError(_kt("Zip file given does not exist"));
+ return PEAR::raiseError(_kt("Archive file given does not exist"));
}
unlink($sTmpPath);
mkdir($sTmpPath, 0700);
$this->sBasePath = $sTmpPath;
- $sUnzipCommand = KTUtil::findCommand("import/unzip", "unzip");
- if (empty($sUnzipCommand)) {
- return PEAR::raiseError(_kt("unzip command not found on system"));
- }
- $aArgs = array(
- $sUnzipCommand,
- "-q", "-n",
- "-d", $sTmpPath,
- $this->sZipPath,
- );
- $aRes = KTUtil::pexec($aArgs);
-
- if ($aRes['ret'] !== 0) {
- return PEAR::raiseError(_kt("Could not retrieve contents from zip storage"));
+
+ // File Archive doesn't unzip properly so sticking to the original unzip functionality
+ if($this->sExtension == 'zip'){
+ // ** Original zip functionality
+ $sUnzipCommand = KTUtil::findCommand("import/unzip", "unzip");
+ if (empty($sUnzipCommand)) {
+ return PEAR::raiseError(_kt("unzip command not found on system"));
+ }
+ $aArgs = array(
+ $sUnzipCommand,
+ "-q", "-n",
+ "-d", $sTmpPath,
+ $this->sZipPath,
+ );
+ $aRes = KTUtil::pexec($aArgs);
+
+ if ($aRes['ret'] !== 0) {
+ return PEAR::raiseError(_kt("Could not retrieve contents from zip storage"));
+ }
+ }else{
+ File_Archive::extract(
+ File_Archive::readArchive(
+ $this->sExtension, File_Archive::readUploadedFile('file')
+ ),
+ $dst = $sTmpPath
+ );
}
}
@@ -83,4 +152,4 @@ class KTZipImportStorage extends KTFSImportStorage {
}
}
-?>
+?>
\ No newline at end of file
diff --git a/plugins/ktcore/folder/BulkUpload.php b/plugins/ktcore/folder/BulkUpload.php
index 18839d5..e95dd6f 100644
--- a/plugins/ktcore/folder/BulkUpload.php
+++ b/plugins/ktcore/folder/BulkUpload.php
@@ -115,16 +115,6 @@ class KTBulkUploadFolderAction extends KTFolderAction {
unset($aErrorOptions['message']);
$aFile = $this->oValidator->validateFile($_FILES['file'], $aErrorOptions);
- // Ensure file is a zip file
- $sMime = $aFile['type'];
- $pos = strpos($sMime, 'x-zip-compressed');
- $pos2 = strpos($sMime, 'application/zip');
- if($pos === false && $pos2 === false){
- $this->addErrorMessage(_kt("Bulk Upload failed: File is not a zip file."));
- controllerRedirect("browse", 'fFolderId=' . $this->oFolder->getID());
- exit(0);
- }
-
$matches = array();
$aFields = array();
foreach ($_REQUEST as $k => $v) {
@@ -138,7 +128,14 @@ class KTBulkUploadFolderAction extends KTFolderAction {
'metadata' => $aFields,
);
- $fs =& new KTZipImportStorage($aFile['tmp_name']);
+ $fs =& new KTZipImportStorage('file');
+ if(!$fs->CheckFormat()){
+ $sFormats = $fs->getFormats();
+ $this->addErrorMessage(_kt("Bulk Upload failed. Archive is not an accepted format. Accepted formats are: ".$sFormats));
+ controllerRedirect("browse", 'fFolderId=' . $this->oFolder->getID());
+ exit;
+ }
+
$bm =& new KTBulkImportManager($this->oFolder, $fs, $this->oUser, $aOptions);
$this->startTransaction();
$res = $bm->import();
@@ -152,3 +149,4 @@ class KTBulkUploadFolderAction extends KTFolderAction {
exit(0);
}
}
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive.php b/thirdparty/pear/File/Archive.php
new file mode 100644
index 0000000..b3a5f95
--- /dev/null
+++ b/thirdparty/pear/File/Archive.php
@@ -0,0 +1,1403 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Archive.php,v 1.85 2005/08/16 08:48:59 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+/**
+ * To have access to PEAR::isError and PEAR::raiseError
+ * We should probably use lazy include and remove this inclusion...
+ */
+require_once "PEAR.php";
+
+function File_Archive_cleanCache($file, $group)
+{
+ $file = split('_', $file);
+ if (count($file) != 3) {
+ return false; //not a File_Archive file, keep it
+ }
+
+ $name = $file[2];
+ $name = urldecode($name);
+
+ $group = $file[1];
+
+ //clean the cache only for files in File_Archive groups
+ return substr($group, 0, 11) == 'FileArchive' &&
+ !file_exists($name); //and only if the related file no longer exists
+}
+
+/**
+ * Factory to access the most common File_Archive features
+ * It uses lazy include, so you dont have to include the files from
+ * File/Archive/* directories
+ */
+class File_Archive
+{
+ function& _option($name)
+ {
+ static $container = array(
+ 'zipCompressionLevel' => 9,
+ 'gzCompressionLevel' => 9,
+ 'tmpDirectory' => '.',
+ 'cache' => null,
+ 'appendRemoveDuplicates' => false,
+ 'blockSize' => 65536,
+ 'cacheCondition' => false
+ );
+ return $container[$name];
+ }
+ /**
+ * Sets an option that will be used by default by all readers or writers
+ * Option names are case sensitive
+ * Currently, the following options are used:
+ *
+ * "cache"
+ * Instance of a Cache_Lite object used to cache some compressed
+ * data to speed up future compressions of files
+ * Default: null (no cache used)
+ *
+ * "zipCompressionLevel"
+ * Value between 0 and 9 specifying the default compression level used
+ * by Zip writers (0 no compression, 9 highest compression)
+ * Default: 9
+ *
+ * "gzCompressionLevel"
+ * Value between 0 and 9 specifying the default compression level used
+ * by Gz writers (0 no compression, 9 highest compression)
+ * Default: 9
+ *
+ * "tmpDirectory"
+ * Directory where the temporary files generated by File_Archive will
+ * be created
+ * Default: '.'
+ *
+ * "appendRemoveDuplicates"
+ * If set to true, the appender created will by default remove the
+ * file present in the archive when adding a new one. This will slow the
+ * appending of files to archives
+ * Default: false
+ *
+ * "blockSize"
+ * To transfer data from a reader to a writer, some chunks a read from the
+ * source and written to the writer. This parameter controls the size of the
+ * chunks
+ * Default: 64kB
+ *
+ * "cacheCondition"
+ * This parameter specifies when a cache should be used. When the cache is
+ * used, the data of the reader is saved in a temporary file for future access.
+ * The cached reader will be read only once, even if you read it several times.
+ * This can be usefull to read compressed files or downloaded files (from http or ftp)
+ * The possible values for this option are
+ * - false: never use cache
+ * - a regexp: A cache will be used if the specified URL matches the regexp
+ * preg_match is used
+ * Default: false
+ * Example: '/^(http|ftp):\/\//' will cache all files downloaded via http or ftp
+ *
+ */
+ function setOption($name, $value)
+ {
+ $option =& File_Archive::_option($name);
+ $option = $value;
+ if ($name == 'cache' && $value !== null) {
+ //TODO: ask to Cache_Lite to allow that
+ $value->_fileNameProtection = false;
+ }
+ }
+
+ /**
+ * Retrieve the value of an option
+ */
+ function getOption($name)
+ {
+ return File_Archive::_option($name);
+ }
+
+ /**
+ * Create a reader to read the URL $URL.
+ * If the URL is a directory, it will recursively read that directory.
+ * If $uncompressionLevel is not null, the archives (files with extension
+ * tar, zip, gz or tgz) will be considered as directories (up to a depth of
+ * $uncompressionLevel if $uncompressionLevel > 0). The reader will only
+ * read files with a directory depth of $directoryDepth. It reader will
+ * replace the given URL ($URL) with $symbolic in the public filenames
+ * The default symbolic name is the last filename in the URL (or '' for
+ * directories)
+ *
+ * Examples:
+ * Considere the following file system
+ *
+ * a.txt
+ * b.tar (archive that contains the following files)
+ * c.txt
+ * d.tgz (archive that contains the following files)
+ * e.txt
+ * dir1/
+ * f.txt
+ * dir2/
+ * g.txt
+ * dir3/
+ * h.tar (archive that contains the following files)
+ * i.txt
+ *
+ *
+ * read('.') will return a reader that gives access to following
+ * files (recursively read current dir):
+ *
+ * a.txt
+ * b.tar
+ * dir2/g.txt
+ * dir2/dir3/h.tar
+ *
+ *
+ * read('.', 'myBaseDir') will return the following reader:
+ *
+ * myBaseDir/a.txt
+ * myBaseDir/b.tar
+ * myBaseDir/dir2/g.txt
+ * myBaseDir/dir2/dir3/h.tar
+ *
+ *
+ * read('.', '', -1) will return the following reader (uncompress
+ * everything)
+ *
+ * a.txt
+ * b.tar/c.txt
+ * b.tar/d.tgz/e.txt
+ * b.tar/d.tgz/dir1/f.txt
+ * dir2/g.txt
+ * dir2/dir3/h.tar/i.txt
+ *
+ *
+ * read('.', '', 1) will uncompress only one level (so d.tgz will
+ * not be uncompressed):
+ *
+ * a.txt
+ * b.tar/c.txt
+ * b.tar/d.tgz
+ * dir2/g.txt
+ * dir2/dir3/h.tar/i.txt
+ *
+ *
+ * read('.', '', 0, 0) will not recurse into subdirectories
+ *
+ * a.txt
+ * b.tar
+ *
+ *
+ * read('.', '', 0, 1) will recurse only one level in
+ * subdirectories
+ *
+ * a.txt
+ * b.tar
+ * dir2/g.txt
+ *
+ *
+ * read('.', '', -1, 2) will uncompress everything and recurse in
+ * only 2 levels in subdirectories or archives
+ *
+ * a.txt
+ * b.tar/c.txt
+ * b.tar/d.tgz/e.txt
+ * dir2/g.txt
+ *
+ *
+ * The recursion level is determined by the real path, not the symbolic one.
+ * So read('.', 'myBaseDir', -1, 2) will result to the same files:
+ *
+ * myBaseDir/a.txt
+ * myBaseDir/b.tar/c.txt
+ * myBaseDir/b.tar/d.tgz/e.txt (accepted because the real depth is 2)
+ * myBaseDir/dir2/g.txt
+ *
+ *
+ * Use readSource to do the same thing, reading from a specified reader instead of
+ * reading from the system files
+ *
+ * To read a single file, you can do read('a.txt', 'public_name.txt')
+ * If no public name is provided, the default one is the name of the file
+ * read('dir2/g.txt') contains the single file named 'g.txt'
+ * read('b.tar/c.txt') contains the single file named 'c.txt'
+ *
+ * Note: This function uncompress files reading their extension
+ * The compressed files must have a tar, zip, gz or tgz extension
+ * Since it is impossible for some URLs to use is_dir or is_file, this
+ * function may not work with
+ * URLs containing folders which name ends with such an extension
+ */
+ function readSource(&$source, $URL, $symbolic = null,
+ $uncompression = 0, $directoryDepth = -1)
+ {
+ return File_Archive::_readSource($source, $URL, $reachable, $baseDir,
+ $symbolic, $uncompression, $directoryDepth);
+ }
+
+ /**
+ * This function performs exactly as readSource, but with two additional parameters
+ * ($reachable and $baseDir) that will be set so that $reachable."/".$baseDir == $URL
+ * and $reachable can be reached (in case of error)
+ *
+ * @access private
+ */
+ function _readSource(&$toConvert, $URL, &$reachable, &$baseDir, $symbolic = null,
+ $uncompression = 0, $directoryDepth = -1)
+ {
+ $source =& File_Archive::_convertToReader($toConvert);
+ if (PEAR::isError($source)) {
+ return $source;
+ }
+ if (is_array($URL)) {
+ $converted = array();
+ foreach($URL as $key => $foo) {
+ $converted[] =& File_Archive::_convertToReader($URL[$key]);
+ }
+ return File_Archive::readMulti($converted);
+ }
+
+ //No need to uncompress more than $directoryDepth
+ //That's not perfect, and some archives will still be uncompressed just
+ //to be filtered out :(
+ if ($directoryDepth >= 0) {
+ $uncompressionLevel = min($uncompression, $directoryDepth);
+ } else {
+ $uncompressionLevel = $uncompression;
+ }
+
+ require_once 'File/Archive/Reader.php';
+ $std = File_Archive_Reader::getStandardURL($URL);
+
+ //Modify the symbolic name if necessary
+ $slashPos = strrpos($std, '/');
+ if ($symbolic === null) {
+ if ($slashPos === false) {
+ $realSymbolic = $std;
+ } else {
+ $realSymbolic = substr($std, $slashPos+1);
+ }
+ } else {
+ $realSymbolic = $symbolic;
+ }
+ if ($slashPos !== false) {
+ $baseFile = substr($std, 0, $slashPos+1);
+ $lastFile = substr($std, $slashPos+1);
+ } else {
+ $baseFile = '';
+ $lastFile = $std;
+ }
+
+ if (strpos($lastFile, '*')!==false ||
+ strpos($lastFile, '?')!==false) {
+ //We have to build a regexp here
+ $regexp = str_replace(
+ array('\*', '\?'),
+ array('[^/]*', '[^/]'),
+ preg_quote($lastFile)
+ );
+ $result = File_Archive::_readSource($source, $baseFile,
+ $reachable, $baseDir, null, 0, -1);
+ return File_Archive::filter(
+ File_Archive::predEreg('^'.$regexp.'$'),
+ $result
+ );
+ }
+
+ //If the URL can be interpreted as a directory, and we are reading from the file system
+ if ((empty($URL) || is_dir($URL)) && $source === null) {
+ require_once "File/Archive/Reader/Directory.php";
+ require_once "File/Archive/Reader/ChangeName.php";
+
+ if ($uncompressionLevel != 0) {
+ require_once "File/Archive/Reader/Uncompress.php";
+ $result = new File_Archive_Reader_Uncompress(
+ new File_Archive_Reader_Directory($std, '', $directoryDepth),
+ $uncompressionLevel
+ );
+ } else {
+ $result = new File_Archive_Reader_Directory($std, '', $directoryDepth);
+ }
+
+ if ($directoryDepth >= 0) {
+ require_once 'File/Archive/Reader/Filter.php';
+ require_once 'File/Archive/Predicate/MaxDepth.php';
+
+ $tmp =& File_Archive::filter(
+ new File_Archive_Predicate_MaxDepth($directoryDepth),
+ $result
+ );
+ unset($result);
+ $result =& $tmp;
+ }
+ if (!empty($realSymbolic)) {
+ if ($symbolic === null) {
+ $realSymbolic = '';
+ }
+ $tmp =& new File_Archive_Reader_AddBaseName(
+ $realSymbolic,
+ $result
+ );
+ unset($result);
+ $result =& $tmp;
+ }
+
+ //If the URL can be interpreted as a file, and we are reading from the file system
+ } else if (is_file($URL) && substr($URL, -1)!='/' && $source === null) {
+ require_once "File/Archive/Reader/File.php";
+ $result = new File_Archive_Reader_File($URL, $realSymbolic);
+
+ //Else, we will have to build a complex reader
+ } else {
+ require_once "File/Archive/Reader/File.php";
+
+ $realPath = $std;
+
+ // Try to find a file with a known extension in the path (
+ // (to manage URLs like archive.tar/directory/file)
+ $pos = 0;
+ do {
+ if ($pos+1setBaseDir($std);
+ if (PEAR::isError($isDir)) {
+ return $isDir;
+ }
+ if ($isDir && $symbolic==null) {
+ //Default symbolic name for directories is empty
+ $realSymbolic = '';
+ }
+
+ if ($directoryDepth >= 0) {
+ //Limit the maximum depth if necessary
+ require_once "File/Archive/Predicate/MaxDepth.php";
+
+ $tmp = new File_Archive_Reader_Filter(
+ new File_Archive_Predicate(
+ $directoryDepth +
+ substr_count(substr($std, $pos+1), '/')
+ ),
+ $result
+ );
+ unset($result);
+ $result =& $tmp;
+ }
+
+ if ($std != $realSymbolic) {
+ require_once "File/Archive/Reader/ChangeName.php";
+
+ //Change the base name to the symbolic one if necessary
+ $tmp = new File_Archive_Reader_ChangeBaseName(
+ $std,
+ $realSymbolic,
+ $result
+ );
+ unset($result);
+ $result =& $tmp;
+ }
+ }
+
+ $cacheCondition = File_Archive::getOption('cacheCondition');
+ if ($cacheCondition !== false &&
+ preg_match($cacheCondition, $URL)) {
+ $tmp =& File_Archive::cache($result);
+ unset($result);
+ $result =& $tmp;
+ }
+
+ return $result;
+ }
+ function read($URL, $symbolic = null,
+ $uncompression = 0, $directoryDepth = -1)
+ {
+ $source = null;
+ return File_Archive::readSource($source, $URL, $symbolic, $uncompression, $directoryDepth);
+ }
+
+ /**
+ * Create a file reader on an uploaded file. The reader will read
+ * $_FILES[$name]['tmp_name'] and will have $_FILES[$name]['name']
+ * as a symbolic filename.
+ *
+ * A PEAR error is returned if one of the following happen
+ * - $_FILES[$name] is not set
+ * - $_FILES[$name]['error'] is not 0
+ * - is_uploaded_file returns false
+ *
+ * @param string $name Index of the file in the $_FILES array
+ * @return File_Archive_Reader File reader on the uploaded file
+ */
+ function readUploadedFile($name)
+ {
+ if (!isset($_FILES[$name])) {
+ return PEAR::raiseError("File $name has not been uploaded");
+ }
+ switch ($_FILES[$name]['error']) {
+ case 0:
+ //No error
+ break;
+ case 1:
+ return PEAR::raiseError(
+ "The upload size limit didn't allow to upload file ".
+ $_FILES[$name]['name']
+ );
+ case 2:
+ return PEAR::raiseError(
+ "The form size limit didn't allow to upload file ".
+ $_FILES[$name]['name']
+ );
+ case 3:
+ return PEAR::raiseError(
+ "The file was not entirely uploaded"
+ );
+ case 4:
+ return PEAR::raiseError(
+ "The uploaded file is empty"
+ );
+ default:
+ return PEAR::raiseError(
+ "Unknown error ".$_FILES[$name]['error']." in file upload. ".
+ "Please, report a bug"
+ );
+ }
+ if (!is_uploaded_file($_FILES[$name]['tmp_name'])) {
+ return PEAR::raiseError("The file is not an uploaded file");
+ }
+
+ require_once "File/Archive/Reader/File.php";
+ return new File_Archive_Reader_File(
+ $_FILES[$name]['tmp_name'],
+ $_FILES[$name]['name'],
+ $_FILES[$name]['type']
+ );
+ }
+
+ /**
+ * Adds a cache layer above the specified reader
+ * The data of the reader is saved in a temporary file for future access.
+ * The cached reader will be read only once, even if you read it several times.
+ * This can be usefull to read compressed files or downloaded files (from http or ftp)
+ *
+ * @param mixed $toConvert The reader to cache
+ * It can be a File_Archive_Reader or a string, which will be converted using the
+ * read function
+ */
+ function cache(&$toConvert)
+ {
+ $source =& File_Archive::_convertToReader($toConvert);
+ if (PEAR::isError($source)) {
+ return $source;
+ }
+
+ require_once 'File/Archive/Reader/Cache.php';
+ return new File_Archive_Reader_Cache($source);
+ }
+
+ /**
+ * Try to interpret the object as a reader
+ * Strings are converted to readers using File_Archive::read
+ * Arrays are converted to readers using File_Archive::readMulti
+ *
+ * @access private
+ */
+ function &_convertToReader(&$source)
+ {
+ if (is_string($source)) {
+ $cacheCondition = File_Archive::getOption('cacheCondition');
+ if ($cacheCondition !== false &&
+ preg_match($cacheCondition, $source)) {
+ return File_Archive::cache(File_Archive::read($source));
+ } else {
+ return File_Archive::read($source);
+ }
+ } else if (is_array($source)) {
+ return File_Archive::readMulti($source);
+ } else {
+ return $source;
+ }
+ }
+
+ /**
+ * Try to interpret the object as a writer
+ * Strings are converted to writers using File_Archive::appender
+ * Arrays are converted to writers using a multi writer
+ *
+ * @access private
+ */
+ function &_convertToWriter(&$dest)
+ {
+ if (is_string($dest)) {
+ return File_Archive::appender($dest);
+ } else if (is_array($dest)) {
+ require_once 'File/Archive/Writer/Multi.php';
+ $writer = new File_Archive_Writer_Multi();
+ foreach($dest as $key => $foo) {
+ $writer->addWriter($dest[$key]);
+ }
+ } else {
+ return $dest;
+ }
+ }
+
+ /**
+ * Check if a file with a specific extension can be read as an archive
+ * with File_Archive::read*
+ * This function is case sensitive.
+ *
+ * @param string $extension the checked extension
+ * @return bool whether this file can be understood reading its extension
+ * Currently, supported extensions are tar, zip, gz, tgz, tbz, bz2,
+ * bzip2, ar, deb
+ */
+ function isKnownExtension($extension)
+ {
+ return $extension == 'tar' ||
+ $extension == 'zip' ||
+ $extension == 'gz' ||
+ $extension == 'tgz' ||
+ $extension == 'tbz' ||
+ $extension == 'bz2' ||
+ $extension == 'bzip2' ||
+ $extension == 'ar' ||
+ $extension == 'deb' /* ||
+ $extension == 'cab' ||
+ $extension == 'rar' */;
+ }
+
+ /**
+ * Create a reader that will read the single file source $source as
+ * a specific archive
+ *
+ * @param string $extension determines the kind of archive $source contains
+ * $extension is case sensitive
+ * @param File_Archive_Reader $source stores the archive
+ * @param bool $sourceOpened specifies if the archive is already opened
+ * if false, next will be called on source
+ * Closing the returned archive will close $source iif $sourceOpened
+ * is true
+ * @return A File_Archive_Reader that uncompresses the archive contained in
+ * $source interpreting it as a $extension archive
+ * If $extension is not handled return false
+ */
+ function readArchive($extension, &$toConvert, $sourceOpened = false)
+ {
+ $source =& File_Archive::_convertToReader($toConvert);
+ if (PEAR::isError($source)) {
+ return $source;
+ }
+
+ switch($extension) {
+ case 'tgz':
+ return File_Archive::readArchive('tar',
+ File_Archive::readArchive('gz', $source, $sourceOpened)
+ );
+ case 'tbz':
+ return File_Archive::readArchive('tar',
+ File_Archive::readArchive('bz2', $source, $sourceOpened)
+ );
+ case 'tar':
+ require_once 'File/Archive/Reader/Tar.php';
+ return new File_Archive_Reader_Tar($source, $sourceOpened);
+
+ case 'gz':
+ case 'gzip':
+ require_once 'File/Archive/Reader/Gzip.php';
+ return new File_Archive_Reader_Gzip($source, $sourceOpened);
+
+ case 'zip':
+ require_once 'File/Archive/Reader/Zip.php';
+ return new File_Archive_Reader_Zip($source, $sourceOpened);
+
+ case 'bz2':
+ case 'bzip2':
+ require_once 'File/Archive/Reader/Bzip2.php';
+ return new File_Archive_Reader_Bzip2($source, $sourceOpened);
+
+ case 'deb':
+ case 'ar':
+ require_once 'File/Archive/Reader/Ar.php';
+ return new File_Archive_Reader_Ar($source, $sourceOpened);
+
+/* case 'cab':
+ require_once 'File/Archive/Reader/Cab.php';
+ return new File_Archive_Reader_Cab($source, $sourceOpened);
+
+
+ case 'rar':
+ require_once "File/Archive/Reader/Rar.php";
+ return new File_Archive_Reader_Rar($source, $sourceOpened); */
+
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Contains only one file with data read from a memory buffer
+ *
+ * @param string $memory content of the file
+ * @param string $filename public name of the file
+ * @param array $stat statistics of the file. Index 7 (size) will be
+ * overwritten to match the size of $memory
+ * @param string $mime mime type of the file. Default will determine the
+ * mime type thanks to the extension of $filename
+ * @see File_Archive_Reader_Memory
+ */
+ function readMemory($memory, $filename, $stat=array(), $mime=null)
+ {
+ require_once "File/Archive/Reader/Memory.php";
+ return new File_Archive_Reader_Memory($memory, $filename, $stat, $mime);
+ }
+
+ /**
+ * Contains several other sources. Take care the sources don't have several
+ * files with the same filename. The sources are given as a parameter, or
+ * can be added thanks to the reader addSource method
+ *
+ * @param array $sources Array of strings or readers that will be added to
+ * the multi reader. If the parameter is a string, a reader will be
+ * built thanks to the read function
+ * @see File_Archive_Reader_Multi, File_Archive::read()
+ */
+ function readMulti($sources = array())
+ {
+ require_once "File/Archive/Reader/Multi.php";
+ $result = new File_Archive_Reader_Multi();
+ foreach ($sources as $index => $foo) {
+ $s =& File_Archive::_convertToReader($sources[$index]);
+ if (PEAR::isError($s)) {
+ return $s;
+ } else {
+ $result->addSource($s);
+ }
+ }
+ return $result;
+ }
+ /**
+ * Make the files of a source appear as one large file whose content is the
+ * concatenation of the content of all the files
+ *
+ * @param File_Archive_Reader $source The source whose files must be
+ * concatened
+ * @param string $filename name of the only file of the created reader
+ * @param array $stat statistics of the file. Index 7 (size) will be
+ * overwritten to match the total size of the files
+ * @param string $mime mime type of the file. Default will determine the
+ * mime type thanks to the extension of $filename
+ * @see File_Archive_Reader_Concat
+ */
+ function readConcat(&$toConvert, $filename, $stat=array(), $mime=null)
+ {
+ $source =& File_Archive::_convertToReader($toConvert);
+ if (PEAR::isError($source)) {
+ return $source;
+ }
+
+ require_once "File/Archive/Reader/Concat.php";
+ return new File_Archive_Reader_Concat($source, $filename, $stat, $mime);
+ }
+
+ /**
+ * Removes from a source the files that do not follow a given predicat
+ *
+ * @param File_Archive_Predicate $predicate Only the files for which
+ * $predicate->isTrue() will be kept
+ * @param File_Archive_Reader $source Source that will be filtered
+ * @see File_Archive_Reader_Filter
+ */
+ function filter($predicate, &$toConvert)
+ {
+ $source =& File_Archive::_convertToReader($toConvert);
+ if (PEAR::isError($source)) {
+ return $source;
+ }
+
+ require_once "File/Archive/Reader/Filter.php";
+ return new File_Archive_Reader_Filter($predicate, $source);
+ }
+ /**
+ * Predicate that always evaluate to true
+ *
+ * @see File_Archive_Predicate_True
+ */
+ function predTrue()
+ {
+ require_once "File/Archive/Predicate/True.php";
+ return new File_Archive_Predicate_True();
+ }
+ /**
+ * Predicate that always evaluate to false
+ *
+ * @see File_Archive_Predicate_False
+ */
+ function predFalse()
+ {
+ require_once "File/Archive/Predicate/False.php";
+ return new File_Archive_Predicate_False();
+ }
+ /**
+ * Predicate that evaluates to the logical AND of the parameters
+ * You can add other predicates thanks to the
+ * File_Archive_Predicate_And::addPredicate() function
+ *
+ * @param File_Archive_Predicate (any number of them)
+ * @see File_Archive_Predicate_And
+ */
+ function predAnd()
+ {
+ require_once "File/Archive/Predicate/And.php";
+ $pred = new File_Archive_Predicate_And();
+ $args = func_get_args();
+ foreach ($args as $p) {
+ $pred->addPredicate($p);
+ }
+ return $pred;
+ }
+ /**
+ * Predicate that evaluates to the logical OR of the parameters
+ * You can add other predicates thanks to the
+ * File_Archive_Predicate_Or::addPredicate() function
+ *
+ * @param File_Archive_Predicate (any number of them)
+ * @see File_Archive_Predicate_Or
+ */
+ function predOr()
+ {
+ require_once "File/Archive/Predicate/Or.php";
+ $pred = new File_Archive_Predicate_Or();
+ $args = func_get_args();
+ foreach ($args as $p) {
+ $pred->addPredicate($p);
+ }
+ return $pred;
+ }
+ /**
+ * Negate a predicate
+ *
+ * @param File_Archive_Predicate $pred Predicate to negate
+ * @see File_Archive_Predicate_Not
+ */
+ function predNot($pred)
+ {
+ require_once "File/Archive/Predicate/Not.php";
+ return new File_Archive_Predicate_Not($pred);
+ }
+ /**
+ * Evaluates to true iif the file is larger than a given size
+ *
+ * @param int $size the minimal size of the files (in Bytes)
+ * @see File_Archive_Predicate_MinSize
+ */
+ function predMinSize($size)
+ {
+ require_once "File/Archive/Predicate/MinSize.php";
+ return new File_Archive_Predicate_MinSize($size);
+ }
+ /**
+ * Evaluates to true iif the file has been modified after a given time
+ *
+ * @param int $time Unix timestamp of the minimal modification time of the
+ * files
+ * @see File_Archive_Predicate_MinTime
+ */
+ function predMinTime($time)
+ {
+ require_once "File/Archive/Predicate/MinTime.php";
+ return new File_Archive_Predicate_MinTime($time);
+ }
+ /**
+ * Evaluates to true iif the file has less that a given number of
+ * directories in its path
+ *
+ * @param int $depth Maximal number of directories in path of the files
+ * @see File_Archive_Predicate_MaxDepth
+ */
+ function predMaxDepth($depth)
+ {
+ require_once "File/Archive/Predicate/MaxDepth.php";
+ return new File_Archive_Predicate_MaxDepth($depth);
+ }
+ /**
+ * Evaluates to true iif the extension of the file is in a given list
+ *
+ * @param array or string $list List or comma separated string of possible
+ * extension of the files
+ * @see File_Archive_Predicate_Extension
+ */
+ function predExtension($list)
+ {
+ require_once "File/Archive/Predicate/Extension.php";
+ return new File_Archive_Predicate_Extension($list);
+ }
+ /**
+ * Evaluates to true iif the MIME type of the file is in a given list
+ *
+ * @param array or string $list List or comma separated string of possible
+ * MIME types of the files. You may enter wildcards like "image/*" to
+ * select all the MIME in class image
+ * @see File_Archive_Predicate_MIME, MIME_Type::isWildcard()
+ */
+ function predMIME($list)
+ {
+ require_once "File/Archive/Predicate/MIME.php";
+ return new File_Archive_Predicate_MIME($list);
+ }
+ /**
+ * Evaluates to true iif the name of the file follow a given regular
+ * expression
+ *
+ * @param string $ereg regular expression that the filename must follow
+ * @see File_Archive_Predicate_Ereg, ereg()
+ */
+ function predEreg($ereg)
+ {
+ require_once "File/Archive/Predicate/Ereg.php";
+ return new File_Archive_Predicate_Ereg($ereg);
+ }
+ /**
+ * Evaluates to true iif the name of the file follow a given regular
+ * expression (case insensitive version)
+ *
+ * @param string $ereg regular expression that the filename must follow
+ * @see File_Archive_Predicate_Eregi, eregi
+ */
+ function predEregi($ereg)
+ {
+ require_once "File/Archive/Predicate/Eregi.php";
+ return new File_Archive_Predicate_Eregi($ereg);
+ }
+ /**
+ * Evaluates to true only after a given number of evaluations
+ * This can be used to select files by index since the evaluation is done
+ * once per file
+ *
+ * @param array The indexes for which the returned predicate will return true
+ * are the keys of the array
+ * The predicate will return true if isset($indexes[$pos])
+ */
+ function predIndex($indexes)
+ {
+ require_once "File/Archive/Predicate/Index.php";
+ return new File_Archive_Predicate_Index($indexes);
+ }
+ /**
+ * Custom predicate built by supplying a string expression
+ *
+ * Here are different ways to create a predicate that keeps only files
+ * with names shorter than 100 chars
+ *
+ * File_Archive::predCustom("return strlen($name)<100;")
+ * File_Archive::predCustom("strlen($name)<100;")
+ * File_Archive::predCustom("strlen($name)<100")
+ * File_Archive::predCustom("strlen($source->getFilename())<100")
+ *
+ *
+ * @param string $expression String containing an expression that evaluates
+ * to a boolean. If the expression doesn't contain a return
+ * statement, it will be added at the begining of the expression
+ * A ';' will be added at the end of the expression so that you don't
+ * have to write it. You may use the $name variable to refer to the
+ * current filename (with path...), $time for the modification time
+ * (unix timestamp), $size for the size of the file in bytes, $mime
+ * for the MIME type of the file
+ * @see File_Archive_Predicate_Custom
+ */
+ function predCustom($expression)
+ {
+ require_once "File/Archive/Predicate/Custom.php";
+ return new File_Archive_Predicate_Custom($expression);
+ }
+
+ /**
+ * Send the files as a mail attachment
+ *
+ * @param Mail $mail Object used to send mail (see Mail::factory)
+ * @param array or String $to An array or a string with comma separated
+ * recipients
+ * @param array $headers The headers that will be passed to the Mail_mime
+ * object
+ * @param string $message Text body of the mail
+ * @see File_Archive_Writer_Mail
+ */
+ function toMail($to, $headers, $message, $mail = null)
+ {
+ require_once "File/Archive/Writer/Mail.php";
+ return new File_Archive_Writer_Mail($to, $headers, $message, $mail);
+ }
+ /**
+ * Write the files on the hard drive
+ *
+ * @param string $baseDir if specified, the files will be created in that
+ * directory. If they don't exist, the directories will automatically
+ * be created
+ * @see File_Archive_Writer_Files
+ */
+ function toFiles($baseDir = "")
+ {
+ require_once "File/Archive/Writer/Files.php";
+ return new File_Archive_Writer_Files($baseDir);
+ }
+ /**
+ * Send the content of the files to a memory buffer
+ *
+ * toMemory returns a writer where the data will be written.
+ * In this case, the data is accessible using the getData member
+ *
+ * toVariable returns a writer that will write into the given
+ * variable
+ *
+ * @param out $data if specified, the data will be written to this buffer
+ * Else, you can retrieve the buffer with the
+ * File_Archive_Writer_Memory::getData() function
+ * @see File_Archive_Writer_Memory
+ */
+ function toMemory()
+ {
+ $v = '';
+ return File_Archive::toVariable($v);
+ }
+ function toVariable(&$v)
+ {
+ require_once "File/Archive/Writer/Memory.php";
+ return new File_Archive_Writer_Memory($v);
+ }
+ /**
+ * Duplicate the writing operation on two writers
+ *
+ * @param File_Archive_Writer $a, $b writers where data will be duplicated
+ * @see File_Archive_Writer_Multi
+ */
+ function toMulti(&$aC, &$bC)
+ {
+ $a =& File_Archive::_convertToWriter($aC);
+ $b =& File_Archive::_convertToWriter($bC);
+
+ if (PEAR::isError($a)) {
+ return $a;
+ }
+ if (PEAR::isError($b)) {
+ return $b;
+ }
+
+ require_once "File/Archive/Writer/Multi.php";
+ $writer = new File_Archive_Writer_Multi();
+ $writer->addWriter($a);
+ $writer->addWriter($b);
+ return $writer;
+ }
+ /**
+ * Send the content of the files to the standard output (so to the client
+ * for a website)
+ *
+ * @param bool $sendHeaders If true some headers will be sent to force the
+ * download of the file. Default value is true
+ * @see File_Archive_Writer_Output
+ */
+ function toOutput($sendHeaders = true)
+ {
+ require_once "File/Archive/Writer/Output.php";
+ return new File_Archive_Writer_Output($sendHeaders);
+ }
+ /**
+ * Compress the data to a tar, gz, tar/gz or zip format
+ *
+ * @param string $filename name of the archive file
+ * @param File_Archive_Writer $innerWriter writer where the archive will be
+ * written
+ * @param string $type can be one of tgz, tbz, tar, zip, gz, gzip, bz2,
+ * bzip2 (default is the extension of $filename) or any composition
+ * of them (for example tar.gz or tar.bz2). The case of this
+ * parameter is not important.
+ * @param array $stat Statistics of the archive (see stat function)
+ * @param bool $autoClose If set to true, $innerWriter will be closed when
+ * the returned archive is close. Default value is true.
+ */
+ function toArchive($filename, &$toConvert, $type = null,
+ $stat = array(), $autoClose = true)
+ {
+ $innerWriter =& File_Archive::_convertToWriter($toConvert);
+ if (PEAR::isError($innerWriter)) {
+ return $innerWriter;
+ }
+ $shortcuts = array("tgz" , "tbz" );
+ $reals = array("tar.gz", "tar.bz2");
+
+ if ($type === null) {
+ $extensions = strtolower($filename);
+ } else {
+ $extensions = strtolower($type);
+ }
+ $extensions = explode('.', str_replace($shortcuts, $reals, $extensions));
+ if ($innerWriter !== null) {
+ $writer =& $innerWriter;
+ } else {
+ $writer = File_Archive::toFiles();
+ }
+ $nbCompressions = 0;
+ $currentFilename = $filename;
+ while (($extension = array_pop($extensions)) !== null) {
+ unset($next);
+ switch($extension) {
+ case "tar":
+ require_once "File/Archive/Writer/Tar.php";
+ $next = new File_Archive_Writer_Tar(
+ $currentFilename, $writer, $stat, $autoClose
+ );
+ unset($writer); $writer =& $next;
+ break;
+ case "zip":
+ require_once "File/Archive/Writer/Zip.php";
+ $next = new File_Archive_Writer_Zip(
+ $currentFilename, $writer, $stat, $autoClose
+ );
+ unset($writer); $writer =& $next;
+ break;
+ case "gz":
+ case "gzip":
+ require_once "File/Archive/Writer/Gzip.php";
+ $next = new File_Archive_Writer_Gzip(
+ $currentFilename, $writer, $stat, $autoClose
+ );
+ unset($writer); $writer =& $next;
+ break;
+ case "bz2":
+ case "bzip2":
+ require_once "File/Archive/Writer/Bzip2.php";
+ $next = new File_Archive_Writer_Bzip2(
+ $currentFilename, $writer, $stat, $autoClose
+ );
+ unset($writer); $writer =& $next;
+ break;
+ case "deb":
+ case "ar":
+ require_once "File/Archive/Writer/Ar.php";
+ $next = new File_Archive_Writer_Ar(
+ $currentFilename, $writer, $stat, $autoClose
+ );
+ unset($writer); $writer =& $next;
+ break;
+ default:
+ if ($type !== null || $nbCompressions == 0) {
+ return PEAR::raiseError("Archive $extension unknown");
+ }
+ break;
+ }
+ $nbCompressions ++;
+ $autoClose = true;
+ $currentFilename = implode(".", $extensions);
+ }
+ return $writer;
+ }
+
+
+ /**
+ * File_Archive::extract($source, $dest) is equivalent to $source->extract($dest)
+ * If $source is a PEAR error, the error will be returned
+ * It is thus easier to use this function than $source->extract, since it reduces the number of
+ * error checking and doesn't force you to define a variable $source
+ *
+ * You may use strings as source and dest. In that case the source is automatically
+ * converted to a reader using File_Archive::read and the dest is converted to a
+ * writer using File_Archive::appender
+ * Since PHP doesn't allow to pass literal strings by ref, you will have to use temporary
+ * variables.
+ * File_Archive::extract($src = 'archive.zip/', $dest = 'dir') will extract the archive to 'dir'
+ * It is the same as
+ * File_Archive::extract(
+ * File_Archive::read('archive.zip/'),
+ * File_Archive::appender('dir')
+ * );
+ * You may use any variable in the extract function ($from/$to, $a/$b...).
+ *
+ * @param File_Archive_Reader $source The source that will be read
+ * @param File_Archive_Writer $dest Where to copy $source files
+ * @param bool $autoClose if true (default), $dest will be closed after the extraction
+ * @param int $bufferSize Size of the buffer to use to move data from the reader to the buffer
+ * If $bufferSize <= 0 (default), the blockSize option is used
+ * You shouldn't need to change that
+ * @return null or a PEAR error if an error occured
+ */
+ function extract(&$sourceToConvert, &$destToConvert, $autoClose = true, $bufferSize = 0)
+ {
+ $source =& File_Archive::_convertToReader($sourceToConvert);
+ if (PEAR::isError($source)) {
+ return $source;
+ }
+ $dest =& File_Archive::_convertToWriter($destToConvert);
+ return $source->extract($dest, $autoClose, $bufferSize);
+ }
+
+ /**
+ * Create a writer that can be used to append files to an archive inside a source
+ * If the archive can't be found in the source, it will be created
+ * If source is set to null, File_Archive::toFiles will be assumed
+ * If type is set to null, the type of the archive will be determined looking at
+ * the extension in the URL
+ * stat is the array of stat (returned by stat() PHP function of Reader getStat())
+ * to use if the archive must be created
+ *
+ * This function allows to create or append data to nested archives. Only one
+ * archive will be created and if your creation requires creating several nested
+ * archives, a PEAR error will be returned
+ *
+ * After this call, $source will be closed and should not be used until the
+ * returned writer is closed.
+ *
+ * @param File_Archive_Reader $source A reader where some files will be appended
+ * @param string $URL URL to reach the archive in the source.
+ * if $URL is null, a writer to append files to the $source reader will
+ * be returned
+ * @param bool $unique If true, the duplicate files will be deleted on close
+ * Default is false (and setting it to true may have some performance
+ * consequences)
+ * @param string $type Extension of the archive (or null to use the one in the URL)
+ * @param array $stat Used only if archive is created, array of stat as returned
+ * by PHP stat function or Reader getStat function: stats of the archive)
+ * Time (index 9) will be overwritten to current time
+ * @return File_Archive_Writer a writer that you can use to append files to the reader
+ */
+ function appenderFromSource(&$toConvert, $URL = null, $unique = null,
+ $type = null, $stat = array())
+ {
+ $source =& File_Archive::_convertToReader($toConvert);
+ if (PEAR::isError($source)) {
+ return $source;
+ }
+ if ($unique == null) {
+ $unique = File_Archive::getOption("appendRemoveDuplicates");
+ }
+
+ //Do not report the fact that the archive does not exist as an error
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+
+ if ($URL === null) {
+ $result =& $source;
+ } else {
+ if ($type === null) {
+ $result = File_Archive::_readSource($source, $URL.'/', $reachable, $baseDir);
+ } else {
+ $result = File_Archive::readArchive(
+ $type,
+ File_Archive::_readSource($source, $URL, $reachable, $baseDir)
+ );
+ }
+ }
+
+ PEAR::popErrorHandling();
+
+ if (!PEAR::isError($result)) {
+ if ($unique) {
+ require_once "File/Archive/Writer/UniqueAppender.php";
+ return new File_Archive_Writer_UniqueAppender($result);
+ } else {
+ return $result->makeAppendWriter();
+ }
+ }
+
+ //The source can't be found and has to be created
+ $stat[9] = $stat['mtime'] = time();
+
+ if (empty($baseDir)) {
+ if ($source !== null) {
+ $writer =& $source->makeWriter();
+ } else {
+ $writer =& File_Archive::toFiles();
+ }
+ if (PEAR::isError($writer)) {
+ return $writer;
+ }
+
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ $result = File_Archive::toArchive($reachable, $writer, $type);
+ PEAR::popErrorHandling();
+
+ if (PEAR::isError($result)) {
+ $result = File_Archive::toFiles($reachable);
+ }
+ } else {
+ $reachedSource = File_Archive::readSource($source, $reachable);
+ if (PEAR::isError($reachedSource)) {
+ return $reachedSource;
+ }
+ $writer = $reachedSource->makeWriter();
+ if (PEAR::isError($writer)) {
+ return $writer;
+ }
+
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ $result = File_Archive::toArchive($baseDir, $writer, $type);
+ PEAR::popErrorHandling();
+
+ if (PEAR::isError($result)) {
+ require_once "File/Archive/Writer/AddBaseName.php";
+ $result = new File_Archive_Writer_AddBaseName(
+ $baseDir, $writer);
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Create a writer that allows appending new files to an existing archive
+ * This function actes as appendToSource with source being the system files
+ * $URL can't be null here
+ *
+ * @param File_Archive_Reader $source A reader where some files will be appended
+ * @return File_Archive_Writer a writer that you can use to append files to the reader
+ */
+ function appender($URL, $unique = null, $type = null, $stat = array())
+ {
+ $source = null;
+ return File_Archive::appenderFromSource($source, $URL, $unique, $type, $stat);
+ }
+
+ /**
+ * Remove the files that follow a given predicate from the source
+ * If URL is null, the files will be removed from the source directly
+ * Else, URL must link to a source from which the files will be removed
+ *
+ * @param File_Archive_Predicate $pred The files that follow the predicate
+ * (for which $pred->isTrue($source) is true) will be erased
+ * @param File_Archive_Reader $source A reader that contains the files to remove
+ */
+ function removeFromSource(&$pred, &$toConvert, $URL = null)
+ {
+ $source =& File_Archive::_convertToReader($toConvert);
+ if (PEAR::isError($source)) {
+ return $source;
+ }
+ if ($URL === null) {
+ $result = &$source;
+ } else {
+ if (substr($URL, -1) !== '/') {
+ $URL .= '/';
+ }
+ $result = File_Archive::readSource($source, $URL);
+ }
+
+ $writer = $result->makeWriterRemoveFiles($pred);
+ if (PEAR::isError($writer)) {
+ return $writer;
+ }
+ $writer->close();
+ }
+
+ /**
+ * Remove the files that follow a given predicate from the archive specified
+ * in $URL
+ *
+ * @param $URL URL of the archive where some files must be removed
+ */
+ function remove($pred, $URL)
+ {
+ $source = null;
+ return File_Archive::removeFromSource($pred, $source, $URL);
+ }
+
+ /**
+ * Remove duplicates from a source, keeping the most recent one (or the one that has highest pos in
+ * the archive if the files have same date or no date specified)
+ *
+ * @param File_Archive_Reader a reader that may contain duplicates
+ */
+ function removeDuplicatesFromSource(&$toConvert, $URL = null)
+ {
+ $source =& File_Archive::_convertToReader($toConvert);
+ if (PEAR::isError($source)) {
+ return $source;
+ }
+ if ($URL !== null && substr($URL, -1) != '/') {
+ $URL .= '/';
+ }
+
+ if ($source === null) {
+ $source = File_Archive::read($URL);
+ }
+
+ require_once "File/Archive/Predicate/Duplicate.php";
+ $pred = new File_Archive_Predicate_Duplicate($source);
+ $source->close();
+ return File_Archive::removeFromSource(
+ $pred,
+ $source,
+ null
+ );
+ }
+
+ /**
+ * Remove duplicates from the archive specified in the URL
+ */
+ function removeDuplicates($URL)
+ {
+ $source = null;
+ return File_Archive::removeDuplicatesFromSource($source, $URL);
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Predicate.php b/thirdparty/pear/File/Archive/Predicate.php
new file mode 100644
index 0000000..437e7c5
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Predicate.php
@@ -0,0 +1,57 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Predicate.php,v 1.7 2005/05/26 21:30:18 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Reader.php";
+
+/**
+ * A predicate is an object that can evaluate to true or false depending on the
+ * file currently read by a File_Archive_Reader
+ *
+ * @see File_Archive_Reader_Filter
+ */
+class File_Archive_Predicate
+{
+ /**
+ * Indicates whether the current file from the reader should be kept
+ *
+ * @param File_Archive_Reader $source Reader which will be filtered
+ * @return bool False iif the current file must be filtered out
+ */
+ function isTrue(&$source)
+ {
+ return PEAR::raiseError("Predicat abstract function call");
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Predicate/And.php b/thirdparty/pear/File/Archive/Predicate/And.php
new file mode 100644
index 0000000..04bfc7f
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Predicate/And.php
@@ -0,0 +1,87 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: And.php,v 1.8 2005/04/21 10:01:46 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Predicate.php";
+
+/**
+ * Evaluates to true iif all predicates given as constructor parameters evaluate
+ * to true
+ *
+ * Example:
+ * new File_Archive_Predicate_And($pred1, $pred2, $pred3)
+ *
+ * @see File_Archive_Predicate, File_Archive_Reader_Filter
+ */
+class File_Archive_Predicate_And extends File_Archive_Predicate
+{
+ /**
+ * @var Array List of File_Archive_Predicate objects given as an argument
+ * @access private
+ */
+ var $preds;
+
+ /**
+ * Build the predicate using the optional File_Archive_Predicates given as
+ * arguments
+ *
+ * Example:
+ * new File_Archive_Predicate_And($pred1, $pred2, $pred3)
+ */
+ function File_Archive_Predicate_And()
+ {
+ $this->preds = func_get_args();
+ }
+
+ /**
+ * Add a new predicate to the list
+ *
+ * @param File_Archive_Predicate The predicate to add
+ */
+ function addPredicate($pred)
+ {
+ $this->preds[] = $pred;
+ }
+ /**
+ * @see File_Archive_Predicate::isTrue()
+ */
+ function isTrue(&$source)
+ {
+ foreach ($this->preds as $p) {
+ if (!$p->isTrue($source)) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Predicate/Current.php b/thirdparty/pear/File/Archive/Predicate/Current.php
new file mode 100644
index 0000000..e331104
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Predicate/Current.php
@@ -0,0 +1,52 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Current.php,v 1.1 2005/05/28 23:17:28 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Predicate.php";
+
+/**
+ * Evaluates to true only once, and then always to false
+ */
+class File_Archive_Predicate_Current extends File_Archive_Predicate
+{
+ var $value = true;
+
+ /**
+ * @see File_Archive_Predicate::isTrue()
+ */
+ function isTrue(&$source)
+ {
+ $tmp = $this->value;
+ $this->value = false;
+ return $tmp;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Predicate/Custom.php b/thirdparty/pear/File/Archive/Predicate/Custom.php
new file mode 100644
index 0000000..6e517dc
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Predicate/Custom.php
@@ -0,0 +1,88 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Custom.php,v 1.7 2005/04/21 10:01:46 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Predicate.php";
+
+/**
+ * Custom predicate built by supplying a string expression
+ *
+ * Example:
+ * new File_Archive_Predicate_Custom("return strlen($name)<100;")
+ * new File_Archive_Predicate_Custom("strlen($name)<100;")
+ * new File_Archive_Predicate_Custom("strlen($name)<100")
+ * new File_Archive_Predicate_Custom("strlen($source->getFilename())<100")
+ *
+ * @see File_Archive_Predicate, File_Archive_Reader_Filter
+ */
+class File_Archive_Predicate_Custom extends File_Archive_Predicate
+{
+ var $expression;
+ var $useName;
+ var $useStat;
+ var $useMIME;
+
+ /**
+ * @param string $expression PHP code that evaluates too a boolean
+ * It can use the $source variable. If return is ommited, it will be
+ * added to the begining of the expression. A ; will also be added at
+ * the end so that you don't need to write it
+ */
+ function File_Archive_Predicate_Custom($expression)
+ {
+ $this->expression = $expression.";";
+ if (strpos($this->expression, "return") === false) {
+ $this->expression = "return ".$this->expression;
+ }
+ $this->useName = (strpos($this->expression, '$name') !== false);
+ $this->useStat = (strpos($this->expression, '$stat') !== false);
+ $this->useMIME = (strpos($this->expression, '$mime') !== false);
+ }
+ /**
+ * @see File_Archive_Predicate::isTrue()
+ */
+ function isTrue(&$source)
+ {
+ if ($this->useName) {
+ $name = $source->getFilename();
+ }
+ if ($this->useStat) {
+ $stat = $source->getStat();
+ $size = $stat[7];
+ $time = (isset($stat[9]) ? $stat[9] : null);
+ }
+ if ($this->useMIME) {
+ $mime = $source->getMIME();
+ }
+ return eval($this->expression);
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Predicate/Duplicate.php b/thirdparty/pear/File/Archive/Predicate/Duplicate.php
new file mode 100644
index 0000000..ba1ecdc
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Predicate/Duplicate.php
@@ -0,0 +1,116 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Duplicate.php,v 1.1 2005/05/30 17:18:11 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Predicate.php";
+
+/**
+ * Evaluates to true if a for the files for which a newer version
+ * can be found in a specified archive
+ * Comparison is by default made on dates of the files, or position
+ * in the archive (if two files have the same date or the date of a
+ * file is not specified).
+ */
+class File_Archive_Predicate_Duplicate extends File_Archive_Predicate
+{
+ /**
+ * @var array Key is the filename, value is an array of date (index 0) and
+ * position in the archive (index) 1 of the newest entry with this filename
+ */
+ var $newest = array();
+
+ /**
+ * @var int The current position of the file in the source
+ */
+ var $pos = 0;
+
+ /**
+ * @param File_Archive_Reader $source The source will be inspected to find
+ * the date of old files
+ * The predicate should then be used on the same source to remove the
+ * old duplicate files
+ */
+ function File_Archive_Predicate_Duplicate(&$source)
+ {
+ //Ensure we are at the begining of the file
+ $source->close();
+ $pos = 0;
+ while ($source->next()) {
+ $filename = $source->getFilename();
+ $stat = $source->getStat();
+ $value = isset($this->newest[$filename]) ? $this->newest[$filename] : null;
+
+ if ($value === null ||
+ $this->compare($stat[9], $value[0]) >= 0
+ ) {
+ $this->newest[$filename] = array($stat[9], $pos);
+ }
+ $pos++;
+ }
+ }
+
+ /**
+ * Compare the dates of two files. null is considered infinitely old
+ *
+ * @return int < 0 if $a can be considered older than $b
+ * = 0 if $a and $b can be considered same age
+ * > 0 if $a can be considered newer than $b
+ */
+ function compare($a, $b) {
+ return ($a === null ? -1 : $a) - ($b === null ? -1 : $b);
+ }
+
+ /**
+ * @see File_Archive_Predicate::isTrue()
+ */
+ function isTrue(&$source)
+ {
+ $filename = $source->getFilename();
+ $stat = $source->getStat();
+ $value = isset($this->newest[$filename]) ? $this->newest[$filename] : null;
+ if ($value === null) {
+ $delete = false;
+ } else {
+ $comp = $this->compare($stat[9], $value[0]);
+
+ $delete = $comp < 0 ||
+ ($comp == 0 && $this->pos != $value[1]);
+
+ }
+ $this->pos++;
+ return $delete;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Predicate/Ereg.php b/thirdparty/pear/File/Archive/Predicate/Ereg.php
new file mode 100644
index 0000000..f0c33c6
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Predicate/Ereg.php
@@ -0,0 +1,59 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Ereg.php,v 1.5 2005/04/21 10:01:46 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Predicate.php";
+
+/**
+ * Keep only the files which name follow a given regular expression
+ *
+ * @see File_Archive_Predicate, File_Archive_Reader_Filter ereg
+ */
+class File_Archive_Predicate_Ereg extends File_Archive_Predicate
+{
+ var $ereg;
+
+ /**
+ * @param string $ereg is the regular expression
+ */
+ function File_Archive_Predicate_Ereg($ereg)
+ {
+ $this->ereg = $ereg;
+ }
+ /**
+ * @see File_Archive_Predicate::isTrue()
+ */
+ function isTrue(&$source)
+ {
+ return ereg($this->ereg, $source->getFilename());
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Predicate/Eregi.php b/thirdparty/pear/File/Archive/Predicate/Eregi.php
new file mode 100644
index 0000000..bdf9e50
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Predicate/Eregi.php
@@ -0,0 +1,61 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Eregi.php,v 1.6 2005/04/21 10:01:46 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Predicate.php";
+
+/**
+ * Keep only the files which name follow a given case insensitive regular
+ * expression
+ *
+ * @see File_Archive_Predicate, File_Archive_Reader_Filter eregi
+ */
+class File_Archive_Predicate_Eregi extends File_Archive_Predicate
+{
+ var $ereg;
+
+ /**
+ * @param string $ereg is the regular expression
+ */
+ function File_Archive_Predicate_Eregi($ereg)
+ {
+ $this->ereg = $ereg;
+ }
+ /**
+ * @see File_Archive_Predicate::isTrue()
+ */
+ function isTrue(&$source)
+ {
+ return eregi($this->ereg, $source->getFilename());
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Predicate/Extension.php b/thirdparty/pear/File/Archive/Predicate/Extension.php
new file mode 100644
index 0000000..137fd8f
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Predicate/Extension.php
@@ -0,0 +1,71 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Extension.php,v 1.5 2005/04/21 10:01:46 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Predicate.php";
+
+/**
+ * Keep only the files that have a specific extension
+ *
+ * @see File_Archive_Predicate, File_Archive_Reader_Filter
+ */
+class File_Archive_Predicate_Extension extends File_Archive_Predicate
+{
+ var $extensions;
+
+ /**
+ * @param $extensions array or comma separated string of allowed extensions
+ */
+ function File_Archive_Predicate_Extension($extensions)
+ {
+ if (is_string($extensions)) {
+ $this->extensions = explode(",",$extensions);
+ } else {
+ $this->extensions = $extensions;
+ }
+ }
+ /**
+ * @see File_Archive_Predicate::isTrue()
+ */
+ function isTrue(&$source)
+ {
+ $filename = $source->getFilename();
+ $pos = strrpos($filename, '.');
+ $extension = "";
+ if ($pos !== FALSE) {
+ $extension = strtolower(substr($filename, $pos+1));
+ }
+ $result = in_array($extension, $this->extensions);
+
+ return $result;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Predicate/False.php b/thirdparty/pear/File/Archive/Predicate/False.php
new file mode 100644
index 0000000..21d137b
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Predicate/False.php
@@ -0,0 +1,47 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: False.php,v 1.5 2005/04/21 10:01:46 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Predicate.php";
+
+/**
+ * Always evaluate to false
+ *
+ * @see File_Archive_Predicate, File_Archive_Reader_Filter
+ */
+class File_Archive_Predicate_False extends File_Archive_Predicate
+{
+ /**
+ * @see File_Archive_Predicate::isTrue()
+ */
+ function isTrue(&$source) { return false; }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Predicate/Index.php b/thirdparty/pear/File/Archive/Predicate/Index.php
new file mode 100644
index 0000000..3ac0d68
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Predicate/Index.php
@@ -0,0 +1,62 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Index.php,v 1.1 2005/05/30 19:44:53 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Predicate.php";
+
+/**
+ * Evaluates to true if the index is in a given array of indexes
+ * The array has the indexes in key (so you may want to call
+ * array_flip if your array has indexes as value)
+ */
+class File_Archive_Predicate_Index extends File_Archive_Predicate
+{
+ var $indexes;
+ var $pos = 0;
+
+ /**
+ * @param $extensions array or comma separated string of allowed extensions
+ */
+ function File_Archive_Predicate_Index($indexes)
+ {
+ $this->indexes = $indexes;
+ }
+ /**
+ * @see File_Archive_Predicate::isTrue()
+ */
+ function isTrue(&$source)
+ {
+ return isset($this->indexes[$this->pos++]);
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Predicate/MIME.php b/thirdparty/pear/File/Archive/Predicate/MIME.php
new file mode 100644
index 0000000..9b7e48e
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Predicate/MIME.php
@@ -0,0 +1,75 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: MIME.php,v 1.5 2005/04/21 10:01:46 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Predicate.php";
+require_once "MIME/Type.php";
+
+/**
+ * Keep only the files that have a specific MIME type
+ *
+ * @see File_Archive_Predicate, File_Archive_Reader_Filter
+ */
+class File_Archive_Predicate_MIME extends File_Archive_Predicate
+{
+ var $mimes;
+
+ /**
+ * @param $extensions array or comma separated string of allowed extensions
+ */
+ function File_Archive_Predicate_MIME($mimes)
+ {
+ if (is_string($mimes)) {
+ $this->mimes = explode(",",$mimes);
+ } else {
+ $this->mimes = $mimes;
+ }
+ }
+ /**
+ * @see File_Archive_Predicate::isTrue()
+ */
+ function isTrue(&$source)
+ {
+ $sourceMIME = $source->getMIME();
+ foreach ($this->mimes as $mime) {
+ if (MIME_Type::isWildcard($mime)) {
+ $result = MIME_Type::wildcardMatch($mime, $sourceMIME);
+ } else {
+ $result = ($mime == $sourceMIME);
+ }
+ if ($result !== false) {
+ return $result;
+ }
+ }
+ return false;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Predicate/MaxDepth.php b/thirdparty/pear/File/Archive/Predicate/MaxDepth.php
new file mode 100644
index 0000000..d210a4f
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Predicate/MaxDepth.php
@@ -0,0 +1,63 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: MaxDepth.php,v 1.6 2005/04/21 10:01:46 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Predicate.php";
+
+/**
+ * Remove the URLs with a too high number of nested directories
+ *
+ * @see File_Archive_Predicate, File_Archive_Reader_Filter
+ */
+class File_Archive_Predicate_MaxDepth extends File_Archive_Predicate
+{
+ var $maxDepth;
+
+ /**
+ * @param int $maxDepth Maximal number of folders before the actual file in
+ * $source->getFilename().
+ * '1/2/3/4/foo.txt' will be accepted with $maxDepth == 4 and
+ * rejected with $maxDepth == 5
+ */
+ function File_Archive_Predicate_MaxDepth($maxDepth)
+ {
+ $this->maxDepth = $maxDepth;
+ }
+ /**
+ * @see File_Archive_Predicate::isTrue()
+ */
+ function isTrue(&$source)
+ {
+ $url = parse_url($source->getFilename());
+ return substr_count($url['path'], '/') <= $this->maxDepth ;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Predicate/MinSize.php b/thirdparty/pear/File/Archive/Predicate/MinSize.php
new file mode 100644
index 0000000..5159832
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Predicate/MinSize.php
@@ -0,0 +1,59 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: MinSize.php,v 1.5 2005/04/21 10:01:47 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Predicate.php";
+
+/**
+ * Keep only the files larger than a given size
+ *
+ * @see File_Archive_Predicate, File_Archive_Reader_Filter
+ */
+class File_Archive_Predicate_MinSize extends File_Archive_Predicate
+{
+ var $minSize = 0;
+
+ /**
+ * @param int $minSize minimal size of the file (in Bytes)
+ */
+ function File_Archive_Predicate_MinSize($minSize)
+ {
+ $this->minSize = $minSize;
+ }
+ /**
+ * @see File_Archive_Predicate::isTrue()
+ */
+ function isTrue(&$source)
+ {
+ $stat = $source->getStat();
+ return !isset($stat[7]) || $stat[7]>=$this->minSize;
+ }
+}
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Predicate/MinTime.php b/thirdparty/pear/File/Archive/Predicate/MinTime.php
new file mode 100644
index 0000000..aa74145
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Predicate/MinTime.php
@@ -0,0 +1,63 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: MinTime.php,v 1.6 2005/04/21 10:01:47 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Predicate.php";
+
+/**
+ * Keep only the files modified after a given date (or with unknown modification
+ * date)
+ *
+ * @see File_Archive_Predicate, File_Archive_Reader_Filter
+ */
+class File_Archive_Predicate_MinTime extends File_Archive_Predicate
+{
+ var $minTime = 0;
+
+ /**
+ * @param int $minTime Unix timestamp of the minimal modification date of
+ * the files
+ */
+ function File_Archive_Predicate_MinTime($minTime)
+ {
+ $this->minTime = $minTime;
+
+ }
+ /**
+ * @see File_Archive_Predicate::isTrue()
+ */
+ function isTrue(&$source)
+ {
+ $stat = $source->getStat();
+ return !isset($stat[9]) || $stat[9]>=$this->minTime;
+ }
+}
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Predicate/Not.php b/thirdparty/pear/File/Archive/Predicate/Not.php
new file mode 100644
index 0000000..28fac53
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Predicate/Not.php
@@ -0,0 +1,55 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Not.php,v 1.5 2005/04/21 10:01:47 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Predicate.php";
+
+/**
+ * Evaluates to true iif the predicate given in parameter evaluates to false
+ *
+ * @see File_Archive_Predicate, File_Archive_Reader_Filter
+ */
+class File_Archive_Predicate_Not extends File_Archive_Predicate
+{
+ var $pred;
+ function File_Archive_Predicate_Not($pred)
+ {
+ $this->pred = $pred;
+ }
+ /**
+ * @see File_Archive_Predicate::isTrue()
+ */
+ function isTrue(&$source)
+ {
+ return !$this->pred->isTrue($source);
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Predicate/Or.php b/thirdparty/pear/File/Archive/Predicate/Or.php
new file mode 100644
index 0000000..9d4c473
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Predicate/Or.php
@@ -0,0 +1,85 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Or.php,v 1.8 2005/04/21 10:01:47 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Predicate.php";
+
+/**
+ * Evaluates to true iif one at least of the predicates
+ * given as constructor parameters evaluate to true
+ *
+ * @see File_Archive_Predicate, File_Archive_Reader_Filter
+ */
+class File_Archive_Predicate_Or extends File_Archive_Predicate
+{
+ /**
+ * @var Array List of File_Archive_Predicate objects given as an argument
+ * @access private
+ */
+ var $preds;
+
+ /**
+ * Build the predicate using the optional File_Archive_Predicates given as
+ * arguments
+ *
+ * Example:
+ * new File_Archive_Predicate_And($pred1, $pred2, $pred3)
+ */
+ function File_Archive_Predicate_And()
+ {
+ $this->preds = func_get_args();
+ }
+
+ /**
+ * Add a new predicate to the list
+ *
+ * @param File_Archive_Predicate The predicate to add
+ */
+ function addPredicate($pred)
+ {
+ $this->preds[] = $pred;
+ }
+
+ /**
+ * @see File_Archive_Predicate::isTrue()
+ */
+ function isTrue(&$source)
+ {
+ foreach ($this->preds as $p) {
+ if ($p->isTrue($source)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Predicate/True.php b/thirdparty/pear/File/Archive/Predicate/True.php
new file mode 100644
index 0000000..db1491e
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Predicate/True.php
@@ -0,0 +1,45 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: True.php,v 1.5 2005/04/21 10:01:47 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Predicate.php";
+
+/**
+ * Always evaluate to true
+ */
+class File_Archive_Predicate_True extends File_Archive_Predicate
+{
+ /**
+ * @see File_Archive_Predicate::isTrue()
+ */
+ function isTrue(&$source) { return true; }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Reader.php b/thirdparty/pear/File/Archive/Reader.php
new file mode 100644
index 0000000..0149965
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Reader.php
@@ -0,0 +1,416 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Reader.php,v 1.33 2005/07/07 12:24:57 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "PEAR.php";
+
+/**
+ * Abstract base class for all the readers
+ *
+ * A reader is a compilation of serveral files that can be read
+ */
+class File_Archive_Reader
+{
+ /**
+ * Move to the next file in the reader
+ *
+ * @return bool false iif no more files are available
+ */
+ function next()
+ {
+ return false;
+ }
+
+ /**
+ * Move to the next file whose name is in directory $filename
+ * or is exactly $filename
+ *
+ * @param string $filename Name of the file to find in the archive
+ * @param bool $close If true, close the reader and search from the first file
+ * @return bool whether the file was found in the archive or not
+ */
+ function select($filename, $close = true)
+ {
+ $std = $this->getStandardURL($filename);
+
+ if ($close) {
+ $error = $this->close();
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+ }
+ while (($error = $this->next()) === true) {
+ $sourceName = $this->getFilename();
+ if (
+ empty($std) ||
+
+ //$std is a file
+ $std == $sourceName ||
+
+ //$std is a directory
+ strncmp($std.'/', $sourceName, strlen($std)+1) == 0
+ ) {
+ return true;
+ }
+ }
+ return $error;
+ }
+
+ /**
+ * Returns the standard path
+ * Changes \ to /
+ * Removes the .. and . from the URL
+ * @param string $path a valid URL that may contain . or .. and \
+ * @static
+ */
+ function getStandardURL($path)
+ {
+ if ($path == '.') {
+ return '';
+ }
+ $std = str_replace("\\", "/", $path);
+ while ($std != ($std = preg_replace("/[^\/:?]+\/\.\.\//", "", $std))) ;
+ $std = str_replace("/./", "", $std);
+ if (strncmp($std, "./", 2) == 0) {
+ return substr($std, 2);
+ } else {
+ return $std;
+ }
+ }
+
+ /**
+ * Returns the name of the file currently read by the reader
+ *
+ * Warning: undefined behaviour if no call to next have been
+ * done or if last call to next has returned false
+ *
+ * @return string Name of the current file
+ */
+ function getFilename()
+ {
+ return PEAR::raiseError("Reader abstract function call (getFilename)");
+ }
+
+ /**
+ * Returns the list of filenames from the current pos to the end of the source
+ * The source will be closed after having called this function
+ * This function goes through the whole archive (which may be slow).
+ * If you intend to work on the reader, doing it in one pass would be faster
+ *
+ * @return array filenames from the current pos to the end of the source
+ */
+ function getFileList()
+ {
+ $result = array();
+ while ( ($error = $this->next()) === true) {
+ $result[] = $this->getFilename();
+ }
+ $this->close();
+ if (PEAR::isError($error)) {
+ return $error;
+ } else {
+ return $result;
+ }
+ }
+
+ /**
+ * Returns an array of statistics about the file
+ * (see the PHP stat function for more information)
+ *
+ * The returned array may be empty, even if readers should try
+ * their best to return as many data as possible
+ */
+ function getStat() { return array(); }
+
+ /**
+ * Returns the MIME associated with the current file
+ * The default function does that by looking at the extension of the file
+ */
+ function getMime()
+ {
+ require_once "File/Archive/Reader/MimeList.php";
+ return File_Archive_Reader_GetMime($this->getFilename());
+ }
+
+ /**
+ * If the current file of the archive is a physical file,
+ *
+ * @return the name of the physical file containing the data
+ * or null if no such file exists
+ *
+ * The data filename may not be the same as the filename.
+ */
+ function getDataFilename() { return null; }
+
+ /**
+ * Reads some data from the current file
+ * If the end of the file is reached, returns null
+ * If $length is not specified, reads up to the end of the file
+ * If $length is specified reads up to $length
+ */
+ function getData($length = -1)
+ {
+ return PEAR::raiseError("Reader abstract function call (getData)");
+ }
+
+ /**
+ * Skip some data and returns how many bytes have been skipped
+ * This is strictly equivalent to
+ * return strlen(getData($length))
+ * But could be far more efficient
+ */
+ function skip($length = -1)
+ {
+ $data = $this->getData($length);
+ if (PEAR::isError($data)) {
+ return $data;
+ } else {
+ return strlen($data);
+ }
+ }
+
+ /**
+ * Move the current position back of a given amount of bytes.
+ * Not all readers may implement this function (a PEAR error will
+ * be returned if the reader can't rewind)
+ *
+ * @param int $length number of bytes to seek before the current pos
+ * or -1 to move back to the begining of the current file
+ * @return the number of bytes really rewinded (which may be less than
+ * $length if the current pos is less than $length
+ */
+ function rewind($length = -1)
+ {
+ return PEAR::raiseError('Rewind function is not implemented on this reader');
+ }
+
+ /**
+ * Returns the current offset in the current file
+ */
+ function tell()
+ {
+ $offset = $this->rewind();
+ $this->skip($offset);
+ return $offset;
+ }
+
+ /**
+ * Put back the reader in the state it was before the first call
+ * to next()
+ */
+ function close()
+ {
+ }
+
+ /**
+ * Sends the current file to the Writer $writer
+ * The data will be sent by chunks of at most $bufferSize bytes
+ * If $bufferSize <= 0 (default), the blockSize option is used
+ */
+ function sendData(&$writer, $bufferSize = 0)
+ {
+ if (PEAR::isError($writer)) {
+ return $writer;
+ }
+ if ($bufferSize <= 0) {
+ $bufferSize = File_Archive::getOption('blockSize');
+ }
+
+ $filename = $this->getDataFilename();
+ if ($filename !== null) {
+ $error = $writer->writeFile($filename);
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+ } else {
+ while (($data = $this->getData($bufferSize)) !== null) {
+ if (PEAR::isError($data)) {
+ return $data;
+ }
+ $error = $writer->writeData($data);
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+ }
+ }
+ }
+
+ /**
+ * Sends the whole reader to $writer and close the reader
+ *
+ * @param File_Archive_Writer $writer Where to write the files of the reader
+ * @param bool $autoClose If true, close $writer at the end of the function.
+ * Default value is true
+ * @param int $bufferSize Size of the chunks that will be sent to the writer
+ * If $bufferSize <= 0 (default value), the blockSize option is used
+ */
+ function extract(&$writer, $autoClose = true, $bufferSize = 0)
+ {
+ if (PEAR::isError($writer)) {
+ $this->close();
+ return $writer;
+ }
+
+ while (($error = $this->next()) === true) {
+ if ($writer->newFileNeedsMIME()) {
+ $mime = $this->getMime();
+ } else {
+ $mime = null;
+ }
+ $error = $writer->newFile(
+ $this->getFilename(),
+ $this->getStat(),
+ $mime
+ );
+ if (PEAR::isError($error)) {
+ break;
+ }
+ $error = $this->sendData($writer, $bufferSize);
+ if (PEAR::isError($error)) {
+ break;
+ }
+ }
+ $this->close();
+ if ($autoClose) {
+ $writer->close();
+ }
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+ }
+
+ /**
+ * Extract only one file (given by the URL)
+ *
+ * @param string $filename URL of the file to extract from this
+ * @param File_Archive_Writer $writer Where to write the file
+ * @param bool $autoClose If true, close $writer at the end of the function
+ * Default value is true
+ * @param int $bufferSize Size of the chunks that will be sent to the writer
+ * If $bufferSize <= 0 (default value), the blockSize option is used
+ */
+ function extractFile($filename, &$writer,
+ $autoClose = true, $bufferSize = 0)
+ {
+ if (PEAR::isError($writer)) {
+ return $writer;
+ }
+
+ if (($error = $this->select($filename)) === true) {
+ $result = $this->sendData($writer, $bufferSize);
+ if (!PEAR::isError($result)) {
+ $result = true;
+ }
+ } else if ($error === false) {
+ $result = PEAR::raiseError("File $filename not found");
+ } else {
+ $result = $error;
+ }
+ if ($autoClose) {
+ $error = $writer->close();
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Return a writer that allows appending files to the archive
+ * After having called makeAppendWriter, $this is closed and should not be
+ * used until the returned writer is closed.
+ *
+ * @return a writer that will allow to append files to an existing archive
+ * @see makeWriter
+ */
+ function makeAppendWriter()
+ {
+ require_once "File/Archive/Predicate/False.php";
+ return $this->makeWriterRemoveFiles(new File_Archive_Predicate_False());
+ }
+
+ /**
+ * Return a writer that has the same properties as the one returned by
+ * makeAppendWriter, but after having removed all the files that follow a
+ * given predicate.
+ * After a call to makeWriterRemoveFiles, $this is closed and should not
+ * be used until the returned writer is closed
+ *
+ * @param File_Archive_Predicate $pred the predicate verified by removed files
+ * @return File_Archive_Writer that allows to append files to the archive
+ */
+ function makeWriterRemoveFiles($pred)
+ {
+ return PEAR::raiseError("Reader abstract function call (makeWriterRemoveFiles)");
+ }
+
+ /**
+ * Returns a writer that removes the current file
+ * This is a syntaxic sugar for makeWriterRemoveFiles(new File_Archive_Predicate_Current());
+ */
+ function makeWriterRemove()
+ {
+ require_once "File/Archive/Predicate/Current.php";
+ return $this->makeWriterRemoveFiles(new File_Archive_Predicate_Current());
+ }
+
+ /**
+ * Removes the current file from the reader
+ */
+ function remove()
+ {
+ $writer = $this->makeWriterRemove();
+ if (PEAR::isError($writer)) {
+ return $writer;
+ }
+ $writer->close();
+ }
+
+ /**
+ * Return a writer that has the same properties as the one returned by makeWriter, but after
+ * having removed a block of data from the current file. The writer will append data to the current file
+ * no data (other than the block) will be removed
+ *
+ * @param array Lengths of the blocks. The first one will be discarded, the second one kept, the third
+ * one discarded... If the sum of the blocks is less than the size of the file, the comportment is the
+ * same as if a last block was set in the array to reach the size of the file
+ * if $length is -1, the file is truncated from the specified pos
+ * It is possible to specify blocks of size 0
+ * @param int $seek relative pos of the block
+ */
+ function makeWriterRemoveBlocks($blocks, $seek = 0)
+ {
+ return PEAR::raiseError("Reader abstract function call (makeWriterRemoveBlocks)");
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Reader/Ar.php b/thirdparty/pear/File/Archive/Reader/Ar.php
new file mode 100644
index 0000000..9170bf1
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Reader/Ar.php
@@ -0,0 +1,387 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id:
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Reader/Archive.php";
+
+/**
+ * Read an Ar archive
+ */
+class File_Archive_Reader_Ar extends File_Archive_Reader_Archive
+{
+ /**
+ * @var int The number of files to read to reach the end of the
+ * current ar file
+ *
+ * @access private
+ */
+ var $_nbBytesLeft = 0;
+
+ /**
+ * @var int The size of the header in number of bytes
+ * The header is not always 60 bytes since it sometimes
+ * contains a long filename
+ * @access private
+ */
+ var $_header = 0;
+
+ /**
+ * @var boolean Flag set if their is a 1 byte footer after the data
+ * of the current ar file
+ *
+ * @access private
+ */
+ var $_footer = false;
+
+ /**
+ * @var boolean Flag that has tell us if we have read the header of the
+ * current file
+ * @access private
+ */
+ var $_alreadyRead = false;
+
+ /**
+ * @var string Name of the file being read
+ * @access private
+ */
+ var $_currentFilename = null;
+
+ /**
+ * @var string Stat properties of the file being read
+ * It has: name, utime, uid, gid, mode, size and data
+ * @access private
+ */
+ var $_currentStat = null;
+
+ /**
+ * @see File_Archive_Reader::getFilename()
+ */
+ function getFilename()
+ {
+ return $this->_currentFilename;
+ }
+
+ /**
+ * @see File_Archive_Reader::close()
+ */
+ function close()
+ {
+ $this->_currentFilename = null;
+ $this->_currentStat = null;
+ $this->_nbBytesLeft = 0;
+ $this->_header = 0;
+ $this->_footer = false;
+ $this->_alreadyRead = false;
+ return parent::close();
+ }
+
+ /**
+ * @see File_Archive_Reader::getStat()
+ */
+ function getStat()
+ {
+ return $this->_currentStat;
+ }
+
+ /**
+ * @see File_Archive_Reader::next()
+ */
+ function next()
+ {
+ $error = parent::next();
+ if ($error !== true) {
+ return $error;
+ }
+
+ $this->source->skip(
+ $this->_nbBytesLeft + ($this->_footer ? 1 : 0)
+ );
+
+ $filename = $this->source->getDataFilename();
+
+ if (!$this->_alreadyRead) {
+ $header = $this->source->getData(8);
+ if ($header != "!\n") {
+ return PEAR::raiseError("File {$filename} is not a valid Ar file format (starts with $header)");
+ }
+ $this->_alreadyRead = true;
+ }
+
+
+ $name = $this->source->getData(16);
+ $mtime = $this->source->getData(12);
+ $uid = $this->source->getData(6);
+ $gid = $this->source->getData(6);
+ $mode = $this->source->getData(8);
+ $size = $this->source->getData(10);
+ $delim = $this->source->getData(2);
+
+ if ($delim === null) {
+ return false;
+ }
+
+ // All files inside should have more than 0 bytes of size
+ if ($size < 0) {
+ return PEAR::raiseError("Files must be at least one byte long");
+ }
+
+ $this->_footer = ($size % 2 == 1);
+
+ // if the filename starts with a length, then just read the bytes of it
+ if (preg_match("/\#1\/(\d+)/", $name, $matches)) {
+ $this->_header = 60 + $matches[1];
+ $name = $this->source->getData($matches[1]);
+ $size -= $matches[1];
+ } else {
+ // strip trailing spaces in name, so we can distinguish spaces in a filename with padding
+ $this->_header = 60;
+ $name = preg_replace ("/\s+$/", "", $name);
+ }
+
+ $this->_nbBytesLeft = $size;
+ if (empty($name) || empty($mtime) || empty($uid) ||
+ empty($gid) || empty($mode) || empty($size)) {
+ return PEAR::raiseError("An ar field is empty");
+ }
+
+ $this->_currentFilename = $this->getStandardURL($name);
+ $this->_currentStat = array(
+ 2 => $mode,
+ 'mode' => $mode,
+ 4 => $uid,
+ 'uid' => $uid,
+ 5 => $gid,
+ 'gid' => $gid,
+ 7 => $size,
+ 'size' => $size,
+ 9 => $mtime,
+ 'mtime' => $mtime
+ );
+
+ return true;
+ }
+
+ /**
+ * @see File_Archive_Reader::getData()
+ */
+ function getData($length = -1)
+ {
+ if ($length == -1) {
+ $length = $this->_nbBytesLeft;
+ } else {
+ $length = min($length, $this->_nbBytesLeft);
+ }
+ if ($length == 0) {
+ return null;
+ } else {
+ $this->_nbBytesLeft -= $length;
+ $data = $this->source->getData($length);
+ if (PEAR::isError($data)) {
+ return $data;
+ }
+ if (strlen($data) != $length) {
+ return PEAR::raiseError('Unexpected end of Ar archive');
+ }
+ return $data;
+ }
+ }
+
+ /**
+ * @see File_Archive_Reader::skip
+ */
+ function skip($length = -1)
+ {
+ if ($length == -1) {
+ $length = $this->_nbBytesLeft;
+ } else {
+ $length = min($length, $this->_nbBytesLeft);
+ }
+ if ($length == 0) {
+ return 0;
+ } else {
+ $this->_nbBytesLeft -= $length;
+ $skipped = $this->source->skip($length);
+ if (PEAR::isError($skipped)) {
+ return $skipped;
+ }
+ if ($skipped != $length) {
+ return PEAR::raiseError('Unexpected end of Ar archive');
+ }
+ return $skipped;
+ }
+ }
+
+ /**
+ * @see File_Archive_Reader::rewind
+ */
+ function rewind($length = -1)
+ {
+ if ($length == -1) {
+ $length = $this->_currentStat[7] - $this->_nbBytesLeft;
+ } else {
+ $length = min($length, $this->_currentStat[7] - $this->_nbBytesLeft);
+ }
+ if ($length == 0) {
+ return 0;
+ } else {
+ $rewinded = $this->source->rewind($length);
+ if (!PEAR::isError($rewinded)) {
+ $this->_nbBytesLeft += $rewinded;
+ }
+ return $rewinded;
+ }
+ }
+
+ /**
+ * @see File_Archive_Reader::tell()
+ */
+ function tell()
+ {
+ return $this->_currentStat[7] - $this->_nbBytesLeft;
+ }
+
+ /**
+ * @see File_Archive_Reader::makeWriterRemoveFiles()
+ */
+ function makeWriterRemoveFiles($pred)
+ {
+ require_once "File/Archive/Writer/Ar.php";
+
+ $blocks = array();
+ $seek = null;
+ $gap = 0;
+ if ($this->_currentFilename !== null && $pred->isTrue($this)) {
+ $seek = $this->_header + $this->_currentStat[7] + ($this->_footer ? 1 : 0);
+ $blocks[] = $seek; //Remove this file
+ }
+
+ while (($error = $this->next()) === true) {
+ $size = $this->_header + $this->_currentStat[7] + ($this->_footer ? 1 : 0);
+ if ($pred->isTrue($this)) {
+ if ($seek === null) {
+ $seek = $size;
+ $blocks[] = $size;
+ } else if ($gap > 0) {
+ $blocks[] = $gap; //Don't remove the files between the gap
+ $blocks[] = $size;
+ $seek += $size;
+ } else {
+ $blocks[count($blocks)-1] += $size; //Also remove this file
+ $seek += $size;
+ }
+ $gap = 0;
+ } else {
+ if ($seek !== null) {
+ $seek += $size;
+ $gap += $size;
+ }
+ }
+ }
+ if ($seek === null) {
+ $seek = 0;
+ } else {
+ if ($gap == 0) {
+ array_pop($blocks);
+ } else {
+ $blocks[] = $gap;
+ }
+ }
+
+ $writer = new File_Archive_Writer_Ar(null,
+ $this->source->makeWriterRemoveBlocks($blocks, -$seek)
+ );
+ $this->close();
+ return $writer;
+ }
+
+ /**
+ * @see File_Archive_Reader::makeWriterRemoveBlocks()
+ */
+ function makeWriterRemoveBlocks($blocks, $seek = 0)
+ {
+ if ($this->_currentStat === null) {
+ return PEAR::raiseError('No file selected');
+ }
+
+ $blockPos = $this->_currentStat[7] - $this->_nbBytesLeft + $seek;
+
+ $this->rewind();
+ $keep = false;
+
+ $data = $this->getData($blockPos);
+ foreach ($blocks as $length) {
+ if ($keep) {
+ $data .= $this->getData($length);
+ } else {
+ $this->skip($length);
+ }
+ $keep = !$keep;
+ }
+ if ($keep) {
+ $data .= $this->getData();
+ }
+
+ $filename = $this->_currentFilename;
+ $stat = $this->_currentStat;
+
+ $writer = $this->makeWriterRemove();
+ if (PEAR::isError($writer)) {
+ return $writer;
+ }
+
+ unset($stat[7]);
+ $writer->newFile($filename, $stat);
+ $writer->writeData($data);
+ return $writer;
+ }
+
+ /**
+ * @see File_Archive_Reader::makeAppendWriter
+ */
+ function makeAppendWriter()
+ {
+ require_once "File/Archive/Writer/Ar.php";
+
+ while (($error = $this->next()) === true) { }
+ if (PEAR::isError($error)) {
+ $this->close();
+ return $error;
+ }
+
+ $innerWriter = $this->source->makeWriterRemoveBlocks(array());
+ if (PEAR::isError($innerWriter)) {
+ return $innerWriter;
+ }
+
+ unset($this->source);
+ $this->close();
+
+ return new File_Archive_Writer_Ar(null, $innerWriter);
+ }
+}
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Reader/Archive.php b/thirdparty/pear/File/Archive/Reader/Archive.php
new file mode 100644
index 0000000..2a9004f
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Reader/Archive.php
@@ -0,0 +1,98 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Archive.php,v 1.12 2005/05/23 19:25:24 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Reader.php";
+
+/**
+ * Base class for all the archive readers (that read from a single file)
+ */
+class File_Archive_Reader_Archive extends File_Archive_Reader
+{
+ /**
+ * @var File_Archive_Reader Single file source that contains the archive
+ * to uncompress
+ * @access protected
+ */
+ var $source = null;
+
+ /**
+ * @var bool Indicate whether the $source is currently opened
+ * @access private
+ */
+ var $sourceOpened = false;
+
+ /**
+ * The source was let in this state at the end
+ *
+ * @var bool Indicate whether the $source was given opened
+ * @access private
+ */
+ var $sourceInitiallyOpened;
+
+//ABSTRACT
+ /**
+ * @see File_Archive_Reader::next()
+ *
+ * Open the source if necessary
+ */
+ function next()
+ {
+ if (!$this->sourceOpened && ($error = $this->source->next()) !== true) {
+ return $error;
+ }
+
+ $this->sourceOpened = true;
+ return true;
+ }
+
+//PUBLIC
+ function File_Archive_Reader_Archive(&$source, $sourceOpened = false)
+ {
+ $this->source =& $source;
+ $this->sourceOpened = $this->sourceInitiallyOpened = $sourceOpened;
+ }
+ /**
+ * Close the source if it was given closed in the constructor
+ *
+ * @see File_Archive_Reader::close()
+ */
+ function close()
+ {
+ if (!$this->sourceInitiallyOpened && $this->sourceOpened) {
+ $this->sourceOpened = false;
+ if ($this->source !== null) {
+ return $this->source->close();
+ }
+ }
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Reader/Bzip2.php b/thirdparty/pear/File/Archive/Reader/Bzip2.php
new file mode 100644
index 0000000..495b1f5
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Reader/Bzip2.php
@@ -0,0 +1,254 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Bzip2.php,v 1.19 2005/07/26 09:06:03 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Reader/Archive.php";
+require_once "File/Archive/Writer/Files.php";
+
+/**
+ * Uncompress a file that was compressed in the Bzip2 format
+ */
+class File_Archive_Reader_Bzip2 extends File_Archive_Reader_Archive
+{
+ var $nbRead = 0;
+ var $bzfile = null;
+ var $tmpName = null;
+ var $filePos = 0;
+
+ /**
+ * @see File_Archive_Reader::close()
+ */
+ function close($innerClose = true)
+ {
+ if ($this->bzfile !== null)
+ bzclose($this->bzfile);
+ if ($this->tmpName !== null)
+ unlink($this->tmpName);
+
+ $this->bzfile = null;
+ $this->tmpName = null;
+ $this->nbRead = 0;
+ $this->filePos = 0;
+ return parent::close($innerClose);
+ }
+
+ /**
+ * @see File_Archive_Reader::next()
+ */
+ function next()
+ {
+ if (!parent::next()) {
+ return false;
+ }
+
+ $this->nbRead++;
+ if ($this->nbRead > 1) {
+ return false;
+ }
+
+ $dataFilename = $this->source->getDataFilename();
+ if ($dataFilename !== null)
+ {
+ $this->tmpName = null;
+ $this->bzfile = @bzopen($dataFilename, 'r');
+ if ($this->bzfile === false) {
+ return PEAR::raiseError("bzopen failed to open $dataFilename");
+ }
+ } else {
+ $this->tmpName = tempnam(File_Archive::getOption('tmpDirectory'), 'far');
+
+ //Generate the tmp data
+ $dest = new File_Archive_Writer_Files();
+ $dest->newFile($this->tmpName);
+ $this->source->sendData($dest);
+ $dest->close();
+
+ $this->bzfile = bzopen($this->tmpName, 'r');
+ }
+
+ return true;
+ }
+ /**
+ * Return the name of the single file contained in the archive
+ * deduced from the name of the archive (the extension is removed)
+ *
+ * @see File_Archive_Reader::getFilename()
+ */
+ function getFilename()
+ {
+ $name = $this->source->getFilename();
+ $pos = strrpos($name, ".");
+ if ($pos === false || $pos === 0) {
+ return $name;
+ } else {
+ return substr($name, 0, $pos);
+ }
+ }
+ /**
+ * @see File_Archive_Reader::getData()
+ */
+ function getData($length = -1)
+ {
+ if ($length == -1) {
+ $data = '';
+ do {
+ $newData = bzread($this->bzfile);
+ $data .= $newData;
+ } while ($newData != '');
+ $this->filePos += strlen($data);
+ } else if ($length == 0) {
+ return '';
+ } else {
+ $data = '';
+
+ //The loop is here to correct what appears to be a bzread bug
+ while (strlen($data) < $length) {
+ $newData = bzread($this->bzfile, $length - strlen($data));
+ if ($newData == '') {
+ break;
+ }
+ $data .= $newData;
+ }
+ $this->filePos += strlen($data);
+ }
+
+ return $data == '' ? null : $data;
+ }
+
+ /**
+ * @see File_Archive_Reader::rewind
+ */
+ function rewind($length = -1)
+ {
+ $before = $this->filePos;
+
+ bzclose($this->bzfile);
+ if ($this->tmpName === null) {
+ $this->bzfile = bzopen($this->source->getDataFilename(), 'r');
+ } else {
+ $this->bzfile = bzopen($this->tmpName, 'r');
+ }
+ $this->filePos = 0;
+
+ if ($length != -1) {
+ $this->skip($before - $length);
+ }
+ return $before - $this->filePos;
+ }
+
+ /**
+ * @see File_Archive_Reader::tell()
+ */
+ function tell()
+ {
+ return $this->filePos;
+ }
+
+ /**
+ * @see File_Archive_Reader::makeAppendWriter()
+ */
+ function makeAppendWriter()
+ {
+ return PEAR::raiseError('Unable to append files to a bzip2 archive');
+ }
+
+ /**
+ * @see File_Archive_Reader::makeWriterRemoveFiles()
+ */
+ function makeWriterRemoveFiles($pred)
+ {
+ return PEAR::raiseError('Unable to remove files from a bzip2 archive');
+ }
+
+ /**
+ * @see File_Archive_Reader::makeWriterRemoveBlocks()
+ */
+ function makeWriterRemoveBlocks($blocks, $seek = 0)
+ {
+ require_once "File/Archive/Writer/Bzip2.php";
+
+ if ($this->nbRead == 0) {
+ return PEAR::raiseError('No file selected');
+ }
+
+ //Uncompress data to a temporary file
+ $tmp = tmpfile();
+ $expectedPos = $this->filePos + $seek;
+
+ $this->rewind();
+
+ //Read the begining of the file
+ while ($this->filePos < $expectedPos &&
+ ($data = $this->getData(min($expectedPos - $this->filePos, 8192))) !== null) {
+ fwrite($tmp, $data);
+ }
+
+ $keep = false;
+ foreach ($blocks as $length) {
+ if ($keep) {
+ $expectedPos = $this->filePos + $length;
+ while ($this->filePos < $expectedPos &&
+ ($data = $this->getData(min($expectedPos - $this->filePos, 8192))) !== null) {
+ fwrite($tmp, $data);
+ }
+ } else {
+ $this->skip($length);
+ }
+ $keep = !$keep;
+ }
+ if ($keep) {
+ //Read the end of the file
+ while(($data = $this->getData(8192)) !== null) {
+ fwrite($tmp, $data);
+ }
+ }
+ fseek($tmp, 0);
+
+ //Create the writer
+ $this->source->rewind();
+ $innerWriter = $this->source->makeWriterRemoveBlocks(array()); //Truncate the source
+ unset($this->source);
+ $writer = new File_Archive_Writer_Bzip2(null, $innerWriter);
+
+ //And compress data from the temporary file
+ while (!feof($tmp)) {
+ $data = fread($tmp, 8192);
+ $writer->writeData($data);
+ }
+ fclose($tmp);
+
+ //Do not close inner writer since makeWriter was called
+ $this->close();
+
+ return $writer;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Reader/Cache.php b/thirdparty/pear/File/Archive/Reader/Cache.php
new file mode 100644
index 0000000..f352b68
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Reader/Cache.php
@@ -0,0 +1,262 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Cache.php,v 1.1 2005/07/07 12:24:58 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Reader.php";
+
+/**
+ * This reader caches the files of another reader
+ * It allow fast access to files. This is usefull if the access to the reader
+ * is slow (HTTP, FTP...), but will need more IO if the file is only extracted
+ */
+class File_Archive_Reader_Cache extends File_Archive_Reader
+{
+ var $tmpFile;
+ var $files = array();
+ var $pos = 0;
+ var $fromSource = true;
+ var $endOfSource = false;
+ var $source;
+
+ /**
+ * $source is the reader to filter
+ */
+ function File_Archive_Reader_Cache(&$source)
+ {
+ $this->source =& $source;
+ $this->tmpFile = tmpfile();
+ }
+
+ function _writeEndOfFile()
+ {
+ $bufferSize = File_Archive::getOption('blockSize');
+ while (($data = $this->source->getData($bufferSize))!=null) {
+ fwrite($this->tmpFile, $data);
+ }
+ }
+ /**
+ * @see File_Archive_Reader::next()
+ */
+ function next()
+ {
+ //Write the end of the current file to the temp file
+ if ($this->fromSource && !empty($this->files)) {
+ $this->_writeEndOfFile();
+ }
+
+ if ($this->pos+1 < count($this->files) && !$this->fromSource) {
+ $this->pos++;
+ fseek($this->tmpFile, $this->files[$this->pos]['pos'], SEEK_SET);
+ return true;
+ } else {
+ $this->fromSource = true;
+ if ($this->endOfSource) {
+ return false;
+ }
+
+ $ret = $this->source->next();
+ if ($ret !== true) {
+ $this->endOfSource = true;
+ $this->source->close();
+ return $ret;
+ }
+
+ $this->endOfSource = false;
+ fseek($this->tmpFile, 0, SEEK_END);
+ $this->files[] = array(
+ 'name' => $this->source->getFilename(),
+ 'stat' => $this->source->getStat(),
+ 'mime' => $this->source->getMime(),
+ 'pos' => ftell($this->tmpFile)
+ );
+ $this->pos = count($this->files)-1;
+
+ return true;
+ }
+ }
+
+ /**
+ * @see File_Archive_Reader::getFilename()
+ */
+ function getFilename() { return $this->files[$this->pos]['name']; }
+ /**
+ * @see File_Archive_Reader::getStat()
+ */
+ function getStat() { return $this->files[$this->pos]['stat']; }
+ /**
+ * @see File_Archive_Reader::getMime()
+ */
+ function getMime() { return $this->files[$this->pos]['mime']; }
+ /**
+ * @see File_Archive_Reader::getDataFilename()
+ */
+ function getDataFilename() { return null; }
+ /**
+ * @see File_Archive_Reader::getData()
+ */
+ function getData($length = -1)
+ {
+ if ($this->fromSource) {
+ $data = $this->source->getData($length);
+ if (PEAR::isError($data)) {
+ return $data;
+ }
+
+ fwrite($this->tmpFile, $data);
+ return $data;
+ } else {
+ if ($length == 0) {
+ return '';
+ }
+
+ if ($length > 0 && $this->pos+1 < count($this->files)) {
+ $maxSize = $this->files[$this->pos+1]['pos'] - ftell($this->tmpFile);
+ if ($maxSize == 0) {
+ return null;
+ }
+ if ($length > $maxSize) {
+ $length = $maxSize;
+ }
+ return fread($this->tmpFile, $length);
+ } else {
+ $contents = '';
+ $blockSize = File_Archive::getOption('blockSize');
+ while (!feof($this->tmpFile)) {
+ $contents .= fread($this->tmpFile, $blockSize);
+ }
+ return $contents == '' ? null : $contents;
+ }
+ }
+ }
+ /**
+ * @see File_Archive_Reader::skip()
+ */
+ function skip($length = -1)
+ {
+ if ($this->fromSource) {
+ return strlen($this->getData($length));
+ } else {
+ if ($length >= 0 && $this->pos+1 < count($this->files)) {
+ $maxSize = $this->files[$this->pos+1]['pos'] - ftell($this->tmpFile);
+ if ($maxSize == 0) {
+ return null;
+ }
+ if ($length > $maxSize) {
+ $length = $maxSize;
+ }
+ fseek($this->tmpFile, $length, SEEK_CUR);
+ return $length;
+ } else {
+ $before = ftell($this->tmpFile);
+ fseek($this->tmpFile, 0, SEEK_SET);
+ $after = fteel($this->tmpFile);
+ return $after - $before;
+ }
+ }
+ }
+ /**
+ * @see File_Archive_Reader::rewind()
+ */
+ function rewind($length = -1)
+ {
+ if ($this->fromSource) {
+ $this->_writeEndOfFile();
+ $this->fromSource = false;
+ }
+ $before = ftell($this->tmpFile);
+ $pos = $this->files[$this->pos]['pos'];
+ fseek($this->tmpFile, $pos, SEEK_SET);
+ return $pos - $before;
+ }
+ /**
+ * @see File_Archive_Reader::tell()
+ */
+ function tell()
+ {
+ return ftell($this->tmpFile) - $this->files[$this->pos]['pos'];
+ }
+ /**
+ * @see File_Archive_Reader::close()
+ */
+ function close()
+ {
+ $this->fromSource = false;
+ $this->pos = 0;
+ fseek($this->tmpFile, 0, SEEK_SET);
+ }
+ function _closeAndReset()
+ {
+ $this->close();
+
+ fclose($this->tmpFile);
+ $this->tmpFile = tmpfile();
+ $this->endOfSource = false;
+ $this->files = array();
+ $this->source->close();
+ }
+ /**
+ * @see File_Archive_Reader::makeAppendWriter()
+ */
+ function makeAppendWriter()
+ {
+ $writer = $this->source->makeAppendWriter();
+ if (!PEAR::isError($writer)) {
+ $this->_closeAndReset();
+ }
+
+ return $writer;
+ }
+ /**
+ * @see File_Archive_Reader::makeWriterRemoveFiles()
+ */
+ function makeWriterRemoveFiles($pred)
+ {
+ $writer = $this->source->makeWriterRemoveFiles($pred);
+ if (!PEAR::isError($writer)) {
+ $this->_closeAndReset();
+ }
+ return $writer;
+ }
+ /**
+ * @see File_Archive_Reader::makeWriterRemoveBlocks()
+ */
+ function makeWriterRemoveBlocks($blocks, $seek = 0)
+ {
+ $writer = $this->source->makeWriterRemoveBlocks($blocks, $seek);
+ if (!PEAR::isError($writer)) {
+ $this->_closeAndReset();
+ }
+ return $writer;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Reader/ChangeName.php b/thirdparty/pear/File/Archive/Reader/ChangeName.php
new file mode 100644
index 0000000..595b481
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Reader/ChangeName.php
@@ -0,0 +1,212 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: ChangeName.php,v 1.19 2005/07/09 12:54:35 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Reader/Relay.php";
+
+/**
+ * Add a directory to the public name of all the files of a reader
+ *
+ * Example:
+ * If archive.tar is a file archive containing files a.txt and foo/b.txt
+ * new File_Archive_Reader_AddBaseName('bar',
+ * new File_Archive_Reader_Tar(
+ * new File_Archive_Reader_File('archive.tar')
+ * )
+ * ) is a reader containing files bar/a.txt and bar/foo/b.txt
+ */
+class File_Archive_Reader_AddBaseName extends File_Archive_Reader_Relay
+{
+ var $baseName;
+ function File_Archive_Reader_AddBaseName($baseName, &$source)
+ {
+ parent::File_Archive_Reader_Relay($source);
+ $this->baseName = $this->getStandardURL($baseName);
+ }
+
+ /**
+ * Modify the name by adding baseName to it
+ */
+ function modifyName($name)
+ {
+ return $this->baseName.
+ (empty($this->baseName) || empty($name) ? '': '/').
+ $name;
+ }
+
+ /**
+ * Remove baseName from the name
+ * Return false if the name doesn't start with baseName
+ */
+ function unmodifyName($name)
+ {
+ if (strncmp($name, $this->baseName.'/', strlen($this->baseName)+1) == 0) {
+ $res = substr($name, strlen($this->baseName)+1);
+ if ($res === false) {
+ return '';
+ } else {
+ return $res;
+ }
+ } else if (empty($this->baseName)) {
+ return $name;
+ } else if ($name == $this->baseName) {
+ return '';
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @see File_Archive_Reader::getFilename()
+ */
+ function getFilename()
+ {
+ return $this->modifyName(parent::getFilename());
+ }
+ /**
+ * @see File_Archive_Reader::getFileList()
+ */
+ function getFileList()
+ {
+ $list = parent::getFileList();
+ $result = array();
+ foreach ($list as $name) {
+ $result[] = $this->modifyName($name);
+ }
+ return $result;
+ }
+ /**
+ * @see File_Archive_Reader::select()
+ */
+ function select($filename, $close = true)
+ {
+ $name = $this->unmodifyName($filename);
+ if ($name === false) {
+ return false;
+ } else {
+ return $this->source->select($name, $close);
+ }
+ }
+}
+
+/**
+ * Change a directory name to another
+ *
+ * Example:
+ * If archive.tar is a file archive containing files a.txt and foo/b.txt
+ * new File_Archive_Reader_ChangeBaseName('foo', 'bar'
+ * new File_Archive_Reader_Tar(
+ * new File_Archive_Reader_File('archive.tar')
+ * )
+ * ) is a reader containing files a.txt and bar/b.txt
+ */
+class File_Archive_Reader_ChangeBaseName extends File_Archive_Reader_Relay
+{
+ var $oldBaseName;
+ var $newBaseName;
+
+ function File_Archive_Reader_ChangeBaseName
+ ($oldBaseName, $newBaseName, &$source)
+ {
+ parent::File_Archive_Reader_Relay($source);
+ $this->oldBaseName = $this->getStandardURL($oldBaseName);
+ if (substr($this->oldBaseName, -1) == '/') {
+ $this->oldBaseName = substr($this->oldBaseName, 0, -1);
+ }
+
+ $this->newBaseName = $this->getStandardURL($newBaseName);
+ if (substr($this->newBaseName, -1) == '/') {
+ $this->newBaseName = substr($this->newBaseName, 0, -1);
+ }
+ }
+
+ function modifyName($name)
+ {
+ if (empty($this->oldBaseName) ||
+ !strncmp($name, $this->oldBaseName.'/', strlen($this->oldBaseName)+1) ||
+ strcmp($name, $this->oldBaseName) == 0) {
+ return $this->newBaseName.
+ (
+ empty($this->newBaseName) ||
+ strlen($name)<=strlen($this->oldBaseName)+1 ?
+ '' : '/'
+ ).
+ substr($name, strlen($this->oldBaseName)+1);
+ } else {
+ return $name;
+ }
+ }
+ function unmodifyName($name)
+ {
+ if (empty($this->newBaseName) ||
+ !strncmp($name, $this->newBaseName.'/', strlen($this->newBaseName)+1) ||
+ strcmp($name, $this->newBaseName) == 0) {
+ return $this->oldBaseName.
+ (
+ empty($this->oldBaseName) ||
+ strlen($name)<=strlen($this->newBaseName)+1 ?
+ '' : '/'
+ ).
+ substr($name, strlen($this->newBaseName)+1);
+ } else {
+ return $name;
+ }
+ }
+
+ /**
+ * @see File_Archive_Reader::getFilename()
+ */
+ function getFilename()
+ {
+ return $this->modifyName(parent::getFilename());
+ }
+ /**
+ * @see File_Archive_Reader::getFileList()
+ */
+ function getFileList()
+ {
+ $list = parent::getFileList();
+ $result = array();
+ foreach ($list as $name) {
+ $result[] = $this->modifyName($name);
+ }
+ return $result;
+ }
+ /**
+ * @see File_Archive_Reader::select()
+ */
+ function select($filename, $close = true)
+ {
+ return $this->source->select($this->unmodifyName($filename));
+ }
+
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Reader/Concat.php b/thirdparty/pear/File/Archive/Reader/Concat.php
new file mode 100644
index 0000000..3885554
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Reader/Concat.php
@@ -0,0 +1,187 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Concat.php,v 1.17 2005/07/07 15:48:28 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Reader/Relay.php";
+
+/**
+ * This reader provides one single file that is the concatenation of the data of
+ * all the files of another reader
+ */
+class File_Archive_Reader_Concat extends File_Archive_Reader
+{
+ var $source;
+ var $filename;
+ var $stat;
+ var $mime;
+ var $opened = false;
+ var $filePos = 0;
+
+ function File_Archive_Reader_Concat(&$source, $filename,
+ $stat=array(), $mime=null)
+ {
+ $this->source =& $source;
+ $this->filename = $filename;
+ $this->stat = $stat;
+ $this->mime = $mime;
+
+ //Compute the total length
+ $this->stat[7] = 0;
+ while (($error = $source->next()) === true) {
+ $sourceStat = $source->getStat();
+ if (isset($sourceStat[7])) {
+ $this->stat[7] += $sourceStat[7];
+ } else {
+ unset($this->stat[7]);
+ break;
+ }
+ }
+ if (isset($this->stat[7])) {
+ $this->stat['size'] = $this->stat[7];
+ }
+ if (PEAR::isError($error) || PEAR::isError($source->close())) {
+ die("Error in File_Archive_Reader_Concat constructor ".
+ '('.$error->getMessage().'), cannot continue');
+ }
+ }
+
+ /**
+ * @see File_Archive_Reader::next()
+ */
+ function next()
+ {
+ if (!$this->opened) {
+ return $this->opened = $this->source->next();
+ } else {
+ return false;
+ }
+ }
+ /**
+ * @see File_Archive_Reader::getFilename()
+ */
+ function getFilename() { return $this->filename; }
+ /**
+ * @see File_Archive_Reader::getStat()
+ */
+ function getStat() { return $this->stat; }
+ /**
+ * @see File_Archive_Reader::getMime()
+ */
+ function getMime()
+ {
+ return $this->mime==null ? parent::getMime() : $this->mime;
+ }
+ /**
+ * @see File_Archive_Reader::getData()
+ */
+ function getData($length = -1)
+ {
+ if ($length == 0) {
+ return '';
+ }
+
+ $result = '';
+ while ($length == -1 || strlen($result)<$length) {
+ $sourceData = $this->source->getData(
+ $length==-1 ? -1 : $length - strlen($result)
+ );
+
+ if (PEAR::isError($sourceData)) {
+ return $sourceData;
+ }
+
+ if ($sourceData === null) {
+ $error = $this->source->next();
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+ if (!$error) {
+ break;
+ }
+ } else {
+ $result .= $sourceData;
+ }
+ }
+ $this->filePos += strlen($result);
+ return $result == '' ? null : $result;
+ }
+ /**
+ * @see File_Archive_Reader::skip()
+ */
+ function skip($length = -1)
+ {
+ $skipped = 0;
+ while ($skipped < $length) {
+ $sourceSkipped = $this->source->skip($length);
+ if (PEAR::isError($sourceSkipped)) {
+ return $skipped;
+ }
+ $skipped += $sourceSkipped;
+ $filePos += $sourceSkipped;
+ }
+ return $skipped;
+ }
+ /**
+ * @see File_Archive_Reader::rewind()
+ */
+ function rewind($length = -1)
+ {
+ //TODO: implement rewind
+ return parent::rewind($length);
+ }
+
+ /**
+ * @see File_Archive_Reader::tell()
+ */
+ function tell()
+ {
+ return $this->filePos;
+ }
+
+ /**
+ * @see File_Archive_Reader::close()
+ */
+ function close()
+ {
+ $this->opened = false;
+ $this->filePos = 0;
+ return $this->source->close();
+ }
+
+ /**
+ * @see File_Archive_Reader::makeWriter
+ */
+ function makeWriter($fileModif = true, $seek = 0)
+ {
+ return $this->source->makeWriter($fileModif, $seek);
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Reader/Directory.php b/thirdparty/pear/File/Archive/Reader/Directory.php
new file mode 100644
index 0000000..d1da2fa
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Reader/Directory.php
@@ -0,0 +1,220 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Directory.php,v 1.21 2005/07/07 12:24:58 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Reader/Relay.php";
+require_once "File/Archive/Reader/File.php";
+
+/**
+ * Recursively reads a directory
+ */
+class File_Archive_Reader_Directory extends File_Archive_Reader_Relay
+{
+ /**
+ * @var String URL of the directory that must be read
+ * @access private
+ */
+ var $directory;
+ /**
+ * @var Int The subdirectories will be read up to a depth of maxRecurs
+ * If maxRecurs == 0, the subdirectories will not be read
+ * If maxRecurs == -1, the depth is considered infinite
+ * @access private
+ */
+ var $maxRecurs;
+ /**
+ * @var Object Handle returned by the openedDirectory function
+ * @access private
+ */
+ var $directoryHandle = null;
+
+ /**
+ * $directory is the path of the directory that must be read
+ * If $maxRecurs is specified, the subdirectories will be read up to a depth
+ * of $maxRecurs. In particular, if $maxRecurs == 0, the subdirectories
+ * won't be read.
+ */
+ function File_Archive_Reader_Directory($directory, $symbolic='',
+ $maxRecurs=-1)
+ {
+ parent::File_Archive_Reader_Relay($tmp = null);
+ $this->directory = empty($directory) ? '.' : $directory;
+ $this->symbolic = $this->getStandardURL($symbolic);
+ $this->maxRecurs = $maxRecurs;
+ }
+
+ /**
+ * @see File_Archive_Reader::close()
+ */
+ function close()
+ {
+ $error = parent::close();
+
+ if ($this->directoryHandle !== null) {
+ closedir($this->directoryHandle);
+ $this->directoryHandle = null;
+ }
+
+ return $error;
+ }
+
+ /**
+ * @see File_Archive_Reader::next()
+ *
+ * The files are returned in the same order as readdir
+ */
+ function next()
+ {
+ if ($this->directoryHandle === null) {
+ $this->directoryHandle = opendir($this->directory);
+ if (!is_resource($this->directoryHandle)) {
+ return PEAR::raiseError(
+ "Directory {$this->directory} not found"
+ );
+ }
+ }
+
+ while ($this->source === null ||
+ ($error = $this->source->next()) !== true) {
+
+ if ($this->source !== null) {
+ $this->source->close();
+ }
+
+ $file = readdir($this->directoryHandle);
+ if ($file == '.' || $file == '..') {
+ continue;
+ }
+ if ($file === false) {
+ return false;
+ }
+
+ $current = $this->directory.'/'.$file;
+ if (is_dir($current)) {
+ if ($this->maxRecurs != 0) {
+ $this->source = new File_Archive_Reader_Directory(
+ $current, $file.'/', $this->maxRecurs-1
+ );
+ }
+ } else {
+ $this->source = new File_Archive_Reader_File($current, $file);
+ }
+ }
+
+ return $error;
+ }
+
+ /**
+ * @see File_Archive_Reader::getFilename()
+ */
+ function getFilename() { return $this->symbolic . parent::getFilename(); }
+
+ /**
+ * @see File_Archive_Reader::makeWriterRemoveFiles()
+ */
+ function makeWriterRemoveFiles($pred)
+ {
+ if ($source !== null && $pred->isTrue($this)) {
+ $toUnlink = $this->getDataFilename();
+ } else {
+ $toUnlink = null;
+ }
+
+ while ($this->next()) {
+ if ($toUnlink !== null &&
+ !@unlink($toUnlink)) {
+ return PEAR::raiseError("Unable to unlink $toUnlink");
+ }
+ $toUnlink = ($pred->isTrue($this) ? $this->getDataFilename() : null);
+ }
+ if ($toUnlink !== null &&
+ !@unlink("Unable to unlink $toUnlink")) {
+ return PEAR::raiseError($pred);
+ }
+
+ require_once "File/Archive/Writer/Files.php";
+
+ $writer = new File_Archive_Writer_Files($this->directory);
+ $this->close();
+ return $writer;
+ }
+
+ function &getLastSource()
+ {
+ if ($this->source === null ||
+ is_a($this->source, 'File_Archive_Reader_File')) {
+ return $this->source;
+ } else {
+ return $this->source->getLastSource();
+ }
+ }
+
+ /**
+ * @see File_Archive_Reader::makeWriterRemoveBlocks()
+ */
+ function makeWriterRemoveBlocks($blocks, $seek = 0)
+ {
+ $lastSource = &$this->getLastSource();
+ if ($lastSource === null) {
+ return PEAR::raiseError('No file selected');
+ }
+
+ require_once "File/Archive/Writer/Files.php";
+
+ $writer = $lastSource->makeWriterRemoveBlocks($blocks, $seek);
+ if (!PEAR::isError($writer)) {
+ $writer->basePath = $this->directory;
+ $this->close();
+ }
+
+ return $writer;
+ }
+
+ /**
+ * @see File_Archive_Reader::makeAppendWriter
+ */
+ function makeAppendWriter()
+ {
+ require_once "File/Archive/Writer/Files.php";
+
+ if ($this->source === null ||
+ is_a($this->source, 'File_Archive_Reader_File') ) {
+ $writer = new File_Archive_Writer_Files($this->directory);
+ } else {
+ $writer = $this->source->makeAppendWriter($seek);
+ }
+
+ $this->close();
+
+ return $writer;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Reader/File.php b/thirdparty/pear/File/Archive/Reader/File.php
new file mode 100644
index 0000000..81412d2
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Reader/File.php
@@ -0,0 +1,296 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: File.php,v 1.30 2005/07/11 11:53:53 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Reader.php";
+require_once "MIME/Type.php";
+
+/**
+ * Reader that represents a single file
+ */
+class File_Archive_Reader_File extends File_Archive_Reader
+{
+ /**
+ * @var object Handle to the file being read
+ * @access private
+ */
+ var $handle = null;
+ /**
+ * @var string Name of the physical file being read
+ * @access private
+ */
+ var $filename;
+ /**
+ * @var string Name of the file returned by the reader
+ * @access private
+ */
+ var $symbolic;
+ /**
+ * @var array Stats of the file
+ * Will only be set after a call to $this->getStat()
+ * @access private
+ */
+ var $stat = null;
+ /**
+ * @var string Mime type of the file
+ * Will only be set after a call to $this->getMime()
+ */
+ var $mime = null;
+ /**
+ * @var boolean Has the file already been read
+ * @access private
+ */
+ var $alreadyRead = false;
+
+ /**
+ * $filename is the physical file to read
+ * $symbolic is the name declared by the reader
+ * If $symbolic is not specified, $filename is assumed
+ */
+ function File_Archive_Reader_File($filename, $symbolic = null, $mime = null)
+ {
+ $this->filename = $filename;
+ $this->mime = $mime;
+ if ($symbolic === null) {
+ $this->symbolic = $this->getStandardURL($filename);
+ } else {
+ $this->symbolic = $this->getStandardURL($symbolic);
+ }
+ }
+ /**
+ * @see File_Archive_Reader::close()
+ *
+ * Close the file handle
+ */
+ function close()
+ {
+ $this->alreadyRead = false;
+ if ($this->handle !== null) {
+ fclose($this->handle);
+ $this->handle = null;
+ }
+ }
+ /**
+ * @see File_Archive_Reader::next()
+ *
+ * The first time next is called, it will open the file handle and return
+ * true. Then it will return false
+ * Raise an error if the file does not exist
+ */
+ function next()
+ {
+ if ($this->alreadyRead) {
+ return false;
+ } else {
+ $this->alreadyRead = true;
+ return true;
+ }
+ }
+ /**
+ * @see File_Archive_Reader::getFilename()
+ */
+ function getFilename() { return $this->symbolic; }
+ /**
+ * @see File_Archive_Reader::getDataFilename()
+ *
+ * Return the name of the file
+ */
+ function getDataFilename() { return $this->filename; }
+ /**
+ * @see File_Archive_Reader::getStat() stat()
+ */
+ function getStat()
+ {
+ if ($this->stat === null) {
+ $this->stat = @stat($this->filename);
+
+ //If we can't use the stat function
+ if ($this->stat === false) {
+ $this->stat = array();
+ }
+ }
+ return $this->stat;
+ }
+
+ /**
+ * @see File_Archive_Reader::getMime
+ */
+ function getMime()
+ {
+ if ($this->mime === null) {
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ $this->mime = MIME_Type::autoDetect($this->getDataFilename());
+ PEAR::popErrorHandling();
+
+ if (PEAR::isError($this->mime)) {
+ $this->mime = parent::getMime();
+ }
+ }
+ return $this->mime;
+ }
+
+ /**
+ * Opens the file if it was not already opened
+ */
+ function _ensureFileOpened()
+ {
+ if ($this->handle === null) {
+ $this->handle = @fopen($this->filename, "r");
+
+ if (!is_resource($this->handle)) {
+ $this->handle = null;
+ return PEAR::raiseError("Can't open {$this->filename} for reading");
+ }
+ if ($this->handle === false) {
+ $this->handle = null;
+ return PEAR::raiseError("File {$this->filename} not found");
+ }
+ }
+ }
+
+ /**
+ * @see File_Archive_Reader::getData()
+ */
+ function getData($length = -1)
+ {
+ $error = $this->_ensureFileOpened();
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+
+ if (feof($this->handle)) {
+ return null;
+ }
+ if ($length == -1) {
+ $contents = '';
+ $blockSize = File_Archive::getOption('blockSize');
+ while (!feof($this->handle)) {
+ $contents .= fread($this->handle, $blockSize);
+ }
+ return $contents;
+ } else {
+ if ($length == 0) {
+ return "";
+ } else {
+ return fread($this->handle, $length);
+ }
+ }
+ }
+
+ /**
+ * @see File_Archive_Reader::skip()
+ */
+ function skip($length = -1)
+ {
+ $error = $this->_ensureFileOpened();
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+
+ $before = ftell($this->handle);
+ if (($length == -1 && @fseek($this->handle, 0, SEEK_END) === -1) ||
+ ($length >= 0 && @fseek($this->handle, $length, SEEK_CUR) === -1)) {
+ return parent::skip($length);
+ } else {
+ return ftell($this->handle) - $before;
+ }
+ }
+
+ /**
+ * @see File_Archive_Reader::rewind
+ */
+ function rewind($length = -1)
+ {
+ if ($this->handle === null) {
+ return 0;
+ }
+
+ $before = ftell($this->handle);
+ if (($length == -1 && @fseek($this->handle, 0, SEEK_SET) === -1) ||
+ ($length >= 0 && @fseek($this->handle, -$length, SEEK_CUR) === -1)) {
+ return parent::rewind($length);
+ } else {
+ return $before - ftell($this->handle);
+ }
+ }
+
+ /**
+ * @see File_Archive_Reader::tell()
+ */
+ function tell()
+ {
+ if ($this->handle === null) {
+ return 0;
+ } else {
+ return ftell($this->handle);
+ }
+ }
+
+
+ /**
+ * @see File_Archive_Reader::makeWriterRemoveFiles()
+ */
+ function makeWriterRemoveFiles($pred)
+ {
+ return PEAR::raiseError(
+ 'File_Archive_Reader_File represents a single file, you cant remove it');
+ }
+
+ /**
+ * @see File_Archive_Reader::makeWriterRemoveBlocks()
+ */
+ function makeWriterRemoveBlocks($blocks, $seek = 0)
+ {
+ require_once "File/Archive/Writer/Files.php";
+
+ $writer = new File_Archive_Writer_Files();
+
+ $file = $this->getDataFilename();
+ $pos = $this->tell();
+ $this->close();
+
+ $writer->openFileRemoveBlock($file, $pos + $seek, $blocks);
+
+ return $writer;
+ }
+
+ /**
+ * @see File_Archive_Reader::makeAppendWriter
+ */
+ function makeAppendWriter()
+ {
+ return PEAR::raiseError(
+ 'File_Archive_Reader_File represents a single file.'.
+ ' makeAppendWriter cant be executed on it'
+ );
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Reader/Filter.php b/thirdparty/pear/File/Archive/Reader/Filter.php
new file mode 100644
index 0000000..f8fd70b
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Reader/Filter.php
@@ -0,0 +1,90 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Filter.php,v 1.10 2005/07/09 12:54:35 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Reader/Relay.php";
+
+/**
+ * Filter out the files that do not respect a given predicat
+ */
+class File_Archive_Reader_Filter extends File_Archive_Reader_Relay
+{
+ /**
+ * @var File_Archive_Reader_Predicat
+ * @access private
+ */
+ var $predicate;
+
+ /**
+ * $source is the reader to filter
+ */
+ function File_Archive_Reader_Filter($predicate, &$source)
+ {
+ parent::File_Archive_Reader_Relay($source);
+ $this->predicate = $predicate;
+ }
+
+ /**
+ * @see File_Archive_Reader::next()
+ */
+ function next()
+ {
+ do {
+ $error = $this->source->next();
+ if ($error !== true) {
+ return $error;
+ }
+ } while (!$this->predicate->isTrue($this->source));
+ return true;
+ }
+
+ /**
+ * @see File_Archive_Reader::select()
+ */
+ function select($filename, $close = true)
+ {
+ if ($close) {
+ $error = $this->close();
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+ }
+
+ do {
+ $error = $this->source->select($filename, false);
+ if ($error !== true) {
+ return $error;
+ }
+ } while (!$this->predicate->isTrue($this->source));
+ return true;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Reader/Gzip.php b/thirdparty/pear/File/Archive/Reader/Gzip.php
new file mode 100644
index 0000000..8f13f99
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Reader/Gzip.php
@@ -0,0 +1,276 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Gzip.php,v 1.27 2005/06/19 20:09:57 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Reader/Archive.php";
+require_once "File/Archive/Writer/Files.php";
+
+/**
+ * Uncompress a file that was compressed in the Gzip format
+ */
+class File_Archive_Reader_Gzip extends File_Archive_Reader_Archive
+{
+ var $nbRead = 0;
+ var $filePos = 0;
+ var $gzfile = null;
+ var $tmpName = null;
+
+ /**
+ * @see File_Archive_Reader::close()
+ */
+ function close($innerClose = true)
+ {
+ if ($this->gzfile !== null) {
+ gzclose($this->gzfile);
+ }
+ if ($this->tmpName !== null) {
+ unlink($this->tmpName);
+ }
+
+ $this->nbRead = 0;
+ $this->filePos = 0;
+ $this->gzfile = null;
+ $this->tmpName = null;
+
+ return parent::close($innerClose);
+ }
+
+ /**
+ * @see File_Archive_Reader::next()
+ */
+ function next()
+ {
+ if (!parent::next()) {
+ return false;
+ }
+
+ $this->nbRead++;
+ $this->filePos = 0;
+ if ($this->nbRead > 1) {
+ return false;
+ }
+
+ $dataFilename = $this->source->getDataFilename();
+ if ($dataFilename !== null)
+ {
+ $this->tmpName = null;
+ $this->gzfile = gzopen($dataFilename, 'r');
+ } else {
+ $this->tmpName = tempnam(File_Archive::getOption('tmpDirectory'), 'far');
+
+ //Generate the tmp data
+ $dest = new File_Archive_Writer_Files();
+ $dest->newFile($this->tmpName);
+ $this->source->sendData($dest);
+ $dest->close();
+
+ $this->gzfile = gzopen($this->tmpName, 'r');
+ }
+
+ return true;
+ }
+
+ /**
+ * Return the name of the single file contained in the archive
+ * deduced from the name of the archive (the extension is removed)
+ *
+ * @see File_Archive_Reader::getFilename()
+ */
+ function getFilename()
+ {
+ $name = $this->source->getFilename();
+ $slashPos = strrpos($name, '/');
+ if ($slashPos !== false) {
+ $name = substr($name, $slashPos+1);
+ }
+ $dotPos = strrpos($name, '.');
+ if ($dotPos !== false && $dotPos > 0) {
+ $name = substr($name, 0, $dotPos);
+ }
+
+ return $name;
+ }
+
+ /**
+ * @see File_Archive_Reader::getData()
+ */
+ function getData($length = -1)
+ {
+ if ($length == -1) {
+ $data = '';
+ do
+ {
+ $newData = gzread($this->gzfile, 8192);
+ $data .= $newData;
+ } while ($newData != '');
+ } else if ($length == 0) {
+ return '';
+ } else {
+ $data = gzread($this->gzfile, $length);
+ }
+
+ $this->filePos += strlen($data);
+ return $data == '' ? null : $data;
+ }
+
+ /**
+ * @see File_Archive_Reader::skip()
+ */
+ function skip($length = -1)
+ {
+ if($length == -1) {
+ do
+ {
+ $tmp = gzread($this->gzfile, 8192);
+ $this->filePos += strlen($tmp);
+ } while ($tmp != '');
+ } else {
+ if (@gzseek($this->gzfile, $this->filePos + $length) === -1) {
+ return parent::skip($length);
+ } else {
+ $this->filePos += $length;
+ return $length;
+ }
+ }
+ }
+
+ /**
+ * @see File_Archive_Reader::rewind()
+ */
+ function rewind($length = -1)
+ {
+ if ($length == -1) {
+ if (@gzseek($this->gzfile, 0) === -1) {
+ return parent::rewind($length);
+ } else {
+ $tmp = $this->filePos;
+ $this->filePos = 0;
+ return $tmp;
+ }
+ } else {
+ $length = min($length, $this->filePos);
+ if (@gzseek($this->gzfile, $this->filePos - $length) === -1) {
+ return parent::rewind($length);
+ } else {
+ $this->filePos -= $length;
+ return $length;
+ }
+ }
+ }
+
+ /**
+ * @see File_Archive_Reader::tell()
+ */
+ function tell()
+ {
+ return $this->filePos;
+ }
+
+ /**
+ * @see File_Archive_Reader::makeAppendWriter()
+ */
+ function makeAppendWriter()
+ {
+ return PEAR::raiseError('Unable to append files to a gzip archive');
+ }
+
+ /**
+ * @see File_Archive_Reader::makeWriterRemoveFiles()
+ */
+ function makeWriterRemoveFiles($pred)
+ {
+ return PEAR::raiseError('Unable to remove files from a gzip archive');
+ }
+
+ /**
+ * @see File_Archive_Reader::makeWriterRemoveBlocks()
+ */
+ function makeWriterRemoveBlocks($blocks, $seek = 0)
+ {
+ require_once "File/Archive/Writer/Gzip.php";
+
+ if ($this->nbRead == 0) {
+ return PEAR::raiseError('No file selected');
+ }
+
+ //Uncompress data to a temporary file
+ $tmp = tmpfile();
+ $expectedPos = $this->filePos + $seek;
+ $this->rewind();
+
+ //Read the begining of the file
+ while ($this->filePos < $expectedPos &&
+ ($data = $this->getData(min($expectedPos - $this->filePos, 8192))) !== null) {
+ fwrite($tmp, $data);
+ }
+
+ $keep = false;
+ foreach ($blocks as $length) {
+ if ($keep) {
+ $expectedPos = $this->filePos + $length;
+ while ($this->filePos < $expectedPos &&
+ ($data = $this->getData(min($expectedPos - $this->filePos, 8192))) !== null) {
+ fwrite($tmp, $data);
+ }
+ } else {
+ $this->skip($length);
+ }
+ $keep = !$keep;
+ }
+ if ($keep) {
+ //Read the end of the file
+ while(($data = $this->getData(8192)) !== null) {
+ fwrite($tmp, $data);
+ }
+ }
+ fseek($tmp, 0);
+
+ //Create the writer
+ $this->source->rewind();
+ $innerWriter = $this->source->makeWriterRemoveBlocks(array()); //Truncate the source
+ unset($this->source);
+ $writer = new File_Archive_Writer_Gzip(null, $innerWriter);
+
+ //And compress data from the temporary file
+ while (!feof($tmp)) {
+ $data = fread($tmp, 8192);
+ $writer->writeData($data);
+ }
+ fclose($tmp);
+
+ //Do not close inner writer since makeWriter was called
+ $this->close();
+
+ return $writer;
+ }
+
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Reader/Memory.php b/thirdparty/pear/File/Archive/Reader/Memory.php
new file mode 100644
index 0000000..d77928f
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Reader/Memory.php
@@ -0,0 +1,227 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Memory.php,v 1.19 2005/06/19 20:09:57 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Reader.php";
+
+/**
+ * A reader that takes its input from a memory buffer
+ */
+class File_Archive_Reader_Memory extends File_Archive_Reader
+{
+ /**
+ * @var String Name of the file exported by this reader
+ * @access private
+ */
+ var $filename;
+ /**
+ * @var Array Stat of the file exported by this reader
+ * @access private
+ */
+ var $stat;
+ /**
+ * @var String MIME type of the file exported by this reader
+ * @access private
+ */
+ var $mime;
+ /**
+ * @var String Memory buffer that contains the data of the file
+ * @access private
+ */
+ var $memory;
+ /**
+ * @var Int Current position in the file
+ * @access private
+ */
+ var $offset = 0;
+ /**
+ * @var Boolean Has the file already been read
+ * @access private
+ */
+ var $alreadyRead = false;
+
+ /**
+ * @param string $memory is the content of the file.
+ * This parameter is passed as a reference for performance
+ * reasons. The content should not be changer after the constructor
+ * @param string $filename is the name of the file
+ * @param array $stat are the statistics of the file. The size will be
+ * recomputed from $memory
+ * @param string $mime is the mime type of the file
+ */
+ function File_Archive_Reader_Memory(&$memory, $filename,
+ $stat=array(), $mime=null)
+ {
+ $this->memory = &$memory;
+ $this->filename = $this->getStandardURL($filename);
+ $this->stat = $stat;
+ $this->stat[7] = $this->stat['size'] = strlen($this->memory);
+ $this->mime = $mime;
+ }
+
+ /**
+ * The subclass should overwrite this function to change the filename, stat
+ * and memory
+ */
+ function next()
+ {
+ if ($this->alreadyRead) {
+ return false;
+ } else {
+ $this->alreadyRead = true;
+ return true;
+ }
+ }
+
+ /**
+ * @see File_Archive_Reader::getFilename()
+ */
+ function getFilename() { return $this->filename; }
+ /**
+ * @see File_Archive_Reader::getStat()
+ */
+ function getStat() { return $this->stat; }
+ /**
+ * @see File_Archive_Reader::getMime()
+ */
+ function getMime()
+ {
+ return $this->mime==null ? parent::getMime() : $this->mime;
+ }
+
+ /**
+ * @see File_Archive_Reader::getData()
+ */
+ function getData($length = -1)
+ {
+ if ($this->offset == strlen($this->memory)) {
+ return null;
+ }
+ if ($length == -1) {
+ $actualLength = strlen($this->memory) - $this->offset;
+ } else {
+ $actualLength = min($length, strlen($this->memory) - $this->offset);
+ }
+ $result = substr($this->memory, $this->offset, $actualLength);
+ $this->offset += $actualLength;
+ return $result;
+ }
+
+ /**
+ * @see File_Archive_Reader::skip()
+ */
+ function skip($length = -1)
+ {
+ if ($length == -1) {
+ $length = strlen($this->memory) - $this->offset;
+ } else {
+ $length = min($length, strlen($this->memory) - $this->offset);
+ }
+ $this->offset += $length;
+ return $length;
+ }
+
+ /**
+ * @see File_Archive_Reader::rewind()
+ */
+ function rewind($length = -1)
+ {
+ if ($length == -1) {
+ $tmp = $this->offset;
+ $this->offset = 0;
+ return $tmp;
+ } else {
+ $length = min($length, $this->offset);
+ $this->offset -= $length;
+ return $length;
+ }
+ }
+
+ /**
+ * @see File_Archive_Reader::tell()
+ */
+ function tell()
+ {
+ return $this->offset;
+ }
+
+ /**
+ * @see File_Archive_Reader::close()
+ */
+ function close()
+ {
+ $this->offset = 0;
+ $this->alreadyRead = false;
+ }
+
+ /**
+ * @see File_Archive_Reader::makeAppendWriter()
+ */
+ function makeAppendWriter()
+ {
+ return PEAR::raiseError('Unable to append files to a memory archive');
+ }
+
+ /**
+ * @see File_Archive_Reader::makeWriterRemoveFiles()
+ */
+ function makeWriterRemoveFiles($pred)
+ {
+ return PEAR::raiseError('Unable to remove files from a memory archive');
+ }
+
+ /**
+ * @see File_Archive_Reader::makeWriterRemoveBlocks()
+ */
+ function makeWriterRemoveBlocks($blocks, $seek = 0)
+ {
+ require_once "File/Archive/Writer/Memory.php";
+ $data = substr($this->memory, 0, $this->offset + $seek);
+ $this->memory = substr($this->memory, $this->offset + $seek);
+
+ $keep = false;
+ foreach ($blocks as $length) {
+ if ($keep) {
+ $data .= substr($this->memory, 0, $length);
+ }
+ $this->memory = substr($this->memory, $length);
+ $keep = !$keep;
+ }
+ if ($keep) {
+ $this->memory = $data . $this->memory;
+ } else {
+ $this->memory = $data;
+ }
+ $this->close();
+ return new File_Archive_Writer_Memory($this->memory, strlen($this->memory));
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Reader/MimeList.php b/thirdparty/pear/File/Archive/Reader/MimeList.php
new file mode 100644
index 0000000..7f10f87
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Reader/MimeList.php
@@ -0,0 +1,939 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: MimeList.php,v 1.7 2005/02/23 20:11:42 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+/**
+ * Returns the MIME of the filename, deducted from its extension
+ * If the extension is unknown, returns "application/octet-stream"
+ */
+function File_Archive_Reader_GetMime($filename)
+{
+ $pos = strrpos($filename, '.');
+ $extension = "";
+ if ($pos !== false) {
+ $extension = strtolower(substr($filename, $pos+1));
+ }
+
+ switch($extension) {
+ case '3dmf':
+ return 'x-world/x-3dmf';
+ case 'a':
+ return 'application/octet-stream';
+ case 'aab':
+ return 'application/x-authorware-bin';
+ case 'aam':
+ return 'application/x-authorware-map';
+ case 'aas':
+ return 'application/x-authorware-seg';
+ case 'abc':
+ return 'text/vnd.abc';
+ case 'acgi':
+ return 'text/html';
+ case 'afl':
+ return 'video/animaflex';
+ case 'ai':
+ return 'application/postscript';
+ case 'aif':
+ return 'audio/aiff';
+ case 'aifc':
+ return 'audio/aiff';
+ case 'aiff':
+ return 'audio/aiff';
+ case 'aim':
+ return 'application/x-aim';
+ case 'aip':
+ return 'text/x-audiosoft-intra';
+ case 'ani':
+ return 'application/x-navi-animation';
+ case 'aos':
+ return 'application/x-nokia-9000-communicator-add-on-software';
+ case 'aps':
+ return 'application/mime';
+ case 'arc':
+ return 'application/octet-stream';
+ case 'arj':
+ return 'application/arj';
+ case 'art':
+ return 'image/x-jg';
+ case 'asf':
+ return 'video/x-ms-asf';
+ case 'asm':
+ return 'text/x-asm';
+ case 'asp':
+ return 'text/asp';
+ case 'asx':
+ return 'application/x-mplayer2';
+ case 'au':
+ return 'audio/basic';
+ case 'avi':
+ return 'application/x-troff-msvideo';
+ case 'avs':
+ return 'video/avs-video';
+ case 'bcpio':
+ return 'application/x-bcpio';
+ case 'bin':
+ return 'application/x-binary';
+ case 'bm':
+ return 'image/bmp';
+ case 'bmp':
+ return 'image/bmp';
+ case 'boo':
+ return 'application/book';
+ case 'book':
+ return 'application/book';
+ case 'boz':
+ return 'application/x-bzip2';
+ case 'bsh':
+ return 'application/x-bsh';
+ case 'bz':
+ return 'application/x-bzip';
+ case 'bz2':
+ return 'application/x-bzip2';
+ case 'c':
+ return 'text/plain';
+ case 'c++':
+ return 'text/plain';
+ case 'cat':
+ return 'application/vnd.ms-pki.seccat';
+ case 'cc':
+ return 'text/plain';
+ case 'ccad':
+ return 'application/clariscad';
+ case 'cco':
+ return 'application/x-cocoa';
+ case 'cdf':
+ return 'application/cdf';
+ case 'cer':
+ return 'application/pkix-cert';
+ case 'cha':
+ return 'application/x-chat';
+ case 'chat':
+ return 'application/x-chat';
+ case 'class':
+ return 'application/java';
+ case 'com':
+ return 'application/octet-stream';
+ case 'conf':
+ return 'text/plain';
+ case 'cpio':
+ return 'application/x-cpio';
+ case 'cpp':
+ return 'text/x-c';
+ case 'cpt':
+ return 'application/mac-compactpro';
+ case 'crl':
+ return 'application/pkcs-crl';
+ case 'csh':
+ return 'application/x-csh';
+ case 'css':
+ return 'text/css';
+ case 'cxx':
+ return 'text/plain';
+ case 'dcr':
+ return 'application/x-director';
+ case 'deepv':
+ return 'application/x-deepv';
+ case 'def':
+ return 'text/plain';
+ case 'der':
+ return 'application/x-x509-ca-cert';
+ case 'dif':
+ return 'video/x-dv';
+ case 'dir':
+ return 'application/x-director';
+ case 'dl':
+ return 'video/dl';
+ case 'doc':
+ return 'application/msword';
+ case 'dot':
+ return 'application/msword';
+ case 'dp':
+ return 'application/commonground';
+ case 'drw':
+ return 'application/drafting';
+ case 'dump':
+ return 'application/octet-stream';
+ case 'dv':
+ return 'video/x-dv';
+ case 'dvi':
+ return 'application/x-dvi';
+ case 'dwf':
+ return 'drawing/x-dwf (old)';
+ case 'dwg':
+ return 'application/acad';
+ case 'dxf':
+ return 'application/dxf';
+ case 'dxr':
+ return 'application/x-director';
+ case 'el':
+ return 'text/x-script.elisp';
+ case 'elc':
+ return 'application/x-bytecode.elisp (compiled elisp)';
+ case 'env':
+ return 'application/x-envoy';
+ case 'eps':
+ return 'application/postscript';
+ case 'es':
+ return 'application/x-esrehber';
+ case 'etx':
+ return 'text/x-setext';
+ case 'evy':
+ return 'application/envoy';
+ case 'exe':
+ return 'application/octet-stream';
+ case 'f':
+ return 'text/plain';
+ case 'f77':
+ return 'text/x-fortran';
+ case 'f90':
+ return 'text/plain';
+ case 'fdf':
+ return 'application/vnd.fdf';
+ case 'fif':
+ return 'application/fractals';
+ case 'fli':
+ return 'video/fli';
+ case 'flo':
+ return 'image/florian';
+ case 'flx':
+ return 'text/vnd.fmi.flexstor';
+ case 'fmf':
+ return 'video/x-atomic3d-feature';
+ case 'for':
+ return 'text/plain';
+ case 'fpx':
+ return 'image/vnd.fpx';
+ case 'frl':
+ return 'application/freeloader';
+ case 'funk':
+ return 'audio/make';
+ case 'g':
+ return 'text/plain';
+ case 'g3':
+ return 'image/g3fax';
+ case 'gif':
+ return 'image/gif';
+ case 'gl':
+ return 'video/gl';
+ case 'gsd':
+ return 'audio/x-gsm';
+ case 'gsm':
+ return 'audio/x-gsm';
+ case 'gsp':
+ return 'application/x-gsp';
+ case 'gss':
+ return 'application/x-gss';
+ case 'gtar':
+ return 'application/x-gtar';
+ case 'gz':
+ return 'application/x-compressed';
+ case 'gzip':
+ return 'application/x-gzip';
+ case 'h':
+ return 'text/plain';
+ case 'hdf':
+ return 'application/x-hdf';
+ case 'help':
+ return 'application/x-helpfile';
+ case 'hgl':
+ return 'application/vnd.hp-hpgl';
+ case 'hh':
+ return 'text/plain';
+ case 'hlb':
+ return 'text/x-script';
+ case 'hlp':
+ return 'application/hlp';
+ case 'hpg':
+ return 'application/vnd.hp-hpgl';
+ case 'hpgl':
+ return 'application/vnd.hp-hpgl';
+ case 'hqx':
+ return 'application/binhex';
+ case 'hta':
+ return 'application/hta';
+ case 'htc':
+ return 'text/x-component';
+ case 'htm':
+ return 'text/html';
+ case 'html':
+ return 'text/html';
+ case 'htmls':
+ return 'text/html';
+ case 'htt':
+ return 'text/webviewhtml';
+ case 'htx':
+ return 'text/html';
+ case 'ice':
+ return 'x-conference/x-cooltalk';
+ case 'ico':
+ return 'image/x-icon';
+ case 'idc':
+ return 'text/plain';
+ case 'ief':
+ return 'image/ief';
+ case 'iefs':
+ return 'image/ief';
+ case 'iges':
+ return 'application/iges';
+ case 'igs':
+ return 'application/iges';
+ case 'ima':
+ return 'application/x-ima';
+ case 'imap':
+ return 'application/x-httpd-imap';
+ case 'inf':
+ return 'application/inf';
+ case 'ins':
+ return 'application/x-internett-signup';
+ case 'ip':
+ return 'application/x-ip2';
+ case 'isu':
+ return 'video/x-isvideo';
+ case 'it':
+ return 'audio/it';
+ case 'iv':
+ return 'application/x-inventor';
+ case 'ivr':
+ return 'i-world/i-vrml';
+ case 'ivy':
+ return 'application/x-livescreen';
+ case 'jam':
+ return 'audio/x-jam';
+ case 'jav':
+ return 'text/plain';
+ case 'java':
+ return 'text/plain';
+ case 'jcm':
+ return 'application/x-java-commerce';
+ case 'jfif':
+ return 'image/jpeg';
+ case 'jfif-tbnl':
+ return 'image/jpeg';
+ case 'jpe':
+ return 'image/jpeg';
+ case 'jpeg':
+ return 'image/jpeg';
+ case 'jpg':
+ return 'image/jpeg';
+ case 'jps':
+ return 'image/x-jps';
+ case 'js':
+ return 'application/x-javascript';
+ case 'jut':
+ return 'image/jutvision';
+ case 'kar':
+ return 'audio/midi';
+ case 'ksh':
+ return 'application/x-ksh';
+ case 'la':
+ return 'audio/nspaudio';
+ case 'lam':
+ return 'audio/x-liveaudio';
+ case 'latex':
+ return 'application/x-latex';
+ case 'lha':
+ return 'application/lha';
+ case 'lhx':
+ return 'application/octet-stream';
+ case 'list':
+ return 'text/plain';
+ case 'lma':
+ return 'audio/nspaudio';
+ case 'log':
+ return 'text/plain';
+ case 'lsp':
+ return 'application/x-lisp';
+ case 'lst':
+ return 'text/plain';
+ case 'lsx':
+ return 'text/x-la-asf';
+ case 'ltx':
+ return 'application/x-latex';
+ case 'lzh':
+ return 'application/octet-stream';
+ case 'lzx':
+ return 'application/lzx';
+ case 'm':
+ return 'text/plain';
+ case 'm1v':
+ return 'video/mpeg';
+ case 'm2a':
+ return 'audio/mpeg';
+ case 'm2v':
+ return 'video/mpeg';
+ case 'm3u':
+ return 'audio/x-mpequrl';
+ case 'man':
+ return 'application/x-troff-man';
+ case 'map':
+ return 'application/x-navimap';
+ case 'mar':
+ return 'text/plain';
+ case 'mbd':
+ return 'application/mbedlet';
+ case 'mc$':
+ return 'application/x-magic-cap-package-1.0';
+ case 'mcd':
+ return 'application/mcad';
+ case 'mcf':
+ return 'image/vasa';
+ case 'mcp':
+ return 'application/netmc';
+ case 'me':
+ return 'application/x-troff-me';
+ case 'mht':
+ return 'message/rfc822';
+ case 'mhtml':
+ return 'message/rfc822';
+ case 'mid':
+ return 'application/x-midi';
+ case 'midi':
+ return 'audio/midi';
+ case 'mif':
+ return 'application/x-frame';
+ case 'mime':
+ return 'message/rfc822';
+ case 'mjf':
+ return 'audio/x-vnd.audioexplosion.mjuicemediafile';
+ case 'mjpg':
+ return 'video/x-motion-jpeg';
+ case 'mm':
+ return 'application/base64';
+ case 'mme':
+ return 'application/base64';
+ case 'mod':
+ return 'audio/mod';
+ case 'moov':
+ return 'video/quicktime';
+ case 'mov':
+ return 'video/quicktime';
+ case 'movie':
+ return 'video/x-sgi-movie';
+ case 'mp2':
+ return 'video/mpeg';
+ case 'mp3':
+ return 'video/mpeg';
+ case 'mpa':
+ return 'audio/mpeg';
+ case 'mpc':
+ return 'application/x-project';
+ case 'mpe':
+ return 'video/mpeg';
+ case 'mpeg':
+ return 'video/mpeg';
+ case 'mpg':
+ return 'video/mpeg';
+ case 'mpga':
+ return 'audio/mpeg';
+ case 'mpp':
+ return 'application/vnd.ms-project';
+ case 'mpt':
+ return 'application/x-project';
+ case 'mpv':
+ return 'application/x-project';
+ case 'mpx':
+ return 'application/x-project';
+ case 'mrc':
+ return 'application/marc';
+ case 'ms':
+ return 'application/x-troff-ms';
+ case 'mv':
+ return 'video/x-sgi-movie';
+ case 'my':
+ return 'audio/make';
+ case 'mzz':
+ return 'application/x-vnd.audioexplosion.mzz';
+ case 'nap':
+ return 'image/naplps';
+ case 'naplps':
+ return 'image/naplps';
+ case 'nc':
+ return 'application/x-netcdf';
+ case 'ncm':
+ return 'application/vnd.nokia.configuration-message';
+ case 'nif':
+ return 'image/x-niff';
+ case 'niff':
+ return 'image/x-niff';
+ case 'nix':
+ return 'application/x-mix-transfer';
+ case 'nsc':
+ return 'application/x-conference';
+ case 'nvd':
+ return 'application/x-navidoc';
+ case 'o':
+ return 'application/octet-stream';
+ case 'oda':
+ return 'application/oda';
+ case 'omc':
+ return 'application/x-omc';
+ case 'omcd':
+ return 'application/x-omcdatamaker';
+ case 'omcr':
+ return 'application/x-omcregerator';
+ case 'p':
+ return 'text/x-pascal';
+ case 'p10':
+ return 'application/pkcs10';
+ case 'p12':
+ return 'application/pkcs-12';
+ case 'p7a':
+ return 'application/x-pkcs7-signature';
+ case 'p7c':
+ return 'application/pkcs7-mime';
+ case 'p7m':
+ return 'application/pkcs7-mime';
+ case 'p7r':
+ return 'application/x-pkcs7-certreqresp';
+ case 'p7s':
+ return 'application/pkcs7-signature';
+ case 'part':
+ return 'application/pro_eng';
+ case 'pas':
+ return 'text/pascal';
+ case 'pbm':
+ return 'image/x-portable-bitmap';
+ case 'pcl':
+ return 'application/vnd.hp-pcl';
+ case 'pct':
+ return 'image/x-pict';
+ case 'pcx':
+ return 'image/x-pcx';
+ case 'pdb':
+ return 'chemical/x-pdb';
+ case 'pdf':
+ return 'application/pdf';
+ case 'pfunk':
+ return 'audio/make';
+ case 'pgm':
+ return 'image/x-portable-graymap';
+ case 'pic':
+ return 'image/pict';
+ case 'pict':
+ return 'image/pict';
+ case 'pkg':
+ return 'application/x-newton-compatible-pkg';
+ case 'pko':
+ return 'application/vnd.ms-pki.pko';
+ case 'pl':
+ return 'text/plain';
+ case 'plx':
+ return 'application/x-pixclscript';
+ case 'pm':
+ return 'image/x-xpixmap';
+ case 'pm4':
+ return 'application/x-pagemaker';
+ case 'pm5':
+ return 'application/x-pagemaker';
+ case 'png':
+ return 'image/png';
+ case 'pnm':
+ return 'application/x-portable-anymap';
+ case 'pot':
+ return 'application/mspowerpoint';
+ case 'pov':
+ return 'model/x-pov';
+ case 'ppa':
+ return 'application/vnd.ms-powerpoint';
+ case 'ppm':
+ return 'image/x-portable-pixmap';
+ case 'pps':
+ return 'application/mspowerpoint';
+ case 'ppt':
+ return 'application/mspowerpoint';
+ case 'ppz':
+ return 'application/mspowerpoint';
+ case 'pre':
+ return 'application/x-freelance';
+ case 'prt':
+ return 'application/pro_eng';
+ case 'ps':
+ return 'application/postscript';
+ case 'psd':
+ return 'application/octet-stream';
+ case 'pvu':
+ return 'paleovu/x-pv';
+ case 'pwz':
+ return 'application/vnd.ms-powerpoint';
+ case 'py':
+ return 'text/x-script.phyton';
+ case 'pyc':
+ return 'applicaiton/x-bytecode.python';
+ case 'qcp':
+ return 'audio/vnd.qcelp';
+ case 'qd3':
+ return 'x-world/x-3dmf';
+ case 'qd3d':
+ return 'x-world/x-3dmf';
+ case 'qif':
+ return 'image/x-quicktime';
+ case 'qt':
+ return 'video/quicktime';
+ case 'qtc':
+ return 'video/x-qtc';
+ case 'qti':
+ return 'image/x-quicktime';
+ case 'qtif':
+ return 'image/x-quicktime';
+ case 'ra':
+ return 'audio/x-pn-realaudio';
+ case 'ram':
+ return 'audio/x-pn-realaudio';
+ case 'ras':
+ return 'application/x-cmu-raster';
+ case 'rast':
+ return 'image/cmu-raster';
+ case 'rexx':
+ return 'text/x-script.rexx';
+ case 'rf':
+ return 'image/vnd.rn-realflash';
+ case 'rgb':
+ return 'image/x-rgb';
+ case 'rm':
+ return 'application/vnd.rn-realmedia';
+ case 'rmi':
+ return 'audio/mid';
+ case 'rmm':
+ return 'audio/x-pn-realaudio';
+ case 'rmp':
+ return 'audio/x-pn-realaudio';
+ case 'rng':
+ return 'application/ringing-tones';
+ case 'rnx':
+ return 'application/vnd.rn-realplayer';
+ case 'roff':
+ return 'application/x-troff';
+ case 'rp':
+ return 'image/vnd.rn-realpix';
+ case 'rpm':
+ return 'audio/x-pn-realaudio-plugin';
+ case 'rt':
+ return 'text/richtext';
+ case 'rtf':
+ return 'application/rtf';
+ case 'rtx':
+ return 'text/richtext';
+ case 'rv':
+ return 'video/vnd.rn-realvideo';
+ case 's':
+ return 'text/x-asm';
+ case 's3m':
+ return 'audio/s3m';
+ case 'saveme':
+ return 'application/octet-stream';
+ case 'sbk':
+ return 'application/x-tbook';
+ case 'scm':
+ return 'application/x-lotusscreencam';
+ case 'sdml':
+ return 'text/plain';
+ case 'sdp':
+ return 'application/sdp';
+ case 'sdr':
+ return 'application/sounder';
+ case 'sea':
+ return 'application/sea';
+ case 'set':
+ return 'application/set';
+ case 'sgm':
+ return 'text/sgml';
+ case 'sgml':
+ return 'text/sgml';
+ case 'sh':
+ return 'application/x-bsh';
+ case 'shar':
+ return 'application/x-bsh';
+ case 'shtml':
+ return 'text/html';
+ case 'sid':
+ return 'audio/x-psid';
+ case 'sit':
+ return 'application/x-sit';
+ case 'skd':
+ return 'application/x-koan';
+ case 'skm':
+ return 'application/x-koan';
+ case 'skp':
+ return 'application/x-koan';
+ case 'skt':
+ return 'application/x-koan';
+ case 'sl':
+ return 'application/x-seelogo';
+ case 'smi':
+ return 'application/smil';
+ case 'smil':
+ return 'application/smil';
+ case 'snd':
+ return 'audio/basic';
+ case 'sol':
+ return 'application/solids';
+ case 'spc':
+ return 'application/x-pkcs7-certificates';
+ case 'spl':
+ return 'application/futuresplash';
+ case 'spr':
+ return 'application/x-sprite';
+ case 'sprite':
+ return 'application/x-sprite';
+ case 'src':
+ return 'application/x-wais-source';
+ case 'ssi':
+ return 'text/x-server-parsed-html';
+ case 'ssm':
+ return 'application/streamingmedia';
+ case 'sst':
+ return 'application/vnd.ms-pki.certstore';
+ case 'step':
+ return 'application/step';
+ case 'stl':
+ return 'application/sla';
+ case 'stp':
+ return 'application/step';
+ case 'sv4cpio':
+ return 'application/x-sv4cpio';
+ case 'sv4crc':
+ return 'application/x-sv4crc';
+ case 'svf':
+ return 'image/vnd.dwg';
+ case 'svr':
+ return 'application/x-world';
+ case 'swf':
+ return 'application/x-shockwave-flash';
+ case 't':
+ return 'application/x-troff';
+ case 'talk':
+ return 'text/x-speech';
+ case 'tar':
+ return 'application/x-tar';
+ case 'tbk':
+ return 'application/toolbook';
+ case 'tcl':
+ return 'application/x-tcl';
+ case 'tcsh':
+ return 'text/x-script.tcsh';
+ case 'tex':
+ return 'application/x-tex';
+ case 'texi':
+ return 'application/x-texinfo';
+ case 'texinfo':
+ return 'application/x-texinfo';
+ case 'text':
+ return 'text/plain';
+ case 'tgz':
+ return 'application/x-compressed';
+ case 'tif':
+ return 'image/tiff';
+ case 'tiff':
+ return 'image/tiff';
+ case 'tr':
+ return 'application/x-troff';
+ case 'tsi':
+ return 'audio/tsp-audio';
+ case 'tsp':
+ return 'application/dsptype';
+ case 'tsv':
+ return 'text/tab-separated-values';
+ case 'turbot':
+ return 'image/florian';
+ case 'txt':
+ return 'text/plain';
+ case 'uil':
+ return 'text/x-uil';
+ case 'uni':
+ return 'text/uri-list';
+ case 'unis':
+ return 'text/uri-list';
+ case 'unv':
+ return 'application/i-deas';
+ case 'uri':
+ return 'text/uri-list';
+ case 'uris':
+ return 'text/uri-list';
+ case 'ustar':
+ return 'multipart/x-ustar';
+ case 'uu':
+ return 'application/octet-stream';
+ case 'uue':
+ return 'text/x-uuencode';
+ case 'vcd':
+ return 'application/x-cdlink';
+ case 'vcs':
+ return 'text/x-vcalendar';
+ case 'vda':
+ return 'application/vda';
+ case 'vdo':
+ return 'video/vdo';
+ case 'vew':
+ return 'application/groupwise';
+ case 'viv':
+ return 'video/vivo';
+ case 'vivo':
+ return 'video/vivo';
+ case 'vmd':
+ return 'application/vocaltec-media-desc';
+ case 'vmf':
+ return 'application/vocaltec-media-file';
+ case 'voc':
+ return 'audio/voc';
+ case 'vos':
+ return 'video/vosaic';
+ case 'vox':
+ return 'audio/voxware';
+ case 'vqe':
+ return 'audio/x-twinvq-plugin';
+ case 'vqf':
+ return 'audio/x-twinvq';
+ case 'vql':
+ return 'audio/x-twinvq-plugin';
+ case 'vrml':
+ return 'application/x-vrml';
+ case 'vrt':
+ return 'x-world/x-vrt';
+ case 'vsd':
+ return 'application/x-visio';
+ case 'vst':
+ return 'application/x-visio';
+ case 'vsw':
+ return 'application/x-visio';
+ case 'w60':
+ return 'application/wordperfect6.0';
+ case 'w61':
+ return 'application/wordperfect6.1';
+ case 'w6w':
+ return 'application/msword';
+ case 'wav':
+ return 'audio/wav';
+ case 'wb1':
+ return 'application/x-qpro';
+ case 'wbmp':
+ return 'image/vnd.wap.wbmp';
+ case 'web':
+ return 'application/vnd.xara';
+ case 'wiz':
+ return 'application/msword';
+ case 'wk1':
+ return 'application/x-123';
+ case 'wmf':
+ return 'windows/metafile';
+ case 'wml':
+ return 'text/vnd.wap.wml';
+ case 'wmlc':
+ return 'application/vnd.wap.wmlc';
+ case 'wmls':
+ return 'text/vnd.wap.wmlscript';
+ case 'wmlsc':
+ return 'application/vnd.wap.wmlscriptc';
+ case 'word':
+ return 'application/msword';
+ case 'wp':
+ return 'application/wordperfect';
+ case 'wp5':
+ return 'application/wordperfect6.0';
+ case 'wp6':
+ return 'application/wordperfect';
+ case 'wpd':
+ return 'application/x-wpwin';
+ case 'wq1':
+ return 'application/x-lotus';
+ case 'wri':
+ return 'application/mswrite';
+ case 'wrl':
+ return 'model/vrml';
+ case 'wrz':
+ return 'model/vrml';
+ case 'wsc':
+ return 'text/scriplet';
+ case 'wsrc':
+ return 'application/x-wais-source';
+ case 'wtk':
+ return 'application/x-wintalk';
+ case 'xbm':
+ return 'image/x-xbitmap';
+ case 'xdr':
+ return 'video/x-amt-demorun';
+ case 'xgz':
+ return 'xgl/drawing';
+ case 'xif':
+ return 'image/vnd.xiff';
+ case 'xl':
+ return 'application/excel';
+ case 'xla':
+ return 'application/excel';
+ case 'xlb':
+ return 'application/excel';
+ case 'xlc':
+ return 'application/excel';
+ case 'xld':
+ return 'application/excel';
+ case 'xlk':
+ return 'application/excel';
+ case 'xll':
+ return 'application/excel';
+ case 'xlm':
+ return 'application/excel';
+ case 'xls':
+ return 'application/excel';
+ case 'xlt':
+ return 'application/excel';
+ case 'xlv':
+ return 'application/excel';
+ case 'xlw':
+ return 'application/excel';
+ case 'xm':
+ return 'audio/xm';
+ case 'xml':
+ return 'application/xml';
+ case 'xmz':
+ return 'xgl/movie';
+ case 'xpix':
+ return 'application/x-vnd.ls-xpix';
+ case 'xpm':
+ return 'image/xpm';
+ case 'x-png':
+ return 'image/png';
+ case 'xsr':
+ return 'video/x-amt-showrun';
+ case 'xwd':
+ return 'image/x-xwd';
+ case 'xyz':
+ return 'chemical/x-pdb';
+ case 'z':
+ return 'application/x-compress';
+ case 'zip':
+ return 'application/x-compressed';
+ case 'zoo':
+ return 'application/octet-stream';
+ case 'zsh':
+ return 'text/x-script.zsh';
+ default:
+ return 'application/octet-stream';
+ }
+}
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Reader/Multi.php b/thirdparty/pear/File/Archive/Reader/Multi.php
new file mode 100644
index 0000000..b2c5ee3
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Reader/Multi.php
@@ -0,0 +1,95 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Multi.php,v 1.10 2005/05/26 21:30:18 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Reader/Relay.php";
+
+/**
+ * Regroups several readers to make them appear as a single one
+ */
+class File_Archive_Reader_Multi extends File_Archive_Reader_Relay
+{
+ /**
+ * @var Array All the sources regrouped in this reader
+ * @access private
+ */
+ var $sources = array();
+ /**
+ * @var Int Index of the source being read currently
+ * @access private
+ */
+ var $currentIndex = 0;
+
+ function File_Archive_Reader_Multi()
+ {
+ parent::File_Archive_Reader_Relay($tmp = null);
+ }
+
+ /**
+ * Add a new reader to the list of readers
+ * @param File_Archive_Reader $source The source to add
+ */
+ function addSource(&$source)
+ {
+ $this->sources[] =& $source;
+ }
+
+ /**
+ * @see File_Archive_Reader::next()
+ */
+ function next()
+ {
+ while (array_key_exists($this->currentIndex, $this->sources)) {
+ $this->source =& $this->sources[$this->currentIndex];
+
+ if (($error = $this->source->next()) === false) {
+ $error = $this->source->close();
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+ $this->currentIndex++;
+ } else {
+ return $error;
+ }
+ }
+ return false;
+ }
+ /**
+ * @see File_Archive_Reader::close()
+ */
+ function close()
+ {
+ $error = parent::close();
+ $this->currentIndex = 0;
+ return $error;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Reader/Relay.php b/thirdparty/pear/File/Archive/Reader/Relay.php
new file mode 100644
index 0000000..c6e2323
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Reader/Relay.php
@@ -0,0 +1,134 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Relay.php,v 1.19 2005/07/09 12:54:35 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Reader.php";
+
+/**
+ * This reader appear exactly as $source does
+ * This is usefull if you want to dynamically change $source or change
+ * its behaviour
+ */
+class File_Archive_Reader_Relay extends File_Archive_Reader
+{
+ /**
+ * @var File_Archive_Reader This reader will have the same comportment as
+ * $source
+ * @access protected
+ */
+ var $source;
+
+ function File_Archive_Reader_Relay(&$source)
+ {
+ $this->source =& $source;
+ }
+
+ /**
+ * @see File_Archive_Reader::next()
+ */
+ function next() { return $this->source->next(); }
+ /**
+ * @see File_Archive_Reader::getFilename()
+ */
+ function getFilename() { return $this->source->getFilename(); }
+ /**
+ * @see File_Archive_Reader::getStat()
+ */
+ function getStat() { return $this->source->getStat(); }
+ /**
+ * @see File_Archive_Reader::getMime()
+ */
+ function getMime() { return $this->source->getMime(); }
+ /**
+ * @see File_Archive_Reader::getDataFilename()
+ */
+ function getDataFilename() { return $this->source->getDataFilename(); }
+ /**
+ * @see File_Archive_Reader::getData()
+ */
+ function getData($length = -1) { return $this->source->getData($length); }
+ /**
+ * @see File_Archive_Reader::skip()
+ */
+ function skip($length = -1) { return $this->source->skip($length); }
+ /**
+ * @see File_Archive_Reader::rewind()
+ */
+ function rewind($length = -1) { return $this->source->rewind($length); }
+ /**
+ * @see File_Archive_Reader::tell()
+ */
+ function tell() { return $this->source->tell(); }
+
+ /**
+ * @see File_Archive_Reader::close()
+ */
+ function close()
+ {
+ if ($this->source !== null) {
+ return $this->source->close();
+ }
+ }
+ /**
+ * @see File_Archive_Reader::makeAppendWriter()
+ */
+ function makeAppendWriter()
+ {
+ $writer = $this->source->makeAppendWriter();
+ if (!PEAR::isError($writer)) {
+ $this->close();
+ }
+ return $writer;
+ }
+ /**
+ * @see File_Archive_Reader::makeWriterRemoveFiles()
+ */
+ function makeWriterRemoveFiles($pred)
+ {
+ $writer = $this->source->makeWriterRemoveFiles($pred);
+ if (!PEAR::isError($writer)) {
+ $this->close();
+ }
+ return $writer;
+ }
+ /**
+ * @see File_Archive_Reader::makeWriterRemoveBlocks()
+ */
+ function makeWriterRemoveBlocks($blocks, $seek = 0)
+ {
+ $writer = $this->source->makeWriterRemoveBlocks($blocks, $seek);
+ if (!PEAR::isError($writer)) {
+ $this->close();
+ }
+ return $writer;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Reader/Select.php b/thirdparty/pear/File/Archive/Reader/Select.php
new file mode 100644
index 0000000..a1a27fd
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Reader/Select.php
@@ -0,0 +1,63 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Select.php,v 1.3 2005/05/26 21:30:18 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Reader/Relay.php";
+
+/**
+ * Reader that keeps the files selected by File_Archive::select function
+ */
+class File_Archive_Reader_Select extends File_Archive_Reader_Relay
+{
+ /**
+ * @var File_Archive_Reader_Predicat
+ * @access private
+ */
+ var $filename;
+
+ /**
+ * $source is the reader to filter
+ */
+ function File_Archive_Reader_Select($filename, &$source)
+ {
+ parent::File_Archive_Reader_Relay($source);
+ $this->filename = $filename;
+ }
+
+ /**
+ * @see File_Archive_Reader::next()
+ */
+ function next()
+ {
+ return $this->source->select($this->filename, false);
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Reader/Tar.php b/thirdparty/pear/File/Archive/Reader/Tar.php
new file mode 100644
index 0000000..ee16df6
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Reader/Tar.php
@@ -0,0 +1,355 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Tar.php,v 1.29 2005/07/11 11:53:53 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Reader/Archive.php";
+
+/**
+ * Read a tar archive
+ */
+class File_Archive_Reader_Tar extends File_Archive_Reader_Archive
+{
+ /**
+ * @var String Name of the file being read
+ * @access private
+ */
+ var $currentFilename = null;
+ /**
+ * @var Array Stats of the file being read
+ * In TAR reader, indexes 2, 4, 5, 7, 9 are set
+ * @access private
+ */
+ var $currentStat = null;
+ /**
+ * @var int Number of bytes that still have to be read before the end of
+ * file
+ * @access private
+ */
+ var $leftLength = 0;
+ /**
+ * @var int Size of the footer
+ * A TAR file is made of chunks of 512 bytes. If 512 does not
+ * divide the file size a footer is added
+ * @access private
+ */
+ var $footerLength = 0;
+ /**
+ * @var int nb bytes to seek back in order to reach the end of the archive
+ * or null if the end of the archive has not been reached
+ */
+ var $seekToEnd = null;
+
+ /**
+ * @see File_Archive_Reader::skip()
+ */
+ function skip($length = -1)
+ {
+ if ($length == -1) {
+ $length = $this->leftLength;
+ } else {
+ $length = min($this->leftLength, $length);
+ }
+ $skipped = $this->source->skip($length);
+ if (!PEAR::isError($skipped)) {
+ $this->leftLength -= $skipped;
+ }
+ return $skipped;
+ }
+
+ /**
+ * @see File_Archive_Reader::rewind()
+ */
+ function rewind($length = -1)
+ {
+ if ($length == -1) {
+ $length = $this->currentStat[7] - $this->leftLength;
+ } else {
+ $length = min($length, $this->currentStat[7] - $this->leftLength);
+ }
+ $rewinded = $this->source->rewind($length);
+ if (!PEAR::isError($rewinded)) {
+ $this->leftLength += $rewinded;
+ }
+ return $rewinded;
+ }
+
+ /**
+ * @see File_Archive_Reader::tell()
+ */
+ function tell()
+ {
+ return $this->currentStat[7] - $this->leftLength;
+ }
+
+ /**
+ * @see File_Archive_Reader::close()
+ */
+ function close()
+ {
+ $this->leftLength = 0;
+ $this->currentFilename = null;
+ $this->currentStat = null;
+ $this->seekToEnd = null;
+ return parent::close();
+ }
+
+ /**
+ * @see File_Archive_Reader::getFilename()
+ */
+ function getFilename() { return $this->currentFilename; }
+ /**
+ * @see File_Archive_Reader::getStat()
+ */
+ function getStat() { return $this->currentStat; }
+
+ /**
+ * @see File_Archive_Reader::next()
+ */
+ function next()
+ {
+ $error = parent::next();
+ if ($error !== true) {
+ return $error;
+ }
+ if ($this->seekToEnd !== null) {
+ return false;
+ }
+
+ do
+ {
+ $error = $this->source->skip($this->leftLength + $this->footerLength);
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+ $rawHeader = $this->source->getData(512);
+ if (PEAR::isError($rawHeader)) {
+ return $rawHeader;
+ }
+ if (strlen($rawHeader)<512 || $rawHeader == pack("a512", "")) {
+ $this->seekToEnd = strlen($rawHeader);
+ $this->currentFilename = null;
+ return false;
+ }
+
+ $header = unpack(
+ "a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/".
+ "a8checksum/a1type/a100linkname/a6magic/a2version/".
+ "a32uname/a32gname/a8devmajor/a8devminor/a155prefix",
+ $rawHeader);
+ $this->currentStat = array(
+ 2 => octdec($header['mode']),
+ 4 => octdec($header['uid']),
+ 5 => octdec($header['gid']),
+ 7 => octdec($header['size']),
+ 9 => octdec($header['mtime'])
+ );
+ $this->currentStat['mode'] = $this->currentStat[2];
+ $this->currentStat['uid'] = $this->currentStat[4];
+ $this->currentStat['gid'] = $this->currentStat[5];
+ $this->currentStat['size'] = $this->currentStat[7];
+ $this->currentStat['mtime'] = $this->currentStat[9];
+
+ if ($header['magic'] == 'ustar') {
+ $this->currentFilename = $this->getStandardURL(
+ $header['prefix'] . $header['filename']
+ );
+ } else {
+ $this->currentFilename = $this->getStandardURL(
+ $header['filename']
+ );
+ }
+
+ $this->leftLength = $this->currentStat[7];
+ if ($this->leftLength % 512 == 0) {
+ $this->footerLength = 0;
+ } else {
+ $this->footerLength = 512 - $this->leftLength%512;
+ }
+
+ $checksum = 8*ord(" ");
+ for ($i = 0; $i < 148; $i++) {
+ $checksum += ord($rawHeader{$i});
+ }
+ for ($i = 156; $i < 512; $i++) {
+ $checksum += ord($rawHeader{$i});
+ }
+
+ if (octdec($header['checksum']) != $checksum) {
+ die('Checksum error on entry '.$this->currentFilename);
+ }
+ } while ($header['type'] != 0);
+
+ return true;
+ }
+
+ /**
+ * @see File_Archive_Reader::getData()
+ */
+ function getData($length = -1)
+ {
+ if ($length == -1) {
+ $actualLength = $this->leftLength;
+ } else {
+ $actualLength = min($this->leftLength, $length);
+ }
+
+ if ($this->leftLength == 0) {
+ return null;
+ } else {
+ $data = $this->source->getData($actualLength);
+ if (strlen($data) != $actualLength) {
+ return PEAR::raiseError('Unexpected end of tar archive');
+ }
+ $this->leftLength -= $actualLength;
+ return $data;
+ }
+ }
+
+ /**
+ * @see File_Archive_Reader::makeWriterRemoveFiles()
+ */
+ function makeWriterRemoveFiles($pred)
+ {
+ require_once "File/Archive/Writer/Tar.php";
+
+ $blocks = array();
+ $seek = null;
+ $gap = 0;
+ if ($this->currentFilename !== null && $pred->isTrue($this)) {
+ $seek = 512 + $this->currentStat[7] + $this->footerLength;
+ $blocks[] = $seek; //Remove this file
+ }
+
+ while (($error = $this->next()) === true) {
+ $size = 512 + $this->currentStat[7] + $this->footerLength;
+ if ($pred->isTrue($this)) {
+ if ($seek === null) {
+ $seek = $size;
+ $blocks[] = $size;
+ } else if ($gap > 0) {
+ $blocks[] = $gap; //Don't remove the files between the gap
+ $blocks[] = $size;
+ $seek += $size;
+ } else {
+ $blocks[count($blocks)-1] += $size; //Also remove this file
+ $seek += $size;
+ }
+ $gap = 0;
+ } else {
+ if ($seek !== null) {
+ $seek += $size;
+ $gap += $size;
+ }
+ }
+ }
+ if ($seek === null) {
+ $seek = $this->seekToEnd;
+ } else {
+ $seek += $this->seekToEnd;
+ if ($gap == 0) {
+ array_pop($blocks);
+ } else {
+ $blocks[] = $gap;
+ }
+ }
+
+ $writer = new File_Archive_Writer_Tar(null,
+ $this->source->makeWriterRemoveBlocks($blocks, -$seek)
+ );
+ $this->close();
+ return $writer;
+ }
+
+ /**
+ * @see File_Archive_Reader::makeWriterRemoveBlocks()
+ */
+ function makeWriterRemoveBlocks($blocks, $seek = 0)
+ {
+ if ($this->seekToEnd !== null || $this->currentStat === null) {
+ return PEAR::raiseError('No file selected');
+ }
+
+ $blockPos = $this->currentStat[7] - $this->leftLength + $seek;
+
+ $this->rewind();
+ $keep = false;
+
+ $data = $this->getData($blockPos);
+ foreach ($blocks as $length) {
+ if ($keep) {
+ $data .= $this->getData($length);
+ } else {
+ $this->skip($length);
+ }
+ $keep = !$keep;
+ }
+ if ($keep) {
+ $data .= $this->getData();
+ }
+
+ $filename = $this->currentFilename;
+ $stat = $this->currentStat;
+
+ $writer = $this->makeWriterRemove();
+ if (PEAR::isError($writer)) {
+ return $writer;
+ }
+
+ unset($stat[7]);
+ $stat[9] = $stat['mtime'] = time();
+ $writer->newFile($filename, $stat);
+ $writer->writeData($data);
+ return $writer;
+ }
+
+ /**
+ * @see File_Archive_Reader::makeAppendWriter
+ */
+ function makeAppendWriter()
+ {
+ require_once "File/Archive/Writer/Tar.php";
+
+ while (($error = $this->next()) === true) { }
+ if (PEAR::isError($error)) {
+ $this->close();
+ return $error;
+ }
+
+ $innerWriter = $this->source->makeWriterRemoveBlocks(array(), -$this->seekToEnd);
+ if (PEAR::isError($innerWriter)) {
+ return $innerWriter;
+ }
+
+ $this->close();
+ return new File_Archive_Writer_Tar(null, $innerWriter);
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Reader/Uncompress.php b/thirdparty/pear/File/Archive/Reader/Uncompress.php
new file mode 100644
index 0000000..eb24ee3
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Reader/Uncompress.php
@@ -0,0 +1,312 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Uncompress.php,v 1.32 2005/07/09 12:54:35 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Reader.php";
+require_once "File/Archive/Reader/ChangeName.php";
+
+/**
+ * Recursively uncompress every file it finds
+ */
+class File_Archive_Reader_Uncompress extends File_Archive_Reader_Relay
+{
+ /**
+ * @var Array Stack of readers
+ * @access private
+ */
+ var $readers = array();
+
+ /**
+ * @var array of readers to close when closing $this
+ * @access private
+ */
+ var $toClose = array();
+
+ /**
+ * @var File_Archive_Reader Reader from which all started (usefull to be
+ * able to close)
+ * @access private
+ */
+ var $startReader;
+
+ /**
+ * @var Int Maximum depth of uncompression after the basicDir
+ * (that may contain some uncompression also)
+ * -1 means no limit
+ * @access private
+ */
+ var $uncompressionLevel;
+
+ /**
+ * @var array Only files starting with $baseDir will be reported
+ * This array contains explode('/', $directoryName)
+ * @access private
+ */
+ var $baseDir = '';
+
+ /**
+ * @var int Compression level required to go to reach the baseDir
+ * or null if it is currently being computed
+ * @access private
+ */
+ var $baseDirCompressionLevel = null;
+
+ /**
+ * @var int We are selecting substr($baseDir, 0, $baseDirProgression)
+ */
+ var $baseDirProgression = 0;
+
+ /**
+ * @var boolean Flag set to indicate that the current file has not been
+ * displayed
+ */
+ var $currentFileNotDisplayed = false;
+
+ function File_Archive_Reader_Uncompress(
+ &$innerReader, $uncompressionLevel = -1)
+ {
+ parent::File_Archive_Reader_Relay($innerReader);
+ $this->startReader =& $innerReader;
+ $this->uncompressionLevel = $uncompressionLevel;
+ }
+
+ /**
+ * Attempt to change the current source (if the current file is an archive)
+ * If this is the case, push the current source onto the stack and make the
+ * good archive reader the current source. A file is considered as an
+ * archive if its extension is one of tar, gz, zip, tgz
+ *
+ * @return bool whether the source has been pushed or not
+ * @access private
+ */
+ function push()
+ {
+ if ($this->uncompressionLevel >= 0 &&
+ $this->baseDirCompressionLevel !== null &&
+ count($this->readers) >= $this->uncompressionLevel
+ ) {
+ return false;
+ }
+
+ // Check the extension of the file (maybe we need to uncompress it?)
+ $filename = $this->source->getFilename();
+
+ $extensions = explode('.', strtolower($filename));
+
+ $reader =& $this->source;
+ $nbUncompressions = 0;
+
+ while (($extension = array_pop($extensions)) !== null) {
+ $nbUncompressions++;
+ unset($next);
+ $next = File_Archive::readArchive($extension, $reader, $nbUncompressions == 1);
+ if ($next === false) {
+ $extensions = array();
+ } else {
+ unset($reader);
+ $reader =& $next;
+ }
+ }
+ if ($nbUncompressions == 1) {
+ return false;
+ } else {
+ $this->readers[count($this->readers)] =& $this->source;
+ unset($this->source);
+ $this->source = new File_Archive_Reader_AddBaseName(
+ $filename, $reader
+ );
+ return true;
+ }
+ }
+ /**
+ * @see File_Archive_Reader::close()
+ */
+ function next()
+ {
+ if ($this->currentFileNotDisplayed) {
+ $this->currentFileNotDisplayed = false;
+ return true;
+ }
+
+ do {
+ do {
+ $selection = substr($this->baseDir, 0, $this->baseDirProgression);
+ if ($selection === false) {
+ $selection = '';
+ }
+
+ $error = $this->source->select($selection, false);
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+ if (!$error) {
+ if (empty($this->readers)) {
+ return false;
+ }
+ $this->source->close();
+ unset($this->source);
+ $this->source =& $this->readers[count($this->readers)-1];
+ unset($this->readers[count($this->readers)-1]);
+ }
+ } while (!$error);
+
+ $filename = $this->source->getFilename();
+ if (strlen($filename) < strlen($this->baseDir)) {
+ $goodFile = (strncmp($filename, $this->baseDir, strlen($filename)) == 0 &&
+ $this->baseDir{strlen($filename)} == '/');
+ if ($goodFile) {
+ if (strlen($filename) + 2 < strlen($this->baseDirProgression)) {
+ $this->baseDirProgression = strpos($this->baseDir, '/', strlen($filename)+2);
+ if ($this->baseDirProgression === false) {
+ $this->baseDirProgression = strlen($this->baseDir);
+ }
+ } else {
+ $this->baseDirProgression = strlen($this->baseDir);
+ }
+ }
+ } else {
+ $goodFile = (strncmp($filename, $this->baseDir, strlen($this->baseDir)) == 0);
+ if ($goodFile) {
+ $this->baseDirProgression = strlen($this->baseDir);
+ }
+ }
+ } while ($goodFile && $this->push());
+
+ return true;
+ }
+
+ /**
+ * Efficiently filter out the files which URL does not start with $baseDir
+ * Throws an error if the $baseDir can't be found
+ * @return bool Whether baseDir was a directory or a file
+ */
+ function setBaseDir($baseDir)
+ {
+ $this->baseDir = $baseDir;
+ $this->baseDirProgression = strpos($baseDir, '/');
+ if ($this->baseDirProgression === false) {
+ $this->baseDirProgression = strlen($baseDir);
+ }
+
+ $error = $this->next();
+ if ($error === false) {
+ return PEAR::raiseError("No directory $baseDir in inner reader");
+ } else if (PEAR::isError($error)) {
+ return $error;
+ }
+
+ $this->currentFileNotDisplayed = true;
+ return strlen($this->getFilename())>strlen($baseDir);
+ }
+ /**
+ * @see File_Archive_Reader::select()
+ */
+ function select($filename, $close = true)
+ {
+ if ($close) {
+ $error = $this->close();
+ if (PEAR::isError($close)) {
+ return $error;
+ }
+ }
+
+ $oldBaseDir = $this->baseDir;
+ $oldProgression = $this->baseDirProgression;
+
+ $this->baseDir = $filename;
+ $this->baseDirProgression = 0;
+
+ $res = $this->next();
+
+ $this->baseDir = $oldBaseDir;
+ $this->baseDirProgression = $oldProgression;
+
+ return $res;
+ }
+
+ /**
+ * @see File_Archive_Reader::close()
+ */
+ function close()
+ {
+ for ($i=0; $ireaders); ++$i) {
+ $this->readers[$i]->close();
+ }
+ //var_dump($this->toClose);
+ for ($i=0; $itoClose); ++$i) {
+ if ($this->toClose[$i] !== null) {
+ $this->toClose[$i]->close();
+ }
+ }
+
+ $this->readers = array();
+ $this->toClose = array();
+ $error = parent::close();
+ $this->baseDirCompressionLevel = null;
+ $this->baseDirProgression = 0;
+
+ unset($this->source);
+ $this->source =& $this->startReader;
+ $this->source->close();
+ $this->currentFileNotDisplayed = false;
+
+ return $error;
+ }
+
+ /**
+ * @see File_Archive_Reader::makeAppendWriter()
+ */
+ function makeAppendWriter()
+ {
+ //The reader needs to be open so that the base dir is found
+ $error = $this->next();
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+
+ return parent::makeAppendWriter();
+ }
+
+ /**
+ * @see File_Archive_Reader::makeWriterRemoveFiles()
+ */
+ function makeWriterRemoveFiles($pred)
+ {
+ //The reader needs to be open so that the base dir is found
+ $error = $this->next();
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+
+ return parent::makeWriterRemoveFiles($pred);
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Reader/Zip.php b/thirdparty/pear/File/Archive/Reader/Zip.php
new file mode 100644
index 0000000..44d8aad
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Reader/Zip.php
@@ -0,0 +1,493 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Zip.php,v 1.26 2005/06/19 20:09:58 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Reader/Archive.php";
+
+/**
+ * ZIP archive reader
+ * Currently only allows to browse the archive (getData is not available)
+ */
+class File_Archive_Reader_Zip extends File_Archive_Reader_Archive
+{
+ var $currentFilename = null;
+ var $currentStat = null;
+ var $header = null;
+ var $offset = 0;
+ var $data = null;
+ var $files = array();
+ var $seekToEnd = 0;
+
+ var $centralDirectory = null;
+
+ /**
+ * @see File_Archive_Reader::close()
+ */
+ function close()
+ {
+ $this->currentFilename = null;
+ $this->currentStat = null;
+ $this->compLength = 0;
+ $this->data = null;
+ $this->seekToEnd = 0;
+ $this->files = array();
+ $this->centralDirectory = null;
+
+ return parent::close();
+ }
+
+ /**
+ * @see File_Archive_Reader::getFilename()
+ */
+ function getFilename() { return $this->currentFilename; }
+ /**
+ * @see File_Archive_Reader::getStat()
+ */
+ function getStat() { return $this->currentStat; }
+
+ /**
+ * Go to next entry in ZIP archive
+ * This function may stop on a folder, so it does not comply to the
+ * File_Archive_Reader::next specs
+ *
+ * @see File_Archive_Reader::next()
+ */
+ function nextWithFolders()
+ {
+ if ($this->seekToEnd > 0) {
+ return false;
+ }
+
+ //Skip the data and the footer if they haven't been uncompressed
+ if ($this->header !== null && $this->data === null) {
+ $toSkip = $this->header['CLen'];
+ $error = $this->source->skip($toSkip);
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+ }
+
+ $this->offset = 0;
+ $this->data = null;
+
+ //Read the header
+ $header = $this->source->getData(4);
+ if (PEAR::isError($header)) {
+ return $header;
+ }
+ if ($header == "\x50\x4b\x03\x04") {
+ //New entry
+ $header = $this->source->getData(26);
+ if (PEAR::isError($header)) {
+ return $header;
+ }
+ $this->header = unpack(
+ "vVersion/vFlag/vMethod/vTime/vDate/VCRC/VCLen/VNLen/vFile/vExtra",
+ $header);
+
+ //Check the compression method
+ if ($this->header['Method'] != 0 &&
+ $this->header['Method'] != 8 &&
+ $this->header['Method'] != 12) {
+ return PEAR::raiseError("File_Archive_Reader_Zip doesn't ".
+ "handle compression method {$this->header['Method']}");
+ }
+ if ($this->header['Flag'] & 1) {
+ return PEAR::raiseError("File_Archive_Reader_Zip doesn't ".
+ "handle encrypted files");
+ }
+ if ($this->header['Flag'] & 8) {
+ if ($this->centralDirectory === null) {
+ $this->readCentralDirectory();
+ }
+ $centralDirEntry = $this->centralDirectory[count($this->files)];
+
+ $this->header['CRC'] = $centralDirEntry['CRC'];
+ $this->header['CLen'] = $centralDirEntry['CLen'];
+ $this->header['NLen'] = $centralDirEntry['NLen'];
+ }
+ if ($this->header['Flag'] & 32) {
+ return PEAR::raiseError("File_Archive_Reader_Zip doesn't ".
+ "handle compressed patched data");
+ }
+ if ($this->header['Flag'] & 64) {
+ return PEAR::raiseError("File_Archive_Reader_Zip doesn't ".
+ "handle strong encrypted files");
+ }
+
+ $this->currentStat = array(
+ 7=>$this->header['NLen'],
+ 9=>mktime(
+ ($this->header['Time'] & 0xF800) >> 11, //hour
+ ($this->header['Time'] & 0x07E0) >> 5, //minute
+ ($this->header['Time'] & 0x001F) >> 1, //second
+ ($this->header['Date'] & 0x01E0) >> 5, //month
+ ($this->header['Date'] & 0x001F) , //day
+ (($this->header['Date'] & 0xFE00) >> 9) + 1980 //year
+ )
+ );
+ $this->currentStat['size'] = $this->currentStat[7];
+ $this->currentStat['mtime'] = $this->currentStat[9];
+
+ $this->currentFilename = $this->source->getData($this->header['File']);
+
+ $error = $this->source->skip($this->header['Extra']);
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+
+ $this->files[] = array('name' => $this->currentFilename,
+ 'stat' => $this->currentStat,
+ 'CRC' => $this->header['CRC'],
+ 'CLen' => $this->header['CLen']
+ );
+
+ return true;
+ } else {
+ //Begining of central area
+ $this->seekToEnd = 4;
+ $this->currentFilename = null;
+ return false;
+ }
+ }
+ /**
+ * Go to next file entry in ZIP archive
+ * This function will not stop on a folder entry
+ * @see File_Archive_Reader::next()
+ */
+ function next()
+ {
+ if (!parent::next()) {
+ return false;
+ }
+
+ do {
+ $result = $this->nextWithFolders();
+ if ($result !== true) {
+ return $result;
+ }
+ } while (substr($this->getFilename(), -1) == '/');
+
+ return true;
+ }
+
+ /**
+ * @see File_Archive_Reader::getData()
+ */
+ function getData($length = -1)
+ {
+ if ($this->offset >= $this->currentStat[7]) {
+ return null;
+ }
+
+ if ($length>=0) {
+ $actualLength = min($length, $this->currentStat[7]-$this->offset);
+ } else {
+ $actualLength = $this->currentStat[7]-$this->offset;
+ }
+
+ $error = $this->uncompressData();
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+ $result = substr($this->data, $this->offset, $actualLength);
+ $this->offset += $actualLength;
+ return $result;
+ }
+ /**
+ * @see File_Archive_Reader::skip()
+ */
+ function skip($length = -1)
+ {
+ $before = $this->offset;
+ if ($length == -1) {
+ $this->offset = $this->currentStat[7];
+ } else {
+ $this->offset = min($this->offset + $length, $this->currentStat[7]);
+ }
+ return $this->offset - $before;
+ }
+ /**
+ * @see File_Archive_Reader::rewind()
+ */
+ function rewind($length = -1)
+ {
+ $before = $this->offset;
+ if ($length == -1) {
+ $this->offset = 0;
+ } else {
+ $this->offset = min(0, $this->offset - $length);
+ }
+ return $before - $this->offset;
+ }
+ /**
+ * @see File_Archive_Reader::tell()
+ */
+ function tell()
+ {
+ return $this->offset;
+ }
+
+ function uncompressData()
+ {
+ if ($this->data !== null)
+ return;
+
+ $this->data = $this->source->getData($this->header['CLen']);
+ if (PEAR::isError($this->data)) {
+ return $this->data;
+ }
+ if ($this->header['Method'] == 8) {
+ $this->data = gzinflate($this->data);
+ }
+ if ($this->header['Method'] == 12) {
+ $this->data = bzdecompress($this->data);
+ }
+
+ if (crc32($this->data) != $this->header['CRC']) {
+ return PEAR::raiseError("Zip archive: CRC fails on entry ".
+ $this->currentFilename);
+ }
+ }
+
+ /**
+ * @see File_Archive_Reader::makeWriterRemoveFiles()
+ */
+ function makeWriterRemoveFiles($pred)
+ {
+ require_once "File/Archive/Writer/Zip.php";
+
+ $blocks = array();
+ $seek = null;
+ $gap = 0;
+ if ($this->currentFilename !== null && $pred->isTrue($this)) {
+ $seek = 30 + $this->header['File'] + $this->header['Extra'] + $this->header['CLen'];
+ $blocks[] = $seek; //Remove this file
+ array_pop($this->files);
+ }
+
+ while (($error = $this->nextWithFolders()) === true) {
+ $size = 30 + $this->header['File'] + $this->header['Extra'] + $this->header['CLen'];
+ if (substr($this->getFilename(), -1) == '/' || $pred->isTrue($this)) {
+ array_pop($this->files);
+ if ($seek === null) {
+ $seek = $size;
+ $blocks[] = $size;
+ } else if ($gap > 0) {
+ $blocks[] = $gap; //Don't remove the files between the gap
+ $blocks[] = $size;
+ $seek += $size;
+ } else {
+ $blocks[count($blocks)-1] += $size; //Also remove this file
+ $seek += $size;
+ }
+ $gap = 0;
+ } else {
+ if ($seek !== null) {
+ $seek += $size;
+ $gap += $size;
+ }
+ }
+ }
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+
+ if ($seek === null) {
+ $seek = 4;
+ } else {
+ $seek += 4;
+ if ($gap == 0) {
+ array_pop($blocks);
+ } else {
+ $blocks[] = $gap;
+ }
+ }
+
+ $writer = new File_Archive_Writer_Zip(null,
+ $this->source->makeWriterRemoveBlocks($blocks, -$seek)
+ );
+ if (PEAR::isError($writer)) {
+ return $writer;
+ }
+
+ foreach ($this->files as $file) {
+ $writer->alreadyWrittenFile($file['name'], $file['stat'], $file['CRC'], $file['CLen']);
+ }
+
+ $this->close();
+ return $writer;
+ }
+
+ /**
+ * @see File_Archive_Reader::makeWriterRemoveBlocks()
+ */
+ function makeWriterRemoveBlocks($blocks, $seek = 0)
+ {
+ if ($this->currentFilename === null) {
+ return PEAR::raiseError('No file selected');
+ }
+
+ $keep = false;
+
+ $this->uncompressData();
+ $newData = substr($this->data, 0, $this->offset + $seek);
+ $this->data = substr($this->data, $this->offset + $seek);
+ foreach ($blocks as $length) {
+ if ($keep) {
+ $newData .= substr($this->data, 0, $length);
+ }
+ $this->data = substr($this->data, $length);
+ $keep = !$keep;
+ }
+ if ($keep) {
+ $newData .= $this->data;
+ }
+
+ $filename = $this->currentFilename;
+ $stat = $this->currentStat;
+
+ $writer = $this->makeWriterRemove();
+ if (PEAR::isError($writer)) {
+ return $writer;
+ }
+
+ unset($stat[7]);
+ $stat[9] = $stat['mtime'] = time();
+ $writer->newFile($filename, $stat);
+ $writer->writeData($newData);
+ return $writer;
+ }
+
+ /**
+ * @see File_Archive_Reader::makeAppendWriter
+ */
+ function makeAppendWriter()
+ {
+ require_once "File/Archive/Writer/Zip.php";
+
+ while (($error = $this->next()) === true) { }
+ if (PEAR::isError($error)) {
+ $this->close();
+ return $error;
+ }
+
+ $writer = new File_Archive_Writer_Zip(null,
+ $this->source->makeWriterRemoveBlocks(array(), -4)
+ );
+
+ foreach ($this->files as $file) {
+ $writer->alreadyWrittenFile($file['name'], $file['stat'], $file['CRC'], $file['CLen']);
+ }
+
+ $this->close();
+ return $writer;
+ }
+
+ /**
+ * This function seeks to the start of the [end of central directory] field,
+ * just after the \x50\x4b\x05\x06 signature and returns the number of bytes
+ * skipped
+ *
+ * The stream must initially be positioned before the end of central directory
+ */
+ function seekToEndOfCentralDirectory()
+ {
+ $nbSkipped = $this->source->skip();
+
+ $nbSkipped -= $this->source->rewind(22) - 4;
+ if ($this->source->getData(4) == "\x50\x4b\x05\x06") {
+ return $nbSkipped;
+ }
+
+ while ($nbSkipped > 0) {
+
+ $nbRewind = $this->source->rewind(min(100, $nbSkipped));
+ while ($nbRewind >= -4) {
+ if ($nbRewind-- && $this->source->getData(1) == "\x50" &&
+ $nbRewind-- && $this->source->getData(1) == "\x4b" &&
+ $nbRewind-- && $this->source->getData(1) == "\x05" &&
+ $nbRewind-- && $this->source->getData(1) == "\x06") {
+ //We finally found it!
+ return $nbSkipped - $nbRewind;
+ }
+ }
+ $nbSkipped -= $nbRewind;
+ }
+
+ return PEAR::raiseError('End of central directory not found. The file is probably not a zip archive');
+ }
+
+ /**
+ * This function will fill the central directory variable
+ * and seek back to where it was called
+ */
+ function readCentralDirectory()
+ {
+ $nbSkipped = $this->seekToEndOfCentralDirectory();
+ if (PEAR::isError($nbSkipped)) {
+ return $nbSkipped;
+ }
+
+ $this->source->skip(12);
+ $offset = $this->source->getData(4);
+ $nbSkipped += 16;
+ if (PEAR::isError($offset)) {
+ return $offset;
+ }
+
+ $offset = unpack("Vvalue", $offset);
+ $offset = $offset['value'];
+
+ $current = $this->source->tell();
+ $nbSkipped -= $this->source->rewind($current - $offset);
+
+ //Now we are the right pos to read the central directory
+ $this->centralDirectory = array();
+ while ($this->source->getData(4) == "\x50\x4b\x01\x02") {
+ $this->source->skip(12);
+ $header = $this->source->getData(16);
+ $nbSkipped += 32;
+
+ if (PEAR::isError($header)) {
+ return $header;
+ }
+
+ $header = unpack('VCRC/VCLen/VNLen/vFileLength/vExtraLength', $header);
+ $this->centralDirectory[] = array('CRC' => $header['CRC'],
+ 'CLen' => $header['CLen'],
+ 'NLen' => $header['NLen']);
+ $nbSkipped += $this->source->skip(14 + $header['FileLength'] + $header['ExtraLength']);
+ }
+
+ $this->source->rewind($nbSkipped+4);
+ }
+}
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Writer.php b/thirdparty/pear/File/Archive/Writer.php
new file mode 100644
index 0000000..3785f07
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Writer.php
@@ -0,0 +1,119 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Writer.php,v 1.12 2005/05/31 21:22:02 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "PEAR.php";
+
+/**
+ * Base class for any writer
+ */
+class File_Archive_Writer
+{
+ /**
+ * Create a new file in the writer
+ *
+ * @param string $filename Name of the file, eventually including a path
+ * @param array $stat Its Statistics. None of the indexes are required
+ * @param string $mime MIME type of the file
+ */
+ function newFile($filename, $stat = array(), $mime = "application/octet-stream")
+ {
+ }
+
+ /**
+ * Create a new file in the writer with the content of the physical file $filename
+ * and then unlink $filename.
+ * newFromTempFile($tmpfile, $filename, $stat, $mime) is equivalent to
+ * newFile($filename, $stat, $mime); writeFile($tmpfile); unlink($tmpfile);
+ * but can be more efficient.
+ * A typical use is for File_Archive_Writer_Files: it renames the temporary
+ * file instead of copy/delete
+ *
+ * @param string $tmpfile Name of the physical file that contains data and will be unlinked
+ * @param string $filename Name of the file, eventually including a path
+ * @param array $stat Its Statistics. None of the indexes are required
+ * @param string $mime MIME type of the file
+ */
+ function newFromTempFile($tmpfile, $filename, $stat = array(), $mime = "application/octet-stream")
+ {
+ $this->newFile($filename, $stat, $mime);
+ $this->writeFile($tmpfile);
+ unlink($tmpfile);
+ }
+
+ /**
+ * Returns whether the writer newFile function needs the $mime parameter
+ * Default is false
+ */
+ function newFileNeedsMIME()
+ {
+ return false;
+ }
+
+ /**
+ * Append the specified data to the writer
+ *
+ * @param String $data the data to append to the writer
+ */
+ function writeData($data)
+ {
+ }
+
+ /**
+ * Append the content of the physical file $filename to the writer
+ * writeFile($filename) must be equivalent to
+ * writeData(file_get_contents($filename)) but can be more efficient
+ *
+ * @param string $filename Name of the file which content must be appended
+ * to the writer
+ */
+ function writeFile($filename)
+ {
+ $handle = fopen($filename, "r");
+ if (!is_resource($handle)) {
+ return PEAR::raiseError("Unable to write to $filename");
+ }
+ while (!feof($handle)) {
+ $error = $this->writeData(fread($handle, 102400));
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+ }
+ fclose($handle);
+ }
+
+ /**
+ * Close the writer, eventually flush the data, write the footer...
+ * This function must be called before the end of the script
+ */
+ function close() { }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Writer/AddBaseName.php b/thirdparty/pear/File/Archive/Writer/AddBaseName.php
new file mode 100644
index 0000000..7444ca6
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Writer/AddBaseName.php
@@ -0,0 +1,102 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: AddBaseName.php,v 1.1 2005/06/02 22:45:58 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Writer.php";
+
+/**
+ * Writer wrapper that adds a directory to the written file
+ */
+class File_Archive_Writer_AddBaseName
+{
+ var $writer;
+ var $baseName;
+
+ function File_Archive_Writer_AddBaseName($baseName, &$writer)
+ {
+ if (substr($baseName, -1) == '/') {
+ $this->baseName = $baseName;
+ } else {
+ $this->baseName = $baseName.'/';
+ }
+
+ $this->writer =& $writer;
+ }
+
+ /**
+ * @see File_Archive_Writer::newFile()
+ */
+ function newFile($filename, $stat = array(), $mime = "application/octet-stream")
+ {
+ $this->writer->newFile($this->baseName.$filename, $stat, $mime);
+ }
+
+ /**
+ * @see File_Archive_Writer::newFromTempFile()
+ */
+ function newFromTempFile($tmpfile, $filename, $stat = array(), $mime = "application/octet-stream")
+ {
+ $this->writer->newFromTempFile($tmpfilen $this->baseName.$filename, $stat, $mime);
+ }
+
+ /**
+ * @see File_Archive_Writer::newFileNeedsMIME()
+ */
+ function newFileNeedsMIME()
+ {
+ return $this->writer->newFileNeedsMIME();
+ }
+
+ /**
+ * @see File_Archive_Writer::writeData()
+ */
+ function writeData($data)
+ {
+ $this->writer->writeData($data);
+ }
+
+ /**
+ * @see File_Archive_Writer::writeFile()
+ */
+ function writeFile($filename)
+ {
+ $this->writer->writeFile($filename);
+ }
+
+ /**
+ * @see File_Archive_Writer::close()
+ */
+ function close()
+ {
+ $this->writer->close();
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Writer/Ar.php b/thirdparty/pear/File/Archive/Writer/Ar.php
new file mode 100644
index 0000000..5ddc051
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Writer/Ar.php
@@ -0,0 +1,204 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id:
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Writer/Archive.php";
+
+/**
+ * Write the files as an AR archive
+ */
+class File_Archive_Writer_Ar extends File_Archive_Writer_Archive
+{
+
+ /**
+ * @var string Current data of the file.
+ * @access private
+ */
+ var $_buffer = "";
+
+ /**
+ * @var string Filename of the current filename
+ * @access private
+ */
+ var $_currentFilename = null;
+
+ /**
+ * @var boolean Flag: use buffer or not.
+ * @access private
+ */
+ var $_useBuffer;
+
+ /**
+ * @var array Stats of the current filename
+ * @access private
+ */
+ var $_currentStat = array ();
+
+ /**
+ * @var boolean Flag: beginning of the archive or not
+ * @access private
+ */
+ var $_atStart = true;
+
+ /**
+ * Returns the header of the current file.
+ *
+ * More Info:
+ * http://publibn.boulder.ibm.com/doc_link/en_US/a_doc_lib/files/aixfiles/ar_IA64.htm
+ *
+ * @access private
+ * @param string $filename Name of the current file
+ * @param array $stat Stat array of the current file
+ * @return string The built header struct
+ */
+ function arHeader ($filename, $stat)
+ {
+ $mode = isset($stat[2]) ? $stat[2] : 0x8000;
+ $uid = isset($stat[4]) ? $stat[4] : 0;
+ $gid = isset($stat[5]) ? $stat[5] : 0;
+ $size = $stat[7];
+ $time = isset($stat[9]) ? $stat[9] : time();
+
+ $struct = "";
+ $currentSize = $size;
+ //if file length is > than 16..
+ if (strlen($filename) > 16) {
+ $currentSize += strlen($filename);
+ $struct .= sprintf("#1/%-13d", strlen($filename));
+ $struct .= sprintf("%-12d%-6d%-6d%-8s%-10d",
+ $time, $uid, $gid, $mode, $currentSize);
+ $struct .= "`\n".$filename;
+ } else {
+ $struct .= sprintf("%-16s", $filename);
+ $struct .= sprintf("%-12d%-6d%-6d%-8s%-10d`\n",
+ $time, $uid, $gid, $mode, $size);
+ }
+ return $struct;
+ }
+
+ /**
+ * Returns the footer of the current file, the footer depends
+ * of the size of the file
+ *
+ * @access private
+ * @param string $filename Name of the file, the footer depends on its length
+ * @param int $size Size of the current file, here the size does matters!
+ * @return string The footer struct
+ */
+ function arFooter($filename, $size)
+ {
+ $size = (strlen ($filename) > 16) ? $size + strlen($filename) : $size;
+
+ return ($size % 2 == 1) ? "\n" : "";
+ }
+
+
+ /**
+ * Flush the memory we have in the ar.
+ *
+ * Build the buffer if its called at the end or initialize
+ * it if we are just creating it from the start.
+ */
+ function flush()
+ {
+ if ($this->_atStart) {
+ $this->innerWriter->writeData("!\n");
+ $this->_atStart = false;
+ }
+ if ($this->_currentFilename !== null) {
+ $this->_currentStat[7] = strlen($this->_buffer);
+ if ($this->_useBuffer) {
+ $this->innerWriter->writeData(
+ $this->arHeader($this->_currentFilename, $this->_currentStat)
+ );
+ $this->innerWriter->writeData($this->_buffer);
+ }
+ $this->innerWriter->writeData($this->arFooter($this->_currentFilename, $this->_currentStat[7]));
+ }
+ $this->_buffer = "";
+ }
+
+ /**
+ * @see File_Archive_Writer::newFile()
+ *
+ */
+ function newFile($filename, $stat = array (),
+ $mime = "application/octet-stream")
+ {
+ $this->flush();
+ /*
+ * If the file is empty, there's no reason to have a buffer
+ * or use memory
+ */
+ $this->_useBuffer = !isset($stats[7]);
+ /*
+ * Becaue ar fileformats doesn't support files in directories,
+ * then we need to just save with the filename an ommit the
+ * directory
+ */
+ $this->_currentFilename = basename($filename);
+ $this->_currentStat = $stat;
+
+ if(!$this->_useBuffer) {
+ return $this->innerWriter->writeData($this->arHeader($filename, $stat));
+ }
+ }
+
+ /**
+ * @see File_Archive_Writer::close()
+ */
+ function close()
+ {
+ $this->flush();
+ parent::close();
+ }
+
+ /**
+ * @see File_Archive_Writer::writeData()
+ */
+ function writeData($data)
+ {
+ if ($this->_useBuffer) {
+ $this->_buffer .= $data;
+ } else {
+ $this->innerWriter->writeData($data);
+ }
+
+ }
+ /**
+ * @see File_Archive_Writer::writeFile()
+ */
+ function writeFile($filename)
+ {
+ if ($this->_useBuffer) {
+ $this->_buffer .= file_get_contents($filename);
+ } else {
+ $this->innerWriter->writeFile($filename);
+ }
+ }
+}
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Writer/Archive.php b/thirdparty/pear/File/Archive/Writer/Archive.php
new file mode 100644
index 0000000..8efe7af
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Writer/Archive.php
@@ -0,0 +1,99 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Archive.php,v 1.12 2005/06/02 12:24:43 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Writer.php";
+
+/**
+ * Base class for all the transformation writers that will generate one single
+ * file
+ */
+class File_Archive_Writer_Archive extends File_Archive_Writer
+{
+ /**
+ * @var File_Archive_Writer The compressed data will be written to this
+ * writer
+ * @access protected
+ */
+ var $innerWriter;
+
+ /**
+ * @var bool If true, the innerWriter will be closed when closing this
+ * @access private
+ */
+ var $autoClose;
+
+ /**
+ * @param String $filename Name to give to the archive (the name will
+ * be used by the inner writer)
+ * If $filename is null, the innerWriter is considered already
+ * opened (and thus newFile will not be called)
+ * @param File_Archive_Writer $innerWriter The inner writer to which the
+ * compressed data will be written
+ * @param array $stat The stat of the archive (see the PHP stat() function).
+ * No element are required in this array
+ * @param bool $autoClose Indicate if the inner writer must be closed when
+ * closing this
+ */
+ function File_Archive_Writer_Archive($filename, &$innerWriter,
+ $stat = array(), $autoClose = true)
+ {
+ $this->innerWriter =& $innerWriter;
+ $this->autoClose = $autoClose;
+ if ($filename !== null) {
+ $this->innerWriter->newFile($filename, $stat, $this->getMime());
+ }
+ }
+
+//MUST REWRITE FUNCTIONS
+ //function newFile($filename, $stat, $mime) { }
+
+ /**
+ * @return the MIME extension of the files generated by this writer
+ */
+ function getMime() { return "application/octet-stream"; }
+
+ /**
+ * @see File_Archive_Writer::close()
+ */
+ function close()
+ {
+ if ($this->autoClose) {
+ return $this->innerWriter->close();
+ }
+ }
+// function writeData($data)
+
+//SHOULD REWRITE FUNCTIONS
+// function writeFile($filename)
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Writer/Bzip2.php b/thirdparty/pear/File/Archive/Writer/Bzip2.php
new file mode 100644
index 0000000..5832c02
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Writer/Bzip2.php
@@ -0,0 +1,137 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Bzip2.php,v 1.9 2005/06/02 16:22:47 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Writer.php";
+
+/**
+ * Compress a single file to Bzip2 format
+ */
+class File_Archive_Writer_Bzip2 extends File_Archive_Writer
+{
+ var $compressionLevel=9;
+ var $bzfile;
+ var $tmpName;
+ var $nbFiles = 0;
+
+ var $innerWriter;
+ var $autoClose;
+ var $filename;
+ var $stat;
+
+ /**
+ * @param string $filename Name to give to the archive
+ * @param File_Archive_Writer $innerWriter The inner writer to which the
+ * compressed data will be written
+ * @param array $stat The stat of the archive (see the PHP stat() function).
+ * No element are required in this array
+ * @param bool $autoClose Indicate if the inner writer must be closed when
+ * closing this
+ */
+ function File_Archive_Writer_Bzip2($filename, &$innerWriter,
+ $stat = array(), $autoClose = true)
+ {
+ $this->innerWriter =& $innerWriter;
+ $this->autoClose = $autoClose;
+
+ $this->filename = $filename;
+ $this->stat = $stat;
+
+ if ($this->filename === null) {
+ $this->newFile(null);
+ }
+ }
+
+ /**
+ * Set the compression level
+ *
+ * @param int $compressionLevel From 0 (no compression) to 9 (best
+ * compression)
+ */
+ function setCompressionLevel($compressionLevel)
+ {
+ $this->compressionLevel = $compressionLevel;
+ }
+
+ /**
+ * @see File_Archive_Writer::newFile()
+ *
+ * Check that one single file is written in the BZip2 archive
+ */
+ function newFile($filename, $stat = array(),
+ $mime = "application/octet-stream")
+ {
+ if ($this->nbFiles > 1) {
+ return PEAR::raiseError("A Bzip2 archive can only contain one single file.".
+ "Use Tbz archive to be able to write several files");
+ }
+ $this->nbFiles++;
+
+ $this->tmpName = tempnam(File_Archive::getOption('tmpDirectory'), 'far');
+ $this->bzfile = bzopen($this->tmpName, 'w'.$this->compressionLevel);
+
+ return true;
+ }
+
+ /**
+ * Actually write the tmp file to the inner writer
+ * Close and delete temporary file
+ *
+ * @see File_Archive_Writer::close()
+ */
+ function close()
+ {
+ bzclose($this->bzfile);
+
+ if ($this->filename === null) {
+ //Assume innerWriter is already opened on a file...
+ $this->innerWriter->writeFile($this->tmpName);
+ unlink($this->tmpName);
+ } else {
+ $this->innerWriter->newFromTempFile(
+ $this->tmpName, $this->filename, $this->stat, 'application/x-compressed'
+ );
+ }
+
+ if ($this->autoClose) {
+ return $this->innerWriter->close();
+ }
+ }
+
+ /**
+ * @see File_Archive_Writer::writeData()
+ */
+ function writeData($data)
+ {
+ bzwrite($this->bzfile, $data);
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Writer/Files.php b/thirdparty/pear/File/Archive/Writer/Files.php
new file mode 100644
index 0000000..501fbb6
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Writer/Files.php
@@ -0,0 +1,250 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Files.php,v 1.21 2005/06/18 23:08:16 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Writer.php";
+
+/**
+ * Writer to files
+ */
+class File_Archive_Writer_Files extends File_Archive_Writer
+{
+ /**
+ * @var Object Handle to the file where the data are currently written
+ * @access private
+ */
+ var $handle = null;
+ var $basePath;
+ var $stat = array();
+ var $filename;
+
+ function File_Archive_Writer_Files($base = '')
+ {
+ if ($base === null || $base == '') {
+ $this->basePath = '';
+ } else {
+ if (substr($base, -1) == '/') {
+ $this->basePath = $base;
+ } else {
+ $this->basePath = $base.'/';
+ }
+ }
+ }
+
+ function getFilename($filename)
+ {
+ return $this->basePath.$filename;
+ }
+
+ /**
+ * Ensure that $pathname exists, or create it if it does not
+ * @access private
+ */
+ function mkdirr($pathname)
+ {
+ // Check if directory already exists
+ if (is_dir($pathname) || empty($pathname)) {
+ return;
+ }
+
+ // Ensure a file does not already exist with the same name
+ if (is_file($pathname)) {
+ return PEAR::raiseError(
+ "File $pathname exists, unable to create directory"
+ );
+ }
+
+ // Crawl up the directory tree
+ $next_pathname = substr(
+ $pathname,
+ 0, strrpos($pathname, "/"));
+ $error = $this->mkdirr($next_pathname);
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+ if (!@mkdir($pathname)) {
+ return PEAR::raiseError("Unable to create directory $pathname");
+ }
+ }
+
+ /**
+ * Open a file for writing from a given position
+ *
+ * @param string $filename The name of the file to open
+ * @param int $pos the initial position in the file
+ * @param $stat the stats of the file
+ */
+ function openFile($filename, $pos = 0)
+ {
+ $this->close();
+
+ $this->handle = fopen($filename, 'r+');
+ $this->stat = array();
+ $this->filename = $filename;
+
+ if (!is_resource($this->handle)) {
+ return PEAR::raiseError("Unable to open file $filename");
+ }
+
+ if ($pos > 0) {
+ if (fseek($this->handle, $pos) == -1) {
+ fread($this->handle, $pos);
+ }
+ }
+ }
+
+ /**
+ * Open a file for appending after having removed a block of data from it
+ * See File_Archive_Reader::makeWriterRemoveBlocks
+ */
+ function openFileRemoveBlock($filename, $pos, $blocks)
+ {
+ $error = $this->openFile($filename, $pos);
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+
+ if (!empty($blocks)) {
+ //This will be used to read the initial file
+ //The data, with the unusefull block removed will be written to $this->handle
+ $read = fopen($filename, 'r');
+ if ($pos > 0) {
+ if (fseek($this->handle, $pos) == -1) {
+ fread($this->handle, $pos);
+ }
+ }
+
+ $keep = false;
+ $data = '';
+ foreach ($blocks as $length) {
+ if ($keep) {
+ while ($length > 0 &&
+ ($data = fread($read, min($length, 8192))) != '') {
+ $length -= strlen($data);
+ fwrite($this->handle, $data);
+ }
+ } else {
+ fseek($read, $length, SEEK_CUR);
+ }
+ $keep = !$keep;
+ }
+ if ($keep) {
+ while(!feof($this->handle)) {
+ fwrite($this->handle, fread($read, 8196));
+ }
+ }
+
+ fclose($read);
+ }
+
+ ftruncate($this->handle, ftell($this->handle));
+ }
+
+
+ /**
+ * @see File_Archive_Writer::newFile()
+ */
+ function newFile($filename, $stat = array(), $mime = "application/octet-stream")
+ {
+ $this->close();
+ $this->stat = $stat;
+ $this->filename = $this->getFilename($filename);
+
+ $pos = strrpos($this->filename, "/");
+ if ($pos !== false) {
+ $error = $this->mkdirr(substr($this->filename, 0, $pos));
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+ }
+ $this->handle = @fopen($this->filename, "w");
+ if (!is_resource($this->handle)) {
+ return PEAR::raiseError("Unable to write to file $filename");
+ }
+ }
+ /**
+ * @see File_Archive_Writer::writeData()
+ */
+ function writeData($data) { fwrite($this->handle, $data); }
+ /**
+ * @see File_Archive_Writer::newFromTempFile()
+ */
+ function newFromTempFile($tmpfile, $filename, $stat = array(), $mime = "application/octet-stream")
+ {
+ $this->filename = filename;
+ $complete = $this->getFilename($filename);
+ $pos = strrpos($complete, "/");
+ if ($pos !== false) {
+ $error = $this->mkdirr(substr($complete, 0, $pos));
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+ }
+
+ if ((file_exists($complete) && !@unlink($complete)) ||
+ !@rename($tmpfile, $complete)) {
+ return parent::newFromTempFile($tmpfile, $filename, $stat, $mime);
+ }
+ }
+
+
+ /**
+ * @see File_Archive_Writer::close()
+ */
+ function close()
+ {
+ if ($this->handle !== null) {
+ fclose($this->handle);
+ $this->handle = null;
+
+ if (isset($this->stat[9])) {
+ if (isset($this->stat[8])) {
+ touch($this->filename, $this->stat[9], $this->stat[8]);
+ } else {
+ touch($this->filename, $this->stat[9]);
+ }
+ } else if (isset($this->stat[8])) {
+ touch($this->filename, time(), $this->stat[8]);
+ }
+
+ if (isset($this->stat[2])) {
+ chmod($this->filename, $this->stat[2]);
+ }
+ if (isset($this->stat[5])) {
+ chgrp($this->filename, $this->stat[5]);
+ }
+ if (isset($this->stat[4])) {
+ chown($this->filename, $this->stat[4]);
+ }
+ }
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Writer/Gzip.php b/thirdparty/pear/File/Archive/Writer/Gzip.php
new file mode 100644
index 0000000..e6cded6
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Writer/Gzip.php
@@ -0,0 +1,139 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Gzip.php,v 1.15 2005/06/02 16:22:48 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Writer.php";
+
+/**
+ * Compress a single file to Gzip format
+ */
+class File_Archive_Writer_Gzip extends File_Archive_Writer
+{
+ var $compressionLevel=9;
+ var $gzfile;
+ var $tmpName;
+ var $nbFiles = 0;
+
+ var $innerWriter;
+ var $autoClose;
+ var $filename;
+ var $stat;
+
+ /**
+ * @param string $filename Name to give to the archive
+ * @param File_Archive_Writer $innerWriter The inner writer to which the
+ * compressed data will be written
+ * @param array $stat The stat of the archive (see the PHP stat() function).
+ * No element are required in this array
+ * @param bool $autoClose Indicate if the inner writer must be closed when
+ * closing this
+ */
+ function File_Archive_Writer_Gzip($filename, &$innerWriter,
+ $stat = array(), $autoClose = true)
+ {
+ $this->innerWriter =& $innerWriter;
+ $this->autoClose = $autoClose;
+
+ $this->filename = $filename;
+ $this->stat = $stat;
+
+ if ($this->filename === null) {
+ $this->newFile(null);
+ }
+
+ $compressionLevel = File_Archive::getOption('gzCompressionLevel', 9);
+ }
+
+ /**
+ * Set the compression level
+ *
+ * @param int $compressionLevel From 0 (no compression) to 9 (best
+ * compression)
+ */
+ function setCompressionLevel($compressionLevel)
+ {
+ $this->compressionLevel = $compressionLevel;
+ }
+
+ /**
+ * @see File_Archive_Writer::newFile()
+ *
+ * Check that one single file is written in the GZip archive
+ */
+ function newFile($filename, $stat = array(),
+ $mime = "application/octet-stream")
+ {
+ if ($this->nbFiles > 1) {
+ return PEAR::raiseError("A Gz archive can only contain one single file.".
+ "Use Tgz archive to be able to write several files");
+ }
+ $this->nbFiles++;
+
+ $this->tmpName = tempnam(File_Archive::getOption('tmpDirectory'), 'far');
+ $this->gzfile = gzopen($this->tmpName, 'w'.$this->compressionLevel);
+
+ return true;
+ }
+
+
+ /**
+ * Actually write the tmp file to the inner writer
+ * Close and delete temporary file
+ *
+ * @see File_Archive_Writer::close()
+ */
+ function close()
+ {
+ gzclose($this->gzfile);
+ if ($this->filename === null) {
+ //Assume innerWriter is already opened on a file...
+ $this->innerWriter->writeFile($this->tmpName);
+ unlink($this->tmpName);
+ } else {
+ $this->innerWriter->newFromTempFile(
+ $this->tmpName, $this->filename, $this->stat, 'application/x-compressed'
+ );
+ }
+
+ if ($this->autoClose) {
+ return $this->innerWriter->close();
+ }
+ }
+
+ /**
+ * @see File_Archive_Writer::writeData()
+ */
+ function writeData($data)
+ {
+ gzwrite($this->gzfile, $data);
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Writer/Mail.php b/thirdparty/pear/File/Archive/Writer/Mail.php
new file mode 100644
index 0000000..fd1e51c
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Writer/Mail.php
@@ -0,0 +1,200 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Mail.php,v 1.11 2005/06/02 12:24:43 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Writer.php";
+require_once "Mail.php";
+require_once "Mail/mime.php";
+
+/**
+ * Send the files attached to a mail.
+ */
+class File_Archive_Writer_Mail extends File_Archive_Writer
+{
+ /**
+ * @var Mail_mime object
+ * @access private
+ */
+ var $mime;
+
+ /**
+ * @var Mail object used to send email (built thanks to the factory)
+ * @access private
+ */
+ var $mail;
+
+ /**
+ * @var Array or String An array or a string with comma separated recipients
+ * @access private
+ */
+ var $to;
+
+ /**
+ * @var Array The headers that will be passed to the Mail_mime object
+ * @access private
+ */
+ var $headers;
+
+ /**
+ * @var String Data read from the current file so far
+ * @access private
+ */
+ var $currentData = null;
+
+ /**
+ * @var String Name of the file being attached
+ * @access private
+ */
+ var $currentFilename = null;
+
+ /**
+ * @var String MIME of the file being attached
+ * @access private
+ */
+ var $currentMime = null;
+
+ /**
+ * @param Mail $mail Object used to send mail (see Mail::factory)
+ * @param array or string $to An array or a string with comma separated
+ * recipients
+ * @param array $headers The headers that will be passed to the Mail_mime
+ * object
+ * @param string $message Text body of the mail
+ */
+ function File_Archive_Writer_Mail($to, $headers, $message, &$mail)
+ {
+ $this->mime = new Mail_mime();
+ $this->mime->setTXTBody($message);
+ if (!empty($htmlMessage)) {
+ $this->mime->setHTMLBody($htmlMessage);
+ }
+
+ if ($mail === null)
+ $this->mail = Mail::factory("mail");
+ else
+ $this->mail =& $mail;
+
+ $this->to = $to;
+ $this->headers = $headers;
+ }
+
+ /**
+ * @see Mail_Mime::setHTMLBody()
+ */
+ function setHTMLBody($data, $isfile = false)
+ {
+ return $this->mime->setHTMLBody($data, $isfile);
+ }
+ /**
+ * @see Mail_Mime::addHTMLImage()
+ */
+ function addHTMLImage($file, $c_type = 'application/octet-stream',
+ $name = '', $isfile = true)
+ {
+ return $this->mime->addHTMLImage($file, $c_type, $name, $isfile);
+ }
+
+ /**
+ * @see File_Archive_Writer::writeData()
+ *
+ * This function just put the data in $currentData until the end of file
+ * At that time, addCurrentData is called to attach $currentData to the mail
+ * and to clear $currentData for a new file
+ */
+ function writeData($data)
+ {
+ $this->currentData .= $data;
+ }
+ /**
+ * Called when a file is finished and must be added as attachment to the mail
+ */
+ function addCurrentData()
+ {
+ if ($this->currentFilename === null) {
+ return;
+ }
+
+ $error = $this->mime->addAttachment(
+ $this->currentData,
+ $this->currentMime,
+ $this->currentFilename,
+ false);
+ $this->currentData = "";
+ return $error;
+ }
+ /**
+ * @see File_Archive_Writer::newFile()
+ */
+ function newFile($filename, $stat, $mime = "application/octet-stream")
+ {
+ $error = $this->addCurrentData();
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+
+ $this->currentFilename = $filename;
+ $this->currentMime = $mime;
+ }
+ /**
+ * @see File_Archive_Writer::newFileNeedsMIME()
+ */
+ function newFileNeedsMIME()
+ {
+ return true;
+ }
+
+ /**
+ * @see File_Archive_Writer::close()
+ */
+ function close()
+ {
+ $error = parent::close();
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+ $error = $this->addCurrentData();
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+
+ $body = $this->mime->get();
+ $headers = $this->mime->headers($this->headers);
+
+ if (!$this->mail->send(
+ $this->to,
+ $headers,
+ $body)
+ ) {
+ return PEAR::raiseError("Error sending mail");
+ }
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Writer/Memory.php b/thirdparty/pear/File/Archive/Writer/Memory.php
new file mode 100644
index 0000000..6faba95
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Writer/Memory.php
@@ -0,0 +1,127 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Memory.php,v 1.14 2005/06/02 12:24:43 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Writer.php";
+
+/**
+ * Write the concatenation of the files in a buffer
+ */
+class File_Archive_Writer_Memory extends File_Archive_Writer
+{
+ /**
+ * @var string $data The buffer
+ * @access private
+ */
+ var $data = "";
+ /**
+ * Information about the file being written into this writer
+ * @access private
+ */
+ var $filename;
+ var $stat;
+ var $mime;
+
+ /**
+ * @param reference $data If provided, the data will be output in this
+ * variable. Any existent data in $data will be overwritten by the
+ * actual data of the writer. You should not modify manually this
+ * variable while using this writer (you can safely use all the
+ * functions of the archive, like clear for example)
+ * @param int keptData is the offset from where to start writing in $data
+ * Any data located after $seek will be erased
+ * The default value is 0
+ */
+ function File_Archive_Writer_Memory(&$data, $seek = 0)
+ {
+ $this->data =& $data;
+ $this->data = substr($data, 0, $seek);
+ }
+
+ function writeData($d) { $this->data .= $d; }
+
+ /**
+ * @see File_Archive_Writer::newFile()
+ */
+ function newFile($filename, $stat, $mime = "application/octet-stream")
+ {
+ $this->filename = $filename;
+ $this->stat = $stat;
+ $this->mime = $mime;
+ }
+ /**
+ * @see File_Archive_Writer::newFileNeedsMIME
+ */
+ function newFileNeedsMIME()
+ {
+ return true;
+ }
+
+ /**
+ * Retrieve the concatenated data
+ * The value is returned by reference for performance problems, but you
+ * should not manually modify it
+ *
+ * @return string buffer
+ */
+ function &getData() { return $this->data; }
+
+ /**
+ * Clear the buffer
+ */
+ function clear() { $this->data = ""; }
+
+ /**
+ * Returns true iif the buffer is empty
+ */
+ function isEmpty() { return empty($this->data); }
+
+ /**
+ * Create a reader from this writer
+ *
+ * @param string $filename Name of the file provided by the reader
+ * @param array $stat Statistics of the file provided by the reader
+ * @param string $mime Mime type of the file provided by the reader
+ *
+ * Any unspecified parameter will be set to the value of the last file
+ * written in this writer
+ */
+ function makeReader($filename = null, $stat = null, $mime = null)
+ {
+ require_once "File/Archive/Reader/Memory.php";
+ return new File_Archive_Reader_Memory(
+ $this->data,
+ $filename === null ? $this->filename : $filename,
+ $stat === null ? $this->stat : $stat,
+ $mime === null ? $this->mime : $mime);
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Writer/MemoryArchive.php b/thirdparty/pear/File/Archive/Writer/MemoryArchive.php
new file mode 100644
index 0000000..51687ea
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Writer/MemoryArchive.php
@@ -0,0 +1,213 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: MemoryArchive.php,v 1.16 2005/06/02 12:24:43 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Writer/Archive.php";
+require_once "File/Archive/Writer/Memory.php";
+
+/**
+ * Base class for all the archiveWriters that can only work on complete files
+ * (the write data function may be called with small chunks of data)
+ */
+class File_Archive_Writer_MemoryArchive extends File_Archive_Writer_Archive
+{
+ /**
+ * @var File_Archive_Writer_Memory A buffer where the data will be put
+ * waiting for the file to be complete
+ * @access private
+ */
+ var $buffer = '';
+ /**
+ * @var string Name of the file which data are coming
+ * @access private
+ */
+ var $currentFilename = null;
+ /**
+ * @var array Stats of the file which data are coming
+ * @access private
+ */
+ var $currentStat = null;
+ /**
+ * @var string URL of the file being treated if it is a physical file
+ * @access private
+ */
+ var $currentDataFile = null;
+ /**
+ * @var int Number of times newFile function has been called
+ * @access protected
+ */
+ var $nbFiles = 0;
+
+ /**
+ * @see File_Archive_Writer::File_Archive_Writer()
+ */
+ function File_Archive_Writer_MemoryArchive
+ ($filename, &$t, $stat = array(), $autoClose = true)
+ {
+ parent::File_Archive_Writer_Archive($filename, $t, $stat, $autoClose);
+ }
+
+ /**
+ * @see File_Archive_Writer::newFile()
+ */
+ function newFile($filename, $stat = array(),
+ $mime = "application/octet-stream")
+ {
+ if ($this->nbFiles == 0) {
+ $error = $this->sendHeader();
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+ } else {
+ $error = $this->flush();
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+ }
+
+ $this->nbFiles++;
+
+ $this->currentFilename = $filename;
+ $this->currentStat = $stat;
+
+ return true;
+ }
+ /**
+ * @see File_Archive_Writer::close()
+ */
+ function close()
+ {
+ $error = $this->flush();
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+ $error = $this->sendFooter();
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+
+ return parent::close();
+ }
+ /**
+ * Indicate that all the data have been read from the current file
+ * and send it to appendFileData
+ * Send the current data to the appendFileData function
+ *
+ * @access private
+ */
+ function flush()
+ {
+ if ($this->currentFilename !== null) {
+ if ($this->currentDataFile !== null) {
+ $error = $this->appendFile($this->currentFilename,
+ $this->currentDataFile);
+ } else {
+ $error = $this->appendFileData($this->currentFilename,
+ $this->currentStat,
+ $this->buffer);
+ }
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+
+ $this->currentFilename = null;
+ $this->currentDataFile = null;
+ $this->buffer = '';
+ }
+ }
+ /**
+ * @see File_Archive_Writer::writeData()
+ */
+ function writeData($data)
+ {
+ if ($this->currentDataFile !== null) {
+ $this->buffer .= file_get_contents($this->currentDataFile);
+ $this->currentDataFile = null;
+ }
+ $this->buffer .= $data;
+ }
+ /**
+ * @see File_Archive_Writer::writeFile()
+ */
+ function writeFile($filename)
+ {
+ if ($this->currentDataFile === null && empty($this->buffer)) {
+ $this->currentDataFile = $filename;
+ } else {
+ if ($this->currentDataFile !== null) {
+ $this->buffer .= file_get_contents($this->currentDataFile);
+ $this->currentDataFile = null;
+ }
+ $this->buffer .= file_get_contents($filename);
+ }
+ }
+
+//MUST REWRITE FUNCTIONS
+ /**
+ * The subclass must treat the data $data
+ * $data is the entire data of the filename $filename
+ * $stat is the stat of the file
+ *
+ * @access protected
+ */
+ function appendFileData($filename, $stat, &$data) { }
+
+//SHOULD REWRITE FUNCTIONS
+ /**
+ * The subclass may rewrite the sendHeader function if it needs to execute
+ * code before the first file
+ *
+ * @access protected
+ */
+ function sendHeader() { }
+ /**
+ * The subclass may rewrite the sendFooter function if it needs to execute
+ * code before closing the archive
+ *
+ * @access protected
+ */
+ function sendFooter() { }
+ /**
+ * The subclass may rewrite this class if it knows an efficient way to treat
+ * a physical file.
+ *
+ * @access protected
+ */
+ function appendFile($filename, $dataFilename)
+ {
+ return $this->appendFileData(
+ $filename,
+ stat($dataFilename),
+ file_get_contents($dataFilename));
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Writer/Multi.php b/thirdparty/pear/File/Archive/Writer/Multi.php
new file mode 100644
index 0000000..2e21d8b
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Writer/Multi.php
@@ -0,0 +1,130 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Multi.php,v 1.10 2005/06/05 18:19:33 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Writer.php";
+
+/**
+ * Write to several writers
+ */
+class File_Archive_Writer_Multi extends File_Archive_Writer
+{
+ /**
+ * @var File_Archive_Writer_Writer Data will be copied to these two writers
+ * @access private
+ */
+ var $writers;
+
+ function addWriter(&$writer)
+ {
+ $this->writers[] =& $writer;
+ }
+
+ /**
+ * @see File_Archive_Writer::newFile()
+ */
+ function newFile($filename, $stat = array(), $mime = "application/octet-stream")
+ {
+ $globalError = null;
+ foreach($this->writers as $key => $foo) {
+ $error = $this->writers[$key]->newFile($filename, $stat, $mime);
+ if (PEAR::isError($error)) {
+ $globalError = $error;
+ }
+ }
+ if (PEAR::isError($globalError)) {
+ return $globalError;
+ }
+ }
+ /**
+ * @see File_Archive_Writer::newFileNeedsMIME()
+ */
+ function newFileNeedsMIME()
+ {
+ foreach($this->writers as $key => $foo) {
+ if ($this->writers[$key]->newFileNeedsMIME()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @see File_Archive_Writer::writeData()
+ */
+ function writeData($data)
+ {
+ $globalError = null;
+ foreach($this->writers as $key => $foo) {
+ $error = $this->writers[$key]->writeData($data);
+ if (PEAR::isError($error)) {
+ $globalError = $error;
+ }
+ }
+ if (PEAR::isError($globalError)) {
+ return $globalError;
+ }
+ }
+
+ /**
+ * @see File_Archive_Writer::writeFile()
+ */
+ function writeFile($filename)
+ {
+ $globalError = null;
+ foreach($this->writers as $key => $foo) {
+ $error = $this->writers[$key]->writeFile($filename);
+ if (PEAR::isError($error)) {
+ $globalError = $error;
+ }
+ }
+ if (PEAR::isError($globalError)) {
+ return $globalError;
+ }
+ }
+
+ /**
+ * @see File_Archive_Writer::close()
+ */
+ function close()
+ {
+ $globalError = null;
+ foreach($this->writers as $key => $foo) {
+ $error = $this->writers[$key]->close();
+ if (PEAR::isError($error)) {
+ $globalError = $error;
+ }
+ }
+ if (PEAR::isError($globalError)) {
+ return $globalError;
+ }
+ }
+}
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Writer/Output.php b/thirdparty/pear/File/Archive/Writer/Output.php
new file mode 100644
index 0000000..61db440
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Writer/Output.php
@@ -0,0 +1,93 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Output.php,v 1.8 2005/05/30 15:25:14 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Writer.php";
+
+/**
+ * Writer to the standard output
+ * It will concatenate the files that it receive
+ * It may send some headers, but will do so only for the first file
+ */
+class File_Archive_Writer_Output extends File_Archive_Writer
+{
+ /**
+ * @var bool If true, the Content-type and Content-disposition headers
+ * will be sent. The file will be considered as an attachment and
+ * the MIME will be deduced from its extension
+ * @access private
+ */
+ var $sendHeaders;
+
+ /**
+ * @param $sendHeaders see the variable
+ */
+ function File_Archive_Writer_Output($sendHeaders = true)
+ {
+ $this->sendHeaders = $sendHeaders;
+ }
+ /**
+ * @see File_Archive_Writer::newFile()
+ */
+ function newFile($filename, $stat = array(), $mime = "application/octet-stream")
+ {
+ if ($this->sendHeaders) {
+ if(headers_sent()) {
+ return PEAR::raiseError(
+ 'The headers have already been sent. '.
+ 'Use File_Archive::toOutput(false) to write '.
+ 'to output without sending headers');
+ }
+
+ header("Content-type: $mime");
+ header("Content-disposition: attachment; filename=$filename");
+ $this->sendHeaders = false;
+ }
+ }
+ /**
+ * @see File_Archive_Writer::newFileNeedsMIME
+ */
+ function newFileNeedsMIME()
+ {
+ return $this->sendHeaders;
+ }
+ /**
+ * @see File_Archive_Writer::writeData()
+ */
+ function writeData($data) { echo $data; }
+ /**
+ * @see File_Archive_Writer::writeFile()
+ */
+ function writeFile($filename) { readfile($filename); }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Writer/Tar.php b/thirdparty/pear/File/Archive/Writer/Tar.php
new file mode 100644
index 0000000..cca3c23
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Writer/Tar.php
@@ -0,0 +1,224 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Tar.php,v 1.18 2005/06/02 12:24:43 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Writer/Archive.php";
+
+/**
+ * Write the files as a TAR archive
+ */
+class File_Archive_Writer_Tar extends File_Archive_Writer_Archive
+{
+ var $buffer;
+ var $useBuffer;
+
+ var $filename = null;
+ var $stats = null;
+
+
+ /**
+ * Creates the TAR header for a file
+ *
+ * @param string $filename name of the file
+ * @param array $stat statistics of the file
+ * @return string A 512 byte header for the file
+ * @access private
+ */
+ function tarHeader($filename, $stat)
+ {
+ $mode = isset($stat[2]) ? $stat[2] : 0x8000;
+ $uid = isset($stat[4]) ? $stat[4] : 0;
+ $gid = isset($stat[5]) ? $stat[5] : 0;
+ $size = $stat[7];
+ $time = isset($stat[9]) ? $stat[9] : time();
+ $link = "";
+
+ if ($mode & 0x4000) {
+ $type = 5; // Directory
+ } else if ($mode & 0x8000) {
+ $type = 0; // Regular
+ } else if ($mode & 0xA000) {
+ $type = 1; // Link
+ $link = @readlink($current);
+ } else {
+ $type = 9; // Unknown
+ }
+
+ $filePrefix = '';
+ if (strlen($filename) > 255) {
+ return PEAR::raiseError(
+ "$filename is too long to be put in a tar archive"
+ );
+ } else if (strlen($filename) > 100) {
+ $filePrefix = substr($filename, 0, strlen($filename)-100);
+ $filename = substr($filename, -100);
+ }
+
+ $blockbeg = pack("a100a8a8a8a12a12",
+ $filename,
+ decoct($mode),
+ sprintf("%6s ",decoct($uid)),
+ sprintf("%6s ",decoct($gid)),
+ sprintf("%11s ",decoct($size)),
+ sprintf("%11s ",decoct($time))
+ );
+
+ $blockend = pack("a1a100a6a2a32a32a8a8a155a12",
+ $type,
+ $link,
+ "ustar",
+ "00",
+ "Unknown",
+ "Unknown",
+ "",
+ "",
+ $filePrefix,
+ "");
+
+ $checksum = 8*ord(" ");
+ for ($i = 0; $i < 148; $i++) {
+ $checksum += ord($blockbeg{$i});
+ }
+ for ($i = 0; $i < 356; $i++) {
+ $checksum += ord($blockend{$i});
+ }
+
+ $checksum = pack("a8",sprintf("%6s ",decoct($checksum)));
+
+ return $blockbeg . $checksum . $blockend;
+ }
+ /**
+ * Creates the TAR footer for a file
+ *
+ * @param int $size the size of the data that has been written to the TAR
+ * @return string A string made of less than 512 characteres to fill the
+ * last 512 byte long block
+ * @access private
+ */
+ function tarFooter($size)
+ {
+ if ($size % 512 > 0) {
+ return pack("a".(512 - $size%512), "");
+ } else {
+ return "";
+ }
+ }
+
+ function flush()
+ {
+ if ($this->filename !== null) {
+ if ($this->useBuffer) {
+ $this->stats[7] = strlen($this->buffer);
+
+ $this->innerWriter->writeData(
+ $this->tarHeader($this->filename, $this->stats)
+ );
+ $this->innerWriter->writeData(
+ $this->buffer
+ );
+ }
+ $this->innerWriter->writeData(
+ $this->tarFooter($this->stats[7])
+ );
+ }
+ $this->buffer = "";
+ }
+
+ function newFile($filename, $stats = array(),
+ $mime = "application/octet-stream")
+ {
+ $this->flush();
+
+ $this->useBuffer = !isset($stats[7]);
+ $this->filename = $filename;
+ $this->stats = $stats;
+
+ if (!$this->useBuffer) {
+ return $this->innerWriter->writeData(
+ $this->tarHeader($filename, $stats)
+ );
+ }
+ }
+
+ /**
+ * @see File_Archive_Writer::close()
+ */
+ function close()
+ {
+ $this->flush();
+ $this->innerWriter->writeData(pack("a1024", ""));
+ parent::close();
+ }
+ /**
+ * @see File_Archive_Writer::writeData()
+ */
+ function writeData($data)
+ {
+ if ($this->useBuffer) {
+ $this->buffer .= $data;
+ } else {
+ $this->innerWriter->writeData($data);
+ }
+
+ }
+ /**
+ * @see File_Archive_Writer::writeFile()
+ */
+ function writeFile($filename)
+ {
+ if ($this->useBuffer) {
+ $this->buffer .= file_get_contents($filename);
+ } else {
+ $this->innerWriter->writeFile($filename);
+ }
+ }
+ /**
+ * @see File_Archive_Writer::getMime()
+ */
+ function getMime() { return "application/x-tar"; }
+}
+
+
+/**
+ * A tar archive cannot contain files with name of folders longer than 255 chars
+ * This filter removes them
+ *
+ * @see File_Archive_Predicate, File_Archive_Reader_Filter
+ */
+require_once "File/Archive/Predicate.php";
+class File_Archive_Predicate_TARCompatible extends File_Archive_Predicate
+{
+ function isTrue($source)
+ {
+ return strlen($source->getFilename()) <= 255;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Writer/UniqueAppender.php b/thirdparty/pear/File/Archive/Writer/UniqueAppender.php
new file mode 100644
index 0000000..07116a8
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Writer/UniqueAppender.php
@@ -0,0 +1,143 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: UniqueAppender.php,v 1.1 2005/05/30 19:44:53 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Writer.php";
+require_once "File/Archive/Reader.php";
+require_once "File/Archive/Predicate/Index.php";
+
+/**
+ * A writer wrapper that will remove the files the eventual duplicate
+ * files from the reader to keep only the new ones
+ * If there were already some duplications in the provided reader, not
+ * all duplication will be removed
+ * If you use newFile with the same filename several file, only the latest
+ * write will be kept (no time comparision is done)
+ */
+class File_Archive_Writer_UniqueAppender extends File_Archive_Writer
+{
+ var $reader;
+ var $writer;
+ var $fileList = array();
+ var $toDelete = array();
+
+ /**
+ * Construct a unique writer that will write to the specified writer
+ * and remove duplicate files from the reader on close
+ */
+ function File_Archive_Writer_UniqueAppender(&$reader)
+ {
+ $reader->close();
+ $pos = 0;
+ while ($reader->next()) {
+ $this->fileList[$reader->getFilename()] = $pos++;
+ }
+
+ $this->reader =& $reader;
+ $this->writer = $reader->makeAppendWriter();
+ }
+
+ /**
+ * @see File_Archive_Writer::newFile()
+ */
+ function newFile($filename, $stat = array(), $mime = "application/octet-stream")
+ {
+ if (isset($this->fileList[$filename])) {
+ $this->toDelete[$this->fileList[$filename]] = true;
+ }
+
+ return $this->writer->newFile($filename, $stat, $mime);
+ }
+
+ /**
+ * @see File_Archive_Writer::newFromTempFile()
+ */
+ function newFromTempFile($tmpfile, $filename, $stat = array(), $mime = "application/octet-stream")
+ {
+ if (isset($this->fileList[$filename])) {
+ $this->toDelete[$this->fileList[$filename]] = true;
+ }
+
+ return $this->writer->newFromTempFile($tmpfile, $filename, $stat, $mime);
+ }
+
+ /**
+ * @see File_Archive_Writer::newFileNeedsMIME()
+ */
+ function newFileNeedsMIME()
+ {
+ return $this->writer->newFileNeedsMIME();
+ }
+
+ /**
+ * @see File_Archive_Writer::writeData()
+ */
+ function writeData($data)
+ {
+ return $this->writer->writeData($data);
+ }
+
+ /**
+ * @see File_Archive_Writer::writeFile()
+ */
+ function writeFile($filename)
+ {
+ return $this->writer->writeFile($filename);
+ }
+
+ /**
+ * Close the writer, eventually flush the data, write the footer...
+ * This function must be called before the end of the script
+ */
+ function close()
+ {
+ $error = $this->writer->close();
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+
+ if (!empty($this->toDelete)) {
+ $tmp = $this->reader->makeWriterRemoveFiles(
+ new File_Archive_Predicate_Index($this->toDelete)
+ );
+ if (PEAR::isError($tmp)) {
+ return $tmp;
+ }
+
+ return $tmp->close();
+ }
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/File/Archive/Writer/Zip.php b/thirdparty/pear/File/Archive/Writer/Zip.php
new file mode 100644
index 0000000..ac6ee1b
--- /dev/null
+++ b/thirdparty/pear/File/Archive/Writer/Zip.php
@@ -0,0 +1,260 @@
+
+ * @copyright 1997-2005 The PHP Group
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ * @version CVS: $Id: Zip.php,v 1.20 2005/08/15 18:03:03 vincentlascaux Exp $
+ * @link http://pear.php.net/package/File_Archive
+ */
+
+require_once "File/Archive/Writer/MemoryArchive.php";
+
+/**
+ * ZIP archive writer
+ */
+class File_Archive_Writer_Zip extends File_Archive_Writer_MemoryArchive
+{
+ /**
+ * @var int Compression level
+ * @access private
+ */
+ var $compressionLevel;
+
+ /**
+ * @var int Current position in the writer
+ * @access private
+ */
+ var $offset = 0;
+
+ /**
+ * @var string Optionnal comment to add to the zip
+ * @access private
+ */
+ var $comment = "";
+
+ /**
+ * @var string Data written at the end of the ZIP file
+ * @access private
+ */
+ var $central = "";
+
+ function File_Archive_Writer_Zip($filename, &$innerWriter,
+ $stat=array(), $autoClose = true)
+ {
+ global $_File_Archive_Options;
+ parent::File_Archive_Writer_MemoryArchive(
+ $filename, $innerWriter, $stat, $autoClose
+ );
+
+ $this->compressionLevel = File_Archive::getOption('zipCompressionLevel', 9);
+ }
+
+ /**
+ * Change the level of the compression. This may be done between two files
+ *
+ * @param Int $compressionLevel New compression level from 0 to 9
+ */
+ function setCompressionLevel($compressionLevel)
+ {
+ $this->compressionLevel = $compressionLevel;
+ }
+
+ /**
+ * Set a comment on the ZIP file
+ */
+ function setComment($comment) { $this->comment = $comment; }
+
+ /**
+ * @param int $time Unix timestamp of the date to convert
+ * @return the date formated as a ZIP date
+ */
+ function getMTime($time)
+ {
+ $mtime = ($time !== null ? getdate($time) : getdate());
+ $mtime = preg_replace(
+ "/(..){1}(..){1}(..){1}(..){1}/",
+ "\\x\\4\\x\\3\\x\\2\\x\\1",
+ dechex(($mtime['year']-1980<<25)|
+ ($mtime['mon' ]<<21)|
+ ($mtime['mday' ]<<16)|
+ ($mtime['hours' ]<<11)|
+ ($mtime['minutes']<<5)|
+ ($mtime['seconds']>>1)));
+ eval('$mtime = "'.$mtime.'";');
+ return $mtime;
+ }
+
+ /**
+ * Inform the archive that $filename is present.
+ * Consequences are the same as appendFileData, but no data is output
+ * to the inner writer.
+ * This is used by File_Archive_Reader_Zip::makeWriter()
+ *
+ * @param string $filename name of the file
+ * @param array $stat stats of the file, indexes 9 and 7 must be present
+ * @param int $crc32 checksum of the file
+ * @param int $compLength length of the compressed data
+ */
+ function alreadyWrittenFile($filename, $stat, $crc32, $complength)
+ {
+ $filename = preg_replace("/^(\.{1,2}(\/|\\\))+/","",$filename);
+
+ $mtime = $this->getMTime(isset($stat[9]) ? $stat[9] : null);
+ $normlength = $stat[7];
+
+ $this->nbFiles++;
+
+ $this->central .= "\x50\x4b\x01\x02\x00\x00\x14\x00\x00\x00\x08\x00".
+ $mtime.
+ pack("VVVvvvvvVV",
+ $crc32, $complength, $normlength,
+ strlen($filename), 0x00,0x00,0x00,0x00,
+ 0x0000,$this->offset).
+ $filename;
+
+ $this->offset += 30 + strlen($filename) + $complength;
+ }
+
+ /**
+ * @see File_Archive_Writer_MemoryArchive::appendFileData()
+ * @access protected
+ */
+ function appendFileData($filename, $stat, $data)
+ {
+ $crc32 = crc32($data);
+ $normlength = strlen($data);
+ $data = gzcompress($data,$this->compressionLevel);
+ $data = substr($data,2,strlen($data)-6);
+
+ return $this->appendCompressedData($filename, $stat, $data, $crc32, $normlength);
+ }
+
+ function appendCompressedData($filename, $stat, $data, $crc32, $normlength)
+ {
+ $filename = preg_replace("/^(\.{1,2}(\/|\\\))+/","",$filename);
+ $mtime = $this->getMTime(isset($stat[9]) ? $stat[9] : null);
+
+ $complength = strlen($data);
+
+ $zipData = "\x50\x4b\x03\x04\x14\x00\x00\x00\x08\x00".
+ $mtime.
+ pack("VVVvv",
+ $crc32,
+ $complength,
+ $normlength,
+ strlen($filename),
+ 0x00).
+ $filename.
+ $data;
+
+ $error = $this->innerWriter->writeData($zipData);
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+
+ $this->central .= "\x50\x4b\x01\x02\x00\x00\x14\x00\x00\x00\x08\x00".
+ $mtime.
+ pack("VVVvvvvvVV",
+ $crc32, $complength, $normlength,
+ strlen($filename), 0x00,0x00,0x00,0x00,
+ 0x0000,$this->offset).
+ $filename;
+
+ $this->offset += strlen($zipData);
+ }
+
+ function appendFile($filename, $dataFilename)
+ {
+ //Try to read from the cache
+ $cache = File_Archive::getOption('cache', null);
+ if ($cache !== null && $this->compressionLevel > 0) {
+ $id = realpath($dataFilename);
+ $id = urlencode($id);
+ $id = str_replace('_', '%5F', $id);
+
+ $group = 'FileArchiveZip'.$this->compressionLevel;
+ $mtime = filemtime($dataFilename);
+
+ //Tries to read from cache
+ if (($data = $cache->get($id, $group)) !== false) {
+ $info = unpack('Vmtime/Vcrc/Vnlength', substr($data, 0, 12));
+ $data = substr($data, 12);
+ }
+
+ //If cache failed or file modified since then
+ if ($data === false ||
+ $info['mtime'] != $mtime) {
+
+ $data = file_get_contents($dataFilename);
+
+ $info = array(
+ 'crc' => crc32($data),
+ 'nlength' => strlen($data),
+ 'mtime' => $mtime
+ );
+
+ $data = gzcompress($data,$this->compressionLevel);
+ $data = substr($data,2,strlen($data)-6);
+ $data = pack('VVV', $info['mtime'], $info['crc'], $info['nlength']).$data;
+ $cache->save($data, $id, $group);
+ }
+
+ return $this->appendCompressedData(
+ $filename,
+ stat($dataFilename),
+ $data,
+ $info['crc'],
+ $info['nlength']
+ );
+
+ }
+
+ //If no cache system, use the standard way
+ return parent::appendFile($filename, $dataFilename);
+ }
+
+ /**
+ * @see File_Archive_Writer_MemoryArchive::sendFooter()
+ * @access protected
+ */
+ function sendFooter()
+ {
+ return $this->innerWriter->writeData(
+ $this->central.
+ "\x50\x4b\x05\x06\x00\x00\x00\x00".
+ pack("vvVVv",
+ $this->nbFiles,$this->nbFiles,
+ strlen($this->central),$this->offset,
+ strlen($this->comment)).
+ $this->comment
+ );
+ }
+ /**
+ * @see File_Archive_Writer::getMime()
+ */
+ function getMime() { return "application/zip"; }
+}
+
+?>
\ No newline at end of file
diff --git a/thirdparty/pear/MIME/Type.php b/thirdparty/pear/MIME/Type.php
new file mode 100644
index 0000000..6acc15e
--- /dev/null
+++ b/thirdparty/pear/MIME/Type.php
@@ -0,0 +1,395 @@
+ |
+// +----------------------------------------------------------------------+
+//
+// $Id: Type.php,v 1.2 2004/08/07 22:19:04 ieure Exp $
+
+require_once 'PEAR.php';
+
+$_fileCmd = &PEAR::getStaticProperty('MIME_Type', 'fileCmd');
+$_fileCmd = 'file';
+
+/**
+ * Class for working with MIME types
+ *
+ * @version @version@
+ * @package @package@
+ * @author Ian Eure
+ */
+class MIME_Type {
+ /**
+ * The MIME media type
+ *
+ * @var string
+ */
+ var $media = '';
+
+ /**
+ * The MIME media sub-type
+ *
+ * @var string
+ */
+ var $subType = '';
+
+ /**
+ * Optional MIME parameters
+ *
+ * @var array
+ */
+ var $parameters = array();
+
+ /**
+ * List of valid media types
+ *
+ * @var array
+ */
+ var $validMediaTypes = array(
+ 'text',
+ 'image',
+ 'audio',
+ 'video',
+ 'application',
+ 'multipart',
+ 'message'
+ );
+
+
+ /**
+ * Constructor.
+ *
+ * If $type is set, if will be parsed and the appropriate class vars set. If not,
+ * you get an empty class. This is useful, but not quite as useful as parsing a
+ * type.
+ *
+ * @param string $type MIME type
+ * @return void
+ */
+ function MIME_Type($type = false)
+ {
+ if ($type) {
+ $this->parse($type);
+ }
+ }
+
+
+ /**
+ * Parse a mime-type
+ *
+ * @param $type string MIME type to parse
+ * @return void
+ */
+ function parse($type)
+ {
+ $this->media = $this->getMedia($type);
+ $this->subType = $this->getSubType($type);
+ if (MIME_Type::hasParameters($type)) {
+ require_once 'MIME/Type/Parameter.php';
+ foreach (MIME_Type::getParameters($type) as $param) {
+ $param = &new MIME_Type_Parameter($param);
+ $this->parameters[$param->name] = $param;
+ }
+ }
+ }
+
+
+ /**
+ * Does this type have any parameters?
+ *
+ * @param $type string MIME type to check
+ * @return boolean true if $type has parameters, false otherwise
+ * @static
+ */
+ function hasParameters($type)
+ {
+ if (strstr($type, ';')) {
+ return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * Get a MIME type's parameters
+ *
+ * @param $type string MIME type to get parameters of
+ * @return array $type's parameters
+ * @static
+ */
+ function getParameters($type)
+ {
+ $params = array();
+ $tmp = explode(';', $type);
+ for ($i = 1; $i < count($tmp); $i++) {
+ $params[] = trim($tmp[$i]);
+ }
+ return $params;
+ }
+
+
+ /**
+ * Strip paramaters from a MIME type string
+ *
+ * @param string $type MIME type string
+ * @return string MIME type with parameters removed
+ * @static
+ */
+ function stripParameters($type)
+ {
+ if (strstr($type, ';')) {
+ return substr($type, 0, strpos($type, ';'));
+ }
+ return $type;
+ }
+
+
+ /**
+ * Get a MIME type's media
+ *
+ * @note 'media' refers to the portion before the first slash
+ * @param $type string MIME type to get media of
+ * @return string $type's media
+ * @static
+ */
+ function getMedia($type)
+ {
+ $tmp = explode('/', $type);
+ return strtolower($tmp[0]);
+ }
+
+
+ /**
+ * Get a MIME type's subtype
+ *
+ * @param $type string MIME type to get subtype of
+ * @return string $type's subtype
+ * @static
+ */
+ function getSubType($type)
+ {
+ $tmp = explode('/', $type);
+ $tmp = explode(';', $tmp[1]);
+ return strtolower(trim($tmp[0]));
+ }
+
+
+ /**
+ * Create a textual MIME type from object values
+ *
+ * This function performs the opposite function of parse().
+ *
+ * @return string MIME type string
+ */
+ function get()
+ {
+ $type = strtolower($this->media.'/'.$this->subType);
+ if (count($this->parameters)) {
+ foreach ($this->parameters as $key => $null) {
+ $type .= '; '.$this->parameters[$key]->get();
+ }
+ }
+ return $type;
+ }
+
+
+ /**
+ * Is this type experimental?
+ *
+ * @note Experimental types are denoted by a leading 'x-' in the media or
+ * subtype, e.g. text/x-vcard or x-world/x-vrml.
+ * @param string $type MIME type to check
+ * @return boolean true if $type is experimental, false otherwise
+ * @static
+ */
+ function isExperimental($type)
+ {
+ if (substr(MIME_Type::getMedia($type), 0, 2) == 'x-' ||
+ substr(MIME_Type::getSubType($type), 0, 2) == 'x-') {
+ return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * Is this a vendor MIME type?
+ *
+ * @note Vendor types are denoted with a leading 'vnd. in the subtype.
+ * @param string $type MIME type to check
+ * @return boolean true if $type is a vendor type, false otherwise
+ * @static
+ */
+ function isVendor($type)
+ {
+ if (substr(MIME_Type::getSubType($type), 0, 4) == 'vnd.') {
+ return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * Is this a wildcard type?
+ *
+ * @param string $type MIME type to check
+ * @return boolean true if $type is a wildcard, false otherwise
+ * @static
+ */
+ function isWildcard($type)
+ {
+ if ($type == '*/*' || MIME_Type::getSubtype($type) == '*') {
+ return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * Perform a wildcard match on a MIME type
+ *
+ * Example:
+ * MIME_Type::wildcardMatch('image/*', 'image/png')
+ *
+ * @param string $card Wildcard to check against
+ * @param string $type MIME type to check
+ * @return boolean true if there was a match, false otherwise
+ */
+ function wildcardMatch($card, $type)
+ {
+ if (!MIME_Type::isWildcard($card)) {
+ return false;
+ }
+
+ if ($card == '*/*') {
+ return true;
+ }
+
+ if (MIME_Type::getMedia($card) ==
+ MIME_Type::getMedia($type)) {
+ return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * Add a parameter to this type
+ *
+ * @param string $name Attribute name
+ * @param string $value Attribute value
+ * @param string $comment Comment for this parameter
+ * @return void
+ */
+ function addParameter($name, $value, $comment = false)
+ {
+ $tmp = &new MIME_Type_Parameter;
+ $tmp->name = $name;
+ $tmp->value = $value;
+ $tmp->comment = $comment;
+ $this->parameters[$name] = $tmp;
+ }
+
+
+ /**
+ * Remove a parameter from this type
+ *
+ * @param string $name Parameter name
+ * @return void
+ */
+ function removeParameter($name)
+ {
+ unset ($this->parameters[$name]);
+ }
+
+
+ /**
+ * Autodetect a file's MIME-type
+ *
+ * This function may be called staticly.
+ *
+ * @param string $file Path to the file to get the type of
+ * @param bool $params Append MIME parameters if true
+ * @return string $file's MIME-type on success, PEAR_Error otherwise
+ * @since 1.0.0beta1
+ * @static
+ */
+ function autoDetect($file, $params = false)
+ {
+ @include_once 'System/Command.php';
+ if (function_exists('mime_content_type')) {
+ $type = mime_content_type($file);
+ } else if (class_exists('System_Command')) {
+ $type = MIME_Type::_fileAutoDetect($file);
+ } else {
+ return PEAR::raiseError("Sorry, can't autodetect; you need the mime_magic extension or System_Command and 'file' installed to use this function.");
+ }
+
+ // _fileAutoDetect() may have returned an error.
+ if (PEAR::isError($type)) {
+ return $type;
+ }
+
+ // Don't return an empty string
+ if (!$type || !strlen($type)) {
+ return PEAR::raiseError("Sorry, couldn't determine file type.");
+ }
+
+ // Strip parameters if present & requested
+ if (MIME_Type::hasParameters($type) && !$params) {
+ $type = MIME_Type::stripParameters($type);
+ }
+
+ return $type;
+ }
+
+ /**
+ * Autodetect a file's MIME-type with 'file' and System_Command
+ *
+ * This function may be called staticly.
+ *
+ * @param string $file Path to the file to get the type of
+ * @return string $file's MIME-type
+ * @since 1.0.0beta1
+ * @static
+ */
+ function _fileAutoDetect($file)
+ {
+ // Sanity checks
+ if (!file_exists($file)) {
+ return PEAR::raiseError("File \"$file\" doesn't exist");
+ }
+
+ if (!is_readable($file)) {
+ return PEAR::raiseError("File \"$file\" is not readable");
+ }
+
+ $cmd = new System_Command;
+
+
+ // Make sure we have the 'file' command.
+ $fileCmd = PEAR::getStaticProperty('MIME_Type', 'fileCmd');
+ if (!$cmd->which($fileCmd)) {
+ unset($cmd);
+ return PEAR::raiseError("Can't find file command \"{$fileCmd}\"");
+ }
+
+ $cmd->pushCommand($fileCmd, "-bi '{$file}'");
+ $res = $cmd->execute();
+ unset($cmd);
+
+ return $res;
+ }
+}
\ No newline at end of file
diff --git a/thirdparty/pear/MIME/Type/Parameter.php b/thirdparty/pear/MIME/Type/Parameter.php
new file mode 100644
index 0000000..c37d7bb
--- /dev/null
+++ b/thirdparty/pear/MIME/Type/Parameter.php
@@ -0,0 +1,162 @@
+ |
+// +----------------------------------------------------------------------+
+//
+// $Id: Parameter.php,v 1.1 2004/06/16 08:46:19 ieure Exp $
+
+/**
+ * Class for working with MIME type parameters
+ *
+ * @version @version@
+ * @package @package@
+ * @author Ian Eure
+ */
+class MIME_Type_Parameter {
+ /**
+ * Parameter name
+ *
+ * @var string
+ */
+ var $name;
+
+ /**
+ * Parameter value
+ *
+ * @var string
+ */
+ var $value;
+
+ /**
+ * Parameter comment
+ *
+ * @var string
+ */
+ var $comment;
+
+
+ /**
+ * Constructor.
+ *
+ * @param string $param MIME parameter to parse, if set.
+ * @return void
+ */
+ function MIME_Type_Parameter($param = false)
+ {
+ if ($param) {
+ $this->parse($param);
+ }
+ }
+
+
+ /**
+ * Parse a MIME type parameter and set object fields
+ *
+ * @param string $param MIME type parameter to parse
+ * @return void
+ */
+ function parse($param)
+ {
+ $this->name = $this->getAttribute($param);
+ $this->value = $this->getValue($param);
+ if ($this->hasComment($param)) {
+ $this->comment = $this->getComment($param);
+ }
+ }
+
+
+ /**
+ * Get a parameter attribute (e.g. name)
+ *
+ * @param string MIME type parameter
+ * @return string Attribute name
+ * @static
+ */
+ function getAttribute($param)
+ {
+ $tmp = explode('=', $param);
+ return trim($tmp[0]);
+ }
+
+
+ /**
+ * Get a parameter value
+ *
+ * @param string $param MIME type parameter
+ * @return string Value
+ * @static
+ */
+ function getValue($param)
+ {
+ $tmp = explode('=', $param);
+ $value = $tmp[1];
+ if (MIME_Type_Parameter::hasComment($param)) {
+ $cs = strpos($value, '(');
+ $value = substr($value, 0, $cs);
+ }
+ return trim($value, '" ');
+ }
+
+
+ /**
+ * Get a parameter comment
+ *
+ * @param string $param MIME type parameter
+ * @return string Parameter comment
+ * @see getComment()
+ * @static
+ */
+ function getComment($param)
+ {
+ $cs = strpos($param, '(');
+ $comment = substr($param, $cs);
+ return trim($comment, '() ');
+ }
+
+
+ /**
+ * Does this parameter have a comment?
+ *
+ * @param string $param MIME type parameter
+ * @return boolean true if $param has a comment, false otherwise
+ * @static
+ */
+ function hasComment($param)
+ {
+ if (strstr($param, '(')) {
+ return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * Get a string representation of this parameter
+ *
+ * This function performs the oppsite of parse()
+ *
+ * @return string String representation of parameter
+ */
+ function get()
+ {
+ $val = $this->name.'="'.$this->value.'"';
+ if ($this->comment) {
+ $val .= ' ('.$this->comment.')';
+ }
+ return $val;
+ }
+}
+?>
\ No newline at end of file