Seems quicktime atoms can have multiple mdat's, so we need a way to calculate our signature for them too

This commit is contained in:
Deon George 2024-09-29 00:26:22 +10:00
parent d9908c043f
commit 4e39d01876
4 changed files with 31 additions and 15 deletions

View File

@ -17,6 +17,7 @@ abstract class Base
private mixed $fh; private mixed $fh;
private int $fp; private int $fp;
protected Collection $cache;
protected ?string $unused_data; protected ?string $unused_data;
public function __construct(string $filename,string $type) public function __construct(string $filename,string $type)
@ -26,6 +27,7 @@ abstract class Base
$this->filename = $filename; $this->filename = $filename;
$this->filesize = filesize($filename); $this->filesize = filesize($filename);
$this->type = $type; $this->type = $type;
$this->cache = collect();
} }
/** /**
@ -38,8 +40,9 @@ abstract class Base
public function __get(string $key): mixed public function __get(string $key): mixed
{ {
switch ($key) { switch ($key) {
case 'fh':
case 'type': case 'type':
return $this->type; return $this->{$key};
default: default:
throw new \Exception('Unknown key: '.$key); throw new \Exception('Unknown key: '.$key);

View File

@ -40,9 +40,16 @@ class QuickTime extends Base {
// Signatures are calculated by the sha of the MDAT atom. // Signatures are calculated by the sha of the MDAT atom.
case 'signature': 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 // Creation Time is in the MOOV/MVHD atom
case 'creation_date': case 'creation_date':
@ -74,6 +81,7 @@ class QuickTime extends Base {
return $atom->{$key}; return $atom->{$key};
case 'fh':
case 'type': case 'type':
return parent::__get($key); return parent::__get($key);

View File

@ -15,7 +15,6 @@ abstract class Atom extends QuickTime
protected int $size; protected int $size;
protected string $filename; protected string $filename;
protected Collection $cache;
protected Collection $atoms; protected Collection $atoms;
public function __construct(int $offset,int $size,string $filename) public function __construct(int $offset,int $size,string $filename)
@ -49,11 +48,13 @@ abstract class Atom extends QuickTime
case 'width': case 'width':
$atom = $this->find_atoms(trak::class); $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. // We need to pass our file handle requests to our parent
case 'signature': case 'fh':
return $this->signature(); return parent::__get($key);
default: default:
throw new \Exception('Unknown key: '.$key); throw new \Exception('Unknown key: '.$key);

View File

@ -15,22 +15,26 @@ class mdat extends Atom
* Calculate the signature of the data * Calculate the signature of the data
* *
* @param string $alg * @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 (! Arr::has($this->cache,'signature')) {
if ($this->size) { if ($this->size) {
$this->fopen(); $this->fopen();
$hash = hash_init($alg); $hash = $hash ?: hash_init($alg);
while (! is_null($read=$this->fread(16384)))
while (!is_null($read = $this->fread(16384))) hash_update($hash,$read);
hash_update($hash, $read);
$this->fclose(); $this->fclose();
$this->cache['signature'] = hash_final($hash); if ($next)
return $hash;
else
$this->cache['signature'] = hash_final($hash);
} else { } else {
$this->cache['signature'] = NULL; $this->cache['signature'] = NULL;