diff --git a/app/Media/Base.php b/app/Media/Base.php index bc052b9..c8c8c07 100644 --- a/app/Media/Base.php +++ b/app/Media/Base.php @@ -17,6 +17,7 @@ abstract class Base private mixed $fh; private int $fp; + protected Collection $cache; protected ?string $unused_data; public function __construct(string $filename,string $type) @@ -26,6 +27,7 @@ abstract class Base $this->filename = $filename; $this->filesize = filesize($filename); $this->type = $type; + $this->cache = collect(); } /** @@ -38,8 +40,9 @@ abstract class Base public function __get(string $key): mixed { switch ($key) { + case 'fh': case 'type': - return $this->type; + return $this->{$key}; default: throw new \Exception('Unknown key: '.$key); diff --git a/app/Media/QuickTime.php b/app/Media/QuickTime.php index d49c1b9..26bb5ba 100644 --- a/app/Media/QuickTime.php +++ b/app/Media/QuickTime.php @@ -40,9 +40,16 @@ class QuickTime extends Base { // Signatures are calculated by the sha of the MDAT atom. case 'signature': - $atom = $this->find_atoms(mdat::class,1); + if (! $this->cache->has('signature')) { + $hash = NULL; - return $atom->signature; + foreach ($this->find_atoms(mdat::class) as $atom) + $hash = $atom->signature('sha1',$hash,TRUE); + + $this->cache->put('signature',hash_final($hash)); + } + + return $this->cache->get('signature'); // Creation Time is in the MOOV/MVHD atom case 'creation_date': @@ -74,6 +81,7 @@ class QuickTime extends Base { return $atom->{$key}; + case 'fh': case 'type': return parent::__get($key); diff --git a/app/Media/QuickTime/Atom.php b/app/Media/QuickTime/Atom.php index b790f71..5222ad0 100644 --- a/app/Media/QuickTime/Atom.php +++ b/app/Media/QuickTime/Atom.php @@ -15,7 +15,6 @@ abstract class Atom extends QuickTime protected int $size; protected string $filename; - protected Collection $cache; protected Collection $atoms; public function __construct(int $offset,int $size,string $filename) @@ -49,11 +48,13 @@ abstract class Atom extends QuickTime case 'width': $atom = $this->find_atoms(trak::class); - return $atom->map(fn($item)=>$item->{$key})->filter()->max(); + return $atom->map(fn($item)=>$item->{$key}) + ->filter() + ->max(); - // Signatures are calculated by the sha of the MDAT atom. - case 'signature': - return $this->signature(); + // We need to pass our file handle requests to our parent + case 'fh': + return parent::__get($key); default: throw new \Exception('Unknown key: '.$key); diff --git a/app/Media/QuickTime/Atoms/mdat.php b/app/Media/QuickTime/Atoms/mdat.php index 1c32a9f..c6bf687 100644 --- a/app/Media/QuickTime/Atoms/mdat.php +++ b/app/Media/QuickTime/Atoms/mdat.php @@ -15,22 +15,26 @@ class mdat extends Atom * Calculate the signature of the data * * @param string $alg - * @return string + * @param mixed|null $hash If the hash was initialised already, this is it + * @param bool $next If the final hash is calculated by the calling method + * @return string|\HashContext */ - public function signature(string $alg='sha1'): string + public function signature(string $alg='sha1',mixed $hash=NULL,bool $next=FALSE): string|\HashContext { if (! Arr::has($this->cache,'signature')) { if ($this->size) { $this->fopen(); - $hash = hash_init($alg); - - while (!is_null($read = $this->fread(16384))) - hash_update($hash, $read); + $hash = $hash ?: hash_init($alg); + while (! is_null($read=$this->fread(16384))) + hash_update($hash,$read); $this->fclose(); - $this->cache['signature'] = hash_final($hash); + if ($next) + return $hash; + else + $this->cache['signature'] = hash_final($hash); } else { $this->cache['signature'] = NULL;