From 7e717e51268399515e9c4c13cfac0da9e7f46ffd Mon Sep 17 00:00:00 2001 From: Pavel Starosek Date: Wed, 26 Oct 2022 19:04:18 +0600 Subject: [PATCH 01/25] Update actions/checkout to v3 --- .github/workflows/continuous-integration.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index cdfad56d..881d3446 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -23,7 +23,7 @@ jobs: - "8.1" - "8.2" steps: - - uses: "actions/checkout@v2" + - uses: "actions/checkout@v3" - uses: "shivammathur/setup-php@v2" with: php-version: "${{ matrix.php-version }}" @@ -37,7 +37,7 @@ jobs: name: "Static Analysis" runs-on: "ubuntu-latest" steps: - - uses: "actions/checkout@v2" + - uses: "actions/checkout@v3" - uses: "shivammathur/setup-php@v2" with: php-version: "7.4" From 4f9133e0159b9c62c9588a7fb71c9a577d602068 Mon Sep 17 00:00:00 2001 From: StudioMaX Date: Thu, 27 Oct 2022 15:16:35 +0600 Subject: [PATCH 02/25] Remove deprecated utf8_encode/utf8_decode --- demos/demo.mp3header.php | 61 +++++++++++++++++++--------------------- getid3/getid3.lib.php | 8 ------ 2 files changed, 29 insertions(+), 40 deletions(-) diff --git a/demos/demo.mp3header.php b/demos/demo.mp3header.php index 222fe40e..57c241c8 100644 --- a/demos/demo.mp3header.php +++ b/demos/demo.mp3header.php @@ -705,7 +705,7 @@ function RoughTranslateUnicodeToASCII($rawdata, $frame_textencoding) { break; case 3: // UTF-8 encoded Unicode. Terminated with $00. - $asciidata = utf8_decode($rawdata); + $asciidata = utf8_to_iso8859_1($rawdata); break; case 255: // Unicode, Big-Endian. Terminated with $00 00. @@ -929,43 +929,40 @@ function image_type_to_mime_type($imagetypeid) { } } -if (!function_exists('utf8_decode')) { - // PHP has this function built-in if it's configured with the --with-xml option - // This version of the function is only provided in case XML isn't installed - function utf8_decode($utf8text) { - // http://www.php.net/manual/en/function.utf8-encode.php - // bytes bits representation - // 1 7 0bbbbbbb - // 2 11 110bbbbb 10bbbbbb - // 3 16 1110bbbb 10bbbbbb 10bbbbbb - // 4 21 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb - - $utf8length = strlen($utf8text); - $decodedtext = ''; - for ($i = 0; $i < $utf8length; $i++) { - if ((ord($utf8text[$i]) & 0x80) == 0) { - $decodedtext .= $utf8text[$i]; - } elseif ((ord($utf8text[$i]) & 0xF0) == 0xF0) { - $decodedtext .= '?'; - $i += 3; - } elseif ((ord($utf8text[$i]) & 0xE0) == 0xE0) { +function utf8_to_iso8859_1($utf8text) { + // http://www.php.net/manual/en/function.utf8-encode.php + // bytes bits representation + // 1 7 0bbbbbbb + // 2 11 110bbbbb 10bbbbbb + // 3 16 1110bbbb 10bbbbbb 10bbbbbb + // 4 21 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb + + $utf8length = strlen($utf8text); + $decodedtext = ''; + for ($i = 0; $i < $utf8length; $i++) { + if ((ord($utf8text[$i]) & 0x80) == 0) { + $decodedtext .= $utf8text[$i]; + } elseif ((ord($utf8text[$i]) & 0xF0) == 0xF0) { + $decodedtext .= '?'; + $i += 3; + } elseif ((ord($utf8text[$i]) & 0xE0) == 0xE0) { + $decodedtext .= '?'; + $i += 2; + } elseif ((ord($utf8text[$i]) & 0xC0) == 0xC0) { + // 2 11 110bbbbb 10bbbbbb + $decodedchar = Bin2Dec(substr(Dec2Bin(ord($utf8text[$i])), 3, 5).substr(Dec2Bin(ord($utf8text[($i + 1)])), 2, 6)); + if ($decodedchar <= 255) { + $decodedtext .= chr($decodedchar); + } else { $decodedtext .= '?'; - $i += 2; - } elseif ((ord($utf8text[$i]) & 0xC0) == 0xC0) { - // 2 11 110bbbbb 10bbbbbb - $decodedchar = Bin2Dec(substr(Dec2Bin(ord($utf8text[$i])), 3, 5).substr(Dec2Bin(ord($utf8text[($i + 1)])), 2, 6)); - if ($decodedchar <= 255) { - $decodedtext .= chr($decodedchar); - } else { - $decodedtext .= '?'; - } - $i += 1; } + $i += 1; } - return $decodedtext; } + return $decodedtext; } + if (!function_exists('DateMac2Unix')) { function DateMac2Unix($macdate) { // Macintosh timestamp: seconds since 00:00h January 1, 1904 diff --git a/getid3/getid3.lib.php b/getid3/getid3.lib.php index ba7a8e68..23c57a80 100644 --- a/getid3/getid3.lib.php +++ b/getid3/getid3.lib.php @@ -871,10 +871,6 @@ public static function iconv_fallback_int_utf8($charval) { * @return string */ public static function iconv_fallback_iso88591_utf8($string, $bom=false) { - if (function_exists('utf8_encode')) { - return utf8_encode($string); - } - // utf8_encode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support) $newcharstring = ''; if ($bom) { $newcharstring .= "\xEF\xBB\xBF"; @@ -943,10 +939,6 @@ public static function iconv_fallback_iso88591_utf16($string) { * @return string */ public static function iconv_fallback_utf8_iso88591($string) { - if (function_exists('utf8_decode')) { - return utf8_decode($string); - } - // utf8_decode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support) $newcharstring = ''; $offset = 0; $stringlength = strlen($string); From 4f23aee4323f65c41463148f4d0d87c22f08ded2 Mon Sep 17 00:00:00 2001 From: StudioMaX Date: Thu, 27 Oct 2022 15:47:49 +0600 Subject: [PATCH 03/25] Upgrade PHPStan to v1.8.11 --- .github/workflows/continuous-integration.yml | 2 +- getid3/getid3.lib.php | 2 +- getid3/getid3.php | 18 ++++++++++--- getid3/module.audio-video.asf.php | 6 ++--- getid3/module.audio-video.quicktime.php | 10 +++---- getid3/module.audio-video.riff.php | 16 +++++------ getid3/module.audio.dsdiff.php | 10 ++++--- getid3/module.audio.mp3.php | 16 +---------- getid3/module.audio.ogg.php | 4 +-- getid3/module.audio.wavpack.php | 6 ++--- getid3/module.tag.apetag.php | 4 +-- getid3/module.tag.id3v1.php | 2 +- getid3/module.tag.id3v2.php | 2 +- getid3/write.id3v1.php | 3 ++- getid3/write.id3v2.php | 28 +++++--------------- getid3/write.php | 2 +- phpstan.neon | 1 + 17 files changed, 60 insertions(+), 72 deletions(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 881d3446..0ddfe694 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -41,7 +41,7 @@ jobs: - uses: "shivammathur/setup-php@v2" with: php-version: "7.4" - tools: "phpstan:0.12.99" + tools: "phpstan:1.8.11" coverage: "none" - uses: "ramsey/composer-install@v2" - name: "Run PHPStan" diff --git a/getid3/getid3.lib.php b/getid3/getid3.lib.php index ba7a8e68..c154fbda 100644 --- a/getid3/getid3.lib.php +++ b/getid3/getid3.lib.php @@ -134,7 +134,7 @@ public static function intValueSupported($num) { */ public static function DecimalizeFraction($fraction) { list($numerator, $denominator) = explode('/', $fraction); - return $numerator / ($denominator ? $denominator : 1); + return (int) $numerator / ($denominator ? $denominator : 1); } /** diff --git a/getid3/getid3.php b/getid3/getid3.php index 5e955304..756ad6e5 100644 --- a/getid3/getid3.php +++ b/getid3/getid3.php @@ -436,17 +436,17 @@ public function __construct() { $this->startup_error .= 'WARNING: php.ini contains "mbstring.func_overload = '.ini_get('mbstring.func_overload').'", getID3 cannot run with this setting (bitmask 2 (string functions) cannot be set). Recommended to disable entirely.'."\n"; } - // check for magic quotes in PHP < 7.4.0 (when these functions became deprecated) - if (version_compare(PHP_VERSION, '7.4.0', '<')) { + // check for magic quotes in PHP < 5.4.0 (when these options were removed and getters always return false) + if (version_compare(PHP_VERSION, '5.4.0', '<')) { // Check for magic_quotes_runtime if (function_exists('get_magic_quotes_runtime')) { - if (get_magic_quotes_runtime()) { + if (get_magic_quotes_runtime()) { // @phpstan-ignore-line $this->startup_error .= 'magic_quotes_runtime must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_runtime(0) and set_magic_quotes_runtime(1).'."\n"; } } // Check for magic_quotes_gpc if (function_exists('get_magic_quotes_gpc')) { - if (get_magic_quotes_gpc()) { + if (get_magic_quotes_gpc()) { // @phpstan-ignore-line $this->startup_error .= 'magic_quotes_gpc must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_gpc(0) and set_magic_quotes_gpc(1).'."\n"; } } @@ -2183,6 +2183,8 @@ public function setStringMode($string) { } /** + * @phpstan-impure + * * @return int|bool */ protected function ftell() { @@ -2195,6 +2197,8 @@ protected function ftell() { /** * @param int $bytes * + * @phpstan-impure + * * @return string|false * * @throws getid3_exception @@ -2240,6 +2244,8 @@ protected function fread($bytes) { * @param int $bytes * @param int $whence * + * @phpstan-impure + * * @return int * * @throws getid3_exception @@ -2281,6 +2287,8 @@ protected function fseek($bytes, $whence=SEEK_SET) { } /** + * @phpstan-impure + * * @return string|false * * @throws getid3_exception @@ -2336,6 +2344,8 @@ protected function fgets() { } /** + * @phpstan-impure + * * @return bool */ protected function feof() { diff --git a/getid3/module.audio-video.asf.php b/getid3/module.audio-video.asf.php index e83de754..e01cac4b 100644 --- a/getid3/module.audio-video.asf.php +++ b/getid3/module.audio-video.asf.php @@ -193,7 +193,7 @@ public function Analyze() { $info['playtime_seconds'] = ($thisfile_asf_filepropertiesobject['play_duration'] / 10000000) - ($thisfile_asf_filepropertiesobject['preroll'] / 1000); //$info['bitrate'] = $thisfile_asf_filepropertiesobject['max_bitrate']; - $info['bitrate'] = ((isset($thisfile_asf_filepropertiesobject['filesize']) ? $thisfile_asf_filepropertiesobject['filesize'] : $info['filesize']) * 8) / $info['playtime_seconds']; + $info['bitrate'] = ($thisfile_asf_filepropertiesobject['filesize'] * 8) / $info['playtime_seconds']; } break; @@ -1066,7 +1066,7 @@ public function Analyze() { break; } - if (!empty($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'])) { + if (!empty($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'])) { // @phpstan-ignore-line foreach ($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'] as $dummy => $dataarray) { if (isset($dataarray['flags']['stream_number']) && ($dataarray['flags']['stream_number'] == $streamnumber)) { $thisfile_asf_audiomedia_currentstream['bitrate'] = $dataarray['bitrate']; @@ -1152,7 +1152,7 @@ public function Analyze() { $videomediaoffset += 4; $thisfile_asf_videomedia_currentstream['format_data']['codec_data'] = substr($streamdata['type_specific_data'], $videomediaoffset); - if (!empty($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'])) { + if (!empty($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'])) { // @phpstan-ignore-line foreach ($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'] as $dummy => $dataarray) { if (isset($dataarray['flags']['stream_number']) && ($dataarray['flags']['stream_number'] == $streamnumber)) { $thisfile_asf_videomedia_currentstream['bitrate'] = $dataarray['bitrate']; diff --git a/getid3/module.audio-video.quicktime.php b/getid3/module.audio-video.quicktime.php index a769f9c1..433f4685 100644 --- a/getid3/module.audio-video.quicktime.php +++ b/getid3/module.audio-video.quicktime.php @@ -151,7 +151,7 @@ public function Analyze() { } elseif (strlen($lat_deg) == 4) { // [+-]DDMM.M $ISO6709parsed['latitude'] = (($lat_sign == '-') ? -1 : 1) * floatval(ltrim(substr($lat_deg, 0, 2), '0')) + floatval(ltrim(substr($lat_deg, 2, 2), '0').$lat_deg_dec / 60); } elseif (strlen($lat_deg) == 6) { // [+-]DDMMSS.S - $ISO6709parsed['latitude'] = (($lat_sign == '-') ? -1 : 1) * floatval(ltrim(substr($lat_deg, 0, 2), '0')) + floatval(ltrim(substr($lat_deg, 2, 2), '0') / 60) + floatval(ltrim(substr($lat_deg, 4, 2), '0').$lat_deg_dec / 3600); + $ISO6709parsed['latitude'] = (($lat_sign == '-') ? -1 : 1) * floatval(ltrim(substr($lat_deg, 0, 2), '0')) + floatval((int) ltrim(substr($lat_deg, 2, 2), '0') / 60) + floatval(ltrim(substr($lat_deg, 4, 2), '0').$lat_deg_dec / 3600); } if (strlen($lon_deg) == 3) { // [+-]DDD.D @@ -159,7 +159,7 @@ public function Analyze() { } elseif (strlen($lon_deg) == 5) { // [+-]DDDMM.M $ISO6709parsed['longitude'] = (($lon_sign == '-') ? -1 : 1) * floatval(ltrim(substr($lon_deg, 0, 2), '0')) + floatval(ltrim(substr($lon_deg, 2, 2), '0').$lon_deg_dec / 60); } elseif (strlen($lon_deg) == 7) { // [+-]DDDMMSS.S - $ISO6709parsed['longitude'] = (($lon_sign == '-') ? -1 : 1) * floatval(ltrim(substr($lon_deg, 0, 2), '0')) + floatval(ltrim(substr($lon_deg, 2, 2), '0') / 60) + floatval(ltrim(substr($lon_deg, 4, 2), '0').$lon_deg_dec / 3600); + $ISO6709parsed['longitude'] = (($lon_sign == '-') ? -1 : 1) * floatval(ltrim(substr($lon_deg, 0, 2), '0')) + floatval((int) ltrim(substr($lon_deg, 2, 2), '0') / 60) + floatval(ltrim(substr($lon_deg, 4, 2), '0').$lon_deg_dec / 3600); } if (strlen($alt_deg) == 3) { // [+-]DDD.D @@ -167,7 +167,7 @@ public function Analyze() { } elseif (strlen($alt_deg) == 5) { // [+-]DDDMM.M $ISO6709parsed['altitude'] = (($alt_sign == '-') ? -1 : 1) * floatval(ltrim(substr($alt_deg, 0, 2), '0')) + floatval(ltrim(substr($alt_deg, 2, 2), '0').$alt_deg_dec / 60); } elseif (strlen($alt_deg) == 7) { // [+-]DDDMMSS.S - $ISO6709parsed['altitude'] = (($alt_sign == '-') ? -1 : 1) * floatval(ltrim(substr($alt_deg, 0, 2), '0')) + floatval(ltrim(substr($alt_deg, 2, 2), '0') / 60) + floatval(ltrim(substr($alt_deg, 4, 2), '0').$alt_deg_dec / 3600); + $ISO6709parsed['altitude'] = (($alt_sign == '-') ? -1 : 1) * floatval(ltrim(substr($alt_deg, 0, 2), '0')) + floatval((int) ltrim(substr($alt_deg, 2, 2), '0') / 60) + floatval(ltrim(substr($alt_deg, 4, 2), '0').$alt_deg_dec / 3600); } foreach (array('latitude', 'longitude', 'altitude') as $key) { @@ -1665,7 +1665,7 @@ public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset ); $atom_structure['data'] = $atom_data; $atom_structure['image_mime'] = 'image/jpeg'; - $atom_structure['description'] = isset($descriptions[$atomname]) ? $descriptions[$atomname] : 'Nikon preview image'; + $atom_structure['description'] = $descriptions[$atomname]; $info['quicktime']['comments']['picture'][] = array( 'image_mime' => $atom_structure['image_mime'], 'data' => $atom_data, @@ -1682,7 +1682,7 @@ public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset case 'NCHD': // Nikon:MakerNoteVersion - https://exiftool.org/TagNames/Nikon.html $makerNoteVersion = ''; for ($i = 0, $iMax = strlen($atom_data); $i < $iMax; ++$i) { - if (ord($atom_data[$i]) >= 0x00 && ord($atom_data[$i]) <= 0x1F) { + if (ord($atom_data[$i]) <= 0x1F) { $makerNoteVersion .= ' '.ord($atom_data[$i]); } else { $makerNoteVersion .= $atom_data[$i]; diff --git a/getid3/module.audio-video.riff.php b/getid3/module.audio-video.riff.php index e745ec65..6dc66531 100644 --- a/getid3/module.audio-video.riff.php +++ b/getid3/module.audio-video.riff.php @@ -440,11 +440,11 @@ public function Analyze() { $thisfile_riff_WAVE['iXML'][0]['parsed'] = $parsedXML; if (isset($parsedXML['SPEED']['MASTER_SPEED'])) { @list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['MASTER_SPEED']); - $thisfile_riff_WAVE['iXML'][0]['master_speed'] = $numerator / ($denominator ? $denominator : 1000); + $thisfile_riff_WAVE['iXML'][0]['master_speed'] = (int) $numerator / ($denominator ? $denominator : 1000); } if (isset($parsedXML['SPEED']['TIMECODE_RATE'])) { @list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['TIMECODE_RATE']); - $thisfile_riff_WAVE['iXML'][0]['timecode_rate'] = $numerator / ($denominator ? $denominator : 1000); + $thisfile_riff_WAVE['iXML'][0]['timecode_rate'] = (int) $numerator / ($denominator ? $denominator : 1000); } if (isset($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO']) && !empty($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) && !empty($thisfile_riff_WAVE['iXML'][0]['timecode_rate'])) { $samples_since_midnight = floatval(ltrim($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_HI'].$parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO'], '0')); @@ -632,7 +632,7 @@ public function Analyze() { } } if ($info['avdataend'] > $info['filesize']) { - switch (!empty($thisfile_audio_dataformat) ? $thisfile_audio_dataformat : '') { + switch ($thisfile_audio_dataformat) { case 'wavpack': // WavPack case 'lpac': // LPAC case 'ofr': // OptimFROG @@ -672,7 +672,7 @@ public function Analyze() { $this->warning('Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored'); } } - if (isset($thisfile_audio_dataformat) && ($thisfile_audio_dataformat == 'ac3')) { + if ($thisfile_audio_dataformat == 'ac3') { unset($thisfile_audio['bits_per_sample']); if (!empty($info['ac3']['bitrate']) && ($info['ac3']['bitrate'] != $thisfile_audio['bitrate'])) { $thisfile_audio['bitrate'] = $info['ac3']['bitrate']; @@ -781,15 +781,15 @@ public function Analyze() { /** @var array $thisfile_riff_video_current */ $thisfile_riff_video_current = &$thisfile_riff_video[$streamindex]; - if ($thisfile_riff_raw_avih['dwWidth'] > 0) { + if ($thisfile_riff_raw_avih['dwWidth'] > 0) { // @phpstan-ignore-line $thisfile_riff_video_current['frame_width'] = $thisfile_riff_raw_avih['dwWidth']; $thisfile_video['resolution_x'] = $thisfile_riff_video_current['frame_width']; } - if ($thisfile_riff_raw_avih['dwHeight'] > 0) { + if ($thisfile_riff_raw_avih['dwHeight'] > 0) { // @phpstan-ignore-line $thisfile_riff_video_current['frame_height'] = $thisfile_riff_raw_avih['dwHeight']; $thisfile_video['resolution_y'] = $thisfile_riff_video_current['frame_height']; } - if ($thisfile_riff_raw_avih['dwTotalFrames'] > 0) { + if ($thisfile_riff_raw_avih['dwTotalFrames'] > 0) { // @phpstan-ignore-line $thisfile_riff_video_current['total_frames'] = $thisfile_riff_raw_avih['dwTotalFrames']; $thisfile_video['total_frames'] = $thisfile_riff_video_current['total_frames']; } @@ -1913,7 +1913,7 @@ public function ParseRIFF($startoffset, $maxoffset) { if (isset($RIFFchunk[$chunkname][$thisindex]) && empty($RIFFchunk[$chunkname][$thisindex])) { unset($RIFFchunk[$chunkname][$thisindex]); } - if (isset($RIFFchunk[$chunkname]) && empty($RIFFchunk[$chunkname])) { + if (count($RIFFchunk[$chunkname]) === 0) { unset($RIFFchunk[$chunkname]); } $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['data'] = $this->fread($chunksize); diff --git a/getid3/module.audio.dsdiff.php b/getid3/module.audio.dsdiff.php index 20fb0d9a..9afeddf2 100644 --- a/getid3/module.audio.dsdiff.php +++ b/getid3/module.audio.dsdiff.php @@ -195,9 +195,13 @@ public function Analyze() { $this->fseek(1, SEEK_CUR); } - if ($commentkey = (($thisChunk['name'] == 'DIAR') ? 'artist' : (($thisChunk['name'] == 'DITI') ? 'title' : ''))) { - @$info['dsdiff']['comments'][$commentkey][] = $thisChunk['description']; - } + $commentKeys = array( + 'DIAR' => 'artist', + 'DITI' => 'title' + ); + $commentkey = $commentKeys[$thisChunk['name']]; + + $info['dsdiff']['comments'][$commentkey][] = $thisChunk['description']; break; case 'EMID': // Edited Master ID chunk if ($thisChunk['size']) { diff --git a/getid3/module.audio.mp3.php b/getid3/module.audio.mp3.php index 3d8a9442..5d808028 100644 --- a/getid3/module.audio.mp3.php +++ b/getid3/module.audio.mp3.php @@ -1475,7 +1475,7 @@ public function getOnlyMPEGaudioInfo($avdataoffset, $BitrateHistogram=false) { $SyncSeekAttemptsMax = 1000; $FirstFrameThisfileInfo = null; while ($SynchSeekOffset < $sync_seek_buffer_size) { - if ((($avdataoffset + $SynchSeekOffset) < $info['avdataend']) && !feof($this->getid3->fp)) { + if ((($avdataoffset + $SynchSeekOffset) < $info['avdataend']) && !$this->feof()) { if ($SynchSeekOffset > $sync_seek_buffer_size) { // if a synch's not found within the first 128k bytes, then give up @@ -1490,20 +1490,6 @@ public function getOnlyMPEGaudioInfo($avdataoffset, $BitrateHistogram=false) { unset($info['mpeg']); } return false; - - } elseif (feof($this->getid3->fp)) { - - $this->error('Could not find valid MPEG audio synch before end of file'); - if (isset($info['audio']['bitrate'])) { - unset($info['audio']['bitrate']); - } - if (isset($info['mpeg']['audio'])) { - unset($info['mpeg']['audio']); - } - if (isset($info['mpeg']) && (!is_array($info['mpeg']) || (count($info['mpeg']) == 0))) { - unset($info['mpeg']); - } - return false; } } diff --git a/getid3/module.audio.ogg.php b/getid3/module.audio.ogg.php index 0cbea61e..801c0c2c 100644 --- a/getid3/module.audio.ogg.php +++ b/getid3/module.audio.ogg.php @@ -534,12 +534,12 @@ public function ParseOggPageHeader() { $filedata = $this->fread($this->getid3->fread_buffer_size()); $filedataoffset = 0; - while ((substr($filedata, $filedataoffset++, 4) != 'OggS')) { + while (substr($filedata, $filedataoffset++, 4) != 'OggS') { if (($this->ftell() - $oggheader['page_start_offset']) >= $this->getid3->fread_buffer_size()) { // should be found before here return false; } - if ((($filedataoffset + 28) > strlen($filedata)) || (strlen($filedata) < 28)) { + if (($filedataoffset + 28) > strlen($filedata)) { if ($this->feof() || (($filedata .= $this->fread($this->getid3->fread_buffer_size())) === '')) { // get some more data, unless eof, in which case fail return false; diff --git a/getid3/module.audio.wavpack.php b/getid3/module.audio.wavpack.php index dfeb85d4..570f1293 100644 --- a/getid3/module.audio.wavpack.php +++ b/getid3/module.audio.wavpack.php @@ -42,7 +42,7 @@ public function Analyze() { if ($this->ftell() >= $info['avdataend']) { break; - } elseif (feof($this->getid3->fp)) { + } elseif ($this->feof()) { break; } elseif ( isset($info['wavpack']['blockheader']['total_samples']) && @@ -157,11 +157,11 @@ public function Analyze() { $info['audio']['lossless'] = !$info['wavpack']['blockheader']['flags']['hybrid']; } - while (!feof($this->getid3->fp) && ($this->ftell() < ($blockheader_offset + $blockheader_size + 8))) { + while (!$this->feof() && ($this->ftell() < ($blockheader_offset + $blockheader_size + 8))) { $metablock = array('offset'=>$this->ftell()); $metablockheader = $this->fread(2); - if (feof($this->getid3->fp)) { + if ($this->feof()) { break; } $metablock['id'] = ord($metablockheader[0]); diff --git a/getid3/module.tag.apetag.php b/getid3/module.tag.apetag.php index c5502133..1305cfb5 100644 --- a/getid3/module.tag.apetag.php +++ b/getid3/module.tag.apetag.php @@ -267,7 +267,7 @@ public function Analyze() { case 'cover art (publisher logo)': case 'cover art (recording)': case 'cover art (studio)': - // list of possible cover arts from http://taglib-sharp.sourcearchive.com/documentation/2.0.3.0-2/Ape_2Tag_8cs-source.html + // list of possible cover arts from https://github.com/mono/taglib-sharp/blob/taglib-sharp-2.0.3.2/src/TagLib/Ape/Tag.cs if (is_array($thisfile_ape_items_current['data'])) { $this->warning('APEtag "'.$item_key.'" should be flagged as Binary data, but was incorrectly flagged as UTF-8'); $thisfile_ape_items_current['data'] = implode("\x00", $thisfile_ape_items_current['data']); @@ -332,7 +332,7 @@ public function Analyze() { $info['ape']['comments']['picture'][] = $comments_picture_data; unset($comments_picture_data); } - } while (false); + } while (false); // @phpstan-ignore-line break; default: diff --git a/getid3/module.tag.id3v1.php b/getid3/module.tag.id3v1.php index b1de2578..442aefe3 100644 --- a/getid3/module.tag.id3v1.php +++ b/getid3/module.tag.id3v1.php @@ -66,7 +66,7 @@ public function Analyze() { if (!empty($ParsedID3v1['genre'])) { unset($ParsedID3v1['genreid']); } - if (isset($ParsedID3v1['genre']) && (empty($ParsedID3v1['genre']) || ($ParsedID3v1['genre'] == 'Unknown'))) { + if (empty($ParsedID3v1['genre']) || ($ParsedID3v1['genre'] == 'Unknown')) { unset($ParsedID3v1['genre']); } diff --git a/getid3/module.tag.id3v2.php b/getid3/module.tag.id3v2.php index 9e7b4eb1..5b907434 100644 --- a/getid3/module.tag.id3v2.php +++ b/getid3/module.tag.id3v2.php @@ -1494,7 +1494,7 @@ public function ParseID3v2Frame(&$parsedFrame) { unset($comments_picture_data); } } - } while (false); + } while (false); // @phpstan-ignore-line } } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'GEOB')) || // 4.15 GEOB General encapsulated object diff --git a/getid3/write.id3v1.php b/getid3/write.id3v1.php index 22c46779..c961e937 100644 --- a/getid3/write.id3v1.php +++ b/getid3/write.id3v1.php @@ -80,7 +80,8 @@ public function WriteID3v1() { (isset($this->tag_data['year'] ) ? $this->tag_data['year'] : ''), (isset($this->tag_data['genreid'] ) ? $this->tag_data['genreid'] : ''), (isset($this->tag_data['comment'] ) ? $this->tag_data['comment'] : ''), - (isset($this->tag_data['track_number']) ? $this->tag_data['track_number'] : '')); + $this->tag_data['track_number'] + ); fwrite($fp_source, $new_id3v1_tag_data, 128); fclose($fp_source); return true; diff --git a/getid3/write.id3v2.php b/getid3/write.id3v2.php index 7385a459..e6b40f3b 100644 --- a/getid3/write.id3v2.php +++ b/getid3/write.id3v2.php @@ -126,26 +126,12 @@ public function WriteID3v2() { if (file_exists($this->filename) && getID3::is_writable($this->filename) && isset($OldThisFileInfo['id3v2']['headerlength']) && ($OldThisFileInfo['id3v2']['headerlength'] == strlen($NewID3v2Tag))) { // best and fastest method - insert-overwrite existing tag (padded to length of old tag if neccesary) - if (file_exists($this->filename)) { - - if (is_readable($this->filename) && getID3::is_writable($this->filename) && is_file($this->filename) && ($fp = fopen($this->filename, 'r+b'))) { - rewind($fp); - fwrite($fp, $NewID3v2Tag, strlen($NewID3v2Tag)); - fclose($fp); - } else { - $this->errors[] = 'Could not fopen("'.$this->filename.'", "r+b")'; - } - + if (is_readable($this->filename) && is_file($this->filename) && ($fp = fopen($this->filename, 'r+b'))) { + rewind($fp); + fwrite($fp, $NewID3v2Tag, strlen($NewID3v2Tag)); + fclose($fp); } else { - - if (getID3::is_writable($this->filename) && is_file($this->filename) && ($fp = fopen($this->filename, 'wb'))) { - rewind($fp); - fwrite($fp, $NewID3v2Tag, strlen($NewID3v2Tag)); - fclose($fp); - } else { - $this->errors[] = 'Could not fopen("'.$this->filename.'", "wb")'; - } - + $this->errors[] = 'Could not fopen("'.$this->filename.'", "r+b")'; } } else { @@ -224,7 +210,7 @@ public function RemoveID3v2() { if ($OldThisFileInfo['avdataoffset'] !== false) { fseek($fp_source, $OldThisFileInfo['avdataoffset']); } - if (getID3::is_writable($this->filename) && is_file($this->filename) && ($fp_temp = fopen($this->filename.'getid3tmp', 'w+b'))) { + if (getID3::is_writable($this->filename) && ($fp_temp = fopen($this->filename.'getid3tmp', 'w+b'))) { while ($buffer = fread($fp_source, $this->fread_buffer_size)) { fwrite($fp_temp, $buffer, strlen($buffer)); } @@ -264,7 +250,7 @@ public function RemoveID3v2() { fwrite($fp_temp, $buffer, strlen($buffer)); } fclose($fp_source); - if (getID3::is_writable($this->filename) && is_file($this->filename) && ($fp_source = fopen($this->filename, 'wb'))) { + if (getID3::is_writable($this->filename) && ($fp_source = fopen($this->filename, 'wb'))) { rewind($fp_temp); while ($buffer = fread($fp_temp, $this->fread_buffer_size)) { fwrite($fp_source, $buffer, strlen($buffer)); diff --git a/getid3/write.php b/getid3/write.php index 1167e0f7..ea285670 100644 --- a/getid3/write.php +++ b/getid3/write.php @@ -679,7 +679,7 @@ public function FormatDataForID3v2($id3v2_majorversion) { $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = 0; $tag_data_id3v2[$ID3v2_framename][$key]['data'] = $value; $ID3v2_tag_data_converted = true; - } while (false); + } while (false); // @phpstan-ignore-line } if (!$ID3v2_tag_data_converted) { $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = 1; diff --git a/phpstan.neon b/phpstan.neon index 39fa10d8..94321ef7 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -5,6 +5,7 @@ parameters: - GETID3_OS_ISWINDOWS ignoreErrors: - '#Call to an undefined method COM::GetFile\(\)\.#' + - '#Constant GETID3_TEMP_DIR not found#' - '#Constant GETID3_HELPERAPPSDIR not found#' - '#Constant GETID3_ASF_(\w+) not found#' - From 273e47678035658a6c1c6837448f1732026b77cb Mon Sep 17 00:00:00 2001 From: Tim Starling Date: Mon, 14 Nov 2022 12:17:53 +1100 Subject: [PATCH 04/25] Guard against division by zero * Add getid3_lib::SafeDiv() which does a division with ternary guard. Avoids repeating the denominator expression. * Rearrange a few formulas to avoid unnecessary divisions. a/(b/c) = a*c/b except that the latter produces an answer when c=0. * Remediate divisions that may possibly divide by zero, or look suspicious. * In module.audio.midi.php: remove unused variable * In module.audio.mp3.php: raise an error for zero channels, since lots of things divide by the channel count. * In module.audio.voc.php: ignore channels=0, pretend channels=1 * In module.graphic.bmp.php: with ExtractData the RLE modes will divide by zero if width=0. With any compression mode, zero width or height means empty data, so add that as a shortcut. --- getid3/getid3.lib.php | 12 + getid3/getid3.php | 2 +- getid3/module.archive.hpk.php | 2 +- getid3/module.audio-video.asf.php | 2 +- getid3/module.audio-video.ivf.php | 4 +- getid3/module.audio-video.matroska.php | 12 +- getid3/module.audio-video.mpeg.php | 4 +- getid3/module.audio-video.nsv.php | 2 +- getid3/module.audio-video.real.php | 9 +- getid3/module.audio-video.riff.php | 6 +- getid3/module.audio.amr.php | 2 +- getid3/module.audio.au.php | 4 +- getid3/module.audio.avr.php | 6 +- getid3/module.audio.bonk.php | 2 +- getid3/module.audio.dsf.php | 2 +- getid3/module.audio.lpac.php | 4 +- getid3/module.audio.midi.php | 2 - getid3/module.audio.mp3.php | 10 +- getid3/module.audio.mpc.php | 4 +- getid3/module.audio.ogg.php | 8 +- getid3/module.audio.rkau.php | 2 +- getid3/module.audio.shorten.php | 4 +- getid3/module.audio.tta.php | 8 +- getid3/module.audio.voc.php | 6 +- getid3/module.audio.wavpack.php | 2 +- getid3/module.graphic.bmp.php | 564 +++++++++++++------------ 26 files changed, 354 insertions(+), 331 deletions(-) diff --git a/getid3/getid3.lib.php b/getid3/getid3.lib.php index d84bb4b6..aec550b3 100644 --- a/getid3/getid3.lib.php +++ b/getid3/getid3.lib.php @@ -127,6 +127,18 @@ public static function intValueSupported($num) { return false; } + /** + * Perform a division, guarding against division by zero + * + * @param float|int $numerator + * @param float|int $denominator + * @param float|int $fallback + * @return float|int + */ + public static function SafeDiv($numerator, $denominator, $fallback = 0) { + return $denominator ? $numerator / $denominator : $fallback; + } + /** * @param string $fraction * diff --git a/getid3/getid3.php b/getid3/getid3.php index 756ad6e5..a821ec14 100644 --- a/getid3/getid3.php +++ b/getid3/getid3.php @@ -1977,7 +1977,7 @@ public function CalculateCompressionRatioVideo() { } $BitrateUncompressed = $this->info['video']['resolution_x'] * $this->info['video']['resolution_y'] * $this->info['video']['bits_per_sample'] * $FrameRate; - $this->info['video']['compression_ratio'] = $BitrateCompressed / $BitrateUncompressed; + $this->info['video']['compression_ratio'] = getid3_lib::SafeDiv($BitrateCompressed, $BitrateUncompressed, 1); return true; } diff --git a/getid3/module.archive.hpk.php b/getid3/module.archive.hpk.php index 328dbd59..10c20dc0 100644 --- a/getid3/module.archive.hpk.php +++ b/getid3/module.archive.hpk.php @@ -43,7 +43,7 @@ public function Analyze() { $info['hpk']['header']['fragmented_filesystem_offset'] = getid3_lib::LittleEndian2Int(substr($HPKheader, 28, 4)); $info['hpk']['header']['fragmented_filesystem_length'] = getid3_lib::LittleEndian2Int(substr($HPKheader, 32, 4)); - $info['hpk']['header']['filesystem_entries'] = $info['hpk']['header']['fragmented_filesystem_length'] / ($info['hpk']['header']['fragments_per_file'] * 8); + $info['hpk']['header']['filesystem_entries'] = getid3_lib::SafeDiv($info['hpk']['header']['fragmented_filesystem_length'], $info['hpk']['header']['fragments_per_file'] * 8); $this->fseek($info['hpk']['header']['fragmented_filesystem_offset']); for ($i = 0; $i < $info['hpk']['header']['filesystem_entries']; $i++) { $offset = getid3_lib::LittleEndian2Int($this->fread(4)); diff --git a/getid3/module.audio-video.asf.php b/getid3/module.audio-video.asf.php index e01cac4b..4d3d377d 100644 --- a/getid3/module.audio-video.asf.php +++ b/getid3/module.audio-video.asf.php @@ -193,7 +193,7 @@ public function Analyze() { $info['playtime_seconds'] = ($thisfile_asf_filepropertiesobject['play_duration'] / 10000000) - ($thisfile_asf_filepropertiesobject['preroll'] / 1000); //$info['bitrate'] = $thisfile_asf_filepropertiesobject['max_bitrate']; - $info['bitrate'] = ($thisfile_asf_filepropertiesobject['filesize'] * 8) / $info['playtime_seconds']; + $info['bitrate'] = getid3_lib::SafeDiv($thisfile_asf_filepropertiesobject['filesize'] * 8, $info['playtime_seconds']); } break; diff --git a/getid3/module.audio-video.ivf.php b/getid3/module.audio-video.ivf.php index 293cc99b..c344cf76 100644 --- a/getid3/module.audio-video.ivf.php +++ b/getid3/module.audio-video.ivf.php @@ -45,7 +45,7 @@ public function Analyze() { $info['ivf']['header']['frame_count'] = getid3_lib::LittleEndian2Int(substr($IVFheader, 24, 4)); //$info['ivf']['header']['reserved'] = substr($IVFheader, 28, 4); - $info['ivf']['header']['frame_rate'] = (float) $info['ivf']['header']['timebase_numerator'] / $info['ivf']['header']['timebase_denominator']; + $info['ivf']['header']['frame_rate'] = (float)getid3_lib::SafeDiv($info['ivf']['header']['timebase_denominator'], $info['ivf']['header']['timebase_denominator']); if ($info['ivf']['header']['version'] > 0) { $this->warning('Expecting IVF header version 0, found version '.$info['ivf']['header']['version'].', results may not be accurate'); @@ -65,7 +65,7 @@ public function Analyze() { $info['ivf']['frame_count']++; } } - if ($info['ivf']['frame_count']) { + if ($info['ivf']['frame_count'] && $info['playtime_seconds']) { $info['playtime_seconds'] = $timestamp / 100000; $info['video']['frame_rate'] = (float) $info['ivf']['frame_count'] / $info['playtime_seconds']; } diff --git a/getid3/module.audio-video.matroska.php b/getid3/module.audio-video.matroska.php index 128e614e..eb5febf4 100644 --- a/getid3/module.audio-video.matroska.php +++ b/getid3/module.audio-video.matroska.php @@ -292,12 +292,12 @@ public function Analyze() $track_info['display_x'] = (isset($trackarray['DisplayWidth']) ? $trackarray['DisplayWidth'] : $trackarray['PixelWidth']); $track_info['display_y'] = (isset($trackarray['DisplayHeight']) ? $trackarray['DisplayHeight'] : $trackarray['PixelHeight']); - if (isset($trackarray['PixelCropBottom'])) { $track_info['crop_bottom'] = $trackarray['PixelCropBottom']; } - if (isset($trackarray['PixelCropTop'])) { $track_info['crop_top'] = $trackarray['PixelCropTop']; } - if (isset($trackarray['PixelCropLeft'])) { $track_info['crop_left'] = $trackarray['PixelCropLeft']; } - if (isset($trackarray['PixelCropRight'])) { $track_info['crop_right'] = $trackarray['PixelCropRight']; } - if (isset($trackarray['DefaultDuration'])) { $track_info['frame_rate'] = round(1000000000 / $trackarray['DefaultDuration'], 3); } - if (isset($trackarray['CodecName'])) { $track_info['codec'] = $trackarray['CodecName']; } + if (isset($trackarray['PixelCropBottom'])) { $track_info['crop_bottom'] = $trackarray['PixelCropBottom']; } + if (isset($trackarray['PixelCropTop'])) { $track_info['crop_top'] = $trackarray['PixelCropTop']; } + if (isset($trackarray['PixelCropLeft'])) { $track_info['crop_left'] = $trackarray['PixelCropLeft']; } + if (isset($trackarray['PixelCropRight'])) { $track_info['crop_right'] = $trackarray['PixelCropRight']; } + if (!empty($trackarray['DefaultDuration'])) { $track_info['frame_rate'] = round(1000000000 / $trackarray['DefaultDuration'], 3); } + if (isset($trackarray['CodecName'])) { $track_info['codec'] = $trackarray['CodecName']; } switch ($trackarray['CodecID']) { case 'V_MS/VFW/FOURCC': diff --git a/getid3/module.audio-video.mpeg.php b/getid3/module.audio-video.mpeg.php index 6d6b1cc5..fe16e326 100644 --- a/getid3/module.audio-video.mpeg.php +++ b/getid3/module.audio-video.mpeg.php @@ -505,9 +505,9 @@ public function Analyze() { $last_GOP_id = max(array_keys($FramesByGOP)); $frames_in_last_GOP = count($FramesByGOP[$last_GOP_id]); $gopdata = &$info['mpeg']['group_of_pictures'][$last_GOP_id]; - $info['playtime_seconds'] = ($gopdata['time_code_hours'] * 3600) + ($gopdata['time_code_minutes'] * 60) + $gopdata['time_code_seconds'] + (($gopdata['time_code_pictures'] + $frames_in_last_GOP + 1) / $info['mpeg']['video']['frame_rate']); + $info['playtime_seconds'] = ($gopdata['time_code_hours'] * 3600) + ($gopdata['time_code_minutes'] * 60) + $gopdata['time_code_seconds'] + getid3_lib::SafeDiv($gopdata['time_code_pictures'] + $frames_in_last_GOP + 1, $info['mpeg']['video']['frame_rate']); if (!isset($info['video']['bitrate'])) { - $overall_bitrate = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['playtime_seconds']; + $overall_bitrate = getid3_lib::SafeDiv($info['avdataend'] - $info['avdataoffset'] * 8, $info['playtime_seconds']); $info['video']['bitrate'] = $overall_bitrate - (isset($info['audio']['bitrate']) ? $info['audio']['bitrate'] : 0); } unset($info['mpeg']['group_of_pictures']); diff --git a/getid3/module.audio-video.nsv.php b/getid3/module.audio-video.nsv.php index 043cdfc6..b59642af 100644 --- a/getid3/module.audio-video.nsv.php +++ b/getid3/module.audio-video.nsv.php @@ -215,7 +215,7 @@ public function getNSVfHeaderFilepointer($fileoffset, $getTOCoffsets=false) { } $info['playtime_seconds'] = $info['nsv']['NSVf']['playtime_ms'] / 1000; - $info['bitrate'] = ($info['nsv']['NSVf']['file_size'] * 8) / $info['playtime_seconds']; + $info['bitrate'] = getid3_lib::SafeDiv($info['nsv']['NSVf']['file_size'] * 8, $info['playtime_seconds']); return true; } diff --git a/getid3/module.audio-video.real.php b/getid3/module.audio-video.real.php index 9b6762d7..188df62f 100644 --- a/getid3/module.audio-video.real.php +++ b/getid3/module.audio-video.real.php @@ -47,8 +47,13 @@ public function Analyze() { $info['audio']['bits_per_sample'] = $info['real']['old_ra_header']['bits_per_sample']; $info['audio']['channels'] = $info['real']['old_ra_header']['channels']; - $info['playtime_seconds'] = 60 * ($info['real']['old_ra_header']['audio_bytes'] / $info['real']['old_ra_header']['bytes_per_minute']); - $info['audio']['bitrate'] = 8 * ($info['real']['old_ra_header']['audio_bytes'] / $info['playtime_seconds']); + if ($info['real']['old_ra_header']['bytes_per_minute']) { + $info['playtime_seconds'] = 60 * ($info['real']['old_ra_header']['audio_bytes'] / $info['real']['old_ra_header']['bytes_per_minute']); + $info['audio']['bitrate'] = 8 * ($info['real']['old_ra_header']['audio_bytes'] / $info['playtime_seconds']); + } else { + $info['playtime_seconds'] = 0; + $info['audio']['bitrate'] = 0; + } $info['audio']['codec'] = $this->RealAudioCodecFourCClookup($info['real']['old_ra_header']['fourcc'], $info['audio']['bitrate']); foreach ($info['real']['old_ra_header']['comments'] as $key => $valuearray) { diff --git a/getid3/module.audio-video.riff.php b/getid3/module.audio-video.riff.php index 6dc66531..3dc18de4 100644 --- a/getid3/module.audio-video.riff.php +++ b/getid3/module.audio-video.riff.php @@ -214,7 +214,7 @@ public function Analyze() { $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate']; if (empty($info['playtime_seconds'])) { // may already be set (e.g. DTS-WAV) - $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $thisfile_audio['bitrate']); + $info['playtime_seconds'] = (float)getid3_lib::SafeDiv(($info['avdataend'] - $info['avdataoffset']) * 8, $thisfile_audio['bitrate']); } $thisfile_audio['lossless'] = false; @@ -521,7 +521,7 @@ public function Analyze() { if (!isset($thisfile_audio['bitrate']) && isset($thisfile_riff_audio[$streamindex]['bitrate'])) { $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate']; - $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $thisfile_audio['bitrate']); + $info['playtime_seconds'] = (float)getid3_lib::SafeDiv((($info['avdataend'] - $info['avdataoffset']) * 8), $thisfile_audio['bitrate']); } if (!empty($info['wavpack'])) { @@ -531,7 +531,7 @@ public function Analyze() { // Reset to the way it was - RIFF parsing will have messed this up $info['avdataend'] = $Original['avdataend']; - $thisfile_audio['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; + $thisfile_audio['bitrate'] = getid3_lib::SafeDiv(($info['avdataend'] - $info['avdataoffset']) * 8, $info['playtime_seconds']); $this->fseek($info['avdataoffset'] - 44); $RIFFdata = $this->fread(44); diff --git a/getid3/module.audio.amr.php b/getid3/module.audio.amr.php index e2e45316..2df9ff67 100644 --- a/getid3/module.audio.amr.php +++ b/getid3/module.audio.amr.php @@ -62,7 +62,7 @@ public function Analyze() { } while (strlen($buffer) > 0); $info['playtime_seconds'] = array_sum($thisfile_amr['frame_mode_count']) * 0.020; // each frame contain 160 samples and is 20 milliseconds long - $info['audio']['bitrate'] = (8 * ($info['avdataend'] - $info['avdataoffset'])) / $info['playtime_seconds']; // bitrate could be calculated from average bitrate by distributation of frame types. That would give effective audio bitrate, this gives overall file bitrate which will be a little bit higher since every frame will waste 8 bits for header, plus a few bits for octet padding + $info['audio']['bitrate'] = getid3_lib::SafeDiv(8 * ($info['avdataend'] - $info['avdataoffset']), $info['playtime_seconds']); // bitrate could be calculated from average bitrate by distributation of frame types. That would give effective audio bitrate, this gives overall file bitrate which will be a little bit higher since every frame will waste 8 bits for header, plus a few bits for octet padding $info['bitrate'] = $info['audio']['bitrate']; return true; diff --git a/getid3/module.audio.au.php b/getid3/module.audio.au.php index 73df1031..9be3e3f3 100644 --- a/getid3/module.audio.au.php +++ b/getid3/module.audio.au.php @@ -69,8 +69,8 @@ public function Analyze() { $this->warning('Possible truncated file - expecting "'.$thisfile_au['data_size'].'" bytes of audio data, only found '.($info['avdataend'] - $info['avdataoffset']).' bytes"'); } - $info['playtime_seconds'] = $thisfile_au['data_size'] / ($thisfile_au['sample_rate'] * $thisfile_au['channels'] * ($thisfile_au['used_bits_per_sample'] / 8)); - $info['audio']['bitrate'] = ($thisfile_au['data_size'] * 8) / $info['playtime_seconds']; + $info['audio']['bitrate'] = $thisfile_au['sample_rate'] * $thisfile_au['channels'] * $thisfile_au['used_bits_per_sample']; + $info['playtime_seconds'] = getid3_lib::SafeDiv($thisfile_au['data_size'], $info['audio']['bitrate'] / 8); return true; } diff --git a/getid3/module.audio.avr.php b/getid3/module.audio.avr.php index 69a26056..a681889f 100644 --- a/getid3/module.audio.avr.php +++ b/getid3/module.audio.avr.php @@ -120,9 +120,9 @@ public function Analyze() { $info['audio']['bits_per_sample'] = $info['avr']['bits_per_sample']; $info['audio']['sample_rate'] = $info['avr']['sample_rate']; $info['audio']['channels'] = ($info['avr']['flags']['stereo'] ? 2 : 1); - $info['playtime_seconds'] = ($info['avr']['sample_length'] / $info['audio']['channels']) / $info['avr']['sample_rate']; - $info['audio']['bitrate'] = ($info['avr']['sample_length'] * (($info['avr']['bits_per_sample'] == 8) ? 8 : 16)) / $info['playtime_seconds']; - + $bits_per_sample = ($info['avr']['bits_per_sample'] == 8) ? 8 : 16; + $info['audio']['bitrate'] = $bits_per_sample * $info['audio']['channels'] * $info['avr']['sample_rate']; + $info['playtime_seconds'] = getid3_lib::SafeDiv($info['avr']['sample_length'] * $bits_per_sample, $info['audio']['bitrate']); return true; } diff --git a/getid3/module.audio.bonk.php b/getid3/module.audio.bonk.php index c6cf9ac7..e283631a 100644 --- a/getid3/module.audio.bonk.php +++ b/getid3/module.audio.bonk.php @@ -154,7 +154,7 @@ public function HandleBonkTags($BonkTagName) { $info['audio']['lossless'] = $thisfile_bonk_BONK['lossless']; $info['audio']['codec'] = 'bonk'; - $info['playtime_seconds'] = $thisfile_bonk_BONK['number_samples'] / ($thisfile_bonk_BONK['sample_rate'] * $thisfile_bonk_BONK['channels']); + $info['playtime_seconds'] = getid3_lib::SafeDiv($thisfile_bonk_BONK['number_samples'], $thisfile_bonk_BONK['sample_rate'] * $thisfile_bonk_BONK['channels']); if ($info['playtime_seconds'] > 0) { $info['audio']['bitrate'] = (($info['bonk']['dataend'] - $info['bonk']['dataoffset']) * 8) / $info['playtime_seconds']; } diff --git a/getid3/module.audio.dsf.php b/getid3/module.audio.dsf.php index cd059c92..d8e43422 100644 --- a/getid3/module.audio.dsf.php +++ b/getid3/module.audio.dsf.php @@ -115,7 +115,7 @@ public function Analyze() { $info['audio']['sample_rate'] = $info['dsf']['fmt']['sample_rate']; $info['audio']['channels'] = $info['dsf']['fmt']['channels']; $info['audio']['bitrate'] = $info['audio']['bits_per_sample'] * $info['audio']['sample_rate'] * $info['audio']['channels']; - $info['playtime_seconds'] = ($info['dsf']['data']['data_chunk_size'] * 8) / $info['audio']['bitrate']; + $info['playtime_seconds'] = getid3_lib::SafeDiv($info['dsf']['data']['data_chunk_size'] * 8, $info['audio']['bitrate']); return true; } diff --git a/getid3/module.audio.lpac.php b/getid3/module.audio.lpac.php index 6656a141..427cf664 100644 --- a/getid3/module.audio.lpac.php +++ b/getid3/module.audio.lpac.php @@ -126,8 +126,8 @@ public function Analyze() { } } - $info['playtime_seconds'] = $info['lpac']['total_samples'] / $info['audio']['sample_rate']; - $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; + $info['playtime_seconds'] = getid3_lib::SafeDiv($info['lpac']['total_samples'], $info['audio']['sample_rate']); + $info['audio']['bitrate'] = getid3_lib::SafeDiv(($info['avdataend'] - $info['avdataoffset']) * 8, $info['playtime_seconds']); return true; } diff --git a/getid3/module.audio.midi.php b/getid3/module.audio.midi.php index d5fe81a2..d79a7f02 100644 --- a/getid3/module.audio.midi.php +++ b/getid3/module.audio.midi.php @@ -99,7 +99,6 @@ public function Analyze() { $thisfile_midi['totalticks'] = 0; $info['playtime_seconds'] = 0; $CurrentMicroSecondsPerBeat = 500000; // 120 beats per minute; 60,000,000 microseconds per minute -> 500,000 microseconds per beat - $CurrentBeatsPerMinute = 120; // 120 beats per minute; 60,000,000 microseconds per minute -> 500,000 microseconds per beat $MicroSecondsPerQuarterNoteAfter = array (); $MIDIevents = array(); @@ -244,7 +243,6 @@ public function Analyze() { return false; } $thisfile_midi_raw['events'][$tracknumber][$CumulativeDeltaTime]['us_qnote'] = $CurrentMicroSecondsPerBeat; - $CurrentBeatsPerMinute = (1000000 / $CurrentMicroSecondsPerBeat) * 60; $MicroSecondsPerQuarterNoteAfter[$CumulativeDeltaTime] = $CurrentMicroSecondsPerBeat; $TicksAtCurrentBPM = 0; break; diff --git a/getid3/module.audio.mp3.php b/getid3/module.audio.mp3.php index 5d808028..0d8fee3e 100644 --- a/getid3/module.audio.mp3.php +++ b/getid3/module.audio.mp3.php @@ -1380,11 +1380,11 @@ public function getOnlyMPEGaudioInfoBruteForce() { $Distribution['padding'][intval($LongMPEGpaddingLookup[$head4])] = isset($Distribution['padding'][intval($LongMPEGpaddingLookup[$head4])]) ? ++$Distribution['padding'][intval($LongMPEGpaddingLookup[$head4])] : 1; $Distribution['frequency'][$LongMPEGfrequencyLookup[$head4]] = isset($Distribution['frequency'][$LongMPEGfrequencyLookup[$head4]]) ? ++$Distribution['frequency'][$LongMPEGfrequencyLookup[$head4]] : 1; if (++$frames_scanned >= $max_frames_scan) { - $pct_data_scanned = ($this->ftell() - $info['avdataoffset']) / ($info['avdataend'] - $info['avdataoffset']); + $pct_data_scanned = getid3_lib::SafeDiv($this->ftell() - $info['avdataoffset'], $info['avdataend'] - $info['avdataoffset']); $this->warning('too many MPEG audio frames to scan, only scanned first '.$max_frames_scan.' frames ('.number_format($pct_data_scanned * 100, 1).'% of file) and extrapolated distribution, playtime and bitrate may be incorrect.'); foreach ($Distribution as $key1 => $value1) { foreach ($value1 as $key2 => $value2) { - $Distribution[$key1][$key2] = round($value2 / $pct_data_scanned); + $Distribution[$key1][$key2] = $pct_data_scanned ? round($value2 / $pct_data_scanned) : 1; } } break; @@ -1638,7 +1638,7 @@ public function getOnlyMPEGaudioInfo($avdataoffset, $BitrateHistogram=false) { } $frames_scanned++; if ($frames_scan_per_segment && (++$frames_scanned_this_segment >= $frames_scan_per_segment)) { - $this_pct_scanned = ($this->ftell() - $scan_start_offset[$current_segment]) / ($info['avdataend'] - $info['avdataoffset']); + $this_pct_scanned = getid3_lib::SafeDiv($this->ftell() - $scan_start_offset[$current_segment], $info['avdataend'] - $info['avdataoffset']); if (($current_segment == 0) && (($this_pct_scanned * $max_scan_segments) >= 1)) { // file likely contains < $max_frames_scan, just scan as one segment $max_scan_segments = 1; @@ -1729,6 +1729,10 @@ public function getOnlyMPEGaudioInfo($avdataoffset, $BitrateHistogram=false) { } $info['audio']['channels'] = $info['mpeg']['audio']['channels']; + if ($info['audio']['channels'] < 1) { + $this->error('Corrupt MP3 file: no channels'); + return false; + } $info['audio']['channelmode'] = $info['mpeg']['audio']['channelmode']; $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate']; return true; diff --git a/getid3/module.audio.mpc.php b/getid3/module.audio.mpc.php index e869e29f..f754f4b7 100644 --- a/getid3/module.audio.mpc.php +++ b/getid3/module.audio.mpc.php @@ -137,7 +137,7 @@ public function ParseMPCsv8() { $info['audio']['channels'] = $thisPacket['channels']; $info['audio']['sample_rate'] = $thisPacket['sample_frequency']; $info['playtime_seconds'] = $thisPacket['sample_count'] / $thisPacket['sample_frequency']; - $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; + $info['audio']['bitrate'] = getid3_lib::SafeDiv(($info['avdataend'] - $info['avdataoffset']) * 8, $info['playtime_seconds']); break; case 'RG': // Replay Gain @@ -282,7 +282,7 @@ public function ParseMPCsv7() { $info['audio']['sample_rate'] = $thisfile_mpc_header['sample_rate']; $thisfile_mpc_header['samples'] = ((($thisfile_mpc_header['frame_count'] - 1) * 1152) + $thisfile_mpc_header['last_frame_length']) * $info['audio']['channels']; - $info['playtime_seconds'] = ($thisfile_mpc_header['samples'] / $info['audio']['channels']) / $info['audio']['sample_rate']; + $info['playtime_seconds'] = getid3_lib::SafeDiv($thisfile_mpc_header['samples'], $info['audio']['channels'] * $info['audio']['sample_rate']); if ($info['playtime_seconds'] == 0) { $this->error('Corrupt MPC file: playtime_seconds == zero'); return false; diff --git a/getid3/module.audio.ogg.php b/getid3/module.audio.ogg.php index 801c0c2c..ebd2b946 100644 --- a/getid3/module.audio.ogg.php +++ b/getid3/module.audio.ogg.php @@ -210,8 +210,8 @@ public function Analyze() { $filedataoffset += 20; $info['ogg']['skeleton']['fishead']['version'] = $info['ogg']['skeleton']['fishead']['raw']['version_major'].'.'.$info['ogg']['skeleton']['fishead']['raw']['version_minor']; - $info['ogg']['skeleton']['fishead']['presentationtime'] = $info['ogg']['skeleton']['fishead']['raw']['presentationtime_numerator'] / $info['ogg']['skeleton']['fishead']['raw']['presentationtime_denominator']; - $info['ogg']['skeleton']['fishead']['basetime'] = $info['ogg']['skeleton']['fishead']['raw']['basetime_numerator'] / $info['ogg']['skeleton']['fishead']['raw']['basetime_denominator']; + $info['ogg']['skeleton']['fishead']['presentationtime'] = getid3_lib::SafeDiv($info['ogg']['skeleton']['fishead']['raw']['presentationtime_numerator'], $info['ogg']['skeleton']['fishead']['raw']['presentationtime_denominator']); + $info['ogg']['skeleton']['fishead']['basetime'] = getid3_lib::SafeDiv($info['ogg']['skeleton']['fishead']['raw']['basetime_numerator'], $info['ogg']['skeleton']['fishead']['raw']['basetime_denominator']); $info['ogg']['skeleton']['fishead']['utc'] = $info['ogg']['skeleton']['fishead']['raw']['utc']; @@ -288,7 +288,7 @@ public function Analyze() { $info['audio']['sample_rate'] = $info['flac']['STREAMINFO']['sample_rate']; $info['audio']['channels'] = $info['flac']['STREAMINFO']['channels']; $info['audio']['bits_per_sample'] = $info['flac']['STREAMINFO']['bits_per_sample']; - $info['playtime_seconds'] = $info['flac']['STREAMINFO']['samples_stream'] / $info['flac']['STREAMINFO']['sample_rate']; + $info['playtime_seconds'] = getid3_lib::SafeDiv($info['flac']['STREAMINFO']['samples_stream'], $info['flac']['STREAMINFO']['sample_rate']); } } else { @@ -359,7 +359,7 @@ public function Analyze() { return false; } if (!empty($info['audio']['sample_rate'])) { - $info['ogg']['bitrate_average'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / ($info['ogg']['samples'] / $info['audio']['sample_rate']); + $info['ogg']['bitrate_average'] = (($info['avdataend'] - $info['avdataoffset']) * 8) * $info['audio']['sample_rate'] / $info['ogg']['samples']; } } diff --git a/getid3/module.audio.rkau.php b/getid3/module.audio.rkau.php index 8bbacd43..be635473 100644 --- a/getid3/module.audio.rkau.php +++ b/getid3/module.audio.rkau.php @@ -75,7 +75,7 @@ public function Analyze() { $info['audio']['sample_rate'] = $info['rkau']['sample_rate']; $info['playtime_seconds'] = $info['rkau']['source_bytes'] / ($info['rkau']['sample_rate'] * $info['rkau']['channels'] * ($info['rkau']['bits_per_sample'] / 8)); - $info['audio']['bitrate'] = ($info['rkau']['compressed_bytes'] * 8) / $info['playtime_seconds']; + $info['audio']['bitrate'] = getid3_lib::SafeDiv($info['rkau']['compressed_bytes'] * 8, $info['playtime_seconds']); return true; diff --git a/getid3/module.audio.shorten.php b/getid3/module.audio.shorten.php index 673a4858..2e4060c0 100644 --- a/getid3/module.audio.shorten.php +++ b/getid3/module.audio.shorten.php @@ -166,7 +166,7 @@ public function Analyze() { if (substr($output, 20 + $fmt_size, 4) == 'data') { - $info['playtime_seconds'] = getid3_lib::LittleEndian2Int(substr($output, 20 + 4 + $fmt_size, 4)) / $DecodedWAVFORMATEX['raw']['nAvgBytesPerSec']; + $info['playtime_seconds'] = getid3_lib::SafeDiv(getid3_lib::LittleEndian2Int(substr($output, 20 + 4 + $fmt_size, 4)), $DecodedWAVFORMATEX['raw']['nAvgBytesPerSec']); } else { @@ -175,7 +175,7 @@ public function Analyze() { } - $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8; + $info['audio']['bitrate'] = getid3_lib::SafeDiv($info['avdataend'] - $info['avdataoffset'], $info['playtime_seconds']) * 8; } else { diff --git a/getid3/module.audio.tta.php b/getid3/module.audio.tta.php index 700cd05a..0f0aa8b5 100644 --- a/getid3/module.audio.tta.php +++ b/getid3/module.audio.tta.php @@ -59,7 +59,7 @@ public function Analyze() { $info['tta']['samples_per_channel'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 12, 4)); $info['audio']['encoder_options'] = '-e'.$info['tta']['compression_level']; - $info['playtime_seconds'] = $info['tta']['samples_per_channel'] / $info['tta']['sample_rate']; + $info['playtime_seconds'] = getid3_lib::SafeDiv($info['tta']['samples_per_channel'], $info['tta']['sample_rate']); break; case '2': // TTA v2.x @@ -75,7 +75,7 @@ public function Analyze() { $info['tta']['data_length'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 16, 4)); $info['audio']['encoder_options'] = '-e'.$info['tta']['compression_level']; - $info['playtime_seconds'] = $info['tta']['data_length'] / $info['tta']['sample_rate']; + $info['playtime_seconds'] = getid3_lib::SafeDiv($info['tta']['data_length'], $info['tta']['sample_rate']); break; case '1': // TTA v3.x @@ -91,7 +91,7 @@ public function Analyze() { $info['tta']['crc32_footer'] = substr($ttaheader, 18, 4); $info['tta']['seek_point'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 22, 4)); - $info['playtime_seconds'] = $info['tta']['data_length'] / $info['tta']['sample_rate']; + $info['playtime_seconds'] = getid3_lib::SafeDiv($info['tta']['data_length'], $info['tta']['sample_rate']); break; default: @@ -103,7 +103,7 @@ public function Analyze() { $info['audio']['bits_per_sample'] = $info['tta']['bits_per_sample']; $info['audio']['sample_rate'] = $info['tta']['sample_rate']; $info['audio']['channels'] = $info['tta']['channels']; - $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; + $info['audio']['bitrate'] = getid3_lib::SafeDiv(($info['avdataend'] - $info['avdataoffset']) * 8, $info['playtime_seconds']); return true; } diff --git a/getid3/module.audio.voc.php b/getid3/module.audio.voc.php index 6bed1318..9e771b18 100644 --- a/getid3/module.audio.voc.php +++ b/getid3/module.audio.voc.php @@ -140,7 +140,7 @@ public function Analyze() { $thisfile_audio['sample_rate'] = $ThisBlock['sample_rate']; $thisfile_audio['bits_per_sample'] = $ThisBlock['bits_per_sample']; - $thisfile_audio['channels'] = $ThisBlock['channels']; + $thisfile_audio['channels'] = $ThisBlock['channels'] ?: 1; break; default: @@ -164,8 +164,8 @@ public function Analyze() { ksort($thisfile_voc['blocktypes']); if (!empty($thisfile_voc['compressed_bits_per_sample'])) { - $info['playtime_seconds'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / ($thisfile_voc['compressed_bits_per_sample'] * $thisfile_audio['channels'] * $thisfile_audio['sample_rate']); - $thisfile_audio['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; + $info['playtime_seconds'] = getid3_lib::SafeDiv(($info['avdataend'] - $info['avdataoffset']) * 8, $thisfile_voc['compressed_bits_per_sample'] * $thisfile_audio['channels'] * $thisfile_audio['sample_rate']); + $thisfile_audio['bitrate'] = getid3_lib::SafeDiv(($info['avdataend'] - $info['avdataoffset']) * 8, $info['playtime_seconds']); } return true; diff --git a/getid3/module.audio.wavpack.php b/getid3/module.audio.wavpack.php index 570f1293..53602c33 100644 --- a/getid3/module.audio.wavpack.php +++ b/getid3/module.audio.wavpack.php @@ -243,7 +243,7 @@ public function Analyze() { $metablock['riff']['original_filesize'] = $original_wav_filesize; $info['wavpack']['riff_trailer_size'] = $original_wav_filesize - $metablock['riff']['WAVE']['data'][0]['size'] - $metablock['riff']['header_size']; - $info['playtime_seconds'] = $info['wavpack']['blockheader']['total_samples'] / $info['audio']['sample_rate']; + $info['playtime_seconds'] = getid3_lib::SafeDiv($info['wavpack']['blockheader']['total_samples'], $info['audio']['sample_rate']); // Safe RIFF header in case there's a RIFF footer later $metablockRIFFheader = $metablock['data']; diff --git a/getid3/module.graphic.bmp.php b/getid3/module.graphic.bmp.php index 84565701..fb394722 100644 --- a/getid3/module.graphic.bmp.php +++ b/getid3/module.graphic.bmp.php @@ -336,307 +336,311 @@ public function Analyze() { } if ($this->ExtractData) { - $this->fseek($thisfile_bmp_header_raw['data_offset']); - $RowByteLength = ceil(($thisfile_bmp_header_raw['width'] * ($thisfile_bmp_header_raw['bits_per_pixel'] / 8)) / 4) * 4; // round up to nearest DWORD boundry - $BMPpixelData = $this->fread($thisfile_bmp_header_raw['height'] * $RowByteLength); - $pixeldataoffset = 0; - $thisfile_bmp_header_raw['compression'] = (isset($thisfile_bmp_header_raw['compression']) ? $thisfile_bmp_header_raw['compression'] : ''); - switch ($thisfile_bmp_header_raw['compression']) { - - case 0: // BI_RGB - switch ($thisfile_bmp_header_raw['bits_per_pixel']) { - case 1: - for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) { - for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col = $col) { - $paletteindexbyte = ord($BMPpixelData[$pixeldataoffset++]); - for ($i = 7; $i >= 0; $i--) { - $paletteindex = ($paletteindexbyte & (0x01 << $i)) >> $i; - $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex]; - $col++; + if (!$thisfile_bmp_header_raw['width'] || !$thisfile_bmp_header_raw['height']) { + $thisfile_bmp['data'] = array(); + } else { + $this->fseek($thisfile_bmp_header_raw['data_offset']); + $RowByteLength = ceil(($thisfile_bmp_header_raw['width'] * ($thisfile_bmp_header_raw['bits_per_pixel'] / 8)) / 4) * 4; // round up to nearest DWORD boundry + $BMPpixelData = $this->fread($thisfile_bmp_header_raw['height'] * $RowByteLength); + $pixeldataoffset = 0; + $thisfile_bmp_header_raw['compression'] = (isset($thisfile_bmp_header_raw['compression']) ? $thisfile_bmp_header_raw['compression'] : ''); + switch ($thisfile_bmp_header_raw['compression']) { + + case 0: // BI_RGB + switch ($thisfile_bmp_header_raw['bits_per_pixel']) { + case 1: + for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) { + for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col = $col) { + $paletteindexbyte = ord($BMPpixelData[$pixeldataoffset++]); + for ($i = 7; $i >= 0; $i--) { + $paletteindex = ($paletteindexbyte & (0x01 << $i)) >> $i; + $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex]; + $col++; + } + } + while (($pixeldataoffset % 4) != 0) { + // lines are padded to nearest DWORD + $pixeldataoffset++; } } - while (($pixeldataoffset % 4) != 0) { - // lines are padded to nearest DWORD - $pixeldataoffset++; + break; + + case 4: + for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) { + for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col = $col) { + $paletteindexbyte = ord($BMPpixelData[$pixeldataoffset++]); + for ($i = 1; $i >= 0; $i--) { + $paletteindex = ($paletteindexbyte & (0x0F << (4 * $i))) >> (4 * $i); + $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex]; + $col++; + } + } + while (($pixeldataoffset % 4) != 0) { + // lines are padded to nearest DWORD + $pixeldataoffset++; + } } - } - break; - - case 4: - for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) { - for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col = $col) { - $paletteindexbyte = ord($BMPpixelData[$pixeldataoffset++]); - for ($i = 1; $i >= 0; $i--) { - $paletteindex = ($paletteindexbyte & (0x0F << (4 * $i))) >> (4 * $i); + break; + + case 8: + for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) { + for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) { + $paletteindex = ord($BMPpixelData[$pixeldataoffset++]); $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex]; - $col++; + } + while (($pixeldataoffset % 4) != 0) { + // lines are padded to nearest DWORD + $pixeldataoffset++; } } - while (($pixeldataoffset % 4) != 0) { - // lines are padded to nearest DWORD - $pixeldataoffset++; - } - } - break; - - case 8: - for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) { - for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) { - $paletteindex = ord($BMPpixelData[$pixeldataoffset++]); - $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex]; - } - while (($pixeldataoffset % 4) != 0) { - // lines are padded to nearest DWORD - $pixeldataoffset++; - } - } - break; - - case 24: - for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) { - for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) { - $thisfile_bmp['data'][$row][$col] = (ord($BMPpixelData[$pixeldataoffset+2]) << 16) | (ord($BMPpixelData[$pixeldataoffset+1]) << 8) | ord($BMPpixelData[$pixeldataoffset]); - $pixeldataoffset += 3; - } - while (($pixeldataoffset % 4) != 0) { - // lines are padded to nearest DWORD - $pixeldataoffset++; - } - } - break; - - case 32: - for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) { - for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) { - $thisfile_bmp['data'][$row][$col] = (ord($BMPpixelData[$pixeldataoffset+3]) << 24) | (ord($BMPpixelData[$pixeldataoffset+2]) << 16) | (ord($BMPpixelData[$pixeldataoffset+1]) << 8) | ord($BMPpixelData[$pixeldataoffset]); - $pixeldataoffset += 4; - } - while (($pixeldataoffset % 4) != 0) { - // lines are padded to nearest DWORD - $pixeldataoffset++; - } - } - break; + break; - case 16: - // ? - break; - - default: - $this->error('Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data'); - break; - } - break; - - - case 1: // BI_RLE8 - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_6x0u.asp - switch ($thisfile_bmp_header_raw['bits_per_pixel']) { - case 8: - $pixelcounter = 0; - while ($pixeldataoffset < strlen($BMPpixelData)) { - $firstbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - $secondbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - if ($firstbyte == 0) { - - // escaped/absolute mode - the first byte of the pair can be set to zero to - // indicate an escape character that denotes the end of a line, the end of - // a bitmap, or a delta, depending on the value of the second byte. - switch ($secondbyte) { - case 0: - // end of line - // no need for special processing, just ignore - break; - - case 1: - // end of bitmap - $pixeldataoffset = strlen($BMPpixelData); // force to exit loop just in case - break; - - case 2: - // delta - The 2 bytes following the escape contain unsigned values - // indicating the horizontal and vertical offsets of the next pixel - // from the current position. - $colincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - $rowincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - $col = ($pixelcounter % $thisfile_bmp_header_raw['width']) + $colincrement; - $row = ($thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width'])) - $rowincrement; - $pixelcounter = ($row * $thisfile_bmp_header_raw['width']) + $col; - break; - - default: - // In absolute mode, the first byte is zero and the second byte is a - // value in the range 03H through FFH. The second byte represents the - // number of bytes that follow, each of which contains the color index - // of a single pixel. Each run must be aligned on a word boundary. - for ($i = 0; $i < $secondbyte; $i++) { - $paletteindex = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - $col = $pixelcounter % $thisfile_bmp_header_raw['width']; - $row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']); - $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex]; - $pixelcounter++; - } - while (($pixeldataoffset % 2) != 0) { - // Each run must be aligned on a word boundary. - $pixeldataoffset++; - } - break; + case 24: + for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) { + for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) { + $thisfile_bmp['data'][$row][$col] = (ord($BMPpixelData[$pixeldataoffset+2]) << 16) | (ord($BMPpixelData[$pixeldataoffset+1]) << 8) | ord($BMPpixelData[$pixeldataoffset]); + $pixeldataoffset += 3; } - - } else { - - // encoded mode - the first byte specifies the number of consecutive pixels - // to be drawn using the color index contained in the second byte. - for ($i = 0; $i < $firstbyte; $i++) { - $col = $pixelcounter % $thisfile_bmp_header_raw['width']; - $row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']); - $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$secondbyte]; - $pixelcounter++; + while (($pixeldataoffset % 4) != 0) { + // lines are padded to nearest DWORD + $pixeldataoffset++; } - } - } - break; + break; - default: - $this->error('Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data'); - break; - } - break; - - - - case 2: // BI_RLE4 - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_6x0u.asp - switch ($thisfile_bmp_header_raw['bits_per_pixel']) { - case 4: - $pixelcounter = 0; - $paletteindexes = array(); - while ($pixeldataoffset < strlen($BMPpixelData)) { - $firstbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - $secondbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - if ($firstbyte == 0) { - - // escaped/absolute mode - the first byte of the pair can be set to zero to - // indicate an escape character that denotes the end of a line, the end of - // a bitmap, or a delta, depending on the value of the second byte. - switch ($secondbyte) { - case 0: - // end of line - // no need for special processing, just ignore - break; - - case 1: - // end of bitmap - $pixeldataoffset = strlen($BMPpixelData); // force to exit loop just in case - break; - - case 2: - // delta - The 2 bytes following the escape contain unsigned values - // indicating the horizontal and vertical offsets of the next pixel - // from the current position. - $colincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - $rowincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - $col = ($pixelcounter % $thisfile_bmp_header_raw['width']) + $colincrement; - $row = ($thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width'])) - $rowincrement; - $pixelcounter = ($row * $thisfile_bmp_header_raw['width']) + $col; - break; - - default: - // In absolute mode, the first byte is zero. The second byte contains the number - // of color indexes that follow. Subsequent bytes contain color indexes in their - // high- and low-order 4 bits, one color index for each pixel. In absolute mode, - // each run must be aligned on a word boundary. - $paletteindexes = array(); - for ($i = 0; $i < ceil($secondbyte / 2); $i++) { - $paletteindexbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - $paletteindexes[] = ($paletteindexbyte & 0xF0) >> 4; - $paletteindexes[] = ($paletteindexbyte & 0x0F); - } - while (($pixeldataoffset % 2) != 0) { - // Each run must be aligned on a word boundary. - $pixeldataoffset++; - } - - foreach ($paletteindexes as $paletteindex) { - $col = $pixelcounter % $thisfile_bmp_header_raw['width']; - $row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']); - $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex]; - $pixelcounter++; - } - break; + case 32: + for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) { + for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) { + $thisfile_bmp['data'][$row][$col] = (ord($BMPpixelData[$pixeldataoffset+3]) << 24) | (ord($BMPpixelData[$pixeldataoffset+2]) << 16) | (ord($BMPpixelData[$pixeldataoffset+1]) << 8) | ord($BMPpixelData[$pixeldataoffset]); + $pixeldataoffset += 4; } - - } else { - - // encoded mode - the first byte of the pair contains the number of pixels to be - // drawn using the color indexes in the second byte. The second byte contains two - // color indexes, one in its high-order 4 bits and one in its low-order 4 bits. - // The first of the pixels is drawn using the color specified by the high-order - // 4 bits, the second is drawn using the color in the low-order 4 bits, the third - // is drawn using the color in the high-order 4 bits, and so on, until all the - // pixels specified by the first byte have been drawn. - $paletteindexes[0] = ($secondbyte & 0xF0) >> 4; - $paletteindexes[1] = ($secondbyte & 0x0F); - for ($i = 0; $i < $firstbyte; $i++) { - $col = $pixelcounter % $thisfile_bmp_header_raw['width']; - $row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']); - $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindexes[($i % 2)]]; - $pixelcounter++; + while (($pixeldataoffset % 4) != 0) { + // lines are padded to nearest DWORD + $pixeldataoffset++; } + } + break; + + case 16: + // ? + break; + + default: + $this->error('Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data'); + break; + } + break; + + + case 1: // BI_RLE8 - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_6x0u.asp + switch ($thisfile_bmp_header_raw['bits_per_pixel']) { + case 8: + $pixelcounter = 0; + while ($pixeldataoffset < strlen($BMPpixelData)) { + $firstbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $secondbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + if ($firstbyte == 0) { + + // escaped/absolute mode - the first byte of the pair can be set to zero to + // indicate an escape character that denotes the end of a line, the end of + // a bitmap, or a delta, depending on the value of the second byte. + switch ($secondbyte) { + case 0: + // end of line + // no need for special processing, just ignore + break; + + case 1: + // end of bitmap + $pixeldataoffset = strlen($BMPpixelData); // force to exit loop just in case + break; + + case 2: + // delta - The 2 bytes following the escape contain unsigned values + // indicating the horizontal and vertical offsets of the next pixel + // from the current position. + $colincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $rowincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $col = ($pixelcounter % $thisfile_bmp_header_raw['width']) + $colincrement; + $row = ($thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width'])) - $rowincrement; + $pixelcounter = ($row * $thisfile_bmp_header_raw['width']) + $col; + break; + + default: + // In absolute mode, the first byte is zero and the second byte is a + // value in the range 03H through FFH. The second byte represents the + // number of bytes that follow, each of which contains the color index + // of a single pixel. Each run must be aligned on a word boundary. + for ($i = 0; $i < $secondbyte; $i++) { + $paletteindex = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $col = $pixelcounter % $thisfile_bmp_header_raw['width']; + $row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']); + $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex]; + $pixelcounter++; + } + while (($pixeldataoffset % 2) != 0) { + // Each run must be aligned on a word boundary. + $pixeldataoffset++; + } + break; + } + + } else { + + // encoded mode - the first byte specifies the number of consecutive pixels + // to be drawn using the color index contained in the second byte. + for ($i = 0; $i < $firstbyte; $i++) { + $col = $pixelcounter % $thisfile_bmp_header_raw['width']; + $row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']); + $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$secondbyte]; + $pixelcounter++; + } + } } - } - break; + break; + + default: + $this->error('Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data'); + break; + } + break; + + + + case 2: // BI_RLE4 - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_6x0u.asp + switch ($thisfile_bmp_header_raw['bits_per_pixel']) { + case 4: + $pixelcounter = 0; + $paletteindexes = array(); + while ($pixeldataoffset < strlen($BMPpixelData)) { + $firstbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $secondbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + if ($firstbyte == 0) { + + // escaped/absolute mode - the first byte of the pair can be set to zero to + // indicate an escape character that denotes the end of a line, the end of + // a bitmap, or a delta, depending on the value of the second byte. + switch ($secondbyte) { + case 0: + // end of line + // no need for special processing, just ignore + break; + + case 1: + // end of bitmap + $pixeldataoffset = strlen($BMPpixelData); // force to exit loop just in case + break; + + case 2: + // delta - The 2 bytes following the escape contain unsigned values + // indicating the horizontal and vertical offsets of the next pixel + // from the current position. + $colincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $rowincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $col = ($pixelcounter % $thisfile_bmp_header_raw['width']) + $colincrement; + $row = ($thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width'])) - $rowincrement; + $pixelcounter = ($row * $thisfile_bmp_header_raw['width']) + $col; + break; + + default: + // In absolute mode, the first byte is zero. The second byte contains the number + // of color indexes that follow. Subsequent bytes contain color indexes in their + // high- and low-order 4 bits, one color index for each pixel. In absolute mode, + // each run must be aligned on a word boundary. + $paletteindexes = array(); + for ($i = 0; $i < ceil($secondbyte / 2); $i++) { + $paletteindexbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $paletteindexes[] = ($paletteindexbyte & 0xF0) >> 4; + $paletteindexes[] = ($paletteindexbyte & 0x0F); + } + while (($pixeldataoffset % 2) != 0) { + // Each run must be aligned on a word boundary. + $pixeldataoffset++; + } + + foreach ($paletteindexes as $paletteindex) { + $col = $pixelcounter % $thisfile_bmp_header_raw['width']; + $row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']); + $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex]; + $pixelcounter++; + } + break; + } + + } else { + + // encoded mode - the first byte of the pair contains the number of pixels to be + // drawn using the color indexes in the second byte. The second byte contains two + // color indexes, one in its high-order 4 bits and one in its low-order 4 bits. + // The first of the pixels is drawn using the color specified by the high-order + // 4 bits, the second is drawn using the color in the low-order 4 bits, the third + // is drawn using the color in the high-order 4 bits, and so on, until all the + // pixels specified by the first byte have been drawn. + $paletteindexes[0] = ($secondbyte & 0xF0) >> 4; + $paletteindexes[1] = ($secondbyte & 0x0F); + for ($i = 0; $i < $firstbyte; $i++) { + $col = $pixelcounter % $thisfile_bmp_header_raw['width']; + $row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']); + $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindexes[($i % 2)]]; + $pixelcounter++; + } - default: - $this->error('Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data'); - break; - } - break; - - - case 3: // BI_BITFIELDS - switch ($thisfile_bmp_header_raw['bits_per_pixel']) { - case 16: - case 32: - $redshift = 0; - $greenshift = 0; - $blueshift = 0; - while ((($thisfile_bmp_header_raw['red_mask'] >> $redshift) & 0x01) == 0) { - $redshift++; - } - while ((($thisfile_bmp_header_raw['green_mask'] >> $greenshift) & 0x01) == 0) { - $greenshift++; - } - while ((($thisfile_bmp_header_raw['blue_mask'] >> $blueshift) & 0x01) == 0) { - $blueshift++; - } - for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) { - for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) { - $pixelvalue = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset, $thisfile_bmp_header_raw['bits_per_pixel'] / 8)); - $pixeldataoffset += $thisfile_bmp_header_raw['bits_per_pixel'] / 8; - - $red = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['red_mask']) >> $redshift) / ($thisfile_bmp_header_raw['red_mask'] >> $redshift)) * 255)); - $green = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['green_mask']) >> $greenshift) / ($thisfile_bmp_header_raw['green_mask'] >> $greenshift)) * 255)); - $blue = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['blue_mask']) >> $blueshift) / ($thisfile_bmp_header_raw['blue_mask'] >> $blueshift)) * 255)); - $thisfile_bmp['data'][$row][$col] = (($red << 16) | ($green << 8) | ($blue)); + } + } + break; + + default: + $this->error('Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data'); + break; + } + break; + + + case 3: // BI_BITFIELDS + switch ($thisfile_bmp_header_raw['bits_per_pixel']) { + case 16: + case 32: + $redshift = 0; + $greenshift = 0; + $blueshift = 0; + while ((($thisfile_bmp_header_raw['red_mask'] >> $redshift) & 0x01) == 0) { + $redshift++; + } + while ((($thisfile_bmp_header_raw['green_mask'] >> $greenshift) & 0x01) == 0) { + $greenshift++; + } + while ((($thisfile_bmp_header_raw['blue_mask'] >> $blueshift) & 0x01) == 0) { + $blueshift++; } - while (($pixeldataoffset % 4) != 0) { - // lines are padded to nearest DWORD - $pixeldataoffset++; + for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) { + for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) { + $pixelvalue = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset, $thisfile_bmp_header_raw['bits_per_pixel'] / 8)); + $pixeldataoffset += $thisfile_bmp_header_raw['bits_per_pixel'] / 8; + + $red = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['red_mask']) >> $redshift) / ($thisfile_bmp_header_raw['red_mask'] >> $redshift)) * 255)); + $green = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['green_mask']) >> $greenshift) / ($thisfile_bmp_header_raw['green_mask'] >> $greenshift)) * 255)); + $blue = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['blue_mask']) >> $blueshift) / ($thisfile_bmp_header_raw['blue_mask'] >> $blueshift)) * 255)); + $thisfile_bmp['data'][$row][$col] = (($red << 16) | ($green << 8) | ($blue)); + } + while (($pixeldataoffset % 4) != 0) { + // lines are padded to nearest DWORD + $pixeldataoffset++; + } } - } - break; + break; - default: - $this->error('Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data'); - break; - } - break; + default: + $this->error('Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data'); + break; + } + break; - default: // unhandled compression type - $this->error('Unknown/unhandled compression type value ('.$thisfile_bmp_header_raw['compression'].') - cannot decompress pixel data'); - break; + default: // unhandled compression type + $this->error('Unknown/unhandled compression type value ('.$thisfile_bmp_header_raw['compression'].') - cannot decompress pixel data'); + break; + } } } From c26c1363bb8700896ba8e83233d24b9d86b3b787 Mon Sep 17 00:00:00 2001 From: Tim Starling Date: Tue, 15 Nov 2022 10:35:32 +1100 Subject: [PATCH 05/25] Fix incorrect division in module.audio-video.ivf.php --- getid3/module.audio-video.ivf.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/getid3/module.audio-video.ivf.php b/getid3/module.audio-video.ivf.php index c344cf76..c2219244 100644 --- a/getid3/module.audio-video.ivf.php +++ b/getid3/module.audio-video.ivf.php @@ -45,7 +45,7 @@ public function Analyze() { $info['ivf']['header']['frame_count'] = getid3_lib::LittleEndian2Int(substr($IVFheader, 24, 4)); //$info['ivf']['header']['reserved'] = substr($IVFheader, 28, 4); - $info['ivf']['header']['frame_rate'] = (float)getid3_lib::SafeDiv($info['ivf']['header']['timebase_denominator'], $info['ivf']['header']['timebase_denominator']); + $info['ivf']['header']['frame_rate'] = (float)getid3_lib::SafeDiv($info['ivf']['header']['timebase_numerator'], $info['ivf']['header']['timebase_denominator']); if ($info['ivf']['header']['version'] > 0) { $this->warning('Expecting IVF header version 0, found version '.$info['ivf']['header']['version'].', results may not be accurate'); From a61d9c59cf8a4224baf33f625893d3246e32c51f Mon Sep 17 00:00:00 2001 From: James Heinrich Date: Thu, 12 Jan 2023 21:58:27 -0500 Subject: [PATCH 06/25] #407 https://github.com/JamesHeinrich/getID3/issues/407 --- demos/demo.browse.php | 2 +- getid3/module.graphic.jpg.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/demos/demo.browse.php b/demos/demo.browse.php index ea735c32..e29eca93 100644 --- a/demos/demo.browse.php +++ b/demos/demo.browse.php @@ -469,7 +469,7 @@ function table_var_dump($variable, $wrap_in_td=false, $encoding='') { global $FileSystemEncoding; $encoding = ($encoding ? $encoding : $FileSystemEncoding); $returnstring = ''; - switch (gettype($variable)) { + switch (strtolower(gettype($variable))) { case 'array': $returnstring .= ($wrap_in_td ? '' : ''); $returnstring .= ''; diff --git a/getid3/module.graphic.jpg.php b/getid3/module.graphic.jpg.php index c6ffad7e..f557bf3d 100644 --- a/getid3/module.graphic.jpg.php +++ b/getid3/module.graphic.jpg.php @@ -185,7 +185,7 @@ public function Analyze() { * @return mixed */ public function CastAsAppropriate($value) { - if (is_array($value)) { + if (is_array($value) || is_null($value)) { return $value; } elseif (preg_match('#^[0-9]+/[0-9]+$#', $value)) { return getid3_lib::DecimalizeFraction($value); From 2ed79376dc84ed99d7528406b68cf6593856e644 Mon Sep 17 00:00:00 2001 From: James Heinrich Date: Fri, 10 Feb 2023 11:30:46 -0500 Subject: [PATCH 07/25] basic .7z (7-zip) format detection --- getid3/getid3.php | 12 +++++++- getid3/module.archive.7zip.php | 52 ++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 getid3/module.archive.7zip.php diff --git a/getid3/getid3.php b/getid3/getid3.php index a821ec14..7131f81d 100644 --- a/getid3/getid3.php +++ b/getid3/getid3.php @@ -387,7 +387,7 @@ class getID3 */ protected $startup_warning = ''; - const VERSION = '1.9.22-202207161647'; + const VERSION = '1.9.22-202302101129'; const FREAD_BUFFER_SIZE = 32768; const ATTACHMENTS_NONE = false; @@ -1464,6 +1464,16 @@ public function GetFileFormatArray() { 'fail_ape' => 'ERROR', ), + // XZ - data - XZ compressed data + '7zip' => array( + 'pattern' => '^7z\\xBC\\xAF\\x27\\x1C', + 'group' => 'archive', + 'module' => '7zip', + 'mime_type' => 'application/x-7z-compressed', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + // Misc other formats diff --git a/getid3/module.archive.7zip.php b/getid3/module.archive.7zip.php new file mode 100644 index 00000000..e4eef9de --- /dev/null +++ b/getid3/module.archive.7zip.php @@ -0,0 +1,52 @@ + // +// available at https://github.com/JamesHeinrich/getID3 // +// or https://www.getid3.org // +// or http://getid3.sourceforge.net // +// see readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.archive.7zip.php // +// module for analyzing 7zip files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + +if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers + exit; +} + +class getid3_7zip extends getid3_handler +{ + /** + * @return bool + */ + public function Analyze() { + $info = &$this->getid3->info; + + $this->fseek($info['avdataoffset']); + $z7header = $this->fread(32); + + // https://py7zr.readthedocs.io/en/latest/archive_format.html + $info['7zip']['header']['magic'] = substr($z7header, 0, 6); + if ($info['7zip']['header']['magic'] != '7z'."\xBC\xAF\x27\x1C") { + $this->error('Invalid 7zip stream header magic (expecting 37 7A BC AF 27 1C, found '.getid3_lib::PrintHexBytes($info['7zip']['header']['magic']).') at offset '.$info['avdataoffset']); + return false; + } + $info['fileformat'] = '7zip'; + + $info['7zip']['header']['version_major'] = getid3_lib::LittleEndian2Int(substr($z7header, 6, 1)); // always 0x00 (?) + $info['7zip']['header']['version_minor'] = getid3_lib::LittleEndian2Int(substr($z7header, 7, 1)); // always 0x04 (?) + $info['7zip']['header']['start_header_crc'] = getid3_lib::LittleEndian2Int(substr($z7header, 8, 4)); + $info['7zip']['header']['next_header_offset'] = getid3_lib::LittleEndian2Int(substr($z7header, 12, 8)); + $info['7zip']['header']['next_header_size'] = getid3_lib::LittleEndian2Int(substr($z7header, 20, 8)); + $info['7zip']['header']['next_header_crc'] = getid3_lib::LittleEndian2Int(substr($z7header, 28, 4)); + +$this->error('7zip parsing not enabled in this version of getID3() ['.$this->getid3->version().']'); + return false; + + } + +} From dbfce30a8acb1c2962836e4cb80fa197b66a78b6 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 15 Feb 2023 09:26:02 -0800 Subject: [PATCH 08/25] Fix for MPEG-1 video pixel aspect ratio The reciprocal of the actual value was being returned for MPEG-1 video. Files with square pixels were not affected, nor were MPEG-2 files listing a display aspect ratio. Fixes https://github.com/JamesHeinrich/getID3/issues/410 --- getid3/module.audio-video.mpeg.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/getid3/module.audio-video.mpeg.php b/getid3/module.audio-video.mpeg.php index fe16e326..dcc38469 100644 --- a/getid3/module.audio-video.mpeg.php +++ b/getid3/module.audio-video.mpeg.php @@ -618,6 +618,9 @@ public static function videoAspectRatioLookup($rawaspectratio, $mpeg_version=1, if ($mpeg_version == 2 && $ratio != 1 && $width != 0) { // Calculate pixel aspect ratio from MPEG-2 display aspect ratio $ratio = $ratio * $height / $width; + } else if ($ratio > 0) { + // The MPEG-1 tables store the reciprocal of the pixel aspect ratio. + $ratio = 1 / $ratio; } return $ratio; } From 4c46eb61c07f4afc928941ada725b0472c6e5e77 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 15 Feb 2023 09:38:37 -0800 Subject: [PATCH 09/25] Apply common adjustments to MPEG-1 video capture aspect ratios This gives a nice 320px result instead of 321 point something when producing square pixel output and is commonly used. --- getid3/module.audio-video.mpeg.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/getid3/module.audio-video.mpeg.php b/getid3/module.audio-video.mpeg.php index dcc38469..b6a947fd 100644 --- a/getid3/module.audio-video.mpeg.php +++ b/getid3/module.audio-video.mpeg.php @@ -610,8 +610,11 @@ public static function videoFramerateLookup($rawframerate) { * @return float */ public static function videoAspectRatioLookup($rawaspectratio, $mpeg_version=1, $width=0, $height=0) { + // Per http://forum.doom9.org/archive/index.php/t-84400.html + // 0.9157 is commonly accepted to mean 11/12 or .9166, the reciprocal of 12/11 (1.091) and, + // 1.0950 is commonly accepted to mean 11/10 or 1.1, the reciprocal of 10/11 (0.909) $lookup = array( - 1 => array(0, 1, 0.6735, 0.7031, 0.7615, 0.8055, 0.8437, 0.8935, 0.9157, 0.9815, 1.0255, 1.0695, 1.0950, 1.1575, 1.2015, 0), + 1 => array(0, 1, 0.6735, 0.7031, 0.7615, 0.8055, 0.8437, 0.8935, 11/12, 0.9815, 1.0255, 1.0695, 11/10, 1.1575, 1.2015, 0), 2 => array(0, 1, 1.3333, 1.7778, 2.2100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), ); $ratio = (float) (isset($lookup[$mpeg_version][$rawaspectratio]) ? $lookup[$mpeg_version][$rawaspectratio] : 0); From 812c5926c305a3a82f27aa1b39a4e27b4d62cbe7 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 15 Feb 2023 09:52:29 -0800 Subject: [PATCH 10/25] See if php static analysis likes this guard better Getting this warning: Binary operation "/" between 1 and 0.0|0.6735|0.7031|0.7615|0.8055|0.8437|0.8935|0.91666666666667|0.9815|1.0|1.0255|1.0695|1.1|1.1575|1.2015|1.3333|1.7778|2.21 results in an error. Hopefully this will convince it that it won't divide by zero? --- getid3/module.audio-video.mpeg.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/getid3/module.audio-video.mpeg.php b/getid3/module.audio-video.mpeg.php index b6a947fd..284cc01f 100644 --- a/getid3/module.audio-video.mpeg.php +++ b/getid3/module.audio-video.mpeg.php @@ -621,7 +621,7 @@ public static function videoAspectRatioLookup($rawaspectratio, $mpeg_version=1, if ($mpeg_version == 2 && $ratio != 1 && $width != 0) { // Calculate pixel aspect ratio from MPEG-2 display aspect ratio $ratio = $ratio * $height / $width; - } else if ($ratio > 0) { + } else if ($ratio != 0) { // The MPEG-1 tables store the reciprocal of the pixel aspect ratio. $ratio = 1 / $ratio; } From 8f88da968c64253961d4b11e2b72c350241db2eb Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 15 Feb 2023 09:57:47 -0800 Subject: [PATCH 11/25] Trying to please static analysis --- getid3/module.audio-video.mpeg.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/getid3/module.audio-video.mpeg.php b/getid3/module.audio-video.mpeg.php index 284cc01f..ed4f9013 100644 --- a/getid3/module.audio-video.mpeg.php +++ b/getid3/module.audio-video.mpeg.php @@ -621,7 +621,7 @@ public static function videoAspectRatioLookup($rawaspectratio, $mpeg_version=1, if ($mpeg_version == 2 && $ratio != 1 && $width != 0) { // Calculate pixel aspect ratio from MPEG-2 display aspect ratio $ratio = $ratio * $height / $width; - } else if ($ratio != 0) { + } else if ($mpeg_version == 1 && $ratio != 0) { // The MPEG-1 tables store the reciprocal of the pixel aspect ratio. $ratio = 1 / $ratio; } From a0a8edcd7501e64122a492e972354bef462bedd4 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 15 Feb 2023 10:04:32 -0800 Subject: [PATCH 12/25] Still trying to please static analysis --- getid3/module.audio-video.mpeg.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/getid3/module.audio-video.mpeg.php b/getid3/module.audio-video.mpeg.php index ed4f9013..87085017 100644 --- a/getid3/module.audio-video.mpeg.php +++ b/getid3/module.audio-video.mpeg.php @@ -621,7 +621,7 @@ public static function videoAspectRatioLookup($rawaspectratio, $mpeg_version=1, if ($mpeg_version == 2 && $ratio != 1 && $width != 0) { // Calculate pixel aspect ratio from MPEG-2 display aspect ratio $ratio = $ratio * $height / $width; - } else if ($mpeg_version == 1 && $ratio != 0) { + } else if ($mpeg_version == 1 && $ratio != 0 && !is_nan($ratio)) { // The MPEG-1 tables store the reciprocal of the pixel aspect ratio. $ratio = 1 / $ratio; } From 1fdd05038021afce8ce71759f35e3222079c991e Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 15 Feb 2023 15:01:33 -0800 Subject: [PATCH 13/25] One more attempt to please the static analyzer It seems confused by the guard for $ratio being 0 :) --- getid3/module.audio-video.mpeg.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/getid3/module.audio-video.mpeg.php b/getid3/module.audio-video.mpeg.php index 87085017..876387b4 100644 --- a/getid3/module.audio-video.mpeg.php +++ b/getid3/module.audio-video.mpeg.php @@ -621,9 +621,9 @@ public static function videoAspectRatioLookup($rawaspectratio, $mpeg_version=1, if ($mpeg_version == 2 && $ratio != 1 && $width != 0) { // Calculate pixel aspect ratio from MPEG-2 display aspect ratio $ratio = $ratio * $height / $width; - } else if ($mpeg_version == 1 && $ratio != 0 && !is_nan($ratio)) { + } else if ($mpeg_version == 1 && $ratio !== 0.0) { // The MPEG-1 tables store the reciprocal of the pixel aspect ratio. - $ratio = 1 / $ratio; + $ratio = 1.0 / $ratio; } return $ratio; } From 4efd6d75b396e7067b9958c6bfd12d3ad6c45a75 Mon Sep 17 00:00:00 2001 From: James Heinrich Date: Fri, 31 Mar 2023 13:08:51 -0400 Subject: [PATCH 14/25] #413 Quicktime only use 'mp4a' for extracted audio metadata https://github.com/JamesHeinrich/getID3/issues/413 --- getid3/getid3.php | 2 +- getid3/module.audio-video.quicktime.php | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/getid3/getid3.php b/getid3/getid3.php index 7131f81d..b3c9f64c 100644 --- a/getid3/getid3.php +++ b/getid3/getid3.php @@ -387,7 +387,7 @@ class getID3 */ protected $startup_warning = ''; - const VERSION = '1.9.22-202302101129'; + const VERSION = '1.9.22-202303311306'; const FREAD_BUFFER_SIZE = 32768; const ATTACHMENTS_NONE = false; diff --git a/getid3/module.audio-video.quicktime.php b/getid3/module.audio-video.quicktime.php index 433f4685..084365fc 100644 --- a/getid3/module.audio-video.quicktime.php +++ b/getid3/module.audio-video.quicktime.php @@ -892,7 +892,6 @@ public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset break; case 'mp4a': - default: $info['quicktime']['audio']['codec'] = $this->QuicktimeAudioCodecLookup($atom_structure['sample_description_table'][$i]['data_format']); $info['quicktime']['audio']['sample_rate'] = $atom_structure['sample_description_table'][$i]['audio_sample_rate']; $info['quicktime']['audio']['channels'] = $atom_structure['sample_description_table'][$i]['audio_channels']; @@ -918,6 +917,9 @@ public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset break; } break; + + default: + break; } break; From ce4a1591d3168969b3a43fd78c67ff7723d02caa Mon Sep 17 00:00:00 2001 From: James Heinrich Date: Wed, 5 Apr 2023 14:35:51 -0400 Subject: [PATCH 15/25] #414 Bit rate for MP4 audio tracks https://github.com/JamesHeinrich/getID3/issues/414 --- getid3/getid3.php | 2 +- getid3/module.audio-video.quicktime.php | 123 +++++++++++++++++++++++- 2 files changed, 121 insertions(+), 4 deletions(-) diff --git a/getid3/getid3.php b/getid3/getid3.php index b3c9f64c..7b3d7692 100644 --- a/getid3/getid3.php +++ b/getid3/getid3.php @@ -387,7 +387,7 @@ class getID3 */ protected $startup_warning = ''; - const VERSION = '1.9.22-202303311306'; + const VERSION = '1.9.22-202304051421'; const FREAD_BUFFER_SIZE = 32768; const ATTACHMENTS_NONE = false; diff --git a/getid3/module.audio-video.quicktime.php b/getid3/module.audio-video.quicktime.php index 084365fc..26cafabc 100644 --- a/getid3/module.audio-video.quicktime.php +++ b/getid3/module.audio-video.quicktime.php @@ -775,8 +775,8 @@ public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset case 'stsd': // Sample Table Sample Description atom - $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); - $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); // hardcoded: 0x00 + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x000000 $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); // see: https://github.com/JamesHeinrich/getID3/issues/111 @@ -804,7 +804,6 @@ public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset $stsdEntriesDataOffset += 2; $atom_structure['sample_description_table'][$i]['data'] = substr($atom_data, $stsdEntriesDataOffset, ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2)); $stsdEntriesDataOffset += ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2); - if (substr($atom_structure['sample_description_table'][$i]['data'], 1, 54) == 'application/octet-stream;type=com.parrot.videometadata') { // special handling for apparently-malformed (TextMetaDataSampleEntry?) data for some version of Parrot drones $atom_structure['sample_description_table'][$i]['parrot_frame_metadata']['mime_type'] = substr($atom_structure['sample_description_table'][$i]['data'], 1, 55); @@ -892,6 +891,8 @@ public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset break; case 'mp4a': + $atom_structure['sample_description_table'][$i]['subatoms'] = $this->QuicktimeParseContainerAtom(substr($atom_structure['sample_description_table'][$i]['data'], 20), $baseoffset + $stsdEntriesDataOffset - 20 - 16, $atomHierarchy, $ParseAllPossibleAtoms); + $info['quicktime']['audio']['codec'] = $this->QuicktimeAudioCodecLookup($atom_structure['sample_description_table'][$i]['data_format']); $info['quicktime']['audio']['sample_rate'] = $atom_structure['sample_description_table'][$i]['audio_sample_rate']; $info['quicktime']['audio']['channels'] = $atom_structure['sample_description_table'][$i]['audio_channels']; @@ -2102,6 +2103,99 @@ public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset break; + case 'esds': // Elementary Stream DeScriptor + // https://github.com/JamesHeinrich/getID3/issues/414 + // https://chromium.googlesource.com/chromium/src/media/+/refs/heads/main/formats/mp4/es_descriptor.cc + // https://chromium.googlesource.com/chromium/src/media/+/refs/heads/main/formats/mp4/es_descriptor.h + $bytesread = 0; // for quicktime_readESsize + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); // hardcoded: 0x00 + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x000000 + $esds_offset = 4; + + $atom_structure['ES_DescrTag'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 1)); + $esds_offset += 1; + if ($atom_structure['ES_DescrTag'] != 0x03) { + $this->warning('expecting esds.ES_DescrTag = 0x03, found 0x'.getid3_lib::PrintHexBytes($atom_structure['ES_DescrTag']).'), at offset '.$subatomdata['offset']); + break; + } + $atom_structure['ES_DescrSize'] = $this->quicktime_readESsize(substr($atom_data, $esds_offset, 4), $bytesread); + $esds_offset += $bytesread; + $atom_structure['ES_ID'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 2)); + $esds_offset += 2; + $atom_structure['ES_flagsraw'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 1)); + $esds_offset += 1; + $atom_structure['ES_flags']['stream_dependency'] = (bool) ($atom_structure['ES_flagsraw'] & 0x80); + $atom_structure['ES_flags']['url_flag'] = (bool) ($atom_structure['ES_flagsraw'] & 0x40); + $atom_structure['ES_flags']['ocr_stream'] = (bool) ($atom_structure['ES_flagsraw'] & 0x20); + $atom_structure['ES_stream_priority'] = ($atom_structure['ES_flagsraw'] & 0x1F); + if ($atom_structure['ES_flags']['url_flag']) { + $this->warning('Unsupported esds.url_flag enabled at offset '.$subatomdata['offset']); + break; + } + if ($atom_structure['ES_flags']['stream_dependency']) { + $atom_structure['ES_dependsOn_ES_ID'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 2)); + $esds_offset += 2; + } + if ($atom_structure['ES_flags']['ocr_stream']) { + $atom_structure['ES_OCR_ES_Id'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 2)); + $esds_offset += 2; + } + + $atom_structure['ES_DecoderConfigDescrTag'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 1)); + $esds_offset += 1; + if ($atom_structure['ES_DecoderConfigDescrTag'] != 0x04) { + $this->warning('expecting esds.ES_DecoderConfigDescrTag = 0x04, found 0x'.getid3_lib::PrintHexBytes($atom_structure['ES_DecoderConfigDescrTag']).'), at offset '.$subatomdata['offset']); + break; + } + $atom_structure['ES_DecoderConfigDescrTagSize'] = $this->quicktime_readESsize(substr($atom_data, $esds_offset, 4), $bytesread); + $esds_offset += $bytesread; + + $atom_structure['ES_objectTypeIndication'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 1)); + $esds_offset += 1; + // https://stackoverflow.com/questions/3987850 + // 0x40 = "Audio ISO/IEC 14496-3" = MPEG-4 Audio + // 0x67 = "Audio ISO/IEC 13818-7 LowComplexity Profile" = MPEG-2 AAC LC + // 0x69 = "Audio ISO/IEC 13818-3" = MPEG-2 Backward Compatible Audio (MPEG-2 Layers 1, 2, and 3) + // 0x6B = "Audio ISO/IEC 11172-3" = MPEG-1 Audio (MPEG-1 Layers 1, 2, and 3) + + $streamTypePlusFlags = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 1)); + $esds_offset += 1; + $atom_structure['ES_streamType'] = ($streamTypePlusFlags & 0xFC) >> 2; + $atom_structure['ES_upStream'] = (bool) ($streamTypePlusFlags & 0x02) >> 1; + $atom_structure['ES_bufferSizeDB'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 3)); + $esds_offset += 3; + $atom_structure['ES_maxBitrate'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 4)); + $esds_offset += 4; + $atom_structure['ES_avgBitrate'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 4)); + $esds_offset += 4; + if ($atom_structure['ES_avgBitrate']) { + $info['quicktime']['audio']['bitrate'] = $atom_structure['ES_avgBitrate']; + $info['audio']['bitrate'] = $atom_structure['ES_avgBitrate']; + } + + $atom_structure['ES_DecSpecificInfoTag'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 1)); + $esds_offset += 1; + if ($atom_structure['ES_DecSpecificInfoTag'] != 0x05) { + $this->warning('expecting esds.ES_DecSpecificInfoTag = 0x05, found 0x'.getid3_lib::PrintHexBytes($atom_structure['ES_DecSpecificInfoTag']).'), at offset '.$subatomdata['offset']); + break; + } + $atom_structure['ES_DecSpecificInfoTagSize'] = $this->quicktime_readESsize(substr($atom_data, $esds_offset, 4), $bytesread); + $esds_offset += $bytesread; + $atom_structure['ES_DecSpecificInfo'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, $atom_structure['ES_DecSpecificInfoTagSize'])); + $esds_offset += $atom_structure['ES_DecSpecificInfoTagSize']; + + $atom_structure['ES_SLConfigDescrTag'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 1)); + $esds_offset += 1; + if ($atom_structure['ES_SLConfigDescrTag'] != 0x06) { + $this->warning('expecting esds.ES_SLConfigDescrTag = 0x05, found 0x'.getid3_lib::PrintHexBytes($atom_structure['ES_SLConfigDescrTag']).'), at offset '.$subatomdata['offset']); + break; + } + $atom_structure['ES_SLConfigDescrTagSize'] = $this->quicktime_readESsize(substr($atom_data, $esds_offset, 4), $bytesread); + $esds_offset += $bytesread; + $atom_structure['ES_SLConfigDescr'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, $atom_structure['ES_SLConfigDescrTagSize'])); + $esds_offset += $atom_structure['ES_SLConfigDescrTagSize']; + break; + // AVIF-related - https://docs.rs/avif-parse/0.13.2/src/avif_parse/boxes.rs.html case 'pitm': // Primary ITeM case 'iloc': // Item LOCation @@ -2992,6 +3086,29 @@ public function quicktime_time_to_sample_table($info) { return array(); } + /** + * @param string $data + * @param int $bytesread + * + * @return int + */ + public function quicktime_readESsize($data, &$bytesread) { + // https://chromium.googlesource.com/chromium/src/media/+/refs/heads/main/formats/mp4/es_descriptor.cc + // The elementary stream size is specific by up to 4 bytes. + // The MSB of a byte indicates if there are more bytes for the size. + $esds_entry_size = 0; + for ($bytesread = 1; $bytesread <= 4; $bytesread++) { + $byteval = ord(substr($data, ($bytesread - 1), 1)); + $esds_entry_size = ($esds_entry_size << 7) + ($byteval & 0x7F); + $thisMSB = ($byteval & 0x80) >> 7; + if (!$thisMSB) { + break; + } + } + return $esds_entry_size; + } + + /** * @param array $info * From 9a3509229762c556eddc9c7f7aa9af37cff48c9b Mon Sep 17 00:00:00 2001 From: James Heinrich Date: Wed, 5 Apr 2023 15:40:32 -0400 Subject: [PATCH 16/25] #414 variable name typos Fix wrong variable name in https://github.com/JamesHeinrich/getID3/commit/ce4a1591d3168969b3a43fd78c67ff7723d02caa --- getid3/getid3.php | 2 +- getid3/module.audio-video.quicktime.php | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/getid3/getid3.php b/getid3/getid3.php index 7b3d7692..3fdb00d0 100644 --- a/getid3/getid3.php +++ b/getid3/getid3.php @@ -387,7 +387,7 @@ class getID3 */ protected $startup_warning = ''; - const VERSION = '1.9.22-202304051421'; + const VERSION = '1.9.22-202304051539'; const FREAD_BUFFER_SIZE = 32768; const ATTACHMENTS_NONE = false; diff --git a/getid3/module.audio-video.quicktime.php b/getid3/module.audio-video.quicktime.php index 26cafabc..e998581b 100644 --- a/getid3/module.audio-video.quicktime.php +++ b/getid3/module.audio-video.quicktime.php @@ -2115,7 +2115,7 @@ public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset $atom_structure['ES_DescrTag'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 1)); $esds_offset += 1; if ($atom_structure['ES_DescrTag'] != 0x03) { - $this->warning('expecting esds.ES_DescrTag = 0x03, found 0x'.getid3_lib::PrintHexBytes($atom_structure['ES_DescrTag']).'), at offset '.$subatomdata['offset']); + $this->warning('expecting esds.ES_DescrTag = 0x03, found 0x'.getid3_lib::PrintHexBytes($atom_structure['ES_DescrTag']).'), at offset '.$atom_structure['offset']); break; } $atom_structure['ES_DescrSize'] = $this->quicktime_readESsize(substr($atom_data, $esds_offset, 4), $bytesread); @@ -2129,7 +2129,7 @@ public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset $atom_structure['ES_flags']['ocr_stream'] = (bool) ($atom_structure['ES_flagsraw'] & 0x20); $atom_structure['ES_stream_priority'] = ($atom_structure['ES_flagsraw'] & 0x1F); if ($atom_structure['ES_flags']['url_flag']) { - $this->warning('Unsupported esds.url_flag enabled at offset '.$subatomdata['offset']); + $this->warning('Unsupported esds.url_flag enabled at offset '.$atom_structure['offset']); break; } if ($atom_structure['ES_flags']['stream_dependency']) { @@ -2144,7 +2144,7 @@ public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset $atom_structure['ES_DecoderConfigDescrTag'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 1)); $esds_offset += 1; if ($atom_structure['ES_DecoderConfigDescrTag'] != 0x04) { - $this->warning('expecting esds.ES_DecoderConfigDescrTag = 0x04, found 0x'.getid3_lib::PrintHexBytes($atom_structure['ES_DecoderConfigDescrTag']).'), at offset '.$subatomdata['offset']); + $this->warning('expecting esds.ES_DecoderConfigDescrTag = 0x04, found 0x'.getid3_lib::PrintHexBytes($atom_structure['ES_DecoderConfigDescrTag']).'), at offset '.$atom_structure['offset']); break; } $atom_structure['ES_DecoderConfigDescrTagSize'] = $this->quicktime_readESsize(substr($atom_data, $esds_offset, 4), $bytesread); @@ -2176,7 +2176,7 @@ public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset $atom_structure['ES_DecSpecificInfoTag'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 1)); $esds_offset += 1; if ($atom_structure['ES_DecSpecificInfoTag'] != 0x05) { - $this->warning('expecting esds.ES_DecSpecificInfoTag = 0x05, found 0x'.getid3_lib::PrintHexBytes($atom_structure['ES_DecSpecificInfoTag']).'), at offset '.$subatomdata['offset']); + $this->warning('expecting esds.ES_DecSpecificInfoTag = 0x05, found 0x'.getid3_lib::PrintHexBytes($atom_structure['ES_DecSpecificInfoTag']).'), at offset '.$atom_structure['offset']); break; } $atom_structure['ES_DecSpecificInfoTagSize'] = $this->quicktime_readESsize(substr($atom_data, $esds_offset, 4), $bytesread); @@ -2187,7 +2187,7 @@ public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset $atom_structure['ES_SLConfigDescrTag'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 1)); $esds_offset += 1; if ($atom_structure['ES_SLConfigDescrTag'] != 0x06) { - $this->warning('expecting esds.ES_SLConfigDescrTag = 0x05, found 0x'.getid3_lib::PrintHexBytes($atom_structure['ES_SLConfigDescrTag']).'), at offset '.$subatomdata['offset']); + $this->warning('expecting esds.ES_SLConfigDescrTag = 0x05, found 0x'.getid3_lib::PrintHexBytes($atom_structure['ES_SLConfigDescrTag']).'), at offset '.$atom_structure['offset']); break; } $atom_structure['ES_SLConfigDescrTagSize'] = $this->quicktime_readESsize(substr($atom_data, $esds_offset, 4), $bytesread); From e738a00c13fc431b167bba7a8b1106936b610f91 Mon Sep 17 00:00:00 2001 From: James Heinrich Date: Wed, 5 Apr 2023 19:14:17 -0400 Subject: [PATCH 17/25] #414 use quicktime_read_mp4_descr_length, remove quicktime_readESsize https://github.com/JamesHeinrich/getID3/issues/414 --- getid3/getid3.php | 2 +- getid3/module.audio-video.quicktime.php | 38 +++++-------------------- 2 files changed, 8 insertions(+), 32 deletions(-) diff --git a/getid3/getid3.php b/getid3/getid3.php index 3fdb00d0..4b9fbca0 100644 --- a/getid3/getid3.php +++ b/getid3/getid3.php @@ -387,7 +387,7 @@ class getID3 */ protected $startup_warning = ''; - const VERSION = '1.9.22-202304051539'; + const VERSION = '1.9.22-202304051912'; const FREAD_BUFFER_SIZE = 32768; const ATTACHMENTS_NONE = false; diff --git a/getid3/module.audio-video.quicktime.php b/getid3/module.audio-video.quicktime.php index e998581b..215792f4 100644 --- a/getid3/module.audio-video.quicktime.php +++ b/getid3/module.audio-video.quicktime.php @@ -2107,7 +2107,6 @@ public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset // https://github.com/JamesHeinrich/getID3/issues/414 // https://chromium.googlesource.com/chromium/src/media/+/refs/heads/main/formats/mp4/es_descriptor.cc // https://chromium.googlesource.com/chromium/src/media/+/refs/heads/main/formats/mp4/es_descriptor.h - $bytesread = 0; // for quicktime_readESsize $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); // hardcoded: 0x00 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x000000 $esds_offset = 4; @@ -2118,8 +2117,8 @@ public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset $this->warning('expecting esds.ES_DescrTag = 0x03, found 0x'.getid3_lib::PrintHexBytes($atom_structure['ES_DescrTag']).'), at offset '.$atom_structure['offset']); break; } - $atom_structure['ES_DescrSize'] = $this->quicktime_readESsize(substr($atom_data, $esds_offset, 4), $bytesread); - $esds_offset += $bytesread; + $atom_structure['ES_DescrSize'] = $this->quicktime_read_mp4_descr_length($atom_data, $esds_offset); + $atom_structure['ES_ID'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 2)); $esds_offset += 2; $atom_structure['ES_flagsraw'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 1)); @@ -2147,8 +2146,7 @@ public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset $this->warning('expecting esds.ES_DecoderConfigDescrTag = 0x04, found 0x'.getid3_lib::PrintHexBytes($atom_structure['ES_DecoderConfigDescrTag']).'), at offset '.$atom_structure['offset']); break; } - $atom_structure['ES_DecoderConfigDescrTagSize'] = $this->quicktime_readESsize(substr($atom_data, $esds_offset, 4), $bytesread); - $esds_offset += $bytesread; + $atom_structure['ES_DecoderConfigDescrTagSize'] = $this->quicktime_read_mp4_descr_length($atom_data, $esds_offset); $atom_structure['ES_objectTypeIndication'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 1)); $esds_offset += 1; @@ -2179,8 +2177,8 @@ public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset $this->warning('expecting esds.ES_DecSpecificInfoTag = 0x05, found 0x'.getid3_lib::PrintHexBytes($atom_structure['ES_DecSpecificInfoTag']).'), at offset '.$atom_structure['offset']); break; } - $atom_structure['ES_DecSpecificInfoTagSize'] = $this->quicktime_readESsize(substr($atom_data, $esds_offset, 4), $bytesread); - $esds_offset += $bytesread; + $atom_structure['ES_DecSpecificInfoTagSize'] = $this->quicktime_read_mp4_descr_length($atom_data, $esds_offset); + $atom_structure['ES_DecSpecificInfo'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, $atom_structure['ES_DecSpecificInfoTagSize'])); $esds_offset += $atom_structure['ES_DecSpecificInfoTagSize']; @@ -2190,8 +2188,8 @@ public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset $this->warning('expecting esds.ES_SLConfigDescrTag = 0x05, found 0x'.getid3_lib::PrintHexBytes($atom_structure['ES_SLConfigDescrTag']).'), at offset '.$atom_structure['offset']); break; } - $atom_structure['ES_SLConfigDescrTagSize'] = $this->quicktime_readESsize(substr($atom_data, $esds_offset, 4), $bytesread); - $esds_offset += $bytesread; + $atom_structure['ES_SLConfigDescrTagSize'] = $this->quicktime_read_mp4_descr_length($atom_data, $esds_offset); + $atom_structure['ES_SLConfigDescr'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, $atom_structure['ES_SLConfigDescrTagSize'])); $esds_offset += $atom_structure['ES_SLConfigDescrTagSize']; break; @@ -3086,28 +3084,6 @@ public function quicktime_time_to_sample_table($info) { return array(); } - /** - * @param string $data - * @param int $bytesread - * - * @return int - */ - public function quicktime_readESsize($data, &$bytesread) { - // https://chromium.googlesource.com/chromium/src/media/+/refs/heads/main/formats/mp4/es_descriptor.cc - // The elementary stream size is specific by up to 4 bytes. - // The MSB of a byte indicates if there are more bytes for the size. - $esds_entry_size = 0; - for ($bytesread = 1; $bytesread <= 4; $bytesread++) { - $byteval = ord(substr($data, ($bytesread - 1), 1)); - $esds_entry_size = ($esds_entry_size << 7) + ($byteval & 0x7F); - $thisMSB = ($byteval & 0x80) >> 7; - if (!$thisMSB) { - break; - } - } - return $esds_entry_size; - } - /** * @param array $info From e3b69ad701422ac409739003fbdca01024b3ca46 Mon Sep 17 00:00:00 2001 From: James Heinrich Date: Mon, 29 May 2023 17:38:03 -0400 Subject: [PATCH 18/25] id3v2 IsANumber https://github.com/JamesHeinrich/getID3/pull/416 --- getid3/getid3.php | 2 +- getid3/module.tag.id3v2.php | 23 +++++++---------------- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/getid3/getid3.php b/getid3/getid3.php index 4b9fbca0..d72b3f15 100644 --- a/getid3/getid3.php +++ b/getid3/getid3.php @@ -387,7 +387,7 @@ class getID3 */ protected $startup_warning = ''; - const VERSION = '1.9.22-202304051912'; + const VERSION = '1.9.22-202305291732'; const FREAD_BUFFER_SIZE = 32768; const ATTACHMENTS_NONE = false; diff --git a/getid3/module.tag.id3v2.php b/getid3/module.tag.id3v2.php index 5b907434..ec448be8 100644 --- a/getid3/module.tag.id3v2.php +++ b/getid3/module.tag.id3v2.php @@ -3753,18 +3753,12 @@ public static function IsValidID3v2FrameName($framename, $id3v2majorversion) { * @return bool */ public static function IsANumber($numberstring, $allowdecimal=false, $allownegative=false) { - for ($i = 0; $i < strlen($numberstring); $i++) { - if ((chr($numberstring[$i]) < chr('0')) || (chr($numberstring[$i]) > chr('9'))) { - if (($numberstring[$i] == '.') && $allowdecimal) { - // allowed - } elseif (($numberstring[$i] == '-') && $allownegative && ($i == 0)) { - // allowed - } else { - return false; - } - } - } - return true; + $pattern = '#^'; + $pattern .= ($allownegative ? '\\-?' : ''); + $pattern .= '[0-9]+'; + $pattern .= ($allowdecimal ? '(\\.[0-9]+)?' : ''); + $pattern .= '$#'; + return preg_match($pattern, $numberstring); } /** @@ -3773,10 +3767,7 @@ public static function IsANumber($numberstring, $allowdecimal=false, $allownegat * @return bool */ public static function IsValidDateStampString($datestamp) { - if (strlen($datestamp) != 8) { - return false; - } - if (!self::IsANumber($datestamp, false)) { + if (!preg_match('#^[12][0-9]{3}[01][0-9][0123][0-9]$#', $datestamp)) { return false; } $year = substr($datestamp, 0, 4); From 9993caa131c85115234ba190267401460b4d5842 Mon Sep 17 00:00:00 2001 From: James Heinrich Date: Tue, 4 Jul 2023 20:22:02 -0400 Subject: [PATCH 19/25] gCL references clarify wording that new gCL licenses no longer available --- README.md | 6 +++--- license.txt | 3 ++- readme.txt | 3 ++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index b967df5e..a42f1d77 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ getID3() is released under multiple licenses. You may choose from the following **getID3 Commercial License:** -* [gCL](https://www.getid3.org/#gCL) (payment required) +* [gCL](https://www.getid3.org/#gCL) (no longer available, existing licenses remain valid) * * * Copies of each of the above licenses are included in the `licenses/` @@ -125,7 +125,7 @@ Reads & parses (to varying degrees): * SWF (Flash) * PhotoCD -+ data: ++ data: * ISO-9660 CD-ROM image (directory structure) * SZIP (limited support) * ZIP (directory structure) @@ -297,7 +297,7 @@ could essentially write it today with a one-line function: ``` php function getID3($filename) { return unpack('a3TAG/a30title/a30artist/a30album/a4year/a28comment/c1track/c1genreid', substr(file_get_contents($filename), -128)); } - + ``` diff --git a/license.txt b/license.txt index c67873ae..8978b4a2 100644 --- a/license.txt +++ b/license.txt @@ -20,7 +20,8 @@ GNU LGPL: https://gnu.org/licenses/lgpl.html (v3) Mozilla MPL: https://www.mozilla.org/MPL/2.0/ (v2) -getID3 Commercial License: https://www.getid3.org/#gCL (payment required) +getID3 Commercial License: https://www.getid3.org/#gCL +(no longer available, existing licenses remain valid) ***************************************************************** ***************************************************************** diff --git a/readme.txt b/readme.txt index 0888bc4d..c1b3d47b 100644 --- a/readme.txt +++ b/readme.txt @@ -20,7 +20,8 @@ GNU LGPL: https://gnu.org/licenses/lgpl.html (v3) Mozilla MPL: https://www.mozilla.org/MPL/2.0/ (v2) -getID3 Commercial License: https://www.getid3.org/#gCL (payment required) +getID3 Commercial License: https://www.getid3.org/#gCL +(no longer available, existing licenses remain valid) ***************************************************************** ***************************************************************** From cba30f64f36ec2c3ca78408a15c398d84f55d4bb Mon Sep 17 00:00:00 2001 From: James Heinrich Date: Tue, 8 Aug 2023 19:19:30 -0400 Subject: [PATCH 20/25] #418 fread length error in XMP https://github.com/JamesHeinrich/getID3/issues/418 --- getid3/getid3.php | 2 +- getid3/module.tag.xmp.php | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/getid3/getid3.php b/getid3/getid3.php index d72b3f15..2306348d 100644 --- a/getid3/getid3.php +++ b/getid3/getid3.php @@ -387,7 +387,7 @@ class getID3 */ protected $startup_warning = ''; - const VERSION = '1.9.22-202305291732'; + const VERSION = '1.9.22-202308081917'; const FREAD_BUFFER_SIZE = 32768; const ATTACHMENTS_NONE = false; diff --git a/getid3/module.tag.xmp.php b/getid3/module.tag.xmp.php index 23c0d1ab..8d0e53b7 100644 --- a/getid3/module.tag.xmp.php +++ b/getid3/module.tag.xmp.php @@ -146,7 +146,16 @@ public function _get_jpeg_header_data($filename) $segdatastart = ftell($filehnd); // Read the segment data with length indicated by the previously read size - $segdata = fread($filehnd, $decodedsize['size'] - 2); + // fread will complain about trying to read zero bytes: "fread(): Argument #2 ($length) must be greater than 0" -- https://github.com/JamesHeinrich/getID3/issues/418 + if ($decodedsize['size'] > 2) { + $segdata = fread($filehnd, $decodedsize['size'] - 2); + } elseif ($decodedsize['size'] == 2) { + $segdata = ''; + } else { + // invalid length + fclose($filehnd); + return false; + } // Store the segment information in the output array $headerdata[] = array( From 83cd7656fbf72cf7538b0edc99072de81f2f7a5b Mon Sep 17 00:00:00 2001 From: StudioMaX Date: Thu, 10 Aug 2023 14:24:28 +0600 Subject: [PATCH 21/25] Run lint against PHP 8.3 --- .github/workflows/continuous-integration.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 0ddfe694..3c1acf24 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -22,6 +22,7 @@ jobs: - "8.0" - "8.1" - "8.2" + - "8.3" steps: - uses: "actions/checkout@v3" - uses: "shivammathur/setup-php@v2" From 6a8cc002dfc1cb9975e7899b9b89163bff72ddc0 Mon Sep 17 00:00:00 2001 From: James Heinrich Date: Thu, 10 Aug 2023 08:55:35 -0400 Subject: [PATCH 22/25] #419 Quicktime undefined index: time_scale https://github.com/JamesHeinrich/getID3/issues/419 --- getid3/getid3.php | 2 +- getid3/module.audio-video.quicktime.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/getid3/getid3.php b/getid3/getid3.php index 2306348d..93d26410 100644 --- a/getid3/getid3.php +++ b/getid3/getid3.php @@ -387,7 +387,7 @@ class getID3 */ protected $startup_warning = ''; - const VERSION = '1.9.22-202308081917'; + const VERSION = '1.9.22-202308100852'; const FREAD_BUFFER_SIZE = 32768; const ATTACHMENTS_NONE = false; diff --git a/getid3/module.audio-video.quicktime.php b/getid3/module.audio-video.quicktime.php index 215792f4..c058bbc1 100644 --- a/getid3/module.audio-video.quicktime.php +++ b/getid3/module.audio-video.quicktime.php @@ -331,7 +331,7 @@ public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset } } elseif (isset($value_array['time_to_sample_table'])) { foreach ($value_array['time_to_sample_table'] as $key2 => $value_array2) { - if (isset($value_array2['sample_count']) && isset($value_array2['sample_duration']) && ($value_array2['sample_duration'] > 0)) { + if (isset($value_array2['sample_count']) && isset($value_array2['sample_duration']) && ($value_array2['sample_duration'] > 0) && !empty($info['quicktime']['time_scale'])) { $framerate = round($info['quicktime']['time_scale'] / $value_array2['sample_duration'], 3); $framecount = $value_array2['sample_count']; } From b98030e63c10b35cc522a729eea5e73bd7b080f9 Mon Sep 17 00:00:00 2001 From: Michele Orselli Date: Fri, 1 Sep 2023 15:06:49 +0200 Subject: [PATCH 23/25] move jpeg segments names from $GLOBALS to class static property --- getid3/module.tag.xmp.php | 148 +++++++++++++++++++------------------- 1 file changed, 73 insertions(+), 75 deletions(-) diff --git a/getid3/module.tag.xmp.php b/getid3/module.tag.xmp.php index 8d0e53b7..ab411e25 100644 --- a/getid3/module.tag.xmp.php +++ b/getid3/module.tag.xmp.php @@ -33,6 +33,77 @@ *************************************************************************************************/ class Image_XMP { + /** + * The names of the JPEG segment markers, indexed by their marker number + */ + private static $jpeg_segments_name = array( + 0x01 => 'TEM', + 0x02 => 'RES', + 0xC0 => 'SOF0', + 0xC1 => 'SOF1', + 0xC2 => 'SOF2', + 0xC3 => 'SOF4', + 0xC4 => 'DHT', + 0xC5 => 'SOF5', + 0xC6 => 'SOF6', + 0xC7 => 'SOF7', + 0xC8 => 'JPG', + 0xC9 => 'SOF9', + 0xCA => 'SOF10', + 0xCB => 'SOF11', + 0xCC => 'DAC', + 0xCD => 'SOF13', + 0xCE => 'SOF14', + 0xCF => 'SOF15', + 0xD0 => 'RST0', + 0xD1 => 'RST1', + 0xD2 => 'RST2', + 0xD3 => 'RST3', + 0xD4 => 'RST4', + 0xD5 => 'RST5', + 0xD6 => 'RST6', + 0xD7 => 'RST7', + 0xD8 => 'SOI', + 0xD9 => 'EOI', + 0xDA => 'SOS', + 0xDB => 'DQT', + 0xDC => 'DNL', + 0xDD => 'DRI', + 0xDE => 'DHP', + 0xDF => 'EXP', + 0xE0 => 'APP0', + 0xE1 => 'APP1', + 0xE2 => 'APP2', + 0xE3 => 'APP3', + 0xE4 => 'APP4', + 0xE5 => 'APP5', + 0xE6 => 'APP6', + 0xE7 => 'APP7', + 0xE8 => 'APP8', + 0xE9 => 'APP9', + 0xEA => 'APP10', + 0xEB => 'APP11', + 0xEC => 'APP12', + 0xED => 'APP13', + 0xEE => 'APP14', + 0xEF => 'APP15', + 0xF0 => 'JPG0', + 0xF1 => 'JPG1', + 0xF2 => 'JPG2', + 0xF3 => 'JPG3', + 0xF4 => 'JPG4', + 0xF5 => 'JPG5', + 0xF6 => 'JPG6', + 0xF7 => 'JPG7', + 0xF8 => 'JPG8', + 0xF9 => 'JPG9', + 0xFA => 'JPG10', + 0xFB => 'JPG11', + 0xFC => 'JPG12', + 0xFD => 'JPG13', + 0xFE => 'COM', + ); + /** * @var string * The name of the image file that contains the XMP fields to extract and modify. @@ -160,7 +231,7 @@ public function _get_jpeg_header_data($filename) // Store the segment information in the output array $headerdata[] = array( 'SegType' => ord($data[1]), - 'SegName' => $GLOBALS['JPEG_Segment_Names'][ord($data[1])], + 'SegName' => self::$jpeg_segments_name[ord($data[1])], 'SegDataStart' => $segdatastart, 'SegData' => $segdata, ); @@ -710,77 +781,4 @@ public function __construct($sFilename) 'exif:Rows', 'exif:Settings', ); -*/ - -/** -* Global Variable: JPEG_Segment_Names -* -* The names of the JPEG segment markers, indexed by their marker number -*/ -$GLOBALS['JPEG_Segment_Names'] = array( - 0x01 => 'TEM', - 0x02 => 'RES', - 0xC0 => 'SOF0', - 0xC1 => 'SOF1', - 0xC2 => 'SOF2', - 0xC3 => 'SOF4', - 0xC4 => 'DHT', - 0xC5 => 'SOF5', - 0xC6 => 'SOF6', - 0xC7 => 'SOF7', - 0xC8 => 'JPG', - 0xC9 => 'SOF9', - 0xCA => 'SOF10', - 0xCB => 'SOF11', - 0xCC => 'DAC', - 0xCD => 'SOF13', - 0xCE => 'SOF14', - 0xCF => 'SOF15', - 0xD0 => 'RST0', - 0xD1 => 'RST1', - 0xD2 => 'RST2', - 0xD3 => 'RST3', - 0xD4 => 'RST4', - 0xD5 => 'RST5', - 0xD6 => 'RST6', - 0xD7 => 'RST7', - 0xD8 => 'SOI', - 0xD9 => 'EOI', - 0xDA => 'SOS', - 0xDB => 'DQT', - 0xDC => 'DNL', - 0xDD => 'DRI', - 0xDE => 'DHP', - 0xDF => 'EXP', - 0xE0 => 'APP0', - 0xE1 => 'APP1', - 0xE2 => 'APP2', - 0xE3 => 'APP3', - 0xE4 => 'APP4', - 0xE5 => 'APP5', - 0xE6 => 'APP6', - 0xE7 => 'APP7', - 0xE8 => 'APP8', - 0xE9 => 'APP9', - 0xEA => 'APP10', - 0xEB => 'APP11', - 0xEC => 'APP12', - 0xED => 'APP13', - 0xEE => 'APP14', - 0xEF => 'APP15', - 0xF0 => 'JPG0', - 0xF1 => 'JPG1', - 0xF2 => 'JPG2', - 0xF3 => 'JPG3', - 0xF4 => 'JPG4', - 0xF5 => 'JPG5', - 0xF6 => 'JPG6', - 0xF7 => 'JPG7', - 0xF8 => 'JPG8', - 0xF9 => 'JPG9', - 0xFA => 'JPG10', - 0xFB => 'JPG11', - 0xFC => 'JPG12', - 0xFD => 'JPG13', - 0xFE => 'COM', -); +*/ \ No newline at end of file From 69fe0c122a201f9558ad8c13d0847888e731fb7f Mon Sep 17 00:00:00 2001 From: Namrata Patel Date: Mon, 16 Oct 2023 18:37:04 +0530 Subject: [PATCH 24/25] Update module.audio-video.riff.php --- getid3/module.audio-video.riff.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/getid3/module.audio-video.riff.php b/getid3/module.audio-video.riff.php index 3dc18de4..a94ae24d 100644 --- a/getid3/module.audio-video.riff.php +++ b/getid3/module.audio-video.riff.php @@ -2034,7 +2034,7 @@ public static function parseComments(&$RIFFinfoArray, &$CommentsTargetArray) { foreach ($RIFFinfoKeyLookup as $key => $value) { if (isset($RIFFinfoArray[$key])) { foreach ($RIFFinfoArray[$key] as $commentid => $commentdata) { - if (trim($commentdata['data']) != '') { + if (!empty($commentdata['data']) && trim($commentdata['data']) != '') { if (isset($CommentsTargetArray[$value])) { $CommentsTargetArray[$value][] = trim($commentdata['data']); } else { From 06c7482532ff2b3f9111b011d880ca6699c8542b Mon Sep 17 00:00:00 2001 From: James Heinrich Date: Thu, 19 Oct 2023 09:18:49 -0400 Subject: [PATCH 25/25] changelog v1.9.23-202310190849 --- changelog.txt | 13 +++++++++++++ getid3/getid3.php | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index e6a6e586..488e4c1d 100644 --- a/changelog.txt +++ b/changelog.txt @@ -18,6 +18,19 @@ Version History =============== +1.9.23: [2023-10-19] James Heinrich :: 1.9.23-202310190849 + ยป add detection support for 7-zip archives + * #424 RIFF Undefined index "data" + * #421 tag.xmp remove GLOBALS + * #419 Quicktime Undefined index "time_scale" + * #418 tag.xmp zero-length fread + * #414 Quicktime bitrate for mp4 audio + * #413 Quicktime audio metadata + * #410 MPEG-1 pixel aspect ratio + * #407 PHP 8.1 compatibility + * #404 guard against division by zero + * #402 remove utf8_encode/utf8_decode + 1.9.22: [2022-09-29] James Heinrich :: 1.9.22-202207161647 * bugfix #387 fails to detect h265 video codec (QuickTime) * bugfix #385 Quicktime extended atom size diff --git a/getid3/getid3.php b/getid3/getid3.php index 93d26410..41ef6408 100644 --- a/getid3/getid3.php +++ b/getid3/getid3.php @@ -387,7 +387,7 @@ class getID3 */ protected $startup_warning = ''; - const VERSION = '1.9.22-202308100852'; + const VERSION = '1.9.23-202310190849'; const FREAD_BUFFER_SIZE = 32768; const ATTACHMENTS_NONE = false;