From 37bc9d5ec65cc584ab24508011b0d86423418ab8 Mon Sep 17 00:00:00 2001 From: Markus Birth Date: Mon, 27 May 2024 20:04:23 +0100 Subject: [PATCH] Optimise id3v2 header parsing --- src/Mp3Info.php | 78 ++++++++++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 34 deletions(-) diff --git a/src/Mp3Info.php b/src/Mp3Info.php index e8c0ca9..ea90e22 100644 --- a/src/Mp3Info.php +++ b/src/Mp3Info.php @@ -166,11 +166,13 @@ class Mp3Info * @var int Major version of id3v2 tag (if id3v2 present) (2 or 3 or 4) */ public $id3v2MajorVersion; + public $id3v2Version; /** * @var int Minor version of id3v2 tag (if id3v2 present) */ public $id3v2MinorVersion; + public $id3v2Revision; /** * @var array List of id3v2 header flags (if id3v2 present) @@ -501,45 +503,53 @@ class Mp3Info private function readId3v2Body() { // read the rest of the id3v2 header - $raw = $this->fileObj->getBytes(7); - $data = unpack('Cmajor_version/Cminor_version/Cflags/C4size', $raw); - $this->id3v2MajorVersion = $data['major_version']; - $this->id3v2MinorVersion = $data['minor_version']; - $flags = decbin($data['flags']); - if ($this->id3v2MajorVersion == 2) { // parse id3v2.2.0 header flags - $this->id3v2Flags = array( - 'unsynchronisation' => (bool)substr($flags, 0, 1), - 'compression' => (bool)substr($flags, 1, 1), - ); - } else if ($this->id3v2MajorVersion == 3) { // parse id3v2.3.0 header flags - $this->id3v2Flags = array( - 'unsynchronisation' => (bool)substr($flags, 0, 1), - 'extended_header' => (bool)substr($flags, 1, 1), - 'experimental_indicator' => (bool)substr($flags, 2, 1), - ); - if ($this->id3v2Flags['extended_header']) - throw new \Exception('NEED TO PARSE EXTENDED HEADER!'); - } else if ($this->id3v2MajorVersion == 4) { // parse id3v2.4.0 header flags - $this->id3v2Flags = array( - 'unsynchronisation' => (bool)substr($flags, 0, 1), - 'extended_header' => (bool)substr($flags, 1, 1), - 'experimental_indicator' => (bool)substr($flags, 2, 1), - 'footer_present' => (bool)substr($flags, 3, 1), - ); - if ($this->id3v2Flags['extended_header']) - throw new \Exception('NEED TO PARSE EXTENDED HEADER!'); - if ($this->id3v2Flags['footer_present']) - throw new \Exception('NEED TO PARSE id3v2.4 FOOTER!'); - } - $size = $data['size1'] << 21 | $data['size2'] << 14 | $data['size3'] << 7 | $data['size4']; + $raw = $this->fileObj->getBytes(3); + $data = unpack('Cversion/Crevision/Cflags', $raw); + $this->id3v2Version = $data['version']; + $this->id3v2Revision = $data['revision']; + // backwards compatibility: + $this->id3v2MajorVersion = $data['version']; + $this->id3v2MinorVersion = $data['revision']; - if ($this->id3v2MajorVersion == 2) { + $flags = str_pad(decbin($data['flags']), 8, '0', STR_PAD_LEFT); + $this->id3v2Flags = array(); + + if ($this->id3v2Version >= 2) { + // parse id3v2.2.0 header flags + $this->id3v2Flags['unsynchronisation'] = (bool)substr($flags, 0, 1); + $this->id3v2Flags['compression'] = (bool)substr($flags, 1, 1); + } + + if ($this->id3v2Version >= 3) { + // id3v2.3 changes second bit from compression to extended_header + $this->id3v2Flags['extended_header'] = &$this->id3v2Flags['compression']; + unset($this->id3v2Flags['compression']); + // parse additional id3v2.3.0 header flags + $this->id3v2Flags['experimental_indicator'] = (bool)substr($flags, 2, 1); + + if ($this->id3v2Flags['extended_header']) { + throw new Exception('NEED TO PARSE EXTENDED HEADER!'); + } + } + + if ($this->id3v2Version >= 4) { + // parse additional id3v2.4.0 header flags + $this->id3v2Flags['footer_present'] = (bool)substr($flags, 3, 1); + + if ($this->id3v2Flags['footer_present']) { + throw new Exception('NEED TO PARSE id3v2.4 FOOTER!'); + } + } + + $size = $this->getSyncsafeSize($this->fileObj->getBytes(4)); + + if ($this->id3v2Version == 2) { // parse id3v2.2.0 body /*throw new \Exception('NEED TO PARSE id3v2.2.0 flags!');*/ - } elseif ($this->id3v2MajorVersion == 3) { + } elseif ($this->id3v2Version == 3) { // parse id3v2.3.0 body $this->parseId3v23Body(10 + $size); - } elseif ($this->id3v2MajorVersion == 4) { + } elseif ($this->id3v2Version == 4) { // parse id3v2.4.0 body $this->parseId3v24Body(10 + $size); }