Make WordPress Core

Changeset 51900


Ignore:
Timestamp:
10/10/2021 12:12:03 AM (5 years ago)
Author:
SergeyBiryukov
Message:

External Libraries: Update getID3 to version 1.9.21.

The latest version includes preliminary PHP 8.1 support, as well as a variety of bug fixes.

Release notes: ​https://github.com/JamesHeinrich/getID3/releases/tag/v1.9.21

A full list of changes in this update can be found on GitHub:
​https://github.com/JamesHeinrich/getID3/compare/v1.9.20...v1.9.21

This commit also includes PHPCS adjustments previously made for a passing PHP Compatibility scan.

Follow-up to [47601], [47737], [47902], [48278], [49621], [50714].

Props jrf, SergeyBiryukov.
Fixes #54162.

Location:
trunk/src/wp-includes/ID3
Files:
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/ID3/getid3.lib.php

    r50714 r51900  
    243243         * ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic
    244244         *
    245          * @link http://www.psc.edu/general/software/packages/ieee/ieee.html
     245         * @link https://web.archive.org/web/20120325162206/http://www.psc.edu/general/software/packages/ieee/ieee.php
    246246         * @link http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html
    247247         *
    … …  
    295295                if (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction != 0)) {
    296296                        // Not a Number
    297                         $floatvalue = false;
     297                        $floatvalue = NAN;
    298298                } elseif (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction == 0)) {
    299299                        if ($signbit == '1') {
    300                                 $floatvalue = '-infinity';
     300                                $floatvalue = -INF;
    301301                        } else {
    302                                 $floatvalue = '+infinity';
     302                                $floatvalue = INF;
    303303                        }
    304304                } elseif (($exponent == 0) && ($fraction == 0)) {
    … …  
    428428         */
    429429        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();
    430436                while ($number >= 256) {
    431                         $bytes[] = (($number / 256) - (floor($number / 256))) * 256;
     437                        $bytes[] = (int) (($number / 256) - (floor($number / 256))) * 256;
    432438                        $number = floor($number / 256);
    433439                }
    434                 $bytes[] = $number;
     440                $bytes[] = (int) $number;
    435441                $binstring = '';
    436                 for ($i = 0; $i < count($bytes); $i++) {
    437                         $binstring = (($i == count($bytes) - 1) ? decbin($bytes[$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;
    438444                }
    439445                return $binstring;
    … …  
    666672                //   $foo['path']['to']['my'] = 'file.txt';
    667673                $ArrayPath = ltrim($ArrayPath, $Separator);
     674                $ReturnedArray = array();
    668675                if (($pos = strpos($ArrayPath, $Separator)) !== false) {
    669676                        $ReturnedArray[substr($ArrayPath, 0, $pos)] = self::CreateDeepArray(substr($ArrayPath, $pos + 1), $Separator, $Value);
    … …  
    15391546                // Copy all entries from ['tags'] into common ['comments']
    15401547                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                                }
    15471563                        }
    15481564                        foreach ($ThisFileInfo['tags'] as $tagtype => $tagarray) {
    … …  
    15631579                                                                                break 2;
    15641580                                                                        }
    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                                                                                }
    15711588                                                                        }
    15721589                                                                }
    … …  
    15741591                                                        } elseif (!is_array($value)) {
    15751592
    1576                                                                 $newvaluelength = strlen(trim($value));
     1593                                                                $newvaluelength   =    strlen(trim($value));
     1594                                                                $newvaluelengthMB = mb_strlen(trim($value));
    15771595                                                                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                                                                        }
    15791605                                                                        if ((strlen($existingvalue) > 10) && ($newvaluelength > $oldvaluelength) && (substr(trim($value), 0, strlen($existingvalue)) == $existingvalue)) {
    15801606                                                                                $ThisFileInfo['comments'][$tagname][$existingkey] = trim($value);
    … …  
    16021628
    16031629                        // 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                                        }
    16121640                                }
    16131641                        }
    … …  
    17351763         */
    17361764        public static function getFileSizeSyscall($path) {
     1765                $commandline = null;
    17371766                $filesize = false;
    17381767
    … …  
    17961825         * @return string
    17971826         */
    1798         public static function mb_basename($path, $suffix = null) {
     1827        public static function mb_basename($path, $suffix = '') {
    17991828                $splited = preg_split('#/#', rtrim($path, '/ '));
    18001829                return substr(basename('X'.$splited[count($splited) - 1], $suffix), 1);
  • trunk/src/wp-includes/ID3/getid3.php

    r48278 r51900  
    1717if (!defined('GETID3_INCLUDEPATH')) {
    1818        define('GETID3_INCLUDEPATH', dirname(__FILE__).DIRECTORY_SEPARATOR);
    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);
    2319}
    2420if (!defined('ENT_SUBSTITUTE')) { // PHP5.3 adds ENT_IGNORE, PHP5.4 adds ENT_SUBSTITUTE
    … …  
    5854                        $basedir .= DIRECTORY_SEPARATOR;
    5955                }
    60                 if (preg_match('#^'.preg_quote($basedir).'#', $temp_dir)) {
     56                if (strpos($temp_dir, $basedir) === 0) {
    6157                        $found_valid_tempdir = true;
    6258                        break;
    … …  
    215211        public $option_fread_buffer_size = 32768;
    216212
     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
    217347        // Public variables
    218348
    … …  
    258388        protected $startup_warning = '';
    259389
    260         const VERSION           = '1.9.20-202006061653';
     390        const VERSION           = '1.9.21-202109171300';
    261391        const FREAD_BUFFER_SIZE = 32768;
    262392
    … …  
    638768                        }
    639769                        $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
    640782                        $class->Analyze();
    641783                        unset($class);
    … …  
    13521494                                                        'module'    => 'msoffice',
    13531495                                                        'mime_type' => 'application/octet-stream',
     1496                                                        'fail_id3'  => 'ERROR',
     1497                                                        'fail_ape'  => 'ERROR',
     1498                                                ),
     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',
    13541506                                                        'fail_id3'  => 'ERROR',
    13551507                                                        'fail_ape'  => 'ERROR',
    … …  
    14901642                                                        $value = trim($value, " \r\n\t"); // do not trim nulls from $value!! Unicode characters will get mangled if trailing nulls are removed!
    14911643                                                }
    1492                                                 if ($value) {
     1644                                                if (isset($value) && $value !== "") {
    14931645                                                        if (!is_numeric($key)) {
    14941646                                                                $this->info['tags'][trim($tag_name)][trim($tag_key)][$key] = $value;
    … …  
    20972249                                        break;
    20982250                        }
    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                         }
    2110                 }
    2111                 return fseek($this->getid3->fp, $bytes, $whence);
     2251                        return 0; // fseek returns 0 on success
     2252                }
     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;
    21122270        }
    21132271
    … …  
    22252383         */
    22262384        public function saveAttachment($name, $offset, $length, $image_mime=null) {
     2385                $fp_dest = null;
     2386                $dest = null;
    22272387                try {
    22282388
  • trunk/src/wp-includes/ID3/module.audio-video.asf.php

    r48278 r51900  
    9494                $thisfile_asf_streambitratepropertiesobject = array();
    9595                $thisfile_asf_codeclistobject = array();
     96                $StreamPropertiesObjectData = array();
    9697
    9798                for ($HeaderObjectsCounter = 0; $HeaderObjectsCounter < $thisfile_asf_headerobject['headerobjects']; $HeaderObjectsCounter++) {
    … …  
    284285                                        $offset += 2;
    285286                                        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"');
    287288                                                //return false;
    288289                                                break;
    … …  
    536537                                        $offset += 2;
    537538                                        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"');
    539540                                                break;
    540541                                        }
    … …  
    11941195                                        $offset += 2;
    11951196                                        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"');
    11971198                                                //return false;
    11981199                                                break;
  • trunk/src/wp-includes/ID3/module.audio-video.flv.php

    r48278 r51900  
    162162
    163163                                                $FLVvideoHeader = $this->fread(11);
     164                                                $PictureSizeEnc = array();
    164165
    165166                                                if ($info['flv']['video']['videoCodec'] == GETID3_FLV_VIDEO_H264) {
  • trunk/src/wp-includes/ID3/module.audio-video.matroska.php

    r48278 r51900  
    225225         * @var bool
    226226         */
    227         public static $hide_clusters    = true;
     227        public $hide_clusters    = true;
    228228
    229229        /**
    … …  
    232232         * @var bool
    233233         */
    234         public static $parse_whole_file = false;
     234        public $parse_whole_file = false;
    235235
    236236        /*
    … …  
    587587
    588588                                        while ($this->getEBMLelement($element_data, $top_element['end'])) {
    589                                                 if ($element_data['id'] != EBML_ID_CLUSTER || !self::$hide_clusters) { // collect clusters only if required
     589                                                if ($element_data['id'] != EBML_ID_CLUSTER || !$this->hide_clusters) { // collect clusters only if required
    590590                                                        $info['matroska']['segments'][] = $element_data;
    591591                                                }
    … …  
    619619                                                                                                break;
    620620                                                                                        }
    621                                                                                         if (($seek_entry['target_id'] != EBML_ID_CLUSTER) || !self::$hide_clusters) { // collect clusters only if required
     621                                                                                        if (($seek_entry['target_id'] != EBML_ID_CLUSTER) || !$this->hide_clusters) { // collect clusters only if required
    622622                                                                                                $info['matroska']['seek'][] = $seek_entry;
    623623                                                                                        }
    … …  
    906906
    907907                                                        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 anyway
     908                                                                if ($this->hide_clusters) { // do not parse cues if hide clusters is "ON" till they point to clusters anyway
    909909                                                                        $this->current_offset = $element_data['end'];
    910910                                                                        break;
    … …  
    12471247                                                                        $this->current_offset = $subelement['end'];
    12481248                                                                }
    1249                                                                 if (!self::$hide_clusters) {
     1249                                                                if (!$this->hide_clusters) {
    12501250                                                                        $info['matroska']['cluster'][] = $cluster_entry;
    12511251                                                                }
    12521252
    12531253                                                                // 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) {
    12551255                                                                        if (isset($info['matroska']['info']) && is_array($info['matroska']['info'])) {
    12561256                                                                                if (isset($info['matroska']['tracks']['tracks']) && is_array($info['matroska']['tracks']['tracks'])) {
  • trunk/src/wp-includes/ID3/module.audio-video.quicktime.php

    r48278 r51900  
    2525{
    2626
    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         */
    2839        public $ParseAllPossibleAtoms = false;
    2940
    … …  
    171182                }
    172183
    173                 if (!isset($info['bitrate']) && isset($info['playtime_seconds'])) {
     184                if (!isset($info['bitrate']) && !empty($info['playtime_seconds'])) {
    174185                        $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
    175186                }
    … …  
    561572                                                                                                $atom_structure['data'] = substr($boxdata, 8);
    562573                                                                                                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);
    570595                                                                                                        }
    571                                                                                                         $info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_structure['data'], 'description'=>'cover');
    572596                                                                                                }
    573597                                                                                                break;
    … …  
    729753                                        $atom_structure['flags']['slide_show']   = (bool) $atom_structure['slide_show_flag'];
    730754
    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                                        );
    736762                                        if (isset($ptv_lookup[$atom_structure['display_size_raw']])) {
    737763                                                $atom_structure['display_size'] = $ptv_lookup[$atom_structure['display_size_raw']];
    … …  
    909935                                                                                $atom_structure['sample_description_table'][$i]['video_color_table_id']    =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 68,  2));
    910936
    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');
    912938                                                                                $atom_structure['sample_description_table'][$i]['video_pixel_color_name']  = $this->QuicktimeColorNameLookup($atom_structure['sample_description_table'][$i]['video_pixel_color_depth']);
    913939
    … …  
    915941                                                                                        $info['quicktime']['video']['codec_fourcc']        = $atom_structure['sample_description_table'][$i]['data_format'];
    916942                                                                                        $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']);
    918944                                                                                        $info['quicktime']['video']['color_depth']         = $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'];
    919945                                                                                        $info['quicktime']['video']['color_depth_name']    = $atom_structure['sample_description_table'][$i]['video_pixel_color_name'];
    … …  
    15991625
    16001626                                case 'NCDT':
    1601                                         // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
     1627                                        // https://exiftool.org/TagNames/Nikon.html
    16021628                                        // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100
    16031629                                        $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 4, $atomHierarchy, $ParseAllPossibleAtoms);
    … …  
    16051631                                case 'NCTH': // Nikon Camera THumbnail image
    16061632                                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
    16081636                                        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                                                );
    16091643                                                $atom_structure['data'] = $atom_data;
    16101644                                                $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']);
    1613                                         }
    1614                                         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);
    1617                                         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
     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                                                );
     1651                                        }
     1652                                        break;
     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);
     1658                                        break;
     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
    16211675                                        $atom_structure['data'] = $atom_data;
    16221676                                        break;
    … …  
    16251679                                        // some kind of metacontainer, may contain a big data dump such as:
    16261680                                        // 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.txt
     1681                                        // https://xhelmboyx.tripod.com/formats/qti-layout.txt
    16281682
    16291683                                        $atom_structure['version']   =          getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
    … …  
    17221776                                                                        'debug_list'     => '',      // Used to debug variables stored as comma delimited strings
    17231777                                                        );
     1778                                                        $debug_structure = array();
    17241779                                                        $debug_structure['debug_items'] = array();
    17251780                                                        // Can start loop here to decode all sensor data in 32 Byte chunks:
    … …  
    20402095         */
    20412096        public function QuicktimeParseContainerAtom($atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
    2042                 $atom_structure  = false;
     2097                $atom_structure = array();
    20432098                $subatomoffset  = 0;
    20442099                $subatomcounter = 0;
    … …  
    20582113                                        continue;
    20592114                                }
    2060                                 return $atom_structure;
     2115                                break;
    20612116                        }
    20622117                        if (strlen($subatomdata) < ($subatomsize - 8)) {
    … …  
    20642119                            // this may be because we are refusing to parse large subatoms, or it may be because this atom had its size set too large
    20652120                            // so we passed in the start of a following atom incorrectly?
    2066                             return $atom_structure;
     2121                            break;
    20672122                        }
    20682123                        $atom_structure[$subatomcounter++] = $this->QuicktimeParseAtom($subatomname, $subatomsize, $subatomdata, $baseoffset + $subatomoffset, $atomHierarchy, $ParseAllPossibleAtoms);
    20692124                        $subatomoffset += $subatomsize;
    20702125                }
     2126
     2127                if (empty($atom_structure)) {
     2128                        return false;
     2129                }
     2130
    20712131                return $atom_structure;
    20722132        }
    … …  
    25532613                if (empty($QuicktimeContentRatingLookup)) {
    25542614                        $QuicktimeContentRatingLookup[0]  = 'None';
     2615                        $QuicktimeContentRatingLookup[1]  = 'Explicit';
    25552616                        $QuicktimeContentRatingLookup[2]  = 'Clean';
    2556                         $QuicktimeContentRatingLookup[4]  = 'Explicit';
     2617                        $QuicktimeContentRatingLookup[4]  = 'Explicit (old)';
    25572618                }
    25582619                return (isset($QuicktimeContentRatingLookup[$rtng]) ? $QuicktimeContentRatingLookup[$rtng] : 'invalid');
    … …  
    26052666                }
    26062667                return (isset($QuicktimeStoreFrontCodeLookup[$sfid]) ? $QuicktimeStoreFrontCodeLookup[$sfid] : 'invalid');
    2607         }
    2608 
    2609         /**
    2610          * @param string $atom_data
    2611          *
    2612          * @return array
    2613          */
    2614         public function QuicktimeParseNikonNCTG($atom_data) {
    2615                 // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
    2616                 // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100
    2617                 // Data is stored as records of:
    2618                 // * 4 bytes record type
    2619                 // * 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 CDAB
    2623                 //     0x0004 = QWORD+ (size field *= 4-byte), values are stored EFGHABCD
    2624                 //     0x0005 = float  (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together
    2625                 //     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 field
    2628                 // * ? 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 BigEndian
    2630 
    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 CDAB
    2674                                         $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 EFGHABCD
    2682                                         $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 together
    2690                                         $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: // CreateDate
    2720                                 case 0x00000012: // DateTimeOriginal
    2721                                         $data = strtotime($data);
    2722                                         break;
    2723                                 case 0x0200001e: // ColorSpace
    2724                                         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: // PictureControlData
    2734                                         $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: // WorldTime
    2755                                         // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#WorldTime
    2756                                         // timezone is stored as offset from GMT in minutes
    2757                                         $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: // LensType
    2777                                         $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;
    27902668        }
    27912669
  • trunk/src/wp-includes/ID3/module.audio-video.riff.php

    r48278 r51900  
    5757                $thisfile_riff_WAVE        = array();
    5858
     59                $Original                 = array();
    5960                $Original['avdataoffset'] = $info['avdataoffset'];
    6061                $Original['avdataend']    = $info['avdataend'];
    … …  
    297298                                        $thisfile_riff_WAVE_bext_0 = &$thisfile_riff_WAVE['bext'][0];
    298299
    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
    302312                                        $thisfile_riff_WAVE_bext_0['origin_date']    =                              substr($thisfile_riff_WAVE_bext_0['data'], 320,  10);
    303313                                        $thisfile_riff_WAVE_bext_0['origin_time']    =                              substr($thisfile_riff_WAVE_bext_0['data'], 330,   8);
    … …  
    308318                                        if (preg_match('#^([0-9]{4}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_date'], $matches_bext_date)) {
    309319                                                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();
    310321                                                        list($dummy, $bext_timestamp['year'], $bext_timestamp['month'],  $bext_timestamp['day'])    = $matches_bext_date;
    311322                                                        list($dummy, $bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second']) = $matches_bext_time;
    … …  
    452463                                }
    453464
    454 
     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                                                }
     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                                                }
     516
     517                                        } else {
     518                                                $this->warning('RIFF.guan data not in expected format');
     519                                        }
     520                                }
    455521
    456522                                if (!isset($thisfile_audio['bitrate']) && isset($thisfile_riff_audio[$streamindex]['bitrate'])) {
    … …  
    734800                                if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][0]['data'])) {
    735801                                        if (is_array($thisfile_riff['AVI ']['hdrl']['strl']['strh'])) {
     802                                                $thisfile_riff_raw_strf_strhfccType_streamindex = null;
    736803                                                for ($i = 0; $i < count($thisfile_riff['AVI ']['hdrl']['strl']['strh']); $i++) {
    737804                                                        if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'])) {
    … …  
    10701137                                        getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
    10711138                                        $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);
    10731140                                        $getid3_id3v2 = new getid3_id3v2($getid3_temp);
    10741141                                        $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['ID3 '][0]['offset'] + 8;
    … …  
    11731240
    11741241                                        $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);
    11761243                                        $getid3_mpeg = new getid3_mpeg($getid3_temp);
    11771244                                        $getid3_mpeg->Analyze();
    … …  
    12591326
    12601327                                        $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);
    12621329                                        $getid3_id3v2 = new getid3_id3v2($getid3_temp);
    12631330                                        $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['id3 '][0]['offset'] + 8;
    … …  
    15151582                $RIFFchunk = false;
    15161583                $FoundAllChunksWeNeed = false;
     1584                $LISTchunkParent = null;
     1585                $LISTchunkMaxOffset = null;
     1586                $AC3syncwordBytes = pack('n', getid3_ac3::syncword); // 0x0B77 -> "\x0B\x77"
    15171587
    15181588                try {
    … …  
    15581628                                                                                if (getid3_mp3::MPEGaudioHeaderBytesValid($FirstFourBytes)) {
    15591629                                                                                        $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);
    15611631                                                                                        $getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
    15621632                                                                                        $getid3_temp->info['avdataend']    = $this->ftell() + $AudioChunkSize;
    … …  
    15761646                                                                                }
    15771647
    1578                                                                         } elseif (strpos($FirstFourBytes, getid3_ac3::syncword) === 0) {
    1579 
     1648                                                                        } elseif (strpos($FirstFourBytes, $AC3syncwordBytes) === 0) {
    15801649                                                                                // AC3
    15811650                                                                                $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);
    15831652                                                                                $getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
    15841653                                                                                $getid3_temp->info['avdataend']    = $this->ftell() + $AudioChunkSize;
    … …  
    16411710                                                                        if (getid3_mp3::MPEGaudioHeaderBytesValid(substr($testData, 0, 4))) {
    16421711                                                                                $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);
    16441713                                                                                $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
    16451714                                                                                $getid3_temp->info['avdataend']    = $info['avdataend'];
    … …  
    16531722                                                                        }
    16541723
    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)) {
    16561725
    16571726                                                                        // This is probably AC-3 data
    16581727                                                                        $getid3_temp = new getID3();
    16591728                                                                        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);
    16611730                                                                                $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
    16621731                                                                                $getid3_temp->info['avdataend']    = $info['avdataend'];
    … …  
    16741743                                                                                        $ac3_data .= substr($testData, 8 + $i + 0, 1);
    16751744                                                                                }
     1745                                                                                $getid3_ac3->getid3->info['avdataoffset'] = 0;
     1746                                                                                $getid3_ac3->getid3->info['avdataend']    = strlen($ac3_data);
    16761747                                                                                $getid3_ac3->AnalyzeString($ac3_data);
    16771748                                                                        }
    … …  
    16921763                                                                        // This is probably DTS data
    16931764                                                                        $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);
    16951766                                                                        $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
    16961767                                                                        $getid3_dts = new getid3_dts($getid3_temp);
    … …  
    17331804                                                        case 'MEXT':
    17341805                                                        case 'DISP':
     1806                                                        case 'wamd':
     1807                                                        case 'guan':
    17351808                                                                // always read data in
    17361809                                                        case 'JUNK':
    … …  
    20772150        public static function ParseBITMAPINFOHEADER($BITMAPINFOHEADER, $littleEndian=true) {
    20782151
     2152                $parsed                    = array();
    20792153                $parsed['biSize']          = substr($BITMAPINFOHEADER,  0, 4); // number of bytes required by the BITMAPINFOHEADER structure
    20802154                $parsed['biWidth']         = substr($BITMAPINFOHEADER,  4, 4); // width of the bitmap in pixels
  • trunk/src/wp-includes/ID3/module.audio.flac.php

    r48278 r51900  
    403403                $info = &$this->getid3->info;
    404404
     405                $picture = array();
    405406                $picture['typeid']         = getid3_lib::BigEndian2Int($this->fread(4));
    406407                $picture['picturetype']    = self::pictureTypeLookup($picture['typeid']);
  • trunk/src/wp-includes/ID3/module.audio.mp3.php

    r48278 r51900  
    1919}
    2020
    21 // number of frames to scan to determine if MPEG-audio sequence is valid
    22 // Lower this number to 5-20 for faster scanning
    23 // Increase this number to 50+ for most accurate detection of valid VBR/CBR
    24 // mpeg-audio streams
    25 define('GETID3_MP3_VALID_CHECK_FRAMES', 35);
    26 
    2721
    2822class getid3_mp3 extends getid3_handler
    … …  
    3731
    3832        /**
     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        /**
    3942         * @return bool
    4043         */
    … …  
    5659                }
    5760
     61                $CurrentDataLAMEversionString = null;
    5862                if (((isset($info['id3v2']['headerlength']) && ($info['avdataoffset'] > $info['id3v2']['headerlength'])) || (!isset($info['id3v2']) && ($info['avdataoffset'] > 0) && ($info['avdataoffset'] != $initialOffset)))) {
    5963
    … …  
    122126                                        $PossiblyLongerLAMEversion_NewString = substr($PossiblyLongerLAMEversion_String, 0, strspn($PossiblyLongerLAMEversion_String, 'LAME0123456789., (abcdefghijklmnopqrstuvwxyzJFSOND)')); //"LAME3.90.3"  "LAME3.87 (beta 1, Sep 27 2000)" "LAME3.88 (beta)"
    123127                                        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                                                }
    124134                                                $info['audio']['encoder'] = $PossiblyLongerLAMEversion_NewString;
    125135                                        }
    … …  
    296306
    297307                        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);
    299309                        } else {
    300310                                $encoder_options = strtoupper($info['audio']['bitrate_mode']);
    … …  
    489499                        $thisfile_mpeg_audio['raw'] = $MPEGheaderRawArray;
    490500                } 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);
    492502                        return false;
    493503                }
    … …  
    723733                                        $thisfile_mpeg_audio_lame['long_version']  = substr($headerstring, $VBRidOffset + 120, 20);
    724734                                        $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)) {
    727739                                                $thisfile_mpeg_audio_lame['short_version']   = $matches[0];
    728740                                                $thisfile_mpeg_audio_lame['numeric_version'] = $matches[1];
    729741                                        }
    730                                         foreach (explode('.', $thisfile_mpeg_audio_lame['numeric_version']) as $key => $number) {
    731                                                 $thisfile_mpeg_audio_lame['integer_version'][$key] = intval($number);
    732                                         }
    733 
    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/207
    736 
    737                                                 // extra 11 chars are not part of version string when LAMEtag present
    738                                                 unset($thisfile_mpeg_audio_lame['long_version']);
    739 
    740                                                 // It the LAME tag was only introduced in LAME v3.90
    741                                                 // http://www.hydrogenaudio.org/?act=ST&f=15&t=9933
    742 
    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;
    747 
    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'];
    755 
    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));
    761 
    762                                                 // bytes $9C-$A4  Encoder short VersionString
    763                                                 $thisfile_mpeg_audio_lame['short_version'] = substr($headerstring, $LAMEtagOffsetContant + 0x9C, 9);
    764 
    765                                                 // byte $A5  Info Tag revision + VBR method
    766                                                 $LAMEtagRevisionVBRmethod = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA5, 1));
    767 
    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'
    772 
    773                                                 // byte $A6  Lowpass filter value
    774                                                 $thisfile_mpeg_audio_lame['lowpass_frequency'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA6, 1)) * 100;
    775 
    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));
     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);
    787745                                                }
    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']);
     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
     748
     749                                                        // extra 11 chars are not part of version string when LAMEtag present
     750                                                        unset($thisfile_mpeg_audio_lame['long_version']);
     751
     752                                                        // It the LAME tag was only introduced in LAME v3.90
     753                                                        // http://www.hydrogenaudio.org/?act=ST&f=15&t=9933
     754
     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;
     759
     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'];
     767
     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));
     773
     774                                                        // bytes $9C-$A4  Encoder short VersionString
     775                                                        $thisfile_mpeg_audio_lame['short_version'] = substr($headerstring, $LAMEtagOffsetContant + 0x9C, 9);
     776
     777                                                        // byte $A5  Info Tag revision + VBR method
     778                                                        $LAMEtagRevisionVBRmethod = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA5, 1));
     779
     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'
     784
     785                                                        // byte $A6  Lowpass filter value
     786                                                        $thisfile_mpeg_audio_lame['lowpass_frequency'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA6, 1)) * 100;
     787
     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                                                        }
     805
     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));
     808
     809
     810                                                        if ($thisfile_mpeg_audio_lame_raw['RGAD_track'] != 0) {
     811
     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']);
     819
     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']);
     827                                                        }
     828                                                        if ($thisfile_mpeg_audio_lame_raw['RGAD_album'] != 0) {
     829
     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']);
     837
     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']);
     845                                                        }
     846                                                        if (empty($thisfile_mpeg_audio_lame_RGAD)) {
     847                                                                unset($thisfile_mpeg_audio_lame['RGAD']);
     848                                                        }
     849
     850
     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;
     858
     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                                                        }
     868
     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;
     873
     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']);
     884
     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));
     889
     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                                                        }
     904
     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']);
     908
     909                                                        // bytes $BC-$BD  MusicCRC
     910                                                        $thisfile_mpeg_audio_lame['music_crc']    = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBC, 2));
     911
     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));
     914
     915
     916                                                        // LAME CBR
     917                                                        if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) {
     918
     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                                                                //}
     925
     926                                                        }
     927
    792928                                                }
    793 
    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 
    797 
    798                                                 if ($thisfile_mpeg_audio_lame_raw['RGAD_track'] != 0) {
    799 
    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'];
    810                                                         }
    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) {
    817 
    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']);
    825 
    826                                                         if (!empty($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'])) {
    827                                                                 $info['replay_gain']['album']['peak']   = $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'];
    828                                                         }
    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                                                 }
    837 
    838 
    839                                                 // byte $AF  Encoding flags + ATH Type
    840                                                 $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;
    846 
    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                                                         // ignore
    853                                                 } elseif ($thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] > 0) { // Variable BitRate (VBR) - minimum bitrate
    854                                                         $thisfile_mpeg_audio_lame['bitrate_min'] = $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'];
    855                                                 }
    856 
    857                                                 // bytes $B1-$B3  Encoder delays
    858                                                 $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;
    861 
    862                                                 // byte $B4  Misc
    863                                                 $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']);
    872 
    873                                                 // byte $B5  MP3 Gain
    874                                                 $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));
    877 
    878                                                 // bytes $B6-$B7  Preset and surround info
    879                                                 $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 out
    890                                                         $thisfile_mpeg_audio_lame['short_version'] = 'LAME3.90.3';
    891                                                 }
    892 
    893                                                 // bytes $B8-$BB  MusicLength
    894                                                 $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']);
    896 
    897                                                 // bytes $BC-$BD  MusicCRC
    898                                                 $thisfile_mpeg_audio_lame['music_crc']    = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBC, 2));
    899 
    900                                                 // bytes $BE-$BF  CRC-16 of Info Tag
    901                                                 $thisfile_mpeg_audio_lame['lame_tag_crc'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBE, 2));
    902 
    903 
    904                                                 // LAME CBR
    905                                                 if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) {
    906 
    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                                                         //}
    913 
    914                                                 }
    915 
    916929                                        }
    917930                                }
    … …  
    10091022                        if (!$this->RecursiveFrameScanning($offset, $nextframetestoffset, $ScanAsCBR)) {
    10101023                                return false;
     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']);
    10111040                        }
    10121041
    … …  
    11311160                $this->decodeMPEGaudioHeader($offset, $firstframetestarray, false);
    11321161
    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
    11351165                        if (($nextframetestoffset + 4) >= $info['avdataend']) {
    11361166                                // end of file
    … …  
    11401170                        $nextframetestarray = array('error' => array(), 'warning' => array(), 'avdataend' => $info['avdataend'], 'avdataoffset'=>$info['avdataoffset']);
    11411171                        if ($this->decodeMPEGaudioHeader($nextframetestoffset, $nextframetestarray, false)) {
     1172                                getid3_lib::safe_inc($info['mp3_validity_check_bitrates'][$nextframetestarray['mpeg']['audio']['bitrate']]);
    11421173                                if ($ScanAsCBR) {
    11431174                                        // force CBR mode, used for trying to pick out invalid audio streams with valid(?) VBR headers, or VBR streams with no VBR header
    … …  
    12741305                $LongMPEGpaddingLookup        = array();
    12751306                $LongMPEGfrequencyLookup      = array();
     1307                $Distribution                 = array();
    12761308                $Distribution['bitrate']      = array();
    12771309                $Distribution['frequency']    = array();
    … …  
    14341466                $sync_seek_buffer_size = strlen($header);
    14351467                $SynchSeekOffset = 0;
     1468                $SyncSeekAttempts = 0;
     1469                $SyncSeekAttemptsMax = 1000;
     1470                $FirstFrameThisfileInfo = null;
    14361471                while ($SynchSeekOffset < $sync_seek_buffer_size) {
    14371472                        if ((($avdataoffset + $SynchSeekOffset)  < $info['avdataend']) && !feof($this->getid3->fp)) {
    … …  
    14721507                        }
    14731508
    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                                }
    14751527                                $FirstFrameAVDataOffset = null;
    14761528                                if (!isset($FirstFrameThisfileInfo) && !isset($info['mpeg']['audio'])) {
    … …  
    15121564                                                                $info = $dummy;
    15131565                                                                $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);
    15151567                                                        } 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.')');
    15171569                                                        }
    15181570                                                }
    … …  
    15591611                                                for ($current_segment = 0; $current_segment < $max_scan_segments; $current_segment++) {
    15601612                                                        $frames_scanned_this_segment = 0;
     1613                                                        $scan_start_offset = array();
    15611614                                                        if ($this->ftell() >= $info['avdataend']) {
    15621615                                                                break;
    … …  
    18881941                }
    18891942
     1943                $MPEGrawHeader = array();
    18901944                $MPEGrawHeader['synch']         = (getid3_lib::BigEndian2Int(substr($Header4Bytes, 0, 2)) & 0xFFE0) >> 4;
    18911945                $MPEGrawHeader['version']       = (ord($Header4Bytes[1]) & 0x18) >> 3; //    BB
  • trunk/src/wp-includes/ID3/module.audio.ogg.php

    r48278 r51900  
    530530        public function ParseOggPageHeader() {
    531531                // http://xiph.org/ogg/vorbis/doc/framing.html
     532                $oggheader = array();
    532533                $oggheader['page_start_offset'] = $this->ftell(); // where we started from in the file
    533534
    … …  
    681682                                $VorbisCommentPage++;
    682683
    683                                 $oggpageinfo = $this->ParseOggPageHeader();
    684                                 $info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
    685 
    686                                 // First, save what we haven't read yet
    687                                 $AsYetUnusedData = substr($commentdata, $commentdataoffset);
    688 
    689                                 // Then take that data off the end
    690                                 $commentdata     = substr($commentdata, 0, $commentdataoffset);
    691 
    692                                 // Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct
    693                                 $commentdata .= str_repeat("\x00", 27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
    694                                 $commentdataoffset += (27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
    695 
    696                                 // Finally, stick the unused data back on the end
    697                                 $commentdata .= $AsYetUnusedData;
    698 
    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());
     684                                if ($oggpageinfo = $this->ParseOggPageHeader()) {
     685                                        $info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
     686
     687                                        // First, save what we haven't read yet
     688                                        $AsYetUnusedData = substr($commentdata, $commentdataoffset);
     689
     690                                        // Then take that data off the end
     691                                        $commentdata     = substr($commentdata, 0, $commentdataoffset);
     692
     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']);
     696
     697                                        // Finally, stick the unused data back on the end
     698                                        $commentdata .= $AsYetUnusedData;
     699
     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());
    702715                                        break;
    703716                                }
    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'];
    712717                        }
    713718                        $ThisFileInfo_ogg_comments_raw[$i]['offset'] = $commentdataoffset;
  • trunk/src/wp-includes/ID3/module.tag.apetag.php

    r48278 r51900  
    361361
    362362                // shortcut
     363                $headerfooterinfo = array();
    363364                $headerfooterinfo['raw'] = array();
    364365                $headerfooterinfo_raw = &$headerfooterinfo['raw'];
    … …  
    390391                // All are set to zero on creation and ignored on reading."
    391392                // http://wiki.hydrogenaud.io/index.php?title=Ape_Tags_Flags
     393                $flags                      = array();
    392394                $flags['header']            = (bool) ($rawflagint & 0x80000000);
    393395                $flags['footer']            = (bool) ($rawflagint & 0x40000000);
  • trunk/src/wp-includes/ID3/module.tag.id3v1.php

    r48278 r51900  
    3232                }
    3333
    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                }
     43
    3744
    3845                if (substr($id3v1tag, 0, 3) == 'TAG') {
    … …  
    4047                        $info['avdataend'] = $info['filesize'] - 128;
    4148
     49                        $ParsedID3v1            = array();
    4250                        $ParsedID3v1['title']   = $this->cutfield(substr($id3v1tag,   3, 30));
    4351                        $ParsedID3v1['artist']  = $this->cutfield(substr($id3v1tag,  33, 30));
    … …  
    298306                        146  => 'JPop',
    299307                        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',
    300352
    301353                        255  => 'Unknown',
  • trunk/src/wp-includes/ID3/module.tag.id3v2.php

    r48278 r51900  
    346346                                if (($frame_size <= strlen($framedata)) && ($this->IsValidID3v2FrameName($frame_name, $id3v2_majorversion))) {
    347347
    348                                         unset($parsedFrame);
     348                                        $parsedFrame                    = array();
    349349                                        $parsedFrame['frame_name']      = $frame_name;
    350350                                        $parsedFrame['frame_flags_raw'] = $frame_flags;
    … …  
    979979
    980980                } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'USLT')) || // 4.8   USLT Unsynchronised lyric/text transcription
    981                                 (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'ULT'))) {     // 4.9   ULT  Unsynchronised lyric/text transcription
     981                                (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'ULT'))) {    // 4.9   ULT  Unsynchronised lyric/text transcription
    982982                        //   There may be more than one 'Unsynchronised lyrics/text transcription' frame
    983983                        //   in each tag, but only one with the same language and content descriptor.
    … …  
    995995                                $frame_textencoding_terminator = "\x00";
    996996                        }
    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);
    1007 
    1008                         $parsedFrame['encodingid']   = $frame_textencoding;
    1009                         $parsedFrame['encoding']     = $this->TextEncodingNameLookup($frame_textencoding);
    1010 
    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']);
     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);
     1008
     1009                                $parsedFrame['encodingid']   = $frame_textencoding;
     1010                                $parsedFrame['encoding']     = $this->TextEncodingNameLookup($frame_textencoding);
     1011
     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']);
    10151019                        }
    10161020                        unset($parsedFrame['data']);
    … …  
    13711375                        }
    13721376
     1377                        $frame_imagetype = null;
     1378                        $frame_mimetype = null;
    13731379                        if ($id3v2_majorversion == 2 && strlen($parsedFrame['data']) > $frame_offset) {
    13741380                                $frame_imagetype = substr($parsedFrame['data'], $frame_offset, 3);
    … …  
    19571963                        $parsedFrame['peakamplitude'] = getid3_lib::BigEndian2Float(substr($parsedFrame['data'], $frame_offset, 4));
    19581964                        $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                        }
    19711973                        $parsedFrame['track']['name']       = getid3_lib::RGADnameLookup($parsedFrame['raw']['track']['name']);
    19721974                        $parsedFrame['track']['originator'] = getid3_lib::RGADoriginatorLookup($parsedFrame['raw']['track']['originator']);
    … …  
    24452447                        TND     Dinars
    24462448                        TOP     Pa'anga
    2447                         TRL     Liras
     2449                        TRL     Liras (old)
     2450                        TRY     Liras
    24482451                        TTD     Dollars
    24492452                        TVD     Tuvalu Dollars
    … …  
    26462649                        TOP     Tonga
    26472650                        TRL     Turkey
     2651                        TRY     Turkey
    26482652                        TTD     Trinidad and Tobago
    26492653                        TVD     Tuvalu
  • trunk/src/wp-includes/ID3/module.tag.lyrics3.php

    r48278 r51900  
    3434
    3535                $this->fseek((0 - 128 - 9 - 6), SEEK_END);          // end - ID3v1 - "LYRICSEND" - [Lyrics3size]
     36                $lyrics3offset = null;
     37                $lyrics3version = null;
     38                $lyrics3size   = null;
    3639                $lyrics3_id3v1 = $this->fread(128 + 9 + 6);
    3740                $lyrics3lsz    = (int) substr($lyrics3_id3v1, 0, 6); // Lyrics3size
  • trunk/src/wp-includes/ID3/readme.txt

    r46587 r51900  
    626626* http://www.codeproject.com/Articles/8295/MPEG-Audio-Frame-Header
    627627* http://dsd-guide.com/sites/default/files/white-papers/DSFFileFormatSpec_E.pdf
     628* https://fileformats.fandom.com/wiki/Torrent_file
Note: See TracChangeset for help on using the changeset viewer.