2024-09-24 11:55:40 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace App\Media\MSVideo\Containers;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* https://netghost.narod.ru/gff/graphics/summary/micriff.htm
|
|
|
|
*
|
|
|
|
* Indicate the format of the data stream(s) stored in the file
|
|
|
|
*/
|
|
|
|
|
|
|
|
use Illuminate\Support\Collection;
|
|
|
|
|
|
|
|
use App\Media\MSVideo\Container;
|
|
|
|
use App\Media\MSVideo\Containers\rlist\movi;
|
|
|
|
|
|
|
|
class rlist extends Container
|
|
|
|
{
|
|
|
|
private const container_classes = 'App\\Media\\MSVideo\\Containers\\rlist\\';
|
|
|
|
|
|
|
|
public function __construct(int $offset,int $size,string $filename,bool $be,?string $data)
|
|
|
|
{
|
|
|
|
parent::__construct($offset,$size,$filename,$be,$data);
|
|
|
|
|
|
|
|
$this->containers = $this->parseContainer($data);
|
|
|
|
|
|
|
|
// For debugging
|
|
|
|
if (FALSE)
|
|
|
|
$this->debug = hex_dump($data ?: $this->data(min($size,256)));
|
|
|
|
}
|
|
|
|
|
|
|
|
private function parseContainer(string $bytes=NULL): Collection
|
|
|
|
{
|
|
|
|
$this->be = FALSE; // @todo
|
|
|
|
|
|
|
|
$rp = 0;
|
|
|
|
if (! $bytes) {
|
|
|
|
$fh = fopen($this->filename,'r');
|
|
|
|
fseek($fh,$this->offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
$result = collect();
|
|
|
|
|
|
|
|
// Our first container should be hrl
|
|
|
|
$read = $bytes ? substr($bytes,$rp,4) : fread($fh,4);
|
|
|
|
$rp += 4;
|
|
|
|
$header = unpack('a4name',$read);
|
|
|
|
|
|
|
|
switch ($header['name']) {
|
|
|
|
case 'hdrl':
|
|
|
|
case 'strl':
|
|
|
|
case 'INFO':
|
|
|
|
while ($rp < $this->size) {
|
|
|
|
$read = $bytes ? substr($bytes,$rp,8) : fread($fh,8);
|
|
|
|
$rp += 8;
|
|
|
|
|
|
|
|
$header = unpack('a4name/Vsize',$read);
|
|
|
|
|
|
|
|
// We cant have a php function named 'list', so we change it to rlist
|
|
|
|
if ($header['name'] === 'LIST')
|
|
|
|
$header['name'] = 'RLIST';
|
|
|
|
|
2024-09-27 11:29:18 +00:00
|
|
|
$class = self::container_classes.strtolower($header['name']);
|
2024-09-24 11:55:40 +00:00
|
|
|
|
|
|
|
$data = $bytes
|
|
|
|
? substr($bytes,$rp,$header['size'])
|
|
|
|
: ($header['size'] && ($header['size'] <= self::record_size) ? fread($fh,$header['size']) : NULL);
|
|
|
|
|
|
|
|
if ($header['size']) {
|
|
|
|
$o = class_exists($class)
|
|
|
|
? new $class($this->offset+$rp,$header['size'],$this->filename,$this->be,$data)
|
|
|
|
: new Unknown($this->offset+$rp,$header['size'],$this->filename,$header['name'],$this->be,$data);
|
|
|
|
|
|
|
|
$result->push($o);
|
|
|
|
|
|
|
|
$rp += $header['size'];
|
|
|
|
|
|
|
|
// Only need to seek if we didnt read all the data
|
|
|
|
if ((! $bytes) && ($header['size'] > self::record_size))
|
|
|
|
fseek($fh,$this->offset+$rp);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
dd([get_class($this) => $data,'header'=>$header,'ptr'=>$rp,'size'=>$this->size,'bytes'=>$bytes]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'movi':
|
|
|
|
$result->push(new movi($this->offset,$this->size,$this->filename,$this->be));
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
throw new \Exception('Unhandled header type: '.$header['name']);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! $bytes) {
|
|
|
|
fclose($fh);
|
|
|
|
unset($fh);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
}
|