Changeset 41196
- Timestamp:
- 07/31/2017 07:49:31 PM (9 years ago)
- Location:
- trunk/src/wp-includes/ID3
- Files:
-
- 14 edited
-
getid3.lib.php (modified) (12 diffs)
-
getid3.php (modified) (60 diffs)
-
module.audio-video.asf.php (modified) (16 diffs)
-
module.audio-video.flv.php (modified) (2 diffs)
-
module.audio-video.matroska.php (modified) (37 diffs)
-
module.audio-video.quicktime.php (modified) (39 diffs)
-
module.audio-video.riff.php (modified) (21 diffs)
-
module.audio.ac3.php (modified) (8 diffs)
-
module.audio.mp3.php (modified) (34 diffs)
-
module.audio.ogg.php (modified) (20 diffs)
-
module.tag.apetag.php (modified) (17 diffs)
-
module.tag.id3v1.php (modified) (5 diffs)
-
module.tag.id3v2.php (modified) (53 diffs)
-
module.tag.lyrics3.php (modified) (11 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/ID3/getid3.lib.php
r32979 r41196 294 294 } 295 295 296 public static function LittleEndian2Bin($byteword) { 297 return self::BigEndian2Bin(strrev($byteword)); 298 } 296 299 297 300 public static function BigEndian2Bin($byteword) { … … 413 416 } 414 417 return $newarray; 418 } 419 420 public static function flipped_array_merge_noclobber($array1, $array2) { 421 if (!is_array($array1) || !is_array($array2)) { 422 return false; 423 } 424 # naturally, this only works non-recursively 425 $newarray = array_flip($array1); 426 foreach (array_flip($array2) as $key => $val) { 427 if (!isset($newarray[$key])) { 428 $newarray[$key] = count($newarray); 429 } 430 } 431 return array_flip($newarray); 415 432 } 416 433 … … 947 964 } 948 965 966 // mb_convert_encoding() availble 967 if (function_exists('mb_convert_encoding')) { 968 if ($converted_string = @mb_convert_encoding($string, $out_charset, $in_charset)) { 969 switch ($out_charset) { 970 case 'ISO-8859-1': 971 $converted_string = rtrim($converted_string, "\x00"); 972 break; 973 } 974 return $converted_string; 975 } 976 return $string; 977 } 949 978 // iconv() availble 950 if (function_exists('iconv')) {979 else if (function_exists('iconv')) { 951 980 if ($converted_string = @iconv($in_charset, $out_charset.'//TRANSLIT', $string)) { 952 981 switch ($out_charset) { … … 964 993 965 994 966 // iconv() notavailable995 // neither mb_convert_encoding or iconv() is available 967 996 static $ConversionFunctionList = array(); 968 997 if (empty($ConversionFunctionList)) { … … 986 1015 return self::$ConversionFunction($string); 987 1016 } 988 throw new Exception('PHP does not ha veiconv() support - cannot convert from '.$in_charset.' to '.$out_charset);1017 throw new Exception('PHP does not has mb_convert_encoding() or iconv() support - cannot convert from '.$in_charset.' to '.$out_charset); 989 1018 } 990 1019 … … 1007 1036 $HTMLstring = ''; 1008 1037 1009 switch ( $charset) {1038 switch (strtolower($charset)) { 1010 1039 case '1251': 1011 1040 case '1252': … … 1014 1043 case '936': 1015 1044 case '950': 1016 case ' BIG5':1017 case ' BIG5-HKSCS':1045 case 'big5': 1046 case 'big5-hkscs': 1018 1047 case 'cp1251': 1019 1048 case 'cp1252': 1020 1049 case 'cp866': 1021 case ' EUC-JP':1022 case ' EUCJP':1023 case ' GB2312':1050 case 'euc-jp': 1051 case 'eucjp': 1052 case 'gb2312': 1024 1053 case 'ibm866': 1025 case ' ISO-8859-1':1026 case ' ISO-8859-15':1027 case ' ISO8859-1':1028 case ' ISO8859-15':1029 case ' KOI8-R':1054 case 'iso-8859-1': 1055 case 'iso-8859-15': 1056 case 'iso8859-1': 1057 case 'iso8859-15': 1058 case 'koi8-r': 1030 1059 case 'koi8-ru': 1031 1060 case 'koi8r': 1032 case ' Shift_JIS':1033 case ' SJIS':1061 case 'shift_jis': 1062 case 'sjis': 1034 1063 case 'win-1251': 1035 case ' Windows-1251':1036 case ' Windows-1252':1064 case 'windows-1251': 1065 case 'windows-1252': 1037 1066 $HTMLstring = htmlentities($string, ENT_COMPAT, $charset); 1038 1067 break; 1039 1068 1040 case ' UTF-8':1069 case 'utf-8': 1041 1070 $strlen = strlen($string); 1042 1071 for ($i = 0; $i < $strlen; $i++) { … … 1066 1095 break; 1067 1096 1068 case ' UTF-16LE':1097 case 'utf-16le': 1069 1098 for ($i = 0; $i < strlen($string); $i += 2) { 1070 1099 $charval = self::LittleEndian2Int(substr($string, $i, 2)); … … 1077 1106 break; 1078 1107 1079 case ' UTF-16BE':1108 case 'utf-16be': 1080 1109 for ($i = 0; $i < strlen($string); $i += 2) { 1081 1110 $charval = self::BigEndian2Int(substr($string, $i, 2)); … … 1154 1183 static $tempdir = ''; 1155 1184 if (empty($tempdir)) { 1185 if (function_exists('sys_get_temp_dir')) { 1186 $tempdir = sys_get_temp_dir(); // https://github.com/JamesHeinrich/getID3/issues/52 1187 } 1188 1156 1189 // yes this is ugly, feel free to suggest a better way 1157 require_once(dirname(__FILE__).'/getid3.php'); 1158 $getid3_temp = new getID3(); 1159 $tempdir = $getid3_temp->tempdir; 1160 unset($getid3_temp); 1190 if (include_once(dirname(__FILE__).'/getid3.php')) { 1191 if ($getid3_temp = new getID3()) { 1192 if ($getid3_temp_tempdir = $getid3_temp->tempdir) { 1193 $tempdir = $getid3_temp_tempdir; 1194 } 1195 unset($getid3_temp, $getid3_temp_tempdir); 1196 } 1197 } 1161 1198 } 1162 1199 $GetDataImageSize = false; … … 1166 1203 fclose($tmp); 1167 1204 $GetDataImageSize = @getimagesize($tempfilename, $imageinfo); 1205 if (($GetDataImageSize === false) || !isset($GetDataImageSize[0]) || !isset($GetDataImageSize[1])) { 1206 return false; 1207 } 1168 1208 $GetDataImageSize['height'] = $GetDataImageSize[0]; 1169 1209 $GetDataImageSize['width'] = $GetDataImageSize[1]; … … 1238 1278 if (is_array($value) || empty($ThisFileInfo['comments'][$tagname]) || !in_array(trim($value), $ThisFileInfo['comments'][$tagname])) { 1239 1279 $value = (is_string($value) ? trim($value) : $value); 1240 if (!is_ numeric($key)) {1280 if (!is_int($key) && !ctype_digit($key)) { 1241 1281 $ThisFileInfo['comments'][$tagname][$key] = $value; 1242 1282 } else { 1243 $ThisFileInfo['comments'][$tagname][] = $value; 1283 if (isset($ThisFileInfo['comments'][$tagname])) { 1284 $ThisFileInfo['comments'][$tagname] = array($value); 1285 } else { 1286 $ThisFileInfo['comments'][$tagname][] = $value; 1287 } 1244 1288 } 1245 1289 } 1246 1290 } 1247 1291 } 1292 } 1293 } 1294 1295 // attempt to standardize spelling of returned keys 1296 $StandardizeFieldNames = array( 1297 'tracknumber' => 'track_number', 1298 'track' => 'track_number', 1299 ); 1300 foreach ($StandardizeFieldNames as $badkey => $goodkey) { 1301 if (array_key_exists($badkey, $ThisFileInfo['comments']) && !array_key_exists($goodkey, $ThisFileInfo['comments'])) { 1302 $ThisFileInfo['comments'][$goodkey] = $ThisFileInfo['comments'][$badkey]; 1303 unset($ThisFileInfo['comments'][$badkey]); 1248 1304 } 1249 1305 } -
trunk/src/wp-includes/ID3/getid3.php
r32979 r41196 22 22 if (!defined('IMG_JPG') && defined('IMAGETYPE_JPEG')) { 23 23 define('IMG_JPG', IMAGETYPE_JPEG); 24 } 25 if (!defined('ENT_SUBSTITUTE')) { // PHP5.3 adds ENT_IGNORE, PHP5.4 adds ENT_SUBSTITUTE 26 define('ENT_SUBSTITUTE', (defined('ENT_IGNORE') ? ENT_IGNORE : 8)); 24 27 } 25 28 … … 110 113 protected $startup_warning = ''; 111 114 112 const VERSION = '1.9. 9-20141121';115 const VERSION = '1.9.14-201706111222'; 113 116 const FREAD_BUFFER_SIZE = 32768; 114 117 … … 121 124 // Check memory 122 125 $this->memory_limit = ini_get('memory_limit'); 123 if (preg_match('#([0-9]+) M#i', $this->memory_limit, $matches)) {126 if (preg_match('#([0-9]+) ?M#i', $this->memory_limit, $matches)) { 124 127 // could be stored as "16M" rather than 16777216 for example 125 128 $this->memory_limit = $matches[1] * 1048576; 126 } elseif (preg_match('#([0-9]+) G#i', $this->memory_limit, $matches)) { // The 'G' modifier is available since PHP 5.1.0129 } elseif (preg_match('#([0-9]+) ?G#i', $this->memory_limit, $matches)) { // The 'G' modifier is available since PHP 5.1.0 127 130 // could be stored as "2G" rather than 2147483648 for example 128 131 $this->memory_limit = $matches[1] * 1073741824; … … 131 134 // memory limits probably disabled 132 135 } elseif ($this->memory_limit <= 4194304) { 133 $this->startup_error .= 'PHP has less than 4MB available memory and will very likely run out. Increase memory_limit in php.ini' ;136 $this->startup_error .= 'PHP has less than 4MB available memory and will very likely run out. Increase memory_limit in php.ini'."\n"; 134 137 } elseif ($this->memory_limit <= 12582912) { 135 $this->startup_warning .= 'PHP has less than 12MB available memory and might run out if all modules are loaded. Increase memory_limit in php.ini' ;138 $this->startup_warning .= 'PHP has less than 12MB available memory and might run out if all modules are loaded. Increase memory_limit in php.ini'."\n"; 136 139 } 137 140 … … 141 144 } 142 145 143 if (intval(ini_get('mbstring.func_overload')) > 0) { 144 $this->warning('WARNING: php.ini contains "mbstring.func_overload = '.ini_get('mbstring.func_overload').'", this may break things.'); 146 if (($mbstring_func_overload = ini_get('mbstring.func_overload')) && ($mbstring_func_overload & 0x02)) { 147 // http://php.net/manual/en/mbstring.overload.php 148 // "mbstring.func_overload in php.ini is a positive value that represents a combination of bitmasks specifying the categories of functions to be overloaded. It should be set to 1 to overload the mail() function. 2 for string functions, 4 for regular expression functions" 149 // getID3 cannot run when string functions are overloaded. It doesn't matter if mail() or ereg* functions are overloaded since getID3 does not use those. 150 $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"; 145 151 } 146 152 … … 148 154 if (function_exists('get_magic_quotes_runtime')) { 149 155 if (get_magic_quotes_runtime()) { 150 return $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).');156 $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"; 151 157 } 152 158 } … … 155 161 if (function_exists('magic_quotes_gpc')) { 156 162 if (get_magic_quotes_gpc()) { 157 return $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).');163 $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"; 158 164 } 159 165 } … … 161 167 // Load support library 162 168 if (!include_once(GETID3_INCLUDEPATH.'getid3.lib.php')) { 163 $this->startup_error .= 'getid3.lib.php is missing or corrupt' ;169 $this->startup_error .= 'getid3.lib.php is missing or corrupt'."\n"; 164 170 } 165 171 … … 180 186 181 187 if (!is_dir($helperappsdir)) { 182 $this->startup_warning .= '"'.$helperappsdir.'" cannot be defined as GETID3_HELPERAPPSDIR because it does not exist' ;188 $this->startup_warning .= '"'.$helperappsdir.'" cannot be defined as GETID3_HELPERAPPSDIR because it does not exist'."\n"; 183 189 } elseif (strpos(realpath($helperappsdir), ' ') !== false) { 184 190 $DirPieces = explode(DIRECTORY_SEPARATOR, realpath($helperappsdir)); … … 200 206 } 201 207 } else { 202 $this->startup_warning .= 'GETID3_HELPERAPPSDIR must not have any spaces in it - use 8dot3 naming convention if neccesary. You can run "dir /x" from the commandline to see the correct 8.3-style names.' ;208 $this->startup_warning .= 'GETID3_HELPERAPPSDIR must not have any spaces in it - use 8dot3 naming convention if neccesary. You can run "dir /x" from the commandline to see the correct 8.3-style names.'."\n"; 203 209 } 204 210 } … … 208 214 } 209 215 define('GETID3_HELPERAPPSDIR', $helperappsdir.DIRECTORY_SEPARATOR); 216 } 217 218 if (!empty($this->startup_error)) { 219 echo $this->startup_error; 220 throw new getid3_exception($this->startup_error); 210 221 } 211 222 … … 237 248 238 249 239 public function openfile($filename ) {250 public function openfile($filename, $filesize=null) { 240 251 try { 241 252 if (!empty($this->startup_error)) { … … 243 254 } 244 255 if (!empty($this->startup_warning)) { 245 $this->warning($this->startup_warning); 256 foreach (explode("\n", $this->startup_warning) as $startup_warning) { 257 $this->warning($startup_warning); 258 } 246 259 } 247 260 … … 253 266 254 267 // remote files not supported 255 if (preg_match(' /^(ht|f)tp:\/\//', $filename)) {268 if (preg_match('#^(ht|f)tp://#', $filename)) { 256 269 throw new getid3_exception('Remote files are not supported - please copy the file locally first'); 257 270 } 258 271 259 272 $filename = str_replace('/', DIRECTORY_SEPARATOR, $filename); 260 $filename = preg_replace('#( .+)'.preg_quote(DIRECTORY_SEPARATOR).'{2,}#U', '\1'.DIRECTORY_SEPARATOR, $filename);273 $filename = preg_replace('#(?<!gs:)('.preg_quote(DIRECTORY_SEPARATOR).'{2,})#', DIRECTORY_SEPARATOR, $filename); 261 274 262 275 // open local file … … 281 294 } 282 295 283 $this->info['filesize'] = filesize($filename);296 $this->info['filesize'] = (!is_null($filesize) ? $filesize : filesize($filename)); 284 297 // set redundant parameters - might be needed in some include file 285 298 // filenames / filepaths in getID3 are always expressed with forward slashes (unix-style) for both Windows and other to try and minimize confusion … … 289 302 $this->info['filenamepath'] = $this->info['filepath'].'/'.$this->info['filename']; 290 303 304 // set more parameters 305 $this->info['avdataoffset'] = 0; 306 $this->info['avdataend'] = $this->info['filesize']; 307 $this->info['fileformat'] = ''; // filled in later 308 $this->info['audio']['dataformat'] = ''; // filled in later, unset if not used 309 $this->info['video']['dataformat'] = ''; // filled in later, unset if not used 310 $this->info['tags'] = array(); // filled in later, unset if not used 311 $this->info['error'] = array(); // filled in later, unset if not used 312 $this->info['warning'] = array(); // filled in later, unset if not used 313 $this->info['comments'] = array(); // filled in later, unset if not used 314 $this->info['encoding'] = $this->encoding; // required by id3v2 and iso modules - can be unset at the end if desired 291 315 292 316 // option_max_2gb_check … … 315 339 } 316 340 317 // set more parameters318 $this->info['avdataoffset'] = 0;319 $this->info['avdataend'] = $this->info['filesize'];320 $this->info['fileformat'] = ''; // filled in later321 $this->info['audio']['dataformat'] = ''; // filled in later, unset if not used322 $this->info['video']['dataformat'] = ''; // filled in later, unset if not used323 $this->info['tags'] = array(); // filled in later, unset if not used324 $this->info['error'] = array(); // filled in later, unset if not used325 $this->info['warning'] = array(); // filled in later, unset if not used326 $this->info['comments'] = array(); // filled in later, unset if not used327 $this->info['encoding'] = $this->encoding; // required by id3v2 and iso modules - can be unset at the end if desired328 329 341 return true; 330 342 … … 336 348 337 349 // public: analyze file 338 public function analyze($filename ) {350 public function analyze($filename, $filesize=null, $original_filename='') { 339 351 try { 340 if (!$this->openfile($filename )) {352 if (!$this->openfile($filename, $filesize)) { 341 353 return $this->info; 342 354 } … … 383 395 384 396 // determine format 385 $determined_format = $this->GetFileFormat($formattest, $filename);397 $determined_format = $this->GetFileFormat($formattest, ($original_filename ? $original_filename : $filename)); 386 398 387 399 // unable to determine file format … … 420 432 } 421 433 422 // module requires iconv support434 // module requires mb_convert_encoding/iconv support 423 435 // Check encoding/iconv support 424 if (!empty($determined_format['iconv_req']) && !function_exists(' iconv') && !in_array($this->encoding, array('ISO-8859-1', 'UTF-8', 'UTF-16LE', 'UTF-16BE', 'UTF-16'))) {425 $errormessage = ' iconv() support is required for this module ('.$determined_format['include'].') for encodings other than ISO-8859-1, UTF-8, UTF-16LE, UTF16-BE, UTF-16. ';436 if (!empty($determined_format['iconv_req']) && !function_exists('mb_convert_encoding') && !function_exists('iconv') && !in_array($this->encoding, array('ISO-8859-1', 'UTF-8', 'UTF-16LE', 'UTF-16BE', 'UTF-16'))) { 437 $errormessage = 'mb_convert_encoding() or iconv() support is required for this module ('.$determined_format['include'].') for encodings other than ISO-8859-1, UTF-8, UTF-16LE, UTF16-BE, UTF-16. '; 426 438 if (GETID3_OS_ISWINDOWS) { 427 $errormessage .= 'PHP does not have iconv() support. Please enable php_iconv.dll in php.ini, and copyiconv.dll from c:/php/dlls to c:/windows/system32';439 $errormessage .= 'PHP does not have mb_convert_encoding() or iconv() support. Please enable php_mbstring.dll / php_iconv.dll in php.ini, and copy php_mbstring.dll / iconv.dll from c:/php/dlls to c:/windows/system32'; 428 440 } else { 429 $errormessage .= 'PHP is not compiled with iconv() support. Please recompile with the--with-iconv switch';441 $errormessage .= 'PHP is not compiled with mb_convert_encoding() or iconv() support. Please recompile with the --enable-mbstring / --with-iconv switch'; 430 442 } 431 443 return $this->error($errormessage); … … 562 574 // AC-3 - audio - Dolby AC-3 / Dolby Digital 563 575 'ac3' => array( 564 'pattern' => '^\ x0B\x77',576 'pattern' => '^\\x0B\\x77', 565 577 'group' => 'audio', 566 578 'module' => 'ac3', … … 580 592 // AA - audio - Audible Audiobook 581 593 'aa' => array( 582 'pattern' => '^.{4}\ x57\x90\x75\x36',594 'pattern' => '^.{4}\\x57\\x90\\x75\\x36', 583 595 'group' => 'audio', 584 596 'module' => 'aa', … … 588 600 // AAC - audio - Advanced Audio Coding (AAC) - ADTS format (very similar to MP3) 589 601 'adts' => array( 590 'pattern' => '^\ xFF[\xF0-\xF1\xF8-\xF9]',602 'pattern' => '^\\xFF[\\xF0-\\xF1\\xF8-\\xF9]', 591 603 'group' => 'audio', 592 604 'module' => 'aac', … … 598 610 // AU - audio - NeXT/Sun AUdio (AU) 599 611 'au' => array( 600 'pattern' => '^\ .snd',612 'pattern' => '^\\.snd', 601 613 'group' => 'audio', 602 614 'module' => 'au', … … 606 618 // AMR - audio - Adaptive Multi Rate 607 619 'amr' => array( 608 'pattern' => '^\ x23\x21AMR\x0A', // #!AMR[0A]620 'pattern' => '^\\x23\\x21AMR\\x0A', // #!AMR[0A] 609 621 'group' => 'audio', 610 622 'module' => 'amr', … … 622 634 // BONK - audio - Bonk v0.9+ 623 635 'bonk' => array( 624 'pattern' => '^\ x00(BONK|INFO|META| ID3)',636 'pattern' => '^\\x00(BONK|INFO|META| ID3)', 625 637 'group' => 'audio', 626 638 'module' => 'bonk', … … 628 640 ), 629 641 642 // DSF - audio - Direct Stream Digital (DSD) Storage Facility files (DSF) - https://en.wikipedia.org/wiki/Direct_Stream_Digital 643 'dsf' => array( 644 'pattern' => '^DSD ', // including trailing space: 44 53 44 20 645 'group' => 'audio', 646 'module' => 'dsf', 647 'mime_type' => 'audio/dsd', 648 ), 649 630 650 // DSS - audio - Digital Speech Standard 631 651 'dss' => array( 632 'pattern' => '^[\ x02-\x03]ds[s2]',652 'pattern' => '^[\\x02-\\x06]ds[s2]', 633 653 'group' => 'audio', 634 654 'module' => 'dss', … … 638 658 // DTS - audio - Dolby Theatre System 639 659 'dts' => array( 640 'pattern' => '^\ x7F\xFE\x80\x01',660 'pattern' => '^\\x7F\\xFE\\x80\\x01', 641 661 'group' => 'audio', 642 662 'module' => 'dts', … … 723 743 // MPC - audio - Musepack / MPEGplus 724 744 'mpc' => array( 725 'pattern' => '^(MPCK|MP\ +|[\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])',745 '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])', 726 746 'group' => 'audio', 727 747 'module' => 'mpc', … … 731 751 // MP3 - audio - MPEG-audio Layer 3 (very similar to AAC-ADTS) 732 752 'mp3' => array( 733 'pattern' => '^\ xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\x0B\x10-\x1B\x20-\x2B\x30-\x3B\x40-\x4B\x50-\x5B\x60-\x6B\x70-\x7B\x80-\x8B\x90-\x9B\xA0-\xAB\xB0-\xBB\xC0-\xCB\xD0-\xDB\xE0-\xEB\xF0-\xFB]',753 'pattern' => '^\\xFF[\\xE2-\\xE7\\xF2-\\xF7\\xFA-\\xFF][\\x00-\\x0B\\x10-\\x1B\\x20-\\x2B\\x30-\\x3B\\x40-\\x4B\\x50-\\x5B\\x60-\\x6B\\x70-\\x7B\\x80-\\x8B\\x90-\\x9B\\xA0-\\xAB\\xB0-\\xBB\\xC0-\\xCB\\xD0-\\xDB\\xE0-\\xEB\\xF0-\\xFB]', 734 754 'group' => 'audio', 735 755 'module' => 'mp3', … … 739 759 // OFR - audio - OptimFROG 740 760 'ofr' => array( 741 'pattern' => '^(\ *RIFF|OFR)',761 'pattern' => '^(\\*RIFF|OFR)', 742 762 'group' => 'audio', 743 763 'module' => 'optimfrog', … … 765 785 // TTA - audio - TTA Lossless Audio Compressor (http://tta.corecodec.org) 766 786 'tta' => array( 767 'pattern' => '^TTA', // could also be '^TTA(\ x01|\x02|\x03|2|1)'787 'pattern' => '^TTA', // could also be '^TTA(\\x01|\\x02|\\x03|2|1)' 768 788 'group' => 'audio', 769 789 'module' => 'tta', … … 800 820 // ASF - audio/video - Advanced Streaming Format, Windows Media Video, Windows Media Audio 801 821 'asf' => array( 802 'pattern' => '^\ x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C',822 'pattern' => '^\\x30\\x26\\xB2\\x75\\x8E\\x66\\xCF\\x11\\xA6\\xD9\\x00\\xAA\\x00\\x62\\xCE\\x6C', 803 823 'group' => 'audio-video', 804 824 'module' => 'asf', … … 817 837 // FLV - audio/video - FLash Video 818 838 'flv' => array( 819 'pattern' => '^FLV \x01',839 'pattern' => '^FLV[\\x01]', 820 840 'group' => 'audio-video', 821 841 'module' => 'flv', … … 825 845 // MKAV - audio/video - Mastroka 826 846 'matroska' => array( 827 'pattern' => '^\ x1A\x45\xDF\xA3',847 'pattern' => '^\\x1A\\x45\\xDF\\xA3', 828 848 'group' => 'audio-video', 829 849 'module' => 'matroska', … … 833 853 // MPEG - audio/video - MPEG (Moving Pictures Experts Group) 834 854 'mpeg' => array( 835 'pattern' => '^\ x00\x00\x01(\xBA|\xB3)',855 'pattern' => '^\\x00\\x00\\x01[\\xB3\\xBA]', 836 856 'group' => 'audio-video', 837 857 'module' => 'mpeg', … … 870 890 'group' => 'audio-video', 871 891 'module' => 'riff', 872 'mime_type' => 'audio/x-wav e',892 'mime_type' => 'audio/x-wav', 873 893 'fail_ape' => 'WARNING', 874 894 ), … … 876 896 // Real - audio/video - RealAudio, RealVideo 877 897 'real' => array( 878 'pattern' => '^ (\\.RMF|\\.ra)',898 'pattern' => '^\\.(RMF|ra)', 879 899 'group' => 'audio-video', 880 900 'module' => 'real', … … 892 912 // TS - audio/video - MPEG-2 Transport Stream 893 913 'ts' => array( 894 'pattern' => '^(\ x47.{187}){10,}', // packets are 188 bytes long and start with 0x47 "G". Check for at least 10 packets matching this pattern914 'pattern' => '^(\\x47.{187}){10,}', // packets are 188 bytes long and start with 0x47 "G". Check for at least 10 packets matching this pattern 895 915 'group' => 'audio-video', 896 916 'module' => 'ts', … … 923 943 // JPEG - still image - Joint Photographic Experts Group (JPEG) 924 944 'jpg' => array( 925 'pattern' => '^\ xFF\xD8\xFF',945 'pattern' => '^\\xFF\\xD8\\xFF', 926 946 'group' => 'graphic', 927 947 'module' => 'jpg', … … 933 953 // PCD - still image - Kodak Photo CD 934 954 'pcd' => array( 935 'pattern' => '^.{2048}PCD_IPI\ x00',955 'pattern' => '^.{2048}PCD_IPI\\x00', 936 956 'group' => 'graphic', 937 957 'module' => 'pcd', … … 944 964 // PNG - still image - Portable Network Graphics (PNG) 945 965 'png' => array( 946 'pattern' => '^\ x89\x50\x4E\x47\x0D\x0A\x1A\x0A',966 'pattern' => '^\\x89\\x50\\x4E\\x47\\x0D\\x0A\\x1A\\x0A', 947 967 'group' => 'graphic', 948 968 'module' => 'png', … … 955 975 // SVG - still image - Scalable Vector Graphics (SVG) 956 976 'svg' => array( 957 'pattern' => '(<!DOCTYPE svg PUBLIC |xmlns="http: \/\/www\.w3\.org\/2000\/svg")',977 'pattern' => '(<!DOCTYPE svg PUBLIC |xmlns="http://www\\.w3\\.org/2000/svg")', 958 978 'group' => 'graphic', 959 979 'module' => 'svg', … … 966 986 // TIFF - still image - Tagged Information File Format (TIFF) 967 987 'tiff' => array( 968 'pattern' => '^(II\ x2A\x00|MM\x00\x2A)',988 'pattern' => '^(II\\x2A\\x00|MM\\x00\\x2A)', 969 989 'group' => 'graphic', 970 990 'module' => 'tiff', … … 977 997 // EFAX - still image - eFax (TIFF derivative) 978 998 'efax' => array( 979 'pattern' => '^\ xDC\xFE',999 'pattern' => '^\\xDC\\xFE', 980 1000 'group' => 'graphic', 981 1001 'module' => 'efax', … … 1001 1021 // RAR - data - RAR compressed data 1002 1022 'rar' => array( 1003 'pattern' => '^Rar\ !',1023 'pattern' => '^Rar\\!', 1004 1024 'group' => 'archive', 1005 1025 'module' => 'rar', … … 1011 1031 // SZIP - audio/data - SZIP compressed data 1012 1032 'szip' => array( 1013 'pattern' => '^SZ\ x0A\x04',1033 'pattern' => '^SZ\\x0A\\x04', 1014 1034 'group' => 'archive', 1015 1035 'module' => 'szip', … … 1021 1041 // TAR - data - TAR compressed data 1022 1042 'tar' => array( 1023 'pattern' => '^.{100}[0-9\ x20]{7}\x00[0-9\x20]{7}\x00[0-9\x20]{7}\x00[0-9\x20\x00]{12}[0-9\x20\x00]{12}',1043 'pattern' => '^.{100}[0-9\\x20]{7}\\x00[0-9\\x20]{7}\\x00[0-9\\x20]{7}\\x00[0-9\\x20\\x00]{12}[0-9\\x20\\x00]{12}', 1024 1044 'group' => 'archive', 1025 1045 'module' => 'tar', … … 1031 1051 // GZIP - data - GZIP compressed data 1032 1052 'gz' => array( 1033 'pattern' => '^\ x1F\x8B\x08',1053 'pattern' => '^\\x1F\\x8B\\x08', 1034 1054 'group' => 'archive', 1035 1055 'module' => 'gzip', … … 1041 1061 // ZIP - data - ZIP compressed data 1042 1062 'zip' => array( 1043 'pattern' => '^PK\ x03\x04',1063 'pattern' => '^PK\\x03\\x04', 1044 1064 'group' => 'archive', 1045 1065 'module' => 'zip', … … 1054 1074 // PAR2 - data - Parity Volume Set Specification 2.0 1055 1075 'par2' => array ( 1056 'pattern' => '^PAR2\ x00PKT',1076 'pattern' => '^PAR2\\x00PKT', 1057 1077 'group' => 'misc', 1058 1078 'module' => 'par2', … … 1064 1084 // PDF - data - Portable Document Format 1065 1085 'pdf' => array( 1066 'pattern' => '^\ x25PDF',1086 'pattern' => '^\\x25PDF', 1067 1087 'group' => 'misc', 1068 1088 'module' => 'pdf', … … 1074 1094 // MSOFFICE - data - ZIP compressed data 1075 1095 'msoffice' => array( 1076 'pattern' => '^\ xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1', // D0CF11E == DOCFILE == Microsoft Office Document1096 'pattern' => '^\\xD0\\xCF\\x11\\xE0\\xA1\\xB1\\x1A\\xE1', // D0CF11E == DOCFILE == Microsoft Office Document 1077 1097 'group' => 'misc', 1078 1098 'module' => 'msoffice', … … 1115 1135 1116 1136 1117 if (preg_match('#\ .mp[123a]$#i', $filename)) {1137 if (preg_match('#\\.mp[123a]$#i', $filename)) { 1118 1138 // Too many mp3 encoders on the market put gabage in front of mpeg files 1119 1139 // use assume format on these if format detection failed … … 1122 1142 $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php'; 1123 1143 return $info; 1124 } elseif (preg_match(' /\.cue$/i', $filename) && preg_match('#FILE "[^"]+" (BINARY|MOTOROLA|AIFF|WAVE|MP3)#', $filedata)) {1144 } elseif (preg_match('#\\.cue$#i', $filename) && preg_match('#FILE "[^"]+" (BINARY|MOTOROLA|AIFF|WAVE|MP3)#', $filedata)) { 1125 1145 // there's not really a useful consistent "magic" at the beginning of .cue files to identify them 1126 1146 // so until I think of something better, just go by filename if all other format checks fail … … 1223 1243 } 1224 1244 1245 $this->CharConvert($this->info['tags'][$tag_name], $this->info[$comment_name]['encoding']); // only copy gets converted! 1246 1225 1247 if ($this->option_tags_html) { 1226 1248 foreach ($this->info['tags'][$tag_name] as $tag_key => $valuearray) { 1227 $this->info['tags_html'][$tag_name][$tag_key] = getid3_lib::recursiveMultiByteCharString2HTML($valuearray, $ encoding);1249 $this->info['tags_html'][$tag_name][$tag_key] = getid3_lib::recursiveMultiByteCharString2HTML($valuearray, $this->info[$comment_name]['encoding']); 1228 1250 } 1229 1251 } 1230 1252 1231 $this->CharConvert($this->info['tags'][$tag_name], $encoding); // only copy gets converted!1232 1253 } 1233 1254 … … 1353 1374 if (!empty($VorbisCommentError)) { 1354 1375 1355 $this-> info['warning'][] = 'Failed making system call to vorbiscomment(.exe) - '.$algorithm.'_data will be incorrect. If vorbiscomment is unavailable, please download from http://www.vorbis.com/download.psp and put in the getID3() directory. Error returned: '.$VorbisCommentError;1356 $this->info[$algorithm.'_data'] = false;1376 $this->warning('Failed making system call to vorbiscomment(.exe) - '.$algorithm.'_data will be incorrect. If vorbiscomment is unavailable, please download from http://www.vorbis.com/download.psp and put in the getID3() directory. Error returned: '.$VorbisCommentError); 1377 $this->info[$algorithm.'_data'] = false; 1357 1378 1358 1379 } else { … … 1583 1604 } 1584 1605 1606 public static function is_writable ($filename) { 1607 $ret = is_writable($filename); 1608 1609 if (!$ret) { 1610 $perms = fileperms($filename); 1611 $ret = ($perms & 0x0080) || ($perms & 0x0010) || ($perms & 0x0002); 1612 } 1613 1614 return $ret; 1615 } 1616 1585 1617 } 1586 1618 … … 1662 1694 throw new getid3_exception('cannot fread('.$bytes.' from '.$this->ftell().') because beyond PHP filesystem limit', 10); 1663 1695 } 1664 return fread($this->getid3->fp, $bytes); 1696 1697 //return fread($this->getid3->fp, $bytes); 1698 /* 1699 * http://www.getid3.org/phpBB3/viewtopic.php?t=1930 1700 * "I found out that the root cause for the problem was how getID3 uses the PHP system function fread(). 1701 * It seems to assume that fread() would always return as many bytes as were requested. 1702 * However, according the PHP manual (http://php.net/manual/en/function.fread.php), this is the case only with regular local files, but not e.g. with Linux pipes. 1703 * The call may return only part of the requested data and a new call is needed to get more." 1704 */ 1705 $contents = ''; 1706 do { 1707 $part = fread($this->getid3->fp, $bytes); 1708 $partLength = strlen($part); 1709 $bytes -= $partLength; 1710 $contents .= $part; 1711 } while (($bytes > 0) && ($partLength > 0)); 1712 return $contents; 1665 1713 } 1666 1714 … … 1742 1790 // set up destination path 1743 1791 $dir = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->getid3->option_save_attachments), DIRECTORY_SEPARATOR); 1744 if (!is_dir($dir) || ! is_writable($dir)) { // check supplied directory1792 if (!is_dir($dir) || !getID3::is_writable($dir)) { // check supplied directory 1745 1793 throw new Exception('supplied path ('.$dir.') does not exist, or is not writable'); 1746 1794 } -
trunk/src/wp-includes/ID3/module.audio-video.asf.php
r32979 r41196 267 267 $thisfile_asf_headerextensionobject['reserved_1_guid'] = $this->BytestringToGUID($thisfile_asf_headerextensionobject['reserved_1']); 268 268 if ($thisfile_asf_headerextensionobject['reserved_1'] != GETID3_ASF_Reserved_1) { 269 $ info['warning'][] = 'header_extension_object.reserved_1 GUID ('.$this->BytestringToGUID($thisfile_asf_headerextensionobject['reserved_1']).') does not match expected "GETID3_ASF_Reserved_1" GUID ('.$this->BytestringToGUID(GETID3_ASF_Reserved_1).')';269 $this->warning('header_extension_object.reserved_1 GUID ('.$this->BytestringToGUID($thisfile_asf_headerextensionobject['reserved_1']).') does not match expected "GETID3_ASF_Reserved_1" GUID ('.$this->BytestringToGUID(GETID3_ASF_Reserved_1).')'); 270 270 //return false; 271 271 break; … … 274 274 $offset += 2; 275 275 if ($thisfile_asf_headerextensionobject['reserved_2'] != 6) { 276 $ info['warning'][] = 'header_extension_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_headerextensionobject['reserved_2']).') does not match expected value of "6"';276 $this->warning('header_extension_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_headerextensionobject['reserved_2']).') does not match expected value of "6"'); 277 277 //return false; 278 278 break; … … 317 317 $thisfile_asf_codeclistobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_codeclistobject['reserved']); 318 318 if ($thisfile_asf_codeclistobject['reserved'] != $this->GUIDtoBytestring('86D15241-311D-11D0-A3A4-00A0C90348F6')) { 319 $ info['warning'][] = 'codec_list_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_codeclistobject['reserved']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {86D15241-311D-11D0-A3A4-00A0C90348F6}';319 $this->warning('codec_list_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_codeclistobject['reserved']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {86D15241-311D-11D0-A3A4-00A0C90348F6}'); 320 320 //return false; 321 321 break; … … 350 350 351 351 if (strpos($thisfile_asf_codeclistobject_codecentries_current['description'], ',') === false) { 352 $ info['warning'][] = '[asf][codec_list_object][codec_entries]['.$CodecEntryCounter.'][description] expected to contain comma-seperated list of parameters: "'.$thisfile_asf_codeclistobject_codecentries_current['description'].'"';352 $this->warning('[asf][codec_list_object][codec_entries]['.$CodecEntryCounter.'][description] expected to contain comma-separated list of parameters: "'.$thisfile_asf_codeclistobject_codecentries_current['description'].'"'); 353 353 } else { 354 354 … … 413 413 414 414 default: 415 $ info['warning'][] = 'unknown frequency: "'.$AudioCodecFrequency.'" ('.$this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['description']).')';415 $this->warning('unknown frequency: "'.$AudioCodecFrequency.'" ('.$this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['description']).')'); 416 416 break; 417 417 } … … 459 459 $thisfile_asf_scriptcommandobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_scriptcommandobject['reserved']); 460 460 if ($thisfile_asf_scriptcommandobject['reserved'] != $this->GUIDtoBytestring('4B1ACBE3-100B-11D0-A39B-00A0C90348F6')) { 461 $ info['warning'][] = 'script_command_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_scriptcommandobject['reserved']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {4B1ACBE3-100B-11D0-A39B-00A0C90348F6}';461 $this->warning('script_command_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_scriptcommandobject['reserved']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {4B1ACBE3-100B-11D0-A39B-00A0C90348F6}'); 462 462 //return false; 463 463 break; … … 518 518 $thisfile_asf_markerobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_markerobject['reserved']); 519 519 if ($thisfile_asf_markerobject['reserved'] != $this->GUIDtoBytestring('4CFEDB20-75F6-11CF-9C0F-00A0C90349CB')) { 520 $ info['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}';520 $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}'); 521 521 break; 522 522 } … … 526 526 $offset += 2; 527 527 if ($thisfile_asf_markerobject['reserved_2'] != 0) { 528 $ info['warning'][] = 'marker_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_markerobject['reserved_2']).') does not match expected value of "0"';528 $this->warning('marker_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_markerobject['reserved_2']).') does not match expected value of "0"'); 529 529 break; 530 530 } … … 577 577 $offset += 16; 578 578 if (($thisfile_asf_bitratemutualexclusionobject['reserved'] != GETID3_ASF_Mutex_Bitrate) && ($thisfile_asf_bitratemutualexclusionobject['reserved'] != GETID3_ASF_Mutex_Unknown)) { 579 $ info['warning'][] = 'bitrate_mutual_exclusion_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_bitratemutualexclusionobject['reserved']).'} does not match expected "GETID3_ASF_Mutex_Bitrate" GUID {'.$this->BytestringToGUID(GETID3_ASF_Mutex_Bitrate).'} or "GETID3_ASF_Mutex_Unknown" GUID {'.$this->BytestringToGUID(GETID3_ASF_Mutex_Unknown).'}';579 $this->warning('bitrate_mutual_exclusion_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_bitratemutualexclusionobject['reserved']).'} does not match expected "GETID3_ASF_Mutex_Bitrate" GUID {'.$this->BytestringToGUID(GETID3_ASF_Mutex_Bitrate).'} or "GETID3_ASF_Mutex_Unknown" GUID {'.$this->BytestringToGUID(GETID3_ASF_Mutex_Unknown).'}'); 580 580 //return false; 581 581 break; … … 638 638 639 639 default: 640 $ info['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).'}';640 $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).'}'); 641 641 //return false; 642 642 break; … … 762 762 763 763 default: 764 $ info['warning'][] = 'extended_content_description.content_descriptors.'.$ExtendedContentDescriptorsCounter.'.value_type is invalid ('.$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type'].')';764 $this->warning('extended_content_description.content_descriptors.'.$ExtendedContentDescriptorsCounter.'.value_type is invalid ('.$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type'].')'); 765 765 //return false; 766 766 break; … … 963 963 // Implementations shall ignore any standard or non-standard object that they do not know how to handle. 964 964 if ($this->GUIDname($NextObjectGUIDtext)) { 965 $ info['warning'][] = 'unhandled GUID "'.$this->GUIDname($NextObjectGUIDtext).'" {'.$NextObjectGUIDtext.'} in ASF header at offset '.($offset - 16 - 8);965 $this->warning('unhandled GUID "'.$this->GUIDname($NextObjectGUIDtext).'" {'.$NextObjectGUIDtext.'} in ASF header at offset '.($offset - 16 - 8)); 966 966 } else { 967 $ info['warning'][] = 'unknown GUID {'.$NextObjectGUIDtext.'} in ASF header at offset '.($offset - 16 - 8);967 $this->warning('unknown GUID {'.$NextObjectGUIDtext.'} in ASF header at offset '.($offset - 16 - 8)); 968 968 } 969 969 $offset += ($NextObjectSize - 16 - 8); … … 1184 1184 $offset += 2; 1185 1185 if ($thisfile_asf_dataobject['reserved'] != 0x0101) { 1186 $ info['warning'][] = 'data_object.reserved ('.getid3_lib::PrintHexBytes($thisfile_asf_dataobject['reserved']).') does not match expected value of "0x0101"';1186 $this->warning('data_object.reserved ('.getid3_lib::PrintHexBytes($thisfile_asf_dataobject['reserved']).') does not match expected value of "0x0101"'); 1187 1187 //return false; 1188 1188 break; … … 1320 1320 // Implementations shall ignore any standard or non-standard object that they do not know how to handle. 1321 1321 if ($this->GUIDname($NextObjectGUIDtext)) { 1322 $ info['warning'][] = 'unhandled GUID "'.$this->GUIDname($NextObjectGUIDtext).'" {'.$NextObjectGUIDtext.'} in ASF body at offset '.($offset - 16 - 8);1322 $this->warning('unhandled GUID "'.$this->GUIDname($NextObjectGUIDtext).'" {'.$NextObjectGUIDtext.'} in ASF body at offset '.($offset - 16 - 8)); 1323 1323 } else { 1324 $ info['warning'][] = 'unknown GUID {'.$NextObjectGUIDtext.'} in ASF body at offset '.($this->ftell() - 16 - 8);1324 $this->warning('unknown GUID {'.$NextObjectGUIDtext.'} in ASF body at offset '.($this->ftell() - 16 - 8)); 1325 1325 } 1326 1326 $this->fseek(($NextObjectSize - 16 - 8), SEEK_CUR); … … 1406 1406 1407 1407 default: 1408 $ info['warning'][] = 'Unknown streamtype: [codec_list_object][codec_entries]['.$streamnumber.'][type_raw] == '.$streamdata['type_raw'];1408 $this->warning('Unknown streamtype: [codec_list_object][codec_entries]['.$streamnumber.'][type_raw] == '.$streamdata['type_raw']); 1409 1409 break; 1410 1410 … … 1918 1918 $unhandled_sections++; 1919 1919 if ($this->GUIDname($thisObject['guid_text'])) { 1920 $this-> getid3->info['warning'][] = 'unhandled Header Extension Object GUID "'.$this->GUIDname($thisObject['guid_text']).'" {'.$thisObject['guid_text'].'} at offset '.($offset - 16 - 8);1920 $this->warning('unhandled Header Extension Object GUID "'.$this->GUIDname($thisObject['guid_text']).'" {'.$thisObject['guid_text'].'} at offset '.($offset - 16 - 8)); 1921 1921 } else { 1922 $this-> getid3->info['warning'][] = 'unknown Header Extension Object GUID {'.$thisObject['guid_text'].'} in at offset '.($offset - 16 - 8);1922 $this->warning('unknown Header Extension Object GUID {'.$thisObject['guid_text'].'} in at offset '.($offset - 16 - 8)); 1923 1923 } 1924 1924 break; -
trunk/src/wp-includes/ID3/module.audio-video.flv.php
r32979 r41196 94 94 95 95 if ($info['flv']['header']['signature'] != self::magic) { 96 $ info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes(self::magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['flv']['header']['signature']).'"';96 $this->error('Expecting "'.getid3_lib::PrintHexBytes(self::magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['flv']['header']['signature']).'"'); 97 97 unset($info['flv'], $info['fileformat']); 98 98 return false; … … 542 542 default: 543 543 $value = '(unknown or unsupported data type)'; 544 break;544 break; 545 545 } 546 546 -
trunk/src/wp-includes/ID3/module.audio-video.matroska.php
r32979 r41196 235 235 $this->parseEBML($info); 236 236 } catch (Exception $e) { 237 $ info['error'][] = 'EBML parser: '.$e->getMessage();237 $this->error('EBML parser: '.$e->getMessage()); 238 238 } 239 239 … … 331 331 332 332 case 'A_AC3': 333 case 'A_EAC3': 333 334 case 'A_DTS': 334 335 case 'A_MPEG/L3': 335 336 case 'A_MPEG/L2': 336 337 case 'A_FLAC': 337 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.'.($track_info['dataformat'] == 'mp2' ? 'mp3' : $track_info['dataformat']).'.php', __FILE__, true); 338 $module_dataformat = ($track_info['dataformat'] == 'mp2' ? 'mp3' : ($track_info['dataformat'] == 'eac3' ? 'ac3' : $track_info['dataformat'])); 339 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.'.$module_dataformat.'.php', __FILE__, true); 338 340 339 341 if (!isset($info['matroska']['track_data_offsets'][$trackarray['TrackNumber']])) { … … 353 355 354 356 // analyze 355 $class = 'getid3_'. ($track_info['dataformat'] == 'mp2' ? 'mp3' : $track_info['dataformat']);357 $class = 'getid3_'.$module_dataformat; 356 358 $header_data_key = $track_info['dataformat'][0] == 'm' ? 'mpeg' : $track_info['dataformat']; 357 359 $getid3_audio = new $class($getid3_temp, __CLASS__); … … 458 460 default: 459 461 $this->warning('Unhandled audio type "'.(isset($trackarray['CodecID']) ? $trackarray['CodecID'] : '').'"'); 462 break; 460 463 } 461 464 … … 525 528 default: 526 529 $this->unhandledElement('header', __LINE__, $element_data); 530 break; 527 531 } 528 532 … … 563 567 default: 564 568 $this->unhandledElement('seekhead.seek', __LINE__, $sub_seek_entry); } 569 break; 565 570 } 566 567 if ($seek_entry['target_id'] != EBML_ID_CLUSTER || !self::$hide_clusters) { // collect clusters only if required 571 if (!isset($seek_entry['target_id'])) { 572 $this->warning('seek_entry[target_id] unexpectedly not set at '.$seek_entry['offset']); 573 break; 574 } 575 if (($seek_entry['target_id'] != EBML_ID_CLUSTER) || !self::$hide_clusters) { // collect clusters only if required 568 576 $info['matroska']['seek'][] = $seek_entry; 569 577 } … … 572 580 default: 573 581 $this->unhandledElement('seekhead', __LINE__, $seek_entry); 582 break; 574 583 } 575 584 } … … 654 663 default: 655 664 $this->unhandledElement('track.video', __LINE__, $sub_subelement); 665 break; 656 666 } 657 667 } … … 679 689 default: 680 690 $this->unhandledElement('track.audio', __LINE__, $sub_subelement); 691 break; 681 692 } 682 693 } … … 714 725 default: 715 726 $this->unhandledElement('track.contentencodings.contentencoding.contentcompression', __LINE__, $sub_sub_sub_subelement); 727 break; 716 728 } 717 729 } … … 737 749 default: 738 750 $this->unhandledElement('track.contentencodings.contentencoding.contentcompression', __LINE__, $sub_sub_sub_subelement); 751 break; 739 752 } 740 753 } … … 743 756 default: 744 757 $this->unhandledElement('track.contentencodings.contentencoding', __LINE__, $sub_sub_subelement); 758 break; 745 759 } 746 760 } … … 749 763 default: 750 764 $this->unhandledElement('track.contentencodings', __LINE__, $sub_subelement); 765 break; 751 766 } 752 767 } … … 755 770 default: 756 771 $this->unhandledElement('track', __LINE__, $subelement); 772 break; 757 773 } 758 774 } … … 763 779 default: 764 780 $this->unhandledElement('tracks', __LINE__, $track_entry); 781 break; 765 782 } 766 783 } … … 826 843 default: 827 844 $this->unhandledElement('info.chaptertranslate', __LINE__, $sub_subelement); 845 break; 828 846 } 829 847 } … … 833 851 default: 834 852 $this->unhandledElement('info', __LINE__, $subelement); 853 break; 835 854 } 836 855 } … … 869 888 default: 870 889 $this->unhandledElement('cues.cuepoint.cuetrackpositions', __LINE__, $sub_sub_subelement); 890 break; 871 891 } 872 892 } … … 880 900 default: 881 901 $this->unhandledElement('cues.cuepoint', __LINE__, $sub_subelement); 902 break; 882 903 } 883 904 } … … 887 908 default: 888 909 $this->unhandledElement('cues', __LINE__, $subelement); 910 break; 889 911 } 890 912 } … … 928 950 default: 929 951 $this->unhandledElement('tags.tag.targets', __LINE__, $sub_sub_subelement); 952 break; 930 953 } 931 954 } … … 939 962 default: 940 963 $this->unhandledElement('tags.tag', __LINE__, $sub_subelement); 964 break; 941 965 } 942 966 } … … 946 970 default: 947 971 $this->unhandledElement('tags', __LINE__, $subelement); 972 break; 948 973 } 949 974 } … … 986 1011 default: 987 1012 $this->unhandledElement('attachments.attachedfile', __LINE__, $sub_subelement); 1013 break; 988 1014 } 989 1015 } … … 993 1019 default: 994 1020 $this->unhandledElement('attachments', __LINE__, $subelement); 1021 break; 995 1022 } 996 1023 } … … 1052 1079 default: 1053 1080 $this->unhandledElement('chapters.editionentry.chapteratom.chaptertrack', __LINE__, $sub_sub_sub_subelement); 1081 break; 1054 1082 } 1055 1083 } … … 1071 1099 default: 1072 1100 $this->unhandledElement('chapters.editionentry.chapteratom.chapterdisplay', __LINE__, $sub_sub_sub_subelement); 1101 break; 1073 1102 } 1074 1103 } … … 1078 1107 default: 1079 1108 $this->unhandledElement('chapters.editionentry.chapteratom', __LINE__, $sub_sub_subelement); 1109 break; 1080 1110 } 1081 1111 } … … 1085 1115 default: 1086 1116 $this->unhandledElement('chapters.editionentry', __LINE__, $sub_subelement); 1117 break; 1087 1118 } 1088 1119 } … … 1092 1123 default: 1093 1124 $this->unhandledElement('chapters', __LINE__, $subelement); 1125 break; 1094 1126 } 1095 1127 } … … 1120 1152 default: 1121 1153 $this->unhandledElement('cluster.silenttracks', __LINE__, $sub_subelement); 1154 break; 1122 1155 } 1123 1156 } … … 1150 1183 default: 1151 1184 $this->unhandledElement('clusters.blockgroup', __LINE__, $sub_subelement); 1185 break; 1152 1186 } 1153 1187 } … … 1161 1195 default: 1162 1196 $this->unhandledElement('cluster', __LINE__, $subelement); 1197 break; 1163 1198 } 1164 1199 $this->current_offset = $subelement['end']; … … 1182 1217 default: 1183 1218 $this->unhandledElement('segment', __LINE__, $element_data); 1219 break; 1184 1220 } 1185 1221 } … … 1188 1224 default: 1189 1225 $this->unhandledElement('root', __LINE__, $top_element); 1226 break; 1190 1227 } 1191 1228 } … … 1340 1377 default: 1341 1378 $this->unhandledElement('tag.simpletag', __LINE__, $element); 1379 break; 1342 1380 } 1343 1381 } … … 1491 1529 $CodecIDlist['A_AAC/MPEG2/LC'] = 'aac'; 1492 1530 $CodecIDlist['A_AC3'] = 'ac3'; 1531 $CodecIDlist['A_EAC3'] = 'eac3'; 1493 1532 $CodecIDlist['A_DTS'] = 'dts'; 1494 1533 $CodecIDlist['A_FLAC'] = 'flac'; -
trunk/src/wp-includes/ID3/module.audio-video.quicktime.php
r32979 r41196 36 36 $offset = 0; 37 37 $atomcounter = 0; 38 $atom_data_read_buffer_size = ($info['php_memory_limit'] ? round($info['php_memory_limit'] / 2) : $this->getid3->option_fread_buffer_size * 1024); // allow [default: 32MB] if PHP configured with no memory_limit38 $atom_data_read_buffer_size = max($this->getid3->option_fread_buffer_size * 1024, ($info['php_memory_limit'] ? round($info['php_memory_limit'] / 4) : 1024)); // set read buffer to 25% of PHP memory limit (if one is specified), otherwise use option_fread_buffer_size [default: 32MB] 39 39 while ($offset < $info['avdataend']) { 40 40 if (!getid3_lib::intValueSupported($offset)) { 41 $ info['error'][] = 'Unable to parse atom at offset '.$offset.' because beyond '.round(PHP_INT_MAX / 1073741824).'GB limit of PHP filesystem functions';41 $this->error('Unable to parse atom at offset '.$offset.' because beyond '.round(PHP_INT_MAX / 1073741824).'GB limit of PHP filesystem functions'); 42 42 break; 43 43 } … … 58 58 59 59 if (($offset + $atomsize) > $info['avdataend']) { 60 $ info['error'][] = 'Atom at offset '.$offset.' claims to go beyond end-of-file (length: '.$atomsize.' bytes)';60 $this->error('Atom at offset '.$offset.' claims to go beyond end-of-file (length: '.$atomsize.' bytes)'); 61 61 return false; 62 62 } … … 80 80 $info['avdataend'] = $info['avdataend_tmp']; 81 81 unset($info['avdataend_tmp']); 82 } 83 84 if (!empty($info['quicktime']['comments']['chapters']) && is_array($info['quicktime']['comments']['chapters']) && (count($info['quicktime']['comments']['chapters']) > 0)) { 85 $durations = $this->quicktime_time_to_sample_table($info); 86 for ($i = 0; $i < count($info['quicktime']['comments']['chapters']); $i++) { 87 $bookmark = array(); 88 $bookmark['title'] = $info['quicktime']['comments']['chapters'][$i]; 89 if (isset($durations[$i])) { 90 $bookmark['duration_sample'] = $durations[$i]['sample_duration']; 91 if ($i > 0) { 92 $bookmark['start_sample'] = $info['quicktime']['bookmarks'][($i - 1)]['start_sample'] + $info['quicktime']['bookmarks'][($i - 1)]['duration_sample']; 93 } else { 94 $bookmark['start_sample'] = 0; 95 } 96 if ($time_scale = $this->quicktime_bookmark_time_scale($info)) { 97 $bookmark['duration_seconds'] = $bookmark['duration_sample'] / $time_scale; 98 $bookmark['start_seconds'] = $bookmark['start_sample'] / $time_scale; 99 } 100 } 101 $info['quicktime']['bookmarks'][] = $bookmark; 102 } 103 } 104 105 if (isset($info['quicktime']['temp_meta_key_names'])) { 106 unset($info['quicktime']['temp_meta_key_names']); 107 } 108 109 if (!empty($info['quicktime']['comments']['location.ISO6709'])) { 110 // https://en.wikipedia.org/wiki/ISO_6709 111 foreach ($info['quicktime']['comments']['location.ISO6709'] as $ISO6709string) { 112 $latitude = false; 113 $longitude = false; 114 $altitude = false; 115 if (preg_match('#^([\\+\\-])([0-9]{2}|[0-9]{4}|[0-9]{6})(\\.[0-9]+)?([\\+\\-])([0-9]{3}|[0-9]{5}|[0-9]{7})(\\.[0-9]+)?(([\\+\\-])([0-9]{3}|[0-9]{5}|[0-9]{7})(\\.[0-9]+)?)?/$#', $ISO6709string, $matches)) { 116 @list($dummy, $lat_sign, $lat_deg, $lat_deg_dec, $lon_sign, $lon_deg, $lon_deg_dec, $dummy, $alt_sign, $alt_deg, $alt_deg_dec) = $matches; 117 118 if (strlen($lat_deg) == 2) { // [+-]DD.D 119 $latitude = floatval(ltrim($lat_deg, '0').$lat_deg_dec); 120 } elseif (strlen($lat_deg) == 4) { // [+-]DDMM.M 121 $latitude = floatval(ltrim(substr($lat_deg, 0, 2), '0')) + floatval(ltrim(substr($lat_deg, 2, 2), '0').$lat_deg_dec / 60); 122 } elseif (strlen($lat_deg) == 6) { // [+-]DDMMSS.S 123 $latitude = 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); 124 } 125 126 if (strlen($lon_deg) == 3) { // [+-]DDD.D 127 $longitude = floatval(ltrim($lon_deg, '0').$lon_deg_dec); 128 } elseif (strlen($lon_deg) == 5) { // [+-]DDDMM.M 129 $longitude = floatval(ltrim(substr($lon_deg, 0, 2), '0')) + floatval(ltrim(substr($lon_deg, 2, 2), '0').$lon_deg_dec / 60); 130 } elseif (strlen($lon_deg) == 7) { // [+-]DDDMMSS.S 131 $longitude = 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); 132 } 133 134 if (strlen($alt_deg) == 3) { // [+-]DDD.D 135 $altitude = floatval(ltrim($alt_deg, '0').$alt_deg_dec); 136 } elseif (strlen($alt_deg) == 5) { // [+-]DDDMM.M 137 $altitude = floatval(ltrim(substr($alt_deg, 0, 2), '0')) + floatval(ltrim(substr($alt_deg, 2, 2), '0').$alt_deg_dec / 60); 138 } elseif (strlen($alt_deg) == 7) { // [+-]DDDMMSS.S 139 $altitude = 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); 140 } 141 142 if ($latitude !== false) { 143 $info['quicktime']['comments']['gps_latitude'][] = (($lat_sign == '-') ? -1 : 1) * floatval($latitude); 144 } 145 if ($longitude !== false) { 146 $info['quicktime']['comments']['gps_longitude'][] = (($lon_sign == '-') ? -1 : 1) * floatval($longitude); 147 } 148 if ($altitude !== false) { 149 $info['quicktime']['comments']['gps_altitude'][] = (($alt_sign == '-') ? -1 : 1) * floatval($altitude); 150 } 151 } 152 if ($latitude === false) { 153 $this->warning('location.ISO6709 string not parsed correctly: "'.$ISO6709string.'", please submit as a bug'); 154 } 155 break; 156 } 82 157 } 83 158 … … 99 174 } 100 175 } 101 if ( ($info['audio']['dataformat'] == 'mp4') && empty($info['video']['resolution_x'])) {176 if ($info['audio']['dataformat'] == 'mp4') { 102 177 $info['fileformat'] = 'mp4'; 103 $info['mime_type'] = 'audio/mp4'; 104 unset($info['video']['dataformat']); 178 if (empty($info['video']['resolution_x'])) { 179 $info['mime_type'] = 'audio/mp4'; 180 unset($info['video']['dataformat']); 181 } else { 182 $info['mime_type'] = 'video/mp4'; 183 } 105 184 } 106 185 … … 121 200 public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) { 122 201 // http://developer.apple.com/techpubs/quicktime/qtdevdocs/APIREF/INDEX/atomalphaindex.htm 202 // https://code.google.com/p/mp4v2/wiki/iTunesMetadata 123 203 124 204 $info = &$this->getid3->info; … … 223 303 224 304 305 case "\xA9".'alb': // ALBum 306 case "\xA9".'ART': // 307 case "\xA9".'art': // ARTist 308 case "\xA9".'aut': // 309 case "\xA9".'cmt': // CoMmenT 310 case "\xA9".'com': // COMposer 311 case "\xA9".'cpy': // 312 case "\xA9".'day': // content created year 313 case "\xA9".'dir': // 314 case "\xA9".'ed1': // 315 case "\xA9".'ed2': // 316 case "\xA9".'ed3': // 317 case "\xA9".'ed4': // 318 case "\xA9".'ed5': // 319 case "\xA9".'ed6': // 320 case "\xA9".'ed7': // 321 case "\xA9".'ed8': // 322 case "\xA9".'ed9': // 323 case "\xA9".'enc': // 324 case "\xA9".'fmt': // 325 case "\xA9".'gen': // GENre 326 case "\xA9".'grp': // GRouPing 327 case "\xA9".'hst': // 328 case "\xA9".'inf': // 329 case "\xA9".'lyr': // LYRics 330 case "\xA9".'mak': // 331 case "\xA9".'mod': // 332 case "\xA9".'nam': // full NAMe 333 case "\xA9".'ope': // 334 case "\xA9".'PRD': // 335 case "\xA9".'prf': // 336 case "\xA9".'req': // 337 case "\xA9".'src': // 338 case "\xA9".'swr': // 339 case "\xA9".'too': // encoder 340 case "\xA9".'trk': // TRacK 341 case "\xA9".'url': // 342 case "\xA9".'wrn': // 343 case "\xA9".'wrt': // WRiTer 344 case '----': // itunes specific 225 345 case 'aART': // Album ARTist 346 case 'akID': // iTunes store account type 347 case 'apID': // Purchase Account 348 case 'atID': // 226 349 case 'catg': // CaTeGory 350 case 'cmID': // 351 case 'cnID': // 227 352 case 'covr': // COVeR artwork 228 353 case 'cpil': // ComPILation … … 231 356 case 'disk': // DISK number 232 357 case 'egid': // Episode Global ID 358 case 'geID': // 233 359 case 'gnre': // GeNRE 360 case 'hdvd': // HD ViDeo 234 361 case 'keyw': // KEYWord 235 case 'ldes': 362 case 'ldes': // Long DEScription 236 363 case 'pcst': // PodCaST 237 364 case 'pgap': // GAPless Playback 365 case 'plID': // 238 366 case 'purd': // PURchase Date 239 367 case 'purl': // Podcast URL 240 case 'rati': 241 case 'rndu': 242 case 'rpdu': 368 case 'rati': // 369 case 'rndu': // 370 case 'rpdu': // 243 371 case 'rtng': // RaTiNG 244 case 'stik': 372 case 'sfID': // iTunes store country 373 case 'soaa': // SOrt Album Artist 374 case 'soal': // SOrt ALbum 375 case 'soar': // SOrt ARtist 376 case 'soco': // SOrt COmposer 377 case 'sonm': // SOrt NaMe 378 case 'sosn': // SOrt Show Name 379 case 'stik': // 245 380 case 'tmpo': // TeMPO (BPM) 246 381 case 'trkn': // TRacK Number 382 case 'tven': // tvEpisodeID 247 383 case 'tves': // TV EpiSode 248 384 case 'tvnn': // TV Network Name 249 385 case 'tvsh': // TV SHow Name 250 386 case 'tvsn': // TV SeasoN 251 case 'akID': // iTunes store account type252 case 'apID':253 case 'atID':254 case 'cmID':255 case 'cnID':256 case 'geID':257 case 'plID':258 case 'sfID': // iTunes store country259 case "\xA9".'alb': // ALBum260 case "\xA9".'art': // ARTist261 case "\xA9".'ART':262 case "\xA9".'aut':263 case "\xA9".'cmt': // CoMmenT264 case "\xA9".'com': // COMposer265 case "\xA9".'cpy':266 case "\xA9".'day': // content created year267 case "\xA9".'dir':268 case "\xA9".'ed1':269 case "\xA9".'ed2':270 case "\xA9".'ed3':271 case "\xA9".'ed4':272 case "\xA9".'ed5':273 case "\xA9".'ed6':274 case "\xA9".'ed7':275 case "\xA9".'ed8':276 case "\xA9".'ed9':277 case "\xA9".'enc':278 case "\xA9".'fmt':279 case "\xA9".'gen': // GENre280 case "\xA9".'grp': // GRouPing281 case "\xA9".'hst':282 case "\xA9".'inf':283 case "\xA9".'lyr': // LYRics284 case "\xA9".'mak':285 case "\xA9".'mod':286 case "\xA9".'nam': // full NAMe287 case "\xA9".'ope':288 case "\xA9".'PRD':289 case "\xA9".'prd':290 case "\xA9".'prf':291 case "\xA9".'req':292 case "\xA9".'src':293 case "\xA9".'swr':294 case "\xA9".'too': // encoder295 case "\xA9".'trk': // TRacK296 case "\xA9".'url':297 case "\xA9".'wrn':298 case "\xA9".'wrt': // WRiTer299 case '----': // itunes specific300 387 if ($atom_parent == 'udta') { 301 388 // User data atom handler … … 319 406 $boxsmalldata = substr($atom_data, $atomoffset + 4, $boxsmallsize); 320 407 if ($boxsmallsize <= 1) { 321 $ info['warning'][] = 'Invalid QuickTime atom smallbox size "'.$boxsmallsize.'" in atom "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" at offset: '.($atom_structure['offset'] + $atomoffset);408 $this->warning('Invalid QuickTime atom smallbox size "'.$boxsmallsize.'" in atom "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" at offset: '.($atom_structure['offset'] + $atomoffset)); 322 409 $atom_structure['data'] = null; 323 410 $atomoffset = strlen($atom_data); … … 329 416 break; 330 417 default: 331 $ info['warning'][] = 'Unknown QuickTime smallbox type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $boxsmalltype).'" ('.trim(getid3_lib::PrintHexBytes($boxsmalltype)).') at offset '.$baseoffset;418 $this->warning('Unknown QuickTime smallbox type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $boxsmalltype).'" ('.trim(getid3_lib::PrintHexBytes($boxsmalltype)).') at offset '.$baseoffset); 332 419 $atom_structure['data'] = $atom_data; 333 420 break; … … 341 428 $boxdata = substr($atom_data, $atomoffset + 8, $boxsize - 8); 342 429 if ($boxsize <= 1) { 343 $ info['warning'][] = 'Invalid QuickTime atom box size "'.$boxsize.'" in atom "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" at offset: '.($atom_structure['offset'] + $atomoffset);430 $this->warning('Invalid QuickTime atom box size "'.$boxsize.'" in atom "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" at offset: '.($atom_structure['offset'] + $atomoffset)); 344 431 $atom_structure['data'] = null; 345 432 $atomoffset = strlen($atom_data); … … 362 449 switch ($atomname) { 363 450 case 'cpil': 451 case 'hdvd': 364 452 case 'pcst': 365 453 case 'pgap': 454 // 8-bit integer (boolean) 366 455 $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1)); 367 456 break; 368 457 369 458 case 'tmpo': 459 // 16-bit integer 370 460 $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 2)); 371 461 break; … … 373 463 case 'disk': 374 464 case 'trkn': 465 // binary 375 466 $num = getid3_lib::BigEndian2Int(substr($boxdata, 10, 2)); 376 467 $num_total = getid3_lib::BigEndian2Int(substr($boxdata, 12, 2)); … … 380 471 381 472 case 'gnre': 473 // enum 382 474 $GenreID = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4)); 383 475 $atom_structure['data'] = getid3_id3v1::LookupGenreName($GenreID - 1); … … 385 477 386 478 case 'rtng': 479 // 8-bit integer 387 480 $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1)); 388 481 $atom_structure['data'] = $this->QuicktimeContentRatingLookup($atom_structure[$atomname]); … … 390 483 391 484 case 'stik': 485 // 8-bit integer (enum) 392 486 $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1)); 393 487 $atom_structure['data'] = $this->QuicktimeSTIKLookup($atom_structure[$atomname]); … … 395 489 396 490 case 'sfID': 491 // 32-bit integer 397 492 $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4)); 398 493 $atom_structure['data'] = $this->QuicktimeStoreFrontCodeLookup($atom_structure[$atomname]); … … 404 499 break; 405 500 501 case 'plID': 502 // 64-bit integer 503 $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 8)); 504 break; 505 506 case 'covr': 507 $atom_structure['data'] = substr($boxdata, 8); 508 // not a foolproof check, but better than nothing 509 if (preg_match('#^\\xFF\\xD8\\xFF#', $atom_structure['data'])) { 510 $atom_structure['image_mime'] = 'image/jpeg'; 511 } elseif (preg_match('#^\\x89\\x50\\x4E\\x47\\x0D\\x0A\\x1A\\x0A#', $atom_structure['data'])) { 512 $atom_structure['image_mime'] = 'image/png'; 513 } elseif (preg_match('#^GIF#', $atom_structure['data'])) { 514 $atom_structure['image_mime'] = 'image/gif'; 515 } 516 break; 517 518 case 'atID': 519 case 'cnID': 520 case 'geID': 521 case 'tves': 522 case 'tvsn': 406 523 default: 524 // 32-bit integer 407 525 $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4)); 408 526 } … … 415 533 if ($atomname == 'covr') { 416 534 // not a foolproof check, but better than nothing 417 if (preg_match('#^\ xFF\xD8\xFF#', $atom_structure['data'])) {535 if (preg_match('#^\\xFF\\xD8\\xFF#', $atom_structure['data'])) { 418 536 $atom_structure['image_mime'] = 'image/jpeg'; 419 } elseif (preg_match('#^\ x89\x50\x4E\x47\x0D\x0A\x1A\x0A#', $atom_structure['data'])) {537 } elseif (preg_match('#^\\x89\\x50\\x4E\\x47\\x0D\\x0A\\x1A\\x0A#', $atom_structure['data'])) { 420 538 $atom_structure['image_mime'] = 'image/png'; 421 539 } elseif (preg_match('#^GIF#', $atom_structure['data'])) { … … 429 547 430 548 default: 431 $ info['warning'][] = 'Unknown QuickTime box type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $boxtype).'" ('.trim(getid3_lib::PrintHexBytes($boxtype)).') at offset '.$baseoffset;549 $this->warning('Unknown QuickTime box type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $boxtype).'" ('.trim(getid3_lib::PrintHexBytes($boxtype)).') at offset '.$baseoffset); 432 550 $atom_structure['data'] = $atom_data; 433 551 … … 477 595 $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($UncompressedHeader, 0, $atomHierarchy, $ParseAllPossibleAtoms); 478 596 } else { 479 $ info['warning'][] = 'Error decompressing compressed MOV atom at offset '.$atom_structure['offset'];597 $this->warning('Error decompressing compressed MOV atom at offset '.$atom_structure['offset']); 480 598 } 481 599 break; … … 596 714 $atom_structure['display_size'] = $ptv_lookup[$atom_structure['display_size_raw']]; 597 715 } else { 598 $ info['warning'][] = 'unknown "ptv " display constant ('.$atom_structure['display_size_raw'].')';716 $this->warning('unknown "ptv " display constant ('.$atom_structure['display_size_raw'].')'); 599 717 } 600 718 break; … … 605 723 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 606 724 $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); 725 726 // see: https://github.com/JamesHeinrich/getID3/issues/111 727 // Some corrupt files have been known to have high bits set in the number_entries field 728 // This field shouldn't really need to be 32-bits, values stores are likely in the range 1-100000 729 // Workaround: mask off the upper byte and throw a warning if it's nonzero 730 if ($atom_structure['number_entries'] > 0x000FFFFF) { 731 if ($atom_structure['number_entries'] > 0x00FFFFFF) { 732 $this->warning('"stsd" atom contains improbably large number_entries (0x'.getid3_lib::PrintHexBytes(substr($atom_data, 4, 4), true, false).' = '.$atom_structure['number_entries'].'), probably in error. Ignoring upper byte and interpreting this as 0x'.getid3_lib::PrintHexBytes(substr($atom_data, 5, 3), true, false).' = '.($atom_structure['number_entries'] & 0x00FFFFFF)); 733 $atom_structure['number_entries'] = ($atom_structure['number_entries'] & 0x00FFFFFF); 734 } else { 735 $this->warning('"stsd" atom contains improbably large number_entries (0x'.getid3_lib::PrintHexBytes(substr($atom_data, 4, 4), true, false).' = '.$atom_structure['number_entries'].'), probably in error. Please report this to [email protected] referencing bug report #111'); 736 } 737 } 738 607 739 $stsdEntriesDataOffset = 8; 608 740 for ($i = 0; $i < $atom_structure['number_entries']; $i++) { … … 802 934 $max_stts_entries_to_scan = ($info['php_memory_limit'] ? min(floor($this->getid3->memory_limit / 10000), $atom_structure['number_entries']) : $atom_structure['number_entries']); 803 935 if ($max_stts_entries_to_scan < $atom_structure['number_entries']) { 804 $ info['warning'][] = 'QuickTime atom "stts" has '.$atom_structure['number_entries'].' but only scanning the first '.$max_stts_entries_to_scan.' entries due to limited PHP memory available ('.floor($atom_structure['number_entries'] / 1048576).'MB).';936 $this->warning('QuickTime atom "stts" has '.$atom_structure['number_entries'].' but only scanning the first '.$max_stts_entries_to_scan.' entries due to limited PHP memory available ('.floor($atom_structure['number_entries'] / 1048576).'MB).'); 805 937 } 806 938 for ($i = 0; $i < $max_stts_entries_to_scan; $i++) { … … 929 1061 $atom_structure['data_references'][$i]['size'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 4)); 930 1062 $drefDataOffset += 4; 931 $atom_structure['data_references'][$i]['type'] = substr($atom_data, $drefDataOffset, 4);1063 $atom_structure['data_references'][$i]['type'] = substr($atom_data, $drefDataOffset, 4); 932 1064 $drefDataOffset += 4; 933 1065 $atom_structure['data_references'][$i]['version'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 1)); … … 935 1067 $atom_structure['data_references'][$i]['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 3)); // hardcoded: 0x0000 936 1068 $drefDataOffset += 3; 937 $atom_structure['data_references'][$i]['data'] = substr($atom_data, $drefDataOffset, ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3));1069 $atom_structure['data_references'][$i]['data'] = substr($atom_data, $drefDataOffset, ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3)); 938 1070 $drefDataOffset += ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3); 939 1071 … … 1002 1134 1003 1135 if ($atom_structure['time_scale'] == 0) { 1004 $ info['error'][] = 'Corrupt Quicktime file: mdhd.time_scale == zero';1136 $this->error('Corrupt Quicktime file: mdhd.time_scale == zero'); 1005 1137 return false; 1006 1138 } 1007 $info['quicktime']['time_scale'] = ( isset($info['quicktime']['time_scale']) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']);1139 $info['quicktime']['time_scale'] = ((isset($info['quicktime']['time_scale']) && ($info['quicktime']['time_scale'] < 1000)) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']); 1008 1140 1009 1141 $atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']); … … 1020 1152 $atom_structure['modification_date'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); // "standard Macintosh format" 1021 1153 $atom_structure['version_number'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x00 1022 $atom_structure['atom_type'] = substr($atom_data, 6, 4); // usually: 'PICT'1154 $atom_structure['atom_type'] = substr($atom_data, 6, 4); // usually: 'PICT' 1023 1155 $atom_structure['atom_index'] = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2)); // usually: 0x01 1024 1156 … … 1030 1162 $atom_structure['region_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2)); // The Region size, Region boundary box, 1031 1163 $atom_structure['boundary_box'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 8)); // and Clipping region data fields 1032 $atom_structure['clipping_data'] = substr($atom_data, 10); // constitute a QuickDraw region.1164 $atom_structure['clipping_data'] = substr($atom_data, 10); // constitute a QuickDraw region. 1033 1165 break; 1034 1166 … … 1116 1248 1117 1249 if ($atom_structure['time_scale'] == 0) { 1118 $ info['error'][] = 'Corrupt Quicktime file: mvhd.time_scale == zero';1250 $this->error('Corrupt Quicktime file: mvhd.time_scale == zero'); 1119 1251 return false; 1120 1252 } 1121 1253 $atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']); 1122 1254 $atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']); 1123 $info['quicktime']['time_scale'] = ( isset($info['quicktime']['time_scale']) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']);1255 $info['quicktime']['time_scale'] = ((isset($info['quicktime']['time_scale']) && ($info['quicktime']['time_scale'] < 1000)) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']); 1124 1256 $info['quicktime']['display_scale'] = $atom_structure['matrix_a']; 1125 1257 $info['playtime_seconds'] = $atom_structure['duration'] / $atom_structure['time_scale']; … … 1241 1373 1242 1374 // check to see if it looks like chapter titles, in the form of unterminated strings with a leading 16-bit size field 1243 while (($chapter_string_length = getid3_lib::BigEndian2Int(substr($atom_data, $mdat_offset, 2))) 1375 while (($mdat_offset < (strlen($atom_data) - 8)) 1376 && ($chapter_string_length = getid3_lib::BigEndian2Int(substr($atom_data, $mdat_offset, 2))) 1244 1377 && ($chapter_string_length < 1000) 1245 1378 && ($chapter_string_length <= (strlen($atom_data) - $mdat_offset - 2)) 1246 && preg_match('#^[\x20-\xFF]+$#', substr($atom_data, $mdat_offset + 2, $chapter_string_length), $chapter_matches)) { 1379 && preg_match('#^([\x00-\xFF]{2})([\x20-\xFF]+)$#', substr($atom_data, $mdat_offset, $chapter_string_length + 2), $chapter_matches)) { 1380 list($dummy, $chapter_string_length_hex, $chapter_string) = $chapter_matches; 1247 1381 $mdat_offset += (2 + $chapter_string_length); 1248 @$info['quicktime']['comments']['chapters'][] = $chapter_matches[0]; 1249 } 1250 1382 @$info['quicktime']['comments']['chapters'][] = $chapter_string; 1383 1384 // "encd" atom specifies encoding. In theory could be anything, almost always UTF-8, but may be UTF-16 with BOM (not currently handled) 1385 if (substr($atom_data, $mdat_offset, 12) == "\x00\x00\x00\x0C\x65\x6E\x63\x64\x00\x00\x01\x00") { // UTF-8 1386 $mdat_offset += 12; 1387 } 1388 } 1251 1389 1252 1390 … … 1266 1404 if (!empty($getid3_temp->info['warning'])) { 1267 1405 foreach ($getid3_temp->info['warning'] as $value) { 1268 $ info['warning'][] = $value;1406 $this->warning($value); 1269 1407 } 1270 1408 } … … 1369 1507 } 1370 1508 } else { 1371 $ info['warning'][] = 'QuickTime atom "©xyz" data does not match expected data pattern at offset '.$baseoffset.'. Please report as getID3() bug.';1509 $this->warning('QuickTime atom "©xyz" data does not match expected data pattern at offset '.$baseoffset.'. Please report as getID3() bug.'); 1372 1510 } 1373 1511 break; … … 1398 1536 1399 1537 case "\x00\x00\x00\x00": 1400 case 'meta': // METAdata atom1401 1538 // some kind of metacontainer, may contain a big data dump such as: 1402 1539 // mdta keys \005 mdtacom.apple.quicktime.make (mdtacom.apple.quicktime.creationdate ,mdtacom.apple.quicktime.location.ISO6709 $mdtacom.apple.quicktime.software !mdtacom.apple.quicktime.model ilst \01D \001 \015data \001DE\010Apple 0 \002 (data \001DE\0102011-05-11T17:54:04+0200 2 \003 *data \001DE\010+52.4936+013.3897+040.247/ \01D \004 \015data \001DE\0104.3.1 \005 \018data \001DE\010iPhone 4 1403 1540 // http://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt 1404 1541 1405 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));1406 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));1407 $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom(substr($atom_data, 4), $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);1542 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 1543 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); 1544 $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom(substr($atom_data, 4), $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms); 1408 1545 //$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms); 1409 1546 break; 1410 1547 1548 case 'meta': // METAdata atom 1549 // https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/Metadata/Metadata.html 1550 1551 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 1552 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); 1553 $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms); 1554 break; 1555 1411 1556 case 'data': // metaDATA atom 1557 static $metaDATAkey = 1; // real ugly, but so is the QuickTime structure that stores keys and values in different multinested locations that are hard to relate to each other 1412 1558 // seems to be 2 bytes language code (ASCII), 2 bytes unknown (set to 0x10B5 in sample I have), remainder is useful data 1413 1559 $atom_structure['language'] = substr($atom_data, 4 + 0, 2); 1414 1560 $atom_structure['unknown'] = getid3_lib::BigEndian2Int(substr($atom_data, 4 + 2, 2)); 1415 1561 $atom_structure['data'] = substr($atom_data, 4 + 4); 1416 break; 1562 $atom_structure['key_name'] = @$info['quicktime']['temp_meta_key_names'][$metaDATAkey++]; 1563 1564 if ($atom_structure['key_name'] && $atom_structure['data']) { 1565 @$info['quicktime']['comments'][str_replace('com.apple.quicktime.', '', $atom_structure['key_name'])][] = $atom_structure['data']; 1566 } 1567 break; 1568 1569 case 'keys': // KEYS that may be present in the metadata atom. 1570 // https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/Metadata/Metadata.html#//apple_ref/doc/uid/TP40000939-CH1-SW21 1571 // The metadata item keys atom holds a list of the metadata keys that may be present in the metadata atom. 1572 // This list is indexed starting with 1; 0 is a reserved index value. The metadata item keys atom is a full atom with an atom type of "keys". 1573 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 1574 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); 1575 $atom_structure['entry_count'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); 1576 $keys_atom_offset = 8; 1577 for ($i = 1; $i <= $atom_structure['entry_count']; $i++) { 1578 $atom_structure['keys'][$i]['key_size'] = getid3_lib::BigEndian2Int(substr($atom_data, $keys_atom_offset + 0, 4)); 1579 $atom_structure['keys'][$i]['key_namespace'] = substr($atom_data, $keys_atom_offset + 4, 4); 1580 $atom_structure['keys'][$i]['key_value'] = substr($atom_data, $keys_atom_offset + 8, $atom_structure['keys'][$i]['key_size'] - 8); 1581 $keys_atom_offset += $atom_structure['keys'][$i]['key_size']; // key_size includes the 4+4 bytes for key_size and key_namespace 1582 1583 $info['quicktime']['temp_meta_key_names'][$i] = $atom_structure['keys'][$i]['key_value']; 1584 } 1585 break; 1586 1587 case 'gps ': 1588 // https://dashcamtalk.com/forum/threads/script-to-extract-gps-data-from-novatek-mp4.20808/page-2#post-291730 1589 // The 'gps ' contains simple look up table made up of 8byte rows, that point to the 'free' atoms that contains the actual GPS data. 1590 // The first row is version/metadata/notsure, I skip that. 1591 // The following rows consist of 4byte address (absolute) and 4byte size (0x1000), these point to the GPS data in the file. 1592 1593 $GPS_rowsize = 8; // 4 bytes for offset, 4 bytes for size 1594 if (strlen($atom_data) > 0) { 1595 if ((strlen($atom_data) % $GPS_rowsize) == 0) { 1596 $atom_structure['gps_toc'] = array(); 1597 foreach (str_split($atom_data, $GPS_rowsize) as $counter => $datapair) { 1598 $atom_structure['gps_toc'][] = unpack('Noffset/Nsize', substr($atom_data, $counter * $GPS_rowsize, $GPS_rowsize)); 1599 } 1600 1601 $atom_structure['gps_entries'] = array(); 1602 $previous_offset = $this->ftell(); 1603 foreach ($atom_structure['gps_toc'] as $key => $gps_pointer) { 1604 if ($key == 0) { 1605 // "The first row is version/metadata/notsure, I skip that." 1606 continue; 1607 } 1608 $this->fseek($gps_pointer['offset']); 1609 $GPS_free_data = $this->fread($gps_pointer['size']); 1610 1611 /* 1612 // 2017-05-10: I see some of the data, notably the Hour-Minute-Second, but cannot reconcile the rest of the data. However, the NMEA "GPRMC" line is there and relatively easy to parse, so I'm using that instead 1613 1614 // https://dashcamtalk.com/forum/threads/script-to-extract-gps-data-from-novatek-mp4.20808/page-2#post-291730 1615 // The structure of the GPS data atom (the 'free' atoms mentioned above) is following: 1616 // hour,minute,second,year,month,day,active,latitude_b,longitude_b,unknown2,latitude,longitude,speed = struct.unpack_from('<IIIIIIssssfff',data, 48) 1617 // For those unfamiliar with python struct: 1618 // I = int 1619 // s = is string (size 1, in this case) 1620 // f = float 1621 1622 //$atom_structure['gps_entries'][$key] = unpack('Vhour/Vminute/Vsecond/Vyear/Vmonth/Vday/Vactive/Vlatitude_b/Vlongitude_b/Vunknown2/flatitude/flongitude/fspeed', substr($GPS_free_data, 48)); 1623 */ 1624 1625 // $GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62 1626 // $GPRMC,183731,A,3907.482,N,12102.436,W,000.0,360.0,080301,015.5,E*67 1627 // $GPRMC,002454,A,3553.5295,N,13938.6570,E,0.0,43.1,180700,7.1,W,A*3F 1628 // $GPRMC,094347.000,A,5342.0061,N,00737.9908,W,0.01,156.75,140217,,,A*7D 1629 if (preg_match('#\\$GPRMC,([0-9\\.]*),([AV]),([0-9\\.]*),([NS]),([0-9\\.]*),([EW]),([0-9\\.]*),([0-9\\.]*),([0-9]*),([0-9\\.]*),([EW]?)(,[A])?(\\*[0-9A-F]{2})#', $GPS_free_data, $matches)) { 1630 $GPS_this_GPRMC = array(); 1631 list( 1632 $GPS_this_GPRMC['raw']['gprmc'], 1633 $GPS_this_GPRMC['raw']['timestamp'], 1634 $GPS_this_GPRMC['raw']['status'], 1635 $GPS_this_GPRMC['raw']['latitude'], 1636 $GPS_this_GPRMC['raw']['latitude_direction'], 1637 $GPS_this_GPRMC['raw']['longitude'], 1638 $GPS_this_GPRMC['raw']['longitude_direction'], 1639 $GPS_this_GPRMC['raw']['knots'], 1640 $GPS_this_GPRMC['raw']['angle'], 1641 $GPS_this_GPRMC['raw']['datestamp'], 1642 $GPS_this_GPRMC['raw']['variation'], 1643 $GPS_this_GPRMC['raw']['variation_direction'], 1644 $dummy, 1645 $GPS_this_GPRMC['raw']['checksum'], 1646 ) = $matches; 1647 1648 $hour = substr($GPS_this_GPRMC['raw']['timestamp'], 0, 2); 1649 $minute = substr($GPS_this_GPRMC['raw']['timestamp'], 2, 2); 1650 $second = substr($GPS_this_GPRMC['raw']['timestamp'], 4, 2); 1651 $ms = substr($GPS_this_GPRMC['raw']['timestamp'], 6); // may contain decimal seconds 1652 $day = substr($GPS_this_GPRMC['raw']['datestamp'], 0, 2); 1653 $month = substr($GPS_this_GPRMC['raw']['datestamp'], 2, 2); 1654 $year = substr($GPS_this_GPRMC['raw']['datestamp'], 4, 2); 1655 $year += (($year > 90) ? 1900 : 2000); // complete lack of foresight: datestamps are stored with 2-digit years, take best guess 1656 $GPS_this_GPRMC['timestamp'] = $year.'-'.$month.'-'.$day.' '.$hour.':'.$minute.':'.$second.$ms; 1657 1658 $GPS_this_GPRMC['active'] = ($GPS_this_GPRMC['raw']['status'] == 'A'); // A=Active,V=Void 1659 1660 foreach (array('latitude','longitude') as $latlon) { 1661 preg_match('#^([0-9]{1,3})([0-9]{2}\\.[0-9]+)$#', $GPS_this_GPRMC['raw'][$latlon], $matches); 1662 list($dummy, $deg, $min) = $matches; 1663 $GPS_this_GPRMC[$latlon] = $deg + ($min / 60); 1664 } 1665 $GPS_this_GPRMC['latitude'] *= (($GPS_this_GPRMC['raw']['latitude_direction'] == 'S') ? -1 : 1); 1666 $GPS_this_GPRMC['longitude'] *= (($GPS_this_GPRMC['raw']['longitude_direction'] == 'W') ? -1 : 1); 1667 1668 $GPS_this_GPRMC['heading'] = $GPS_this_GPRMC['raw']['angle']; 1669 $GPS_this_GPRMC['speed_knot'] = $GPS_this_GPRMC['raw']['knots']; 1670 $GPS_this_GPRMC['speed_kmh'] = $GPS_this_GPRMC['raw']['knots'] * 1.852; 1671 if ($GPS_this_GPRMC['raw']['variation']) { 1672 $GPS_this_GPRMC['variation'] = $GPS_this_GPRMC['raw']['variation']; 1673 $GPS_this_GPRMC['variation'] *= (($GPS_this_GPRMC['raw']['variation_direction'] == 'W') ? -1 : 1); 1674 } 1675 1676 $atom_structure['gps_entries'][$key] = $GPS_this_GPRMC; 1677 1678 @$info['quicktime']['gps_track'][$GPS_this_GPRMC['timestamp']] = array( 1679 'latitude' => $GPS_this_GPRMC['latitude'], 1680 'longitude' => $GPS_this_GPRMC['longitude'], 1681 'speed_kmh' => $GPS_this_GPRMC['speed_kmh'], 1682 'heading' => $GPS_this_GPRMC['heading'], 1683 ); 1684 1685 } else { 1686 $this->warning('Unhandled GPS format in "free" atom at offset '.$gps_pointer['offset']); 1687 } 1688 } 1689 $this->fseek($previous_offset); 1690 1691 } else { 1692 $this->warning('QuickTime atom "'.$atomname.'" is not mod-8 bytes long ('.$atomsize.' bytes) at offset '.$baseoffset); 1693 } 1694 } else { 1695 $this->warning('QuickTime atom "'.$atomname.'" is zero bytes long at offset '.$baseoffset); 1696 } 1697 break; 1698 1699 case 'loci':// 3GP location (El Loco) 1700 $info['quicktime']['comments']['gps_flags'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); 1701 $info['quicktime']['comments']['gps_lang'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); 1702 $loffset = 0; 1703 $info['quicktime']['comments']['gps_location'] = $this->LociString(substr($atom_data, 6), $loffset); 1704 $loci_data=substr($atom_data, 6 + $loffset); 1705 $info['quicktime']['comments']['gps_role'] = getid3_lib::BigEndian2Int(substr($loci_data, 0, 1)); 1706 $info['quicktime']['comments']['gps_longitude'] = getid3_lib::FixedPoint16_16(substr($loci_data, 1, 4)); 1707 $info['quicktime']['comments']['gps_latitude'] = getid3_lib::FixedPoint16_16(substr($loci_data, 5, 4)); 1708 $info['quicktime']['comments']['gps_altitude'] = getid3_lib::FixedPoint16_16(substr($loci_data, 9, 4)); 1709 $info['quicktime']['comments']['gps_body'] = $this->LociString(substr($loci_data, 13), $loffset); 1710 $info['quicktime']['comments']['gps_notes'] = $this->LociString(substr($loci_data, 13 + $loffset), $loffset); 1711 break; 1417 1712 1418 1713 default: 1419 $ info['warning'][] = 'Unknown QuickTime atom type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" ('.trim(getid3_lib::PrintHexBytes($atomname)).') at offset '.$baseoffset;1714 $this->warning('Unknown QuickTime atom type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" ('.trim(getid3_lib::PrintHexBytes($atomname)).') at offset '.$baseoffset); 1420 1715 $atom_structure['data'] = $atom_data; 1421 1716 break; … … 1441 1736 // terminated by a 32-bit integer set to 0. If you are writing a program 1442 1737 // to read user data atoms, you should allow for the terminating 0. 1738 if (strlen($atom_data) > 12) { 1739 $subatomoffset += 4; 1740 continue; 1741 } 1443 1742 return $atom_structure; 1444 1743 } … … 1754 2053 if (empty($QuicktimeIODSaudioProfileNameLookup)) { 1755 2054 $QuicktimeIODSaudioProfileNameLookup = array( 1756 0x00 => 'ISO Reserved (0x00)',1757 0x01 => 'Main Audio Profile @ Level 1',1758 0x02 => 'Main Audio Profile @ Level 2',1759 0x03 => 'Main Audio Profile @ Level 3',1760 0x04 => 'Main Audio Profile @ Level 4',1761 0x05 => 'Scalable Audio Profile @ Level 1',1762 0x06 => 'Scalable Audio Profile @ Level 2',1763 0x07 => 'Scalable Audio Profile @ Level 3',1764 0x08 => 'Scalable Audio Profile @ Level 4',1765 0x09 => 'Speech Audio Profile @ Level 1',1766 0x0A => 'Speech Audio Profile @ Level 2',1767 0x0B => 'Synthetic Audio Profile @ Level 1',1768 0x0C => 'Synthetic Audio Profile @ Level 2',1769 0x0D => 'Synthetic Audio Profile @ Level 3',1770 0x0E => 'High Quality Audio Profile @ Level 1',1771 0x0F => 'High Quality Audio Profile @ Level 2',1772 0x10 => 'High Quality Audio Profile @ Level 3',1773 0x11 => 'High Quality Audio Profile @ Level 4',1774 0x12 => 'High Quality Audio Profile @ Level 5',1775 0x13 => 'High Quality Audio Profile @ Level 6',1776 0x14 => 'High Quality Audio Profile @ Level 7',1777 0x15 => 'High Quality Audio Profile @ Level 8',1778 0x16 => 'Low Delay Audio Profile @ Level 1',1779 0x17 => 'Low Delay Audio Profile @ Level 2',1780 0x18 => 'Low Delay Audio Profile @ Level 3',1781 0x19 => 'Low Delay Audio Profile @ Level 4',1782 0x1A => 'Low Delay Audio Profile @ Level 5',1783 0x1B => 'Low Delay Audio Profile @ Level 6',1784 0x1C => 'Low Delay Audio Profile @ Level 7',1785 0x1D => 'Low Delay Audio Profile @ Level 8',1786 0x1E => 'Natural Audio Profile @ Level 1',1787 0x1F => 'Natural Audio Profile @ Level 2',1788 0x20 => 'Natural Audio Profile @ Level 3',1789 0x21 => 'Natural Audio Profile @ Level 4',1790 0x22 => 'Mobile Audio Internetworking Profile @ Level 1',1791 0x23 => 'Mobile Audio Internetworking Profile @ Level 2',1792 0x24 => 'Mobile Audio Internetworking Profile @ Level 3',1793 0x25 => 'Mobile Audio Internetworking Profile @ Level 4',1794 0x26 => 'Mobile Audio Internetworking Profile @ Level 5',1795 0x27 => 'Mobile Audio Internetworking Profile @ Level 6',1796 0x28 => 'AAC Profile @ Level 1',1797 0x29 => 'AAC Profile @ Level 2',1798 0x2A => 'AAC Profile @ Level 4',1799 0x2B => 'AAC Profile @ Level 5',1800 0x2C => 'High Efficiency AAC Profile @ Level 2',1801 0x2D => 'High Efficiency AAC Profile @ Level 3',1802 0x2E => 'High Efficiency AAC Profile @ Level 4',1803 0x2F => 'High Efficiency AAC Profile @ Level 5',1804 0xFE => 'Not part of MPEG-4 audio profiles',1805 0xFF => 'No audio capability required',2055 0x00 => 'ISO Reserved (0x00)', 2056 0x01 => 'Main Audio Profile @ Level 1', 2057 0x02 => 'Main Audio Profile @ Level 2', 2058 0x03 => 'Main Audio Profile @ Level 3', 2059 0x04 => 'Main Audio Profile @ Level 4', 2060 0x05 => 'Scalable Audio Profile @ Level 1', 2061 0x06 => 'Scalable Audio Profile @ Level 2', 2062 0x07 => 'Scalable Audio Profile @ Level 3', 2063 0x08 => 'Scalable Audio Profile @ Level 4', 2064 0x09 => 'Speech Audio Profile @ Level 1', 2065 0x0A => 'Speech Audio Profile @ Level 2', 2066 0x0B => 'Synthetic Audio Profile @ Level 1', 2067 0x0C => 'Synthetic Audio Profile @ Level 2', 2068 0x0D => 'Synthetic Audio Profile @ Level 3', 2069 0x0E => 'High Quality Audio Profile @ Level 1', 2070 0x0F => 'High Quality Audio Profile @ Level 2', 2071 0x10 => 'High Quality Audio Profile @ Level 3', 2072 0x11 => 'High Quality Audio Profile @ Level 4', 2073 0x12 => 'High Quality Audio Profile @ Level 5', 2074 0x13 => 'High Quality Audio Profile @ Level 6', 2075 0x14 => 'High Quality Audio Profile @ Level 7', 2076 0x15 => 'High Quality Audio Profile @ Level 8', 2077 0x16 => 'Low Delay Audio Profile @ Level 1', 2078 0x17 => 'Low Delay Audio Profile @ Level 2', 2079 0x18 => 'Low Delay Audio Profile @ Level 3', 2080 0x19 => 'Low Delay Audio Profile @ Level 4', 2081 0x1A => 'Low Delay Audio Profile @ Level 5', 2082 0x1B => 'Low Delay Audio Profile @ Level 6', 2083 0x1C => 'Low Delay Audio Profile @ Level 7', 2084 0x1D => 'Low Delay Audio Profile @ Level 8', 2085 0x1E => 'Natural Audio Profile @ Level 1', 2086 0x1F => 'Natural Audio Profile @ Level 2', 2087 0x20 => 'Natural Audio Profile @ Level 3', 2088 0x21 => 'Natural Audio Profile @ Level 4', 2089 0x22 => 'Mobile Audio Internetworking Profile @ Level 1', 2090 0x23 => 'Mobile Audio Internetworking Profile @ Level 2', 2091 0x24 => 'Mobile Audio Internetworking Profile @ Level 3', 2092 0x25 => 'Mobile Audio Internetworking Profile @ Level 4', 2093 0x26 => 'Mobile Audio Internetworking Profile @ Level 5', 2094 0x27 => 'Mobile Audio Internetworking Profile @ Level 6', 2095 0x28 => 'AAC Profile @ Level 1', 2096 0x29 => 'AAC Profile @ Level 2', 2097 0x2A => 'AAC Profile @ Level 4', 2098 0x2B => 'AAC Profile @ Level 5', 2099 0x2C => 'High Efficiency AAC Profile @ Level 2', 2100 0x2D => 'High Efficiency AAC Profile @ Level 3', 2101 0x2E => 'High Efficiency AAC Profile @ Level 4', 2102 0x2F => 'High Efficiency AAC Profile @ Level 5', 2103 0xFE => 'Not part of MPEG-4 audio profiles', 2104 0xFF => 'No audio capability required', 1806 2105 ); 1807 2106 } … … 2112 2411 static $handyatomtranslatorarray = array(); 2113 2412 if (empty($handyatomtranslatorarray)) { 2413 // http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt 2414 // http://www.geocities.com/xhelmboyx/quicktime/formats/mp4-layout.txt 2415 // http://atomicparsley.sourceforge.net/mpeg-4files.html 2416 // https://code.google.com/p/mp4v2/wiki/iTunesMetadata 2417 $handyatomtranslatorarray["\xA9".'alb'] = 'album'; // iTunes 4.0 2418 $handyatomtranslatorarray["\xA9".'ART'] = 'artist'; 2419 $handyatomtranslatorarray["\xA9".'art'] = 'artist'; // iTunes 4.0 2420 $handyatomtranslatorarray["\xA9".'aut'] = 'author'; 2421 $handyatomtranslatorarray["\xA9".'cmt'] = 'comment'; // iTunes 4.0 2422 $handyatomtranslatorarray["\xA9".'com'] = 'comment'; 2114 2423 $handyatomtranslatorarray["\xA9".'cpy'] = 'copyright'; 2115 $handyatomtranslatorarray["\xA9".'day'] = 'creation_date'; // iTunes 4.02424 $handyatomtranslatorarray["\xA9".'day'] = 'creation_date'; // iTunes 4.0 2116 2425 $handyatomtranslatorarray["\xA9".'dir'] = 'director'; 2117 2426 $handyatomtranslatorarray["\xA9".'ed1'] = 'edit1'; … … 2124 2433 $handyatomtranslatorarray["\xA9".'ed8'] = 'edit8'; 2125 2434 $handyatomtranslatorarray["\xA9".'ed9'] = 'edit9'; 2435 $handyatomtranslatorarray["\xA9".'enc'] = 'encoded_by'; 2126 2436 $handyatomtranslatorarray["\xA9".'fmt'] = 'format'; 2437 $handyatomtranslatorarray["\xA9".'gen'] = 'genre'; // iTunes 4.0 2438 $handyatomtranslatorarray["\xA9".'grp'] = 'grouping'; // iTunes 4.2 2439 $handyatomtranslatorarray["\xA9".'hst'] = 'host_computer'; 2127 2440 $handyatomtranslatorarray["\xA9".'inf'] = 'information'; 2441 $handyatomtranslatorarray["\xA9".'lyr'] = 'lyrics'; // iTunes 5.0 2442 $handyatomtranslatorarray["\xA9".'mak'] = 'make'; 2443 $handyatomtranslatorarray["\xA9".'mod'] = 'model'; 2444 $handyatomtranslatorarray["\xA9".'nam'] = 'title'; // iTunes 4.0 2445 $handyatomtranslatorarray["\xA9".'ope'] = 'composer'; 2128 2446 $handyatomtranslatorarray["\xA9".'prd'] = 'producer'; 2447 $handyatomtranslatorarray["\xA9".'PRD'] = 'product'; 2129 2448 $handyatomtranslatorarray["\xA9".'prf'] = 'performers'; 2130 2449 $handyatomtranslatorarray["\xA9".'req'] = 'system_requirements'; 2131 2450 $handyatomtranslatorarray["\xA9".'src'] = 'source_credit'; 2132 $handyatomtranslatorarray["\xA9".'wrt'] = 'writer'; 2133 2134 // http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt 2135 $handyatomtranslatorarray["\xA9".'nam'] = 'title'; // iTunes 4.0 2136 $handyatomtranslatorarray["\xA9".'cmt'] = 'comment'; // iTunes 4.0 2451 $handyatomtranslatorarray["\xA9".'swr'] = 'software'; 2452 $handyatomtranslatorarray["\xA9".'too'] = 'encoding_tool'; // iTunes 4.0 2453 $handyatomtranslatorarray["\xA9".'trk'] = 'track'; 2454 $handyatomtranslatorarray["\xA9".'url'] = 'url'; 2137 2455 $handyatomtranslatorarray["\xA9".'wrn'] = 'warning'; 2138 $handyatomtranslatorarray["\xA9".'hst'] = 'host_computer'; 2139 $handyatomtranslatorarray["\xA9".'mak'] = 'make'; 2140 $handyatomtranslatorarray["\xA9".'mod'] = 'model'; 2141 $handyatomtranslatorarray["\xA9".'PRD'] = 'product'; 2142 $handyatomtranslatorarray["\xA9".'swr'] = 'software'; 2143 $handyatomtranslatorarray["\xA9".'aut'] = 'author'; 2144 $handyatomtranslatorarray["\xA9".'ART'] = 'artist'; 2145 $handyatomtranslatorarray["\xA9".'trk'] = 'track'; 2146 $handyatomtranslatorarray["\xA9".'alb'] = 'album'; // iTunes 4.0 2147 $handyatomtranslatorarray["\xA9".'com'] = 'comment'; 2148 $handyatomtranslatorarray["\xA9".'gen'] = 'genre'; // iTunes 4.0 2149 $handyatomtranslatorarray["\xA9".'ope'] = 'composer'; 2150 $handyatomtranslatorarray["\xA9".'url'] = 'url'; 2151 $handyatomtranslatorarray["\xA9".'enc'] = 'encoder'; 2152 2153 // http://atomicparsley.sourceforge.net/mpeg-4files.html 2154 $handyatomtranslatorarray["\xA9".'art'] = 'artist'; // iTunes 4.0 2456 $handyatomtranslatorarray["\xA9".'wrt'] = 'composer'; 2155 2457 $handyatomtranslatorarray['aART'] = 'album_artist'; 2156 $handyatomtranslatorarray['trkn'] = 'track_number'; // iTunes 4.0 2157 $handyatomtranslatorarray['disk'] = 'disc_number'; // iTunes 4.0 2158 $handyatomtranslatorarray['gnre'] = 'genre'; // iTunes 4.0 2159 $handyatomtranslatorarray["\xA9".'too'] = 'encoder'; // iTunes 4.0 2160 $handyatomtranslatorarray['tmpo'] = 'bpm'; // iTunes 4.0 2161 $handyatomtranslatorarray['cprt'] = 'copyright'; // iTunes 4.0? 2162 $handyatomtranslatorarray['cpil'] = 'compilation'; // iTunes 4.0 2163 $handyatomtranslatorarray['covr'] = 'picture'; // iTunes 4.0 2164 $handyatomtranslatorarray['rtng'] = 'rating'; // iTunes 4.0 2165 $handyatomtranslatorarray["\xA9".'grp'] = 'grouping'; // iTunes 4.2 2166 $handyatomtranslatorarray['stik'] = 'stik'; // iTunes 4.9 2167 $handyatomtranslatorarray['pcst'] = 'podcast'; // iTunes 4.9 2168 $handyatomtranslatorarray['catg'] = 'category'; // iTunes 4.9 2169 $handyatomtranslatorarray['keyw'] = 'keyword'; // iTunes 4.9 2170 $handyatomtranslatorarray['purl'] = 'podcast_url'; // iTunes 4.9 2171 $handyatomtranslatorarray['egid'] = 'episode_guid'; // iTunes 4.9 2172 $handyatomtranslatorarray['desc'] = 'description'; // iTunes 5.0 2173 $handyatomtranslatorarray["\xA9".'lyr'] = 'lyrics'; // iTunes 5.0 2174 $handyatomtranslatorarray['tvnn'] = 'tv_network_name'; // iTunes 6.0 2175 $handyatomtranslatorarray['tvsh'] = 'tv_show_name'; // iTunes 6.0 2176 $handyatomtranslatorarray['tvsn'] = 'tv_season'; // iTunes 6.0 2177 $handyatomtranslatorarray['tves'] = 'tv_episode'; // iTunes 6.0 2178 $handyatomtranslatorarray['purd'] = 'purchase_date'; // iTunes 6.0.2 2179 $handyatomtranslatorarray['pgap'] = 'gapless_playback'; // iTunes 7.0 2180 2181 // http://www.geocities.com/xhelmboyx/quicktime/formats/mp4-layout.txt 2182 2183 2458 $handyatomtranslatorarray['apID'] = 'purchase_account'; 2459 $handyatomtranslatorarray['catg'] = 'category'; // iTunes 4.9 2460 $handyatomtranslatorarray['covr'] = 'picture'; // iTunes 4.0 2461 $handyatomtranslatorarray['cpil'] = 'compilation'; // iTunes 4.0 2462 $handyatomtranslatorarray['cprt'] = 'copyright'; // iTunes 4.0? 2463 $handyatomtranslatorarray['desc'] = 'description'; // iTunes 5.0 2464 $handyatomtranslatorarray['disk'] = 'disc_number'; // iTunes 4.0 2465 $handyatomtranslatorarray['egid'] = 'episode_guid'; // iTunes 4.9 2466 $handyatomtranslatorarray['gnre'] = 'genre'; // iTunes 4.0 2467 $handyatomtranslatorarray['hdvd'] = 'hd_video'; // iTunes 4.0 2468 $handyatomtranslatorarray['ldes'] = 'description_long'; // 2469 $handyatomtranslatorarray['keyw'] = 'keyword'; // iTunes 4.9 2470 $handyatomtranslatorarray['pcst'] = 'podcast'; // iTunes 4.9 2471 $handyatomtranslatorarray['pgap'] = 'gapless_playback'; // iTunes 7.0 2472 $handyatomtranslatorarray['purd'] = 'purchase_date'; // iTunes 6.0.2 2473 $handyatomtranslatorarray['purl'] = 'podcast_url'; // iTunes 4.9 2474 $handyatomtranslatorarray['rtng'] = 'rating'; // iTunes 4.0 2475 $handyatomtranslatorarray['soaa'] = 'sort_album_artist'; // 2476 $handyatomtranslatorarray['soal'] = 'sort_album'; // 2477 $handyatomtranslatorarray['soar'] = 'sort_artist'; // 2478 $handyatomtranslatorarray['soco'] = 'sort_composer'; // 2479 $handyatomtranslatorarray['sonm'] = 'sort_title'; // 2480 $handyatomtranslatorarray['sosn'] = 'sort_show'; // 2481 $handyatomtranslatorarray['stik'] = 'stik'; // iTunes 4.9 2482 $handyatomtranslatorarray['tmpo'] = 'bpm'; // iTunes 4.0 2483 $handyatomtranslatorarray['trkn'] = 'track_number'; // iTunes 4.0 2484 $handyatomtranslatorarray['tven'] = 'tv_episode_id'; // 2485 $handyatomtranslatorarray['tves'] = 'tv_episode'; // iTunes 6.0 2486 $handyatomtranslatorarray['tvnn'] = 'tv_network_name'; // iTunes 6.0 2487 $handyatomtranslatorarray['tvsh'] = 'tv_show_name'; // iTunes 6.0 2488 $handyatomtranslatorarray['tvsn'] = 'tv_season'; // iTunes 6.0 2184 2489 2185 2490 // boxnames: … … 2226 2531 } 2227 2532 } 2228 $info['quicktime']['comments'][$comment_key][] = $data; 2533 $gooddata = array($data); 2534 if ($comment_key == 'genre') { 2535 // some other taggers separate multiple genres with semicolon, e.g. "Heavy Metal;Thrash Metal;Metal" 2536 $gooddata = explode(';', $data); 2537 } 2538 foreach ($gooddata as $data) { 2539 $info['quicktime']['comments'][$comment_key][] = $data; 2540 } 2229 2541 } 2230 2542 return true; 2231 2543 } 2544 2545 public function LociString($lstring, &$count) { 2546 // Loci strings are UTF-8 or UTF-16 and null (x00/x0000) terminated. UTF-16 has a BOM 2547 // Also need to return the number of bytes the string occupied so additional fields can be extracted 2548 $len = strlen($lstring); 2549 if ($len == 0) { 2550 $count = 0; 2551 return ''; 2552 } 2553 if ($lstring[0] == "\x00") { 2554 $count = 1; 2555 return ''; 2556 } 2557 //check for BOM 2558 if ($len > 2 && (($lstring[0] == "\xFE" && $lstring[1] == "\xFF") || ($lstring[0] == "\xFF" && $lstring[1] == "\xFE"))) { 2559 //UTF-16 2560 if (preg_match('/(.*)\x00/', $lstring, $lmatches)){ 2561 $count = strlen($lmatches[1]) * 2 + 2; //account for 2 byte characters and trailing \x0000 2562 return getid3_lib::iconv_fallback_utf16_utf8($lmatches[1]); 2563 } else { 2564 return ''; 2565 } 2566 } else { 2567 //UTF-8 2568 if (preg_match('/(.*)\x00/', $lstring, $lmatches)){ 2569 $count = strlen($lmatches[1]) + 1; //account for trailing \x00 2570 return $lmatches[1]; 2571 }else { 2572 return ''; 2573 } 2574 2575 } 2576 } 2232 2577 2233 2578 public function NoNullString($nullterminatedstring) { … … 2244 2589 } 2245 2590 2591 2592 /* 2593 // helper functions for m4b audiobook chapters 2594 // code by Steffen Hartmann 2015-Nov-08 2595 */ 2596 public function search_tag_by_key($info, $tag, $history, &$result) { 2597 foreach ($info as $key => $value) { 2598 $key_history = $history.'/'.$key; 2599 if ($key === $tag) { 2600 $result[] = array($key_history, $info); 2601 } else { 2602 if (is_array($value)) { 2603 $this->search_tag_by_key($value, $tag, $key_history, $result); 2604 } 2605 } 2606 } 2607 } 2608 2609 public function search_tag_by_pair($info, $k, $v, $history, &$result) { 2610 foreach ($info as $key => $value) { 2611 $key_history = $history.'/'.$key; 2612 if (($key === $k) && ($value === $v)) { 2613 $result[] = array($key_history, $info); 2614 } else { 2615 if (is_array($value)) { 2616 $this->search_tag_by_pair($value, $k, $v, $key_history, $result); 2617 } 2618 } 2619 } 2620 } 2621 2622 public function quicktime_time_to_sample_table($info) { 2623 $res = array(); 2624 $this->search_tag_by_pair($info['quicktime']['moov'], 'name', 'stbl', 'quicktime/moov', $res); 2625 foreach ($res as $value) { 2626 $stbl_res = array(); 2627 $this->search_tag_by_pair($value[1], 'data_format', 'text', $value[0], $stbl_res); 2628 if (count($stbl_res) > 0) { 2629 $stts_res = array(); 2630 $this->search_tag_by_key($value[1], 'time_to_sample_table', $value[0], $stts_res); 2631 if (count($stts_res) > 0) { 2632 return $stts_res[0][1]['time_to_sample_table']; 2633 } 2634 } 2635 } 2636 return array(); 2637 } 2638 2639 function quicktime_bookmark_time_scale($info) { 2640 $time_scale = ''; 2641 $ts_prefix_len = 0; 2642 $res = array(); 2643 $this->search_tag_by_pair($info['quicktime']['moov'], 'name', 'stbl', 'quicktime/moov', $res); 2644 foreach ($res as $value) { 2645 $stbl_res = array(); 2646 $this->search_tag_by_pair($value[1], 'data_format', 'text', $value[0], $stbl_res); 2647 if (count($stbl_res) > 0) { 2648 $ts_res = array(); 2649 $this->search_tag_by_key($info['quicktime']['moov'], 'time_scale', 'quicktime/moov', $ts_res); 2650 foreach ($ts_res as $value) { 2651 $prefix = substr($value[0], 0, -12); 2652 if ((substr($stbl_res[0][0], 0, strlen($prefix)) === $prefix) && ($ts_prefix_len < strlen($prefix))) { 2653 $time_scale = $value[1]['time_scale']; 2654 $ts_prefix_len = strlen($prefix); 2655 } 2656 } 2657 } 2658 } 2659 return $time_scale; 2660 } 2661 /* 2662 // END helper functions for m4b audiobook chapters 2663 */ 2664 2665 2246 2666 } -
trunk/src/wp-includes/ID3/module.audio-video.riff.php
r29734 r41196 191 191 $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag']; 192 192 if (!isset($thisfile_riff_audio[$streamindex]['bitrate']) || ($thisfile_riff_audio[$streamindex]['bitrate'] == 0)) { 193 $ info['error'][] = 'Corrupt RIFF file: bitrate_audio == zero';193 $this->error('Corrupt RIFF file: bitrate_audio == zero'); 194 194 return false; 195 195 } … … 200 200 $thisfile_audio = getid3_lib::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]); 201 201 if (substr($thisfile_audio['codec'], 0, strlen('unknown: 0x')) == 'unknown: 0x') { 202 $ info['warning'][] = 'Audio codec = '.$thisfile_audio['codec'];202 $this->warning('Audio codec = '.$thisfile_audio['codec']); 203 203 } 204 204 $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate']; … … 303 303 $thisfile_riff_WAVE_bext_0['origin_date_unix'] = gmmktime($bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second'], $bext_timestamp['month'], $bext_timestamp['day'], $bext_timestamp['year']); 304 304 } else { 305 $ info['warning'][] = 'RIFF.WAVE.BEXT.origin_time is invalid';305 $this->warning('RIFF.WAVE.BEXT.origin_time is invalid'); 306 306 } 307 307 } else { 308 $ info['warning'][] = 'RIFF.WAVE.BEXT.origin_date is invalid';308 $this->warning('RIFF.WAVE.BEXT.origin_date is invalid'); 309 309 } 310 310 $thisfile_riff['comments']['author'][] = $thisfile_riff_WAVE_bext_0['author']; … … 386 386 387 387 if ($SNDM_thisTagSize != (4 + 4 + 2 + 2 + $SNDM_thisTagDataSize)) { 388 $ info['warning'][] = 'RIFF.WAVE.SNDM.data contains tag not expected length (expected: '.$SNDM_thisTagSize.', found: '.(4 + 4 + 2 + 2 + $SNDM_thisTagDataSize).') at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')';388 $this->warning('RIFF.WAVE.SNDM.data contains tag not expected length (expected: '.$SNDM_thisTagSize.', found: '.(4 + 4 + 2 + 2 + $SNDM_thisTagDataSize).') at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')'); 389 389 break; 390 390 } elseif ($SNDM_thisTagSize <= 0) { 391 $ info['warning'][] = 'RIFF.WAVE.SNDM.data contains zero-size tag at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')';391 $this->warning('RIFF.WAVE.SNDM.data contains zero-size tag at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')'); 392 392 break; 393 393 } … … 398 398 $thisfile_riff_WAVE_SNDM_0['parsed'][$parsedkey] = $SNDM_thisTagDataText; 399 399 } else { 400 $ info['warning'][] = 'RIFF.WAVE.SNDM contains unknown tag "'.$SNDM_thisTagKey.'" at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')';400 $this->warning('RIFF.WAVE.SNDM contains unknown tag "'.$SNDM_thisTagKey.'" at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')'); 401 401 } 402 402 } … … 429 429 if (isset($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO']) && !empty($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) && !empty($thisfile_riff_WAVE['iXML'][0]['timecode_rate'])) { 430 430 $samples_since_midnight = floatval(ltrim($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_HI'].$parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO'], '0')); 431 $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] = $samples_since_midnight / $parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']; 431 $timestamp_sample_rate = (is_array($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) ? max($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) : $parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']); // XML could possibly contain more than one TIMESTAMP_SAMPLE_RATE tag, returning as array instead of integer [why? does it make sense? perhaps doesn't matter but getID3 needs to deal with it] - see https://github.com/JamesHeinrich/getID3/issues/105 432 $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] = $samples_since_midnight / $timestamp_sample_rate; 432 433 $h = floor( $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] / 3600); 433 434 $m = floor(($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600)) / 60); … … 436 437 $thisfile_riff_WAVE['iXML'][0]['timecode_string'] = sprintf('%02d:%02d:%02d:%05.2f', $h, $m, $s, $f); 437 438 $thisfile_riff_WAVE['iXML'][0]['timecode_string_round'] = sprintf('%02d:%02d:%02d:%02d', $h, $m, $s, round($f)); 439 unset($samples_since_midnight, $timestamp_sample_rate, $h, $m, $s, $f); 438 440 } 439 441 unset($parsedXML); … … 571 573 } else { 572 574 // Short by more than one byte, throw warning 573 $ info['warning'][] = 'Probably truncated file - expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)';575 $this->warning('Probably truncated file - expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)'); 574 576 $info['avdataend'] = $info['filesize']; 575 577 } … … 580 582 // output file appears to be incorrectly *not* padded to nearest WORD boundary 581 583 // Output less severe warning 582 $ info['warning'][] = 'File should probably be padded to nearest WORD boundary, but it is not (expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' therefore short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)';584 $this->warning('File should probably be padded to nearest WORD boundary, but it is not (expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' therefore short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)'); 583 585 $info['avdataend'] = $info['filesize']; 584 586 } else { 585 587 // Short by more than one byte, throw warning 586 $ info['warning'][] = 'Probably truncated file - expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)';588 $this->warning('Probably truncated file - expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)'); 587 589 $info['avdataend'] = $info['filesize']; 588 590 } … … 593 595 if ((($info['avdataend'] - $info['avdataoffset']) - $info['mpeg']['audio']['LAME']['audio_bytes']) == 1) { 594 596 $info['avdataend']--; 595 $ info['warning'][] = 'Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored';597 $this->warning('Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored'); 596 598 } 597 599 } … … 620 622 } 621 623 if ($info['avdataend'] > $info['filesize']) { 622 $ info['warning'][] = 'Probably truncated file - expecting '.($info['avdataend'] - $info['avdataoffset']).' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($info['avdataend'] - $info['filesize']).' bytes)';624 $this->warning('Probably truncated file - expecting '.($info['avdataend'] - $info['avdataoffset']).' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($info['avdataend'] - $info['filesize']).' bytes)'); 623 625 $info['avdataend'] = $info['filesize']; 624 626 } … … 661 663 $thisfile_riff_raw_avih['dwMicroSecPerFrame'] = $this->EitherEndian2Int(substr($avihData, 0, 4)); // frame display rate (or 0L) 662 664 if ($thisfile_riff_raw_avih['dwMicroSecPerFrame'] == 0) { 663 $ info['error'][] = 'Corrupt RIFF file: avih.dwMicroSecPerFrame == zero';665 $this->error('Corrupt RIFF file: avih.dwMicroSecPerFrame == zero'); 664 666 return false; 665 667 } … … 859 861 860 862 default: 861 $ info['warning'][] = 'Unhandled fccType for stream ('.$i.'): "'.$strhfccType.'"';863 $this->warning('Unhandled fccType for stream ('.$i.'): "'.$strhfccType.'"'); 862 864 break; 863 865 … … 964 966 // forget to pad end of file to make this actually work 965 967 } else { 966 $ info['warning'][] = 'Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['SSND'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found';968 $this->warning('Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['SSND'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found'); 967 969 } 968 970 $info['avdataend'] = $info['filesize']; … … 1021 1023 $thisfile_audio['sample_rate'] = $thisfile_riff_audio['sample_rate']; 1022 1024 if ($thisfile_audio['sample_rate'] == 0) { 1023 $ info['error'][] = 'Corrupted AIFF file: sample_rate == zero';1025 $this->error('Corrupted AIFF file: sample_rate == zero'); 1024 1026 return false; 1025 1027 } … … 1081 1083 $info['avdataend'] = $info['avdataoffset'] + $thisfile_riff[$RIFFsubtype]['BODY'][0]['size']; 1082 1084 if ($info['avdataend'] > $info['filesize']) { 1083 $ info['warning'][] = 'Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['BODY'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found';1085 $this->warning('Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['BODY'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found'); 1084 1086 } 1085 1087 } … … 1113 1115 1114 1116 default: 1115 $ info['warning'][] = 'Unexpected sCompression value in 8SVX.VHDR chunk - expecting 0 or 1, found "'.sCompression.'"';1117 $this->warning('Unexpected sCompression value in 8SVX.VHDR chunk - expecting 0 or 1, found "'.sCompression.'"'); 1116 1118 break; 1117 1119 } … … 1131 1133 1132 1134 default: 1133 $ info['warning'][] = 'Unexpected value in 8SVX.CHAN chunk - expecting 2 or 4 or 6, found "'.$ChannelsIndex.'"';1135 $this->warning('Unexpected value in 8SVX.CHAN chunk - expecting 2 or 4 or 6, found "'.$ChannelsIndex.'"'); 1134 1136 break; 1135 1137 } … … 1171 1173 break; 1172 1174 1175 case 'WEBP': 1176 // https://developers.google.com/speed/webp/docs/riff_container 1177 // https://tools.ietf.org/html/rfc6386 1178 // https://chromium.googlesource.com/webm/libwebp/+/master/doc/webp-lossless-bitstream-spec.txt 1179 $info['fileformat'] = 'webp'; 1180 $info['mime_type'] = 'image/webp'; 1181 1182 if (!empty($thisfile_riff['WEBP']['VP8 '][0]['size'])) { 1183 $old_offset = $this->ftell(); 1184 $this->fseek($thisfile_riff['WEBP']['VP8 '][0]['offset'] + 8); // 4 bytes "VP8 " + 4 bytes chunk size 1185 $WEBP_VP8_header = $this->fread(10); 1186 $this->fseek($old_offset); 1187 if (substr($WEBP_VP8_header, 3, 3) == "\x9D\x01\x2A") { 1188 $thisfile_riff['WEBP']['VP8 '][0]['keyframe'] = !(getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 0, 3)) & 0x800000); 1189 $thisfile_riff['WEBP']['VP8 '][0]['version'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 0, 3)) & 0x700000) >> 20; 1190 $thisfile_riff['WEBP']['VP8 '][0]['show_frame'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 0, 3)) & 0x080000); 1191 $thisfile_riff['WEBP']['VP8 '][0]['data_bytes'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 0, 3)) & 0x07FFFF) >> 0; 1192 1193 $thisfile_riff['WEBP']['VP8 '][0]['scale_x'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 6, 2)) & 0xC000) >> 14; 1194 $thisfile_riff['WEBP']['VP8 '][0]['width'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 6, 2)) & 0x3FFF); 1195 $thisfile_riff['WEBP']['VP8 '][0]['scale_y'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 8, 2)) & 0xC000) >> 14; 1196 $thisfile_riff['WEBP']['VP8 '][0]['height'] = (getid3_lib::LittleEndian2Int(substr($WEBP_VP8_header, 8, 2)) & 0x3FFF); 1197 1198 $info['video']['resolution_x'] = $thisfile_riff['WEBP']['VP8 '][0]['width']; 1199 $info['video']['resolution_y'] = $thisfile_riff['WEBP']['VP8 '][0]['height']; 1200 } else { 1201 $this->error('Expecting 9D 01 2A at offset '.($thisfile_riff['WEBP']['VP8 '][0]['offset'] + 8 + 3).', found "'.getid3_lib::PrintHexBytes(substr($WEBP_VP8_header, 3, 3)).'"'); 1202 } 1203 1204 } 1205 if (!empty($thisfile_riff['WEBP']['VP8L'][0]['size'])) { 1206 $old_offset = $this->ftell(); 1207 $this->fseek($thisfile_riff['WEBP']['VP8L'][0]['offset'] + 8); // 4 bytes "VP8L" + 4 bytes chunk size 1208 $WEBP_VP8L_header = $this->fread(10); 1209 $this->fseek($old_offset); 1210 if (substr($WEBP_VP8L_header, 0, 1) == "\x2F") { 1211 $width_height_flags = getid3_lib::LittleEndian2Bin(substr($WEBP_VP8L_header, 1, 4)); 1212 $thisfile_riff['WEBP']['VP8L'][0]['width'] = bindec(substr($width_height_flags, 18, 14)) + 1; 1213 $thisfile_riff['WEBP']['VP8L'][0]['height'] = bindec(substr($width_height_flags, 4, 14)) + 1; 1214 $thisfile_riff['WEBP']['VP8L'][0]['alpha_is_used'] = (bool) bindec(substr($width_height_flags, 3, 1)); 1215 $thisfile_riff['WEBP']['VP8L'][0]['version'] = bindec(substr($width_height_flags, 0, 3)); 1216 1217 $info['video']['resolution_x'] = $thisfile_riff['WEBP']['VP8L'][0]['width']; 1218 $info['video']['resolution_y'] = $thisfile_riff['WEBP']['VP8L'][0]['height']; 1219 } else { 1220 $this->error('Expecting 2F at offset '.($thisfile_riff['WEBP']['VP8L'][0]['offset'] + 8).', found "'.getid3_lib::PrintHexBytes(substr($WEBP_VP8L_header, 0, 1)).'"'); 1221 } 1222 1223 } 1224 break; 1173 1225 1174 1226 default: 1175 $ info['error'][] = 'Unknown RIFF type: expecting one of (WAVE|RMP3|AVI |CDDA|AIFF|AIFC|8SVX|CDXA), found "'.$RIFFsubtype.'" instead';1227 $this->error('Unknown RIFF type: expecting one of (WAVE|RMP3|AVI |CDDA|AIFF|AIFC|8SVX|CDXA|WEBP), found "'.$RIFFsubtype.'" instead'); 1176 1228 //unset($info['fileformat']); 1177 1229 } … … 1186 1238 if (isset($thisfile_riff[$RIFFsubtype][$ID3v2_key_bad]) && !array_key_exists($ID3v2_key_good, $thisfile_riff[$RIFFsubtype])) { 1187 1239 $thisfile_riff[$RIFFsubtype][$ID3v2_key_good] = $thisfile_riff[$RIFFsubtype][$ID3v2_key_bad]; 1188 $ info['warning'][] = 'mapping "'.$ID3v2_key_bad.'" chunk to "'.$ID3v2_key_good.'"';1240 $this->warning('mapping "'.$ID3v2_key_bad.'" chunk to "'.$ID3v2_key_good.'"'); 1189 1241 } 1190 1242 } … … 1510 1562 if (!empty($getid3_temp->info['warning'])) { 1511 1563 foreach ($getid3_temp->info['warning'] as $key => $value) { 1512 $ info['warning'][] = $value;1564 $this->warning($value); 1513 1565 } 1514 1566 } -
trunk/src/wp-includes/ID3/module.audio.ac3.php
r32979 r41196 21 21 private $BSIoffset = 0; 22 22 23 const syncword = "\x0B\x77";23 const syncword = 0x0B77; 24 24 25 25 public function Analyze() { … … 56 56 57 57 $this->fseek($info['avdataoffset']); 58 $this->AC3header['syncinfo'] = $this->fread(5); 59 60 if (strpos($this->AC3header['syncinfo'], self::syncword) === 0) { 61 $thisfile_ac3_raw['synchinfo']['synchword'] = self::syncword; 62 $offset = 2; 63 } else { 58 $tempAC3header = $this->fread(100); // should be enough to cover all data, there are some variable-length fields...? 59 $this->AC3header['syncinfo'] = getid3_lib::BigEndian2Int(substr($tempAC3header, 0, 2)); 60 $this->AC3header['bsi'] = getid3_lib::BigEndian2Bin(substr($tempAC3header, 2)); 61 $thisfile_ac3_raw_bsi['bsid'] = (getid3_lib::LittleEndian2Int(substr($tempAC3header, 5, 1)) & 0xF8) >> 3; // AC3 and E-AC3 put the "bsid" version identifier in the same place, but unfortnately the 4 bytes between the syncword and the version identifier are interpreted differently, so grab it here so the following code structure can make sense 62 unset($tempAC3header); 63 64 if ($this->AC3header['syncinfo'] !== self::syncword) { 64 65 if (!$this->isDependencyFor('matroska')) { 65 66 unset($info['fileformat'], $info['ac3']); 66 return $this->error('Expecting "'.getid3_lib::PrintHexBytes(self::syncword).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($this->AC3header['syncinfo'], 0, 2)).'"'); 67 } 68 $offset = 0; 69 $this->fseek(-2, SEEK_CUR); 67 return $this->error('Expecting "'.dechex(self::syncword).'" at offset '.$info['avdataoffset'].', found "'.dechex($this->AC3header['syncinfo']).'"'); 68 } 70 69 } 71 70 … … 74 73 $info['audio']['lossless'] = false; 75 74 76 $thisfile_ac3_raw['synchinfo']['crc1'] = getid3_lib::LittleEndian2Int(substr($this->AC3header['syncinfo'], $offset, 2)); 77 $ac3_synchinfo_fscod_frmsizecod = getid3_lib::LittleEndian2Int(substr($this->AC3header['syncinfo'], ($offset + 2), 1)); 78 $thisfile_ac3_raw['synchinfo']['fscod'] = ($ac3_synchinfo_fscod_frmsizecod & 0xC0) >> 6; 79 $thisfile_ac3_raw['synchinfo']['frmsizecod'] = ($ac3_synchinfo_fscod_frmsizecod & 0x3F); 80 81 $thisfile_ac3['sample_rate'] = self::sampleRateCodeLookup($thisfile_ac3_raw['synchinfo']['fscod']); 82 if ($thisfile_ac3_raw['synchinfo']['fscod'] <= 3) { 83 $info['audio']['sample_rate'] = $thisfile_ac3['sample_rate']; 84 } 85 86 $thisfile_ac3['frame_length'] = self::frameSizeLookup($thisfile_ac3_raw['synchinfo']['frmsizecod'], $thisfile_ac3_raw['synchinfo']['fscod']); 87 $thisfile_ac3['bitrate'] = self::bitrateLookup($thisfile_ac3_raw['synchinfo']['frmsizecod']); 88 $info['audio']['bitrate'] = $thisfile_ac3['bitrate']; 89 90 $this->AC3header['bsi'] = getid3_lib::BigEndian2Bin($this->fread(15)); 91 $ac3_bsi_offset = 0; 92 93 $thisfile_ac3_raw_bsi['bsid'] = $this->readHeaderBSI(5); 94 if ($thisfile_ac3_raw_bsi['bsid'] > 8) { 95 // Decoders which can decode version 8 will thus be able to decode version numbers less than 8. 96 // If this standard is extended by the addition of additional elements or features, a value of bsid greater than 8 will be used. 97 // Decoders built to this version of the standard will not be able to decode versions with bsid greater than 8. 98 $this->error('Bit stream identification is version '.$thisfile_ac3_raw_bsi['bsid'].', but getID3() only understands up to version 8'); 75 if ($thisfile_ac3_raw_bsi['bsid'] <= 8) { 76 77 $thisfile_ac3_raw_bsi['crc1'] = getid3_lib::Bin2Dec($this->readHeaderBSI(16)); 78 $thisfile_ac3_raw_bsi['fscod'] = $this->readHeaderBSI(2); // 5.4.1.3 79 $thisfile_ac3_raw_bsi['frmsizecod'] = $this->readHeaderBSI(6); // 5.4.1.4 80 if ($thisfile_ac3_raw_bsi['frmsizecod'] > 37) { // binary: 100101 - see Table 5.18 Frame Size Code Table (1 word = 16 bits) 81 $this->warning('Unexpected ac3.bsi.frmsizecod value: '.$thisfile_ac3_raw_bsi['frmsizecod'].', bitrate not set correctly'); 82 } 83 84 $thisfile_ac3_raw_bsi['bsid'] = $this->readHeaderBSI(5); // we already know this from pre-parsing the version identifier, but re-read it to let the bitstream flow as intended 85 $thisfile_ac3_raw_bsi['bsmod'] = $this->readHeaderBSI(3); 86 $thisfile_ac3_raw_bsi['acmod'] = $this->readHeaderBSI(3); 87 88 if ($thisfile_ac3_raw_bsi['acmod'] & 0x01) { 89 // If the lsb of acmod is a 1, center channel is in use and cmixlev follows in the bit stream. 90 $thisfile_ac3_raw_bsi['cmixlev'] = $this->readHeaderBSI(2); 91 $thisfile_ac3['center_mix_level'] = self::centerMixLevelLookup($thisfile_ac3_raw_bsi['cmixlev']); 92 } 93 94 if ($thisfile_ac3_raw_bsi['acmod'] & 0x04) { 95 // If the msb of acmod is a 1, surround channels are in use and surmixlev follows in the bit stream. 96 $thisfile_ac3_raw_bsi['surmixlev'] = $this->readHeaderBSI(2); 97 $thisfile_ac3['surround_mix_level'] = self::surroundMixLevelLookup($thisfile_ac3_raw_bsi['surmixlev']); 98 } 99 100 if ($thisfile_ac3_raw_bsi['acmod'] == 0x02) { 101 // When operating in the two channel mode, this 2-bit code indicates whether or not the program has been encoded in Dolby Surround. 102 $thisfile_ac3_raw_bsi['dsurmod'] = $this->readHeaderBSI(2); 103 $thisfile_ac3['dolby_surround_mode'] = self::dolbySurroundModeLookup($thisfile_ac3_raw_bsi['dsurmod']); 104 } 105 106 $thisfile_ac3_raw_bsi['flags']['lfeon'] = (bool) $this->readHeaderBSI(1); 107 108 // This indicates how far the average dialogue level is below digital 100 percent. Valid values are 1-31. 109 // The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent. 110 $thisfile_ac3_raw_bsi['dialnorm'] = $this->readHeaderBSI(5); // 5.4.2.8 dialnorm: Dialogue Normalization, 5 Bits 111 112 $thisfile_ac3_raw_bsi['flags']['compr'] = (bool) $this->readHeaderBSI(1); // 5.4.2.9 compre: Compression Gain Word Exists, 1 Bit 113 if ($thisfile_ac3_raw_bsi['flags']['compr']) { 114 $thisfile_ac3_raw_bsi['compr'] = $this->readHeaderBSI(8); // 5.4.2.10 compr: Compression Gain Word, 8 Bits 115 $thisfile_ac3['heavy_compression'] = self::heavyCompression($thisfile_ac3_raw_bsi['compr']); 116 } 117 118 $thisfile_ac3_raw_bsi['flags']['langcod'] = (bool) $this->readHeaderBSI(1); // 5.4.2.11 langcode: Language Code Exists, 1 Bit 119 if ($thisfile_ac3_raw_bsi['flags']['langcod']) { 120 $thisfile_ac3_raw_bsi['langcod'] = $this->readHeaderBSI(8); // 5.4.2.12 langcod: Language Code, 8 Bits 121 } 122 123 $thisfile_ac3_raw_bsi['flags']['audprodinfo'] = (bool) $this->readHeaderBSI(1); // 5.4.2.13 audprodie: Audio Production Information Exists, 1 Bit 124 if ($thisfile_ac3_raw_bsi['flags']['audprodinfo']) { 125 $thisfile_ac3_raw_bsi['mixlevel'] = $this->readHeaderBSI(5); // 5.4.2.14 mixlevel: Mixing Level, 5 Bits 126 $thisfile_ac3_raw_bsi['roomtyp'] = $this->readHeaderBSI(2); // 5.4.2.15 roomtyp: Room Type, 2 Bits 127 128 $thisfile_ac3['mixing_level'] = (80 + $thisfile_ac3_raw_bsi['mixlevel']).'dB'; 129 $thisfile_ac3['room_type'] = self::roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp']); 130 } 131 132 133 $thisfile_ac3_raw_bsi['dialnorm2'] = $this->readHeaderBSI(5); // 5.4.2.16 dialnorm2: Dialogue Normalization, ch2, 5 Bits 134 $thisfile_ac3['dialogue_normalization2'] = '-'.$thisfile_ac3_raw_bsi['dialnorm2'].'dB'; // This indicates how far the average dialogue level is below digital 100 percent. Valid values are 1-31. The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent. 135 136 $thisfile_ac3_raw_bsi['flags']['compr2'] = (bool) $this->readHeaderBSI(1); // 5.4.2.17 compr2e: Compression Gain Word Exists, ch2, 1 Bit 137 if ($thisfile_ac3_raw_bsi['flags']['compr2']) { 138 $thisfile_ac3_raw_bsi['compr2'] = $this->readHeaderBSI(8); // 5.4.2.18 compr2: Compression Gain Word, ch2, 8 Bits 139 $thisfile_ac3['heavy_compression2'] = self::heavyCompression($thisfile_ac3_raw_bsi['compr2']); 140 } 141 142 $thisfile_ac3_raw_bsi['flags']['langcod2'] = (bool) $this->readHeaderBSI(1); // 5.4.2.19 langcod2e: Language Code Exists, ch2, 1 Bit 143 if ($thisfile_ac3_raw_bsi['flags']['langcod2']) { 144 $thisfile_ac3_raw_bsi['langcod2'] = $this->readHeaderBSI(8); // 5.4.2.20 langcod2: Language Code, ch2, 8 Bits 145 } 146 147 $thisfile_ac3_raw_bsi['flags']['audprodinfo2'] = (bool) $this->readHeaderBSI(1); // 5.4.2.21 audprodi2e: Audio Production Information Exists, ch2, 1 Bit 148 if ($thisfile_ac3_raw_bsi['flags']['audprodinfo2']) { 149 $thisfile_ac3_raw_bsi['mixlevel2'] = $this->readHeaderBSI(5); // 5.4.2.22 mixlevel2: Mixing Level, ch2, 5 Bits 150 $thisfile_ac3_raw_bsi['roomtyp2'] = $this->readHeaderBSI(2); // 5.4.2.23 roomtyp2: Room Type, ch2, 2 Bits 151 152 $thisfile_ac3['mixing_level2'] = (80 + $thisfile_ac3_raw_bsi['mixlevel2']).'dB'; 153 $thisfile_ac3['room_type2'] = self::roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp2']); 154 } 155 156 $thisfile_ac3_raw_bsi['copyright'] = (bool) $this->readHeaderBSI(1); // 5.4.2.24 copyrightb: Copyright Bit, 1 Bit 157 158 $thisfile_ac3_raw_bsi['original'] = (bool) $this->readHeaderBSI(1); // 5.4.2.25 origbs: Original Bit Stream, 1 Bit 159 160 $thisfile_ac3_raw_bsi['flags']['timecod1'] = $this->readHeaderBSI(2); // 5.4.2.26 timecod1e, timcode2e: Time Code (first and second) Halves Exist, 2 Bits 161 if ($thisfile_ac3_raw_bsi['flags']['timecod1'] & 0x01) { 162 $thisfile_ac3_raw_bsi['timecod1'] = $this->readHeaderBSI(14); // 5.4.2.27 timecod1: Time code first half, 14 bits 163 $thisfile_ac3['timecode1'] = 0; 164 $thisfile_ac3['timecode1'] += (($thisfile_ac3_raw_bsi['timecod1'] & 0x3E00) >> 9) * 3600; // The first 5 bits of this 14-bit field represent the time in hours, with valid values of 0�23 165 $thisfile_ac3['timecode1'] += (($thisfile_ac3_raw_bsi['timecod1'] & 0x01F8) >> 3) * 60; // The next 6 bits represent the time in minutes, with valid values of 0�59 166 $thisfile_ac3['timecode1'] += (($thisfile_ac3_raw_bsi['timecod1'] & 0x0003) >> 0) * 8; // The final 3 bits represents the time in 8 second increments, with valid values of 0�7 (representing 0, 8, 16, ... 56 seconds) 167 } 168 if ($thisfile_ac3_raw_bsi['flags']['timecod1'] & 0x02) { 169 $thisfile_ac3_raw_bsi['timecod2'] = $this->readHeaderBSI(14); // 5.4.2.28 timecod2: Time code second half, 14 bits 170 $thisfile_ac3['timecode2'] = 0; 171 $thisfile_ac3['timecode2'] += (($thisfile_ac3_raw_bsi['timecod2'] & 0x3800) >> 11) * 1; // The first 3 bits of this 14-bit field represent the time in seconds, with valid values from 0�7 (representing 0-7 seconds) 172 $thisfile_ac3['timecode2'] += (($thisfile_ac3_raw_bsi['timecod2'] & 0x07C0) >> 6) * (1 / 30); // The next 5 bits represents the time in frames, with valid values from 0�29 (one frame = 1/30th of a second) 173 $thisfile_ac3['timecode2'] += (($thisfile_ac3_raw_bsi['timecod2'] & 0x003F) >> 0) * ((1 / 30) / 60); // The final 6 bits represents fractions of 1/64 of a frame, with valid values from 0�63 174 } 175 176 $thisfile_ac3_raw_bsi['flags']['addbsi'] = (bool) $this->readHeaderBSI(1); 177 if ($thisfile_ac3_raw_bsi['flags']['addbsi']) { 178 $thisfile_ac3_raw_bsi['addbsi_length'] = $this->readHeaderBSI(6) + 1; // This 6-bit code, which exists only if addbside is a 1, indicates the length in bytes of additional bit stream information. The valid range of addbsil is 0�63, indicating 1�64 additional bytes, respectively. 179 180 $this->AC3header['bsi'] .= getid3_lib::BigEndian2Bin($this->fread($thisfile_ac3_raw_bsi['addbsi_length'])); 181 182 $thisfile_ac3_raw_bsi['addbsi_data'] = substr($this->AC3header['bsi'], $this->BSIoffset, $thisfile_ac3_raw_bsi['addbsi_length'] * 8); 183 $this->BSIoffset += $thisfile_ac3_raw_bsi['addbsi_length'] * 8; 184 } 185 186 187 } elseif ($thisfile_ac3_raw_bsi['bsid'] <= 16) { // E-AC3 188 189 190 $this->error('E-AC3 parsing is incomplete and experimental in this version of getID3 ('.$this->getid3->version().'). Notably the bitrate calculations are wrong -- value might (or not) be correct, but it is not calculated correctly. Email [email protected] if you know how to calculate EAC3 bitrate correctly.'); 191 $info['audio']['dataformat'] = 'eac3'; 192 193 $thisfile_ac3_raw_bsi['strmtyp'] = $this->readHeaderBSI(2); 194 $thisfile_ac3_raw_bsi['substreamid'] = $this->readHeaderBSI(3); 195 $thisfile_ac3_raw_bsi['frmsiz'] = $this->readHeaderBSI(11); 196 $thisfile_ac3_raw_bsi['fscod'] = $this->readHeaderBSI(2); 197 if ($thisfile_ac3_raw_bsi['fscod'] == 3) { 198 $thisfile_ac3_raw_bsi['fscod2'] = $this->readHeaderBSI(2); 199 $thisfile_ac3_raw_bsi['numblkscod'] = 3; // six blocks per syncframe 200 } else { 201 $thisfile_ac3_raw_bsi['numblkscod'] = $this->readHeaderBSI(2); 202 } 203 $thisfile_ac3['bsi']['blocks_per_sync_frame'] = self::blocksPerSyncFrame($thisfile_ac3_raw_bsi['numblkscod']); 204 $thisfile_ac3_raw_bsi['acmod'] = $this->readHeaderBSI(3); 205 $thisfile_ac3_raw_bsi['flags']['lfeon'] = (bool) $this->readHeaderBSI(1); 206 $thisfile_ac3_raw_bsi['bsid'] = $this->readHeaderBSI(5); // we already know this from pre-parsing the version identifier, but re-read it to let the bitstream flow as intended 207 $thisfile_ac3_raw_bsi['dialnorm'] = $this->readHeaderBSI(5); 208 $thisfile_ac3_raw_bsi['flags']['compr'] = (bool) $this->readHeaderBSI(1); 209 if ($thisfile_ac3_raw_bsi['flags']['compr']) { 210 $thisfile_ac3_raw_bsi['compr'] = $this->readHeaderBSI(8); 211 } 212 if ($thisfile_ac3_raw_bsi['acmod'] == 0) { // if 1+1 mode (dual mono, so some items need a second value) 213 $thisfile_ac3_raw_bsi['dialnorm2'] = $this->readHeaderBSI(5); 214 $thisfile_ac3_raw_bsi['flags']['compr2'] = (bool) $this->readHeaderBSI(1); 215 if ($thisfile_ac3_raw_bsi['flags']['compr2']) { 216 $thisfile_ac3_raw_bsi['compr2'] = $this->readHeaderBSI(8); 217 } 218 } 219 if ($thisfile_ac3_raw_bsi['strmtyp'] == 1) { // if dependent stream 220 $thisfile_ac3_raw_bsi['flags']['chanmap'] = (bool) $this->readHeaderBSI(1); 221 if ($thisfile_ac3_raw_bsi['flags']['chanmap']) { 222 $thisfile_ac3_raw_bsi['chanmap'] = $this->readHeaderBSI(8); 223 } 224 } 225 $thisfile_ac3_raw_bsi['flags']['mixmdat'] = (bool) $this->readHeaderBSI(1); 226 if ($thisfile_ac3_raw_bsi['flags']['mixmdat']) { // Mixing metadata 227 if ($thisfile_ac3_raw_bsi['acmod'] > 2) { // if more than 2 channels 228 $thisfile_ac3_raw_bsi['dmixmod'] = $this->readHeaderBSI(2); 229 } 230 if (($thisfile_ac3_raw_bsi['acmod'] & 0x01) && ($thisfile_ac3_raw_bsi['acmod'] > 2)) { // if three front channels exist 231 $thisfile_ac3_raw_bsi['ltrtcmixlev'] = $this->readHeaderBSI(3); 232 $thisfile_ac3_raw_bsi['lorocmixlev'] = $this->readHeaderBSI(3); 233 } 234 if ($thisfile_ac3_raw_bsi['acmod'] & 0x04) { // if a surround channel exists 235 $thisfile_ac3_raw_bsi['ltrtsurmixlev'] = $this->readHeaderBSI(3); 236 $thisfile_ac3_raw_bsi['lorosurmixlev'] = $this->readHeaderBSI(3); 237 } 238 if ($thisfile_ac3_raw_bsi['flags']['lfeon']) { // if the LFE channel exists 239 $thisfile_ac3_raw_bsi['flags']['lfemixlevcod'] = (bool) $this->readHeaderBSI(1); 240 if ($thisfile_ac3_raw_bsi['flags']['lfemixlevcod']) { 241 $thisfile_ac3_raw_bsi['lfemixlevcod'] = $this->readHeaderBSI(5); 242 } 243 } 244 if ($thisfile_ac3_raw_bsi['strmtyp'] == 0) { // if independent stream 245 $thisfile_ac3_raw_bsi['flags']['pgmscl'] = (bool) $this->readHeaderBSI(1); 246 if ($thisfile_ac3_raw_bsi['flags']['pgmscl']) { 247 $thisfile_ac3_raw_bsi['pgmscl'] = $this->readHeaderBSI(6); 248 } 249 if ($thisfile_ac3_raw_bsi['acmod'] == 0) { // if 1+1 mode (dual mono, so some items need a second value) 250 $thisfile_ac3_raw_bsi['flags']['pgmscl2'] = (bool) $this->readHeaderBSI(1); 251 if ($thisfile_ac3_raw_bsi['flags']['pgmscl2']) { 252 $thisfile_ac3_raw_bsi['pgmscl2'] = $this->readHeaderBSI(6); 253 } 254 } 255 $thisfile_ac3_raw_bsi['flags']['extpgmscl'] = (bool) $this->readHeaderBSI(1); 256 if ($thisfile_ac3_raw_bsi['flags']['extpgmscl']) { 257 $thisfile_ac3_raw_bsi['extpgmscl'] = $this->readHeaderBSI(6); 258 } 259 $thisfile_ac3_raw_bsi['mixdef'] = $this->readHeaderBSI(2); 260 if ($thisfile_ac3_raw_bsi['mixdef'] == 1) { // mixing option 2 261 $thisfile_ac3_raw_bsi['premixcmpsel'] = (bool) $this->readHeaderBSI(1); 262 $thisfile_ac3_raw_bsi['drcsrc'] = (bool) $this->readHeaderBSI(1); 263 $thisfile_ac3_raw_bsi['premixcmpscl'] = $this->readHeaderBSI(3); 264 } elseif ($thisfile_ac3_raw_bsi['mixdef'] == 2) { // mixing option 3 265 $thisfile_ac3_raw_bsi['mixdata'] = $this->readHeaderBSI(12); 266 } elseif ($thisfile_ac3_raw_bsi['mixdef'] == 3) { // mixing option 4 267 $mixdefbitsread = 0; 268 $thisfile_ac3_raw_bsi['mixdeflen'] = $this->readHeaderBSI(5); $mixdefbitsread += 5; 269 $thisfile_ac3_raw_bsi['flags']['mixdata2'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1; 270 if ($thisfile_ac3_raw_bsi['flags']['mixdata2']) { 271 $thisfile_ac3_raw_bsi['premixcmpsel'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1; 272 $thisfile_ac3_raw_bsi['drcsrc'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1; 273 $thisfile_ac3_raw_bsi['premixcmpscl'] = $this->readHeaderBSI(3); $mixdefbitsread += 3; 274 $thisfile_ac3_raw_bsi['flags']['extpgmlscl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1; 275 if ($thisfile_ac3_raw_bsi['flags']['extpgmlscl']) { 276 $thisfile_ac3_raw_bsi['extpgmlscl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4; 277 } 278 $thisfile_ac3_raw_bsi['flags']['extpgmcscl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1; 279 if ($thisfile_ac3_raw_bsi['flags']['extpgmcscl']) { 280 $thisfile_ac3_raw_bsi['extpgmcscl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4; 281 } 282 $thisfile_ac3_raw_bsi['flags']['extpgmrscl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1; 283 if ($thisfile_ac3_raw_bsi['flags']['extpgmrscl']) { 284 $thisfile_ac3_raw_bsi['extpgmrscl'] = $this->readHeaderBSI(4); 285 } 286 $thisfile_ac3_raw_bsi['flags']['extpgmlsscl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1; 287 if ($thisfile_ac3_raw_bsi['flags']['extpgmlsscl']) { 288 $thisfile_ac3_raw_bsi['extpgmlsscl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4; 289 } 290 $thisfile_ac3_raw_bsi['flags']['extpgmrsscl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1; 291 if ($thisfile_ac3_raw_bsi['flags']['extpgmrsscl']) { 292 $thisfile_ac3_raw_bsi['extpgmrsscl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4; 293 } 294 $thisfile_ac3_raw_bsi['flags']['extpgmlfescl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1; 295 if ($thisfile_ac3_raw_bsi['flags']['extpgmlfescl']) { 296 $thisfile_ac3_raw_bsi['extpgmlfescl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4; 297 } 298 $thisfile_ac3_raw_bsi['flags']['dmixscl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1; 299 if ($thisfile_ac3_raw_bsi['flags']['dmixscl']) { 300 $thisfile_ac3_raw_bsi['dmixscl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4; 301 } 302 $thisfile_ac3_raw_bsi['flags']['addch'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1; 303 if ($thisfile_ac3_raw_bsi['flags']['addch']) { 304 $thisfile_ac3_raw_bsi['flags']['extpgmaux1scl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1; 305 if ($thisfile_ac3_raw_bsi['flags']['extpgmaux1scl']) { 306 $thisfile_ac3_raw_bsi['extpgmaux1scl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4; 307 } 308 $thisfile_ac3_raw_bsi['flags']['extpgmaux2scl'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1; 309 if ($thisfile_ac3_raw_bsi['flags']['extpgmaux2scl']) { 310 $thisfile_ac3_raw_bsi['extpgmaux2scl'] = $this->readHeaderBSI(4); $mixdefbitsread += 4; 311 } 312 } 313 } 314 $thisfile_ac3_raw_bsi['flags']['mixdata3'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1; 315 if ($thisfile_ac3_raw_bsi['flags']['mixdata3']) { 316 $thisfile_ac3_raw_bsi['spchdat'] = $this->readHeaderBSI(5); $mixdefbitsread += 5; 317 $thisfile_ac3_raw_bsi['flags']['addspchdat'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1; 318 if ($thisfile_ac3_raw_bsi['flags']['addspchdat']) { 319 $thisfile_ac3_raw_bsi['spchdat1'] = $this->readHeaderBSI(5); $mixdefbitsread += 5; 320 $thisfile_ac3_raw_bsi['spchan1att'] = $this->readHeaderBSI(2); $mixdefbitsread += 2; 321 $thisfile_ac3_raw_bsi['flags']['addspchdat1'] = (bool) $this->readHeaderBSI(1); $mixdefbitsread += 1; 322 if ($thisfile_ac3_raw_bsi['flags']['addspchdat1']) { 323 $thisfile_ac3_raw_bsi['spchdat2'] = $this->readHeaderBSI(5); $mixdefbitsread += 5; 324 $thisfile_ac3_raw_bsi['spchan2att'] = $this->readHeaderBSI(3); $mixdefbitsread += 3; 325 } 326 } 327 } 328 $mixdata_bits = (8 * ($thisfile_ac3_raw_bsi['mixdeflen'] + 2)) - $mixdefbitsread; 329 $mixdata_fill = (($mixdata_bits % 8) ? 8 - ($mixdata_bits % 8) : 0); 330 $thisfile_ac3_raw_bsi['mixdata'] = $this->readHeaderBSI($mixdata_bits); 331 $thisfile_ac3_raw_bsi['mixdatafill'] = $this->readHeaderBSI($mixdata_fill); 332 unset($mixdefbitsread, $mixdata_bits, $mixdata_fill); 333 } 334 if ($thisfile_ac3_raw_bsi['acmod'] < 2) { // if mono or dual mono source 335 $thisfile_ac3_raw_bsi['flags']['paninfo'] = (bool) $this->readHeaderBSI(1); 336 if ($thisfile_ac3_raw_bsi['flags']['paninfo']) { 337 $thisfile_ac3_raw_bsi['panmean'] = $this->readHeaderBSI(8); 338 $thisfile_ac3_raw_bsi['paninfo'] = $this->readHeaderBSI(6); 339 } 340 if ($thisfile_ac3_raw_bsi['acmod'] == 0) { // if 1+1 mode (dual mono, so some items need a second value) 341 $thisfile_ac3_raw_bsi['flags']['paninfo2'] = (bool) $this->readHeaderBSI(1); 342 if ($thisfile_ac3_raw_bsi['flags']['paninfo2']) { 343 $thisfile_ac3_raw_bsi['panmean2'] = $this->readHeaderBSI(8); 344 $thisfile_ac3_raw_bsi['paninfo2'] = $this->readHeaderBSI(6); 345 } 346 } 347 } 348 $thisfile_ac3_raw_bsi['flags']['frmmixcfginfo'] = (bool) $this->readHeaderBSI(1); 349 if ($thisfile_ac3_raw_bsi['flags']['frmmixcfginfo']) { // mixing configuration information 350 if ($thisfile_ac3_raw_bsi['numblkscod'] == 0) { 351 $thisfile_ac3_raw_bsi['blkmixcfginfo'][0] = $this->readHeaderBSI(5); 352 } else { 353 for ($blk = 0; $blk < $thisfile_ac3_raw_bsi['numblkscod']; $blk++) { 354 $thisfile_ac3_raw_bsi['flags']['blkmixcfginfo'.$blk] = (bool) $this->readHeaderBSI(1); 355 if ($thisfile_ac3_raw_bsi['flags']['blkmixcfginfo'.$blk]) { // mixing configuration information 356 $thisfile_ac3_raw_bsi['blkmixcfginfo'][$blk] = $this->readHeaderBSI(5); 357 } 358 } 359 } 360 } 361 } 362 } 363 $thisfile_ac3_raw_bsi['flags']['infomdat'] = (bool) $this->readHeaderBSI(1); 364 if ($thisfile_ac3_raw_bsi['flags']['infomdat']) { // Informational metadata 365 $thisfile_ac3_raw_bsi['bsmod'] = $this->readHeaderBSI(3); 366 $thisfile_ac3_raw_bsi['flags']['copyrightb'] = (bool) $this->readHeaderBSI(1); 367 $thisfile_ac3_raw_bsi['flags']['origbs'] = (bool) $this->readHeaderBSI(1); 368 if ($thisfile_ac3_raw_bsi['acmod'] == 2) { // if in 2/0 mode 369 $thisfile_ac3_raw_bsi['dsurmod'] = $this->readHeaderBSI(2); 370 $thisfile_ac3_raw_bsi['dheadphonmod'] = $this->readHeaderBSI(2); 371 } 372 if ($thisfile_ac3_raw_bsi['acmod'] >= 6) { // if both surround channels exist 373 $thisfile_ac3_raw_bsi['dsurexmod'] = $this->readHeaderBSI(2); 374 } 375 $thisfile_ac3_raw_bsi['flags']['audprodi'] = (bool) $this->readHeaderBSI(1); 376 if ($thisfile_ac3_raw_bsi['flags']['audprodi']) { 377 $thisfile_ac3_raw_bsi['mixlevel'] = $this->readHeaderBSI(5); 378 $thisfile_ac3_raw_bsi['roomtyp'] = $this->readHeaderBSI(2); 379 $thisfile_ac3_raw_bsi['flags']['adconvtyp'] = (bool) $this->readHeaderBSI(1); 380 } 381 if ($thisfile_ac3_raw_bsi['acmod'] == 0) { // if 1+1 mode (dual mono, so some items need a second value) 382 $thisfile_ac3_raw_bsi['flags']['audprodi2'] = (bool) $this->readHeaderBSI(1); 383 if ($thisfile_ac3_raw_bsi['flags']['audprodi2']) { 384 $thisfile_ac3_raw_bsi['mixlevel2'] = $this->readHeaderBSI(5); 385 $thisfile_ac3_raw_bsi['roomtyp2'] = $this->readHeaderBSI(2); 386 $thisfile_ac3_raw_bsi['flags']['adconvtyp2'] = (bool) $this->readHeaderBSI(1); 387 } 388 } 389 if ($thisfile_ac3_raw_bsi['fscod'] < 3) { // if not half sample rate 390 $thisfile_ac3_raw_bsi['flags']['sourcefscod'] = (bool) $this->readHeaderBSI(1); 391 } 392 } 393 if (($thisfile_ac3_raw_bsi['strmtyp'] == 0) && ($thisfile_ac3_raw_bsi['numblkscod'] != 3)) { // if both surround channels exist 394 $thisfile_ac3_raw_bsi['flags']['convsync'] = (bool) $this->readHeaderBSI(1); 395 } 396 if ($thisfile_ac3_raw_bsi['strmtyp'] == 2) { // if bit stream converted from AC-3 397 if ($thisfile_ac3_raw_bsi['numblkscod'] != 3) { // 6 blocks per syncframe 398 $thisfile_ac3_raw_bsi['flags']['blkid'] = 1; 399 } else { 400 $thisfile_ac3_raw_bsi['flags']['blkid'] = (bool) $this->readHeaderBSI(1); 401 } 402 if ($thisfile_ac3_raw_bsi['flags']['blkid']) { 403 $thisfile_ac3_raw_bsi['frmsizecod'] = $this->readHeaderBSI(6); 404 } 405 } 406 $thisfile_ac3_raw_bsi['flags']['addbsi'] = (bool) $this->readHeaderBSI(1); 407 if ($thisfile_ac3_raw_bsi['flags']['addbsi']) { 408 $thisfile_ac3_raw_bsi['addbsil'] = $this->readHeaderBSI(6); 409 $thisfile_ac3_raw_bsi['addbsi'] = $this->readHeaderBSI(($thisfile_ac3_raw_bsi['addbsil'] + 1) * 8); 410 } 411 412 } else { 413 414 $this->error('Bit stream identification is version '.$thisfile_ac3_raw_bsi['bsid'].', but getID3() only understands up to version 16. Please submit a support ticket with a sample file.'); 99 415 unset($info['ac3']); 100 416 return false; 101 } 102 103 $thisfile_ac3_raw_bsi['bsmod'] = $this->readHeaderBSI(3); 104 $thisfile_ac3_raw_bsi['acmod'] = $this->readHeaderBSI(3); 417 418 } 419 420 if (isset($thisfile_ac3_raw_bsi['fscod2'])) { 421 $thisfile_ac3['sample_rate'] = self::sampleRateCodeLookup2($thisfile_ac3_raw_bsi['fscod2']); 422 } else { 423 $thisfile_ac3['sample_rate'] = self::sampleRateCodeLookup($thisfile_ac3_raw_bsi['fscod']); 424 } 425 if ($thisfile_ac3_raw_bsi['fscod'] <= 3) { 426 $info['audio']['sample_rate'] = $thisfile_ac3['sample_rate']; 427 } else { 428 $this->warning('Unexpected ac3.bsi.fscod value: '.$thisfile_ac3_raw_bsi['fscod']); 429 } 430 if (isset($thisfile_ac3_raw_bsi['frmsizecod'])) { 431 $thisfile_ac3['frame_length'] = self::frameSizeLookup($thisfile_ac3_raw_bsi['frmsizecod'], $thisfile_ac3_raw_bsi['fscod']); 432 $thisfile_ac3['bitrate'] = self::bitrateLookup($thisfile_ac3_raw_bsi['frmsizecod']); 433 } elseif (!empty($thisfile_ac3_raw_bsi['frmsiz'])) { 434 // this isn't right, but it's (usually) close, roughly 5% less than it should be. 435 // but WHERE is the actual bitrate value stored in EAC3?? email [email protected] if you know! 436 $thisfile_ac3['bitrate'] = ($thisfile_ac3_raw_bsi['frmsiz'] + 1) * 16 * 30; // The frmsiz field shall contain a value one less than the overall size of the coded syncframe in 16-bit words. That is, this field may assume a value ranging from 0 to 2047, and these values correspond to syncframe sizes ranging from 1 to 2048. 437 // kludge-fix to make it approximately the expected value, still not "right": 438 $thisfile_ac3['bitrate'] = round(($thisfile_ac3['bitrate'] * 1.05) / 16000) * 16000; 439 } 440 $info['audio']['bitrate'] = $thisfile_ac3['bitrate']; 105 441 106 442 $thisfile_ac3['service_type'] = self::serviceTypeLookup($thisfile_ac3_raw_bsi['bsmod'], $thisfile_ac3_raw_bsi['acmod']); … … 124 460 $info['audio']['channels'] = $thisfile_ac3['num_channels']; 125 461 126 if ($thisfile_ac3_raw_bsi['acmod'] & 0x01) { 127 // If the lsb of acmod is a 1, center channel is in use and cmixlev follows in the bit stream. 128 $thisfile_ac3_raw_bsi['cmixlev'] = $this->readHeaderBSI(2); 129 $thisfile_ac3['center_mix_level'] = self::centerMixLevelLookup($thisfile_ac3_raw_bsi['cmixlev']); 130 } 131 132 if ($thisfile_ac3_raw_bsi['acmod'] & 0x04) { 133 // If the msb of acmod is a 1, surround channels are in use and surmixlev follows in the bit stream. 134 $thisfile_ac3_raw_bsi['surmixlev'] = $this->readHeaderBSI(2); 135 $thisfile_ac3['surround_mix_level'] = self::surroundMixLevelLookup($thisfile_ac3_raw_bsi['surmixlev']); 136 } 137 138 if ($thisfile_ac3_raw_bsi['acmod'] == 0x02) { 139 // When operating in the two channel mode, this 2-bit code indicates whether or not the program has been encoded in Dolby Surround. 140 $thisfile_ac3_raw_bsi['dsurmod'] = $this->readHeaderBSI(2); 141 $thisfile_ac3['dolby_surround_mode'] = self::dolbySurroundModeLookup($thisfile_ac3_raw_bsi['dsurmod']); 142 } 143 144 $thisfile_ac3_raw_bsi['lfeon'] = (bool) $this->readHeaderBSI(1); 145 $thisfile_ac3['lfe_enabled'] = $thisfile_ac3_raw_bsi['lfeon']; 146 if ($thisfile_ac3_raw_bsi['lfeon']) { 147 //$info['audio']['channels']++; 462 $thisfile_ac3['lfe_enabled'] = $thisfile_ac3_raw_bsi['flags']['lfeon']; 463 if ($thisfile_ac3_raw_bsi['flags']['lfeon']) { 148 464 $info['audio']['channels'] .= '.1'; 149 465 } 150 466 151 $thisfile_ac3['channels_enabled'] = self::channelsEnabledLookup($thisfile_ac3_raw_bsi['acmod'], $thisfile_ac3_raw_bsi['lfeon']); 152 153 // This indicates how far the average dialogue level is below digital 100 percent. Valid values are 1-31. 154 // The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent. 155 $thisfile_ac3_raw_bsi['dialnorm'] = $this->readHeaderBSI(5); 467 $thisfile_ac3['channels_enabled'] = self::channelsEnabledLookup($thisfile_ac3_raw_bsi['acmod'], $thisfile_ac3_raw_bsi['flags']['lfeon']); 156 468 $thisfile_ac3['dialogue_normalization'] = '-'.$thisfile_ac3_raw_bsi['dialnorm'].'dB'; 157 158 $thisfile_ac3_raw_bsi['compre_flag'] = (bool) $this->readHeaderBSI(1);159 if ($thisfile_ac3_raw_bsi['compre_flag']) {160 $thisfile_ac3_raw_bsi['compr'] = $this->readHeaderBSI(8);161 $thisfile_ac3['heavy_compression'] = self::heavyCompression($thisfile_ac3_raw_bsi['compr']);162 }163 164 $thisfile_ac3_raw_bsi['langcode_flag'] = (bool) $this->readHeaderBSI(1);165 if ($thisfile_ac3_raw_bsi['langcode_flag']) {166 $thisfile_ac3_raw_bsi['langcod'] = $this->readHeaderBSI(8);167 }168 169 $thisfile_ac3_raw_bsi['audprodie'] = (bool) $this->readHeaderBSI(1);170 if ($thisfile_ac3_raw_bsi['audprodie']) {171 $thisfile_ac3_raw_bsi['mixlevel'] = $this->readHeaderBSI(5);172 $thisfile_ac3_raw_bsi['roomtyp'] = $this->readHeaderBSI(2);173 174 $thisfile_ac3['mixing_level'] = (80 + $thisfile_ac3_raw_bsi['mixlevel']).'dB';175 $thisfile_ac3['room_type'] = self::roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp']);176 }177 178 if ($thisfile_ac3_raw_bsi['acmod'] == 0x00) {179 // If acmod is 0, then two completely independent program channels (dual mono)180 // are encoded into the bit stream, and are referenced as Ch1, Ch2. In this case,181 // a number of additional items are present in BSI or audblk to fully describe Ch2.182 183 // This indicates how far the average dialogue level is below digital 100 percent. Valid values are 1-31.184 // The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent.185 $thisfile_ac3_raw_bsi['dialnorm2'] = $this->readHeaderBSI(5);186 $thisfile_ac3['dialogue_normalization2'] = '-'.$thisfile_ac3_raw_bsi['dialnorm2'].'dB';187 188 $thisfile_ac3_raw_bsi['compre_flag2'] = (bool) $this->readHeaderBSI(1);189 if ($thisfile_ac3_raw_bsi['compre_flag2']) {190 $thisfile_ac3_raw_bsi['compr2'] = $this->readHeaderBSI(8);191 $thisfile_ac3['heavy_compression2'] = self::heavyCompression($thisfile_ac3_raw_bsi['compr2']);192 }193 194 $thisfile_ac3_raw_bsi['langcode_flag2'] = (bool) $this->readHeaderBSI(1);195 if ($thisfile_ac3_raw_bsi['langcode_flag2']) {196 $thisfile_ac3_raw_bsi['langcod2'] = $this->readHeaderBSI(8);197 }198 199 $thisfile_ac3_raw_bsi['audprodie2'] = (bool) $this->readHeaderBSI(1);200 if ($thisfile_ac3_raw_bsi['audprodie2']) {201 $thisfile_ac3_raw_bsi['mixlevel2'] = $this->readHeaderBSI(5);202 $thisfile_ac3_raw_bsi['roomtyp2'] = $this->readHeaderBSI(2);203 204 $thisfile_ac3['mixing_level2'] = (80 + $thisfile_ac3_raw_bsi['mixlevel2']).'dB';205 $thisfile_ac3['room_type2'] = self::roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp2']);206 }207 208 }209 210 $thisfile_ac3_raw_bsi['copyright'] = (bool) $this->readHeaderBSI(1);211 212 $thisfile_ac3_raw_bsi['original'] = (bool) $this->readHeaderBSI(1);213 214 $thisfile_ac3_raw_bsi['timecode1_flag'] = (bool) $this->readHeaderBSI(1);215 if ($thisfile_ac3_raw_bsi['timecode1_flag']) {216 $thisfile_ac3_raw_bsi['timecode1'] = $this->readHeaderBSI(14);217 }218 219 $thisfile_ac3_raw_bsi['timecode2_flag'] = (bool) $this->readHeaderBSI(1);220 if ($thisfile_ac3_raw_bsi['timecode2_flag']) {221 $thisfile_ac3_raw_bsi['timecode2'] = $this->readHeaderBSI(14);222 }223 224 $thisfile_ac3_raw_bsi['addbsi_flag'] = (bool) $this->readHeaderBSI(1);225 if ($thisfile_ac3_raw_bsi['addbsi_flag']) {226 $thisfile_ac3_raw_bsi['addbsi_length'] = $this->readHeaderBSI(6);227 228 $this->AC3header['bsi'] .= getid3_lib::BigEndian2Bin($this->fread($thisfile_ac3_raw_bsi['addbsi_length']));229 230 $thisfile_ac3_raw_bsi['addbsi_data'] = substr($this->AC3header['bsi'], $this->BSIoffset, $thisfile_ac3_raw_bsi['addbsi_length'] * 8);231 $this->BSIoffset += $thisfile_ac3_raw_bsi['addbsi_length'] * 8;232 }233 469 234 470 return true; … … 250 486 ); 251 487 return (isset($sampleRateCodeLookup[$fscod]) ? $sampleRateCodeLookup[$fscod] : false); 488 } 489 490 public static function sampleRateCodeLookup2($fscod2) { 491 static $sampleRateCodeLookup2 = array( 492 0 => 24000, 493 1 => 22050, 494 2 => 16000, 495 3 => 'reserved' // If the reserved code is indicated, the decoder should not attempt to decode audio and should mute. 496 ); 497 return (isset($sampleRateCodeLookup2[$fscod2]) ? $sampleRateCodeLookup2[$fscod2] : false); 252 498 } 253 499 … … 410 656 411 657 public static function frameSizeLookup($frmsizecod, $fscod) { 412 $padding = (bool) ($frmsizecod % 2); 413 $framesizeid = floor($frmsizecod / 2); 658 // LSB is whether padding is used or not 659 $padding = (bool) ($frmsizecod & 0x01); 660 $framesizeid = ($frmsizecod & 0x3E) >> 1; 414 661 415 662 static $frameSizeLookup = array(); 416 663 if (empty($frameSizeLookup)) { 417 664 $frameSizeLookup = array ( 418 0 => array( 128, 138, 192),419 1 => array( 40, 160, 174, 240),420 2 => array( 48, 192, 208, 288),421 3 => array( 56, 224, 242, 336),422 4 => array( 64, 256, 278, 384),423 5 => array( 80, 320, 348, 480),424 6 => array( 96, 384, 416, 576),425 7 => array( 112, 448, 486, 672),426 8 => array( 128, 512, 556, 768),427 9 => array( 160, 640, 696, 960),428 10 => array( 192, 768, 834, 1152),429 11 => array( 224, 896, 974, 1344),430 12 => array( 256, 1024, 1114, 1536),431 13 => array( 320, 1280, 1392, 1920),432 14 => array( 384, 1536, 1670, 2304),433 15 => array( 448, 1792, 1950, 2688),434 16 => array( 512, 2048, 2228, 3072),435 17 => array( 576, 2304, 2506, 3456),436 18 => array( 640, 2560, 2786, 3840)665 0 => array( 128, 138, 192), // 32 kbps 666 1 => array( 160, 174, 240), // 40 kbps 667 2 => array( 192, 208, 288), // 48 kbps 668 3 => array( 224, 242, 336), // 56 kbps 669 4 => array( 256, 278, 384), // 64 kbps 670 5 => array( 320, 348, 480), // 80 kbps 671 6 => array( 384, 416, 576), // 96 kbps 672 7 => array( 448, 486, 672), // 112 kbps 673 8 => array( 512, 556, 768), // 128 kbps 674 9 => array( 640, 696, 960), // 160 kbps 675 10 => array( 768, 834, 1152), // 192 kbps 676 11 => array( 896, 974, 1344), // 224 kbps 677 12 => array(1024, 1114, 1536), // 256 kbps 678 13 => array(1280, 1392, 1920), // 320 kbps 679 14 => array(1536, 1670, 2304), // 384 kbps 680 15 => array(1792, 1950, 2688), // 448 kbps 681 16 => array(2048, 2228, 3072), // 512 kbps 682 17 => array(2304, 2506, 3456), // 576 kbps 683 18 => array(2560, 2786, 3840) // 640 kbps 437 684 ); 438 685 } … … 445 692 446 693 public static function bitrateLookup($frmsizecod) { 447 $framesizeid = floor($frmsizecod / 2); 694 // LSB is whether padding is used or not 695 $padding = (bool) ($frmsizecod & 0x01); 696 $framesizeid = ($frmsizecod & 0x3E) >> 1; 448 697 449 698 static $bitrateLookup = array( 450 0 =>32000,451 1 =>40000,452 2 =>48000,453 3 =>56000,454 4 =>64000,455 5 =>80000,456 6 =>96000,457 7=> 112000,458 8=> 128000,459 9=> 160000,699 0 => 32000, 700 1 => 40000, 701 2 => 48000, 702 3 => 56000, 703 4 => 64000, 704 5 => 80000, 705 6 => 96000, 706 7 => 112000, 707 8 => 128000, 708 9 => 160000, 460 709 10 => 192000, 461 710 11 => 224000, … … 466 715 16 => 512000, 467 716 17 => 576000, 468 18 => 640000 717 18 => 640000, 469 718 ); 470 719 return (isset($bitrateLookup[$framesizeid]) ? $bitrateLookup[$framesizeid] : false); 471 720 } 472 721 722 public static function blocksPerSyncFrame($numblkscod) { 723 static $blocksPerSyncFrameLookup = array( 724 0 => 1, 725 1 => 2, 726 2 => 3, 727 3 => 6, 728 ); 729 return (isset($blocksPerSyncFrameLookup[$numblkscod]) ? $blocksPerSyncFrameLookup[$numblkscod] : false); 730 } 731 473 732 474 733 } -
trunk/src/wp-includes/ID3/module.audio.mp3.php
r32979 r41196 35 35 if (!$this->getOnlyMPEGaudioInfo($info['avdataoffset'])) { 36 36 if ($this->allow_bruteforce) { 37 $ info['error'][] = 'Rescanning file in BruteForce mode';37 $this->error('Rescanning file in BruteForce mode'); 38 38 $this->getOnlyMPEGaudioInfoBruteForce($this->getid3->fp, $info); 39 39 } … … 73 73 74 74 } 75 $ info['warning'][] = $synchoffsetwarning;75 $this->warning($synchoffsetwarning); 76 76 77 77 } … … 135 135 136 136 default: 137 $ info['warning'][] = 'Expecting [audio][dataformat] to be mp1/mp2/mp3 when fileformat == mp3, [audio][dataformat] actually "'.$info['audio']['dataformat'].'"';137 $this->warning('Expecting [audio][dataformat] to be mp1/mp2/mp3 when fileformat == mp3, [audio][dataformat] actually "'.$info['audio']['dataformat'].'"'); 138 138 break; 139 139 } … … 425 425 426 426 if ($this->fseek($offset) != 0) { 427 $ info['error'][] = 'decodeMPEGaudioHeader() failed to seek to next offset at '.$offset;427 $this->error('decodeMPEGaudioHeader() failed to seek to next offset at '.$offset); 428 428 return false; 429 429 } … … 438 438 439 439 $head4 = substr($headerstring, 0, 4); 440 440 $head4_key = getid3_lib::PrintHexBytes($head4, true, false, false); 441 441 static $MPEGaudioHeaderDecodeCache = array(); 442 if (isset($MPEGaudioHeaderDecodeCache[$head4 ])) {443 $MPEGheaderRawArray = $MPEGaudioHeaderDecodeCache[$head4 ];442 if (isset($MPEGaudioHeaderDecodeCache[$head4_key])) { 443 $MPEGheaderRawArray = $MPEGaudioHeaderDecodeCache[$head4_key]; 444 444 } else { 445 445 $MPEGheaderRawArray = self::MPEGaudioHeaderDecode($head4); 446 $MPEGaudioHeaderDecodeCache[$head4 ] = $MPEGheaderRawArray;446 $MPEGaudioHeaderDecodeCache[$head4_key] = $MPEGheaderRawArray; 447 447 } 448 448 449 449 static $MPEGaudioHeaderValidCache = array(); 450 if (!isset($MPEGaudioHeaderValidCache[$head4 ])) { // Not in cache451 //$MPEGaudioHeaderValidCache[$head4 ] = self::MPEGaudioHeaderValid($MPEGheaderRawArray, false, true); // allow badly-formatted freeformat (from LAME 3.90 - 3.93.1)452 $MPEGaudioHeaderValidCache[$head4 ] = self::MPEGaudioHeaderValid($MPEGheaderRawArray, false, false);450 if (!isset($MPEGaudioHeaderValidCache[$head4_key])) { // Not in cache 451 //$MPEGaudioHeaderValidCache[$head4_key] = self::MPEGaudioHeaderValid($MPEGheaderRawArray, false, true); // allow badly-formatted freeformat (from LAME 3.90 - 3.93.1) 452 $MPEGaudioHeaderValidCache[$head4_key] = self::MPEGaudioHeaderValid($MPEGheaderRawArray, false, false); 453 453 } 454 454 … … 460 460 461 461 462 if ($MPEGaudioHeaderValidCache[$head4 ]) {462 if ($MPEGaudioHeaderValidCache[$head4_key]) { 463 463 $thisfile_mpeg_audio['raw'] = $MPEGheaderRawArray; 464 464 } else { 465 $ info['error'][] = 'Invalid MPEG audio header ('.getid3_lib::PrintHexBytes($head4).') at offset '.$offset;465 $this->error('Invalid MPEG audio header ('.getid3_lib::PrintHexBytes($head4).') at offset '.$offset); 466 466 return false; 467 467 } … … 491 491 if ($thisfile_mpeg_audio['raw']['bitrate'] == 15) { 492 492 // http://www.hydrogenaudio.org/?act=ST&f=16&t=9682&st=0 493 $ info['warning'][] = 'Invalid bitrate index (15), this is a known bug in free-format MP3s encoded by LAME v3.90 - 3.93.1';493 $this->warning('Invalid bitrate index (15), this is a known bug in free-format MP3s encoded by LAME v3.90 - 3.93.1'); 494 494 $thisfile_mpeg_audio['raw']['bitrate'] = 0; 495 495 } … … 513 513 // these are ok 514 514 } else { 515 $ info['error'][] = $thisfile_mpeg_audio['bitrate'].'kbps not allowed in Layer 2, '.$thisfile_mpeg_audio['channelmode'].'.';515 $this->error($thisfile_mpeg_audio['bitrate'].'kbps not allowed in Layer 2, '.$thisfile_mpeg_audio['channelmode'].'.'); 516 516 return false; 517 517 } … … 524 524 // these are ok 525 525 } else { 526 $ info['error'][] = intval(round($thisfile_mpeg_audio['bitrate'] / 1000)).'kbps not allowed in Layer 2, '.$thisfile_mpeg_audio['channelmode'].'.';526 $this->error(intval(round($thisfile_mpeg_audio['bitrate'] / 1000)).'kbps not allowed in Layer 2, '.$thisfile_mpeg_audio['channelmode'].'.'); 527 527 return false; 528 528 } … … 546 546 $nextframetestoffset = $offset + $thisfile_mpeg_audio['framelength']; 547 547 } else { 548 $ info['error'][] = 'Frame at offset('.$offset.') is has an invalid frame length.';548 $this->error('Frame at offset('.$offset.') is has an invalid frame length.'); 549 549 return false; 550 550 } … … 649 649 650 650 //if (($thisfile_mpeg_audio['bitrate'] == 'free') && !empty($thisfile_mpeg_audio['VBR_frames']) && !empty($thisfile_mpeg_audio['VBR_bytes'])) { 651 if (!empty($thisfile_mpeg_audio['VBR_frames']) && !empty($thisfile_mpeg_audio['VBR_bytes'])) { 652 653 $framelengthfloat = $thisfile_mpeg_audio['VBR_bytes'] / $thisfile_mpeg_audio['VBR_frames']; 651 //if (!empty($thisfile_mpeg_audio['VBR_frames']) && !empty($thisfile_mpeg_audio['VBR_bytes'])) { 652 if (!empty($thisfile_mpeg_audio['VBR_frames'])) { 653 $used_filesize = 0; 654 if (!empty($thisfile_mpeg_audio['VBR_bytes'])) { 655 $used_filesize = $thisfile_mpeg_audio['VBR_bytes']; 656 } elseif (!empty($info['filesize'])) { 657 $used_filesize = $info['filesize']; 658 $used_filesize -= intval(@$info['id3v2']['headerlength']); 659 $used_filesize -= (isset($info['id3v1']) ? 128 : 0); 660 $used_filesize -= (isset($info['tag_offset_end']) ? $info['tag_offset_end'] - $info['tag_offset_start'] : 0); 661 $this->warning('MP3.Xing header missing VBR_bytes, assuming MPEG audio portion of file is '.number_format($used_filesize).' bytes'); 662 } 663 664 $framelengthfloat = $used_filesize / $thisfile_mpeg_audio['VBR_frames']; 654 665 655 666 if ($thisfile_mpeg_audio['layer'] == '1') { … … 838 849 $thisfile_mpeg_audio_lame['preset_used'] = self::LAMEpresetUsedLookup($thisfile_mpeg_audio_lame); 839 850 if (!empty($thisfile_mpeg_audio_lame['preset_used_id']) && empty($thisfile_mpeg_audio_lame['preset_used'])) { 840 $ info['warning'][] = 'Unknown LAME preset used ('.$thisfile_mpeg_audio_lame['preset_used_id'].') - please report to [email protected]';851 $this->warning('Unknown LAME preset used ('.$thisfile_mpeg_audio_lame['preset_used_id'].') - please report to [email protected]'); 841 852 } 842 853 if (($thisfile_mpeg_audio_lame['short_version'] == 'LAME3.90.') && !empty($thisfile_mpeg_audio_lame['preset_used_id'])) { … … 882 893 } 883 894 if ($thisfile_mpeg_audio['bitrate_mode'] == 'vbr') { 884 $ info['warning'][] = 'VBR file with no VBR header. Bitrate values calculated from actual frame bitrates.';895 $this->warning('VBR file with no VBR header. Bitrate values calculated from actual frame bitrates.'); 885 896 } 886 897 } … … 909 920 // if ($PossibleNullByte === "\x00") { 910 921 $info['avdataend']--; 911 // $ info['warning'][] = 'Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored';922 // $this->warning('Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored'); 912 923 // } else { 913 // $ info['warning'][] = 'Too much data in file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset']).' ('.(($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes).' bytes too many)';924 // $this->warning('Too much data in file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset']).' ('.(($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes).' bytes too many)'); 914 925 // } 915 926 } else { 916 $ info['warning'][] = 'Too much data in file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset']).' ('.(($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes).' bytes too many)';927 $this->warning('Too much data in file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset']).' ('.(($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes).' bytes too many)'); 917 928 } 918 929 } … … 932 943 } 933 944 } else { 934 $ info['error'][] = 'Error calculating frame length of free-format MP3 without Xing/LAME header';945 $this->error('Error calculating frame length of free-format MP3 without Xing/LAME header'); 935 946 } 936 947 } … … 949 960 $thisfile_mpeg_audio['VBR_bitrate'] = (isset($thisfile_mpeg_audio['VBR_bytes']) ? (($thisfile_mpeg_audio['VBR_bytes'] / $thisfile_mpeg_audio['VBR_frames']) * 8) * ($info['audio']['sample_rate'] / $bytes_per_frame) : 0); 950 961 if ($thisfile_mpeg_audio['VBR_bitrate'] > 0) { 951 $info['audio']['bitrate'] = $thisfile_mpeg_audio['VBR_bitrate'];962 $info['audio']['bitrate'] = $thisfile_mpeg_audio['VBR_bitrate']; 952 963 $thisfile_mpeg_audio['bitrate'] = $thisfile_mpeg_audio['VBR_bitrate']; // to avoid confusion 953 964 } … … 1075 1086 public function RecursiveFrameScanning(&$offset, &$nextframetestoffset, $ScanAsCBR) { 1076 1087 $info = &$this->getid3->info; 1077 $firstframetestarray = array('error' =>'', 'warning'=>'', 'avdataend'=>$info['avdataend'], 'avdataoffset'=>$info['avdataoffset']);1088 $firstframetestarray = array('error' => array(), 'warning'=> array(), 'avdataend' => $info['avdataend'], 'avdataoffset' => $info['avdataoffset']); 1078 1089 $this->decodeMPEGaudioHeader($offset, $firstframetestarray, false); 1079 1090 … … 1085 1096 } 1086 1097 1087 $nextframetestarray = array('error' =>'', 'warning'=>'', 'avdataend'=>$info['avdataend'], 'avdataoffset'=>$info['avdataoffset']);1098 $nextframetestarray = array('error' => array(), 'warning' => array(), 'avdataend' => $info['avdataend'], 'avdataoffset'=>$info['avdataoffset']); 1088 1099 if ($this->decodeMPEGaudioHeader($nextframetestoffset, $nextframetestarray, false)) { 1089 1100 if ($ScanAsCBR) { … … 1099 1110 $nextframetestoffset += $nextframetestarray['mpeg']['audio']['framelength']; 1100 1111 } else { 1101 $ info['error'][] = 'Frame at offset ('.$offset.') is has an invalid frame length.';1112 $this->error('Frame at offset ('.$offset.') is has an invalid frame length.'); 1102 1113 return false; 1103 1114 } … … 1111 1122 1112 1123 // next frame is not valid, note the error and fail, so scanning can contiue for a valid frame sequence 1113 $ info['warning'][] = 'Frame at offset ('.$offset.') is valid, but the next one at ('.$nextframetestoffset.') is not.';1124 $this->warning('Frame at offset ('.$offset.') is valid, but the next one at ('.$nextframetestoffset.') is not.'); 1114 1125 1115 1126 return false; … … 1154 1165 } 1155 1166 if (!$framelength) { 1156 $ info['error'][] = 'Cannot find next free-format synch pattern ('.getid3_lib::PrintHexBytes($SyncPattern1).' or '.getid3_lib::PrintHexBytes($SyncPattern2).') after offset '.$offset;1167 $this->error('Cannot find next free-format synch pattern ('.getid3_lib::PrintHexBytes($SyncPattern1).' or '.getid3_lib::PrintHexBytes($SyncPattern2).') after offset '.$offset); 1157 1168 return false; 1158 1169 } else { 1159 $ info['warning'][] = 'ModeExtension varies between first frame and other frames (known free-format issue in LAME 3.88)';1170 $this->warning('ModeExtension varies between first frame and other frames (known free-format issue in LAME 3.88)'); 1160 1171 $info['audio']['codec'] = 'LAME'; 1161 1172 $info['audio']['encoder'] = 'LAME3.88'; … … 1184 1195 $nextoffset++; 1185 1196 } else { 1186 $ info['error'][] = 'Did not find expected free-format sync pattern at offset '.$nextoffset;1197 $this->error('Did not find expected free-format sync pattern at offset '.$nextoffset); 1187 1198 return false; 1188 1199 } … … 1282 1293 if ($max_frames_scan && (++$frames_scanned >= $max_frames_scan)) { 1283 1294 $pct_data_scanned = ($this->ftell() - $info['avdataoffset']) / ($info['avdataend'] - $info['avdataoffset']); 1284 $ info['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.';1295 $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.'); 1285 1296 foreach ($Distribution as $key1 => $value1) { 1286 1297 foreach ($value1 as $key2 => $value2) { … … 1309 1320 $info['mpeg']['audio']['padding_distribution'] = $Distribution['padding']; 1310 1321 if (count($Distribution['version']) > 1) { 1311 $ info['error'][] = 'Corrupt file - more than one MPEG version detected';1322 $this->error('Corrupt file - more than one MPEG version detected'); 1312 1323 } 1313 1324 if (count($Distribution['layer']) > 1) { 1314 $ info['error'][] = 'Corrupt file - more than one MPEG layer detected';1325 $this->error('Corrupt file - more than one MPEG layer detected'); 1315 1326 } 1316 1327 if (count($Distribution['frequency']) > 1) { 1317 $ info['error'][] = 'Corrupt file - more than one MPEG sample rate detected';1328 $this->error('Corrupt file - more than one MPEG sample rate detected'); 1318 1329 } 1319 1330 … … 1327 1338 $info['mpeg']['audio']['frame_count'] = array_sum($Distribution['bitrate']); 1328 1339 if ($info['mpeg']['audio']['frame_count'] == 0) { 1329 $ info['error'][] = 'no MPEG audio frames found';1340 $this->error('no MPEG audio frames found'); 1330 1341 return false; 1331 1342 } … … 1362 1373 $sync_seek_buffer_size = min(128 * 1024, $info['avdataend'] - $avdataoffset); 1363 1374 if ($sync_seek_buffer_size <= 0) { 1364 $ info['error'][] = 'Invalid $sync_seek_buffer_size at offset '.$avdataoffset;1375 $this->error('Invalid $sync_seek_buffer_size at offset '.$avdataoffset); 1365 1376 return false; 1366 1377 } … … 1373 1384 if ($SynchSeekOffset > $sync_seek_buffer_size) { 1374 1385 // if a synch's not found within the first 128k bytes, then give up 1375 $ info['error'][] = 'Could not find valid MPEG audio synch within the first '.round($sync_seek_buffer_size / 1024).'kB';1386 $this->error('Could not find valid MPEG audio synch within the first '.round($sync_seek_buffer_size / 1024).'kB'); 1376 1387 if (isset($info['audio']['bitrate'])) { 1377 1388 unset($info['audio']['bitrate']); … … 1387 1398 } elseif (feof($this->getid3->fp)) { 1388 1399 1389 $ info['error'][] = 'Could not find valid MPEG audio synch before end of file';1400 $this->error('Could not find valid MPEG audio synch before end of file'); 1390 1401 if (isset($info['audio']['bitrate'])) { 1391 1402 unset($info['audio']['bitrate']); … … 1402 1413 1403 1414 if (($SynchSeekOffset + 1) >= strlen($header)) { 1404 $ info['error'][] = 'Could not find valid MPEG synch before end of file';1415 $this->error('Could not find valid MPEG synch before end of file'); 1405 1416 return false; 1406 1417 } … … 1445 1456 $info = $dummy; 1446 1457 $info['avdataoffset'] = $GarbageOffsetEnd; 1447 $ info['warning'][] = 'apparently-valid VBR header not used because could not find '.GETID3_MP3_VALID_CHECK_FRAMES.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.'), but did find valid CBR stream starting at '.$GarbageOffsetEnd;1458 $this->warning('apparently-valid VBR header not used because could not find '.GETID3_MP3_VALID_CHECK_FRAMES.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.'), but did find valid CBR stream starting at '.$GarbageOffsetEnd); 1448 1459 } else { 1449 $ info['warning'][] = 'using data from VBR header even though could not find '.GETID3_MP3_VALID_CHECK_FRAMES.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.')';1460 $this->warning('using data from VBR header even though could not find '.GETID3_MP3_VALID_CHECK_FRAMES.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.')'); 1450 1461 } 1451 1462 } … … 1540 1551 } 1541 1552 if ($pct_data_scanned > 0) { 1542 $ info['warning'][] = 'too many MPEG audio frames to scan, only scanned '.$frames_scanned.' frames in '.$max_scan_segments.' segments ('.number_format($pct_data_scanned * 100, 1).'% of file) and extrapolated distribution, playtime and bitrate may be incorrect.';1553 $this->warning('too many MPEG audio frames to scan, only scanned '.$frames_scanned.' frames in '.$max_scan_segments.' segments ('.number_format($pct_data_scanned * 100, 1).'% of file) and extrapolated distribution, playtime and bitrate may be incorrect.'); 1543 1554 foreach ($info['mpeg']['audio'] as $key1 => $value1) { 1544 1555 if (!preg_match('#_distribution$#i', $key1)) { … … 1552 1563 1553 1564 if ($SynchErrorsFound > 0) { 1554 $ info['warning'][] = 'Found '.$SynchErrorsFound.' synch errors in histogram analysis';1565 $this->warning('Found '.$SynchErrorsFound.' synch errors in histogram analysis'); 1555 1566 //return false; 1556 1567 } … … 1565 1576 } 1566 1577 if ($framecounter == 0) { 1567 $ info['error'][] = 'Corrupt MP3 file: framecounter == zero';1578 $this->error('Corrupt MP3 file: framecounter == zero'); 1568 1579 return false; 1569 1580 } … … 1600 1611 if (empty($info['mpeg']['audio'])) { 1601 1612 1602 $ info['error'][] = 'could not find valid MPEG synch before end of file';1613 $this->error('could not find valid MPEG synch before end of file'); 1603 1614 if (isset($info['audio']['bitrate'])) { 1604 1615 unset($info['audio']['bitrate']); -
trunk/src/wp-includes/ID3/module.audio.ogg.php
r32979 r41196 27 27 // Warn about illegal tags - only vorbiscomments are allowed 28 28 if (isset($info['id3v2'])) { 29 $ info['warning'][] = 'Illegal ID3v2 tag present.';29 $this->warning('Illegal ID3v2 tag present.'); 30 30 } 31 31 if (isset($info['id3v1'])) { 32 $ info['warning'][] = 'Illegal ID3v1 tag present.';32 $this->warning('Illegal ID3v1 tag present.'); 33 33 } 34 34 if (isset($info['ape'])) { 35 $ info['warning'][] = 'Illegal APE tag present.';35 $this->warning('Illegal APE tag present.'); 36 36 } 37 37 … … 45 45 46 46 if ($this->ftell() >= $this->getid3->fread_buffer_size()) { 47 $ info['error'][] = 'Could not find start of Ogg page in the first '.$this->getid3->fread_buffer_size().' bytes (this might not be an Ogg-Vorbis file?)';47 $this->error('Could not find start of Ogg page in the first '.$this->getid3->fread_buffer_size().' bytes (this might not be an Ogg-Vorbis file?)'); 48 48 unset($info['fileformat']); 49 49 unset($info['ogg']); … … 180 180 $info['video']['pixel_aspect_ratio'] = (float) $info['ogg']['pageheader']['theora']['pixel_aspect_numerator'] / $info['ogg']['pageheader']['theora']['pixel_aspect_denominator']; 181 181 } 182 $ info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of getID3 ['.$this->getid3->version().'] -- bitrate, playtime and all audio data are currently unavailable';182 $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'); 183 183 184 184 … … 241 241 242 242 $info['video']['dataformat'] = 'theora1'; 243 $ info['error'][] = 'Ogg Theora (v1) not correctly handled in this version of getID3 ['.$this->getid3->version().']';243 $this->error('Ogg Theora (v1) not correctly handled in this version of getID3 ['.$this->getid3->version().']'); 244 244 //break; 245 245 … … 249 249 250 250 } else { 251 $ info['error'][] = 'unexpected';251 $this->error('unexpected'); 252 252 //break; 253 253 } … … 257 257 $this->fseek($oggpageinfo['page_start_offset']); 258 258 259 $ info['error'][] = 'Ogg Skeleton not correctly handled in this version of getID3 ['.$this->getid3->version().']';259 $this->error('Ogg Skeleton not correctly handled in this version of getID3 ['.$this->getid3->version().']'); 260 260 //return false; 261 261 262 262 } else { 263 263 264 $ info['error'][] = 'Expecting either "Speex ", "OpusHead" or "vorbis" identifier strings, found "'.substr($filedata, 0, 8).'"';264 $this->error('Expecting either "Speex ", "OpusHead" or "vorbis" identifier strings, found "'.substr($filedata, 0, 8).'"'); 265 265 unset($info['ogg']); 266 266 unset($info['mime_type']); … … 285 285 $flac = new getid3_flac($this->getid3); 286 286 if (!$flac->parseMETAdata()) { 287 $ info['error'][] = 'Failed to parse FLAC headers';287 $this->error('Failed to parse FLAC headers'); 288 288 return false; 289 289 } … … 300 300 $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['stream_type'] = substr($filedata, 0, 8); // hard-coded to 'OpusTags' 301 301 if(substr($filedata, 0, 8) != 'OpusTags') { 302 $ info['error'][] = 'Expected "OpusTags" as header but got "'.substr($filedata, 0, 8).'"';302 $this->error('Expected "OpusTags" as header but got "'.substr($filedata, 0, 8).'"'); 303 303 return false; 304 304 } … … 312 312 if (!getid3_lib::intValueSupported($info['avdataend'])) { 313 313 314 $ info['warning'][] = 'Unable to parse Ogg end chunk file (PHP does not support file operations beyond '.round(PHP_INT_MAX / 1073741824).'GB)';314 $this->warning('Unable to parse Ogg end chunk file (PHP does not support file operations beyond '.round(PHP_INT_MAX / 1073741824).'GB)'); 315 315 316 316 } else { … … 324 324 $info['ogg']['samples'] = $info['ogg']['pageheader']['eos']['pcm_abs_position']; 325 325 if ($info['ogg']['samples'] == 0) { 326 $ info['error'][] = 'Corrupt Ogg file: eos.number of samples == zero';326 $this->error('Corrupt Ogg file: eos.number of samples == zero'); 327 327 return false; 328 328 } … … 343 343 if (isset($info['audio']['bitrate']) && !isset($info['playtime_seconds'])) { 344 344 if ($info['audio']['bitrate'] == 0) { 345 $ info['error'][] = 'Corrupt Ogg file: bitrate_audio == zero';345 $this->error('Corrupt Ogg file: bitrate_audio == zero'); 346 346 return false; 347 347 } … … 396 396 $filedataoffset += 4; 397 397 if ($info['ogg']['samplerate'] == 0) { 398 $ info['error'][] = 'Corrupt Ogg file: sample rate == zero';398 $this->error('Corrupt Ogg file: sample rate == zero'); 399 399 return false; 400 400 } … … 444 444 445 445 if ($info['ogg']['pageheader']['opus']['version'] < 1 || $info['ogg']['pageheader']['opus']['version'] > 15) { 446 $ info['error'][] = 'Unknown opus version number (only accepting 1-15)';446 $this->error('Unknown opus version number (only accepting 1-15)'); 447 447 return false; 448 448 } … … 452 452 453 453 if ($info['ogg']['pageheader']['opus']['out_channel_count'] == 0) { 454 $ info['error'][] = 'Invalid channel count in opus header (must not be zero)';454 $this->error('Invalid channel count in opus header (must not be zero)'); 455 455 return false; 456 456 } … … 563 563 default: 564 564 return false; 565 break; 565 566 } 566 567 … … 581 582 if ($i >= 10000) { 582 583 // https://github.com/owncloud/music/issues/212#issuecomment-43082336 583 $ info['warning'][] = 'Unexpectedly large number ('.$CommentsCount.') of Ogg comments - breaking after reading '.$i.' comments';584 $this->warning('Unexpectedly large number ('.$CommentsCount.') of Ogg comments - breaking after reading '.$i.' comments'); 584 585 break; 585 586 } … … 619 620 while ((strlen($commentdata) - $commentdataoffset) < $ThisFileInfo_ogg_comments_raw[$i]['size']) { 620 621 if (($ThisFileInfo_ogg_comments_raw[$i]['size'] > $info['avdataend']) || ($ThisFileInfo_ogg_comments_raw[$i]['size'] < 0)) { 621 $ info['warning'][] = 'Invalid Ogg comment size (comment #'.$i.', claims to be '.number_format($ThisFileInfo_ogg_comments_raw[$i]['size']).' bytes) - aborting reading comments';622 $this->warning('Invalid Ogg comment size (comment #'.$i.', claims to be '.number_format($ThisFileInfo_ogg_comments_raw[$i]['size']).' bytes) - aborting reading comments'); 622 623 break 2; 623 624 } … … 643 644 //$commentdata .= $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']); 644 645 if (!isset($info['ogg']['pageheader'][$VorbisCommentPage])) { 645 $ info['warning'][] = 'undefined Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell();646 $this->warning('undefined Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell()); 646 647 break; 647 648 } 648 649 $readlength = self::OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1); 649 650 if ($readlength <= 0) { 650 $ info['warning'][] = 'invalid length Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell();651 $this->warning('invalid length Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell()); 651 652 break; 652 653 } … … 662 663 663 664 // no comment? 664 $ info['warning'][] = 'Blank Ogg comment ['.$i.']';665 $this->warning('Blank Ogg comment ['.$i.']'); 665 666 666 667 } elseif (strstr($commentstring, '=')) { … … 712 713 } else { 713 714 714 $ info['warning'][] = '[known problem with CDex >= v1.40, < v1.50b7] Invalid Ogg comment name/value pair ['.$i.']: '.$commentstring;715 $this->warning('[known problem with CDex >= v1.40, < v1.50b7] Invalid Ogg comment name/value pair ['.$i.']: '.$commentstring); 715 716 716 717 } -
trunk/src/wp-includes/ID3/module.tag.apetag.php
r32979 r41196 24 24 25 25 if (!getid3_lib::intValueSupported($info['filesize'])) { 26 $ info['warning'][] = 'Unable to check for APEtags because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB';26 $this->warning('Unable to check for APEtags because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB'); 27 27 return false; 28 28 } … … 73 73 $APEfooterData = $this->fread(32); 74 74 if (!($thisfile_ape['footer'] = $this->parseAPEheaderFooter($APEfooterData))) { 75 $ info['error'][] = 'Error parsing APE footer at offset '.$thisfile_ape['tag_offset_end'];75 $this->error('Error parsing APE footer at offset '.$thisfile_ape['tag_offset_end']); 76 76 return false; 77 77 } … … 89 89 90 90 if (isset($info['id3v1']['tag_offset_start']) && ($info['id3v1']['tag_offset_start'] < $thisfile_ape['tag_offset_end'])) { 91 $ info['warning'][] = 'ID3v1 tag information ignored since it appears to be a false synch in APEtag data';91 $this->warning('ID3v1 tag information ignored since it appears to be a false synch in APEtag data'); 92 92 unset($info['id3v1']); 93 93 foreach ($info['warning'] as $key => $value) { … … 105 105 $offset += $apetagheadersize; 106 106 } else { 107 $ info['error'][] = 'Error parsing APE header at offset '.$thisfile_ape['tag_offset_start'];107 $this->error('Error parsing APE header at offset '.$thisfile_ape['tag_offset_start']); 108 108 return false; 109 109 } … … 120 120 $offset += 4; 121 121 if (strstr(substr($APEtagData, $offset), "\x00") === false) { 122 $ info['error'][] = 'Cannot find null-byte (0x00) seperator between ItemKey #'.$i.' and value. ItemKey starts '.$offset.' bytes into the APE tag, at file offset '.($thisfile_ape['tag_offset_start'] + $offset);122 $this->error('Cannot find null-byte (0x00) separator between ItemKey #'.$i.' and value. ItemKey starts '.$offset.' bytes into the APE tag, at file offset '.($thisfile_ape['tag_offset_start'] + $offset)); 123 123 return false; 124 124 } … … 155 155 $thisfile_replaygain['track']['originator'] = 'unspecified'; 156 156 } else { 157 $ info['warning'][] = 'MP3gainTrackGain value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"';157 $this->warning('MP3gainTrackGain value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"'); 158 158 } 159 159 break; … … 164 164 $thisfile_replaygain['track']['originator'] = 'unspecified'; 165 165 if ($thisfile_replaygain['track']['peak'] <= 0) { 166 $ info['warning'][] = 'ReplayGain Track peak from APEtag appears invalid: '.$thisfile_replaygain['track']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")';167 } 168 } else { 169 $ info['warning'][] = 'MP3gainTrackPeak value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"';166 $this->warning('ReplayGain Track peak from APEtag appears invalid: '.$thisfile_replaygain['track']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")'); 167 } 168 } else { 169 $this->warning('MP3gainTrackPeak value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"'); 170 170 } 171 171 break; … … 176 176 $thisfile_replaygain['album']['originator'] = 'unspecified'; 177 177 } else { 178 $ info['warning'][] = 'MP3gainAlbumGain value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"';178 $this->warning('MP3gainAlbumGain value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"'); 179 179 } 180 180 break; … … 185 185 $thisfile_replaygain['album']['originator'] = 'unspecified'; 186 186 if ($thisfile_replaygain['album']['peak'] <= 0) { 187 $ info['warning'][] = 'ReplayGain Album peak from APEtag appears invalid: '.$thisfile_replaygain['album']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")';188 } 189 } else { 190 $ info['warning'][] = 'MP3gainAlbumPeak value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"';187 $this->warning('ReplayGain Album peak from APEtag appears invalid: '.$thisfile_replaygain['album']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")'); 188 } 189 } else { 190 $this->warning('MP3gainAlbumPeak value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"'); 191 191 } 192 192 break; … … 199 199 $thisfile_replaygain['mp3gain']['undo_wrap'] = (($mp3gain_undo_wrap == 'Y') ? true : false); 200 200 } else { 201 $ info['warning'][] = 'MP3gainUndo value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"';201 $this->warning('MP3gainUndo value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"'); 202 202 } 203 203 break; … … 209 209 $thisfile_replaygain['mp3gain']['globalgain_track_max'] = intval($mp3gain_globalgain_max); 210 210 } else { 211 $ info['warning'][] = 'MP3gainMinMax value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"';211 $this->warning('MP3gainMinMax value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"'); 212 212 } 213 213 break; … … 219 219 $thisfile_replaygain['mp3gain']['globalgain_album_max'] = intval($mp3gain_globalgain_album_max); 220 220 } else { 221 $ info['warning'][] = 'MP3gainAlbumMinMax value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"';221 $this->warning('MP3gainAlbumMinMax value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"'); 222 222 } 223 223 break; … … 254 254 // list of possible cover arts from http://taglib-sharp.sourcearchive.com/documentation/2.0.3.0-2/Ape_2Tag_8cs-source.html 255 255 if (is_array($thisfile_ape_items_current['data'])) { 256 $ info['warning'][] = 'APEtag "'.$item_key.'" should be flagged as Binary data, but was incorrectly flagged as UTF-8';256 $this->warning('APEtag "'.$item_key.'" should be flagged as Binary data, but was incorrectly flagged as UTF-8'); 257 257 $thisfile_ape_items_current['data'] = implode("\x00", $thisfile_ape_items_current['data']); 258 258 } … … 261 261 $thisfile_ape_items_current['data_length'] = strlen($thisfile_ape_items_current['data']); 262 262 263 $thisfile_ape_items_current['image_mime'] = '';264 $imageinfo = array();265 $imagechunkcheck = getid3_lib::GetDataImageSize($thisfile_ape_items_current['data'], $imageinfo);266 $thisfile_ape_items_current['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]);267 268 263 do { 264 $thisfile_ape_items_current['image_mime'] = ''; 265 $imageinfo = array(); 266 $imagechunkcheck = getid3_lib::GetDataImageSize($thisfile_ape_items_current['data'], $imageinfo); 267 if (($imagechunkcheck === false) || !isset($imagechunkcheck[2])) { 268 $this->warning('APEtag "'.$item_key.'" contains invalid image data'); 269 break; 270 } 271 $thisfile_ape_items_current['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]); 272 269 273 if ($this->inline_attachments === false) { 270 274 // skip entirely … … 277 281 if ($this->inline_attachments < $thisfile_ape_items_current['data_length']) { 278 282 // too big, skip 279 $ info['warning'][] = 'attachment at '.$thisfile_ape_items_current['offset'].' is too large to process inline ('.number_format($thisfile_ape_items_current['data_length']).' bytes)';283 $this->warning('attachment at '.$thisfile_ape_items_current['offset'].' is too large to process inline ('.number_format($thisfile_ape_items_current['data_length']).' bytes)'); 280 284 unset($thisfile_ape_items_current['data']); 281 285 break; … … 283 287 } elseif (is_string($this->inline_attachments)) { 284 288 $this->inline_attachments = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->inline_attachments), DIRECTORY_SEPARATOR); 285 if (!is_dir($this->inline_attachments) || ! is_writable($this->inline_attachments)) {289 if (!is_dir($this->inline_attachments) || !getID3::is_writable($this->inline_attachments)) { 286 290 // cannot write, skip 287 $ info['warning'][] = 'attachment at '.$thisfile_ape_items_current['offset'].' cannot be saved to "'.$this->inline_attachments.'" (not writable)';291 $this->warning('attachment at '.$thisfile_ape_items_current['offset'].' cannot be saved to "'.$this->inline_attachments.'" (not writable)'); 288 292 unset($thisfile_ape_items_current['data']); 289 293 break; … … 293 297 if (is_string($this->inline_attachments)) { 294 298 $destination_filename = $this->inline_attachments.DIRECTORY_SEPARATOR.md5($info['filenamepath']).'_'.$thisfile_ape_items_current['data_offset']; 295 if (!file_exists($destination_filename) || is_writable($destination_filename)) {299 if (!file_exists($destination_filename) || getID3::is_writable($destination_filename)) { 296 300 file_put_contents($destination_filename, $thisfile_ape_items_current['data']); 297 301 } else { 298 $ info['warning'][] = 'attachment at '.$thisfile_ape_items_current['offset'].' cannot be saved to "'.$destination_filename.'" (not writable)';302 $this->warning('attachment at '.$thisfile_ape_items_current['offset'].' cannot be saved to "'.$destination_filename.'" (not writable)'); 299 303 } 300 304 $thisfile_ape_items_current['data_filename'] = $destination_filename; -
trunk/src/wp-includes/ID3/module.tag.id3v1.php
r32979 r41196 23 23 24 24 if (!getid3_lib::intValueSupported($info['filesize'])) { 25 $ info['warning'][] = 'Unable to check for ID3v1 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB';25 $this->warning('Unable to check for ID3v1 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB'); 26 26 return false; 27 27 } … … 61 61 $ParsedID3v1['comments'][$key][0] = $value; 62 62 } 63 // ID3v1 encoding detection hack START 64 // ID3v1 is defined as always using ISO-8859-1 encoding, but it is not uncommon to find files tagged with ID3v1 using Windows-1251 or other character sets 65 // Since ID3v1 has no concept of character sets there is no certain way to know we have the correct non-ISO-8859-1 character set, but we can guess 66 $ID3v1encoding = 'ISO-8859-1'; 67 foreach ($ParsedID3v1['comments'] as $tag_key => $valuearray) { 68 foreach ($valuearray as $key => $value) { 69 if (preg_match('#^[\\x00-\\x40\\xA8\\B8\\x80-\\xFF]+$#', $value)) { 70 foreach (array('Windows-1251', 'KOI8-R') as $id3v1_bad_encoding) { 71 if (function_exists('mb_convert_encoding') && @mb_convert_encoding($value, $id3v1_bad_encoding, $id3v1_bad_encoding) === $value) { 72 $ID3v1encoding = $id3v1_bad_encoding; 73 break 3; 74 } elseif (function_exists('iconv') && @iconv($id3v1_bad_encoding, $id3v1_bad_encoding, $value) === $value) { 75 $ID3v1encoding = $id3v1_bad_encoding; 76 break 3; 77 } 78 } 79 } 80 } 81 } 82 // ID3v1 encoding detection hack END 63 83 64 84 // ID3v1 data is supposed to be padded with NULL characters, but some taggers pad with spaces … … 74 94 if ($id3v1tag !== $GoodFormatID3v1tag) { 75 95 $ParsedID3v1['padding_valid'] = false; 76 $ info['warning'][] = 'Some ID3v1 fields do not use NULL characters for padding';96 $this->warning('Some ID3v1 fields do not use NULL characters for padding'); 77 97 } 78 98 … … 81 101 82 102 $info['id3v1'] = $ParsedID3v1; 103 $info['id3v1']['encoding'] = $ID3v1encoding; 83 104 } 84 105 … … 96 117 } else { 97 118 // APE and Lyrics3 footers not found - assume double ID3v1 98 $ info['warning'][] = 'Duplicate ID3v1 tag detected - this has been known to happen with iTunes';119 $this->warning('Duplicate ID3v1 tag detected - this has been known to happen with iTunes'); 99 120 $info['avdataend'] -= 128; 100 121 } -
trunk/src/wp-includes/ID3/module.tag.id3v2.php
r32979 r41196 72 72 if ($id3v2_majorversion > 4) { // this script probably won't correctly parse ID3v2.5.x and above (if it ever exists) 73 73 74 $ info['error'][] = 'this script only parses up to ID3v2.4.x - this tag is ID3v2.'.$id3v2_majorversion.'.'.$thisfile_id3v2['minorversion'];74 $this->error('this script only parses up to ID3v2.4.x - this tag is ID3v2.'.$id3v2_majorversion.'.'.$thisfile_id3v2['minorversion']); 75 75 return false; 76 76 … … 242 242 243 243 if ($thisfile_id3v2['exthead']['length'] != $extended_header_offset) { 244 $ info['warning'][] = 'ID3v2.4 extended header length mismatch (expecting '.intval($thisfile_id3v2['exthead']['length']).', found '.intval($extended_header_offset).')';244 $this->warning('ID3v2.4 extended header length mismatch (expecting '.intval($thisfile_id3v2['exthead']['length']).', found '.intval($extended_header_offset).')'); 245 245 } 246 246 } … … 261 261 $thisfile_id3v2['padding']['valid'] = false; 262 262 $thisfile_id3v2['padding']['errorpos'] = $thisfile_id3v2['padding']['start'] + $i; 263 $ info['warning'][] = 'Invalid ID3v2 padding found at offset '.$thisfile_id3v2['padding']['errorpos'].' (the remaining '.($thisfile_id3v2['padding']['length'] - $i).' bytes are considered invalid)';263 $this->warning('Invalid ID3v2 padding found at offset '.$thisfile_id3v2['padding']['errorpos'].' (the remaining '.($thisfile_id3v2['padding']['length'] - $i).' bytes are considered invalid)'); 264 264 break; 265 265 } … … 301 301 // MP3ext known broken frames - "ok" for the purposes of this test 302 302 } elseif (($id3v2_majorversion == 4) && ($this->IsValidID3v2FrameName(substr($framedata, getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0), 4), 3))) { 303 $ info['warning'][] = 'ID3v2 tag written as ID3v2.4, but with non-synchsafe integers (ID3v2.3 style). Older versions of (Helium2; iTunes) are known culprits of this. Tag has been parsed as ID3v2.3';303 $this->warning('ID3v2 tag written as ID3v2.4, but with non-synchsafe integers (ID3v2.3 style). Older versions of (Helium2; iTunes) are known culprits of this. Tag has been parsed as ID3v2.3'); 304 304 $id3v2_majorversion = 3; 305 305 $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0); // 32-bit integer … … 323 323 $thisfile_id3v2['padding']['valid'] = false; 324 324 $thisfile_id3v2['padding']['errorpos'] = $thisfile_id3v2['padding']['start'] + $i; 325 $ info['warning'][] = 'Invalid ID3v2 padding found at offset '.$thisfile_id3v2['padding']['errorpos'].' (the remaining '.($thisfile_id3v2['padding']['length'] - $i).' bytes are considered invalid)';325 $this->warning('Invalid ID3v2 padding found at offset '.$thisfile_id3v2['padding']['errorpos'].' (the remaining '.($thisfile_id3v2['padding']['length'] - $i).' bytes are considered invalid)'); 326 326 break; 327 327 } … … 330 330 } 331 331 332 if ($ frame_name == 'COM ') {333 $ info['warning'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))). [Note: this particular error has been known to happen with tags edited by iTunes (versions "X v2.0.3", "v3.0.1" are known-guilty, probably others too)]';334 $frame_name = 'COMM';332 if ($iTunesBrokenFrameNameFixed = self::ID3v22iTunesBrokenFrameName($frame_name)) { 333 $this->warning('error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))). [Note: this particular error has been known to happen with tags edited by iTunes (versions "X v2.0.3", "v3.0.1", "v7.0.0.70" are known-guilty, probably others too)]. Translated frame name from "'.str_replace("\x00", ' ', $frame_name).'" to "'.$iTunesBrokenFrameNameFixed.'" for parsing.'); 334 $frame_name = $iTunesBrokenFrameNameFixed; 335 335 } 336 336 if (($frame_size <= strlen($framedata)) && ($this->IsValidID3v2FrameName($frame_name, $id3v2_majorversion))) { … … 356 356 // next frame is valid, just skip the current frame 357 357 $framedata = substr($framedata, $frame_size); 358 $ info['warning'][] = 'Next ID3v2 frame is valid, skipping current frame.';358 $this->warning('Next ID3v2 frame is valid, skipping current frame.'); 359 359 360 360 } else { … … 363 363 //unset($framedata); 364 364 $framedata = null; 365 $ info['error'][] = 'Next ID3v2 frame is also invalid, aborting processing.';365 $this->error('Next ID3v2 frame is also invalid, aborting processing.'); 366 366 367 367 } … … 370 370 371 371 // this is the last frame, just skip 372 $ info['warning'][] = 'This was the last ID3v2 frame.';372 $this->warning('This was the last ID3v2 frame.'); 373 373 374 374 } else { … … 377 377 //unset($framedata); 378 378 $framedata = null; 379 $ info['warning'][] = 'Invalid ID3v2 frame size, aborting.';379 $this->warning('Invalid ID3v2 frame size, aborting.'); 380 380 381 381 } … … 390 390 case ' MP': 391 391 case 'MP3': 392 $ info['warning'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: !IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))). [Note: this particular error has been known to happen with tags edited by "MP3ext (www.mutschler.de/mp3ext/)"]';392 $this->warning('error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: !IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))). [Note: this particular error has been known to happen with tags edited by "MP3ext (www.mutschler.de/mp3ext/)"]'); 393 393 break; 394 394 395 395 default: 396 $ info['warning'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: !IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))).';396 $this->warning('error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: !IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))).'); 397 397 break; 398 398 } … … 400 400 } elseif (!isset($framedata) || ($frame_size > strlen($framedata))) { 401 401 402 $ info['error'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: $frame_size ('.$frame_size.') > strlen($framedata) ('.(isset($framedata) ? strlen($framedata) : 'null').')).';402 $this->error('error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: $frame_size ('.$frame_size.') > strlen($framedata) ('.(isset($framedata) ? strlen($framedata) : 'null').')).'); 403 403 404 404 } else { 405 405 406 $ info['error'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag).';406 $this->error('error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag).'); 407 407 408 408 } … … 443 443 444 444 if (isset($thisfile_id3v2['comments']['genre'])) { 445 $genres = array(); 445 446 foreach ($thisfile_id3v2['comments']['genre'] as $key => $value) { 446 unset($thisfile_id3v2['comments']['genre'][$key]); 447 $thisfile_id3v2['comments'] = getid3_lib::array_merge_noclobber($thisfile_id3v2['comments'], array('genre'=>$this->ParseID3v2GenreString($value))); 448 } 447 foreach ($this->ParseID3v2GenreString($value) as $genre) { 448 $genres[] = $genre; 449 } 450 } 451 $thisfile_id3v2['comments']['genre'] = array_unique($genres); 452 unset($key, $value, $genres, $genre); 449 453 } 450 454 … … 501 505 // ID3v2.4.x: '21' $00 'Eurodisco' $00 502 506 $clean_genres = array(); 507 508 // hack-fixes for some badly-written ID3v2.3 taggers, while trying not to break correctly-written tags 509 if (($this->getid3->info['id3v2']['majorversion'] == 3) && !preg_match('#[\x00]#', $genrestring)) { 510 // note: MusicBrainz Picard incorrectly stores plaintext genres separated by "/" when writing in ID3v2.3 mode, hack-fix here: 511 // replace / with NULL, then replace back the two ID3v1 genres that legitimately have "/" as part of the single genre name 512 if (preg_match('#/#', $genrestring)) { 513 $genrestring = str_replace('/', "\x00", $genrestring); 514 $genrestring = str_replace('Pop'."\x00".'Funk', 'Pop/Funk', $genrestring); 515 $genrestring = str_replace('Rock'."\x00".'Rock', 'Folk/Rock', $genrestring); 516 } 517 518 // some other taggers separate multiple genres with semicolon, e.g. "Heavy Metal;Thrash Metal;Metal" 519 if (preg_match('#;#', $genrestring)) { 520 $genrestring = str_replace(';', "\x00", $genrestring); 521 } 522 } 523 524 503 525 if (strpos($genrestring, "\x00") === false) { 504 526 $genrestring = preg_replace('#\(([0-9]{1,3})\)#', '$1'."\x00", $genrestring); 505 527 } 528 506 529 $genre_elements = explode("\x00", $genrestring); 507 530 foreach ($genre_elements as $element) { … … 572 595 $parsedFrame['decompressed_size'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 0, 4)); 573 596 if (!function_exists('gzuncompress')) { 574 $ info['warning'][] = 'gzuncompress() support required to decompress ID3v2 frame "'.$parsedFrame['frame_name'].'"';597 $this->warning('gzuncompress() support required to decompress ID3v2 frame "'.$parsedFrame['frame_name'].'"'); 575 598 } else { 576 599 if ($decompresseddata = @gzuncompress(substr($parsedFrame['data'], 4))) { … … 579 602 unset($decompresseddata); 580 603 } else { 581 $ info['warning'][] = 'gzuncompress() failed on compressed contents of ID3v2 frame "'.$parsedFrame['frame_name'].'"';604 $this->warning('gzuncompress() failed on compressed contents of ID3v2 frame "'.$parsedFrame['frame_name'].'"'); 582 605 } 583 606 } … … 587 610 if (!empty($parsedFrame['flags']['DataLengthIndicator'])) { 588 611 if ($parsedFrame['data_length_indicator'] != strlen($parsedFrame['data'])) { 589 $ info['warning'][] = 'ID3v2 frame "'.$parsedFrame['frame_name'].'" should be '.$parsedFrame['data_length_indicator'].' bytes long according to DataLengthIndicator, but found '.strlen($parsedFrame['data']).' bytes of data';612 $this->warning('ID3v2 frame "'.$parsedFrame['frame_name'].'" should be '.$parsedFrame['data_length_indicator'].' bytes long according to DataLengthIndicator, but found '.strlen($parsedFrame['data']).' bytes of data'); 590 613 } 591 614 } … … 602 625 break; 603 626 } 604 $ info['warning'][] = $warning;627 $this->warning($warning); 605 628 606 629 } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'UFID')) || // 4.1 UFID Unique file identifier … … 628 651 $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding); 629 652 if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { 630 $ info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';653 $this->warning('Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'); 631 654 $frame_textencoding_terminator = "\x00"; 632 655 } … … 636 659 } 637 660 $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); 638 if (ord($frame_description) === 0) { 661 if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) { 662 // if description only contains a BOM or terminator then make it blank 639 663 $frame_description = ''; 640 664 } … … 665 689 $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); 666 690 if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { 667 $ info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';691 $this->warning('Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'); 668 692 } 669 693 … … 721 745 $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding); 722 746 if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { 723 $ info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';747 $this->warning('Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'); 724 748 $frame_textencoding_terminator = "\x00"; 725 749 } … … 729 753 } 730 754 $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); 731 732 if (ord($frame_description) === 0) {755 if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) { 756 // if description only contains a BOM or terminator then make it blank 733 757 $frame_description = ''; 734 758 } … … 784 808 $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); 785 809 if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { 786 $ info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';810 $this->warning('Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'); 787 811 } 788 812 $parsedFrame['encodingid'] = $frame_textencoding; … … 962 986 $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding); 963 987 if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { 964 $ info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';988 $this->warning('Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'); 965 989 $frame_textencoding_terminator = "\x00"; 966 990 } … … 972 996 } 973 997 $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); 974 if (ord($frame_description) === 0) { 998 if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) { 999 // if description only contains a BOM or terminator then make it blank 975 1000 $frame_description = ''; 976 1001 } … … 980 1005 $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); 981 1006 982 $parsedFrame['data'] = $parsedFrame['data'];983 1007 $parsedFrame['language'] = $frame_language; 984 1008 $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false); … … 1010 1034 $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding); 1011 1035 if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { 1012 $ info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';1036 $this->warning('Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'); 1013 1037 $frame_textencoding_terminator = "\x00"; 1014 1038 } … … 1062 1086 if (strlen($parsedFrame['data']) < 5) { 1063 1087 1064 $ info['warning'][] = 'Invalid data (too short) for "'.$parsedFrame['frame_name'].'" frame at offset '.$parsedFrame['dataoffset'];1088 $this->warning('Invalid data (too short) for "'.$parsedFrame['frame_name'].'" frame at offset '.$parsedFrame['dataoffset']); 1065 1089 1066 1090 } else { … … 1070 1094 $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding); 1071 1095 if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { 1072 $ info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';1096 $this->warning('Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'); 1073 1097 $frame_textencoding_terminator = "\x00"; 1074 1098 } … … 1080 1104 } 1081 1105 $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); 1082 if (ord($frame_description) === 0) { 1106 if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) { 1107 // if description only contains a BOM or terminator then make it blank 1083 1108 $frame_description = ''; 1084 1109 } … … 1133 1158 $parsedFrame[$RVA2channelcounter]['bitspeakvolume'] = ord(substr($frame_remainingdata, $frame_offset++, 1)); 1134 1159 if (($parsedFrame[$RVA2channelcounter]['bitspeakvolume'] < 1) || ($parsedFrame[$RVA2channelcounter]['bitspeakvolume'] > 4)) { 1135 $ info['warning'][] = 'ID3v2::RVA2 frame['.$RVA2channelcounter.'] contains invalid '.$parsedFrame[$RVA2channelcounter]['bitspeakvolume'].'-byte bits-representing-peak value';1160 $this->warning('ID3v2::RVA2 frame['.$RVA2channelcounter.'] contains invalid '.$parsedFrame[$RVA2channelcounter]['bitspeakvolume'].'-byte bits-representing-peak value'); 1136 1161 break; 1137 1162 } … … 1342 1367 $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding); 1343 1368 if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { 1344 $ info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';1369 $this->warning('Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'); 1345 1370 $frame_textencoding_terminator = "\x00"; 1346 1371 } … … 1377 1402 1378 1403 if ($frame_offset >= $parsedFrame['datalength']) { 1379 $ info['warning'][] = 'data portion of APIC frame is missing at offset '.($parsedFrame['dataoffset'] + 8 + $frame_offset);1404 $this->warning('data portion of APIC frame is missing at offset '.($parsedFrame['dataoffset'] + 8 + $frame_offset)); 1380 1405 } else { 1381 1406 $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset); … … 1384 1409 } 1385 1410 $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); 1386 if (ord($frame_description) === 0) { 1411 if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) { 1412 // if description only contains a BOM or terminator then make it blank 1387 1413 $frame_description = ''; 1388 1414 } … … 1403 1429 $parsedFrame['image_mime'] = ''; 1404 1430 $imageinfo = array(); 1405 $imagechunkcheck = getid3_lib::GetDataImageSize($parsedFrame['data'], $imageinfo); 1406 if (($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3)) { 1407 $parsedFrame['image_mime'] = 'image/'.getid3_lib::ImageTypesLookup($imagechunkcheck[2]); 1408 if ($imagechunkcheck[0]) { 1409 $parsedFrame['image_width'] = $imagechunkcheck[0]; 1410 } 1411 if ($imagechunkcheck[1]) { 1412 $parsedFrame['image_height'] = $imagechunkcheck[1]; 1431 if ($imagechunkcheck = getid3_lib::GetDataImageSize($parsedFrame['data'], $imageinfo)) { 1432 if (($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3)) { 1433 $parsedFrame['image_mime'] = 'image/'.getid3_lib::ImageTypesLookup($imagechunkcheck[2]); 1434 if ($imagechunkcheck[0]) { 1435 $parsedFrame['image_width'] = $imagechunkcheck[0]; 1436 } 1437 if ($imagechunkcheck[1]) { 1438 $parsedFrame['image_height'] = $imagechunkcheck[1]; 1439 } 1413 1440 } 1414 1441 } … … 1426 1453 if ($this->getid3->option_save_attachments < $parsedFrame['data_length']) { 1427 1454 // too big, skip 1428 $ info['warning'][] = 'attachment at '.$frame_offset.' is too large to process inline ('.number_format($parsedFrame['data_length']).' bytes)';1455 $this->warning('attachment at '.$frame_offset.' is too large to process inline ('.number_format($parsedFrame['data_length']).' bytes)'); 1429 1456 unset($parsedFrame['data']); 1430 1457 break; … … 1433 1460 } elseif (is_string($this->getid3->option_save_attachments)) { 1434 1461 $dir = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->getid3->option_save_attachments), DIRECTORY_SEPARATOR); 1435 if (!is_dir($dir) || ! is_writable($dir)) {1462 if (!is_dir($dir) || !getID3::is_writable($dir)) { 1436 1463 // cannot write, skip 1437 $ info['warning'][] = 'attachment at '.$frame_offset.' cannot be saved to "'.$dir.'" (not writable)';1464 $this->warning('attachment at '.$frame_offset.' cannot be saved to "'.$dir.'" (not writable)'); 1438 1465 unset($parsedFrame['data']); 1439 1466 break; … … 1443 1470 if (is_string($this->getid3->option_save_attachments)) { 1444 1471 $destination_filename = $dir.DIRECTORY_SEPARATOR.md5($info['filenamepath']).'_'.$frame_offset; 1445 if (!file_exists($destination_filename) || is_writable($destination_filename)) {1472 if (!file_exists($destination_filename) || getID3::is_writable($destination_filename)) { 1446 1473 file_put_contents($destination_filename, $parsedFrame['data']); 1447 1474 } else { 1448 $ info['warning'][] = 'attachment at '.$frame_offset.' cannot be saved to "'.$destination_filename.'" (not writable)';1475 $this->warning('attachment at '.$frame_offset.' cannot be saved to "'.$destination_filename.'" (not writable)'); 1449 1476 } 1450 1477 $parsedFrame['data_filename'] = $destination_filename; … … 1483 1510 $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding); 1484 1511 if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { 1485 $ info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';1512 $this->warning('Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'); 1486 1513 $frame_textencoding_terminator = "\x00"; 1487 1514 } … … 1508 1535 } 1509 1536 $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); 1510 if (ord($frame_description) === 0) { 1537 if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) { 1538 // if description only contains a BOM or terminator then make it blank 1511 1539 $frame_description = ''; 1512 1540 } … … 1590 1618 $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); 1591 1619 $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); 1592 if (ord($frame_description) === 0) { 1620 if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) { 1621 // if description only contains a BOM or terminator then make it blank 1593 1622 $frame_description = ''; 1594 1623 } … … 1615 1644 $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); 1616 1645 if (ord($frame_ownerid) === 0) { 1617 $frame_ownerid = ='';1646 $frame_ownerid = ''; 1618 1647 } 1619 1648 $frame_offset = $frame_terminatorpos + strlen("\x00"); … … 1684 1713 $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); 1685 1714 if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { 1686 $ info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';1715 $this->warning('Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'); 1687 1716 } 1688 1717 $frame_language = substr($parsedFrame['data'], $frame_offset, 3); … … 1711 1740 $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); 1712 1741 if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { 1713 $ info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';1742 $this->warning('Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'); 1714 1743 } 1715 1744 $parsedFrame['encodingid'] = $frame_textencoding; … … 1725 1754 1726 1755 $parsedFrame['purchasedate'] = substr($parsedFrame['data'], $frame_offset, 8); 1727 if ( !$this->IsValidDateStampString($parsedFrame['purchasedate'])) {1756 if ($this->IsValidDateStampString($parsedFrame['purchasedate'])) { 1728 1757 $parsedFrame['purchasedateunix'] = mktime (0, 0, 0, substr($parsedFrame['purchasedate'], 4, 2), substr($parsedFrame['purchasedate'], 6, 2), substr($parsedFrame['purchasedate'], 0, 4)); 1729 1758 } … … 1752 1781 $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding); 1753 1782 if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { 1754 $ info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';1783 $this->warning('Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'); 1755 1784 $frame_textencoding_terminator = "\x00"; 1756 1785 } … … 1790 1819 } 1791 1820 $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); 1792 if (ord($frame_description) === 0) { 1821 if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) { 1822 // if description only contains a BOM or terminator then make it blank 1793 1823 $frame_description = ''; 1794 1824 } … … 2007 2037 $frame_offset += 2; 2008 2038 if ($subframe['size'] > (strlen($parsedFrame['data']) - $frame_offset)) { 2009 $ info['warning'][] = 'CHAP subframe "'.$subframe['name'].'" at frame offset '.$frame_offset.' claims to be "'.$subframe['size'].'" bytes, which is more than the available data ('.(strlen($parsedFrame['data']) - $frame_offset).' bytes)';2039 $this->warning('CHAP subframe "'.$subframe['name'].'" at frame offset '.$frame_offset.' claims to be "'.$subframe['size'].'" bytes, which is more than the available data ('.(strlen($parsedFrame['data']) - $frame_offset).' bytes)'); 2010 2040 break; 2011 2041 } … … 2044 2074 $parsedFrame['subframes'][] = $subframe; 2045 2075 } else { 2046 $ info['warning'][] = 'ID3v2.CHAP subframe "'.$subframe['name'].'" not handled (only TIT2 and TIT3)';2076 $this->warning('ID3v2.CHAP subframe "'.$subframe['name'].'" not handled (only TIT2 and TIT3)'); 2047 2077 } 2048 2078 } … … 2104 2134 $frame_offset += 2; 2105 2135 if ($subframe['size'] > (strlen($parsedFrame['data']) - $frame_offset)) { 2106 $ info['warning'][] = 'CTOS subframe "'.$subframe['name'].'" at frame offset '.$frame_offset.' claims to be "'.$subframe['size'].'" bytes, which is more than the available data ('.(strlen($parsedFrame['data']) - $frame_offset).' bytes)';2136 $this->warning('CTOS subframe "'.$subframe['name'].'" at frame offset '.$frame_offset.' claims to be "'.$subframe['size'].'" bytes, which is more than the available data ('.(strlen($parsedFrame['data']) - $frame_offset).' bytes)'); 2107 2137 break; 2108 2138 } … … 2141 2171 $parsedFrame['subframes'][] = $subframe; 2142 2172 } else { 2143 $ info['warning'][] = 'ID3v2.CTOC subframe "'.$subframe['name'].'" not handled (only TIT2 and TIT3)';2173 $this->warning('ID3v2.CTOC subframe "'.$subframe['name'].'" not handled (only TIT2 and TIT3)'); 2144 2174 } 2145 2175 } … … 3624 3654 } 3625 3655 3656 public static function ID3v22iTunesBrokenFrameName($frame_name) { 3657 // iTunes (multiple versions) has been known to write ID3v2.3 style frames 3658 // but use ID3v2.2 frame names, right-padded using either [space] or [null] 3659 // to make them fit in the 4-byte frame name space of the ID3v2.3 frame. 3660 // This function will detect and translate the corrupt frame name into ID3v2.3 standard. 3661 static $ID3v22_iTunes_BrokenFrames = array( 3662 'BUF' => 'RBUF', // Recommended buffer size 3663 'CNT' => 'PCNT', // Play counter 3664 'COM' => 'COMM', // Comments 3665 'CRA' => 'AENC', // Audio encryption 3666 'EQU' => 'EQUA', // Equalisation 3667 'ETC' => 'ETCO', // Event timing codes 3668 'GEO' => 'GEOB', // General encapsulated object 3669 'IPL' => 'IPLS', // Involved people list 3670 'LNK' => 'LINK', // Linked information 3671 'MCI' => 'MCDI', // Music CD identifier 3672 'MLL' => 'MLLT', // MPEG location lookup table 3673 'PIC' => 'APIC', // Attached picture 3674 'POP' => 'POPM', // Popularimeter 3675 'REV' => 'RVRB', // Reverb 3676 'RVA' => 'RVAD', // Relative volume adjustment 3677 'SLT' => 'SYLT', // Synchronised lyric/text 3678 'STC' => 'SYTC', // Synchronised tempo codes 3679 'TAL' => 'TALB', // Album/Movie/Show title 3680 'TBP' => 'TBPM', // BPM (beats per minute) 3681 'TCM' => 'TCOM', // Composer 3682 'TCO' => 'TCON', // Content type 3683 'TCP' => 'TCMP', // Part of a compilation 3684 'TCR' => 'TCOP', // Copyright message 3685 'TDA' => 'TDAT', // Date 3686 'TDY' => 'TDLY', // Playlist delay 3687 'TEN' => 'TENC', // Encoded by 3688 'TFT' => 'TFLT', // File type 3689 'TIM' => 'TIME', // Time 3690 'TKE' => 'TKEY', // Initial key 3691 'TLA' => 'TLAN', // Language(s) 3692 'TLE' => 'TLEN', // Length 3693 'TMT' => 'TMED', // Media type 3694 'TOA' => 'TOPE', // Original artist(s)/performer(s) 3695 'TOF' => 'TOFN', // Original filename 3696 'TOL' => 'TOLY', // Original lyricist(s)/text writer(s) 3697 'TOR' => 'TORY', // Original release year 3698 'TOT' => 'TOAL', // Original album/movie/show title 3699 'TP1' => 'TPE1', // Lead performer(s)/Soloist(s) 3700 'TP2' => 'TPE2', // Band/orchestra/accompaniment 3701 'TP3' => 'TPE3', // Conductor/performer refinement 3702 'TP4' => 'TPE4', // Interpreted, remixed, or otherwise modified by 3703 'TPA' => 'TPOS', // Part of a set 3704 'TPB' => 'TPUB', // Publisher 3705 'TRC' => 'TSRC', // ISRC (international standard recording code) 3706 'TRD' => 'TRDA', // Recording dates 3707 'TRK' => 'TRCK', // Track number/Position in set 3708 'TS2' => 'TSO2', // Album-Artist sort order 3709 'TSA' => 'TSOA', // Album sort order 3710 'TSC' => 'TSOC', // Composer sort order 3711 'TSI' => 'TSIZ', // Size 3712 'TSP' => 'TSOP', // Performer sort order 3713 'TSS' => 'TSSE', // Software/Hardware and settings used for encoding 3714 'TST' => 'TSOT', // Title sort order 3715 'TT1' => 'TIT1', // Content group description 3716 'TT2' => 'TIT2', // Title/songname/content description 3717 'TT3' => 'TIT3', // Subtitle/Description refinement 3718 'TXT' => 'TEXT', // Lyricist/Text writer 3719 'TXX' => 'TXXX', // User defined text information frame 3720 'TYE' => 'TYER', // Year 3721 'UFI' => 'UFID', // Unique file identifier 3722 'ULT' => 'USLT', // Unsynchronised lyric/text transcription 3723 'WAF' => 'WOAF', // Official audio file webpage 3724 'WAR' => 'WOAR', // Official artist/performer webpage 3725 'WAS' => 'WOAS', // Official audio source webpage 3726 'WCM' => 'WCOM', // Commercial information 3727 'WCP' => 'WCOP', // Copyright/Legal information 3728 'WPB' => 'WPUB', // Publishers official webpage 3729 'WXX' => 'WXXX', // User defined URL link frame 3730 ); 3731 if (strlen($frame_name) == 4) { 3732 if ((substr($frame_name, 3, 1) == ' ') || (substr($frame_name, 3, 1) == "\x00")) { 3733 if (isset($ID3v22_iTunes_BrokenFrames[substr($frame_name, 0, 3)])) { 3734 return $ID3v22_iTunes_BrokenFrames[substr($frame_name, 0, 3)]; 3735 } 3736 } 3737 } 3738 return false; 3739 } 3740 3626 3741 } 3627 -
trunk/src/wp-includes/ID3/module.tag.lyrics3.php
r32979 r41196 25 25 26 26 if (!getid3_lib::intValueSupported($info['filesize'])) { 27 $ info['warning'][] = 'Unable to check for Lyrics3 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB';27 $this->warning('Unable to check for Lyrics3 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB'); 28 28 return false; 29 29 } … … 81 81 $info['avdataend'] = $lyrics3offset; 82 82 $lyrics3version = 1; 83 $ info['warning'][] = 'APE tag located after Lyrics3, will probably break Lyrics3 compatability';83 $this->warning('APE tag located after Lyrics3, will probably break Lyrics3 compatability'); 84 84 85 85 } elseif ($lyrics3end == 'LYRICS200') { … … 89 89 $lyrics3offset = $info['ape']['tag_offset_start'] - $lyrics3size; 90 90 $lyrics3version = 2; 91 $ info['warning'][] = 'APE tag located after Lyrics3, will probably break Lyrics3 compatability';91 $this->warning('APE tag located after Lyrics3, will probably break Lyrics3 compatability'); 92 92 93 93 } … … 118 118 unset($getid3_temp, $getid3_apetag); 119 119 } else { 120 $ info['warning'][] = 'Lyrics3 and APE tags appear to have become entangled (most likely due to updating the APE tags with a non-Lyrics3-aware tagger)';120 $this->warning('Lyrics3 and APE tags appear to have become entangled (most likely due to updating the APE tags with a non-Lyrics3-aware tagger)'); 121 121 } 122 122 } … … 133 133 134 134 if (!getid3_lib::intValueSupported($endoffset)) { 135 $ info['warning'][] = 'Unable to check for Lyrics3 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB';135 $this->warning('Unable to check for Lyrics3 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB'); 136 136 return false; 137 137 } … … 151 151 if (strpos($rawdata, 'LYRICSBEGIN') !== false) { 152 152 153 $ info['warning'][] = '"LYRICSBEGIN" expected at '.$endoffset.' but actually found at '.($endoffset + strpos($rawdata, 'LYRICSBEGIN')).' - this is invalid for Lyrics3 v'.$version;153 $this->warning('"LYRICSBEGIN" expected at '.$endoffset.' but actually found at '.($endoffset + strpos($rawdata, 'LYRICSBEGIN')).' - this is invalid for Lyrics3 v'.$version); 154 154 $info['avdataend'] = $endoffset + strpos($rawdata, 'LYRICSBEGIN'); 155 155 $rawdata = substr($rawdata, strpos($rawdata, 'LYRICSBEGIN')); … … 160 160 } else { 161 161 162 $ info['error'][] = '"LYRICSBEGIN" expected at '.$endoffset.' but found "'.substr($rawdata, 0, 11).'" instead';162 $this->error('"LYRICSBEGIN" expected at '.$endoffset.' but found "'.substr($rawdata, 0, 11).'" instead'); 163 163 return false; 164 164 … … 174 174 $this->Lyrics3LyricsTimestampParse($ParsedLyrics3); 175 175 } else { 176 $ info['error'][] = '"LYRICSEND" expected at '.($this->ftell() - 11 + $length - 9).' but found "'.substr($rawdata, strlen($rawdata) - 9, 9).'" instead';176 $this->error('"LYRICSEND" expected at '.($this->ftell() - 11 + $length - 9).' but found "'.substr($rawdata, strlen($rawdata) - 9, 9).'" instead'); 177 177 return false; 178 178 } … … 222 222 } 223 223 } else { 224 $ info['error'][] = '"LYRICS200" expected at '.($this->ftell() - 11 + $length - 9).' but found "'.substr($rawdata, strlen($rawdata) - 9, 9).'" instead';224 $this->error('"LYRICS200" expected at '.($this->ftell() - 11 + $length - 9).' but found "'.substr($rawdata, strlen($rawdata) - 9, 9).'" instead'); 225 225 return false; 226 226 } … … 228 228 229 229 default: 230 $ info['error'][] = 'Cannot process Lyrics3 version '.$version.' (only v1 and v2)';230 $this->error('Cannot process Lyrics3 version '.$version.' (only v1 and v2)'); 231 231 return false; 232 232 break; … … 235 235 236 236 if (isset($info['id3v1']['tag_offset_start']) && ($info['id3v1']['tag_offset_start'] <= $ParsedLyrics3['tag_offset_end'])) { 237 $ info['warning'][] = 'ID3v1 tag information ignored since it appears to be a false synch in Lyrics3 tag data';237 $this->warning('ID3v1 tag information ignored since it appears to be a false synch in Lyrics3 tag data'); 238 238 unset($info['id3v1']); 239 239 foreach ($info['warning'] as $key => $value) {
Note: See TracChangeset
for help on using the changeset viewer.