ConLite/conlite/plugins/pluginmanager/docs/pear/File/Archive/Reader.php

427 Zeilen
13 KiB
PHP

<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* Abstract base class for all the readers
*
* A reader is a compilation of serveral files that can be read
*
* PHP versions 4 and 5
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330,Boston,MA 02111-1307 USA
*
* @category File Formats
* @package File_Archive
* @author Vincent Lascaux <vincentlascaux@php.net>
* @copyright 1997-2005 The PHP Group
* @license http://www.gnu.org/copyleft/lesser.html LGPL
* @version CVS: $Id: Reader.php 2 2010-11-23 14:32:26Z oldperl $
* @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 or folder 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 (substr($std, -1)=='/') {
$std = substr($std, 0, -1);
}
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 &&
strlen($sourceName) > strlen($std)+1)
) {
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) {
/**
* If return value is going to be / (root on POSIX)
*/
if (substr($std, 2) === '/') {
return $std;
}
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)");
}
}
?>