* @copyright Copyright (c) 2006-2009 The PHP Reader Project Workgroup * @license http://code.google.com/p/php-reader/wiki/License New BSD License * @version $Rev$ */ class ASF extends ASF_Object_Container { /** @var string */ private $_filename; /** * Constructs the ASF class with given file and options. * * The following options are currently recognized: * o encoding -- Indicates the encoding that all the texts are presented * with. By default this is set to utf-8. See the documentation of iconv * for accepted values. * o readonly -- Indicates that the file is read from a temporary location * or another source it cannot be written back to. * * @param string $filename The path to the file or file descriptor of an * opened file. * @param Array $options The options array. */ public function __construct($filename, $options = array()) { $this->_reader = new Reader($this->_filename = $filename); $this->setOptions($options); if ($this->getOption("encoding", false) === false) $this->setOption("encoding", "utf-8"); $this->setOffset(0); $this->setSize($this->_reader->getSize()); $this->constructObjects (array (self::HEADER => "Header", self::DATA => "Data", self::SIMPLE_INDEX => "SimpleIndex", self::INDEX => "Index", self::MEDIA_OBJECT_INDEX => "MediaObjectIndex", self::TIMECODE_INDEX => "TimecodeIndex")); } /** * Returns the mandatory header object contained in this file. * * @return ASF_Object_Header */ public function getHeader() { $header = $this->getObjectsByIdentifier(self::HEADER); return $header[0]; } /** * Returns the mandatory data object contained in this file. * * @return ASF_Object_Data */ public function getData() { $data = $this->getObjectsByIdentifier(self::DATA); return $data[0]; } /** * Returns an array of index objects contained in this file. * * @return Array */ public function getIndices() { return $this->getObjectsByIdentifier (self::SIMPLE_INDEX . "|" . self::INDEX . "|" . self::MEDIA_OBJECT_INDEX . "|" . self::TIMECODE_INDEX); } /** * Writes the changes back to the original media file. */ public function write($filename = false) { if ($filename === false) $filename = $this->_filename; if ($filename !== false && $this->_filename !== false && realpath($filename) != realpath($this->_filename) && !copy($this->_filename, $filename)) { require_once("ASF/Exception.php"); throw new ASF_Exception("Unable to copy source to destination: " . realpath($this->_filename) . "->" . realpath($filename)); } if (($fd = fopen ($filename, file_exists($filename) ? "r+b" : "wb")) === false) { require_once("ASF/Exception.php"); throw new ASF_Exception("Unable to open file for writing: " . $filename); } $header = $this->getHeader(); $headerLengthOld = $header->getSize(); $header->removeObjectsByIdentifier(ASF_Object::PADDING); $header->headerExtension->removeObjectsByIdentifier(ASF_Object::PADDING); $headerData = $header->__toString(); $headerLengthNew = $header->getSize(); // Fits right in if ($headerLengthOld == $headerLengthNew) { } // Fits with adjusted padding else if ($headerLengthOld >= $headerLengthNew + 24 /* for header */) { $header->headerExtension->padding->setSize ($headerLengthOld - $headerLengthNew); $headerData = $header->__toString(); $headerLengthNew = $header->getSize(); } // Must expand else { $header->headerExtension->padding->setSize(4096); $headerData = $header->__toString(); $headerLengthNew = $header->getSize(); fseek($fd, 0, SEEK_END); $oldFileSize = ftell($fd); ftruncate ($fd, $newFileSize = $headerLengthNew - $headerLengthOld + $oldFileSize); for ($i = 1, $cur = $oldFileSize; $cur > 0; $cur -= 1024, $i++) { fseek($fd, -(($i * 1024) + ($newFileSize - $oldFileSize)), SEEK_END); $buffer = fread($fd, 1024); fseek($fd, -($i * 1024), SEEK_END); fwrite($fd, $buffer, 1024); } } fseek($fd, 0); fwrite($fd, $headerData, $headerLengthNew); fclose($fd); $this->_filename = $filename; } /** * Returns the whether the object is required to be present, or whether * minimum cardinality is 1. * * @return boolean */ public function isMandatory() { return true; } /** * Returns whether multiple instances of this object can be present, or * whether maximum cardinality is greater than 1. * * @return boolean */ public function isMultiple() { return false; } }