From aa873a407356924c5f062ccdbebb9d05a4835fbf Mon Sep 17 00:00:00 2001
From: b_b <bruno@eliaz.fr>
Date: Thu, 26 Jan 2023 15:08:21 +0100
Subject: [PATCH] build: update getid3 en version v1.9.22-202207161647

voir https://github.com/JamesHeinrich/getID3/releases/tag/v1.9.22

Ref: https://git.spip.net/spip/spip/issues/5292
---
 lib/getid3/getid3.lib.php                   |  14 +-
 lib/getid3/getid3.php                       |  42 +++--
 lib/getid3/module.archive.zip.php           |   2 +-
 lib/getid3/module.audio-video.asf.php       | 174 ++++++++++++++++++--
 lib/getid3/module.audio-video.mpeg.php      |   2 +-
 lib/getid3/module.audio-video.quicktime.php |  62 ++++++-
 lib/getid3/module.audio-video.real.php      |   3 +-
 lib/getid3/module.audio-video.riff.php      |  11 +-
 lib/getid3/module.audio.aac.php             |   2 +-
 lib/getid3/module.audio.mod.php             |  57 ++++++-
 lib/getid3/module.audio.mp3.php             |  12 +-
 lib/getid3/module.audio.mpc.php             |   2 +-
 lib/getid3/module.audio.ogg.php             |   2 +-
 lib/getid3/module.audio.voc.php             |   2 +
 lib/getid3/module.graphic.gif.php           |  34 +++-
 lib/getid3/module.misc.cue.php              |   2 +-
 lib/getid3/module.misc.pdf.php              |   2 +-
 lib/getid3/module.tag.id3v2.php             |   2 +-
 lib/getid3/write.metaflac.php               |   8 +-
 lib/getid3/write.vorbiscomment.php          |   4 +-
 20 files changed, 366 insertions(+), 73 deletions(-)

diff --git a/lib/getid3/getid3.lib.php b/lib/getid3/getid3.lib.php
index a24a0652..ba7a8e68 100644
--- a/lib/getid3/getid3.lib.php
+++ b/lib/getid3/getid3.lib.php
@@ -11,6 +11,13 @@
 //                                                            ///
 /////////////////////////////////////////////////////////////////
 
+if(!defined('GETID3_LIBXML_OPTIONS') && defined('LIBXML_VERSION')) {
+	if(LIBXML_VERSION >= 20621) {
+		define('GETID3_LIBXML_OPTIONS', LIBXML_NOENT | LIBXML_NONET | LIBXML_NOWARNING | LIBXML_COMPACT);
+	} else {
+		define('GETID3_LIBXML_OPTIONS', LIBXML_NOENT | LIBXML_NONET | LIBXML_NOWARNING);
+	}
+}
 
 class getid3_lib
 {
@@ -303,11 +310,10 @@ class getid3_lib
 			}
 		} elseif (($exponent == 0) && ($fraction == 0)) {
 			if ($signbit == '1') {
-				$floatvalue = -0;
+				$floatvalue = -0.0;
 			} else {
-				$floatvalue = 0;
+				$floatvalue = 0.0;
 			}
-			$floatvalue = ($signbit ? 0 : -0);
 		} elseif (($exponent == 0) && ($fraction != 0)) {
 			// These are 'unnormalized' values
 			$floatvalue = pow(2, (-1 * (pow(2, $exponentbits - 1) - 2))) * self::DecimalBinary2Float($fractionstring);
@@ -732,7 +738,7 @@ class getid3_lib
 			// This function has been deprecated in PHP 8.0 because in libxml 2.9.0, external entity loading is
 			// disabled by default, but is still needed when LIBXML_NOENT is used.
 			$loader = @libxml_disable_entity_loader(true);
-			$XMLobject = simplexml_load_string($XMLstring, 'SimpleXMLElement', LIBXML_NOENT);
+			$XMLobject = simplexml_load_string($XMLstring, 'SimpleXMLElement', GETID3_LIBXML_OPTIONS);
 			$return = self::SimpleXMLelement2array($XMLobject);
 			@libxml_disable_entity_loader($loader);
 			return $return;
diff --git a/lib/getid3/getid3.php b/lib/getid3/getid3.php
index c4be4845..5e955304 100644
--- a/lib/getid3/getid3.php
+++ b/lib/getid3/getid3.php
@@ -182,7 +182,7 @@ class getID3
 	public $option_md5_data          = false;
 
 	/**
-	 * Use MD5 of source file if availble - only FLAC and OptimFROG
+	 * Use MD5 of source file if available - only FLAC and OptimFROG
 	 *
 	 * @var bool
 	 */
@@ -387,12 +387,15 @@ class getID3
 	 */
 	protected $startup_warning = '';
 
-	const VERSION           = '1.9.21-202109171300';
+	const VERSION           = '1.9.22-202207161647';
 	const FREAD_BUFFER_SIZE = 32768;
 
 	const ATTACHMENTS_NONE   = false;
 	const ATTACHMENTS_INLINE = true;
 
+	/**
+	 * @throws getid3_exception
+	 */
 	public function __construct() {
 
 		// Check for PHP version
@@ -565,7 +568,7 @@ class getID3
 			$this->info['php_memory_limit'] = (($this->memory_limit > 0) ? $this->memory_limit : false);
 
 			// remote files not supported
-			if (preg_match('#^(ht|f)tp://#', $filename)) {
+			if (preg_match('#^(ht|f)tps?://#', $filename)) {
 				throw new getid3_exception('Remote files are not supported - please copy the file locally first');
 			}
 
@@ -1051,15 +1054,16 @@ class getID3
 							'mime_type' => 'audio/x-monkeys-audio',
 						),
 
-// has been known to produce false matches in random files (e.g. JPEGs), leave out until more precise matching available
-//				// MOD  - audio       - MODule (assorted sub-formats)
-//				'mod'  => array(
-//							'pattern'   => '^.{1080}(M\\.K\\.|M!K!|FLT4|FLT8|[5-9]CHN|[1-3][0-9]CH)',
-//							'group'     => 'audio',
-//							'module'    => 'mod',
-//							'option'    => 'mod',
-//							'mime_type' => 'audio/mod',
-//						),
+
+				// MOD  - audio       - MODule (SoundTracker)
+				'mod'  => array(
+							//'pattern'   => '^.{1080}(M\\.K\\.|M!K!|FLT4|FLT8|[5-9]CHN|[1-3][0-9]CH)', // has been known to produce false matches in random files (e.g. JPEGs), leave out until more precise matching available
+							'pattern'   => '^.{1080}(M\\.K\\.)',
+							'group'     => 'audio',
+							'module'    => 'mod',
+							'option'    => 'mod',
+							'mime_type' => 'audio/mod',
+						),
 
 				// MOD  - audio       - MODule (Impulse Tracker)
 				'it'   => array(
@@ -1090,7 +1094,7 @@ class getID3
 
 				// MPC  - audio       - Musepack / MPEGplus
 				'mpc'  => array(
-							'pattern'   => '^(MPCK|MP\\+|[\\x00\\x01\\x10\\x11\\x40\\x41\\x50\\x51\\x80\\x81\\x90\\x91\\xC0\\xC1\\xD0\\xD1][\\x20-\\x37][\\x00\\x20\\x40\\x60\\x80\\xA0\\xC0\\xE0])',
+							'pattern'   => '^(MPCK|MP\\+)',
 							'group'     => 'audio',
 							'module'    => 'mpc',
 							'mime_type' => 'audio/x-musepack',
@@ -1547,6 +1551,13 @@ class getID3
 			$info = $GetFileFormatArray['mp3'];
 			$info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php';
 			return $info;
+		} elseif (preg_match('#\\.mp[cp\\+]$#i', $filename) && preg_match('#[\x00\x01\x10\x11\x40\x41\x50\x51\x80\x81\x90\x91\xC0\xC1\xD0\xD1][\x20-37][\x00\x20\x40\x60\x80\xA0\xC0\xE0]#s', $filedata)) {
+			// old-format (SV4-SV6) Musepack header that has a very loose pattern match and could falsely match other data (e.g. corrupt mp3)
+			// only enable this pattern check if the filename ends in .mpc/mpp/mp+
+			$GetFileFormatArray = $this->GetFileFormatArray();
+			$info = $GetFileFormatArray['mpc'];
+			$info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php';
+			return $info;
 		} elseif (preg_match('#\\.cue$#i', $filename) && preg_match('#FILE "[^"]+" (BINARY|MOTOROLA|AIFF|WAVE|MP3)#', $filedata)) {
 			// there's not really a useful consistent "magic" at the beginning of .cue files to identify them
 			// so until I think of something better, just go by filename if all other format checks fail
@@ -2193,6 +2204,11 @@ abstract class getid3_handler
 			$this->data_string_position += $bytes;
 			return substr($this->data_string, $this->data_string_position - $bytes, $bytes);
 		}
+		if ($bytes == 0) {
+			return '';
+		} elseif ($bytes < 0) {
+			throw new getid3_exception('cannot fread('.$bytes.' from '.$this->ftell().')', 10);
+		}
 		$pos = $this->ftell() + $bytes;
 		if (!getid3_lib::intValueSupported($pos)) {
 			throw new getid3_exception('cannot fread('.$bytes.' from '.$this->ftell().') because beyond PHP filesystem limit', 10);
diff --git a/lib/getid3/module.archive.zip.php b/lib/getid3/module.archive.zip.php
index ef99c141..ffd196df 100644
--- a/lib/getid3/module.archive.zip.php
+++ b/lib/getid3/module.archive.zip.php
@@ -297,7 +297,7 @@ class getid3_zip extends getid3_handler
 			$DataDescriptor = $this->fread(16);
 			$LocalFileHeader['data_descriptor']['signature']         = getid3_lib::LittleEndian2Int(substr($DataDescriptor,  0, 4));
 			if ($LocalFileHeader['data_descriptor']['signature'] != 0x08074B50) { // "PK\x07\x08"
-				$this->getid3->warning('invalid Local File Header Data Descriptor Signature at offset '.($this->ftell() - 16).' - expecting 08 07 4B 50, found '.getid3_lib::PrintHexBytes($LocalFileHeader['data_descriptor']['signature']));
+				$this->getid3->warning('invalid Local File Header Data Descriptor Signature at offset '.($this->ftell() - 16).' - expecting 08 07 4B 50, found '.getid3_lib::PrintHexBytes(substr($DataDescriptor,  0, 4)));
 				$this->fseek($LocalFileHeader['offset']); // seek back to where filepointer originally was so it can be handled properly
 				return false;
 			}
diff --git a/lib/getid3/module.audio-video.asf.php b/lib/getid3/module.audio-video.asf.php
index 85edb7d7..e83de754 100644
--- a/lib/getid3/module.audio-video.asf.php
+++ b/lib/getid3/module.audio-video.asf.php
@@ -20,6 +20,24 @@ getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php',
 
 class getid3_asf extends getid3_handler
 {
+	protected static $ASFIndexParametersObjectIndexSpecifiersIndexTypes = array(
+		1 => 'Nearest Past Data Packet',
+		2 => 'Nearest Past Media Object',
+		3 => 'Nearest Past Cleanpoint'
+	);
+
+	protected static $ASFMediaObjectIndexParametersObjectIndexSpecifiersIndexTypes = array(
+		1 => 'Nearest Past Data Packet',
+		2 => 'Nearest Past Media Object',
+		3 => 'Nearest Past Cleanpoint',
+		0xFF => 'Frame Number Offset'
+	);
+
+	protected static $ASFTimecodeIndexParametersObjectIndexSpecifiersIndexTypes = array(
+		2 => 'Nearest Past Media Object',
+		3 => 'Nearest Past Cleanpoint'
+	);
+
 	/**
 	 * @param getID3 $getid3
 	 */
@@ -317,6 +335,7 @@ class getid3_asf extends getid3_handler
 
 					// shortcut
 					$thisfile_asf['codec_list_object'] = array();
+					/** @var mixed[] $thisfile_asf_codeclistobject */
 					$thisfile_asf_codeclistobject      = &$thisfile_asf['codec_list_object'];
 
 					$thisfile_asf_codeclistobject['offset']                    = $NextObjectOffset + $offset;
@@ -332,6 +351,9 @@ class getid3_asf extends getid3_handler
 						break;
 					}
 					$thisfile_asf_codeclistobject['codec_entries_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
+					if ($thisfile_asf_codeclistobject['codec_entries_count'] > 0) {
+						$thisfile_asf_codeclistobject['codec_entries'] = array();
+					}
 					$offset += 4;
 					for ($CodecEntryCounter = 0; $CodecEntryCounter < $thisfile_asf_codeclistobject['codec_entries_count']; $CodecEntryCounter++) {
 						// shortcut
@@ -528,7 +550,7 @@ class getid3_asf extends getid3_handler
 					$offset += 16;
 					$thisfile_asf_markerobject['reserved_guid']        = $this->BytestringToGUID($thisfile_asf_markerobject['reserved']);
 					if ($thisfile_asf_markerobject['reserved'] != $this->GUIDtoBytestring('4CFEDB20-75F6-11CF-9C0F-00A0C90349CB')) {
-						$this->warning('marker_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_markerobject['reserved_1']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {4CFEDB20-75F6-11CF-9C0F-00A0C90349CB}');
+						$this->warning('marker_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_markerobject['reserved']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {4CFEDB20-75F6-11CF-9C0F-00A0C90349CB}');
 						break;
 					}
 					$thisfile_asf_markerobject['markers_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
@@ -648,7 +670,7 @@ class getid3_asf extends getid3_handler
 							break;
 
 						default:
-							$this->warning('error_correction_object.error_correction_type GUID {'.$this->BytestringToGUID($thisfile_asf_errorcorrectionobject['reserved']).'} does not match expected "GETID3_ASF_No_Error_Correction" GUID {'.$this->BytestringToGUID(GETID3_ASF_No_Error_Correction).'} or  "GETID3_ASF_Audio_Spread" GUID {'.$this->BytestringToGUID(GETID3_ASF_Audio_Spread).'}');
+							$this->warning('error_correction_object.error_correction_type GUID {'.$this->BytestringToGUID($thisfile_asf_errorcorrectionobject['error_correction_type']).'} does not match expected "GETID3_ASF_No_Error_Correction" GUID {'.$this->BytestringToGUID(GETID3_ASF_No_Error_Correction).'} or  "GETID3_ASF_Audio_Spread" GUID {'.$this->BytestringToGUID(GETID3_ASF_Audio_Spread).'}');
 							//return false;
 							break;
 					}
@@ -1442,7 +1464,7 @@ class getid3_asf extends getid3_handler
 				}
 			}
 		}
-		$info['bitrate'] = (isset($thisfile_audio['bitrate']) ? $thisfile_audio['bitrate'] : 0) + (isset($thisfile_video['bitrate']) ? $thisfile_video['bitrate'] : 0);
+		$info['bitrate'] = 0 + (isset($thisfile_audio['bitrate']) ? $thisfile_audio['bitrate'] : 0) + (isset($thisfile_video['bitrate']) ? $thisfile_video['bitrate'] : 0);
 
 		if ((!isset($info['playtime_seconds']) || ($info['playtime_seconds'] <= 0)) && ($info['bitrate'] > 0)) {
 			$info['playtime_seconds'] = ($info['filesize'] - $info['avdataoffset']) / ($info['bitrate'] / 8);
@@ -1577,8 +1599,9 @@ class getid3_asf extends getid3_handler
 			'GETID3_ASF_Audio_Media'                         => 'F8699E40-5B4D-11CF-A8FD-00805F5C442B',
 			'GETID3_ASF_Media_Object_Index_Object'           => 'FEB103F8-12AD-4C64-840F-2A1D2F7AD48C',
 			'GETID3_ASF_Alt_Extended_Content_Encryption_Obj' => 'FF889EF1-ADEE-40DA-9E71-98704BB928CE',
-			'GETID3_ASF_Index_Placeholder_Object'            => 'D9AADE20-7C17-4F9C-BC28-8555DD98E2A2', // http://cpan.uwinnipeg.ca/htdocs/Audio-WMA/Audio/WMA.pm.html
-			'GETID3_ASF_Compatibility_Object'                => '26F18B5D-4584-47EC-9F5F-0E651F0452C9', // http://cpan.uwinnipeg.ca/htdocs/Audio-WMA/Audio/WMA.pm.html
+			'GETID3_ASF_Index_Placeholder_Object'            => 'D9AADE20-7C17-4F9C-BC28-8555DD98E2A2', // https://metacpan.org/dist/Audio-WMA/source/WMA.pm
+			'GETID3_ASF_Compatibility_Object'                => '26F18B5D-4584-47EC-9F5F-0E651F0452C9', // https://metacpan.org/dist/Audio-WMA/source/WMA.pm
+			'GETID3_ASF_Media_Object_Index_Parameters_Object'=> '6B203BAD-3F11-48E4-ACA8-D7613DE2CFA7',
 		);
 		return $GUIDarray;
 	}
@@ -1741,7 +1764,7 @@ class getid3_asf extends getid3_handler
 	 * @return array
 	 */
 	public function HeaderExtensionObjectDataParse(&$asf_header_extension_object_data, &$unhandled_sections) {
-		// http://msdn.microsoft.com/en-us/library/bb643323.aspx
+		// https://web.archive.org/web/20140419205228/http://msdn.microsoft.com/en-us/library/bb643323.aspx
 
 		$offset = 0;
 		$objectOffset = 0;
@@ -1805,8 +1828,8 @@ class getid3_asf extends getid3_handler
 					$thisObject['stream_language_id_index']          = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
 					$offset += 2;
 
-					$thisObject['average_time_per_frame']            = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
-					$offset += 4;
+					$thisObject['average_time_per_frame']            = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  8));
+					$offset += 8;
 
 					$thisObject['stream_name_count']                 = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
 					$offset += 2;
@@ -1823,7 +1846,7 @@ class getid3_asf extends getid3_handler
 						$streamName['stream_name_length']            = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
 						$offset += 2;
 
-						$streamName['stream_name']                   = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  $streamName['stream_name_length']));
+						$streamName['stream_name']                   =                              substr($asf_header_extension_object_data, $offset,  $streamName['stream_name_length']);
 						$offset += $streamName['stream_name_length'];
 
 						$thisObject['stream_names'][$i] = $streamName;
@@ -1845,7 +1868,7 @@ class getid3_asf extends getid3_handler
 						$payloadExtensionSystem['extension_system_info_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
 						$offset += 4;
 
-						$payloadExtensionSystem['extension_system_info_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  $payloadExtensionSystem['extension_system_info_length']));
+						$payloadExtensionSystem['extension_system_info'] = substr($asf_header_extension_object_data, $offset,  $payloadExtensionSystem['extension_system_info_length']);
 						$offset += $payloadExtensionSystem['extension_system_info_length'];
 
 						$thisObject['payload_extension_systems'][$i] = $payloadExtensionSystem;
@@ -1853,6 +1876,40 @@ class getid3_asf extends getid3_handler
 
 					break;
 
+				case GETID3_ASF_Advanced_Mutual_Exclusion_Object:
+					$thisObject['exclusion_type']       = substr($asf_header_extension_object_data, $offset, 16);
+					$offset += 16;
+					$thisObject['exclusion_type_text']  = $this->BytestringToGUID($thisObject['exclusion_type']);
+
+					$thisObject['stream_numbers_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
+					$offset += 2;
+
+					for ($i = 0; $i < $thisObject['stream_numbers_count']; $i++) {
+						$thisObject['stream_numbers'][$i] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
+						$offset += 2;
+					}
+
+					break;
+
+				case GETID3_ASF_Stream_Prioritization_Object:
+					$thisObject['priority_records_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
+					$offset += 2;
+
+					for ($i = 0; $i < $thisObject['priority_records_count']; $i++) {
+						$priorityRecord = array();
+
+						$priorityRecord['stream_number'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
+						$offset += 2;
+
+						$priorityRecord['flags_raw']     = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
+						$offset += 2;
+						$priorityRecord['flags']['mandatory'] = (bool) $priorityRecord['flags_raw'] & 0x00000001;
+
+						$thisObject['priority_records'][$i] = $priorityRecord;
+					}
+
+					break;
+
 				case GETID3_ASF_Padding_Object:
 					// padding, skip it
 					break;
@@ -1970,6 +2027,103 @@ class getid3_asf extends getid3_handler
 					}
 					break;
 
+				case GETID3_ASF_Index_Parameters_Object:
+					$thisObject['index_entry_time_interval'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4));
+					$offset += 4;
+
+					$thisObject['index_specifiers_count']    = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
+					$offset += 2;
+
+					for ($i = 0; $i < $thisObject['index_specifiers_count']; $i++) {
+						$indexSpecifier = array();
+
+						$indexSpecifier['stream_number']   = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
+						$offset += 2;
+
+						$indexSpecifier['index_type']      = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
+						$offset += 2;
+						$indexSpecifier['index_type_text'] = isset(static::$ASFIndexParametersObjectIndexSpecifiersIndexTypes[$indexSpecifier['index_type']])
+							? static::$ASFIndexParametersObjectIndexSpecifiersIndexTypes[$indexSpecifier['index_type']]
+							: 'invalid'
+						;
+
+						$thisObject['index_specifiers'][$i] = $indexSpecifier;
+					}
+
+					break;
+
+				case GETID3_ASF_Media_Object_Index_Parameters_Object:
+					$thisObject['index_entry_count_interval'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4));
+					$offset += 4;
+
+					$thisObject['index_specifiers_count']     = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
+					$offset += 2;
+
+					for ($i = 0; $i < $thisObject['index_specifiers_count']; $i++) {
+						$indexSpecifier = array();
+
+						$indexSpecifier['stream_number']   = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
+						$offset += 2;
+
+						$indexSpecifier['index_type']      = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
+						$offset += 2;
+						$indexSpecifier['index_type_text'] = isset(static::$ASFMediaObjectIndexParametersObjectIndexSpecifiersIndexTypes[$indexSpecifier['index_type']])
+							? static::$ASFMediaObjectIndexParametersObjectIndexSpecifiersIndexTypes[$indexSpecifier['index_type']]
+							: 'invalid'
+						;
+
+						$thisObject['index_specifiers'][$i] = $indexSpecifier;
+					}
+
+					break;
+
+				case GETID3_ASF_Timecode_Index_Parameters_Object:
+					// 4.11	Timecode Index Parameters Object (mandatory only if TIMECODE index is present in file, 0 or 1)
+					// Field name                     Field type   Size (bits)
+					// Object ID                      GUID         128             // GUID for the Timecode Index Parameters Object - ASF_Timecode_Index_Parameters_Object
+					// Object Size                    QWORD        64              // Specifies the size, in bytes, of the Timecode Index Parameters Object. Valid values are at least 34 bytes.
+					// Index Entry Count Interval     DWORD        32              // This value is ignored for the Timecode Index Parameters Object.
+					// Index Specifiers Count         WORD         16              // Specifies the number of entries in the Index Specifiers list. Valid values are 1 and greater.
+					// Index Specifiers               array of:    varies          //
+					// * Stream Number                WORD         16              // Specifies the stream number that the Index Specifiers refer to. Valid values are between 1 and 127.
+					// * Index Type                   WORD         16              // Specifies the type of index. Values are defined as follows (1 is not a valid value):
+					                                                               // 2 = Nearest Past Media Object - indexes point to the closest data packet containing an entire video frame or the first fragment of a video frame
+					                                                               // 3 = Nearest Past Cleanpoint - indexes point to the closest data packet containing an entire video frame (or first fragment of a video frame) that is a key frame.
+					                                                               // Nearest Past Media Object is the most common value
+
+					$thisObject['index_entry_count_interval'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4));
+					$offset += 4;
+
+					$thisObject['index_specifiers_count']     = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
+					$offset += 2;
+
+					for ($i = 0; $i < $thisObject['index_specifiers_count']; $i++) {
+						$indexSpecifier = array();
+
+						$indexSpecifier['stream_number']   = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
+						$offset += 2;
+
+						$indexSpecifier['index_type']      = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
+						$offset += 2;
+						$indexSpecifier['index_type_text'] = isset(static::$ASFTimecodeIndexParametersObjectIndexSpecifiersIndexTypes[$indexSpecifier['index_type']])
+							? static::$ASFTimecodeIndexParametersObjectIndexSpecifiersIndexTypes[$indexSpecifier['index_type']]
+							: 'invalid'
+						;
+
+						$thisObject['index_specifiers'][$i] = $indexSpecifier;
+					}
+
+					break;
+
+				case GETID3_ASF_Compatibility_Object:
+					$thisObject['profile'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 1));
+					$offset += 1;
+
+					$thisObject['mode']    = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 1));
+					$offset += 1;
+
+					break;
+
 				default:
 					$unhandled_sections++;
 					if ($this->GUIDname($thisObject['guid_text'])) {
diff --git a/lib/getid3/module.audio-video.mpeg.php b/lib/getid3/module.audio-video.mpeg.php
index 0504da19..6d6b1cc5 100644
--- a/lib/getid3/module.audio-video.mpeg.php
+++ b/lib/getid3/module.audio-video.mpeg.php
@@ -615,7 +615,7 @@ echo 'average_File_bitrate = '.number_format(array_sum($vbr_bitrates) / count($v
 			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);
-		if ($mpeg_version == 2 && $ratio != 1) {
+		if ($mpeg_version == 2 && $ratio != 1 && $width != 0) {
 			// Calculate pixel aspect ratio from MPEG-2 display aspect ratio
 			$ratio = $ratio * $height / $width;
 		}
diff --git a/lib/getid3/module.audio-video.quicktime.php b/lib/getid3/module.audio-video.quicktime.php
index 2250e1c7..a769f9c1 100644
--- a/lib/getid3/module.audio-video.quicktime.php
+++ b/lib/getid3/module.audio-video.quicktime.php
@@ -61,12 +61,16 @@ class getid3_quicktime extends getid3_handler
 			$this->fseek($offset);
 			$AtomHeader = $this->fread(8);
 
+			// https://github.com/JamesHeinrich/getID3/issues/382
+			// Atom sizes are stored as 32-bit number in most cases, but sometimes (notably for "mdat")
+			// a 64-bit value is required, in which case the normal 32-bit size field is set to 0x00000001
+			// and the 64-bit "real" size value is the next 8 bytes.
+			$atom_size_extended_bytes = 0;
 			$atomsize = getid3_lib::BigEndian2Int(substr($AtomHeader, 0, 4));
 			$atomname = substr($AtomHeader, 4, 4);
-
-			// 64-bit MOV patch by jlegateØktnc*com
 			if ($atomsize == 1) {
-				$atomsize = getid3_lib::BigEndian2Int($this->fread(8));
+				$atom_size_extended_bytes = 8;
+				$atomsize = getid3_lib::BigEndian2Int($this->fread($atom_size_extended_bytes));
 			}
 
 			if (($offset + $atomsize) > $info['avdataend']) {
@@ -85,12 +89,14 @@ class getid3_quicktime extends getid3_handler
 				$info['quicktime'][$atomname]['offset'] = $offset;
 				break;
 			}
-
 			$atomHierarchy = array();
-			$parsedAtomData = $this->QuicktimeParseAtom($atomname, $atomsize, $this->fread(min($atomsize, $atom_data_read_buffer_size)), $offset, $atomHierarchy, $this->ParseAllPossibleAtoms);
+			$parsedAtomData = $this->QuicktimeParseAtom($atomname, $atomsize, $this->fread(min($atomsize - $atom_size_extended_bytes, $atom_data_read_buffer_size)), $offset, $atomHierarchy, $this->ParseAllPossibleAtoms);
 			$parsedAtomData['name']   = $atomname;
 			$parsedAtomData['size']   = $atomsize;
 			$parsedAtomData['offset'] = $offset;
+			if ($atom_size_extended_bytes) {
+				$parsedAtomData['xsize_bytes'] = $atom_size_extended_bytes;
+			}
 			if (in_array($atomname, array('uuid'))) {
 				@$info['quicktime'][$atomname][] = $parsedAtomData;
 			} else {
@@ -108,7 +114,7 @@ class getid3_quicktime extends getid3_handler
 			unset($info['avdataend_tmp']);
 		}
 
-		if (!empty($info['quicktime']['comments']['chapters']) && is_array($info['quicktime']['comments']['chapters']) && (count($info['quicktime']['comments']['chapters']) > 0)) {
+		if (isset($info['quicktime']['comments']['chapters']) && is_array($info['quicktime']['comments']['chapters']) && (count($info['quicktime']['comments']['chapters']) > 0)) {
 			$durations = $this->quicktime_time_to_sample_table($info);
 			for ($i = 0; $i < count($info['quicktime']['comments']['chapters']); $i++) {
 				$bookmark = array();
@@ -258,7 +264,9 @@ class getid3_quicktime extends getid3_handler
 		} else {
 			switch ($atomname) {
 				case 'moov': // MOVie container atom
+				case 'moof': // MOvie Fragment box
 				case 'trak': // TRAcK container atom
+				case 'traf': // TRAck Fragment box
 				case 'clip': // CLIPping container atom
 				case 'matt': // track MATTe container atom
 				case 'edts': // EDiTS container atom
@@ -842,6 +850,7 @@ $this->warning('incomplete/incorrect handling of "stsd" with Parrot metadata in
 									case 'dvcp':
 									case 'gif ':
 									case 'h263':
+									case 'hvc1':
 									case 'jpeg':
 									case 'kpcd':
 									case 'mjpa':
@@ -1540,6 +1549,21 @@ $this->warning('incomplete/incorrect handling of "stsd" with Parrot metadata in
 					unset($mdat_offset, $chapter_string_length, $chapter_matches);
 					break;
 
+				case 'ID32': // ID3v2
+					getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
+
+					$getid3_temp = new getID3();
+					$getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
+					$getid3_id3v2 = new getid3_id3v2($getid3_temp);
+					$getid3_id3v2->StartingOffset = $atom_structure['offset'] + 14; // framelength(4)+framename(4)+flags(4)+??(2)
+					if ($atom_structure['valid'] = $getid3_id3v2->Analyze()) {
+						$atom_structure['id3v2'] = $getid3_temp->info['id3v2'];
+					} else {
+						$this->warning('ID32 frame at offset '.$atom_structure['offset'].' did not parse');
+					}
+					unset($getid3_temp, $getid3_id3v2);
+					break;
+
 				case 'free': // FREE space atom
 				case 'skip': // SKIP atom
 				case 'wide': // 64-bit expansion placeholder atom
@@ -1699,7 +1723,8 @@ $this->warning('incomplete/incorrect handling of "stsd" with Parrot metadata in
 					$atom_structure['language'] =                           substr($atom_data, 4 + 0, 2);
 					$atom_structure['unknown']  = getid3_lib::BigEndian2Int(substr($atom_data, 4 + 2, 2));
 					$atom_structure['data']     =                           substr($atom_data, 4 + 4);
-					$atom_structure['key_name'] = @$info['quicktime']['temp_meta_key_names'][$metaDATAkey++];
+					$atom_structure['key_name'] = (isset($info['quicktime']['temp_meta_key_names'][$metaDATAkey]) ? $info['quicktime']['temp_meta_key_names'][$metaDATAkey] : '');
+					$metaDATAkey++;
 
 					if ($atom_structure['key_name'] && $atom_structure['data']) {
 						@$info['quicktime']['comments'][str_replace('com.apple.quicktime.', '', $atom_structure['key_name'])][] = $atom_structure['data'];
@@ -2074,6 +2099,28 @@ $this->warning('incomplete/incorrect handling of "stsd" with Parrot metadata in
 					$atom_structure['track_number'] = getid3_lib::BigEndian2Int($atom_data);
 					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
+				case 'iinf': // Item INFo
+				case 'iref': // Image REFerence
+				case 'iprp': // Image PRoPerties
+$this->error('AVIF files not currently supported');
+					$atom_structure['data'] = $atom_data;
+					break;
+
+				case 'tfdt': // Track Fragment base media Decode Time box
+				case 'tfhd': // Track Fragment HeaDer box
+				case 'mfhd': // Movie Fragment HeaDer box
+				case 'trun': // Track fragment RUN box
+$this->error('fragmented mp4 files not currently supported');
+					$atom_structure['data'] = $atom_data;
+					break;
+
+				case 'mvex': // MoVie EXtends box
+				case 'pssh': // Protection System Specific Header box
+				case 'sidx': // Segment InDeX box
 				default:
 					$this->warning('Unknown QuickTime atom type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" ('.trim(getid3_lib::PrintHexBytes($atomname)).'), '.$atomsize.' bytes at offset '.$baseoffset);
 					$atom_structure['data'] = $atom_data;
@@ -2322,6 +2369,7 @@ $this->warning('incomplete/incorrect handling of "stsd" with Parrot metadata in
 			$QuicktimeVideoCodecLookup['gif '] = 'GIF';
 			$QuicktimeVideoCodecLookup['h261'] = 'H261';
 			$QuicktimeVideoCodecLookup['h263'] = 'H263';
+			$QuicktimeVideoCodecLookup['hvc1'] = 'H.265/HEVC';
 			$QuicktimeVideoCodecLookup['IV41'] = 'Indeo4';
 			$QuicktimeVideoCodecLookup['jpeg'] = 'JPEG';
 			$QuicktimeVideoCodecLookup['kpcd'] = 'PhotoCD';
diff --git a/lib/getid3/module.audio-video.real.php b/lib/getid3/module.audio-video.real.php
index 990379e9..9b6762d7 100644
--- a/lib/getid3/module.audio-video.real.php
+++ b/lib/getid3/module.audio-video.real.php
@@ -219,7 +219,8 @@ class getid3_real extends getid3_handler
 
 							case 'audio/x-pn-realaudio':
 							case 'audio/x-pn-multirate-realaudio':
-								$this->ParseOldRAheader($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk['parsed_audio_data']);
+								$this->ParseOldRAheader($thisfile_real_chunks_currentchunk_typespecificdata, $parsedAudioData);
+								$thisfile_real_chunks_currentchunk['parsed_audio_data'] = &$parsedAudioData;
 
 								$info['audio']['sample_rate']     = $thisfile_real_chunks_currentchunk['parsed_audio_data']['sample_rate'];
 								$info['audio']['bits_per_sample'] = $thisfile_real_chunks_currentchunk['parsed_audio_data']['bits_per_sample'];
diff --git a/lib/getid3/module.audio-video.riff.php b/lib/getid3/module.audio-video.riff.php
index 6ef1116a..e745ec65 100644
--- a/lib/getid3/module.audio-video.riff.php
+++ b/lib/getid3/module.audio-video.riff.php
@@ -808,6 +808,9 @@ class getid3_riff extends getid3_handler
 								if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'])) {
 									$strfData = $thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'];
 
+									if (!isset($thisfile_riff_raw['strf'][$strhfccType][$streamindex])) {
+										$thisfile_riff_raw['strf'][$strhfccType][$streamindex] = null;
+									}
 									// shortcut
 									$thisfile_riff_raw_strf_strhfccType_streamindex = &$thisfile_riff_raw['strf'][$strhfccType][$streamindex];
 
@@ -1353,10 +1356,10 @@ class getid3_riff extends getid3_handler
 		if (!isset($info['playtime_seconds'])) {
 			$info['playtime_seconds'] = 0;
 		}
-		if (isset($thisfile_riff_raw['strh'][0]['dwLength']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) {
+		if (isset($thisfile_riff_raw['strh'][0]['dwLength']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) { // @phpstan-ignore-line
 			// needed for >2GB AVIs where 'avih' chunk only lists number of frames in that chunk, not entire movie
 			$info['playtime_seconds'] = $thisfile_riff_raw['strh'][0]['dwLength'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000);
-		} elseif (isset($thisfile_riff_raw['avih']['dwTotalFrames']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) {
+		} elseif (isset($thisfile_riff_raw['avih']['dwTotalFrames']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) { // @phpstan-ignore-line
 			$info['playtime_seconds'] = $thisfile_riff_raw['avih']['dwTotalFrames'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000);
 		}
 
@@ -1579,7 +1582,7 @@ class getid3_riff extends getid3_handler
 	public function ParseRIFF($startoffset, $maxoffset) {
 		$info = &$this->getid3->info;
 
-		$RIFFchunk = false;
+		$RIFFchunk = array();
 		$FoundAllChunksWeNeed = false;
 		$LISTchunkParent = null;
 		$LISTchunkMaxOffset = null;
@@ -1934,7 +1937,7 @@ class getid3_riff extends getid3_handler
 			}
 		}
 
-		return $RIFFchunk;
+		return !empty($RIFFchunk) ? $RIFFchunk : false;
 	}
 
 	/**
diff --git a/lib/getid3/module.audio.aac.php b/lib/getid3/module.audio.aac.php
index d4f04b85..5b8448d2 100644
--- a/lib/getid3/module.audio.aac.php
+++ b/lib/getid3/module.audio.aac.php
@@ -400,7 +400,7 @@ class getid3_aac extends getid3_handler
 			if (!isset($BitrateCache[$FrameLength])) {
 				$BitrateCache[$FrameLength] = ($info['aac']['header']['sample_frequency'] / 1024) * $FrameLength * 8;
 			}
-			getid3_lib::safe_inc($info['aac']['bitrate_distribution'][$BitrateCache[$FrameLength]], 1);
+			getid3_lib::safe_inc($info['aac']['bitrate_distribution'][(string)$BitrateCache[$FrameLength]], 1);
 
 			$info['aac'][$framenumber]['aac_frame_length']     = $FrameLength;
 
diff --git a/lib/getid3/module.audio.mod.php b/lib/getid3/module.audio.mod.php
index bf8be33e..4841c640 100644
--- a/lib/getid3/module.audio.mod.php
+++ b/lib/getid3/module.audio.mod.php
@@ -31,9 +31,17 @@ class getid3_mod extends getid3_handler
 			return $this->getITheaderFilepointer();
 		} elseif (preg_match('#^Extended Module#', $fileheader)) {
 			return $this->getXMheaderFilepointer();
-		} elseif (preg_match('#^.{44}SCRM#', $fileheader)) {
+		} elseif (preg_match('#^.{44}SCRM#s', $fileheader)) {
 			return $this->getS3MheaderFilepointer();
-		} elseif (preg_match('#^.{1080}(M\\.K\\.|M!K!|FLT4|FLT8|[5-9]CHN|[1-3][0-9]CH)#', $fileheader)) {
+		//} elseif (preg_match('#^.{1080}(M\\.K\\.|M!K!|FLT4|FLT8|[5-9]CHN|[1-3][0-9]CH)#s', $fileheader)) {
+		} elseif (preg_match('#^.{1080}(M\\.K\\.)#s', $fileheader)) {
+			/*
+			The four letters "M.K." - This is something Mahoney & Kaktus inserted when they
+			increased the number of samples from 15 to 31. If it's not there, the module/song
+			uses 15 samples or the text has been removed to make the module harder to rip.
+			Startrekker puts "FLT4" or "FLT8" there instead.
+			If there are more than 64 patterns, PT2.3 will insert M!K! here.
+			*/
 			return $this->getMODheaderFilepointer();
 		}
 		$this->error('This is not a known type of MOD file');
@@ -45,17 +53,48 @@ class getid3_mod extends getid3_handler
 	 */
 	public function getMODheaderFilepointer() {
 		$info = &$this->getid3->info;
-		$this->fseek($info['avdataoffset'] + 1080);
-		$FormatID = $this->fread(4);
-		if (!preg_match('#^(M.K.|[5-9]CHN|[1-3][0-9]CH)$#', $FormatID)) {
-			$this->error('This is not a known type of MOD file');
+		$this->fseek($info['avdataoffset']);
+		$filedata = $this->fread(1084);
+		//if (!preg_match('#^(M.K.|[5-9]CHN|[1-3][0-9]CH)$#', $FormatID)) {
+		if (substr($filedata, 1080, 4) == 'M.K.') {
+
+			// + 0                song/module working title
+			// + 20               15 sample headers (see below)
+			// + 470              song length (number of steps in pattern table)
+			// + 471              song speed in beats per minute (see below)
+			// + 472              pattern step table
+			$offset = 0;
+ 			$info['mod']['title'] = rtrim(substr($filedata, $offset, 20), "\x00");  $offset += 20;
+
+ 			$info['tags']['mod']['title'] = array($info['mod']['title']);
+
+ 			for ($samplenumber = 0; $samplenumber <= 30; $samplenumber++) {
+ 				$sampledata = array();
+ 				$sampledata['name']          =                           substr($filedata, $offset, 22);   $offset += 22;
+ 				$sampledata['length']        = getid3_lib::BigEndian2Int(substr($filedata, $offset,  2));  $offset +=  2;
+ 				$sampledata['volume']        = getid3_lib::BigEndian2Int(substr($filedata, $offset,  2));  $offset +=  2;
+ 				$sampledata['repeat_offset'] = getid3_lib::BigEndian2Int(substr($filedata, $offset,  2));  $offset +=  2;
+ 				$sampledata['repeat_length'] = getid3_lib::BigEndian2Int(substr($filedata, $offset,  2));  $offset +=  2;
+ 				$info['mod']['samples'][$samplenumber] = $sampledata;
+ 			}
+
+ 			$info['mod']['song_length'] = getid3_lib::BigEndian2Int(substr($filedata, $offset++,  1));// Songlength. Range is 1-128.
+ 			$info['mod']['bpm']         = getid3_lib::BigEndian2Int(substr($filedata, $offset++,  1));// This byte is set to 127, so that old trackers will search through all patterns when loading. Noisetracker uses this byte for restart, ProTracker doesn't.
+
+ 			for ($songposition = 0; $songposition <= 127; $songposition++) {
+ 				// Song positions 0-127.  Each hold a number from 0-63 (or 0-127)
+ 				// that tells the tracker what pattern to play at that position.
+				$info['mod']['song_positions'][$songposition] = getid3_lib::BigEndian2Int(substr($filedata, $offset++, 1));
+ 			}
+
+		} else {
+			$this->error('unknown MOD ID at offset 1080: '.getid3_lib::PrintHexBytes(substr($filedata, 1080, 4)));
 			return false;
 		}
-
 		$info['fileformat'] = 'mod';
 
-		$this->error('MOD parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
-		return false;
+$this->warning('MOD (SoundTracker) parsing incomplete in this version of getID3() ['.$this->getid3->version().']');
+		return true;
 	}
 
 	/**
diff --git a/lib/getid3/module.audio.mp3.php b/lib/getid3/module.audio.mp3.php
index 1f5a566b..3d8a9442 100644
--- a/lib/getid3/module.audio.mp3.php
+++ b/lib/getid3/module.audio.mp3.php
@@ -315,6 +315,10 @@ class getid3_mp3 extends getid3_handler
 			$encoder_options .= ' -b'.$thisfile_mpeg_audio_lame['bitrate_min'];
 		}
 
+		if (isset($thisfile_mpeg_audio['bitrate']) && $thisfile_mpeg_audio['bitrate'] === 'free') {
+			$encoder_options .= ' --freeformat';
+		}
+
 		if (!empty($thisfile_mpeg_audio_lame['encoding_flags']['nogap_prev']) || !empty($thisfile_mpeg_audio_lame['encoding_flags']['nogap_next'])) {
 			$encoder_options .= ' --nogap';
 		}
@@ -750,7 +754,8 @@ class getid3_mp3 extends getid3_handler
 							unset($thisfile_mpeg_audio_lame['long_version']);
 
 							// It the LAME tag was only introduced in LAME v3.90
-							// http://www.hydrogenaudio.org/?act=ST&f=15&t=9933
+							// https://wiki.hydrogenaud.io/index.php/LAME#VBR_header_and_LAME_tag
+							// https://hydrogenaud.io/index.php?topic=9933
 
 							// Offsets of various bytes in http://gabriel.mp3-tech.org/mp3infotag.html
 							// are assuming a 'Xing' identifier offset of 0x24, which is the case for
@@ -786,7 +791,7 @@ class getid3_mp3 extends getid3_handler
 							$thisfile_mpeg_audio_lame['lowpass_frequency'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA6, 1)) * 100;
 
 							// bytes $A7-$AE  Replay Gain
-							// http://privatewww.essex.ac.uk/~djmrob/replaygain/rg_data_format.html
+							// https://web.archive.org/web/20021015212753/http://privatewww.essex.ac.uk/~djmrob/replaygain/rg_data_format.html
 							// bytes $A7-$AA : 32 bit floating point "Peak signal amplitude"
 							if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.94b') {
 								// LAME 3.94a16 and later - 9.23 fixed point
@@ -914,7 +919,7 @@ class getid3_mp3 extends getid3_handler
 
 
 							// LAME CBR
-							if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) {
+							if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1 && $thisfile_mpeg_audio['bitrate'] !== 'free') {
 
 								$thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
 								$thisfile_mpeg_audio['bitrate'] = self::ClosestStandardMP3Bitrate($thisfile_mpeg_audio['bitrate']);
@@ -1169,6 +1174,7 @@ class getid3_mp3 extends getid3_handler
 
 			$nextframetestarray = array('error' => array(), 'warning' => array(), 'avdataend' => $info['avdataend'], 'avdataoffset'=>$info['avdataoffset']);
 			if ($this->decodeMPEGaudioHeader($nextframetestoffset, $nextframetestarray, false)) {
+				/** @phpstan-ignore-next-line */
 				getid3_lib::safe_inc($info['mp3_validity_check_bitrates'][$nextframetestarray['mpeg']['audio']['bitrate']]);
 				if ($ScanAsCBR) {
 					// force CBR mode, used for trying to pick out invalid audio streams with valid(?) VBR headers, or VBR streams with no VBR header
diff --git a/lib/getid3/module.audio.mpc.php b/lib/getid3/module.audio.mpc.php
index d7f2d99f..e869e29f 100644
--- a/lib/getid3/module.audio.mpc.php
+++ b/lib/getid3/module.audio.mpc.php
@@ -48,7 +48,7 @@ class getid3_mpc extends getid3_handler
 			// this is SV7
 			return $this->ParseMPCsv7();
 
-		} elseif (preg_match('/^[\x00\x01\x10\x11\x40\x41\x50\x51\x80\x81\x90\x91\xC0\xC1\xD0\xD1][\x20-37][\x00\x20\x40\x60\x80\xA0\xC0\xE0]/s', $MPCheaderData)) {
+		} elseif (preg_match('#^[\x00\x01\x10\x11\x40\x41\x50\x51\x80\x81\x90\x91\xC0\xC1\xD0\xD1][\x20-37][\x00\x20\x40\x60\x80\xA0\xC0\xE0]#s', $MPCheaderData)) {
 
 			// this is SV4 - SV6, handle seperately
 			return $this->ParseMPCsv6();
diff --git a/lib/getid3/module.audio.ogg.php b/lib/getid3/module.audio.ogg.php
index 5786fd0d..0cbea61e 100644
--- a/lib/getid3/module.audio.ogg.php
+++ b/lib/getid3/module.audio.ogg.php
@@ -186,7 +186,7 @@ class getid3_ogg extends getid3_handler
 			if ($info['ogg']['pageheader']['theora']['pixel_aspect_denominator'] > 0) {
 				$info['video']['pixel_aspect_ratio'] = (float) $info['ogg']['pageheader']['theora']['pixel_aspect_numerator'] / $info['ogg']['pageheader']['theora']['pixel_aspect_denominator'];
 			}
-			$this->warning('Ogg Theora (v3) not fully supported in this version of getID3 ['.$this->getid3->version().'] -- bitrate, playtime and all audio data are currently unavailable');
+$this->warning('Ogg Theora (v3) not fully supported in this version of getID3 ['.$this->getid3->version().'] -- bitrate, playtime and all audio data are currently unavailable');
 
 
 		} elseif (substr($filedata, 0, 8) == "fishead\x00") {
diff --git a/lib/getid3/module.audio.voc.php b/lib/getid3/module.audio.voc.php
index f765719e..6bed1318 100644
--- a/lib/getid3/module.audio.voc.php
+++ b/lib/getid3/module.audio.voc.php
@@ -59,6 +59,7 @@ class getid3_voc extends getid3_handler
 		$thisfile_voc['header']['datablock_offset'] = getid3_lib::LittleEndian2Int(substr($VOCheader, 20, 2));
 		$thisfile_voc['header']['minor_version']    = getid3_lib::LittleEndian2Int(substr($VOCheader, 22, 1));
 		$thisfile_voc['header']['major_version']    = getid3_lib::LittleEndian2Int(substr($VOCheader, 23, 1));
+		$thisfile_voc['blocktypes']                 = array();
 
 		do {
 
@@ -68,6 +69,7 @@ class getid3_voc extends getid3_handler
 			$BlockSize      = getid3_lib::LittleEndian2Int(substr($BlockData, 1, 3));
 			$ThisBlock      = array();
 
+			/** @phpstan-ignore-next-line */
 			getid3_lib::safe_inc($thisfile_voc['blocktypes'][$BlockType], 1);
 			switch ($BlockType) {
 				case 0:  // Terminator
diff --git a/lib/getid3/module.graphic.gif.php b/lib/getid3/module.graphic.gif.php
index 0e463c8c..f9719137 100644
--- a/lib/getid3/module.graphic.gif.php
+++ b/lib/getid3/module.graphic.gif.php
@@ -17,6 +17,7 @@
 /**
  * @link https://www.w3.org/Graphics/GIF/spec-gif89a.txt
  * @link http://www.matthewflickinger.com/lab/whatsinagif/bits_and_bytes.asp
+ * @link http://www.vurdalakov.net/misc/gif/netscape-looping-application-extension
  */
 
 if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
@@ -168,14 +169,31 @@ class getid3_gif extends getid3_handler
 					$ExtensionBlock['byte_length']    = getid3_lib::LittleEndian2Int(substr($ExtensionBlockData, 2, 1));
 					$ExtensionBlock['data']           = (($ExtensionBlock['byte_length'] > 0) ? $this->fread($ExtensionBlock['byte_length']) : null);
 
-					if (substr($ExtensionBlock['data'], 0, 11) == 'NETSCAPE2.0') { // Netscape Application Block (NAB)
-						$ExtensionBlock['data'] .= $this->fread(4);
-						if (substr($ExtensionBlock['data'], 11, 2) == "\x03\x01") {
-							$info['gif']['animation']['animated']   = true;
-							$info['gif']['animation']['loop_count'] = getid3_lib::LittleEndian2Int(substr($ExtensionBlock['data'], 13, 2));
-						} else {
-							$this->warning('Expecting 03 01 at offset '.($this->ftell() - 4).', found "'.getid3_lib::PrintHexBytes(substr($ExtensionBlock['data'], 11, 2)).'"');
-						}
+					switch ($ExtensionBlock['function_code']) {
+						case 0xFF:
+							// Application Extension
+							if ($ExtensionBlock['byte_length'] != 11) {
+								$this->warning('Expected block size of the Application Extension is 11 bytes, found '.$ExtensionBlock['byte_length'].' at offset '.$this->ftell());
+								break;
+							}
+
+							if (substr($ExtensionBlock['data'], 0, 11) !== 'NETSCAPE2.0'
+								&& substr($ExtensionBlock['data'], 0, 11) !== 'ANIMEXTS1.0'
+							) {
+								$this->warning('Ignoring unsupported Application Extension '.substr($ExtensionBlock['data'], 0, 11));
+								break;
+							}
+
+							// Netscape Application Block (NAB)
+							$ExtensionBlock['data'] .= $this->fread(4);
+							if (substr($ExtensionBlock['data'], 11, 2) == "\x03\x01") {
+								$info['gif']['animation']['animated']   = true;
+								$info['gif']['animation']['loop_count'] = getid3_lib::LittleEndian2Int(substr($ExtensionBlock['data'], 13, 2));
+							} else {
+								$this->warning('Expecting 03 01 at offset '.($this->ftell() - 4).', found "'.getid3_lib::PrintHexBytes(substr($ExtensionBlock['data'], 11, 2)).'"');
+							}
+
+							break;
 					}
 
 					if ($this->getid3->option_extra_info) {
diff --git a/lib/getid3/module.misc.cue.php b/lib/getid3/module.misc.cue.php
index 5082f2fb..b358f8ac 100644
--- a/lib/getid3/module.misc.cue.php
+++ b/lib/getid3/module.misc.cue.php
@@ -73,7 +73,7 @@ class getid3_cue extends getid3_handler
 	public function readCueSheet(&$filedata)
 	{
 		$cue_lines = array();
-		foreach (explode("\n", str_replace("\r", null, $filedata)) as $line)
+		foreach (explode("\n", str_replace("\r", '', $filedata)) as $line)
 		{
 			if ( (strlen($line) > 0) && ($line[0] != '#'))
 			{
diff --git a/lib/getid3/module.misc.pdf.php b/lib/getid3/module.misc.pdf.php
index 975fe3df..fd4ae728 100644
--- a/lib/getid3/module.misc.pdf.php
+++ b/lib/getid3/module.misc.pdf.php
@@ -85,7 +85,7 @@ class getid3_pdf extends getid3_handler
 							// "free" object means "deleted", ignore
 							continue;
 						}
-						if (($maxObjLengths[$objectNumber] > 0) && ($maxObjLengths[$objectNumber] < $this->getid3->option_fread_buffer_size)) {
+						if (!empty($maxObjLengths[$objectNumber]) && ($maxObjLengths[$objectNumber] < $this->getid3->option_fread_buffer_size)) {
 							// ignore object that are zero-size or >32kB, they are unlikely to contain information we're interested in
 							$this->fseek($offset);
 							$objBlob = $this->fread($maxObjLengths[$objectNumber]);
diff --git a/lib/getid3/module.tag.id3v2.php b/lib/getid3/module.tag.id3v2.php
index 99e56a5f..9e7b4eb1 100644
--- a/lib/getid3/module.tag.id3v2.php
+++ b/lib/getid3/module.tag.id3v2.php
@@ -2064,7 +2064,7 @@ class getid3_id3v2 extends getid3_handler
 							$parsedFrame['subframes'][] = $subframe;
 							break;
 						case 'WXXX':
-							list($subframe['chapter_url_description'], $subframe['chapter_url']) = explode("\x00", $encoding_converted_text, 2);
+							@list($subframe['chapter_url_description'], $subframe['chapter_url']) = explode("\x00", $encoding_converted_text, 2);
 							$parsedFrame['chapter_url'][$subframe['chapter_url_description']] = $subframe['chapter_url'];
 							$parsedFrame['subframes'][] = $subframe;
 							break;
diff --git a/lib/getid3/write.metaflac.php b/lib/getid3/write.metaflac.php
index 29863344..65cf3c15 100644
--- a/lib/getid3/write.metaflac.php
+++ b/lib/getid3/write.metaflac.php
@@ -110,7 +110,7 @@ class getid3_write_metaflac
 
 				// On top of that, if error messages are not always captured properly under Windows
 				// To at least see if there was a problem, compare file modification timestamps before and after writing
-				clearstatcache();
+				clearstatcache(true, $this->filename);
 				$timestampbeforewriting = filemtime($this->filename);
 
 				$commandline  = GETID3_HELPERAPPSDIR.'metaflac.exe --no-utf8-convert --remove-all-tags --import-tags-from='.escapeshellarg($tempcommentsfilename);
@@ -121,7 +121,7 @@ class getid3_write_metaflac
 				$metaflacError = `$commandline`;
 
 				if (empty($metaflacError)) {
-					clearstatcache();
+					clearstatcache(true, $this->filename);
 					if ($timestampbeforewriting == filemtime($this->filename)) {
 						$metaflacError = 'File modification timestamp has not changed - it looks like the tags were not written';
 					}
@@ -173,14 +173,14 @@ class getid3_write_metaflac
 
 			if (file_exists(GETID3_HELPERAPPSDIR.'metaflac.exe')) {
 				// To at least see if there was a problem, compare file modification timestamps before and after writing
-				clearstatcache();
+				clearstatcache(true, $this->filename);
 				$timestampbeforewriting = filemtime($this->filename);
 
 				$commandline = GETID3_HELPERAPPSDIR.'metaflac.exe --remove-all-tags "'.$this->filename.'" 2>&1';
 				$metaflacError = `$commandline`;
 
 				if (empty($metaflacError)) {
-					clearstatcache();
+					clearstatcache(true, $this->filename);
 					if ($timestampbeforewriting == filemtime($this->filename)) {
 						$metaflacError = 'File modification timestamp has not changed - it looks like the tags were not deleted';
 					}
diff --git a/lib/getid3/write.vorbiscomment.php b/lib/getid3/write.vorbiscomment.php
index 5f89868c..31cc5a40 100644
--- a/lib/getid3/write.vorbiscomment.php
+++ b/lib/getid3/write.vorbiscomment.php
@@ -84,14 +84,14 @@ class getid3_write_vorbiscomment
 
 				// On top of that, if error messages are not always captured properly under Windows
 				// To at least see if there was a problem, compare file modification timestamps before and after writing
-				clearstatcache();
+				clearstatcache(true, $this->filename);
 				$timestampbeforewriting = filemtime($this->filename);
 
 				$commandline = GETID3_HELPERAPPSDIR.'vorbiscomment.exe -w --raw -c "'.$tempcommentsfilename.'" "'.$this->filename.'" 2>&1';
 				$VorbiscommentError = `$commandline`;
 
 				if (empty($VorbiscommentError)) {
-					clearstatcache();
+					clearstatcache(true, $this->filename);
 					if ($timestampbeforewriting == filemtime($this->filename)) {
 						$VorbiscommentError = 'File modification timestamp has not changed - it looks like the tags were not written';
 					}
-- 
GitLab