75 define(
'PATH_MOOVRELOCATOR', CH_DIRECTORY_PATH_PLUGINS . 
'moovrelocator/lib/');
 
  111     private static $_instance = 
null;
 
  119     private $_outputFile = 
false;
 
  127     private $_filesize = 0;
 
  135     private $_fp = 
false;
 
  162     private $_middleBytes;
 
  170     private $_fileAtoms = array();
 
  178     private $_lastAtom = 
null;
 
  186     private $_successfullyParsed = 
false;
 
  194     private $_fileValid = 
null;
 
  216         if (!file_exists($filename) || !($this->_fp = fopen($filename, 
'rb'))) {
 
  217             return 'cannot open file: '.$filename;
 
  221         $this->_filesize = filesize($filename);
 
  224         if ($this->_filesize == 0) {
 
  225             return 'file '.$filename.
' seems to be empty!';
 
  229         while (!feof($this->_fp) && ftell($this->_fp) < $this->_filesize) {
 
  230             $this->_fileAtoms[] = $this->_parseAtomsFromInput();
 
  233         $moovEOFCheck = $this->_moovAtomAtEOF();
 
  234         if ($moovEOFCheck !== 
true) {
 
  235             return $moovEOFCheck;
 
  238             $this->_successfullyParsed = 
true;
 
  257     private function _parseAtomsFromInput()
 
  260         if ((isset($this->_fileAtoms[count($this->_fileAtoms) - 1]))) {
 
  261             $lastAtom = $this->_fileAtoms[count($this->_fileAtoms) - 1];
 
  262             $position = $lastAtom->getSize() + $lastAtom->getOffset();
 
  263             if (ftell($this->_fp) <= $position) {
 
  264                 fseek($this->_fp, $position);
 
  269         $atomData = unpack(
'NtotalSize/NboxType', fread($this->_fp, 8));
 
  271         $offset = ftell($this->_fp) - 8;
 
  272         $size = $atomData[
'totalSize'];
 
  273         $type = pack(
'N', $atomData[
'boxType']);
 
  277             $highInt = $atomData[
'totalSize'];
 
  278             $size = ($highInt << 32) | $atomData[
'totalSize'];
 
  282         fseek($this->_fp, ($size + $offset));
 
  300     private function _isValidQTFile()
 
  303         if (!$this->_successfullyParsed) {
 
  304             return 'please open a file first!';
 
  308         $firstAtom = $this->_fileAtoms[0];
 
  312             $this->_fileValid = 
false;
 
  313             return 'encountered non-QT top-level atom (is this a Quicktime file?)';
 
  317         $lastAtom = $this->_fileAtoms[count($this->_fileAtoms) - 1];
 
  320             $this->_fileValid = 
false;
 
  321             return 'encountered non-QT top-level atom (is this a Quicktime file?';
 
  325         return $this->_fileValid = 
true;
 
  340     private function _moovAtomAtEOF()
 
  342         if ($this->_fileAtoms[count($this->_fileAtoms) - 1]->getType() != 
Atom::MOOV_ATOM) {
 
  343             return 'The moov-atom isn\'t located at the end of the file, the file is allready ready for progressive download or it is a invalid file';
 
  367         $this->_outputFile = $filename;
 
  392         $result = $this->
setInput($filename);
 
  393         if ($result !== 
true) {
 
  397         if (is_null($outputFilename) && $overwrite === 
true) {
 
  398             $fileResult = $filename;
 
  400             $fileResult = $outputFilename;
 
  405         if ($result !== 
true) {
 
  410         $result = $this->
fix();
 
  411         if ($result !== 
true) {
 
  434         if (!$this->_successfullyParsed) {
 
  435             return 'please open a file first! (syntax: '.__CLASS__.
'->setInput($filename);)';
 
  438         if (!$this->_outputFile) {
 
  439             return 'please set an outputfile first! (syntax: '.__CLASS__.
'->setOutput($file);)';
 
  443         if (!$this->_moovAtomAtEOF()) {
 
  444             return 'nothing to do! moov allready at begin of file!';
 
  453         $result = $this->_readBytes();
 
  454         if ($result !== 
true) {
 
  459         $result = $this->_swapIndex();
 
  460         if ($result !== 
true) {
 
  465         $result = $this->_writeFile();
 
  466         if ($result !== 
true) {
 
  486     private function _readBytes()
 
  489         for ($atom = 0; $atom < count($this->_fileAtoms); $atom++) {
 
  492             $currentAtom = $this->_fileAtoms[$atom];
 
  493             $currentAtomType = $currentAtom->getType();
 
  498                 fseek($this->_fp, 0);
 
  499                 $bytes = fread($this->_fp, $currentAtom->getSize());
 
  500                 $this->_ftypBytes->writeBytes($bytes);
 
  503                 $bytes = fread($this->_fp, $currentAtom->getSize());
 
  504                 $this->_moovBytes->writeBytes($bytes);
 
  507                 $bytes = fread($this->_fp, $currentAtom->getSize());
 
  508                 $this->_middleBytes->writeBytes($bytes);
 
  527     private function _swapIndex()
 
  529         $moovSize = $this->_moovBytes->bytesAvailable();
 
  535         $compressionCheck = $this->_moovBytes->readBytes(12, 4);
 
  538             throw new Exception(
'compressed MP4/QT-file can\'t do this file: '.$file);
 
  542         $metaDataOffsets = array();
 
  543         $metaDataStrings = array();
 
  544         $metaDataCurrentLevel = 0;
 
  546         $moovStartOffset = 12;
 
  548         for ($i = $moovStartOffset; $i < $moovSize - $moovStartOffset; $i++) {
 
  549             $moovAType = $this->_moovBytes->readUTFBytes($i, 4);
 
  553                 $moovASize = $this->_moovBytes->readUnsignedInt($i - 4);
 
  555                 if (($moovASize > 8) && ($moovASize + $i < ($moovSize - $moovStartOffset))) {
 
  558                         $containerLength = 0;
 
  559                         $containerString = $moovAType;
 
  561                         for ($mi = count($metaDataOffsets) - 1; $mi > - 1; $mi--) {
 
  563                             $containerLength = $metaDataOffsets[$mi];
 
  565                             if ($i - $moovStartOffset < $containerLength && $i - $moovStartOffset + $moovASize > $containerLength) {
 
  566                                 throw new Exception(
'bad atom nested size');
 
  569                             if ($i - $moovStartOffset == $containerLength) {
 
  570                                 array_pop($metaDataOffsets);
 
  571                                 array_pop($metaDataStrings);
 
  573                                 $containerString = $metaDataStrings[$mi].
".".$containerString;
 
  577                         if (($i - $moovStartOffset) <= $containerLength) {
 
  578                             array_push($metaDataOffsets, ($i - $moovStartOffset + $moovASize));
 
  579                             array_push($metaDataStrings, $moovAType);
 
  585                             $i += $moovASize - 4;
 
  588                     catch(Exception $e) {
 
  589                         echo 
'EXCEPTION: '.$e->getMessage();
 
  596                 $moovASize = $this->_moovBytes->readUnsignedInt($i - 4);
 
  598                 if ($i + $moovASize - $moovStartOffset > $moovSize) {
 
  599                     throw new Exception(
'bad atom size');
 
  603                 $offsetCount = $this->_moovBytes->readUnsignedInt($i + 8);
 
  605                 for ($j = 0; $j < $offsetCount; $j++) {
 
  606                     $position = ($i + 12 + $j * 4);
 
  608                     $currentOffset = $this->_moovBytes->readUnsignedInt($position);
 
  613                     $currentOffset += $moovSize;
 
  617                 $i += $moovASize - 4;
 
  620                 $moovASize = $this->_moovBytes->readUnsignedInt($i - 4);
 
  622                 if ($i + $moovASize - $moovStartOffset > $moovSize) {
 
  623                     throw new Exception(
'bad atom size');
 
  627                 $offsetCount = $this->_moovBytes->readDouble($i + 8);
 
  629                 for ($j2 = 0; $j2 < $offsetCount; $j2++) {
 
  630                     $position = ($i + 12 + $j * 8);
 
  632                     $currentOffset = $this->_moovBytes->readUnsignedInt($position);
 
  637                     $currentOffset += $moovSize;
 
  642                 $i += $moovASize - 4;
 
  661     private function _writeFile()
 
  664         if (file_exists($this->_outputFile)) {
 
  672             if (!@unlink($this->_outputFile)) {
 
  673                 return 'error deleting file: '.$this->_outputFile.
' outputfile "'.$this->_outputFile.
'" exists (overwite = true)!';
 
  678         if (!$fh = fopen($this->_outputFile, 
'wb+')) {
 
  679             return 'error opening outputfile: '.$this->_outputFile.
' for wb+ access!';
 
  683         if (!fwrite($fh, $this->_ftypBytes->readAllBytes())) {
 
  684             return 'error writing ftyp-atom to outputfile: '.$this->_outputFile;
 
  688         if (!fwrite($fh, $this->_moovBytes->readAllBytes())) {
 
  689             return 'error writing moov-atom to outputfile: '.$this->_outputFile;
 
  693         if (!fwrite($fh, $this->_middleBytes->readAllBytes())) {
 
  694             return 'error writing other atom(s) to outputfile: '.$this->_outputFile;
 
  720     public static function factory($offset, $size, $type)
 
  726         $atom->setOffset($offset);
 
  727         $atom->setSize($size);
 
  728         $atom->setType($type);
 
  745     private function _reset()
 
  747         $this->_fileAtoms = array();
 
  748         $this->_lastAtom = 
null;
 
  749         $this->_successfullyParsed = 
false;
 
  750         $this->_fileValid = 
null;
 
  771         if (is_null(self::$_instance)) {
 
  772             self::$_instance = 
new self();
 
  774         return self::$_instance;
 
  790     private function __clone()