Ticket #54162: 54162.diff
File 54162.diff, 110.1 KB (added by , 22 months ago) |
---|
-
src/wp-admin/includes/media.php
3558 3558 require ABSPATH . WPINC . '/ID3/getid3.php'; 3559 3559 } 3560 3560 3561 $id3 = new getID3(); 3561 $id3 = new getID3(); 3562 // Required to get the `created_timestamp` value. 3563 $id3->options_audiovideo_quicktime_ReturnAtomData = true; // phpcs:ignore WordPress.NamingConventions.ValidVariableName 3564 3562 3565 $data = $id3->analyze( $file ); 3563 3566 3564 3567 if ( isset( $data['video']['lossless'] ) ) { … … 3669 3672 require ABSPATH . WPINC . '/ID3/getid3.php'; 3670 3673 } 3671 3674 3672 $id3 = new getID3(); 3675 $id3 = new getID3(); 3676 // Required to get the `created_timestamp` value. 3677 $id3->options_audiovideo_quicktime_ReturnAtomData = true; // phpcs:ignore WordPress.NamingConventions.ValidVariableName 3678 3673 3679 $data = $id3->analyze( $file ); 3674 3680 3675 3681 if ( ! empty( $data['audio'] ) ) { -
src/wp-includes/ID3/getid3.lib.php
242 242 /** 243 243 * ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic 244 244 * 245 * @link http ://www.psc.edu/general/software/packages/ieee/ieee.html245 * @link https://web.archive.org/web/20120325162206/http://www.psc.edu/general/software/packages/ieee/ieee.php 246 246 * @link http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html 247 247 * 248 248 * @param string $byteword … … 294 294 295 295 if (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction != 0)) { 296 296 // Not a Number 297 $floatvalue = false;297 $floatvalue = NAN; 298 298 } elseif (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction == 0)) { 299 299 if ($signbit == '1') { 300 $floatvalue = '-infinity';300 $floatvalue = -INF; 301 301 } else { 302 $floatvalue = '+infinity';302 $floatvalue = INF; 303 303 } 304 304 } elseif (($exponent == 0) && ($fraction == 0)) { 305 305 if ($signbit == '1') { … … 427 427 * @return string 428 428 */ 429 429 public static function Dec2Bin($number) { 430 if (!is_numeric($number)) { 431 // https://github.com/JamesHeinrich/getID3/issues/299 432 trigger_error('TypeError: Dec2Bin(): Argument #1 ($number) must be numeric, '.gettype($number).' given', E_USER_WARNING); 433 return ''; 434 } 435 $bytes = array(); 430 436 while ($number >= 256) { 431 $bytes[] = ( ($number / 256) - (floor($number / 256))) * 256;437 $bytes[] = (int) (($number / 256) - (floor($number / 256))) * 256; 432 438 $number = floor($number / 256); 433 439 } 434 $bytes[] = $number;440 $bytes[] = (int) $number; 435 441 $binstring = ''; 436 for ($i = 0; $i < count($bytes); $i++) {437 $binstring = (($i == count($bytes) - 1) ? decbin($byte s[$i]) : str_pad(decbin($bytes[$i]), 8, '0', STR_PAD_LEFT)).$binstring;442 foreach ($bytes as $i => $byte) { 443 $binstring = (($i == count($bytes) - 1) ? decbin($byte) : str_pad(decbin($byte), 8, '0', STR_PAD_LEFT)).$binstring; 438 444 } 439 445 return $binstring; 440 446 } … … 665 671 // or 666 672 // $foo['path']['to']['my'] = 'file.txt'; 667 673 $ArrayPath = ltrim($ArrayPath, $Separator); 674 $ReturnedArray = array(); 668 675 if (($pos = strpos($ArrayPath, $Separator)) !== false) { 669 676 $ReturnedArray[substr($ArrayPath, 0, $pos)] = self::CreateDeepArray(substr($ArrayPath, $pos + 1), $Separator, $Value); 670 677 } else { … … 1538 1545 public static function CopyTagsToComments(&$ThisFileInfo, $option_tags_html=true) { 1539 1546 // Copy all entries from ['tags'] into common ['comments'] 1540 1547 if (!empty($ThisFileInfo['tags'])) { 1541 if (isset($ThisFileInfo['tags']['id3v1'])) { 1542 // bubble ID3v1 to the end, if present to aid in detecting bad ID3v1 encodings 1543 $ID3v1 = $ThisFileInfo['tags']['id3v1']; 1544 unset($ThisFileInfo['tags']['id3v1']); 1545 $ThisFileInfo['tags']['id3v1'] = $ID3v1; 1546 unset($ID3v1); 1548 1549 // Some tag types can only support limited character sets and may contain data in non-standard encoding (usually ID3v1) 1550 // and/or poorly-transliterated tag values that are also in tag formats that do support full-range character sets 1551 // To make the output more user-friendly, process the potentially-problematic tag formats last to enhance the chance that 1552 // the first entries in [comments] are the most correct and the "bad" ones (if any) come later. 1553 // https://github.com/JamesHeinrich/getID3/issues/338 1554 $processLastTagTypes = array('id3v1','riff'); 1555 foreach ($processLastTagTypes as $processLastTagType) { 1556 if (isset($ThisFileInfo['tags'][$processLastTagType])) { 1557 // bubble ID3v1 to the end, if present to aid in detecting bad ID3v1 encodings 1558 $temp = $ThisFileInfo['tags'][$processLastTagType]; 1559 unset($ThisFileInfo['tags'][$processLastTagType]); 1560 $ThisFileInfo['tags'][$processLastTagType] = $temp; 1561 unset($temp); 1562 } 1547 1563 } 1548 1564 foreach ($ThisFileInfo['tags'] as $tagtype => $tagarray) { 1549 1565 foreach ($tagarray as $tagname => $tagdata) { … … 1562 1578 // new value is identical but shorter-than (or equal-length to) one already in comments - skip 1563 1579 break 2; 1564 1580 } 1565 } 1566 if (function_exists('mb_convert_encoding')) { 1567 if (trim($value) == trim(substr(mb_convert_encoding($existingvalue, $ThisFileInfo['id3v1']['encoding'], $ThisFileInfo['encoding']), 0, 30))) { 1568 // value stored in ID3v1 appears to be probably the multibyte value transliterated (badly) into ISO-8859-1 in ID3v1. 1569 // As an example, Foobar2000 will do this if you tag a file with Chinese or Arabic or Cyrillic or something that doesn't fit into ISO-8859-1 the ID3v1 will consist of mostly "?" characters, one per multibyte unrepresentable character 1570 break 2; 1581 1582 if (function_exists('mb_convert_encoding')) { 1583 if (trim($value) == trim(substr(mb_convert_encoding($existingvalue, $ThisFileInfo['id3v1']['encoding'], $ThisFileInfo['encoding']), 0, 30))) { 1584 // value stored in ID3v1 appears to be probably the multibyte value transliterated (badly) into ISO-8859-1 in ID3v1. 1585 // As an example, Foobar2000 will do this if you tag a file with Chinese or Arabic or Cyrillic or something that doesn't fit into ISO-8859-1 the ID3v1 will consist of mostly "?" characters, one per multibyte unrepresentable character 1586 break 2; 1587 } 1571 1588 } 1572 1589 } 1573 1590 1574 1591 } elseif (!is_array($value)) { 1575 1592 1576 $newvaluelength = strlen(trim($value)); 1593 $newvaluelength = strlen(trim($value)); 1594 $newvaluelengthMB = mb_strlen(trim($value)); 1577 1595 foreach ($ThisFileInfo['comments'][$tagname] as $existingkey => $existingvalue) { 1578 $oldvaluelength = strlen(trim($existingvalue)); 1596 $oldvaluelength = strlen(trim($existingvalue)); 1597 $oldvaluelengthMB = mb_strlen(trim($existingvalue)); 1598 if (($newvaluelengthMB == $oldvaluelengthMB) && ($existingvalue == getid3_lib::iconv_fallback('UTF-8', 'ASCII', $value))) { 1599 // https://github.com/JamesHeinrich/getID3/issues/338 1600 // check for tags containing extended characters that may have been forced into limited-character storage (e.g. UTF8 values into ASCII) 1601 // which will usually display unrepresentable characters as "?" 1602 $ThisFileInfo['comments'][$tagname][$existingkey] = trim($value); 1603 break; 1604 } 1579 1605 if ((strlen($existingvalue) > 10) && ($newvaluelength > $oldvaluelength) && (substr(trim($value), 0, strlen($existingvalue)) == $existingvalue)) { 1580 1606 $ThisFileInfo['comments'][$tagname][$existingkey] = trim($value); 1581 1607 break; … … 1601 1627 } 1602 1628 1603 1629 // attempt to standardize spelling of returned keys 1604 $StandardizeFieldNames = array( 1605 'tracknumber' => 'track_number', 1606 'track' => 'track_number', 1607 ); 1608 foreach ($StandardizeFieldNames as $badkey => $goodkey) { 1609 if (array_key_exists($badkey, $ThisFileInfo['comments']) && !array_key_exists($goodkey, $ThisFileInfo['comments'])) { 1610 $ThisFileInfo['comments'][$goodkey] = $ThisFileInfo['comments'][$badkey]; 1611 unset($ThisFileInfo['comments'][$badkey]); 1630 if (!empty($ThisFileInfo['comments'])) { 1631 $StandardizeFieldNames = array( 1632 'tracknumber' => 'track_number', 1633 'track' => 'track_number', 1634 ); 1635 foreach ($StandardizeFieldNames as $badkey => $goodkey) { 1636 if (array_key_exists($badkey, $ThisFileInfo['comments']) && !array_key_exists($goodkey, $ThisFileInfo['comments'])) { 1637 $ThisFileInfo['comments'][$goodkey] = $ThisFileInfo['comments'][$badkey]; 1638 unset($ThisFileInfo['comments'][$badkey]); 1639 } 1612 1640 } 1613 1641 } 1614 1642 … … 1734 1762 * @return float|bool 1735 1763 */ 1736 1764 public static function getFileSizeSyscall($path) { 1765 $commandline = null; 1737 1766 $filesize = false; 1738 1767 1739 1768 if (GETID3_OS_ISWINDOWS) { … … 1795 1824 * 1796 1825 * @return string 1797 1826 */ 1798 public static function mb_basename($path, $suffix = null) {1827 public static function mb_basename($path, $suffix = '') { 1799 1828 $splited = preg_split('#/#', rtrim($path, '/ ')); 1800 1829 return substr(basename('X'.$splited[count($splited) - 1], $suffix), 1); 1801 1830 } -
src/wp-includes/ID3/getid3.php
17 17 if (!defined('GETID3_INCLUDEPATH')) { 18 18 define('GETID3_INCLUDEPATH', dirname(__FILE__).DIRECTORY_SEPARATOR); 19 19 } 20 // Workaround Bug #39923 (https://bugs.php.net/bug.php?id=39923)21 if (!defined('IMG_JPG') && defined('IMAGETYPE_JPEG')) {22 define('IMG_JPG', IMAGETYPE_JPEG);23 }24 20 if (!defined('ENT_SUBSTITUTE')) { // PHP5.3 adds ENT_IGNORE, PHP5.4 adds ENT_SUBSTITUTE 25 21 define('ENT_SUBSTITUTE', (defined('ENT_IGNORE') ? ENT_IGNORE : 8)); 26 22 } … … 57 53 if (substr($basedir, -1, 1) != DIRECTORY_SEPARATOR) { 58 54 $basedir .= DIRECTORY_SEPARATOR; 59 55 } 60 if ( preg_match('#^'.preg_quote($basedir).'#', $temp_dir)) {56 if (strpos($temp_dir, $basedir) === 0) { 61 57 $found_valid_tempdir = true; 62 58 break; 63 59 } … … 214 210 */ 215 211 public $option_fread_buffer_size = 32768; 216 212 213 214 215 // module-specific options 216 217 /** archive.rar 218 * if true use PHP RarArchive extension, if false (non-extension parsing not yet written in getID3) 219 * 220 * @var bool 221 */ 222 public $options_archive_rar_use_php_rar_extension = true; 223 224 /** archive.gzip 225 * Optional file list - disable for speed. 226 * Decode gzipped files, if possible, and parse recursively (.tar.gz for example). 227 * 228 * @var bool 229 */ 230 public $options_archive_gzip_parse_contents = false; 231 232 /** audio.midi 233 * if false only parse most basic information, much faster for some files but may be inaccurate 234 * 235 * @var bool 236 */ 237 public $options_audio_midi_scanwholefile = true; 238 239 /** audio.mp3 240 * Forces getID3() to scan the file byte-by-byte and log all the valid audio frame headers - extremely slow, 241 * unrecommended, but may provide data from otherwise-unusable files. 242 * 243 * @var bool 244 */ 245 public $options_audio_mp3_allow_bruteforce = false; 246 247 /** audio.mp3 248 * number of frames to scan to determine if MPEG-audio sequence is valid 249 * Lower this number to 5-20 for faster scanning 250 * Increase this number to 50+ for most accurate detection of valid VBR/CBR mpeg-audio streams 251 * 252 * @var int 253 */ 254 public $options_audio_mp3_mp3_valid_check_frames = 50; 255 256 /** audio.wavpack 257 * Avoid scanning all frames (break after finding ID_RIFF_HEADER and ID_CONFIG_BLOCK, 258 * significantly faster for very large files but other data may be missed 259 * 260 * @var bool 261 */ 262 public $options_audio_wavpack_quick_parsing = false; 263 264 /** audio-video.flv 265 * Break out of the loop if too many frames have been scanned; only scan this 266 * many if meta frame does not contain useful duration. 267 * 268 * @var int 269 */ 270 public $options_audiovideo_flv_max_frames = 100000; 271 272 /** audio-video.matroska 273 * If true, do not return information about CLUSTER chunks, since there's a lot of them 274 * and they're not usually useful [default: TRUE]. 275 * 276 * @var bool 277 */ 278 public $options_audiovideo_matroska_hide_clusters = true; 279 280 /** audio-video.matroska 281 * True to parse the whole file, not only header [default: FALSE]. 282 * 283 * @var bool 284 */ 285 public $options_audiovideo_matroska_parse_whole_file = false; 286 287 /** audio-video.quicktime 288 * return all parsed data from all atoms if true, otherwise just returned parsed metadata 289 * 290 * @var bool 291 */ 292 public $options_audiovideo_quicktime_ReturnAtomData = false; 293 294 /** audio-video.quicktime 295 * return all parsed data from all atoms if true, otherwise just returned parsed metadata 296 * 297 * @var bool 298 */ 299 public $options_audiovideo_quicktime_ParseAllPossibleAtoms = false; 300 301 /** audio-video.swf 302 * return all parsed tags if true, otherwise do not return tags not parsed by getID3 303 * 304 * @var bool 305 */ 306 public $options_audiovideo_swf_ReturnAllTagData = false; 307 308 /** graphic.bmp 309 * return BMP palette 310 * 311 * @var bool 312 */ 313 public $options_graphic_bmp_ExtractPalette = false; 314 315 /** graphic.bmp 316 * return image data 317 * 318 * @var bool 319 */ 320 public $options_graphic_bmp_ExtractData = false; 321 322 /** graphic.png 323 * If data chunk is larger than this do not read it completely (getID3 only needs the first 324 * few dozen bytes for parsing). 325 * 326 * @var int 327 */ 328 public $options_graphic_png_max_data_bytes = 10000000; 329 330 /** misc.pdf 331 * return full details of PDF Cross-Reference Table (XREF) 332 * 333 * @var bool 334 */ 335 public $options_misc_pdf_returnXREF = false; 336 337 /** misc.torrent 338 * Assume all .torrent files are less than 1MB and just read entire thing into memory for easy processing. 339 * Override this value if you need to process files larger than 1MB 340 * 341 * @var int 342 */ 343 public $options_misc_torrent_max_torrent_filesize = 1048576; 344 345 346 217 347 // Public variables 218 348 219 349 /** … … 257 387 */ 258 388 protected $startup_warning = ''; 259 389 260 const VERSION = '1.9.2 0-202006061653';390 const VERSION = '1.9.21-202109171300'; 261 391 const FREAD_BUFFER_SIZE = 32768; 262 392 263 393 const ATTACHMENTS_NONE = false; … … 637 767 return $this->error('Format not supported, module "'.$determined_format['include'].'" is corrupt.'); 638 768 } 639 769 $class = new $class_name($this); 770 771 // set module-specific options 772 foreach (get_object_vars($this) as $getid3_object_vars_key => $getid3_object_vars_value) { 773 if (preg_match('#^options_([^_]+)_([^_]+)_(.+)$#i', $getid3_object_vars_key, $matches)) { 774 list($dummy, $GOVgroup, $GOVmodule, $GOVsetting) = $matches; 775 $GOVgroup = (($GOVgroup == 'audiovideo') ? 'audio-video' : $GOVgroup); // variable names can only contain 0-9a-z_ so standardize here 776 if (($GOVgroup == $determined_format['group']) && ($GOVmodule == $determined_format['module'])) { 777 $class->$GOVsetting = $getid3_object_vars_value; 778 } 779 } 780 } 781 640 782 $class->Analyze(); 641 783 unset($class); 642 784 … … 1355 1497 'fail_ape' => 'ERROR', 1356 1498 ), 1357 1499 1500 // TORRENT - .torrent 1501 'torrent' => array( 1502 'pattern' => '^(d8\\:announce|d7\\:comment)', 1503 'group' => 'misc', 1504 'module' => 'torrent', 1505 'mime_type' => 'application/x-bittorrent', 1506 'fail_id3' => 'ERROR', 1507 'fail_ape' => 'ERROR', 1508 ), 1509 1358 1510 // CUE - data - CUEsheet (index to single-file disc images) 1359 1511 'cue' => array( 1360 1512 'pattern' => '', // empty pattern means cannot be automatically detected, will fall through all other formats and match based on filename and very basic file contents … … 1489 1641 if (is_string($value)) { 1490 1642 $value = trim($value, " \r\n\t"); // do not trim nulls from $value!! Unicode characters will get mangled if trailing nulls are removed! 1491 1643 } 1492 if ( $value) {1644 if (isset($value) && $value !== "") { 1493 1645 if (!is_numeric($key)) { 1494 1646 $this->info['tags'][trim($tag_name)][trim($tag_key)][$key] = $value; 1495 1647 } else { … … 2096 2248 $this->data_string_position = $this->data_string_length + $bytes; 2097 2249 break; 2098 2250 } 2099 return 0; 2100 } else { 2101 $pos = $bytes; 2102 if ($whence == SEEK_CUR) { 2103 $pos = $this->ftell() + $bytes; 2104 } elseif ($whence == SEEK_END) { 2105 $pos = $this->getid3->info['filesize'] + $bytes; 2106 } 2107 if (!getid3_lib::intValueSupported($pos)) { 2108 throw new getid3_exception('cannot fseek('.$pos.') because beyond PHP filesystem limit', 10); 2109 } 2251 return 0; // fseek returns 0 on success 2110 2252 } 2111 return fseek($this->getid3->fp, $bytes, $whence); 2253 2254 $pos = $bytes; 2255 if ($whence == SEEK_CUR) { 2256 $pos = $this->ftell() + $bytes; 2257 } elseif ($whence == SEEK_END) { 2258 $pos = $this->getid3->info['filesize'] + $bytes; 2259 } 2260 if (!getid3_lib::intValueSupported($pos)) { 2261 throw new getid3_exception('cannot fseek('.$pos.') because beyond PHP filesystem limit', 10); 2262 } 2263 2264 // https://github.com/JamesHeinrich/getID3/issues/327 2265 $result = fseek($this->getid3->fp, $bytes, $whence); 2266 if ($result !== 0) { // fseek returns 0 on success 2267 throw new getid3_exception('cannot fseek('.$pos.'). resource/stream does not appear to support seeking', 10); 2268 } 2269 return $result; 2112 2270 } 2113 2271 2114 2272 /** … … 2224 2382 * @throws getid3_exception 2225 2383 */ 2226 2384 public function saveAttachment($name, $offset, $length, $image_mime=null) { 2385 $fp_dest = null; 2386 $dest = null; 2227 2387 try { 2228 2388 2229 2389 // do not extract at all -
src/wp-includes/ID3/module.audio-video.asf.php
93 93 $offset = 0; 94 94 $thisfile_asf_streambitratepropertiesobject = array(); 95 95 $thisfile_asf_codeclistobject = array(); 96 $StreamPropertiesObjectData = array(); 96 97 97 98 for ($HeaderObjectsCounter = 0; $HeaderObjectsCounter < $thisfile_asf_headerobject['headerobjects']; $HeaderObjectsCounter++) { 98 99 $NextObjectGUID = substr($ASFHeaderData, $offset, 16); … … 283 284 $thisfile_asf_headerextensionobject['reserved_2'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); 284 285 $offset += 2; 285 286 if ($thisfile_asf_headerextensionobject['reserved_2'] != 6) { 286 $this->warning('header_extension_object.reserved_2 ('. getid3_lib::PrintHexBytes($thisfile_asf_headerextensionobject['reserved_2']).') does not match expected value of "6"');287 $this->warning('header_extension_object.reserved_2 ('.$thisfile_asf_headerextensionobject['reserved_2'].') does not match expected value of "6"'); 287 288 //return false; 288 289 break; 289 290 } … … 535 536 $thisfile_asf_markerobject['reserved_2'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); 536 537 $offset += 2; 537 538 if ($thisfile_asf_markerobject['reserved_2'] != 0) { 538 $this->warning('marker_object.reserved_2 ('. getid3_lib::PrintHexBytes($thisfile_asf_markerobject['reserved_2']).') does not match expected value of "0"');539 $this->warning('marker_object.reserved_2 ('.$thisfile_asf_markerobject['reserved_2'].') does not match expected value of "0"'); 539 540 break; 540 541 } 541 542 $thisfile_asf_markerobject['name_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); … … 1193 1194 $thisfile_asf_dataobject['reserved'] = getid3_lib::LittleEndian2Int(substr($DataObjectData, $offset, 2)); 1194 1195 $offset += 2; 1195 1196 if ($thisfile_asf_dataobject['reserved'] != 0x0101) { 1196 $this->warning('data_object.reserved ( '.getid3_lib::PrintHexBytes($thisfile_asf_dataobject['reserved']).') does not match expected value of "0x0101"');1197 $this->warning('data_object.reserved (0x'.sprintf('%04X', $thisfile_asf_dataobject['reserved']).') does not match expected value of "0x0101"'); 1197 1198 //return false; 1198 1199 break; 1199 1200 } -
src/wp-includes/ID3/module.audio-video.flv.php
161 161 $info['flv']['video']['videoCodec'] = $LastHeaderByte & 0x07; 162 162 163 163 $FLVvideoHeader = $this->fread(11); 164 $PictureSizeEnc = array(); 164 165 165 166 if ($info['flv']['video']['videoCodec'] == GETID3_FLV_VIDEO_H264) { 166 167 // this code block contributed by: moysevichØgmail*com -
src/wp-includes/ID3/module.audio-video.matroska.php
224 224 * 225 225 * @var bool 226 226 */ 227 public static$hide_clusters = true;227 public $hide_clusters = true; 228 228 229 229 /** 230 230 * True to parse the whole file, not only header [default: FALSE]. … … 231 231 * 232 232 * @var bool 233 233 */ 234 public static$parse_whole_file = false;234 public $parse_whole_file = false; 235 235 236 236 /* 237 237 * Private parser settings/placeholders. … … 586 586 $info['matroska']['segment'][0]['length'] = $top_element['length']; 587 587 588 588 while ($this->getEBMLelement($element_data, $top_element['end'])) { 589 if ($element_data['id'] != EBML_ID_CLUSTER || ! self::$hide_clusters) { // collect clusters only if required589 if ($element_data['id'] != EBML_ID_CLUSTER || !$this->hide_clusters) { // collect clusters only if required 590 590 $info['matroska']['segments'][] = $element_data; 591 591 } 592 592 switch ($element_data['id']) { … … 618 618 $this->warning('seek_entry[target_id] unexpectedly not set at '.$seek_entry['offset']); 619 619 break; 620 620 } 621 if (($seek_entry['target_id'] != EBML_ID_CLUSTER) || ! self::$hide_clusters) { // collect clusters only if required621 if (($seek_entry['target_id'] != EBML_ID_CLUSTER) || !$this->hide_clusters) { // collect clusters only if required 622 622 $info['matroska']['seek'][] = $seek_entry; 623 623 } 624 624 break; … … 905 905 break; 906 906 907 907 case EBML_ID_CUES: // A top-level element to speed seeking access. All entries are local to the segment. Should be mandatory for non "live" streams. 908 if ( self::$hide_clusters) { // do not parse cues if hide clusters is "ON" till they point to clusters anyway908 if ($this->hide_clusters) { // do not parse cues if hide clusters is "ON" till they point to clusters anyway 909 909 $this->current_offset = $element_data['end']; 910 910 break; 911 911 } … … 1246 1246 } 1247 1247 $this->current_offset = $subelement['end']; 1248 1248 } 1249 if (! self::$hide_clusters) {1249 if (!$this->hide_clusters) { 1250 1250 $info['matroska']['cluster'][] = $cluster_entry; 1251 1251 } 1252 1252 1253 1253 // check to see if all the data we need exists already, if so, break out of the loop 1254 if (! self::$parse_whole_file) {1254 if (!$this->parse_whole_file) { 1255 1255 if (isset($info['matroska']['info']) && is_array($info['matroska']['info'])) { 1256 1256 if (isset($info['matroska']['tracks']['tracks']) && is_array($info['matroska']['tracks']['tracks'])) { 1257 1257 if (count($info['matroska']['track_data_offsets']) == count($info['matroska']['tracks']['tracks'])) { -
src/wp-includes/ID3/module.audio-video.quicktime.php
24 24 class getid3_quicktime extends getid3_handler 25 25 { 26 26 27 public $ReturnAtomData = true; 27 /** audio-video.quicktime 28 * return all parsed data from all atoms if true, otherwise just returned parsed metadata 29 * 30 * @var bool 31 */ 32 public $ReturnAtomData = false; 33 34 /** audio-video.quicktime 35 * return all parsed data from all atoms if true, otherwise just returned parsed metadata 36 * 37 * @var bool 38 */ 28 39 public $ParseAllPossibleAtoms = false; 29 40 30 41 /** … … 170 181 } 171 182 } 172 183 173 if (!isset($info['bitrate']) && isset($info['playtime_seconds'])) {184 if (!isset($info['bitrate']) && !empty($info['playtime_seconds'])) { 174 185 $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; 175 186 } 176 187 if (isset($info['bitrate']) && !isset($info['audio']['bitrate']) && !isset($info['quicktime']['video'])) { … … 560 571 default: 561 572 $atom_structure['data'] = substr($boxdata, 8); 562 573 if ($atomname == 'covr') { 563 // not a foolproof check, but better than nothing 564 if (preg_match('#^\\xFF\\xD8\\xFF#', $atom_structure['data'])) { 565 $atom_structure['image_mime'] = 'image/jpeg'; 566 } elseif (preg_match('#^\\x89\\x50\\x4E\\x47\\x0D\\x0A\\x1A\\x0A#', $atom_structure['data'])) { 567 $atom_structure['image_mime'] = 'image/png'; 568 } elseif (preg_match('#^GIF#', $atom_structure['data'])) { 569 $atom_structure['image_mime'] = 'image/gif'; 574 if (!empty($atom_structure['data'])) { 575 $atom_structure['image_mime'] = 'image/unknown'; // provide default MIME type to ensure array keys exist 576 if (function_exists('getimagesizefromstring') && ($getimagesize = getimagesizefromstring($atom_structure['data'])) && !empty($getimagesize['mime'])) { 577 $atom_structure['image_mime'] = $getimagesize['mime']; 578 } else { 579 // if getimagesizefromstring is not available, or fails for some reason, fall back to simple detection of common image formats 580 $ImageFormatSignatures = array( 581 'image/jpeg' => "\xFF\xD8\xFF", 582 'image/png' => "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 583 'image/gif' => 'GIF', 584 ); 585 foreach ($ImageFormatSignatures as $mime => $image_format_signature) { 586 if (substr($atom_structure['data'], 0, strlen($image_format_signature)) == $image_format_signature) { 587 $atom_structure['image_mime'] = $mime; 588 break; 589 } 590 } 591 } 592 $info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_structure['data'], 'description'=>'cover'); 593 } else { 594 $this->warning('Unknown empty "covr" image at offset '.$baseoffset); 570 595 } 571 $info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_structure['data'], 'description'=>'cover');572 596 } 573 597 break; 574 598 … … 728 752 $atom_structure['flags']['play_on_open'] = (bool) $atom_structure['play_on_open_flag']; 729 753 $atom_structure['flags']['slide_show'] = (bool) $atom_structure['slide_show_flag']; 730 754 731 $ptv_lookup[0] = 'normal'; 732 $ptv_lookup[1] = 'double'; 733 $ptv_lookup[2] = 'half'; 734 $ptv_lookup[3] = 'full'; 735 $ptv_lookup[4] = 'current'; 755 $ptv_lookup = array( 756 0 => 'normal', 757 1 => 'double', 758 2 => 'half', 759 3 => 'full', 760 4 => 'current' 761 ); 736 762 if (isset($ptv_lookup[$atom_structure['display_size_raw']])) { 737 763 $atom_structure['display_size'] = $ptv_lookup[$atom_structure['display_size_raw']]; 738 764 } else { … … 908 934 $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 66, 2)); 909 935 $atom_structure['sample_description_table'][$i]['video_color_table_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 68, 2)); 910 936 911 $atom_structure['sample_description_table'][$i]['video_pixel_color_type'] = (( $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] > 32) ? 'grayscale' : 'color');937 $atom_structure['sample_description_table'][$i]['video_pixel_color_type'] = (((int) $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] > 32) ? 'grayscale' : 'color'); 912 938 $atom_structure['sample_description_table'][$i]['video_pixel_color_name'] = $this->QuicktimeColorNameLookup($atom_structure['sample_description_table'][$i]['video_pixel_color_depth']); 913 939 914 940 if ($atom_structure['sample_description_table'][$i]['video_pixel_color_name'] != 'invalid') { 915 941 $info['quicktime']['video']['codec_fourcc'] = $atom_structure['sample_description_table'][$i]['data_format']; 916 942 $info['quicktime']['video']['codec_fourcc_lookup'] = $this->QuicktimeVideoCodecLookup($atom_structure['sample_description_table'][$i]['data_format']); 917 $info['quicktime']['video']['codec'] = (( $atom_structure['sample_description_table'][$i]['video_encoder_name_len'] > 0) ? $atom_structure['sample_description_table'][$i]['video_encoder_name'] : $atom_structure['sample_description_table'][$i]['data_format']);943 $info['quicktime']['video']['codec'] = (((int) $atom_structure['sample_description_table'][$i]['video_encoder_name_len'] > 0) ? $atom_structure['sample_description_table'][$i]['video_encoder_name'] : $atom_structure['sample_description_table'][$i]['data_format']); 918 944 $info['quicktime']['video']['color_depth'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_depth']; 919 945 $info['quicktime']['video']['color_depth_name'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_name']; 920 946 … … 1598 1624 break; 1599 1625 1600 1626 case 'NCDT': 1601 // http ://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html1627 // https://exiftool.org/TagNames/Nikon.html 1602 1628 // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100 1603 1629 $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 4, $atomHierarchy, $ParseAllPossibleAtoms); 1604 1630 break; 1605 1631 case 'NCTH': // Nikon Camera THumbnail image 1606 1632 case 'NCVW': // Nikon Camera preVieW image 1607 // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html 1633 case 'NCM1': // Nikon Camera preview iMage 1 1634 case 'NCM2': // Nikon Camera preview iMage 2 1635 // https://exiftool.org/TagNames/Nikon.html 1608 1636 if (preg_match('/^\xFF\xD8\xFF/', $atom_data)) { 1637 $descriptions = array( 1638 'NCTH' => 'Nikon Camera Thumbnail Image', 1639 'NCVW' => 'Nikon Camera Preview Image', 1640 'NCM1' => 'Nikon Camera Preview Image 1', 1641 'NCM2' => 'Nikon Camera Preview Image 2', 1642 ); 1609 1643 $atom_structure['data'] = $atom_data; 1610 1644 $atom_structure['image_mime'] = 'image/jpeg'; 1611 $atom_structure['description'] = (($atomname == 'NCTH') ? 'Nikon Camera Thumbnail Image' : (($atomname == 'NCVW') ? 'Nikon Camera Preview Image' : 'Nikon preview image')); 1612 $info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_data, 'description'=>$atom_structure['description']); 1645 $atom_structure['description'] = isset($descriptions[$atomname]) ? $descriptions[$atomname] : 'Nikon preview image'; 1646 $info['quicktime']['comments']['picture'][] = array( 1647 'image_mime' => $atom_structure['image_mime'], 1648 'data' => $atom_data, 1649 'description' => $atom_structure['description'] 1650 ); 1613 1651 } 1614 1652 break; 1615 case 'NCTG': // Nikon - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG 1616 $atom_structure['data'] = $this->QuicktimeParseNikonNCTG($atom_data); 1653 case 'NCTG': // Nikon - https://exiftool.org/TagNames/Nikon.html#NCTG 1654 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.nikon-nctg.php', __FILE__, true); 1655 $nikonNCTG = new getid3_tag_nikon_nctg($this->getid3); 1656 1657 $atom_structure['data'] = $nikonNCTG->parse($atom_data); 1617 1658 break; 1618 case 'NCHD': // Nikon:MakerNoteVersion - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html 1619 case 'NCDB': // Nikon - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html 1620 case 'CNCV': // Canon:CompressorVersion - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Canon.html 1659 case 'NCHD': // Nikon:MakerNoteVersion - https://exiftool.org/TagNames/Nikon.html 1660 $makerNoteVersion = ''; 1661 for ($i = 0, $iMax = strlen($atom_data); $i < $iMax; ++$i) { 1662 if (ord($atom_data[$i]) >= 0x00 && ord($atom_data[$i]) <= 0x1F) { 1663 $makerNoteVersion .= ' '.ord($atom_data[$i]); 1664 } else { 1665 $makerNoteVersion .= $atom_data[$i]; 1666 } 1667 } 1668 $makerNoteVersion = rtrim($makerNoteVersion, "\x00"); 1669 $atom_structure['data'] = array( 1670 'MakerNoteVersion' => $makerNoteVersion 1671 ); 1672 break; 1673 case 'NCDB': // Nikon - https://exiftool.org/TagNames/Nikon.html 1674 case 'CNCV': // Canon:CompressorVersion - https://exiftool.org/TagNames/Canon.html 1621 1675 $atom_structure['data'] = $atom_data; 1622 1676 break; 1623 1677 … … 1624 1678 case "\x00\x00\x00\x00": 1625 1679 // some kind of metacontainer, may contain a big data dump such as: 1626 1680 // 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 1627 // http ://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt1681 // https://xhelmboyx.tripod.com/formats/qti-layout.txt 1628 1682 1629 1683 $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); 1630 1684 $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); … … 1721 1775 'unknown_data' => array(), 1722 1776 'debug_list' => '', // Used to debug variables stored as comma delimited strings 1723 1777 ); 1778 $debug_structure = array(); 1724 1779 $debug_structure['debug_items'] = array(); 1725 1780 // Can start loop here to decode all sensor data in 32 Byte chunks: 1726 1781 foreach (str_split($atom_SENSOR_data, 32) as $sensor_key => $sensor_data) { … … 2039 2094 * @return array|false 2040 2095 */ 2041 2096 public function QuicktimeParseContainerAtom($atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) { 2042 $atom_structure = false;2097 $atom_structure = array(); 2043 2098 $subatomoffset = 0; 2044 2099 $subatomcounter = 0; 2045 2100 if ((strlen($atom_data) == 4) && (getid3_lib::BigEndian2Int($atom_data) == 0x00000000)) { … … 2057 2112 $subatomoffset += 4; 2058 2113 continue; 2059 2114 } 2060 return $atom_structure;2115 break; 2061 2116 } 2062 2117 if (strlen($subatomdata) < ($subatomsize - 8)) { 2063 2118 // we don't have enough data to decode the subatom. 2064 2119 // this may be because we are refusing to parse large subatoms, or it may be because this atom had its size set too large 2065 2120 // so we passed in the start of a following atom incorrectly? 2066 return $atom_structure;2121 break; 2067 2122 } 2068 2123 $atom_structure[$subatomcounter++] = $this->QuicktimeParseAtom($subatomname, $subatomsize, $subatomdata, $baseoffset + $subatomoffset, $atomHierarchy, $ParseAllPossibleAtoms); 2069 2124 $subatomoffset += $subatomsize; 2070 2125 } 2126 2127 if (empty($atom_structure)) { 2128 return false; 2129 } 2130 2071 2131 return $atom_structure; 2072 2132 } 2073 2133 … … 2552 2612 static $QuicktimeContentRatingLookup = array(); 2553 2613 if (empty($QuicktimeContentRatingLookup)) { 2554 2614 $QuicktimeContentRatingLookup[0] = 'None'; 2615 $QuicktimeContentRatingLookup[1] = 'Explicit'; 2555 2616 $QuicktimeContentRatingLookup[2] = 'Clean'; 2556 $QuicktimeContentRatingLookup[4] = 'Explicit ';2617 $QuicktimeContentRatingLookup[4] = 'Explicit (old)'; 2557 2618 } 2558 2619 return (isset($QuicktimeContentRatingLookup[$rtng]) ? $QuicktimeContentRatingLookup[$rtng] : 'invalid'); 2559 2620 } … … 2607 2668 } 2608 2669 2609 2670 /** 2610 * @param string $atom_data2611 *2612 * @return array2613 */2614 public function QuicktimeParseNikonNCTG($atom_data) {2615 // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG2616 // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D51002617 // Data is stored as records of:2618 // * 4 bytes record type2619 // * 2 bytes size of data field type:2620 // 0x0001 = flag (size field *= 1-byte)2621 // 0x0002 = char (size field *= 1-byte)2622 // 0x0003 = DWORD+ (size field *= 2-byte), values are stored CDAB2623 // 0x0004 = QWORD+ (size field *= 4-byte), values are stored EFGHABCD2624 // 0x0005 = float (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together2625 // 0x0007 = bytes (size field *= 1-byte), values are stored as ??????2626 // 0x0008 = ????? (size field *= 2-byte), values are stored as ??????2627 // * 2 bytes data size field2628 // * ? bytes data (string data may be null-padded; datestamp fields are in the format "2011:05:25 20:24:15")2629 // all integers are stored BigEndian2630 2631 $NCTGtagName = array(2632 0x00000001 => 'Make',2633 0x00000002 => 'Model',2634 0x00000003 => 'Software',2635 0x00000011 => 'CreateDate',2636 0x00000012 => 'DateTimeOriginal',2637 0x00000013 => 'FrameCount',2638 0x00000016 => 'FrameRate',2639 0x00000022 => 'FrameWidth',2640 0x00000023 => 'FrameHeight',2641 0x00000032 => 'AudioChannels',2642 0x00000033 => 'AudioBitsPerSample',2643 0x00000034 => 'AudioSampleRate',2644 0x02000001 => 'MakerNoteVersion',2645 0x02000005 => 'WhiteBalance',2646 0x0200000b => 'WhiteBalanceFineTune',2647 0x0200001e => 'ColorSpace',2648 0x02000023 => 'PictureControlData',2649 0x02000024 => 'WorldTime',2650 0x02000032 => 'UnknownInfo',2651 0x02000083 => 'LensType',2652 0x02000084 => 'Lens',2653 );2654 2655 $offset = 0;2656 $data = null;2657 $datalength = strlen($atom_data);2658 $parsed = array();2659 while ($offset < $datalength) {2660 $record_type = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 4)); $offset += 4;2661 $data_size_type = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2)); $offset += 2;2662 $data_size = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2)); $offset += 2;2663 switch ($data_size_type) {2664 case 0x0001: // 0x0001 = flag (size field *= 1-byte)2665 $data = getid3_lib::BigEndian2Int(substr($atom_data, $offset, $data_size * 1));2666 $offset += ($data_size * 1);2667 break;2668 case 0x0002: // 0x0002 = char (size field *= 1-byte)2669 $data = substr($atom_data, $offset, $data_size * 1);2670 $offset += ($data_size * 1);2671 $data = rtrim($data, "\x00");2672 break;2673 case 0x0003: // 0x0003 = DWORD+ (size field *= 2-byte), values are stored CDAB2674 $data = '';2675 for ($i = $data_size - 1; $i >= 0; $i--) {2676 $data .= substr($atom_data, $offset + ($i * 2), 2);2677 }2678 $data = getid3_lib::BigEndian2Int($data);2679 $offset += ($data_size * 2);2680 break;2681 case 0x0004: // 0x0004 = QWORD+ (size field *= 4-byte), values are stored EFGHABCD2682 $data = '';2683 for ($i = $data_size - 1; $i >= 0; $i--) {2684 $data .= substr($atom_data, $offset + ($i * 4), 4);2685 }2686 $data = getid3_lib::BigEndian2Int($data);2687 $offset += ($data_size * 4);2688 break;2689 case 0x0005: // 0x0005 = float (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together2690 $data = array();2691 for ($i = 0; $i < $data_size; $i++) {2692 $numerator = getid3_lib::BigEndian2Int(substr($atom_data, $offset + ($i * 8) + 0, 4));2693 $denomninator = getid3_lib::BigEndian2Int(substr($atom_data, $offset + ($i * 8) + 4, 4));2694 if ($denomninator == 0) {2695 $data[$i] = false;2696 } else {2697 $data[$i] = (double) $numerator / $denomninator;2698 }2699 }2700 $offset += (8 * $data_size);2701 if (count($data) == 1) {2702 $data = $data[0];2703 }2704 break;2705 case 0x0007: // 0x0007 = bytes (size field *= 1-byte), values are stored as ??????2706 $data = substr($atom_data, $offset, $data_size * 1);2707 $offset += ($data_size * 1);2708 break;2709 case 0x0008: // 0x0008 = ????? (size field *= 2-byte), values are stored as ??????2710 $data = substr($atom_data, $offset, $data_size * 2);2711 $offset += ($data_size * 2);2712 break;2713 default:2714 echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br>';2715 break 2;2716 }2717 2718 switch ($record_type) {2719 case 0x00000011: // CreateDate2720 case 0x00000012: // DateTimeOriginal2721 $data = strtotime($data);2722 break;2723 case 0x0200001e: // ColorSpace2724 switch ($data) {2725 case 1:2726 $data = 'sRGB';2727 break;2728 case 2:2729 $data = 'Adobe RGB';2730 break;2731 }2732 break;2733 case 0x02000023: // PictureControlData2734 $PictureControlAdjust = array(0=>'default', 1=>'quick', 2=>'full');2735 $FilterEffect = array(0x80=>'off', 0x81=>'yellow', 0x82=>'orange', 0x83=>'red', 0x84=>'green', 0xff=>'n/a');2736 $ToningEffect = array(0x80=>'b&w', 0x81=>'sepia', 0x82=>'cyanotype', 0x83=>'red', 0x84=>'yellow', 0x85=>'green', 0x86=>'blue-green', 0x87=>'blue', 0x88=>'purple-blue', 0x89=>'red-purple', 0xff=>'n/a');2737 $data = array(2738 'PictureControlVersion' => substr($data, 0, 4),2739 'PictureControlName' => rtrim(substr($data, 4, 20), "\x00"),2740 'PictureControlBase' => rtrim(substr($data, 24, 20), "\x00"),2741 //'?' => substr($data, 44, 4),2742 'PictureControlAdjust' => $PictureControlAdjust[ord(substr($data, 48, 1))],2743 'PictureControlQuickAdjust' => ord(substr($data, 49, 1)),2744 'Sharpness' => ord(substr($data, 50, 1)),2745 'Contrast' => ord(substr($data, 51, 1)),2746 'Brightness' => ord(substr($data, 52, 1)),2747 'Saturation' => ord(substr($data, 53, 1)),2748 'HueAdjustment' => ord(substr($data, 54, 1)),2749 'FilterEffect' => $FilterEffect[ord(substr($data, 55, 1))],2750 'ToningEffect' => $ToningEffect[ord(substr($data, 56, 1))],2751 'ToningSaturation' => ord(substr($data, 57, 1)),2752 );2753 break;2754 case 0x02000024: // WorldTime2755 // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#WorldTime2756 // timezone is stored as offset from GMT in minutes2757 $timezone = getid3_lib::BigEndian2Int(substr($data, 0, 2));2758 if ($timezone & 0x8000) {2759 $timezone = 0 - (0x10000 - $timezone);2760 }2761 $timezone /= 60;2762 2763 $dst = (bool) getid3_lib::BigEndian2Int(substr($data, 2, 1));2764 switch (getid3_lib::BigEndian2Int(substr($data, 3, 1))) {2765 case 2:2766 $datedisplayformat = 'D/M/Y'; break;2767 case 1:2768 $datedisplayformat = 'M/D/Y'; break;2769 case 0:2770 default:2771 $datedisplayformat = 'Y/M/D'; break;2772 }2773 2774 $data = array('timezone'=>floatval($timezone), 'dst'=>$dst, 'display'=>$datedisplayformat);2775 break;2776 case 0x02000083: // LensType2777 $data = array(2778 //'_' => $data,2779 'mf' => (bool) ($data & 0x01),2780 'd' => (bool) ($data & 0x02),2781 'g' => (bool) ($data & 0x04),2782 'vr' => (bool) ($data & 0x08),2783 );2784 break;2785 }2786 $tag_name = (isset($NCTGtagName[$record_type]) ? $NCTGtagName[$record_type] : '0x'.str_pad(dechex($record_type), 8, '0', STR_PAD_LEFT));2787 $parsed[$tag_name] = $data;2788 }2789 return $parsed;2790 }2791 2792 /**2793 2671 * @param string $keyname 2794 2672 * @param string|array $data 2795 2673 * @param string $boxname -
src/wp-includes/ID3/module.audio-video.riff.php
56 56 $thisfile_riff_video = &$thisfile_riff['video']; 57 57 $thisfile_riff_WAVE = array(); 58 58 59 $Original = array(); 59 60 $Original['avdataoffset'] = $info['avdataoffset']; 60 61 $Original['avdataend'] = $info['avdataend']; 61 62 … … 296 297 // shortcut 297 298 $thisfile_riff_WAVE_bext_0 = &$thisfile_riff_WAVE['bext'][0]; 298 299 299 $thisfile_riff_WAVE_bext_0['title'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 0, 256)); 300 $thisfile_riff_WAVE_bext_0['author'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 256, 32)); 301 $thisfile_riff_WAVE_bext_0['reference'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 288, 32)); 300 $thisfile_riff_WAVE_bext_0['title'] = substr($thisfile_riff_WAVE_bext_0['data'], 0, 256); 301 $thisfile_riff_WAVE_bext_0['author'] = substr($thisfile_riff_WAVE_bext_0['data'], 256, 32); 302 $thisfile_riff_WAVE_bext_0['reference'] = substr($thisfile_riff_WAVE_bext_0['data'], 288, 32); 303 foreach (array('title','author','reference') as $bext_key) { 304 // Some software (notably Logic Pro) may not blank existing data before writing a null-terminated string to the offsets 305 // assigned for text fields, resulting in a null-terminated string (or possibly just a single null) followed by garbage 306 // Keep only string as far as first null byte, discard rest of fixed-width data 307 // https://github.com/JamesHeinrich/getID3/issues/263 308 $null_terminator_offset = strpos($thisfile_riff_WAVE_bext_0[$bext_key], "\x00"); 309 $thisfile_riff_WAVE_bext_0[$bext_key] = substr($thisfile_riff_WAVE_bext_0[$bext_key], 0, $null_terminator_offset); 310 } 311 302 312 $thisfile_riff_WAVE_bext_0['origin_date'] = substr($thisfile_riff_WAVE_bext_0['data'], 320, 10); 303 313 $thisfile_riff_WAVE_bext_0['origin_time'] = substr($thisfile_riff_WAVE_bext_0['data'], 330, 8); 304 314 $thisfile_riff_WAVE_bext_0['time_reference'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 338, 8)); … … 307 317 $thisfile_riff_WAVE_bext_0['coding_history'] = explode("\r\n", trim(substr($thisfile_riff_WAVE_bext_0['data'], 601))); 308 318 if (preg_match('#^([0-9]{4}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_date'], $matches_bext_date)) { 309 319 if (preg_match('#^([0-9]{2}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_time'], $matches_bext_time)) { 320 $bext_timestamp = array(); 310 321 list($dummy, $bext_timestamp['year'], $bext_timestamp['month'], $bext_timestamp['day']) = $matches_bext_date; 311 322 list($dummy, $bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second']) = $matches_bext_time; 312 323 $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']); … … 451 462 } 452 463 } 453 464 465 if (isset($thisfile_riff_WAVE['guan'][0]['data'])) { 466 // shortcut 467 $thisfile_riff_WAVE_guan_0 = &$thisfile_riff_WAVE['guan'][0]; 468 if (!empty($thisfile_riff_WAVE_guan_0['data']) && (substr($thisfile_riff_WAVE_guan_0['data'], 0, 14) == 'GUANO|Version:')) { 469 $thisfile_riff['guano'] = array(); 470 foreach (explode("\n", $thisfile_riff_WAVE_guan_0['data']) as $line) { 471 if ($line) { 472 @list($key, $value) = explode(':', $line, 2); 473 if (substr($value, 0, 3) == '[{"') { 474 if ($decoded = @json_decode($value, true)) { 475 if (!empty($decoded) && (count($decoded) == 1)) { 476 $value = $decoded[0]; 477 } else { 478 $value = $decoded; 479 } 480 } 481 } 482 $thisfile_riff['guano'] = array_merge_recursive($thisfile_riff['guano'], getid3_lib::CreateDeepArray($key, '|', $value)); 483 } 484 } 454 485 486 // https://www.wildlifeacoustics.com/SCHEMA/GUANO.html 487 foreach ($thisfile_riff['guano'] as $key => $value) { 488 switch ($key) { 489 case 'Loc Position': 490 if (preg_match('#^([\\+\\-]?[0-9]+\\.[0-9]+) ([\\+\\-]?[0-9]+\\.[0-9]+)$#', $value, $matches)) { 491 list($dummy, $latitude, $longitude) = $matches; 492 $thisfile_riff['comments']['gps_latitude'][0] = floatval($latitude); 493 $thisfile_riff['comments']['gps_longitude'][0] = floatval($longitude); 494 $thisfile_riff['guano'][$key] = floatval($latitude).' '.floatval($longitude); 495 } 496 break; 497 case 'Loc Elevation': // Elevation/altitude above mean sea level in meters 498 $thisfile_riff['comments']['gps_altitude'][0] = floatval($value); 499 $thisfile_riff['guano'][$key] = (float) $value; 500 break; 501 case 'Filter HP': // High-pass filter frequency in kHz 502 case 'Filter LP': // Low-pass filter frequency in kHz 503 case 'Humidity': // Relative humidity as a percentage 504 case 'Length': // Recording length in seconds 505 case 'Loc Accuracy': // Estimated Position Error in meters 506 case 'Temperature Ext': // External temperature in degrees Celsius outside the recorder's housing 507 case 'Temperature Int': // Internal temperature in degrees Celsius inside the recorder's housing 508 $thisfile_riff['guano'][$key] = (float) $value; 509 break; 510 case 'Samplerate': // Recording sample rate, Hz 511 case 'TE': // Time-expansion factor. If not specified, then 1 (no time-expansion a.k.a. direct-recording) is assumed. 512 $thisfile_riff['guano'][$key] = (int) $value; 513 break; 514 } 515 } 455 516 517 } else { 518 $this->warning('RIFF.guan data not in expected format'); 519 } 520 } 521 456 522 if (!isset($thisfile_audio['bitrate']) && isset($thisfile_riff_audio[$streamindex]['bitrate'])) { 457 523 $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate']; 458 524 $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $thisfile_audio['bitrate']); … … 733 799 } 734 800 if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][0]['data'])) { 735 801 if (is_array($thisfile_riff['AVI ']['hdrl']['strl']['strh'])) { 802 $thisfile_riff_raw_strf_strhfccType_streamindex = null; 736 803 for ($i = 0; $i < count($thisfile_riff['AVI ']['hdrl']['strl']['strh']); $i++) { 737 804 if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'])) { 738 805 $strhData = $thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data']; … … 1069 1136 if (isset($thisfile_riff[$RIFFsubtype]['ID3 '])) { 1070 1137 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true); 1071 1138 $getid3_temp = new getID3(); 1072 $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);1139 $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp); 1073 1140 $getid3_id3v2 = new getid3_id3v2($getid3_temp); 1074 1141 $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['ID3 '][0]['offset'] + 8; 1075 1142 if ($thisfile_riff[$RIFFsubtype]['ID3 '][0]['valid'] = $getid3_id3v2->Analyze()) { … … 1172 1239 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.mpeg.php', __FILE__, true); 1173 1240 1174 1241 $getid3_temp = new getID3(); 1175 $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);1242 $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp); 1176 1243 $getid3_mpeg = new getid3_mpeg($getid3_temp); 1177 1244 $getid3_mpeg->Analyze(); 1178 1245 if (empty($getid3_temp->info['error'])) { … … 1258 1325 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true); 1259 1326 1260 1327 $getid3_temp = new getID3(); 1261 $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);1328 $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp); 1262 1329 $getid3_id3v2 = new getid3_id3v2($getid3_temp); 1263 1330 $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['id3 '][0]['offset'] + 8; 1264 1331 if ($thisfile_riff[$RIFFsubtype]['id3 '][0]['valid'] = $getid3_id3v2->Analyze()) { … … 1514 1581 1515 1582 $RIFFchunk = false; 1516 1583 $FoundAllChunksWeNeed = false; 1584 $LISTchunkParent = null; 1585 $LISTchunkMaxOffset = null; 1586 $AC3syncwordBytes = pack('n', getid3_ac3::syncword); // 0x0B77 -> "\x0B\x77" 1517 1587 1518 1588 try { 1519 1589 $this->fseek($startoffset); … … 1557 1627 // MP3 1558 1628 if (getid3_mp3::MPEGaudioHeaderBytesValid($FirstFourBytes)) { 1559 1629 $getid3_temp = new getID3(); 1560 $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);1630 $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp); 1561 1631 $getid3_temp->info['avdataoffset'] = $this->ftell() - 4; 1562 1632 $getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize; 1563 1633 $getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__); … … 1575 1645 unset($getid3_temp, $getid3_mp3); 1576 1646 } 1577 1647 1578 } elseif (strpos($FirstFourBytes, getid3_ac3::syncword) === 0) { 1579 1648 } elseif (strpos($FirstFourBytes, $AC3syncwordBytes) === 0) { 1580 1649 // AC3 1581 1650 $getid3_temp = new getID3(); 1582 $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);1651 $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp); 1583 1652 $getid3_temp->info['avdataoffset'] = $this->ftell() - 4; 1584 1653 $getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize; 1585 1654 $getid3_ac3 = new getid3_ac3($getid3_temp); … … 1640 1709 // Probably is MP3 data 1641 1710 if (getid3_mp3::MPEGaudioHeaderBytesValid(substr($testData, 0, 4))) { 1642 1711 $getid3_temp = new getID3(); 1643 $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);1712 $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp); 1644 1713 $getid3_temp->info['avdataoffset'] = $info['avdataoffset']; 1645 1714 $getid3_temp->info['avdataend'] = $info['avdataend']; 1646 1715 $getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__); … … 1652 1721 unset($getid3_temp, $getid3_mp3); 1653 1722 } 1654 1723 1655 } elseif (($isRegularAC3 = (substr($testData, 0, 2) == getid3_ac3::syncword)) || substr($testData, 8, 2) == strrev(getid3_ac3::syncword)) {1724 } elseif (($isRegularAC3 = (substr($testData, 0, 2) == $AC3syncwordBytes)) || substr($testData, 8, 2) == strrev($AC3syncwordBytes)) { 1656 1725 1657 1726 // This is probably AC-3 data 1658 1727 $getid3_temp = new getID3(); 1659 1728 if ($isRegularAC3) { 1660 $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);1729 $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp); 1661 1730 $getid3_temp->info['avdataoffset'] = $info['avdataoffset']; 1662 1731 $getid3_temp->info['avdataend'] = $info['avdataend']; 1663 1732 } … … 1673 1742 $ac3_data .= substr($testData, 8 + $i + 1, 1); 1674 1743 $ac3_data .= substr($testData, 8 + $i + 0, 1); 1675 1744 } 1745 $getid3_ac3->getid3->info['avdataoffset'] = 0; 1746 $getid3_ac3->getid3->info['avdataend'] = strlen($ac3_data); 1676 1747 $getid3_ac3->AnalyzeString($ac3_data); 1677 1748 } 1678 1749 … … 1691 1762 1692 1763 // This is probably DTS data 1693 1764 $getid3_temp = new getID3(); 1694 $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);1765 $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp); 1695 1766 $getid3_temp->info['avdataoffset'] = $info['avdataoffset']; 1696 1767 $getid3_dts = new getid3_dts($getid3_temp); 1697 1768 $getid3_dts->Analyze(); … … 1732 1803 case 'indx': 1733 1804 case 'MEXT': 1734 1805 case 'DISP': 1806 case 'wamd': 1807 case 'guan': 1735 1808 // always read data in 1736 1809 case 'JUNK': 1737 1810 // should be: never read data in … … 2076 2149 */ 2077 2150 public static function ParseBITMAPINFOHEADER($BITMAPINFOHEADER, $littleEndian=true) { 2078 2151 2152 $parsed = array(); 2079 2153 $parsed['biSize'] = substr($BITMAPINFOHEADER, 0, 4); // number of bytes required by the BITMAPINFOHEADER structure 2080 2154 $parsed['biWidth'] = substr($BITMAPINFOHEADER, 4, 4); // width of the bitmap in pixels 2081 2155 $parsed['biHeight'] = substr($BITMAPINFOHEADER, 8, 4); // height of the bitmap in pixels. If biHeight is positive, the bitmap is a 'bottom-up' DIB and its origin is the lower left corner. If biHeight is negative, the bitmap is a 'top-down' DIB and its origin is the upper left corner -
src/wp-includes/ID3/module.audio.flac.php
402 402 public function parsePICTURE() { 403 403 $info = &$this->getid3->info; 404 404 405 $picture = array(); 405 406 $picture['typeid'] = getid3_lib::BigEndian2Int($this->fread(4)); 406 407 $picture['picturetype'] = self::pictureTypeLookup($picture['typeid']); 407 408 $picture['image_mime'] = $this->fread(getid3_lib::BigEndian2Int($this->fread(4))); -
src/wp-includes/ID3/module.audio.mp3.php
18 18 exit; 19 19 } 20 20 21 // number of frames to scan to determine if MPEG-audio sequence is valid22 // Lower this number to 5-20 for faster scanning23 // Increase this number to 50+ for most accurate detection of valid VBR/CBR24 // mpeg-audio streams25 define('GETID3_MP3_VALID_CHECK_FRAMES', 35);26 21 27 28 22 class getid3_mp3 extends getid3_handler 29 23 { 30 24 /** … … 36 30 public $allow_bruteforce = false; 37 31 38 32 /** 33 * number of frames to scan to determine if MPEG-audio sequence is valid 34 * Lower this number to 5-20 for faster scanning 35 * Increase this number to 50+ for most accurate detection of valid VBR/CBR mpeg-audio streams 36 * 37 * @var int 38 */ 39 public $mp3_valid_check_frames = 50; 40 41 /** 39 42 * @return bool 40 43 */ 41 44 public function Analyze() { … … 55 58 $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']); 56 59 } 57 60 61 $CurrentDataLAMEversionString = null; 58 62 if (((isset($info['id3v2']['headerlength']) && ($info['avdataoffset'] > $info['id3v2']['headerlength'])) || (!isset($info['id3v2']) && ($info['avdataoffset'] > 0) && ($info['avdataoffset'] != $initialOffset)))) { 59 63 60 64 $synchoffsetwarning = 'Unknown data before synch '; … … 121 125 if (substr($PossiblyLongerLAMEversion_String, 0, strlen($CurrentDataLAMEversionString)) == $CurrentDataLAMEversionString) { 122 126 $PossiblyLongerLAMEversion_NewString = substr($PossiblyLongerLAMEversion_String, 0, strspn($PossiblyLongerLAMEversion_String, 'LAME0123456789., (abcdefghijklmnopqrstuvwxyzJFSOND)')); //"LAME3.90.3" "LAME3.87 (beta 1, Sep 27 2000)" "LAME3.88 (beta)" 123 127 if (empty($info['audio']['encoder']) || (strlen($PossiblyLongerLAMEversion_NewString) > strlen($info['audio']['encoder']))) { 128 if (!empty($info['audio']['encoder']) && !empty($info['mpeg']['audio']['LAME']['short_version']) && ($info['audio']['encoder'] == $info['mpeg']['audio']['LAME']['short_version'])) { 129 if (preg_match('#^LAME[0-9\\.]+#', $PossiblyLongerLAMEversion_NewString, $matches)) { 130 // "LAME3.100" -> "LAME3.100.1", but avoid including "(alpha)" and similar 131 $info['mpeg']['audio']['LAME']['short_version'] = $matches[0]; 132 } 133 } 124 134 $info['audio']['encoder'] = $PossiblyLongerLAMEversion_NewString; 125 135 } 126 136 } … … 295 305 } elseif (!empty($info['audio']['bitrate'])) { 296 306 297 307 if ($info['audio']['bitrate_mode'] == 'cbr') { 298 $encoder_options = strtoupper($info['audio']['bitrate_mode']). ceil($info['audio']['bitrate'] / 1000);308 $encoder_options = strtoupper($info['audio']['bitrate_mode']).round($info['audio']['bitrate'] / 1000); 299 309 } else { 300 310 $encoder_options = strtoupper($info['audio']['bitrate_mode']); 301 311 } … … 488 498 if ($MPEGaudioHeaderValidCache[$head4_key]) { 489 499 $thisfile_mpeg_audio['raw'] = $MPEGheaderRawArray; 490 500 } else { 491 $this-> error('Invalid MPEG audio header ('.getid3_lib::PrintHexBytes($head4).') at offset '.$offset);501 $this->warning('Invalid MPEG audio header ('.getid3_lib::PrintHexBytes($head4).') at offset '.$offset); 492 502 return false; 493 503 } 494 504 … … 722 732 723 733 $thisfile_mpeg_audio_lame['long_version'] = substr($headerstring, $VBRidOffset + 120, 20); 724 734 $thisfile_mpeg_audio_lame['short_version'] = substr($thisfile_mpeg_audio_lame['long_version'], 0, 9); 725 $thisfile_mpeg_audio_lame['numeric_version'] = str_replace('LAME', '', $thisfile_mpeg_audio_lame['short_version']); 726 if (preg_match('#^LAME([0-9\\.a-z]+)#', $thisfile_mpeg_audio_lame['long_version'], $matches)) { 735 736 //$thisfile_mpeg_audio_lame['numeric_version'] = str_replace('LAME', '', $thisfile_mpeg_audio_lame['short_version']); 737 $thisfile_mpeg_audio_lame['numeric_version'] = ''; 738 if (preg_match('#^LAME([0-9\\.a-z]*)#', $thisfile_mpeg_audio_lame['long_version'], $matches)) { 727 739 $thisfile_mpeg_audio_lame['short_version'] = $matches[0]; 728 740 $thisfile_mpeg_audio_lame['numeric_version'] = $matches[1]; 729 741 } 730 foreach (explode('.', $thisfile_mpeg_audio_lame['numeric_version']) as $key => $number) { 731 $thisfile_mpeg_audio_lame['integer_version'][$key] = intval($number); 732 } 742 if (strlen($thisfile_mpeg_audio_lame['numeric_version']) > 0) { 743 foreach (explode('.', $thisfile_mpeg_audio_lame['numeric_version']) as $key => $number) { 744 $thisfile_mpeg_audio_lame['integer_version'][$key] = intval($number); 745 } 746 //if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.90') { 747 if ((($thisfile_mpeg_audio_lame['integer_version'][0] * 1000) + $thisfile_mpeg_audio_lame['integer_version'][1]) >= 3090) { // cannot use string version compare, may have "LAME3.90" or "LAME3.100" -- see https://github.com/JamesHeinrich/getID3/issues/207 733 748 734 //if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.90') {735 if ((($thisfile_mpeg_audio_lame['integer_version'][0] * 1000) + $thisfile_mpeg_audio_lame['integer_version'][1]) >= 3090) { // cannot use string version compare, may have "LAME3.90" or "LAME3.100" -- see https://github.com/JamesHeinrich/getID3/issues/207749 // extra 11 chars are not part of version string when LAMEtag present 750 unset($thisfile_mpeg_audio_lame['long_version']); 736 751 737 // extra 11 chars are not part of version string when LAMEtag present738 unset($thisfile_mpeg_audio_lame['long_version']);752 // It the LAME tag was only introduced in LAME v3.90 753 // http://www.hydrogenaudio.org/?act=ST&f=15&t=9933 739 754 740 // It the LAME tag was only introduced in LAME v3.90 741 // http://www.hydrogenaudio.org/?act=ST&f=15&t=9933 755 // Offsets of various bytes in http://gabriel.mp3-tech.org/mp3infotag.html 756 // are assuming a 'Xing' identifier offset of 0x24, which is the case for 757 // MPEG-1 non-mono, but not for other combinations 758 $LAMEtagOffsetContant = $VBRidOffset - 0x24; 742 759 743 // Offsets of various bytes in http://gabriel.mp3-tech.org/mp3infotag.html 744 // are assuming a 'Xing' identifier offset of 0x24, which is the case for 745 // MPEG-1 non-mono, but not for other combinations 746 $LAMEtagOffsetContant = $VBRidOffset - 0x24; 760 // shortcuts 761 $thisfile_mpeg_audio_lame['RGAD'] = array('track'=>array(), 'album'=>array()); 762 $thisfile_mpeg_audio_lame_RGAD = &$thisfile_mpeg_audio_lame['RGAD']; 763 $thisfile_mpeg_audio_lame_RGAD_track = &$thisfile_mpeg_audio_lame_RGAD['track']; 764 $thisfile_mpeg_audio_lame_RGAD_album = &$thisfile_mpeg_audio_lame_RGAD['album']; 765 $thisfile_mpeg_audio_lame['raw'] = array(); 766 $thisfile_mpeg_audio_lame_raw = &$thisfile_mpeg_audio_lame['raw']; 747 767 748 // shortcuts 749 $thisfile_mpeg_audio_lame['RGAD'] = array('track'=>array(), 'album'=>array()); 750 $thisfile_mpeg_audio_lame_RGAD = &$thisfile_mpeg_audio_lame['RGAD']; 751 $thisfile_mpeg_audio_lame_RGAD_track = &$thisfile_mpeg_audio_lame_RGAD['track']; 752 $thisfile_mpeg_audio_lame_RGAD_album = &$thisfile_mpeg_audio_lame_RGAD['album']; 753 $thisfile_mpeg_audio_lame['raw'] = array(); 754 $thisfile_mpeg_audio_lame_raw = &$thisfile_mpeg_audio_lame['raw']; 768 // byte $9B VBR Quality 769 // This field is there to indicate a quality level, although the scale was not precised in the original Xing specifications. 770 // Actually overwrites original Xing bytes 771 unset($thisfile_mpeg_audio['VBR_scale']); 772 $thisfile_mpeg_audio_lame['vbr_quality'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0x9B, 1)); 755 773 756 // byte $9B VBR Quality 757 // This field is there to indicate a quality level, although the scale was not precised in the original Xing specifications. 758 // Actually overwrites original Xing bytes 759 unset($thisfile_mpeg_audio['VBR_scale']); 760 $thisfile_mpeg_audio_lame['vbr_quality'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0x9B, 1)); 774 // bytes $9C-$A4 Encoder short VersionString 775 $thisfile_mpeg_audio_lame['short_version'] = substr($headerstring, $LAMEtagOffsetContant + 0x9C, 9); 761 776 762 // bytes $9C-$A4 Encoder short VersionString763 $thisfile_mpeg_audio_lame['short_version'] = substr($headerstring, $LAMEtagOffsetContant + 0x9C, 9);777 // byte $A5 Info Tag revision + VBR method 778 $LAMEtagRevisionVBRmethod = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA5, 1)); 764 779 765 // byte $A5 Info Tag revision + VBR method 766 $LAMEtagRevisionVBRmethod = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA5, 1)); 780 $thisfile_mpeg_audio_lame['tag_revision'] = ($LAMEtagRevisionVBRmethod & 0xF0) >> 4; 781 $thisfile_mpeg_audio_lame_raw['vbr_method'] = $LAMEtagRevisionVBRmethod & 0x0F; 782 $thisfile_mpeg_audio_lame['vbr_method'] = self::LAMEvbrMethodLookup($thisfile_mpeg_audio_lame_raw['vbr_method']); 783 $thisfile_mpeg_audio['bitrate_mode'] = substr($thisfile_mpeg_audio_lame['vbr_method'], 0, 3); // usually either 'cbr' or 'vbr', but truncates 'vbr-old / vbr-rh' to 'vbr' 767 784 768 $thisfile_mpeg_audio_lame['tag_revision'] = ($LAMEtagRevisionVBRmethod & 0xF0) >> 4; 769 $thisfile_mpeg_audio_lame_raw['vbr_method'] = $LAMEtagRevisionVBRmethod & 0x0F; 770 $thisfile_mpeg_audio_lame['vbr_method'] = self::LAMEvbrMethodLookup($thisfile_mpeg_audio_lame_raw['vbr_method']); 771 $thisfile_mpeg_audio['bitrate_mode'] = substr($thisfile_mpeg_audio_lame['vbr_method'], 0, 3); // usually either 'cbr' or 'vbr', but truncates 'vbr-old / vbr-rh' to 'vbr' 785 // byte $A6 Lowpass filter value 786 $thisfile_mpeg_audio_lame['lowpass_frequency'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA6, 1)) * 100; 772 787 773 // byte $A6 Lowpass filter value 774 $thisfile_mpeg_audio_lame['lowpass_frequency'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA6, 1)) * 100; 788 // bytes $A7-$AE Replay Gain 789 // http://privatewww.essex.ac.uk/~djmrob/replaygain/rg_data_format.html 790 // bytes $A7-$AA : 32 bit floating point "Peak signal amplitude" 791 if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.94b') { 792 // LAME 3.94a16 and later - 9.23 fixed point 793 // ie 0x0059E2EE / (2^23) = 5890798 / 8388608 = 0.7022378444671630859375 794 $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] = (float) ((getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4))) / 8388608); 795 } else { 796 // LAME 3.94a15 and earlier - 32-bit floating point 797 // Actually 3.94a16 will fall in here too and be WRONG, but is hard to detect 3.94a16 vs 3.94a15 798 $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] = getid3_lib::LittleEndian2Float(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4)); 799 } 800 if ($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] == 0) { 801 unset($thisfile_mpeg_audio_lame_RGAD['peak_amplitude']); 802 } else { 803 $thisfile_mpeg_audio_lame_RGAD['peak_db'] = getid3_lib::RGADamplitude2dB($thisfile_mpeg_audio_lame_RGAD['peak_amplitude']); 804 } 775 805 776 // bytes $A7-$AE Replay Gain 777 // http://privatewww.essex.ac.uk/~djmrob/replaygain/rg_data_format.html 778 // bytes $A7-$AA : 32 bit floating point "Peak signal amplitude" 779 if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.94b') { 780 // LAME 3.94a16 and later - 9.23 fixed point 781 // ie 0x0059E2EE / (2^23) = 5890798 / 8388608 = 0.7022378444671630859375 782 $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] = (float) ((getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4))) / 8388608); 783 } else { 784 // LAME 3.94a15 and earlier - 32-bit floating point 785 // Actually 3.94a16 will fall in here too and be WRONG, but is hard to detect 3.94a16 vs 3.94a15 786 $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] = getid3_lib::LittleEndian2Float(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4)); 787 } 788 if ($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] == 0) { 789 unset($thisfile_mpeg_audio_lame_RGAD['peak_amplitude']); 790 } else { 791 $thisfile_mpeg_audio_lame_RGAD['peak_db'] = getid3_lib::RGADamplitude2dB($thisfile_mpeg_audio_lame_RGAD['peak_amplitude']); 792 } 806 $thisfile_mpeg_audio_lame_raw['RGAD_track'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAB, 2)); 807 $thisfile_mpeg_audio_lame_raw['RGAD_album'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAD, 2)); 793 808 794 $thisfile_mpeg_audio_lame_raw['RGAD_track'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAB, 2));795 $thisfile_mpeg_audio_lame_raw['RGAD_album'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAD, 2));796 809 810 if ($thisfile_mpeg_audio_lame_raw['RGAD_track'] != 0) { 797 811 798 if ($thisfile_mpeg_audio_lame_raw['RGAD_track'] != 0) { 812 $thisfile_mpeg_audio_lame_RGAD_track['raw']['name'] = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0xE000) >> 13; 813 $thisfile_mpeg_audio_lame_RGAD_track['raw']['originator'] = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x1C00) >> 10; 814 $thisfile_mpeg_audio_lame_RGAD_track['raw']['sign_bit'] = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x0200) >> 9; 815 $thisfile_mpeg_audio_lame_RGAD_track['raw']['gain_adjust'] = $thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x01FF; 816 $thisfile_mpeg_audio_lame_RGAD_track['name'] = getid3_lib::RGADnameLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['name']); 817 $thisfile_mpeg_audio_lame_RGAD_track['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['originator']); 818 $thisfile_mpeg_audio_lame_RGAD_track['gain_db'] = getid3_lib::RGADadjustmentLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_RGAD_track['raw']['sign_bit']); 799 819 800 $thisfile_mpeg_audio_lame_RGAD_track['raw']['name'] = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0xE000) >> 13; 801 $thisfile_mpeg_audio_lame_RGAD_track['raw']['originator'] = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x1C00) >> 10; 802 $thisfile_mpeg_audio_lame_RGAD_track['raw']['sign_bit'] = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x0200) >> 9; 803 $thisfile_mpeg_audio_lame_RGAD_track['raw']['gain_adjust'] = $thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x01FF; 804 $thisfile_mpeg_audio_lame_RGAD_track['name'] = getid3_lib::RGADnameLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['name']); 805 $thisfile_mpeg_audio_lame_RGAD_track['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['originator']); 806 $thisfile_mpeg_audio_lame_RGAD_track['gain_db'] = getid3_lib::RGADadjustmentLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_RGAD_track['raw']['sign_bit']); 807 808 if (!empty($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'])) { 809 $info['replay_gain']['track']['peak'] = $thisfile_mpeg_audio_lame_RGAD['peak_amplitude']; 820 if (!empty($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'])) { 821 $info['replay_gain']['track']['peak'] = $thisfile_mpeg_audio_lame_RGAD['peak_amplitude']; 822 } 823 $info['replay_gain']['track']['originator'] = $thisfile_mpeg_audio_lame_RGAD_track['originator']; 824 $info['replay_gain']['track']['adjustment'] = $thisfile_mpeg_audio_lame_RGAD_track['gain_db']; 825 } else { 826 unset($thisfile_mpeg_audio_lame_RGAD['track']); 810 827 } 811 $info['replay_gain']['track']['originator'] = $thisfile_mpeg_audio_lame_RGAD_track['originator']; 812 $info['replay_gain']['track']['adjustment'] = $thisfile_mpeg_audio_lame_RGAD_track['gain_db']; 813 } else { 814 unset($thisfile_mpeg_audio_lame_RGAD['track']); 815 } 816 if ($thisfile_mpeg_audio_lame_raw['RGAD_album'] != 0) { 828 if ($thisfile_mpeg_audio_lame_raw['RGAD_album'] != 0) { 817 829 818 $thisfile_mpeg_audio_lame_RGAD_album['raw']['name'] = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0xE000) >> 13;819 $thisfile_mpeg_audio_lame_RGAD_album['raw']['originator'] = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x1C00) >> 10;820 $thisfile_mpeg_audio_lame_RGAD_album['raw']['sign_bit'] = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x0200) >> 9;821 $thisfile_mpeg_audio_lame_RGAD_album['raw']['gain_adjust'] = $thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x01FF;822 $thisfile_mpeg_audio_lame_RGAD_album['name'] = getid3_lib::RGADnameLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['name']);823 $thisfile_mpeg_audio_lame_RGAD_album['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['originator']);824 $thisfile_mpeg_audio_lame_RGAD_album['gain_db'] = getid3_lib::RGADadjustmentLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_RGAD_album['raw']['sign_bit']);830 $thisfile_mpeg_audio_lame_RGAD_album['raw']['name'] = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0xE000) >> 13; 831 $thisfile_mpeg_audio_lame_RGAD_album['raw']['originator'] = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x1C00) >> 10; 832 $thisfile_mpeg_audio_lame_RGAD_album['raw']['sign_bit'] = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x0200) >> 9; 833 $thisfile_mpeg_audio_lame_RGAD_album['raw']['gain_adjust'] = $thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x01FF; 834 $thisfile_mpeg_audio_lame_RGAD_album['name'] = getid3_lib::RGADnameLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['name']); 835 $thisfile_mpeg_audio_lame_RGAD_album['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['originator']); 836 $thisfile_mpeg_audio_lame_RGAD_album['gain_db'] = getid3_lib::RGADadjustmentLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_RGAD_album['raw']['sign_bit']); 825 837 826 if (!empty($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'])) { 827 $info['replay_gain']['album']['peak'] = $thisfile_mpeg_audio_lame_RGAD['peak_amplitude']; 838 if (!empty($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'])) { 839 $info['replay_gain']['album']['peak'] = $thisfile_mpeg_audio_lame_RGAD['peak_amplitude']; 840 } 841 $info['replay_gain']['album']['originator'] = $thisfile_mpeg_audio_lame_RGAD_album['originator']; 842 $info['replay_gain']['album']['adjustment'] = $thisfile_mpeg_audio_lame_RGAD_album['gain_db']; 843 } else { 844 unset($thisfile_mpeg_audio_lame_RGAD['album']); 828 845 } 829 $info['replay_gain']['album']['originator'] = $thisfile_mpeg_audio_lame_RGAD_album['originator']; 830 $info['replay_gain']['album']['adjustment'] = $thisfile_mpeg_audio_lame_RGAD_album['gain_db']; 831 } else { 832 unset($thisfile_mpeg_audio_lame_RGAD['album']); 833 } 834 if (empty($thisfile_mpeg_audio_lame_RGAD)) { 835 unset($thisfile_mpeg_audio_lame['RGAD']); 836 } 846 if (empty($thisfile_mpeg_audio_lame_RGAD)) { 847 unset($thisfile_mpeg_audio_lame['RGAD']); 848 } 837 849 838 850 839 // byte $AF Encoding flags + ATH Type840 $EncodingFlagsATHtype = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAF, 1));841 $thisfile_mpeg_audio_lame['encoding_flags']['nspsytune'] = (bool) ($EncodingFlagsATHtype & 0x10);842 $thisfile_mpeg_audio_lame['encoding_flags']['nssafejoint'] = (bool) ($EncodingFlagsATHtype & 0x20);843 $thisfile_mpeg_audio_lame['encoding_flags']['nogap_next'] = (bool) ($EncodingFlagsATHtype & 0x40);844 $thisfile_mpeg_audio_lame['encoding_flags']['nogap_prev'] = (bool) ($EncodingFlagsATHtype & 0x80);845 $thisfile_mpeg_audio_lame['ath_type'] = $EncodingFlagsATHtype & 0x0F;851 // byte $AF Encoding flags + ATH Type 852 $EncodingFlagsATHtype = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAF, 1)); 853 $thisfile_mpeg_audio_lame['encoding_flags']['nspsytune'] = (bool) ($EncodingFlagsATHtype & 0x10); 854 $thisfile_mpeg_audio_lame['encoding_flags']['nssafejoint'] = (bool) ($EncodingFlagsATHtype & 0x20); 855 $thisfile_mpeg_audio_lame['encoding_flags']['nogap_next'] = (bool) ($EncodingFlagsATHtype & 0x40); 856 $thisfile_mpeg_audio_lame['encoding_flags']['nogap_prev'] = (bool) ($EncodingFlagsATHtype & 0x80); 857 $thisfile_mpeg_audio_lame['ath_type'] = $EncodingFlagsATHtype & 0x0F; 846 858 847 // byte $B0 if ABR {specified bitrate} else {minimal bitrate}848 $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB0, 1));849 if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 2) { // Average BitRate (ABR)850 $thisfile_mpeg_audio_lame['bitrate_abr'] = $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'];851 } elseif ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) { // Constant BitRate (CBR)852 // ignore853 } elseif ($thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] > 0) { // Variable BitRate (VBR) - minimum bitrate854 $thisfile_mpeg_audio_lame['bitrate_min'] = $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'];855 }859 // byte $B0 if ABR {specified bitrate} else {minimal bitrate} 860 $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB0, 1)); 861 if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 2) { // Average BitRate (ABR) 862 $thisfile_mpeg_audio_lame['bitrate_abr'] = $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate']; 863 } elseif ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) { // Constant BitRate (CBR) 864 // ignore 865 } elseif ($thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] > 0) { // Variable BitRate (VBR) - minimum bitrate 866 $thisfile_mpeg_audio_lame['bitrate_min'] = $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate']; 867 } 856 868 857 // bytes $B1-$B3 Encoder delays858 $EncoderDelays = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB1, 3));859 $thisfile_mpeg_audio_lame['encoder_delay'] = ($EncoderDelays & 0xFFF000) >> 12;860 $thisfile_mpeg_audio_lame['end_padding'] = $EncoderDelays & 0x000FFF;869 // bytes $B1-$B3 Encoder delays 870 $EncoderDelays = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB1, 3)); 871 $thisfile_mpeg_audio_lame['encoder_delay'] = ($EncoderDelays & 0xFFF000) >> 12; 872 $thisfile_mpeg_audio_lame['end_padding'] = $EncoderDelays & 0x000FFF; 861 873 862 // byte $B4 Misc863 $MiscByte = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB4, 1));864 $thisfile_mpeg_audio_lame_raw['noise_shaping'] = ($MiscByte & 0x03);865 $thisfile_mpeg_audio_lame_raw['stereo_mode'] = ($MiscByte & 0x1C) >> 2;866 $thisfile_mpeg_audio_lame_raw['not_optimal_quality'] = ($MiscByte & 0x20) >> 5;867 $thisfile_mpeg_audio_lame_raw['source_sample_freq'] = ($MiscByte & 0xC0) >> 6;868 $thisfile_mpeg_audio_lame['noise_shaping'] = $thisfile_mpeg_audio_lame_raw['noise_shaping'];869 $thisfile_mpeg_audio_lame['stereo_mode'] = self::LAMEmiscStereoModeLookup($thisfile_mpeg_audio_lame_raw['stereo_mode']);870 $thisfile_mpeg_audio_lame['not_optimal_quality'] = (bool) $thisfile_mpeg_audio_lame_raw['not_optimal_quality'];871 $thisfile_mpeg_audio_lame['source_sample_freq'] = self::LAMEmiscSourceSampleFrequencyLookup($thisfile_mpeg_audio_lame_raw['source_sample_freq']);874 // byte $B4 Misc 875 $MiscByte = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB4, 1)); 876 $thisfile_mpeg_audio_lame_raw['noise_shaping'] = ($MiscByte & 0x03); 877 $thisfile_mpeg_audio_lame_raw['stereo_mode'] = ($MiscByte & 0x1C) >> 2; 878 $thisfile_mpeg_audio_lame_raw['not_optimal_quality'] = ($MiscByte & 0x20) >> 5; 879 $thisfile_mpeg_audio_lame_raw['source_sample_freq'] = ($MiscByte & 0xC0) >> 6; 880 $thisfile_mpeg_audio_lame['noise_shaping'] = $thisfile_mpeg_audio_lame_raw['noise_shaping']; 881 $thisfile_mpeg_audio_lame['stereo_mode'] = self::LAMEmiscStereoModeLookup($thisfile_mpeg_audio_lame_raw['stereo_mode']); 882 $thisfile_mpeg_audio_lame['not_optimal_quality'] = (bool) $thisfile_mpeg_audio_lame_raw['not_optimal_quality']; 883 $thisfile_mpeg_audio_lame['source_sample_freq'] = self::LAMEmiscSourceSampleFrequencyLookup($thisfile_mpeg_audio_lame_raw['source_sample_freq']); 872 884 873 // byte $B5 MP3 Gain874 $thisfile_mpeg_audio_lame_raw['mp3_gain'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB5, 1), false, true);875 $thisfile_mpeg_audio_lame['mp3_gain_db'] = (getid3_lib::RGADamplitude2dB(2) / 4) * $thisfile_mpeg_audio_lame_raw['mp3_gain'];876 $thisfile_mpeg_audio_lame['mp3_gain_factor'] = pow(2, ($thisfile_mpeg_audio_lame['mp3_gain_db'] / 6));885 // byte $B5 MP3 Gain 886 $thisfile_mpeg_audio_lame_raw['mp3_gain'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB5, 1), false, true); 887 $thisfile_mpeg_audio_lame['mp3_gain_db'] = (getid3_lib::RGADamplitude2dB(2) / 4) * $thisfile_mpeg_audio_lame_raw['mp3_gain']; 888 $thisfile_mpeg_audio_lame['mp3_gain_factor'] = pow(2, ($thisfile_mpeg_audio_lame['mp3_gain_db'] / 6)); 877 889 878 // bytes $B6-$B7 Preset and surround info879 $PresetSurroundBytes = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB6, 2));880 // Reserved = ($PresetSurroundBytes & 0xC000);881 $thisfile_mpeg_audio_lame_raw['surround_info'] = ($PresetSurroundBytes & 0x3800);882 $thisfile_mpeg_audio_lame['surround_info'] = self::LAMEsurroundInfoLookup($thisfile_mpeg_audio_lame_raw['surround_info']);883 $thisfile_mpeg_audio_lame['preset_used_id'] = ($PresetSurroundBytes & 0x07FF);884 $thisfile_mpeg_audio_lame['preset_used'] = self::LAMEpresetUsedLookup($thisfile_mpeg_audio_lame);885 if (!empty($thisfile_mpeg_audio_lame['preset_used_id']) && empty($thisfile_mpeg_audio_lame['preset_used'])) {886 $this->warning('Unknown LAME preset used ('.$thisfile_mpeg_audio_lame['preset_used_id'].') - please report to info@getid3.org');887 }888 if (($thisfile_mpeg_audio_lame['short_version'] == 'LAME3.90.') && !empty($thisfile_mpeg_audio_lame['preset_used_id'])) {889 // this may change if 3.90.4 ever comes out890 $thisfile_mpeg_audio_lame['short_version'] = 'LAME3.90.3';891 }890 // bytes $B6-$B7 Preset and surround info 891 $PresetSurroundBytes = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB6, 2)); 892 // Reserved = ($PresetSurroundBytes & 0xC000); 893 $thisfile_mpeg_audio_lame_raw['surround_info'] = ($PresetSurroundBytes & 0x3800); 894 $thisfile_mpeg_audio_lame['surround_info'] = self::LAMEsurroundInfoLookup($thisfile_mpeg_audio_lame_raw['surround_info']); 895 $thisfile_mpeg_audio_lame['preset_used_id'] = ($PresetSurroundBytes & 0x07FF); 896 $thisfile_mpeg_audio_lame['preset_used'] = self::LAMEpresetUsedLookup($thisfile_mpeg_audio_lame); 897 if (!empty($thisfile_mpeg_audio_lame['preset_used_id']) && empty($thisfile_mpeg_audio_lame['preset_used'])) { 898 $this->warning('Unknown LAME preset used ('.$thisfile_mpeg_audio_lame['preset_used_id'].') - please report to info@getid3.org'); 899 } 900 if (($thisfile_mpeg_audio_lame['short_version'] == 'LAME3.90.') && !empty($thisfile_mpeg_audio_lame['preset_used_id'])) { 901 // this may change if 3.90.4 ever comes out 902 $thisfile_mpeg_audio_lame['short_version'] = 'LAME3.90.3'; 903 } 892 904 893 // bytes $B8-$BB MusicLength894 $thisfile_mpeg_audio_lame['audio_bytes'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB8, 4));895 $ExpectedNumberOfAudioBytes = (($thisfile_mpeg_audio_lame['audio_bytes'] > 0) ? $thisfile_mpeg_audio_lame['audio_bytes'] : $thisfile_mpeg_audio['VBR_bytes']);905 // bytes $B8-$BB MusicLength 906 $thisfile_mpeg_audio_lame['audio_bytes'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB8, 4)); 907 $ExpectedNumberOfAudioBytes = (($thisfile_mpeg_audio_lame['audio_bytes'] > 0) ? $thisfile_mpeg_audio_lame['audio_bytes'] : $thisfile_mpeg_audio['VBR_bytes']); 896 908 897 // bytes $BC-$BD MusicCRC898 $thisfile_mpeg_audio_lame['music_crc'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBC, 2));909 // bytes $BC-$BD MusicCRC 910 $thisfile_mpeg_audio_lame['music_crc'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBC, 2)); 899 911 900 // bytes $BE-$BF CRC-16 of Info Tag901 $thisfile_mpeg_audio_lame['lame_tag_crc'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBE, 2));912 // bytes $BE-$BF CRC-16 of Info Tag 913 $thisfile_mpeg_audio_lame['lame_tag_crc'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBE, 2)); 902 914 903 915 904 // LAME CBR905 if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) {916 // LAME CBR 917 if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) { 906 918 907 $thisfile_mpeg_audio['bitrate_mode'] = 'cbr';908 $thisfile_mpeg_audio['bitrate'] = self::ClosestStandardMP3Bitrate($thisfile_mpeg_audio['bitrate']);909 $info['audio']['bitrate'] = $thisfile_mpeg_audio['bitrate'];910 //if (empty($thisfile_mpeg_audio['bitrate']) || (!empty($thisfile_mpeg_audio_lame['bitrate_min']) && ($thisfile_mpeg_audio_lame['bitrate_min'] != 255))) {911 // $thisfile_mpeg_audio['bitrate'] = $thisfile_mpeg_audio_lame['bitrate_min'];912 //}919 $thisfile_mpeg_audio['bitrate_mode'] = 'cbr'; 920 $thisfile_mpeg_audio['bitrate'] = self::ClosestStandardMP3Bitrate($thisfile_mpeg_audio['bitrate']); 921 $info['audio']['bitrate'] = $thisfile_mpeg_audio['bitrate']; 922 //if (empty($thisfile_mpeg_audio['bitrate']) || (!empty($thisfile_mpeg_audio_lame['bitrate_min']) && ($thisfile_mpeg_audio_lame['bitrate_min'] != 255))) { 923 // $thisfile_mpeg_audio['bitrate'] = $thisfile_mpeg_audio_lame['bitrate_min']; 924 //} 913 925 926 } 927 914 928 } 915 916 929 } 917 930 } 918 931 … … 1009 1022 if (!$this->RecursiveFrameScanning($offset, $nextframetestoffset, $ScanAsCBR)) { 1010 1023 return false; 1011 1024 } 1025 if (!empty($this->getid3->info['mp3_validity_check_bitrates']) && !empty($thisfile_mpeg_audio['bitrate_mode']) && ($thisfile_mpeg_audio['bitrate_mode'] == 'vbr') && !empty($thisfile_mpeg_audio['VBR_bitrate'])) { 1026 // https://github.com/JamesHeinrich/getID3/issues/287 1027 if (count(array_keys($this->getid3->info['mp3_validity_check_bitrates'])) == 1) { 1028 list($cbr_bitrate_in_short_scan) = array_keys($this->getid3->info['mp3_validity_check_bitrates']); 1029 $deviation_cbr_from_header_bitrate = abs($thisfile_mpeg_audio['VBR_bitrate'] - $cbr_bitrate_in_short_scan) / $cbr_bitrate_in_short_scan; 1030 if ($deviation_cbr_from_header_bitrate < 0.01) { 1031 // VBR header bitrate may differ slightly from true bitrate of frames, perhaps accounting for overhead of VBR header frame itself? 1032 // If measured CBR bitrate is within 1% of specified bitrate in VBR header then assume that file is truly CBR 1033 $thisfile_mpeg_audio['bitrate_mode'] = 'cbr'; 1034 //$this->warning('VBR header ignored, assuming CBR '.round($cbr_bitrate_in_short_scan / 1000).'kbps based on scan of '.$this->mp3_valid_check_frames.' frames'); 1035 } 1036 } 1037 } 1038 if (isset($this->getid3->info['mp3_validity_check_bitrates'])) { 1039 unset($this->getid3->info['mp3_validity_check_bitrates']); 1040 } 1012 1041 1013 1042 } 1014 1043 … … 1130 1159 $firstframetestarray = array('error' => array(), 'warning'=> array(), 'avdataend' => $info['avdataend'], 'avdataoffset' => $info['avdataoffset']); 1131 1160 $this->decodeMPEGaudioHeader($offset, $firstframetestarray, false); 1132 1161 1133 for ($i = 0; $i < GETID3_MP3_VALID_CHECK_FRAMES; $i++) { 1134 // check next GETID3_MP3_VALID_CHECK_FRAMES frames for validity, to make sure we haven't run across a false synch 1162 $info['mp3_validity_check_bitrates'] = array(); 1163 for ($i = 0; $i < $this->mp3_valid_check_frames; $i++) { 1164 // check next (default: 50) frames for validity, to make sure we haven't run across a false synch 1135 1165 if (($nextframetestoffset + 4) >= $info['avdataend']) { 1136 1166 // end of file 1137 1167 return true; … … 1139 1169 1140 1170 $nextframetestarray = array('error' => array(), 'warning' => array(), 'avdataend' => $info['avdataend'], 'avdataoffset'=>$info['avdataoffset']); 1141 1171 if ($this->decodeMPEGaudioHeader($nextframetestoffset, $nextframetestarray, false)) { 1172 getid3_lib::safe_inc($info['mp3_validity_check_bitrates'][$nextframetestarray['mpeg']['audio']['bitrate']]); 1142 1173 if ($ScanAsCBR) { 1143 1174 // force CBR mode, used for trying to pick out invalid audio streams with valid(?) VBR headers, or VBR streams with no VBR header 1144 1175 if (!isset($nextframetestarray['mpeg']['audio']['bitrate']) || !isset($firstframetestarray['mpeg']['audio']['bitrate']) || ($nextframetestarray['mpeg']['audio']['bitrate'] != $firstframetestarray['mpeg']['audio']['bitrate'])) { … … 1273 1304 $LongMPEGbitrateLookup = array(); 1274 1305 $LongMPEGpaddingLookup = array(); 1275 1306 $LongMPEGfrequencyLookup = array(); 1307 $Distribution = array(); 1276 1308 $Distribution['bitrate'] = array(); 1277 1309 $Distribution['frequency'] = array(); 1278 1310 $Distribution['layer'] = array(); … … 1433 1465 $header = $this->fread($sync_seek_buffer_size); 1434 1466 $sync_seek_buffer_size = strlen($header); 1435 1467 $SynchSeekOffset = 0; 1468 $SyncSeekAttempts = 0; 1469 $SyncSeekAttemptsMax = 1000; 1470 $FirstFrameThisfileInfo = null; 1436 1471 while ($SynchSeekOffset < $sync_seek_buffer_size) { 1437 1472 if ((($avdataoffset + $SynchSeekOffset) < $info['avdataend']) && !feof($this->getid3->fp)) { 1438 1473 … … 1471 1506 return false; 1472 1507 } 1473 1508 1474 if (($header[$SynchSeekOffset] == "\xFF") && ($header[($SynchSeekOffset + 1)] > "\xE0")) { // synch detected 1509 if (($header[$SynchSeekOffset] == "\xFF") && ($header[($SynchSeekOffset + 1)] > "\xE0")) { // possible synch detected 1510 if (++$SyncSeekAttempts >= $SyncSeekAttemptsMax) { 1511 // https://github.com/JamesHeinrich/getID3/issues/286 1512 // corrupt files claiming to be MP3, with a large number of 0xFF bytes near the beginning, can cause this loop to take a very long time 1513 // should have escape condition to avoid spending too much time scanning a corrupt file 1514 // if a synch's not found within the first 128k bytes, then give up 1515 $this->error('Could not find valid MPEG audio synch after scanning '.$SyncSeekAttempts.' candidate offsets'); 1516 if (isset($info['audio']['bitrate'])) { 1517 unset($info['audio']['bitrate']); 1518 } 1519 if (isset($info['mpeg']['audio'])) { 1520 unset($info['mpeg']['audio']); 1521 } 1522 if (empty($info['mpeg'])) { 1523 unset($info['mpeg']); 1524 } 1525 return false; 1526 } 1475 1527 $FirstFrameAVDataOffset = null; 1476 1528 if (!isset($FirstFrameThisfileInfo) && !isset($info['mpeg']['audio'])) { 1477 1529 $FirstFrameThisfileInfo = $info; … … 1511 1563 if ($this->decodeMPEGaudioHeader($GarbageOffsetEnd, $dummy, true, true)) { 1512 1564 $info = $dummy; 1513 1565 $info['avdataoffset'] = $GarbageOffsetEnd; 1514 $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);1566 $this->warning('apparently-valid VBR header not used because could not find '.$this->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); 1515 1567 } else { 1516 $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.')');1568 $this->warning('using data from VBR header even though could not find '.$this->mp3_valid_check_frames.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.')'); 1517 1569 } 1518 1570 } 1519 1571 } … … 1558 1610 $pct_data_scanned = 0; 1559 1611 for ($current_segment = 0; $current_segment < $max_scan_segments; $current_segment++) { 1560 1612 $frames_scanned_this_segment = 0; 1613 $scan_start_offset = array(); 1561 1614 if ($this->ftell() >= $info['avdataend']) { 1562 1615 break; 1563 1616 } … … 1887 1940 return false; 1888 1941 } 1889 1942 1943 $MPEGrawHeader = array(); 1890 1944 $MPEGrawHeader['synch'] = (getid3_lib::BigEndian2Int(substr($Header4Bytes, 0, 2)) & 0xFFE0) >> 4; 1891 1945 $MPEGrawHeader['version'] = (ord($Header4Bytes[1]) & 0x18) >> 3; // BB 1892 1946 $MPEGrawHeader['layer'] = (ord($Header4Bytes[1]) & 0x06) >> 1; // CC -
src/wp-includes/ID3/module.audio.ogg.php
529 529 */ 530 530 public function ParseOggPageHeader() { 531 531 // http://xiph.org/ogg/vorbis/doc/framing.html 532 $oggheader = array(); 532 533 $oggheader['page_start_offset'] = $this->ftell(); // where we started from in the file 533 534 534 535 $filedata = $this->fread($this->getid3->fread_buffer_size()); … … 680 681 681 682 $VorbisCommentPage++; 682 683 683 $oggpageinfo = $this->ParseOggPageHeader();684 $info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;684 if ($oggpageinfo = $this->ParseOggPageHeader()) { 685 $info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo; 685 686 686 // First, save what we haven't read yet687 $AsYetUnusedData = substr($commentdata, $commentdataoffset);687 // First, save what we haven't read yet 688 $AsYetUnusedData = substr($commentdata, $commentdataoffset); 688 689 689 // Then take that data off the end690 $commentdata = substr($commentdata, 0, $commentdataoffset);690 // Then take that data off the end 691 $commentdata = substr($commentdata, 0, $commentdataoffset); 691 692 692 // Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct693 $commentdata .= str_repeat("\x00", 27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);694 $commentdataoffset += (27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);693 // Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct 694 $commentdata .= str_repeat("\x00", 27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']); 695 $commentdataoffset += (27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']); 695 696 696 // Finally, stick the unused data back on the end697 $commentdata .= $AsYetUnusedData;697 // Finally, stick the unused data back on the end 698 $commentdata .= $AsYetUnusedData; 698 699 699 //$commentdata .= $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']); 700 if (!isset($info['ogg']['pageheader'][$VorbisCommentPage])) { 701 $this->warning('undefined Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell()); 700 //$commentdata .= $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']); 701 if (!isset($info['ogg']['pageheader'][$VorbisCommentPage])) { 702 $this->warning('undefined Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell()); 703 break; 704 } 705 $readlength = self::OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1); 706 if ($readlength <= 0) { 707 $this->warning('invalid length Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell()); 708 break; 709 } 710 $commentdata .= $this->fread($readlength); 711 712 //$filebaseoffset += $oggpageinfo['header_end_offset'] - $oggpageinfo['page_start_offset']; 713 } else { 714 $this->warning('failed to ParseOggPageHeader() at offset '.$this->ftell()); 702 715 break; 703 716 } 704 $readlength = self::OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1);705 if ($readlength <= 0) {706 $this->warning('invalid length Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell());707 break;708 }709 $commentdata .= $this->fread($readlength);710 711 //$filebaseoffset += $oggpageinfo['header_end_offset'] - $oggpageinfo['page_start_offset'];712 717 } 713 718 $ThisFileInfo_ogg_comments_raw[$i]['offset'] = $commentdataoffset; 714 719 $commentstring = substr($commentdata, $commentdataoffset, $ThisFileInfo_ogg_comments_raw[$i]['size']); -
src/wp-includes/ID3/module.tag.apetag.php
360 360 // http://www.uni-jena.de/~pfk/mpp/sv8/apeheader.html 361 361 362 362 // shortcut 363 $headerfooterinfo = array(); 363 364 $headerfooterinfo['raw'] = array(); 364 365 $headerfooterinfo_raw = &$headerfooterinfo['raw']; 365 366 … … 389 390 // "Note: APE Tags 1.0 do not use any of the APE Tag flags. 390 391 // All are set to zero on creation and ignored on reading." 391 392 // http://wiki.hydrogenaud.io/index.php?title=Ape_Tags_Flags 393 $flags = array(); 392 394 $flags['header'] = (bool) ($rawflagint & 0x80000000); 393 395 $flags['footer'] = (bool) ($rawflagint & 0x40000000); 394 396 $flags['this_is_header'] = (bool) ($rawflagint & 0x20000000); -
src/wp-includes/ID3/module.tag.id3v1.php
31 31 return false; 32 32 } 33 33 34 $this->fseek(-256, SEEK_END); 35 $preid3v1 = $this->fread(128); 36 $id3v1tag = $this->fread(128); 34 if($info['filesize'] < 256) { 35 $this->fseek(-128, SEEK_END); 36 $preid3v1 = ''; 37 $id3v1tag = $this->fread(128); 38 } else { 39 $this->fseek(-256, SEEK_END); 40 $preid3v1 = $this->fread(128); 41 $id3v1tag = $this->fread(128); 42 } 37 43 44 38 45 if (substr($id3v1tag, 0, 3) == 'TAG') { 39 46 40 47 $info['avdataend'] = $info['filesize'] - 128; 41 48 49 $ParsedID3v1 = array(); 42 50 $ParsedID3v1['title'] = $this->cutfield(substr($id3v1tag, 3, 30)); 43 51 $ParsedID3v1['artist'] = $this->cutfield(substr($id3v1tag, 33, 30)); 44 52 $ParsedID3v1['album'] = $this->cutfield(substr($id3v1tag, 63, 30)); … … 297 305 145 => 'Anime', 298 306 146 => 'JPop', 299 307 147 => 'Synthpop', 308 148 => 'Abstract', 309 149 => 'Art Rock', 310 150 => 'Baroque', 311 151 => 'Bhangra', 312 152 => 'Big Beat', 313 153 => 'Breakbeat', 314 154 => 'Chillout', 315 155 => 'Downtempo', 316 156 => 'Dub', 317 157 => 'EBM', 318 158 => 'Eclectic', 319 159 => 'Electro', 320 160 => 'Electroclash', 321 161 => 'Emo', 322 162 => 'Experimental', 323 163 => 'Garage', 324 164 => 'Global', 325 165 => 'IDM', 326 166 => 'Illbient', 327 167 => 'Industro-Goth', 328 168 => 'Jam Band', 329 169 => 'Krautrock', 330 170 => 'Leftfield', 331 171 => 'Lounge', 332 172 => 'Math Rock', 333 173 => 'New Romantic', 334 174 => 'Nu-Breakz', 335 175 => 'Post-Punk', 336 176 => 'Post-Rock', 337 177 => 'Psytrance', 338 178 => 'Shoegaze', 339 179 => 'Space Rock', 340 180 => 'Trop Rock', 341 181 => 'World Music', 342 182 => 'Neoclassical', 343 183 => 'Audiobook', 344 184 => 'Audio Theatre', 345 185 => 'Neue Deutsche Welle', 346 186 => 'Podcast', 347 187 => 'Indie-Rock', 348 188 => 'G-Funk', 349 189 => 'Dubstep', 350 190 => 'Garage Rock', 351 191 => 'Psybient', 300 352 301 353 255 => 'Unknown', 302 354 -
src/wp-includes/ID3/module.tag.id3v2.php
345 345 } 346 346 if (($frame_size <= strlen($framedata)) && ($this->IsValidID3v2FrameName($frame_name, $id3v2_majorversion))) { 347 347 348 unset($parsedFrame);348 $parsedFrame = array(); 349 349 $parsedFrame['frame_name'] = $frame_name; 350 350 $parsedFrame['frame_flags_raw'] = $frame_flags; 351 351 $parsedFrame['data'] = substr($framedata, 0, $frame_size); … … 978 978 979 979 980 980 } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'USLT')) || // 4.8 USLT Unsynchronised lyric/text transcription 981 (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'ULT'))) { 981 (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'ULT'))) { // 4.9 ULT Unsynchronised lyric/text transcription 982 982 // There may be more than one 'Unsynchronised lyrics/text transcription' frame 983 983 // in each tag, but only one with the same language and content descriptor. 984 984 // <Header for 'Unsynchronised lyrics/text transcription', ID: 'USLT'> … … 994 994 $this->warning('Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'); 995 995 $frame_textencoding_terminator = "\x00"; 996 996 } 997 $frame_language = substr($parsedFrame['data'], $frame_offset, 3); 998 $frame_offset += 3; 999 $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset); 1000 if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) { 1001 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 1002 } 1003 $parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); 1004 $parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']); 1005 $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator)); 1006 $parsedFrame['data'] = $this->RemoveStringTerminator($parsedFrame['data'], $frame_textencoding_terminator); 997 if (strlen($parsedFrame['data']) >= (4 + strlen($frame_textencoding_terminator))) { // shouldn't be an issue but badly-written files have been spotted in the wild with not only no contents but also missing the required language field, see https://github.com/JamesHeinrich/getID3/issues/315 998 $frame_language = substr($parsedFrame['data'], $frame_offset, 3); 999 $frame_offset += 3; 1000 $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset); 1001 if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) { 1002 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 1003 } 1004 $parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); 1005 $parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']); 1006 $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator)); 1007 $parsedFrame['data'] = $this->RemoveStringTerminator($parsedFrame['data'], $frame_textencoding_terminator); 1007 1008 1008 $parsedFrame['encodingid'] = $frame_textencoding;1009 $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);1009 $parsedFrame['encodingid'] = $frame_textencoding; 1010 $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); 1010 1011 1011 $parsedFrame['language'] = $frame_language; 1012 $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false); 1013 if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) { 1014 $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']); 1012 $parsedFrame['language'] = $frame_language; 1013 $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false); 1014 if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) { 1015 $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']); 1016 } 1017 } else { 1018 $this->warning('Invalid data in frame "'.$parsedFrame['frame_name'].'" at offset '.$parsedFrame['dataoffset']); 1015 1019 } 1016 1020 unset($parsedFrame['data']); 1017 1021 … … 1370 1374 $frame_textencoding_terminator = "\x00"; 1371 1375 } 1372 1376 1377 $frame_imagetype = null; 1378 $frame_mimetype = null; 1373 1379 if ($id3v2_majorversion == 2 && strlen($parsedFrame['data']) > $frame_offset) { 1374 1380 $frame_imagetype = substr($parsedFrame['data'], $frame_offset, 3); 1375 1381 if (strtolower($frame_imagetype) == 'ima') { … … 1956 1962 $frame_offset = 0; 1957 1963 $parsedFrame['peakamplitude'] = getid3_lib::BigEndian2Float(substr($parsedFrame['data'], $frame_offset, 4)); 1958 1964 $frame_offset += 4; 1959 $rg_track_adjustment = getid3_lib::Dec2Bin(substr($parsedFrame['data'], $frame_offset, 2)); 1960 $frame_offset += 2; 1961 $rg_album_adjustment = getid3_lib::Dec2Bin(substr($parsedFrame['data'], $frame_offset, 2)); 1962 $frame_offset += 2; 1963 $parsedFrame['raw']['track']['name'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 0, 3)); 1964 $parsedFrame['raw']['track']['originator'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 3, 3)); 1965 $parsedFrame['raw']['track']['signbit'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 6, 1)); 1966 $parsedFrame['raw']['track']['adjustment'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 7, 9)); 1967 $parsedFrame['raw']['album']['name'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 0, 3)); 1968 $parsedFrame['raw']['album']['originator'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 3, 3)); 1969 $parsedFrame['raw']['album']['signbit'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 6, 1)); 1970 $parsedFrame['raw']['album']['adjustment'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 7, 9)); 1965 foreach (array('track','album') as $rgad_entry_type) { 1966 $rg_adjustment_word = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2)); 1967 $frame_offset += 2; 1968 $parsedFrame['raw'][$rgad_entry_type]['name'] = ($rg_adjustment_word & 0xE000) >> 13; 1969 $parsedFrame['raw'][$rgad_entry_type]['originator'] = ($rg_adjustment_word & 0x1C00) >> 10; 1970 $parsedFrame['raw'][$rgad_entry_type]['signbit'] = ($rg_adjustment_word & 0x0200) >> 9; 1971 $parsedFrame['raw'][$rgad_entry_type]['adjustment'] = ($rg_adjustment_word & 0x0100); 1972 } 1971 1973 $parsedFrame['track']['name'] = getid3_lib::RGADnameLookup($parsedFrame['raw']['track']['name']); 1972 1974 $parsedFrame['track']['originator'] = getid3_lib::RGADoriginatorLookup($parsedFrame['raw']['track']['originator']); 1973 1975 $parsedFrame['track']['adjustment'] = getid3_lib::RGADadjustmentLookup($parsedFrame['raw']['track']['adjustment'], $parsedFrame['raw']['track']['signbit']); … … 2444 2446 TMM Manats 2445 2447 TND Dinars 2446 2448 TOP Pa'anga 2447 TRL Liras 2449 TRL Liras (old) 2450 TRY Liras 2448 2451 TTD Dollars 2449 2452 TVD Tuvalu Dollars 2450 2453 TWD New Dollars … … 2645 2648 TND Tunisia 2646 2649 TOP Tonga 2647 2650 TRL Turkey 2651 TRY Turkey 2648 2652 TTD Trinidad and Tobago 2649 2653 TVD Tuvalu 2650 2654 TWD Taiwan -
src/wp-includes/ID3/module.tag.lyrics3.php
33 33 } 34 34 35 35 $this->fseek((0 - 128 - 9 - 6), SEEK_END); // end - ID3v1 - "LYRICSEND" - [Lyrics3size] 36 $lyrics3offset = null; 37 $lyrics3version = null; 38 $lyrics3size = null; 36 39 $lyrics3_id3v1 = $this->fread(128 + 9 + 6); 37 40 $lyrics3lsz = (int) substr($lyrics3_id3v1, 0, 6); // Lyrics3size 38 41 $lyrics3end = substr($lyrics3_id3v1, 6, 9); // LYRICSEND or LYRICS200 -
src/wp-includes/ID3/readme.txt
625 625 * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html 626 626 * http://www.codeproject.com/Articles/8295/MPEG-Audio-Frame-Header 627 627 * http://dsd-guide.com/sites/default/files/white-papers/DSFFileFormatSpec_E.pdf 628 * https://fileformats.fandom.com/wiki/Torrent_file 629 No newline at end of file