Make WordPress Core

Ticket #54162: 54162.diff

File 54162.diff, 110.1 KB (added by SergeyBiryukov, 22 months ago)
  • src/wp-admin/includes/media.php

     
    35583558                require ABSPATH . WPINC . '/ID3/getid3.php';
    35593559        }
    35603560
    3561         $id3  = new getID3();
     3561        $id3 = new getID3();
     3562        // Required to get the `created_timestamp` value.
     3563        $id3->options_audiovideo_quicktime_ReturnAtomData = true; // phpcs:ignore WordPress.NamingConventions.ValidVariableName
     3564
    35623565        $data = $id3->analyze( $file );
    35633566
    35643567        if ( isset( $data['video']['lossless'] ) ) {
     
    36693672                require ABSPATH . WPINC . '/ID3/getid3.php';
    36703673        }
    36713674
    3672         $id3  = new getID3();
     3675        $id3 = new getID3();
     3676        // Required to get the `created_timestamp` value.
     3677        $id3->options_audiovideo_quicktime_ReturnAtomData = true; // phpcs:ignore WordPress.NamingConventions.ValidVariableName
     3678
    36733679        $data = $id3->analyze( $file );
    36743680
    36753681        if ( ! empty( $data['audio'] ) ) {
  • src/wp-includes/ID3/getid3.lib.php

     
    242242        /**
    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         *
    248248         * @param string $byteword
     
    294294
    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)) {
    305305                        if ($signbit == '1') {
     
    427427         * @return string
    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;
    440446        }
     
    665671                // or
    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);
    670677                } else {
     
    15381545        public static function CopyTagsToComments(&$ThisFileInfo, $option_tags_html=true) {
    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) {
    15491565                                foreach ($tagarray as $tagname => $tagdata) {
     
    15621578                                                                                // new value is identical but shorter-than (or equal-length to) one already in comments - skip
    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                                                                }
    15731590
    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);
    15811607                                                                                break;
     
    16011627                        }
    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                        }
    16141642
     
    17341762         * @return float|bool
    17351763         */
    17361764        public static function getFileSizeSyscall($path) {
     1765                $commandline = null;
    17371766                $filesize = false;
    17381767
    17391768                if (GETID3_OS_ISWINDOWS) {
     
    17951824         *
    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);
    18011830        }
  • src/wp-includes/ID3/getid3.php

     
    1717if (!defined('GETID3_INCLUDEPATH')) {
    1818        define('GETID3_INCLUDEPATH', dirname(__FILE__).DIRECTORY_SEPARATOR);
    1919}
    20 // Workaround Bug #39923 (https://bugs.php.net/bug.php?id=39923)
    21 if (!defined('IMG_JPG') && defined('IMAGETYPE_JPEG')) {
    22         define('IMG_JPG', IMAGETYPE_JPEG);
    23 }
    2420if (!defined('ENT_SUBSTITUTE')) { // PHP5.3 adds ENT_IGNORE, PHP5.4 adds ENT_SUBSTITUTE
    2521        define('ENT_SUBSTITUTE', (defined('ENT_IGNORE') ? ENT_IGNORE : 8));
    2622}
     
    5753                if (substr($basedir, -1, 1) != DIRECTORY_SEPARATOR) {
    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;
    6359                }
     
    214210         */
    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
    219349        /**
     
    257387         */
    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
    263393        const ATTACHMENTS_NONE   = false;
     
    637767                                return $this->error('Format not supported, module "'.$determined_format['include'].'" is corrupt.');
    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);
    642784
     
    13551497                                                        'fail_ape'  => 'ERROR',
    13561498                                                ),
    13571499
     1500                                // TORRENT             - .torrent
     1501                                'torrent' => array(
     1502                                                        'pattern'   => '^(d8\\:announce|d7\\:comment)',
     1503                                                        'group'     => 'misc',
     1504                                                        'module'    => 'torrent',
     1505                                                        'mime_type' => 'application/x-bittorrent',
     1506                                                        'fail_id3'  => 'ERROR',
     1507                                                        'fail_ape'  => 'ERROR',
     1508                                                ),
     1509
    13581510                                 // CUE  - data       - CUEsheet (index to single-file disc images)
    13591511                                 'cue' => array(
    13601512                                                        'pattern'   => '', // empty pattern means cannot be automatically detected, will fall through all other formats and match based on filename and very basic file contents
     
    14891641                                                if (is_string($value)) {
    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;
    14951647                                                        } else {
     
    20962248                                        $this->data_string_position = $this->data_string_length + $bytes;
    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                         }
     2251                        return 0; // fseek returns 0 on success
    21102252                }
    2111                 return fseek($this->getid3->fp, $bytes, $whence);
     2253
     2254                $pos = $bytes;
     2255                if ($whence == SEEK_CUR) {
     2256                        $pos = $this->ftell() + $bytes;
     2257                } elseif ($whence == SEEK_END) {
     2258                        $pos = $this->getid3->info['filesize'] + $bytes;
     2259                }
     2260                if (!getid3_lib::intValueSupported($pos)) {
     2261                        throw new getid3_exception('cannot fseek('.$pos.') because beyond PHP filesystem limit', 10);
     2262                }
     2263
     2264                // https://github.com/JamesHeinrich/getID3/issues/327
     2265                $result = fseek($this->getid3->fp, $bytes, $whence);
     2266                if ($result !== 0) { // fseek returns 0 on success
     2267                        throw new getid3_exception('cannot fseek('.$pos.'). resource/stream does not appear to support seeking', 10);
     2268                }
     2269                return $result;
    21122270        }
    21132271
    21142272        /**
     
    22242382         * @throws getid3_exception
    22252383         */
    22262384        public function saveAttachment($name, $offset, $length, $image_mime=null) {
     2385                $fp_dest = null;
     2386                $dest = null;
    22272387                try {
    22282388
    22292389                        // do not extract at all
  • src/wp-includes/ID3/module.audio-video.asf.php

     
    9393                $offset = 0;
    9494                $thisfile_asf_streambitratepropertiesobject = array();
    9595                $thisfile_asf_codeclistobject = array();
     96                $StreamPropertiesObjectData = array();
    9697
    9798                for ($HeaderObjectsCounter = 0; $HeaderObjectsCounter < $thisfile_asf_headerobject['headerobjects']; $HeaderObjectsCounter++) {
    9899                        $NextObjectGUID = substr($ASFHeaderData, $offset, 16);
     
    283284                                        $thisfile_asf_headerextensionobject['reserved_2']          = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
    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;
    289290                                        }
     
    535536                                        $thisfile_asf_markerobject['reserved_2'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
    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                                        }
    541542                                        $thisfile_asf_markerobject['name_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
     
    11931194                                        $thisfile_asf_dataobject['reserved']           = getid3_lib::LittleEndian2Int(substr($DataObjectData, $offset, 2));
    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;
    11991200                                        }
  • src/wp-includes/ID3/module.audio-video.flv.php

     
    161161                                                $info['flv']['video']['videoCodec'] = $LastHeaderByte & 0x07;
    162162
    163163                                                $FLVvideoHeader = $this->fread(11);
     164                                                $PictureSizeEnc = array();
    164165
    165166                                                if ($info['flv']['video']['videoCodec'] == GETID3_FLV_VIDEO_H264) {
    166167                                                        // this code block contributed by: moysevichØgmail*com
  • src/wp-includes/ID3/module.audio-video.matroska.php

     
    224224         *
    225225         * @var bool
    226226         */
    227         public static $hide_clusters    = true;
     227        public $hide_clusters    = true;
    228228
    229229        /**
    230230         * True to parse the whole file, not only header [default: FALSE].
     
    231231         *
    232232         * @var bool
    233233         */
    234         public static $parse_whole_file = false;
     234        public $parse_whole_file = false;
    235235
    236236        /*
    237237         * Private parser settings/placeholders.
     
    586586                                        $info['matroska']['segment'][0]['length'] = $top_element['length'];
    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                                                }
    592592                                                switch ($element_data['id']) {
     
    618618                                                                                                $this->warning('seek_entry[target_id] unexpectedly not set at '.$seek_entry['offset']);
    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                                                                                        }
    624624                                                                                        break;
     
    905905                                                                break;
    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;
    911911                                                                }
     
    12461246                                                                        }
    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'])) {
    12571257                                                                                        if (count($info['matroska']['track_data_offsets']) == count($info['matroska']['tracks']['tracks'])) {
  • src/wp-includes/ID3/module.audio-video.quicktime.php

     
    2424class getid3_quicktime extends getid3_handler
    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
    3041        /**
     
    170181                        }
    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                }
    176187                if (isset($info['bitrate']) && !isset($info['audio']['bitrate']) && !isset($info['quicktime']['video'])) {
     
    560571                                                                                        default:
    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;
    574598
     
    728752                                        $atom_structure['flags']['play_on_open'] = (bool) $atom_structure['play_on_open_flag'];
    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']];
    738764                                        } else {
     
    908934                                                                                $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 66,  2));
    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
    914940                                                                                if ($atom_structure['sample_description_table'][$i]['video_pixel_color_name'] != 'invalid') {
    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'];
    920946
     
    15981624                                        break;
    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);
    16041630                                        break;
    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']);
     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                                                );
    16131651                                        }
    16141652                                        break;
    1615                                 case 'NCTG': // Nikon - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
    1616                                         $atom_structure['data'] = $this->QuicktimeParseNikonNCTG($atom_data);
     1653                                case 'NCTG': // Nikon - https://exiftool.org/TagNames/Nikon.html#NCTG
     1654                                        getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.nikon-nctg.php', __FILE__, true);
     1655                                        $nikonNCTG = new getid3_tag_nikon_nctg($this->getid3);
     1656
     1657                                        $atom_structure['data'] = $nikonNCTG->parse($atom_data);
    16171658                                        break;
    1618                                 case 'NCHD': // Nikon:MakerNoteVersion  - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
    1619                                 case 'NCDB': // Nikon                   - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
    1620                                 case 'CNCV': // Canon:CompressorVersion - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Canon.html
     1659                                case 'NCHD': // Nikon:MakerNoteVersion  - https://exiftool.org/TagNames/Nikon.html
     1660                                        $makerNoteVersion = '';
     1661                                        for ($i = 0, $iMax = strlen($atom_data); $i < $iMax; ++$i) {
     1662                                                if (ord($atom_data[$i]) >= 0x00 && ord($atom_data[$i]) <= 0x1F) {
     1663                                                        $makerNoteVersion .= ' '.ord($atom_data[$i]);
     1664                                                } else {
     1665                                                        $makerNoteVersion .= $atom_data[$i];
     1666                                                }
     1667                                        }
     1668                                        $makerNoteVersion = rtrim($makerNoteVersion, "\x00");
     1669                                        $atom_structure['data'] = array(
     1670                                                'MakerNoteVersion' => $makerNoteVersion
     1671                                        );
     1672                                        break;
     1673                                case 'NCDB': // Nikon                   - https://exiftool.org/TagNames/Nikon.html
     1674                                case 'CNCV': // Canon:CompressorVersion - https://exiftool.org/TagNames/Canon.html
    16211675                                        $atom_structure['data'] = $atom_data;
    16221676                                        break;
    16231677
     
    16241678                                case "\x00\x00\x00\x00":
    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));
    16301684                                        $atom_structure['flags_raw'] =          getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
     
    17211775                                                                        'unknown_data'   => array(),
    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:
    17261781                                                        foreach (str_split($atom_SENSOR_data, 32) as $sensor_key => $sensor_data) {
     
    20392094         * @return array|false
    20402095         */
    20412096        public function QuicktimeParseContainerAtom($atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
    2042                 $atom_structure  = false;
     2097                $atom_structure = array();
    20432098                $subatomoffset  = 0;
    20442099                $subatomcounter = 0;
    20452100                if ((strlen($atom_data) == 4) && (getid3_lib::BigEndian2Int($atom_data) == 0x00000000)) {
     
    20572112                                        $subatomoffset += 4;
    20582113                                        continue;
    20592114                                }
    2060                                 return $atom_structure;
     2115                                break;
    20612116                        }
    20622117                        if (strlen($subatomdata) < ($subatomsize - 8)) {
    20632118                            // we don't have enough data to decode the subatom.
    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        }
    20732133
     
    25522612                static $QuicktimeContentRatingLookup = array();
    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');
    25592620        }
     
    26072668        }
    26082669
    26092670        /**
    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;
    2790         }
    2791 
    2792         /**
    27932671         * @param string $keyname
    27942672         * @param string|array $data
    27952673         * @param string $boxname
  • src/wp-includes/ID3/module.audio-video.riff.php

     
    5656                $thisfile_riff_video       = &$thisfile_riff['video'];
    5757                $thisfile_riff_WAVE        = array();
    5858
     59                $Original                 = array();
    5960                $Original['avdataoffset'] = $info['avdataoffset'];
    6061                $Original['avdataend']    = $info['avdataend'];
    6162
     
    296297                                        // shortcut
    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);
    304314                                        $thisfile_riff_WAVE_bext_0['time_reference'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 338,   8));
     
    307317                                        $thisfile_riff_WAVE_bext_0['coding_history'] =         explode("\r\n", trim(substr($thisfile_riff_WAVE_bext_0['data'], 601)));
    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;
    312323                                                        $thisfile_riff_WAVE_bext_0['origin_date_unix'] = gmmktime($bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second'], $bext_timestamp['month'], $bext_timestamp['day'], $bext_timestamp['year']);
     
    451462                                        }
    452463                                }
    453464
     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                                                }
    454485
     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                                                }
    455516
     517                                        } else {
     518                                                $this->warning('RIFF.guan data not in expected format');
     519                                        }
     520                                }
     521
    456522                                if (!isset($thisfile_audio['bitrate']) && isset($thisfile_riff_audio[$streamindex]['bitrate'])) {
    457523                                        $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
    458524                                        $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $thisfile_audio['bitrate']);
     
    733799                                }
    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'])) {
    738805                                                                $strhData = $thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'];
     
    10691136                                if (isset($thisfile_riff[$RIFFsubtype]['ID3 '])) {
    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;
    10751142                                        if ($thisfile_riff[$RIFFsubtype]['ID3 '][0]['valid'] = $getid3_id3v2->Analyze()) {
     
    11721239                                        getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.mpeg.php', __FILE__, true);
    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();
    11781245                                        if (empty($getid3_temp->info['error'])) {
     
    12581325                                        getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
    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;
    12641331                                        if ($thisfile_riff[$RIFFsubtype]['id3 '][0]['valid'] = $getid3_id3v2->Analyze()) {
     
    15141581
    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 {
    15191589                        $this->fseek($startoffset);
     
    15571627                                                                                // MP3
    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;
    15631633                                                                                        $getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__);
     
    15751645                                                                                        unset($getid3_temp, $getid3_mp3);
    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;
    15851654                                                                                $getid3_ac3 = new getid3_ac3($getid3_temp);
     
    16401709                                                                        // Probably is MP3 data
    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'];
    16461715                                                                                $getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__);
     
    16521721                                                                                unset($getid3_temp, $getid3_mp3);
    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'];
    16631732                                                                        }
     
    16731742                                                                                        $ac3_data .= substr($testData, 8 + $i + 1, 1);
    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                                                                        }
    16781749
     
    16911762
    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);
    16971768                                                                        $getid3_dts->Analyze();
     
    17321803                                                        case 'indx':
    17331804                                                        case 'MEXT':
    17341805                                                        case 'DISP':
     1806                                                        case 'wamd':
     1807                                                        case 'guan':
    17351808                                                                // always read data in
    17361809                                                        case 'JUNK':
    17371810                                                                // should be: never read data in
     
    20762149         */
    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
    20812155                $parsed['biHeight']        = substr($BITMAPINFOHEADER,  8, 4); // height of the bitmap in pixels. If biHeight is positive, the bitmap is a 'bottom-up' DIB and its origin is the lower left corner. If biHeight is negative, the bitmap is a 'top-down' DIB and its origin is the upper left corner
  • src/wp-includes/ID3/module.audio.flac.php

     
    402402        public function parsePICTURE() {
    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']);
    407408                $picture['image_mime']     = $this->fread(getid3_lib::BigEndian2Int($this->fread(4)));
  • src/wp-includes/ID3/module.audio.mp3.php

     
    1818        exit;
    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);
    2621
    27 
    2822class getid3_mp3 extends getid3_handler
    2923{
    3024        /**
     
    3630        public $allow_bruteforce = false;
    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         */
    4144        public function Analyze() {
     
    5558                        $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
    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
    6064                        $synchoffsetwarning = 'Unknown data before synch ';
     
    121125                                if (substr($PossiblyLongerLAMEversion_String, 0, strlen($CurrentDataLAMEversionString)) == $CurrentDataLAMEversionString) {
    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                                        }
    126136                                }
     
    295305                } elseif (!empty($info['audio']['bitrate'])) {
    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']);
    301311                        }
     
    488498                if ($MPEGaudioHeaderValidCache[$head4_key]) {
    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                }
    494504
     
    722732
    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                                         }
     742                                        if (strlen($thisfile_mpeg_audio_lame['numeric_version']) > 0) {
     743                                                foreach (explode('.', $thisfile_mpeg_audio_lame['numeric_version']) as $key => $number) {
     744                                                        $thisfile_mpeg_audio_lame['integer_version'][$key] = intval($number);
     745                                                }
     746                                                //if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.90') {
     747                                                if ((($thisfile_mpeg_audio_lame['integer_version'][0] * 1000) + $thisfile_mpeg_audio_lame['integer_version'][1]) >= 3090) { // cannot use string version compare, may have "LAME3.90" or "LAME3.100" -- see https://github.com/JamesHeinrich/getID3/issues/207
    733748
    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
     749                                                        // extra 11 chars are not part of version string when LAMEtag present
     750                                                        unset($thisfile_mpeg_audio_lame['long_version']);
    736751
    737                                                 // extra 11 chars are not part of version string when LAMEtag present
    738                                                 unset($thisfile_mpeg_audio_lame['long_version']);
     752                                                        // It the LAME tag was only introduced in LAME v3.90
     753                                                        // http://www.hydrogenaudio.org/?act=ST&f=15&t=9933
    739754
    740                                                 // It the LAME tag was only introduced in LAME v3.90
    741                                                 // http://www.hydrogenaudio.org/?act=ST&f=15&t=9933
     755                                                        // Offsets of various bytes in http://gabriel.mp3-tech.org/mp3infotag.html
     756                                                        // are assuming a 'Xing' identifier offset of 0x24, which is the case for
     757                                                        // MPEG-1 non-mono, but not for other combinations
     758                                                        $LAMEtagOffsetContant = $VBRidOffset - 0x24;
    742759
    743                                                 // Offsets of various bytes in http://gabriel.mp3-tech.org/mp3infotag.html
    744                                                 // are assuming a 'Xing' identifier offset of 0x24, which is the case for
    745                                                 // MPEG-1 non-mono, but not for other combinations
    746                                                 $LAMEtagOffsetContant = $VBRidOffset - 0x24;
     760                                                        // shortcuts
     761                                                        $thisfile_mpeg_audio_lame['RGAD']    = array('track'=>array(), 'album'=>array());
     762                                                        $thisfile_mpeg_audio_lame_RGAD       = &$thisfile_mpeg_audio_lame['RGAD'];
     763                                                        $thisfile_mpeg_audio_lame_RGAD_track = &$thisfile_mpeg_audio_lame_RGAD['track'];
     764                                                        $thisfile_mpeg_audio_lame_RGAD_album = &$thisfile_mpeg_audio_lame_RGAD['album'];
     765                                                        $thisfile_mpeg_audio_lame['raw'] = array();
     766                                                        $thisfile_mpeg_audio_lame_raw    = &$thisfile_mpeg_audio_lame['raw'];
    747767
    748                                                 // shortcuts
    749                                                 $thisfile_mpeg_audio_lame['RGAD']    = array('track'=>array(), 'album'=>array());
    750                                                 $thisfile_mpeg_audio_lame_RGAD       = &$thisfile_mpeg_audio_lame['RGAD'];
    751                                                 $thisfile_mpeg_audio_lame_RGAD_track = &$thisfile_mpeg_audio_lame_RGAD['track'];
    752                                                 $thisfile_mpeg_audio_lame_RGAD_album = &$thisfile_mpeg_audio_lame_RGAD['album'];
    753                                                 $thisfile_mpeg_audio_lame['raw'] = array();
    754                                                 $thisfile_mpeg_audio_lame_raw    = &$thisfile_mpeg_audio_lame['raw'];
     768                                                        // byte $9B  VBR Quality
     769                                                        // This field is there to indicate a quality level, although the scale was not precised in the original Xing specifications.
     770                                                        // Actually overwrites original Xing bytes
     771                                                        unset($thisfile_mpeg_audio['VBR_scale']);
     772                                                        $thisfile_mpeg_audio_lame['vbr_quality'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0x9B, 1));
    755773
    756                                                 // byte $9B  VBR Quality
    757                                                 // This field is there to indicate a quality level, although the scale was not precised in the original Xing specifications.
    758                                                 // Actually overwrites original Xing bytes
    759                                                 unset($thisfile_mpeg_audio['VBR_scale']);
    760                                                 $thisfile_mpeg_audio_lame['vbr_quality'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0x9B, 1));
     774                                                        // bytes $9C-$A4  Encoder short VersionString
     775                                                        $thisfile_mpeg_audio_lame['short_version'] = substr($headerstring, $LAMEtagOffsetContant + 0x9C, 9);
    761776
    762                                                 // bytes $9C-$A4  Encoder short VersionString
    763                                                 $thisfile_mpeg_audio_lame['short_version'] = substr($headerstring, $LAMEtagOffsetContant + 0x9C, 9);
     777                                                        // byte $A5  Info Tag revision + VBR method
     778                                                        $LAMEtagRevisionVBRmethod = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA5, 1));
    764779
    765                                                 // byte $A5  Info Tag revision + VBR method
    766                                                 $LAMEtagRevisionVBRmethod = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA5, 1));
     780                                                        $thisfile_mpeg_audio_lame['tag_revision']   = ($LAMEtagRevisionVBRmethod & 0xF0) >> 4;
     781                                                        $thisfile_mpeg_audio_lame_raw['vbr_method'] =  $LAMEtagRevisionVBRmethod & 0x0F;
     782                                                        $thisfile_mpeg_audio_lame['vbr_method']     = self::LAMEvbrMethodLookup($thisfile_mpeg_audio_lame_raw['vbr_method']);
     783                                                        $thisfile_mpeg_audio['bitrate_mode']        = substr($thisfile_mpeg_audio_lame['vbr_method'], 0, 3); // usually either 'cbr' or 'vbr', but truncates 'vbr-old / vbr-rh' to 'vbr'
    767784
    768                                                 $thisfile_mpeg_audio_lame['tag_revision']   = ($LAMEtagRevisionVBRmethod & 0xF0) >> 4;
    769                                                 $thisfile_mpeg_audio_lame_raw['vbr_method'] =  $LAMEtagRevisionVBRmethod & 0x0F;
    770                                                 $thisfile_mpeg_audio_lame['vbr_method']     = self::LAMEvbrMethodLookup($thisfile_mpeg_audio_lame_raw['vbr_method']);
    771                                                 $thisfile_mpeg_audio['bitrate_mode']        = substr($thisfile_mpeg_audio_lame['vbr_method'], 0, 3); // usually either 'cbr' or 'vbr', but truncates 'vbr-old / vbr-rh' to 'vbr'
     785                                                        // byte $A6  Lowpass filter value
     786                                                        $thisfile_mpeg_audio_lame['lowpass_frequency'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA6, 1)) * 100;
    772787
    773                                                 // byte $A6  Lowpass filter value
    774                                                 $thisfile_mpeg_audio_lame['lowpass_frequency'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA6, 1)) * 100;
     788                                                        // bytes $A7-$AE  Replay Gain
     789                                                        // http://privatewww.essex.ac.uk/~djmrob/replaygain/rg_data_format.html
     790                                                        // bytes $A7-$AA : 32 bit floating point "Peak signal amplitude"
     791                                                        if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.94b') {
     792                                                                // LAME 3.94a16 and later - 9.23 fixed point
     793                                                                // ie 0x0059E2EE / (2^23) = 5890798 / 8388608 = 0.7022378444671630859375
     794                                                                $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] = (float) ((getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4))) / 8388608);
     795                                                        } else {
     796                                                                // LAME 3.94a15 and earlier - 32-bit floating point
     797                                                                // Actually 3.94a16 will fall in here too and be WRONG, but is hard to detect 3.94a16 vs 3.94a15
     798                                                                $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] = getid3_lib::LittleEndian2Float(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4));
     799                                                        }
     800                                                        if ($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] == 0) {
     801                                                                unset($thisfile_mpeg_audio_lame_RGAD['peak_amplitude']);
     802                                                        } else {
     803                                                                $thisfile_mpeg_audio_lame_RGAD['peak_db'] = getid3_lib::RGADamplitude2dB($thisfile_mpeg_audio_lame_RGAD['peak_amplitude']);
     804                                                        }
    775805
    776                                                 // bytes $A7-$AE  Replay Gain
    777                                                 // http://privatewww.essex.ac.uk/~djmrob/replaygain/rg_data_format.html
    778                                                 // bytes $A7-$AA : 32 bit floating point "Peak signal amplitude"
    779                                                 if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.94b') {
    780                                                         // LAME 3.94a16 and later - 9.23 fixed point
    781                                                         // ie 0x0059E2EE / (2^23) = 5890798 / 8388608 = 0.7022378444671630859375
    782                                                         $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] = (float) ((getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4))) / 8388608);
    783                                                 } else {
    784                                                         // LAME 3.94a15 and earlier - 32-bit floating point
    785                                                         // Actually 3.94a16 will fall in here too and be WRONG, but is hard to detect 3.94a16 vs 3.94a15
    786                                                         $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] = getid3_lib::LittleEndian2Float(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4));
    787                                                 }
    788                                                 if ($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] == 0) {
    789                                                         unset($thisfile_mpeg_audio_lame_RGAD['peak_amplitude']);
    790                                                 } else {
    791                                                         $thisfile_mpeg_audio_lame_RGAD['peak_db'] = getid3_lib::RGADamplitude2dB($thisfile_mpeg_audio_lame_RGAD['peak_amplitude']);
    792                                                 }
     806                                                        $thisfile_mpeg_audio_lame_raw['RGAD_track']      =   getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAB, 2));
     807                                                        $thisfile_mpeg_audio_lame_raw['RGAD_album']      =   getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAD, 2));
    793808
    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));
    796809
     810                                                        if ($thisfile_mpeg_audio_lame_raw['RGAD_track'] != 0) {
    797811
    798                                                 if ($thisfile_mpeg_audio_lame_raw['RGAD_track'] != 0) {
     812                                                                $thisfile_mpeg_audio_lame_RGAD_track['raw']['name']        = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0xE000) >> 13;
     813                                                                $thisfile_mpeg_audio_lame_RGAD_track['raw']['originator']  = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x1C00) >> 10;
     814                                                                $thisfile_mpeg_audio_lame_RGAD_track['raw']['sign_bit']    = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x0200) >> 9;
     815                                                                $thisfile_mpeg_audio_lame_RGAD_track['raw']['gain_adjust'] =  $thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x01FF;
     816                                                                $thisfile_mpeg_audio_lame_RGAD_track['name']       = getid3_lib::RGADnameLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['name']);
     817                                                                $thisfile_mpeg_audio_lame_RGAD_track['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['originator']);
     818                                                                $thisfile_mpeg_audio_lame_RGAD_track['gain_db']    = getid3_lib::RGADadjustmentLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_RGAD_track['raw']['sign_bit']);
    799819
    800                                                         $thisfile_mpeg_audio_lame_RGAD_track['raw']['name']        = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0xE000) >> 13;
    801                                                         $thisfile_mpeg_audio_lame_RGAD_track['raw']['originator']  = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x1C00) >> 10;
    802                                                         $thisfile_mpeg_audio_lame_RGAD_track['raw']['sign_bit']    = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x0200) >> 9;
    803                                                         $thisfile_mpeg_audio_lame_RGAD_track['raw']['gain_adjust'] =  $thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x01FF;
    804                                                         $thisfile_mpeg_audio_lame_RGAD_track['name']       = getid3_lib::RGADnameLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['name']);
    805                                                         $thisfile_mpeg_audio_lame_RGAD_track['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['originator']);
    806                                                         $thisfile_mpeg_audio_lame_RGAD_track['gain_db']    = getid3_lib::RGADadjustmentLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_RGAD_track['raw']['sign_bit']);
    807 
    808                                                         if (!empty($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'])) {
    809                                                                 $info['replay_gain']['track']['peak']   = $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'];
     820                                                                if (!empty($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'])) {
     821                                                                        $info['replay_gain']['track']['peak']   = $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'];
     822                                                                }
     823                                                                $info['replay_gain']['track']['originator'] = $thisfile_mpeg_audio_lame_RGAD_track['originator'];
     824                                                                $info['replay_gain']['track']['adjustment'] = $thisfile_mpeg_audio_lame_RGAD_track['gain_db'];
     825                                                        } else {
     826                                                                unset($thisfile_mpeg_audio_lame_RGAD['track']);
    810827                                                        }
    811                                                         $info['replay_gain']['track']['originator'] = $thisfile_mpeg_audio_lame_RGAD_track['originator'];
    812                                                         $info['replay_gain']['track']['adjustment'] = $thisfile_mpeg_audio_lame_RGAD_track['gain_db'];
    813                                                 } else {
    814                                                         unset($thisfile_mpeg_audio_lame_RGAD['track']);
    815                                                 }
    816                                                 if ($thisfile_mpeg_audio_lame_raw['RGAD_album'] != 0) {
     828                                                        if ($thisfile_mpeg_audio_lame_raw['RGAD_album'] != 0) {
    817829
    818                                                         $thisfile_mpeg_audio_lame_RGAD_album['raw']['name']        = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0xE000) >> 13;
    819                                                         $thisfile_mpeg_audio_lame_RGAD_album['raw']['originator']  = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x1C00) >> 10;
    820                                                         $thisfile_mpeg_audio_lame_RGAD_album['raw']['sign_bit']    = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x0200) >> 9;
    821                                                         $thisfile_mpeg_audio_lame_RGAD_album['raw']['gain_adjust'] = $thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x01FF;
    822                                                         $thisfile_mpeg_audio_lame_RGAD_album['name']       = getid3_lib::RGADnameLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['name']);
    823                                                         $thisfile_mpeg_audio_lame_RGAD_album['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['originator']);
    824                                                         $thisfile_mpeg_audio_lame_RGAD_album['gain_db']    = getid3_lib::RGADadjustmentLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_RGAD_album['raw']['sign_bit']);
     830                                                                $thisfile_mpeg_audio_lame_RGAD_album['raw']['name']        = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0xE000) >> 13;
     831                                                                $thisfile_mpeg_audio_lame_RGAD_album['raw']['originator']  = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x1C00) >> 10;
     832                                                                $thisfile_mpeg_audio_lame_RGAD_album['raw']['sign_bit']    = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x0200) >> 9;
     833                                                                $thisfile_mpeg_audio_lame_RGAD_album['raw']['gain_adjust'] = $thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x01FF;
     834                                                                $thisfile_mpeg_audio_lame_RGAD_album['name']       = getid3_lib::RGADnameLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['name']);
     835                                                                $thisfile_mpeg_audio_lame_RGAD_album['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['originator']);
     836                                                                $thisfile_mpeg_audio_lame_RGAD_album['gain_db']    = getid3_lib::RGADadjustmentLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_RGAD_album['raw']['sign_bit']);
    825837
    826                                                         if (!empty($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'])) {
    827                                                                 $info['replay_gain']['album']['peak']   = $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'];
     838                                                                if (!empty($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'])) {
     839                                                                        $info['replay_gain']['album']['peak']   = $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'];
     840                                                                }
     841                                                                $info['replay_gain']['album']['originator'] = $thisfile_mpeg_audio_lame_RGAD_album['originator'];
     842                                                                $info['replay_gain']['album']['adjustment'] = $thisfile_mpeg_audio_lame_RGAD_album['gain_db'];
     843                                                        } else {
     844                                                                unset($thisfile_mpeg_audio_lame_RGAD['album']);
    828845                                                        }
    829                                                         $info['replay_gain']['album']['originator'] = $thisfile_mpeg_audio_lame_RGAD_album['originator'];
    830                                                         $info['replay_gain']['album']['adjustment'] = $thisfile_mpeg_audio_lame_RGAD_album['gain_db'];
    831                                                 } else {
    832                                                         unset($thisfile_mpeg_audio_lame_RGAD['album']);
    833                                                 }
    834                                                 if (empty($thisfile_mpeg_audio_lame_RGAD)) {
    835                                                         unset($thisfile_mpeg_audio_lame['RGAD']);
    836                                                 }
     846                                                        if (empty($thisfile_mpeg_audio_lame_RGAD)) {
     847                                                                unset($thisfile_mpeg_audio_lame['RGAD']);
     848                                                        }
    837849
    838850
    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;
     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;
    846858
    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                                                 }
     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                                                        }
    856868
    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;
     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;
    861873
    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']);
     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']);
    872884
    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));
     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));
    877889
    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                                                 }
     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                                                        }
    892904
    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']);
     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']);
    896908
    897                                                 // bytes $BC-$BD  MusicCRC
    898                                                 $thisfile_mpeg_audio_lame['music_crc']    = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBC, 2));
     909                                                        // bytes $BC-$BD  MusicCRC
     910                                                        $thisfile_mpeg_audio_lame['music_crc']    = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBC, 2));
    899911
    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));
     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));
    902914
    903915
    904                                                 // LAME CBR
    905                                                 if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) {
     916                                                        // LAME CBR
     917                                                        if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) {
    906918
    907                                                         $thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
    908                                                         $thisfile_mpeg_audio['bitrate'] = self::ClosestStandardMP3Bitrate($thisfile_mpeg_audio['bitrate']);
    909                                                         $info['audio']['bitrate'] = $thisfile_mpeg_audio['bitrate'];
    910                                                         //if (empty($thisfile_mpeg_audio['bitrate']) || (!empty($thisfile_mpeg_audio_lame['bitrate_min']) && ($thisfile_mpeg_audio_lame['bitrate_min'] != 255))) {
    911                                                         //      $thisfile_mpeg_audio['bitrate'] = $thisfile_mpeg_audio_lame['bitrate_min'];
    912                                                         //}
     919                                                                $thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
     920                                                                $thisfile_mpeg_audio['bitrate'] = self::ClosestStandardMP3Bitrate($thisfile_mpeg_audio['bitrate']);
     921                                                                $info['audio']['bitrate'] = $thisfile_mpeg_audio['bitrate'];
     922                                                                //if (empty($thisfile_mpeg_audio['bitrate']) || (!empty($thisfile_mpeg_audio_lame['bitrate_min']) && ($thisfile_mpeg_audio_lame['bitrate_min'] != 255))) {
     923                                                                //      $thisfile_mpeg_audio['bitrate'] = $thisfile_mpeg_audio_lame['bitrate_min'];
     924                                                                //}
    913925
     926                                                        }
     927
    914928                                                }
    915 
    916929                                        }
    917930                                }
    918931
     
    10091022                        if (!$this->RecursiveFrameScanning($offset, $nextframetestoffset, $ScanAsCBR)) {
    10101023                                return false;
    10111024                        }
     1025                        if (!empty($this->getid3->info['mp3_validity_check_bitrates']) && !empty($thisfile_mpeg_audio['bitrate_mode']) && ($thisfile_mpeg_audio['bitrate_mode'] == 'vbr') && !empty($thisfile_mpeg_audio['VBR_bitrate'])) {
     1026                                // https://github.com/JamesHeinrich/getID3/issues/287
     1027                                if (count(array_keys($this->getid3->info['mp3_validity_check_bitrates'])) == 1) {
     1028                                        list($cbr_bitrate_in_short_scan) = array_keys($this->getid3->info['mp3_validity_check_bitrates']);
     1029                                        $deviation_cbr_from_header_bitrate = abs($thisfile_mpeg_audio['VBR_bitrate'] - $cbr_bitrate_in_short_scan) / $cbr_bitrate_in_short_scan;
     1030                                        if ($deviation_cbr_from_header_bitrate < 0.01) {
     1031                                                // VBR header bitrate may differ slightly from true bitrate of frames, perhaps accounting for overhead of VBR header frame itself?
     1032                                                // If measured CBR bitrate is within 1% of specified bitrate in VBR header then assume that file is truly CBR
     1033                                                $thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
     1034                                                //$this->warning('VBR header ignored, assuming CBR '.round($cbr_bitrate_in_short_scan / 1000).'kbps based on scan of '.$this->mp3_valid_check_frames.' frames');
     1035                                        }
     1036                                }
     1037                        }
     1038                        if (isset($this->getid3->info['mp3_validity_check_bitrates'])) {
     1039                                unset($this->getid3->info['mp3_validity_check_bitrates']);
     1040                        }
    10121041
    10131042                }
    10141043
     
    11301159                $firstframetestarray = array('error' => array(), 'warning'=> array(), 'avdataend' => $info['avdataend'], 'avdataoffset' => $info['avdataoffset']);
    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
    11371167                                return true;
     
    11391169
    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
    11441175                                        if (!isset($nextframetestarray['mpeg']['audio']['bitrate']) || !isset($firstframetestarray['mpeg']['audio']['bitrate']) || ($nextframetestarray['mpeg']['audio']['bitrate'] != $firstframetestarray['mpeg']['audio']['bitrate'])) {
     
    12731304                $LongMPEGbitrateLookup        = array();
    12741305                $LongMPEGpaddingLookup        = array();
    12751306                $LongMPEGfrequencyLookup      = array();
     1307                $Distribution                 = array();
    12761308                $Distribution['bitrate']      = array();
    12771309                $Distribution['frequency']    = array();
    12781310                $Distribution['layer']        = array();
     
    14331465                $header = $this->fread($sync_seek_buffer_size);
    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)) {
    14381473
     
    14711506                                return false;
    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'])) {
    14771529                                        $FirstFrameThisfileInfo = $info;
     
    15111563                                                        if ($this->decodeMPEGaudioHeader($GarbageOffsetEnd, $dummy, true, true)) {
    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                                                }
    15191571                                        }
     
    15581610                                                $pct_data_scanned = 0;
    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;
    15631616                                                        }
     
    18871940                        return false;
    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
    18921946                $MPEGrawHeader['layer']         = (ord($Header4Bytes[1]) & 0x06) >> 1; //      CC
  • src/wp-includes/ID3/module.audio.ogg.php

     
    529529         */
    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
    534535                $filedata = $this->fread($this->getid3->fread_buffer_size());
     
    680681
    681682                                $VorbisCommentPage++;
    682683
    683                                 $oggpageinfo = $this->ParseOggPageHeader();
    684                                 $info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
     684                                if ($oggpageinfo = $this->ParseOggPageHeader()) {
     685                                        $info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
    685686
    686                                 // First, save what we haven't read yet
    687                                 $AsYetUnusedData = substr($commentdata, $commentdataoffset);
     687                                        // First, save what we haven't read yet
     688                                        $AsYetUnusedData = substr($commentdata, $commentdataoffset);
    688689
    689                                 // Then take that data off the end
    690                                 $commentdata     = substr($commentdata, 0, $commentdataoffset);
     690                                        // Then take that data off the end
     691                                        $commentdata     = substr($commentdata, 0, $commentdataoffset);
    691692
    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']);
     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']);
    695696
    696                                 // Finally, stick the unused data back on the end
    697                                 $commentdata .= $AsYetUnusedData;
     697                                        // Finally, stick the unused data back on the end
     698                                        $commentdata .= $AsYetUnusedData;
    698699
    699                                 //$commentdata .= $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
    700                                 if (!isset($info['ogg']['pageheader'][$VorbisCommentPage])) {
    701                                         $this->warning('undefined Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell());
     700                                        //$commentdata .= $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
     701                                        if (!isset($info['ogg']['pageheader'][$VorbisCommentPage])) {
     702                                                $this->warning('undefined Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell());
     703                                                break;
     704                                        }
     705                                        $readlength = self::OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1);
     706                                        if ($readlength <= 0) {
     707                                                $this->warning('invalid length Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell());
     708                                                break;
     709                                        }
     710                                        $commentdata .= $this->fread($readlength);
     711
     712                                        //$filebaseoffset += $oggpageinfo['header_end_offset'] - $oggpageinfo['page_start_offset'];
     713                                } else {
     714                                        $this->warning('failed to ParseOggPageHeader() at offset '.$this->ftell());
    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;
    714719                        $commentstring = substr($commentdata, $commentdataoffset, $ThisFileInfo_ogg_comments_raw[$i]['size']);
  • src/wp-includes/ID3/module.tag.apetag.php

     
    360360                // http://www.uni-jena.de/~pfk/mpp/sv8/apeheader.html
    361361
    362362                // shortcut
     363                $headerfooterinfo = array();
    363364                $headerfooterinfo['raw'] = array();
    364365                $headerfooterinfo_raw = &$headerfooterinfo['raw'];
    365366
     
    389390                // "Note: APE Tags 1.0 do not use any of the APE Tag flags.
    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);
    394396                $flags['this_is_header']    = (bool) ($rawflagint & 0x20000000);
  • src/wp-includes/ID3/module.tag.id3v1.php

     
    3131                        return false;
    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                }
    3743
     44
    3845                if (substr($id3v1tag, 0, 3) == 'TAG') {
    3946
    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));
    4452                        $ParsedID3v1['album']   = $this->cutfield(substr($id3v1tag,  63, 30));
     
    297305                        145  => 'Anime',
    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',
    302354
  • src/wp-includes/ID3/module.tag.id3v2.php

     
    345345                                }
    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;
    351351                                        $parsedFrame['data']            = substr($framedata, 0, $frame_size);
     
    978978
    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.
    984984                        // <Header for 'Unsynchronised lyrics/text transcription', ID: 'USLT'>
     
    994994                                $this->warning('Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding');
    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);
     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);
    10071008
    1008                         $parsedFrame['encodingid']   = $frame_textencoding;
    1009                         $parsedFrame['encoding']     = $this->TextEncodingNameLookup($frame_textencoding);
     1009                                $parsedFrame['encodingid']   = $frame_textencoding;
     1010                                $parsedFrame['encoding']     = $this->TextEncodingNameLookup($frame_textencoding);
    10101011
    1011                         $parsedFrame['language']     = $frame_language;
    1012                         $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
    1013                         if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
    1014                                 $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
     1012                                $parsedFrame['language']     = $frame_language;
     1013                                $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
     1014                                if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
     1015                                        $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
     1016                                }
     1017                        } else {
     1018                                $this->warning('Invalid data in frame "'.$parsedFrame['frame_name'].'" at offset '.$parsedFrame['dataoffset']);
    10151019                        }
    10161020                        unset($parsedFrame['data']);
    10171021
     
    13701374                                $frame_textencoding_terminator = "\x00";
    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);
    13751381                                if (strtolower($frame_imagetype) == 'ima') {
     
    19561962                        $frame_offset = 0;
    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']);
    19731975                        $parsedFrame['track']['adjustment'] = getid3_lib::RGADadjustmentLookup($parsedFrame['raw']['track']['adjustment'], $parsedFrame['raw']['track']['signbit']);
     
    24442446                        TMM     Manats
    24452447                        TND     Dinars
    24462448                        TOP     Pa'anga
    2447                         TRL     Liras
     2449                        TRL     Liras (old)
     2450                        TRY     Liras
    24482451                        TTD     Dollars
    24492452                        TVD     Tuvalu Dollars
    24502453                        TWD     New Dollars
     
    26452648                        TND     Tunisia
    26462649                        TOP     Tonga
    26472650                        TRL     Turkey
     2651                        TRY     Turkey
    26482652                        TTD     Trinidad and Tobago
    26492653                        TVD     Tuvalu
    26502654                        TWD     Taiwan
  • src/wp-includes/ID3/module.tag.lyrics3.php

     
    3333                }
    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
    3841                $lyrics3end    = substr($lyrics3_id3v1,  6,   9); // LYRICSEND or LYRICS200
  • src/wp-includes/ID3/readme.txt

     
    625625* http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
    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
     629 No newline at end of file