Make WordPress Core

Changeset 52254


Ignore:
Timestamp:
11/26/2021 03:04:10 AM (3 years ago)
Author:
SergeyBiryukov
Message:

External Libraries: Update getID3 to version 1.9.21.

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

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

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

This commit also includes:

  • Setting the $options_audiovideo_quicktime_ReturnAtomData property (now false by default) to true in wp_read_video_metadata() and wp_read_audio_metadata() in order to get the created_timestamp value.
  • PHPCS adjustments previously made for a passing PHP Compatibility scan.

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

Props jrf, SergeyBiryukov.
Fixes #54162.

Location:
trunk/src
Files:
16 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/includes/media.php

    r52245 r52254  
    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
     
    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
  • trunk/src/wp-includes/ID3/getid3.lib.php

    r51901 r52254  
    243243     * ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic
    244244     *
    245      * @link http://www.psc.edu/general/software/packages/ieee/ieee.html
     245     * @link https://web.archive.org/web/20120325162206/http://www.psc.edu/general/software/packages/ieee/ieee.php
    246246     * @link http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html
    247247     *
     
    295295        if (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction != 0)) {
    296296            // Not a Number
    297             $floatvalue = false;
     297            $floatvalue = NAN;
    298298        } elseif (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction == 0)) {
    299299            if ($signbit == '1') {
    300                 $floatvalue = '-infinity';
     300                $floatvalue = -INF;
    301301            } else {
    302                 $floatvalue = '+infinity';
     302                $floatvalue = INF;
    303303            }
    304304        } elseif (($exponent == 0) && ($fraction == 0)) {
     
    428428     */
    429429    public static function Dec2Bin($number) {
     430        if (!is_numeric($number)) {
     431            // https://github.com/JamesHeinrich/getID3/issues/299
     432            trigger_error('TypeError: Dec2Bin(): Argument #1 ($number) must be numeric, '.gettype($number).' given', E_USER_WARNING);
     433            return '';
     434        }
     435        $bytes = array();
    430436        while ($number >= 256) {
    431             $bytes[] = (($number / 256) - (floor($number / 256))) * 256;
     437            $bytes[] = (int) (($number / 256) - (floor($number / 256))) * 256;
    432438            $number = floor($number / 256);
    433439        }
    434         $bytes[] = $number;
     440        $bytes[] = (int) $number;
    435441        $binstring = '';
    436         for ($i = 0; $i < count($bytes); $i++) {
    437             $binstring = (($i == count($bytes) - 1) ? decbin($bytes[$i]) : str_pad(decbin($bytes[$i]), 8, '0', STR_PAD_LEFT)).$binstring;
     442        foreach ($bytes as $i => $byte) {
     443            $binstring = (($i == count($bytes) - 1) ? decbin($byte) : str_pad(decbin($byte), 8, '0', STR_PAD_LEFT)).$binstring;
    438444        }
    439445        return $binstring;
     
    666672        //   $foo['path']['to']['my'] = 'file.txt';
    667673        $ArrayPath = ltrim($ArrayPath, $Separator);
     674        $ReturnedArray = array();
    668675        if (($pos = strpos($ArrayPath, $Separator)) !== false) {
    669676            $ReturnedArray[substr($ArrayPath, 0, $pos)] = self::CreateDeepArray(substr($ArrayPath, $pos + 1), $Separator, $Value);
     
    15391546        // Copy all entries from ['tags'] into common ['comments']
    15401547        if (!empty($ThisFileInfo['tags'])) {
    1541             if (isset($ThisFileInfo['tags']['id3v1'])) {
    1542                 // bubble ID3v1 to the end, if present to aid in detecting bad ID3v1 encodings
    1543                 $ID3v1 = $ThisFileInfo['tags']['id3v1'];
    1544                 unset($ThisFileInfo['tags']['id3v1']);
    1545                 $ThisFileInfo['tags']['id3v1'] = $ID3v1;
    1546                 unset($ID3v1);
     1548
     1549            // Some tag types can only support limited character sets and may contain data in non-standard encoding (usually ID3v1)
     1550            // and/or poorly-transliterated tag values that are also in tag formats that do support full-range character sets
     1551            // To make the output more user-friendly, process the potentially-problematic tag formats last to enhance the chance that
     1552            // the first entries in [comments] are the most correct and the "bad" ones (if any) come later.
     1553            // https://github.com/JamesHeinrich/getID3/issues/338
     1554            $processLastTagTypes = array('id3v1','riff');
     1555            foreach ($processLastTagTypes as $processLastTagType) {
     1556                if (isset($ThisFileInfo['tags'][$processLastTagType])) {
     1557                    // bubble ID3v1 to the end, if present to aid in detecting bad ID3v1 encodings
     1558                    $temp = $ThisFileInfo['tags'][$processLastTagType];
     1559                    unset($ThisFileInfo['tags'][$processLastTagType]);
     1560                    $ThisFileInfo['tags'][$processLastTagType] = $temp;
     1561                    unset($temp);
     1562                }
    15471563            }
    15481564            foreach ($ThisFileInfo['tags'] as $tagtype => $tagarray) {
     
    15631579                                        break 2;
    15641580                                    }
    1565                                 }
    1566                                 if (function_exists('mb_convert_encoding')) {
    1567                                     if (trim($value) == trim(substr(mb_convert_encoding($existingvalue, $ThisFileInfo['id3v1']['encoding'], $ThisFileInfo['encoding']), 0, 30))) {
    1568                                         // value stored in ID3v1 appears to be probably the multibyte value transliterated (badly) into ISO-8859-1 in ID3v1.
    1569                                         // As an example, Foobar2000 will do this if you tag a file with Chinese or Arabic or Cyrillic or something that doesn't fit into ISO-8859-1 the ID3v1 will consist of mostly "?" characters, one per multibyte unrepresentable character
    1570                                         break 2;
     1581
     1582                                    if (function_exists('mb_convert_encoding')) {
     1583                                        if (trim($value) == trim(substr(mb_convert_encoding($existingvalue, $ThisFileInfo['id3v1']['encoding'], $ThisFileInfo['encoding']), 0, 30))) {
     1584                                            // value stored in ID3v1 appears to be probably the multibyte value transliterated (badly) into ISO-8859-1 in ID3v1.
     1585                                            // As an example, Foobar2000 will do this if you tag a file with Chinese or Arabic or Cyrillic or something that doesn't fit into ISO-8859-1 the ID3v1 will consist of mostly "?" characters, one per multibyte unrepresentable character
     1586                                            break 2;
     1587                                        }
    15711588                                    }
    15721589                                }
     
    15741591                            } elseif (!is_array($value)) {
    15751592
    1576                                 $newvaluelength = strlen(trim($value));
     1593                                $newvaluelength   =    strlen(trim($value));
     1594                                $newvaluelengthMB = mb_strlen(trim($value));
    15771595                                foreach ($ThisFileInfo['comments'][$tagname] as $existingkey => $existingvalue) {
    1578                                     $oldvaluelength = strlen(trim($existingvalue));
     1596                                    $oldvaluelength   =    strlen(trim($existingvalue));
     1597                                    $oldvaluelengthMB = mb_strlen(trim($existingvalue));
     1598                                    if (($newvaluelengthMB == $oldvaluelengthMB) && ($existingvalue == getid3_lib::iconv_fallback('UTF-8', 'ASCII', $value))) {
     1599                                        // https://github.com/JamesHeinrich/getID3/issues/338
     1600                                        // check for tags containing extended characters that may have been forced into limited-character storage (e.g. UTF8 values into ASCII)
     1601                                        // which will usually display unrepresentable characters as "?"
     1602                                        $ThisFileInfo['comments'][$tagname][$existingkey] = trim($value);
     1603                                        break;
     1604                                    }
    15791605                                    if ((strlen($existingvalue) > 10) && ($newvaluelength > $oldvaluelength) && (substr(trim($value), 0, strlen($existingvalue)) == $existingvalue)) {
    15801606                                        $ThisFileInfo['comments'][$tagname][$existingkey] = trim($value);
     
    16021628
    16031629            // attempt to standardize spelling of returned keys
    1604             $StandardizeFieldNames = array(
    1605                 'tracknumber' => 'track_number',
    1606                 'track'       => 'track_number',
    1607             );
    1608             foreach ($StandardizeFieldNames as $badkey => $goodkey) {
    1609                 if (array_key_exists($badkey, $ThisFileInfo['comments']) && !array_key_exists($goodkey, $ThisFileInfo['comments'])) {
    1610                     $ThisFileInfo['comments'][$goodkey] = $ThisFileInfo['comments'][$badkey];
    1611                     unset($ThisFileInfo['comments'][$badkey]);
     1630            if (!empty($ThisFileInfo['comments'])) {
     1631                $StandardizeFieldNames = array(
     1632                    'tracknumber' => 'track_number',
     1633                    'track'       => 'track_number',
     1634                );
     1635                foreach ($StandardizeFieldNames as $badkey => $goodkey) {
     1636                    if (array_key_exists($badkey, $ThisFileInfo['comments']) && !array_key_exists($goodkey, $ThisFileInfo['comments'])) {
     1637                        $ThisFileInfo['comments'][$goodkey] = $ThisFileInfo['comments'][$badkey];
     1638                        unset($ThisFileInfo['comments'][$badkey]);
     1639                    }
    16121640                }
    16131641            }
     
    17351763     */
    17361764    public static function getFileSizeSyscall($path) {
     1765        $commandline = null;
    17371766        $filesize = false;
    17381767
     
    17961825     * @return string
    17971826     */
    1798     public static function mb_basename($path, $suffix = null) {
     1827    public static function mb_basename($path, $suffix = '') {
    17991828        $splited = preg_split('#/#', rtrim($path, '/ '));
    18001829        return substr(basename('X'.$splited[count($splited) - 1], $suffix), 1);
  • trunk/src/wp-includes/ID3/getid3.php

    r51901 r52254  
    1717if (!defined('GETID3_INCLUDEPATH')) {
    1818    define('GETID3_INCLUDEPATH', dirname(__FILE__).DIRECTORY_SEPARATOR);
    19 }
    20 // Workaround Bug #39923 (https://bugs.php.net/bug.php?id=39923)
    21 if (!defined('IMG_JPG') && defined('IMAGETYPE_JPEG')) {
    22     define('IMG_JPG', IMAGETYPE_JPEG);
    2319}
    2420if (!defined('ENT_SUBSTITUTE')) { // PHP5.3 adds ENT_IGNORE, PHP5.4 adds ENT_SUBSTITUTE
     
    5854            $basedir .= DIRECTORY_SEPARATOR;
    5955        }
    60         if (preg_match('#^'.preg_quote($basedir).'#', $temp_dir)) {
     56        if (strpos($temp_dir, $basedir) === 0) {
    6157            $found_valid_tempdir = true;
    6258            break;
     
    215211    public $option_fread_buffer_size = 32768;
    216212
     213
     214
     215    // module-specific options
     216
     217    /** archive.rar
     218     * if true use PHP RarArchive extension, if false (non-extension parsing not yet written in getID3)
     219     *
     220     * @var bool
     221     */
     222    public $options_archive_rar_use_php_rar_extension = true;
     223
     224    /** archive.gzip
     225     * Optional file list - disable for speed.
     226     * Decode gzipped files, if possible, and parse recursively (.tar.gz for example).
     227     *
     228     * @var bool
     229     */
     230    public $options_archive_gzip_parse_contents = false;
     231
     232    /** audio.midi
     233     * if false only parse most basic information, much faster for some files but may be inaccurate
     234     *
     235     * @var bool
     236     */
     237    public $options_audio_midi_scanwholefile = true;
     238
     239    /** audio.mp3
     240     * Forces getID3() to scan the file byte-by-byte and log all the valid audio frame headers - extremely slow,
     241     * unrecommended, but may provide data from otherwise-unusable files.
     242     *
     243     * @var bool
     244     */
     245    public $options_audio_mp3_allow_bruteforce = false;
     246
     247    /** audio.mp3
     248     * number of frames to scan to determine if MPEG-audio sequence is valid
     249     * Lower this number to 5-20 for faster scanning
     250     * Increase this number to 50+ for most accurate detection of valid VBR/CBR mpeg-audio streams
     251     *
     252     * @var int
     253     */
     254    public $options_audio_mp3_mp3_valid_check_frames = 50;
     255
     256    /** audio.wavpack
     257     * Avoid scanning all frames (break after finding ID_RIFF_HEADER and ID_CONFIG_BLOCK,
     258     * significantly faster for very large files but other data may be missed
     259     *
     260     * @var bool
     261     */
     262    public $options_audio_wavpack_quick_parsing = false;
     263
     264    /** audio-video.flv
     265     * Break out of the loop if too many frames have been scanned; only scan this
     266     * many if meta frame does not contain useful duration.
     267     *
     268     * @var int
     269     */
     270    public $options_audiovideo_flv_max_frames = 100000;
     271
     272    /** audio-video.matroska
     273     * If true, do not return information about CLUSTER chunks, since there's a lot of them
     274     * and they're not usually useful [default: TRUE].
     275     *
     276     * @var bool
     277     */
     278    public $options_audiovideo_matroska_hide_clusters    = true;
     279
     280    /** audio-video.matroska
     281     * True to parse the whole file, not only header [default: FALSE].
     282     *
     283     * @var bool
     284     */
     285    public $options_audiovideo_matroska_parse_whole_file = false;
     286
     287    /** audio-video.quicktime
     288     * return all parsed data from all atoms if true, otherwise just returned parsed metadata
     289     *
     290     * @var bool
     291     */
     292    public $options_audiovideo_quicktime_ReturnAtomData  = false;
     293
     294    /** audio-video.quicktime
     295     * return all parsed data from all atoms if true, otherwise just returned parsed metadata
     296     *
     297     * @var bool
     298     */
     299    public $options_audiovideo_quicktime_ParseAllPossibleAtoms = false;
     300
     301    /** audio-video.swf
     302     * return all parsed tags if true, otherwise do not return tags not parsed by getID3
     303     *
     304     * @var bool
     305     */
     306    public $options_audiovideo_swf_ReturnAllTagData = false;
     307
     308    /** graphic.bmp
     309     * return BMP palette
     310     *
     311     * @var bool
     312     */
     313    public $options_graphic_bmp_ExtractPalette = false;
     314
     315    /** graphic.bmp
     316     * return image data
     317     *
     318     * @var bool
     319     */
     320    public $options_graphic_bmp_ExtractData    = false;
     321
     322    /** graphic.png
     323     * If data chunk is larger than this do not read it completely (getID3 only needs the first
     324     * few dozen bytes for parsing).
     325     *
     326     * @var int
     327     */
     328    public $options_graphic_png_max_data_bytes = 10000000;
     329
     330    /** misc.pdf
     331     * return full details of PDF Cross-Reference Table (XREF)
     332     *
     333     * @var bool
     334     */
     335    public $options_misc_pdf_returnXREF = false;
     336
     337    /** misc.torrent
     338     * Assume all .torrent files are less than 1MB and just read entire thing into memory for easy processing.
     339     * Override this value if you need to process files larger than 1MB
     340     *
     341     * @var int
     342     */
     343    public $options_misc_torrent_max_torrent_filesize = 1048576;
     344
     345
     346
    217347    // Public variables
    218348
     
    258388    protected $startup_warning = '';
    259389
    260     const VERSION           = '1.9.20-202006061653';
     390    const VERSION           = '1.9.21-202109171300';
    261391    const FREAD_BUFFER_SIZE = 32768;
    262392
     
    638768            }
    639769            $class = new $class_name($this);
     770
     771            // set module-specific options
     772            foreach (get_object_vars($this) as $getid3_object_vars_key => $getid3_object_vars_value) {
     773                if (preg_match('#^options_([^_]+)_([^_]+)_(.+)$#i', $getid3_object_vars_key, $matches)) {
     774                    list($dummy, $GOVgroup, $GOVmodule, $GOVsetting) = $matches;
     775                    $GOVgroup = (($GOVgroup == 'audiovideo') ? 'audio-video' : $GOVgroup); // variable names can only contain 0-9a-z_ so standardize here
     776                    if (($GOVgroup == $determined_format['group']) && ($GOVmodule == $determined_format['module'])) {
     777                        $class->$GOVsetting = $getid3_object_vars_value;
     778                    }
     779                }
     780            }
     781
    640782            $class->Analyze();
    641783            unset($class);
     
    13521494                            'module'    => 'msoffice',
    13531495                            'mime_type' => 'application/octet-stream',
     1496                            'fail_id3'  => 'ERROR',
     1497                            'fail_ape'  => 'ERROR',
     1498                        ),
     1499
     1500                // TORRENT             - .torrent
     1501                'torrent' => array(
     1502                            'pattern'   => '^(d8\\:announce|d7\\:comment)',
     1503                            'group'     => 'misc',
     1504                            'module'    => 'torrent',
     1505                            'mime_type' => 'application/x-bittorrent',
    13541506                            'fail_id3'  => 'ERROR',
    13551507                            'fail_ape'  => 'ERROR',
     
    14901642                            $value = trim($value, " \r\n\t"); // do not trim nulls from $value!! Unicode characters will get mangled if trailing nulls are removed!
    14911643                        }
    1492                         if ($value) {
     1644                        if (isset($value) && $value !== "") {
    14931645                            if (!is_numeric($key)) {
    14941646                                $this->info['tags'][trim($tag_name)][trim($tag_key)][$key] = $value;
     
    20972249                    break;
    20982250            }
    2099             return 0;
    2100         } else {
    2101             $pos = $bytes;
    2102             if ($whence == SEEK_CUR) {
    2103                 $pos = $this->ftell() + $bytes;
    2104             } elseif ($whence == SEEK_END) {
    2105                 $pos = $this->getid3->info['filesize'] + $bytes;
    2106             }
    2107             if (!getid3_lib::intValueSupported($pos)) {
    2108                 throw new getid3_exception('cannot fseek('.$pos.') because beyond PHP filesystem limit', 10);
    2109             }
    2110         }
    2111         return fseek($this->getid3->fp, $bytes, $whence);
     2251            return 0; // fseek returns 0 on success
     2252        }
     2253
     2254        $pos = $bytes;
     2255        if ($whence == SEEK_CUR) {
     2256            $pos = $this->ftell() + $bytes;
     2257        } elseif ($whence == SEEK_END) {
     2258            $pos = $this->getid3->info['filesize'] + $bytes;
     2259        }
     2260        if (!getid3_lib::intValueSupported($pos)) {
     2261            throw new getid3_exception('cannot fseek('.$pos.') because beyond PHP filesystem limit', 10);
     2262        }
     2263
     2264        // https://github.com/JamesHeinrich/getID3/issues/327
     2265        $result = fseek($this->getid3->fp, $bytes, $whence);
     2266        if ($result !== 0) { // fseek returns 0 on success
     2267            throw new getid3_exception('cannot fseek('.$pos.'). resource/stream does not appear to support seeking', 10);
     2268        }
     2269        return $result;
    21122270    }
    21132271
     
    22252383     */
    22262384    public function saveAttachment($name, $offset, $length, $image_mime=null) {
     2385        $fp_dest = null;
     2386        $dest = null;
    22272387        try {
    22282388
  • trunk/src/wp-includes/ID3/module.audio-video.asf.php

    r51901 r52254  
    9494        $thisfile_asf_streambitratepropertiesobject = array();
    9595        $thisfile_asf_codeclistobject = array();
     96        $StreamPropertiesObjectData = array();
    9697
    9798        for ($HeaderObjectsCounter = 0; $HeaderObjectsCounter < $thisfile_asf_headerobject['headerobjects']; $HeaderObjectsCounter++) {
     
    284285                    $offset += 2;
    285286                    if ($thisfile_asf_headerextensionobject['reserved_2'] != 6) {
    286                         $this->warning('header_extension_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_headerextensionobject['reserved_2']).') does not match expected value of "6"');
     287                        $this->warning('header_extension_object.reserved_2 ('.$thisfile_asf_headerextensionobject['reserved_2'].') does not match expected value of "6"');
    287288                        //return false;
    288289                        break;
     
    536537                    $offset += 2;
    537538                    if ($thisfile_asf_markerobject['reserved_2'] != 0) {
    538                         $this->warning('marker_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_markerobject['reserved_2']).') does not match expected value of "0"');
     539                        $this->warning('marker_object.reserved_2 ('.$thisfile_asf_markerobject['reserved_2'].') does not match expected value of "0"');
    539540                        break;
    540541                    }
     
    11941195                    $offset += 2;
    11951196                    if ($thisfile_asf_dataobject['reserved'] != 0x0101) {
    1196                         $this->warning('data_object.reserved ('.getid3_lib::PrintHexBytes($thisfile_asf_dataobject['reserved']).') does not match expected value of "0x0101"');
     1197                        $this->warning('data_object.reserved (0x'.sprintf('%04X', $thisfile_asf_dataobject['reserved']).') does not match expected value of "0x0101"');
    11971198                        //return false;
    11981199                        break;
  • trunk/src/wp-includes/ID3/module.audio-video.flv.php

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

    r51901 r52254  
    225225     * @var bool
    226226     */
    227     public static $hide_clusters    = true;
     227    public $hide_clusters    = true;
    228228
    229229    /**
     
    232232     * @var bool
    233233     */
    234     public static $parse_whole_file = false;
     234    public $parse_whole_file = false;
    235235
    236236    /*
     
    587587
    588588                    while ($this->getEBMLelement($element_data, $top_element['end'])) {
    589                         if ($element_data['id'] != EBML_ID_CLUSTER || !self::$hide_clusters) { // collect clusters only if required
     589                        if ($element_data['id'] != EBML_ID_CLUSTER || !$this->hide_clusters) { // collect clusters only if required
    590590                            $info['matroska']['segments'][] = $element_data;
    591591                        }
     
    619619                                                break;
    620620                                            }
    621                                             if (($seek_entry['target_id'] != EBML_ID_CLUSTER) || !self::$hide_clusters) { // collect clusters only if required
     621                                            if (($seek_entry['target_id'] != EBML_ID_CLUSTER) || !$this->hide_clusters) { // collect clusters only if required
    622622                                                $info['matroska']['seek'][] = $seek_entry;
    623623                                            }
     
    906906
    907907                            case EBML_ID_CUES: // A top-level element to speed seeking access. All entries are local to the segment. Should be mandatory for non "live" streams.
    908                                 if (self::$hide_clusters) { // do not parse cues if hide clusters is "ON" till they point to clusters anyway
     908                                if ($this->hide_clusters) { // do not parse cues if hide clusters is "ON" till they point to clusters anyway
    909909                                    $this->current_offset = $element_data['end'];
    910910                                    break;
     
    12471247                                    $this->current_offset = $subelement['end'];
    12481248                                }
    1249                                 if (!self::$hide_clusters) {
     1249                                if (!$this->hide_clusters) {
    12501250                                    $info['matroska']['cluster'][] = $cluster_entry;
    12511251                                }
    12521252
    12531253                                // check to see if all the data we need exists already, if so, break out of the loop
    1254                                 if (!self::$parse_whole_file) {
     1254                                if (!$this->parse_whole_file) {
    12551255                                    if (isset($info['matroska']['info']) && is_array($info['matroska']['info'])) {
    12561256                                        if (isset($info['matroska']['tracks']['tracks']) && is_array($info['matroska']['tracks']['tracks'])) {
  • trunk/src/wp-includes/ID3/module.audio-video.quicktime.php

    r51901 r52254  
    2525{
    2626
    27     public $ReturnAtomData        = true;
     27    /** audio-video.quicktime
     28     * return all parsed data from all atoms if true, otherwise just returned parsed metadata
     29     *
     30     * @var bool
     31     */
     32    public $ReturnAtomData        = false;
     33
     34    /** audio-video.quicktime
     35     * return all parsed data from all atoms if true, otherwise just returned parsed metadata
     36     *
     37     * @var bool
     38     */
    2839    public $ParseAllPossibleAtoms = false;
    2940
     
    171182        }
    172183
    173         if (!isset($info['bitrate']) && isset($info['playtime_seconds'])) {
     184        if (!isset($info['bitrate']) && !empty($info['playtime_seconds'])) {
    174185            $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
    175186        }
     
    561572                                                $atom_structure['data'] = substr($boxdata, 8);
    562573                                                if ($atomname == 'covr') {
    563                                                     // not a foolproof check, but better than nothing
    564                                                     if (preg_match('#^\\xFF\\xD8\\xFF#', $atom_structure['data'])) {
    565                                                         $atom_structure['image_mime'] = 'image/jpeg';
    566                                                     } elseif (preg_match('#^\\x89\\x50\\x4E\\x47\\x0D\\x0A\\x1A\\x0A#', $atom_structure['data'])) {
    567                                                         $atom_structure['image_mime'] = 'image/png';
    568                                                     } elseif (preg_match('#^GIF#', $atom_structure['data'])) {
    569                                                         $atom_structure['image_mime'] = 'image/gif';
     574                                                    if (!empty($atom_structure['data'])) {
     575                                                        $atom_structure['image_mime'] = 'image/unknown'; // provide default MIME type to ensure array keys exist
     576                                                        if (function_exists('getimagesizefromstring') && ($getimagesize = getimagesizefromstring($atom_structure['data'])) && !empty($getimagesize['mime'])) {
     577                                                            $atom_structure['image_mime'] = $getimagesize['mime'];
     578                                                        } else {
     579                                                            // if getimagesizefromstring is not available, or fails for some reason, fall back to simple detection of common image formats
     580                                                            $ImageFormatSignatures = array(
     581                                                                'image/jpeg' => "\xFF\xD8\xFF",
     582                                                                'image/png'  => "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A",
     583                                                                'image/gif'  => 'GIF',
     584                                                            );
     585                                                            foreach ($ImageFormatSignatures as $mime => $image_format_signature) {
     586                                                                if (substr($atom_structure['data'], 0, strlen($image_format_signature)) == $image_format_signature) {
     587                                                                    $atom_structure['image_mime'] = $mime;
     588                                                                    break;
     589                                                                }
     590                                                            }
     591                                                        }
     592                                                        $info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_structure['data'], 'description'=>'cover');
     593                                                    } else {
     594                                                        $this->warning('Unknown empty "covr" image at offset '.$baseoffset);
    570595                                                    }
    571                                                     $info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_structure['data'], 'description'=>'cover');
    572596                                                }
    573597                                                break;
     
    729753                    $atom_structure['flags']['slide_show']   = (bool) $atom_structure['slide_show_flag'];
    730754
    731                     $ptv_lookup[0] = 'normal';
    732                     $ptv_lookup[1] = 'double';
    733                     $ptv_lookup[2] = 'half';
    734                     $ptv_lookup[3] = 'full';
    735                     $ptv_lookup[4] = 'current';
     755                    $ptv_lookup = array(
     756                        0 => 'normal',
     757                        1 => 'double',
     758                        2 => 'half',
     759                        3 => 'full',
     760                        4 => 'current'
     761                    );
    736762                    if (isset($ptv_lookup[$atom_structure['display_size_raw']])) {
    737763                        $atom_structure['display_size'] = $ptv_lookup[$atom_structure['display_size_raw']];
     
    909935                                        $atom_structure['sample_description_table'][$i]['video_color_table_id']    =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 68,  2));
    910936
    911                                         $atom_structure['sample_description_table'][$i]['video_pixel_color_type']  = (($atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] > 32) ? 'grayscale' : 'color');
     937                                        $atom_structure['sample_description_table'][$i]['video_pixel_color_type']  = (((int) $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] > 32) ? 'grayscale' : 'color');
    912938                                        $atom_structure['sample_description_table'][$i]['video_pixel_color_name']  = $this->QuicktimeColorNameLookup($atom_structure['sample_description_table'][$i]['video_pixel_color_depth']);
    913939
     
    915941                                            $info['quicktime']['video']['codec_fourcc']        = $atom_structure['sample_description_table'][$i]['data_format'];
    916942                                            $info['quicktime']['video']['codec_fourcc_lookup'] = $this->QuicktimeVideoCodecLookup($atom_structure['sample_description_table'][$i]['data_format']);
    917                                             $info['quicktime']['video']['codec']               = (($atom_structure['sample_description_table'][$i]['video_encoder_name_len'] > 0) ? $atom_structure['sample_description_table'][$i]['video_encoder_name'] : $atom_structure['sample_description_table'][$i]['data_format']);
     943                                            $info['quicktime']['video']['codec']               = (((int) $atom_structure['sample_description_table'][$i]['video_encoder_name_len'] > 0) ? $atom_structure['sample_description_table'][$i]['video_encoder_name'] : $atom_structure['sample_description_table'][$i]['data_format']);
    918944                                            $info['quicktime']['video']['color_depth']         = $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'];
    919945                                            $info['quicktime']['video']['color_depth_name']    = $atom_structure['sample_description_table'][$i]['video_pixel_color_name'];
     
    15991625
    16001626                case 'NCDT':
    1601                     // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
     1627                    // https://exiftool.org/TagNames/Nikon.html
    16021628                    // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100
    16031629                    $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 4, $atomHierarchy, $ParseAllPossibleAtoms);
     
    16051631                case 'NCTH': // Nikon Camera THumbnail image
    16061632                case 'NCVW': // Nikon Camera preVieW image
    1607                     // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
     1633                case 'NCM1': // Nikon Camera preview iMage 1
     1634                case 'NCM2': // Nikon Camera preview iMage 2
     1635                    // https://exiftool.org/TagNames/Nikon.html
    16081636                    if (preg_match('/^\xFF\xD8\xFF/', $atom_data)) {
     1637                        $descriptions = array(
     1638                            'NCTH' => 'Nikon Camera Thumbnail Image',
     1639                            'NCVW' => 'Nikon Camera Preview Image',
     1640                            'NCM1' => 'Nikon Camera Preview Image 1',
     1641                            'NCM2' => 'Nikon Camera Preview Image 2',
     1642                        );
    16091643                        $atom_structure['data'] = $atom_data;
    16101644                        $atom_structure['image_mime'] = 'image/jpeg';
    1611                         $atom_structure['description'] = (($atomname == 'NCTH') ? 'Nikon Camera Thumbnail Image' : (($atomname == 'NCVW') ? 'Nikon Camera Preview Image' : 'Nikon preview image'));
    1612                         $info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_data, 'description'=>$atom_structure['description']);
    1613                     }
    1614                     break;
    1615                 case 'NCTG': // Nikon - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
    1616                     $atom_structure['data'] = $this->QuicktimeParseNikonNCTG($atom_data);
    1617                     break;
    1618                 case 'NCHD': // Nikon:MakerNoteVersion  - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
    1619                 case 'NCDB': // Nikon                   - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
    1620                 case 'CNCV': // Canon:CompressorVersion - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Canon.html
     1645                        $atom_structure['description'] = isset($descriptions[$atomname]) ? $descriptions[$atomname] : 'Nikon preview image';
     1646                        $info['quicktime']['comments']['picture'][] = array(
     1647                            'image_mime' => $atom_structure['image_mime'],
     1648                            'data' => $atom_data,
     1649                            'description' => $atom_structure['description']
     1650                        );
     1651                    }
     1652                    break;
     1653                case 'NCTG': // Nikon - https://exiftool.org/TagNames/Nikon.html#NCTG
     1654                    getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.nikon-nctg.php', __FILE__, true);
     1655                    $nikonNCTG = new getid3_tag_nikon_nctg($this->getid3);
     1656
     1657                    $atom_structure['data'] = $nikonNCTG->parse($atom_data);
     1658                    break;
     1659                case 'NCHD': // Nikon:MakerNoteVersion  - https://exiftool.org/TagNames/Nikon.html
     1660                    $makerNoteVersion = '';
     1661                    for ($i = 0, $iMax = strlen($atom_data); $i < $iMax; ++$i) {
     1662                        if (ord($atom_data[$i]) >= 0x00 && ord($atom_data[$i]) <= 0x1F) {
     1663                            $makerNoteVersion .= ' '.ord($atom_data[$i]);
     1664                        } else {
     1665                            $makerNoteVersion .= $atom_data[$i];
     1666                        }
     1667                    }
     1668                    $makerNoteVersion = rtrim($makerNoteVersion, "\x00");
     1669                    $atom_structure['data'] = array(
     1670                        'MakerNoteVersion' => $makerNoteVersion
     1671                    );
     1672                    break;
     1673                case 'NCDB': // Nikon                   - https://exiftool.org/TagNames/Nikon.html
     1674                case 'CNCV': // Canon:CompressorVersion - https://exiftool.org/TagNames/Canon.html
    16211675                    $atom_structure['data'] = $atom_data;
    16221676                    break;
     
    16251679                    // some kind of metacontainer, may contain a big data dump such as:
    16261680                    // mdta keys \005 mdtacom.apple.quicktime.make (mdtacom.apple.quicktime.creationdate ,mdtacom.apple.quicktime.location.ISO6709 $mdtacom.apple.quicktime.software !mdtacom.apple.quicktime.model ilst \01D \001 \015data \001DE\010Apple 0 \002 (data \001DE\0102011-05-11T17:54:04+0200 2 \003 *data \001DE\010+52.4936+013.3897+040.247/ \01D \004 \015data \001DE\0104.3.1 \005 \018data \001DE\010iPhone 4
    1627                     // http://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt
     1681                    // https://xhelmboyx.tripod.com/formats/qti-layout.txt
    16281682
    16291683                    $atom_structure['version']   =          getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
     
    17221776                                    'debug_list'     => '',      // Used to debug variables stored as comma delimited strings
    17231777                            );
     1778                            $debug_structure = array();
    17241779                            $debug_structure['debug_items'] = array();
    17251780                            // Can start loop here to decode all sensor data in 32 Byte chunks:
     
    20402095     */
    20412096    public function QuicktimeParseContainerAtom($atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
    2042         $atom_structure  = false;
     2097        $atom_structure = array();
    20432098        $subatomoffset  = 0;
    20442099        $subatomcounter = 0;
     
    20582113                    continue;
    20592114                }
    2060                 return $atom_structure;
     2115                break;
    20612116            }
    20622117            if (strlen($subatomdata) < ($subatomsize - 8)) {
     
    20642119                // this may be because we are refusing to parse large subatoms, or it may be because this atom had its size set too large
    20652120                // so we passed in the start of a following atom incorrectly?
    2066                 return $atom_structure;
     2121                break;
    20672122            }
    20682123            $atom_structure[$subatomcounter++] = $this->QuicktimeParseAtom($subatomname, $subatomsize, $subatomdata, $baseoffset + $subatomoffset, $atomHierarchy, $ParseAllPossibleAtoms);
    20692124            $subatomoffset += $subatomsize;
    20702125        }
     2126
     2127        if (empty($atom_structure)) {
     2128            return false;
     2129        }
     2130
    20712131        return $atom_structure;
    20722132    }
     
    25532613        if (empty($QuicktimeContentRatingLookup)) {
    25542614            $QuicktimeContentRatingLookup[0]  = 'None';
     2615            $QuicktimeContentRatingLookup[1]  = 'Explicit';
    25552616            $QuicktimeContentRatingLookup[2]  = 'Clean';
    2556             $QuicktimeContentRatingLookup[4]  = 'Explicit';
     2617            $QuicktimeContentRatingLookup[4]  = 'Explicit (old)';
    25572618        }
    25582619        return (isset($QuicktimeContentRatingLookup[$rtng]) ? $QuicktimeContentRatingLookup[$rtng] : 'invalid');
     
    26052666        }
    26062667        return (isset($QuicktimeStoreFrontCodeLookup[$sfid]) ? $QuicktimeStoreFrontCodeLookup[$sfid] : 'invalid');
    2607     }
    2608 
    2609     /**
    2610      * @param string $atom_data
    2611      *
    2612      * @return array
    2613      */
    2614     public function QuicktimeParseNikonNCTG($atom_data) {
    2615         // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
    2616         // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100
    2617         // Data is stored as records of:
    2618         // * 4 bytes record type
    2619         // * 2 bytes size of data field type:
    2620         //     0x0001 = flag   (size field *= 1-byte)
    2621         //     0x0002 = char   (size field *= 1-byte)
    2622         //     0x0003 = DWORD+ (size field *= 2-byte), values are stored CDAB
    2623         //     0x0004 = QWORD+ (size field *= 4-byte), values are stored EFGHABCD
    2624         //     0x0005 = float  (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together
    2625         //     0x0007 = bytes  (size field *= 1-byte), values are stored as ??????
    2626         //     0x0008 = ?????  (size field *= 2-byte), values are stored as ??????
    2627         // * 2 bytes data size field
    2628         // * ? bytes data (string data may be null-padded; datestamp fields are in the format "2011:05:25 20:24:15")
    2629         // all integers are stored BigEndian
    2630 
    2631         $NCTGtagName = array(
    2632             0x00000001 => 'Make',
    2633             0x00000002 => 'Model',
    2634             0x00000003 => 'Software',
    2635             0x00000011 => 'CreateDate',
    2636             0x00000012 => 'DateTimeOriginal',
    2637             0x00000013 => 'FrameCount',
    2638             0x00000016 => 'FrameRate',
    2639             0x00000022 => 'FrameWidth',
    2640             0x00000023 => 'FrameHeight',
    2641             0x00000032 => 'AudioChannels',
    2642             0x00000033 => 'AudioBitsPerSample',
    2643             0x00000034 => 'AudioSampleRate',
    2644             0x02000001 => 'MakerNoteVersion',
    2645             0x02000005 => 'WhiteBalance',
    2646             0x0200000b => 'WhiteBalanceFineTune',
    2647             0x0200001e => 'ColorSpace',
    2648             0x02000023 => 'PictureControlData',
    2649             0x02000024 => 'WorldTime',
    2650             0x02000032 => 'UnknownInfo',
    2651             0x02000083 => 'LensType',
    2652             0x02000084 => 'Lens',
    2653         );
    2654 
    2655         $offset = 0;
    2656         $data = null;
    2657         $datalength = strlen($atom_data);
    2658         $parsed = array();
    2659         while ($offset < $datalength) {
    2660             $record_type       = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 4));  $offset += 4;
    2661             $data_size_type    = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2));  $offset += 2;
    2662             $data_size         = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2));  $offset += 2;
    2663             switch ($data_size_type) {
    2664                 case 0x0001: // 0x0001 = flag   (size field *= 1-byte)
    2665                     $data = getid3_lib::BigEndian2Int(substr($atom_data, $offset, $data_size * 1));
    2666                     $offset += ($data_size * 1);
    2667                     break;
    2668                 case 0x0002: // 0x0002 = char   (size field *= 1-byte)
    2669                     $data = substr($atom_data, $offset, $data_size * 1);
    2670                     $offset += ($data_size * 1);
    2671                     $data = rtrim($data, "\x00");
    2672                     break;
    2673                 case 0x0003: // 0x0003 = DWORD+ (size field *= 2-byte), values are stored CDAB
    2674                     $data = '';
    2675                     for ($i = $data_size - 1; $i >= 0; $i--) {
    2676                         $data .= substr($atom_data, $offset + ($i * 2), 2);
    2677                     }
    2678                     $data = getid3_lib::BigEndian2Int($data);
    2679                     $offset += ($data_size * 2);
    2680                     break;
    2681                 case 0x0004: // 0x0004 = QWORD+ (size field *= 4-byte), values are stored EFGHABCD
    2682                     $data = '';
    2683                     for ($i = $data_size - 1; $i >= 0; $i--) {
    2684                         $data .= substr($atom_data, $offset + ($i * 4), 4);
    2685                     }
    2686                     $data = getid3_lib::BigEndian2Int($data);
    2687                     $offset += ($data_size * 4);
    2688                     break;
    2689                 case 0x0005: // 0x0005 = float  (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together
    2690                     $data = array();
    2691                     for ($i = 0; $i < $data_size; $i++) {
    2692                         $numerator    = getid3_lib::BigEndian2Int(substr($atom_data, $offset + ($i * 8) + 0, 4));
    2693                         $denomninator = getid3_lib::BigEndian2Int(substr($atom_data, $offset + ($i * 8) + 4, 4));
    2694                         if ($denomninator == 0) {
    2695                             $data[$i] = false;
    2696                         } else {
    2697                             $data[$i] = (double) $numerator / $denomninator;
    2698                         }
    2699                     }
    2700                     $offset += (8 * $data_size);
    2701                     if (count($data) == 1) {
    2702                         $data = $data[0];
    2703                     }
    2704                     break;
    2705                 case 0x0007: // 0x0007 = bytes  (size field *= 1-byte), values are stored as ??????
    2706                     $data = substr($atom_data, $offset, $data_size * 1);
    2707                     $offset += ($data_size * 1);
    2708                     break;
    2709                 case 0x0008: // 0x0008 = ?????  (size field *= 2-byte), values are stored as ??????
    2710                     $data = substr($atom_data, $offset, $data_size * 2);
    2711                     $offset += ($data_size * 2);
    2712                     break;
    2713                 default:
    2714                     echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br>';
    2715                     break 2;
    2716             }
    2717 
    2718             switch ($record_type) {
    2719                 case 0x00000011: // CreateDate
    2720                 case 0x00000012: // DateTimeOriginal
    2721                     $data = strtotime($data);
    2722                     break;
    2723                 case 0x0200001e: // ColorSpace
    2724                     switch ($data) {
    2725                         case 1:
    2726                             $data = 'sRGB';
    2727                             break;
    2728                         case 2:
    2729                             $data = 'Adobe RGB';
    2730                             break;
    2731                     }
    2732                     break;
    2733                 case 0x02000023: // PictureControlData
    2734                     $PictureControlAdjust = array(0=>'default', 1=>'quick', 2=>'full');
    2735                     $FilterEffect = array(0x80=>'off', 0x81=>'yellow', 0x82=>'orange',    0x83=>'red', 0x84=>'green',  0xff=>'n/a');
    2736                     $ToningEffect = array(0x80=>'b&w', 0x81=>'sepia',  0x82=>'cyanotype', 0x83=>'red', 0x84=>'yellow', 0x85=>'green', 0x86=>'blue-green', 0x87=>'blue', 0x88=>'purple-blue', 0x89=>'red-purple', 0xff=>'n/a');
    2737                     $data = array(
    2738                         'PictureControlVersion'     =>                           substr($data,  0,  4),
    2739                         'PictureControlName'        =>                     rtrim(substr($data,  4, 20), "\x00"),
    2740                         'PictureControlBase'        =>                     rtrim(substr($data, 24, 20), "\x00"),
    2741                         //'?'                       =>                           substr($data, 44,  4),
    2742                         'PictureControlAdjust'      => $PictureControlAdjust[ord(substr($data, 48,  1))],
    2743                         'PictureControlQuickAdjust' =>                       ord(substr($data, 49,  1)),
    2744                         'Sharpness'                 =>                       ord(substr($data, 50,  1)),
    2745                         'Contrast'                  =>                       ord(substr($data, 51,  1)),
    2746                         'Brightness'                =>                       ord(substr($data, 52,  1)),
    2747                         'Saturation'                =>                       ord(substr($data, 53,  1)),
    2748                         'HueAdjustment'             =>                       ord(substr($data, 54,  1)),
    2749                         'FilterEffect'              =>         $FilterEffect[ord(substr($data, 55,  1))],
    2750                         'ToningEffect'              =>         $ToningEffect[ord(substr($data, 56,  1))],
    2751                         'ToningSaturation'          =>                       ord(substr($data, 57,  1)),
    2752                     );
    2753                     break;
    2754                 case 0x02000024: // WorldTime
    2755                     // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#WorldTime
    2756                     // timezone is stored as offset from GMT in minutes
    2757                     $timezone = getid3_lib::BigEndian2Int(substr($data, 0, 2));
    2758                     if ($timezone & 0x8000) {
    2759                         $timezone = 0 - (0x10000 - $timezone);
    2760                     }
    2761                     $timezone /= 60;
    2762 
    2763                     $dst = (bool) getid3_lib::BigEndian2Int(substr($data, 2, 1));
    2764                     switch (getid3_lib::BigEndian2Int(substr($data, 3, 1))) {
    2765                         case 2:
    2766                             $datedisplayformat = 'D/M/Y'; break;
    2767                         case 1:
    2768                             $datedisplayformat = 'M/D/Y'; break;
    2769                         case 0:
    2770                         default:
    2771                             $datedisplayformat = 'Y/M/D'; break;
    2772                     }
    2773 
    2774                     $data = array('timezone'=>floatval($timezone), 'dst'=>$dst, 'display'=>$datedisplayformat);
    2775                     break;
    2776                 case 0x02000083: // LensType
    2777                     $data = array(
    2778                         //'_'  => $data,
    2779                         'mf' => (bool) ($data & 0x01),
    2780                         'd'  => (bool) ($data & 0x02),
    2781                         'g'  => (bool) ($data & 0x04),
    2782                         'vr' => (bool) ($data & 0x08),
    2783                     );
    2784                     break;
    2785             }
    2786             $tag_name = (isset($NCTGtagName[$record_type]) ? $NCTGtagName[$record_type] : '0x'.str_pad(dechex($record_type), 8, '0', STR_PAD_LEFT));
    2787             $parsed[$tag_name] = $data;
    2788         }
    2789         return $parsed;
    27902668    }
    27912669
  • trunk/src/wp-includes/ID3/module.audio-video.riff.php

    r51901 r52254  
    5757        $thisfile_riff_WAVE        = array();
    5858
     59        $Original                 = array();
    5960        $Original['avdataoffset'] = $info['avdataoffset'];
    6061        $Original['avdataend']    = $info['avdataend'];
     
    297298                    $thisfile_riff_WAVE_bext_0 = &$thisfile_riff_WAVE['bext'][0];
    298299
    299                     $thisfile_riff_WAVE_bext_0['title']          =                         trim(substr($thisfile_riff_WAVE_bext_0['data'],   0, 256));
    300                     $thisfile_riff_WAVE_bext_0['author']         =                         trim(substr($thisfile_riff_WAVE_bext_0['data'], 256,  32));
    301                     $thisfile_riff_WAVE_bext_0['reference']      =                         trim(substr($thisfile_riff_WAVE_bext_0['data'], 288,  32));
     300                    $thisfile_riff_WAVE_bext_0['title']          =                              substr($thisfile_riff_WAVE_bext_0['data'],   0, 256);
     301                    $thisfile_riff_WAVE_bext_0['author']         =                              substr($thisfile_riff_WAVE_bext_0['data'], 256,  32);
     302                    $thisfile_riff_WAVE_bext_0['reference']      =                              substr($thisfile_riff_WAVE_bext_0['data'], 288,  32);
     303                    foreach (array('title','author','reference') as $bext_key) {
     304                        // Some software (notably Logic Pro) may not blank existing data before writing a null-terminated string to the offsets
     305                        // assigned for text fields, resulting in a null-terminated string (or possibly just a single null) followed by garbage
     306                        // Keep only string as far as first null byte, discard rest of fixed-width data
     307                        // https://github.com/JamesHeinrich/getID3/issues/263
     308                        $null_terminator_offset = strpos($thisfile_riff_WAVE_bext_0[$bext_key], "\x00");
     309                        $thisfile_riff_WAVE_bext_0[$bext_key] = substr($thisfile_riff_WAVE_bext_0[$bext_key], 0, $null_terminator_offset);
     310                    }
     311
    302312                    $thisfile_riff_WAVE_bext_0['origin_date']    =                              substr($thisfile_riff_WAVE_bext_0['data'], 320,  10);
    303313                    $thisfile_riff_WAVE_bext_0['origin_time']    =                              substr($thisfile_riff_WAVE_bext_0['data'], 330,   8);
     
    308318                    if (preg_match('#^([0-9]{4}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_date'], $matches_bext_date)) {
    309319                        if (preg_match('#^([0-9]{2}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_time'], $matches_bext_time)) {
     320                            $bext_timestamp = array();
    310321                            list($dummy, $bext_timestamp['year'], $bext_timestamp['month'],  $bext_timestamp['day'])    = $matches_bext_date;
    311322                            list($dummy, $bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second']) = $matches_bext_time;
     
    452463                }
    453464
    454 
     465                if (isset($thisfile_riff_WAVE['guan'][0]['data'])) {
     466                    // shortcut
     467                    $thisfile_riff_WAVE_guan_0 = &$thisfile_riff_WAVE['guan'][0];
     468                    if (!empty($thisfile_riff_WAVE_guan_0['data']) && (substr($thisfile_riff_WAVE_guan_0['data'], 0, 14) == 'GUANO|Version:')) {
     469                        $thisfile_riff['guano'] = array();
     470                        foreach (explode("\n", $thisfile_riff_WAVE_guan_0['data']) as $line) {
     471                            if ($line) {
     472                                @list($key, $value) = explode(':', $line, 2);
     473                                if (substr($value, 0, 3) == '[{"') {
     474                                    if ($decoded = @json_decode($value, true)) {
     475                                        if (!empty($decoded) && (count($decoded) == 1)) {
     476                                            $value = $decoded[0];
     477                                        } else {
     478                                            $value = $decoded;
     479                                        }
     480                                    }
     481                                }
     482                                $thisfile_riff['guano'] = array_merge_recursive($thisfile_riff['guano'], getid3_lib::CreateDeepArray($key, '|', $value));
     483                            }
     484                        }
     485
     486                        // https://www.wildlifeacoustics.com/SCHEMA/GUANO.html
     487                        foreach ($thisfile_riff['guano'] as $key => $value) {
     488                            switch ($key) {
     489                                case 'Loc Position':
     490                                    if (preg_match('#^([\\+\\-]?[0-9]+\\.[0-9]+) ([\\+\\-]?[0-9]+\\.[0-9]+)$#', $value, $matches)) {
     491                                        list($dummy, $latitude, $longitude) = $matches;
     492                                        $thisfile_riff['comments']['gps_latitude'][0]  = floatval($latitude);
     493                                        $thisfile_riff['comments']['gps_longitude'][0] = floatval($longitude);
     494                                        $thisfile_riff['guano'][$key] = floatval($latitude).' '.floatval($longitude);
     495                                    }
     496                                    break;
     497                                case 'Loc Elevation': // Elevation/altitude above mean sea level in meters
     498                                    $thisfile_riff['comments']['gps_altitude'][0] = floatval($value);
     499                                    $thisfile_riff['guano'][$key] = (float) $value;
     500                                    break;
     501                                case 'Filter HP':        // High-pass filter frequency in kHz
     502                                case 'Filter LP':        // Low-pass filter frequency in kHz
     503                                case 'Humidity':         // Relative humidity as a percentage
     504                                case 'Length':           // Recording length in seconds
     505                                case 'Loc Accuracy':     // Estimated Position Error in meters
     506                                case 'Temperature Ext':  // External temperature in degrees Celsius outside the recorder's housing
     507                                case 'Temperature Int':  // Internal temperature in degrees Celsius inside the recorder's housing
     508                                    $thisfile_riff['guano'][$key] = (float) $value;
     509                                    break;
     510                                case 'Samplerate':       // Recording sample rate, Hz
     511                                case 'TE':               // Time-expansion factor. If not specified, then 1 (no time-expansion a.k.a. direct-recording) is assumed.
     512                                    $thisfile_riff['guano'][$key] = (int) $value;
     513                                    break;
     514                            }
     515                        }
     516
     517                    } else {
     518                        $this->warning('RIFF.guan data not in expected format');
     519                    }
     520                }
    455521
    456522                if (!isset($thisfile_audio['bitrate']) && isset($thisfile_riff_audio[$streamindex]['bitrate'])) {
     
    734800                if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][0]['data'])) {
    735801                    if (is_array($thisfile_riff['AVI ']['hdrl']['strl']['strh'])) {
     802                        $thisfile_riff_raw_strf_strhfccType_streamindex = null;
    736803                        for ($i = 0; $i < count($thisfile_riff['AVI ']['hdrl']['strl']['strh']); $i++) {
    737804                            if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'])) {
     
    10701137                    getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
    10711138                    $getid3_temp = new getID3();
    1072                     $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
     1139                    $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
    10731140                    $getid3_id3v2 = new getid3_id3v2($getid3_temp);
    10741141                    $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['ID3 '][0]['offset'] + 8;
     
    11731240
    11741241                    $getid3_temp = new getID3();
    1175                     $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
     1242                    $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
    11761243                    $getid3_mpeg = new getid3_mpeg($getid3_temp);
    11771244                    $getid3_mpeg->Analyze();
     
    12591326
    12601327                    $getid3_temp = new getID3();
    1261                     $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
     1328                    $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
    12621329                    $getid3_id3v2 = new getid3_id3v2($getid3_temp);
    12631330                    $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['id3 '][0]['offset'] + 8;
     
    15151582        $RIFFchunk = false;
    15161583        $FoundAllChunksWeNeed = false;
     1584        $LISTchunkParent = null;
     1585        $LISTchunkMaxOffset = null;
     1586        $AC3syncwordBytes = pack('n', getid3_ac3::syncword); // 0x0B77 -> "\x0B\x77"
    15171587
    15181588        try {
     
    15581628                                        if (getid3_mp3::MPEGaudioHeaderBytesValid($FirstFourBytes)) {
    15591629                                            $getid3_temp = new getID3();
    1560                                             $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
     1630                                            $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
    15611631                                            $getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
    15621632                                            $getid3_temp->info['avdataend']    = $this->ftell() + $AudioChunkSize;
     
    15761646                                        }
    15771647
    1578                                     } elseif (strpos($FirstFourBytes, getid3_ac3::syncword) === 0) {
    1579 
     1648                                    } elseif (strpos($FirstFourBytes, $AC3syncwordBytes) === 0) {
    15801649                                        // AC3
    15811650                                        $getid3_temp = new getID3();
    1582                                         $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
     1651                                        $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
    15831652                                        $getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
    15841653                                        $getid3_temp->info['avdataend']    = $this->ftell() + $AudioChunkSize;
     
    16411710                                    if (getid3_mp3::MPEGaudioHeaderBytesValid(substr($testData, 0, 4))) {
    16421711                                        $getid3_temp = new getID3();
    1643                                         $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
     1712                                        $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
    16441713                                        $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
    16451714                                        $getid3_temp->info['avdataend']    = $info['avdataend'];
     
    16531722                                    }
    16541723
    1655                                 } elseif (($isRegularAC3 = (substr($testData, 0, 2) == getid3_ac3::syncword)) || substr($testData, 8, 2) == strrev(getid3_ac3::syncword)) {
     1724                                } elseif (($isRegularAC3 = (substr($testData, 0, 2) == $AC3syncwordBytes)) || substr($testData, 8, 2) == strrev($AC3syncwordBytes)) {
    16561725
    16571726                                    // This is probably AC-3 data
    16581727                                    $getid3_temp = new getID3();
    16591728                                    if ($isRegularAC3) {
    1660                                         $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
     1729                                        $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
    16611730                                        $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
    16621731                                        $getid3_temp->info['avdataend']    = $info['avdataend'];
     
    16741743                                            $ac3_data .= substr($testData, 8 + $i + 0, 1);
    16751744                                        }
     1745                                        $getid3_ac3->getid3->info['avdataoffset'] = 0;
     1746                                        $getid3_ac3->getid3->info['avdataend']    = strlen($ac3_data);
    16761747                                        $getid3_ac3->AnalyzeString($ac3_data);
    16771748                                    }
     
    16921763                                    // This is probably DTS data
    16931764                                    $getid3_temp = new getID3();
    1694                                     $getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
     1765                                    $getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
    16951766                                    $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
    16961767                                    $getid3_dts = new getid3_dts($getid3_temp);
     
    17331804                            case 'MEXT':
    17341805                            case 'DISP':
     1806                            case 'wamd':
     1807                            case 'guan':
    17351808                                // always read data in
    17361809                            case 'JUNK':
     
    20772150    public static function ParseBITMAPINFOHEADER($BITMAPINFOHEADER, $littleEndian=true) {
    20782151
     2152        $parsed                    = array();
    20792153        $parsed['biSize']          = substr($BITMAPINFOHEADER,  0, 4); // number of bytes required by the BITMAPINFOHEADER structure
    20802154        $parsed['biWidth']         = substr($BITMAPINFOHEADER,  4, 4); // width of the bitmap in pixels
  • trunk/src/wp-includes/ID3/module.audio.flac.php

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

    r51901 r52254  
    1919}
    2020
    21 // number of frames to scan to determine if MPEG-audio sequence is valid
    22 // Lower this number to 5-20 for faster scanning
    23 // Increase this number to 50+ for most accurate detection of valid VBR/CBR
    24 // mpeg-audio streams
    25 define('GETID3_MP3_VALID_CHECK_FRAMES', 35);
    26 
    2721
    2822class getid3_mp3 extends getid3_handler
     
    3731
    3832    /**
     33     * number of frames to scan to determine if MPEG-audio sequence is valid
     34     * Lower this number to 5-20 for faster scanning
     35     * Increase this number to 50+ for most accurate detection of valid VBR/CBR mpeg-audio streams
     36     *
     37     * @var int
     38     */
     39    public $mp3_valid_check_frames = 50;
     40
     41    /**
    3942     * @return bool
    4043     */
     
    5659        }
    5760
     61        $CurrentDataLAMEversionString = null;
    5862        if (((isset($info['id3v2']['headerlength']) && ($info['avdataoffset'] > $info['id3v2']['headerlength'])) || (!isset($info['id3v2']) && ($info['avdataoffset'] > 0) && ($info['avdataoffset'] != $initialOffset)))) {
    5963
     
    122126                    $PossiblyLongerLAMEversion_NewString = substr($PossiblyLongerLAMEversion_String, 0, strspn($PossiblyLongerLAMEversion_String, 'LAME0123456789., (abcdefghijklmnopqrstuvwxyzJFSOND)')); //"LAME3.90.3"  "LAME3.87 (beta 1, Sep 27 2000)" "LAME3.88 (beta)"
    123127                    if (empty($info['audio']['encoder']) || (strlen($PossiblyLongerLAMEversion_NewString) > strlen($info['audio']['encoder']))) {
     128                        if (!empty($info['audio']['encoder']) && !empty($info['mpeg']['audio']['LAME']['short_version']) && ($info['audio']['encoder'] == $info['mpeg']['audio']['LAME']['short_version'])) {
     129                            if (preg_match('#^LAME[0-9\\.]+#', $PossiblyLongerLAMEversion_NewString, $matches)) {
     130                                // "LAME3.100" -> "LAME3.100.1", but avoid including "(alpha)" and similar
     131                                $info['mpeg']['audio']['LAME']['short_version'] = $matches[0];
     132                            }
     133                        }
    124134                        $info['audio']['encoder'] = $PossiblyLongerLAMEversion_NewString;
    125135                    }
     
    296306
    297307            if ($info['audio']['bitrate_mode'] == 'cbr') {
    298                 $encoder_options = strtoupper($info['audio']['bitrate_mode']).ceil($info['audio']['bitrate'] / 1000);
     308                $encoder_options = strtoupper($info['audio']['bitrate_mode']).round($info['audio']['bitrate'] / 1000);
    299309            } else {
    300310                $encoder_options = strtoupper($info['audio']['bitrate_mode']);
     
    489499            $thisfile_mpeg_audio['raw'] = $MPEGheaderRawArray;
    490500        } else {
    491             $this->error('Invalid MPEG audio header ('.getid3_lib::PrintHexBytes($head4).') at offset '.$offset);
     501            $this->warning('Invalid MPEG audio header ('.getid3_lib::PrintHexBytes($head4).') at offset '.$offset);
    492502            return false;
    493503        }
     
    723733                    $thisfile_mpeg_audio_lame['long_version']  = substr($headerstring, $VBRidOffset + 120, 20);
    724734                    $thisfile_mpeg_audio_lame['short_version'] = substr($thisfile_mpeg_audio_lame['long_version'], 0, 9);
    725                     $thisfile_mpeg_audio_lame['numeric_version'] = str_replace('LAME', '', $thisfile_mpeg_audio_lame['short_version']);
    726                     if (preg_match('#^LAME([0-9\\.a-z]+)#', $thisfile_mpeg_audio_lame['long_version'], $matches)) {
     735
     736                    //$thisfile_mpeg_audio_lame['numeric_version'] = str_replace('LAME', '', $thisfile_mpeg_audio_lame['short_version']);
     737                    $thisfile_mpeg_audio_lame['numeric_version'] = '';
     738                    if (preg_match('#^LAME([0-9\\.a-z]*)#', $thisfile_mpeg_audio_lame['long_version'], $matches)) {
    727739                        $thisfile_mpeg_audio_lame['short_version']   = $matches[0];
    728740                        $thisfile_mpeg_audio_lame['numeric_version'] = $matches[1];
    729741                    }
    730                     foreach (explode('.', $thisfile_mpeg_audio_lame['numeric_version']) as $key => $number) {
    731                         $thisfile_mpeg_audio_lame['integer_version'][$key] = intval($number);
    732                     }
    733 
    734                     //if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.90') {
    735                     if ((($thisfile_mpeg_audio_lame['integer_version'][0] * 1000) + $thisfile_mpeg_audio_lame['integer_version'][1]) >= 3090) { // cannot use string version compare, may have "LAME3.90" or "LAME3.100" -- see https://github.com/JamesHeinrich/getID3/issues/207
    736 
    737                         // extra 11 chars are not part of version string when LAMEtag present
    738                         unset($thisfile_mpeg_audio_lame['long_version']);
    739 
    740                         // It the LAME tag was only introduced in LAME v3.90
    741                         // http://www.hydrogenaudio.org/?act=ST&f=15&t=9933
    742 
    743                         // Offsets of various bytes in http://gabriel.mp3-tech.org/mp3infotag.html
    744                         // are assuming a 'Xing' identifier offset of 0x24, which is the case for
    745                         // MPEG-1 non-mono, but not for other combinations
    746                         $LAMEtagOffsetContant = $VBRidOffset - 0x24;
    747 
    748                         // shortcuts
    749                         $thisfile_mpeg_audio_lame['RGAD']    = array('track'=>array(), 'album'=>array());
    750                         $thisfile_mpeg_audio_lame_RGAD       = &$thisfile_mpeg_audio_lame['RGAD'];
    751                         $thisfile_mpeg_audio_lame_RGAD_track = &$thisfile_mpeg_audio_lame_RGAD['track'];
    752                         $thisfile_mpeg_audio_lame_RGAD_album = &$thisfile_mpeg_audio_lame_RGAD['album'];
    753                         $thisfile_mpeg_audio_lame['raw'] = array();
    754                         $thisfile_mpeg_audio_lame_raw    = &$thisfile_mpeg_audio_lame['raw'];
    755 
    756                         // byte $9B  VBR Quality
    757                         // This field is there to indicate a quality level, although the scale was not precised in the original Xing specifications.
    758                         // Actually overwrites original Xing bytes
    759                         unset($thisfile_mpeg_audio['VBR_scale']);
    760                         $thisfile_mpeg_audio_lame['vbr_quality'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0x9B, 1));
    761 
    762                         // bytes $9C-$A4  Encoder short VersionString
    763                         $thisfile_mpeg_audio_lame['short_version'] = substr($headerstring, $LAMEtagOffsetContant + 0x9C, 9);
    764 
    765                         // byte $A5  Info Tag revision + VBR method
    766                         $LAMEtagRevisionVBRmethod = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA5, 1));
    767 
    768                         $thisfile_mpeg_audio_lame['tag_revision']   = ($LAMEtagRevisionVBRmethod & 0xF0) >> 4;
    769                         $thisfile_mpeg_audio_lame_raw['vbr_method'] =  $LAMEtagRevisionVBRmethod & 0x0F;
    770                         $thisfile_mpeg_audio_lame['vbr_method']     = self::LAMEvbrMethodLookup($thisfile_mpeg_audio_lame_raw['vbr_method']);
    771                         $thisfile_mpeg_audio['bitrate_mode']        = substr($thisfile_mpeg_audio_lame['vbr_method'], 0, 3); // usually either 'cbr' or 'vbr', but truncates 'vbr-old / vbr-rh' to 'vbr'
    772 
    773                         // byte $A6  Lowpass filter value
    774                         $thisfile_mpeg_audio_lame['lowpass_frequency'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA6, 1)) * 100;
    775 
    776                         // bytes $A7-$AE  Replay Gain
    777                         // http://privatewww.essex.ac.uk/~djmrob/replaygain/rg_data_format.html
    778                         // bytes $A7-$AA : 32 bit floating point "Peak signal amplitude"
    779                         if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.94b') {
    780                             // LAME 3.94a16 and later - 9.23 fixed point
    781                             // ie 0x0059E2EE / (2^23) = 5890798 / 8388608 = 0.7022378444671630859375
    782                             $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] = (float) ((getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4))) / 8388608);
    783                         } else {
    784                             // LAME 3.94a15 and earlier - 32-bit floating point
    785                             // Actually 3.94a16 will fall in here too and be WRONG, but is hard to detect 3.94a16 vs 3.94a15
    786                             $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] = getid3_lib::LittleEndian2Float(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4));
     742                    if (strlen($thisfile_mpeg_audio_lame['numeric_version']) > 0) {
     743                        foreach (explode('.', $thisfile_mpeg_audio_lame['numeric_version']) as $key => $number) {
     744                            $thisfile_mpeg_audio_lame['integer_version'][$key] = intval($number);
    787745                        }
    788                         if ($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] == 0) {
    789                             unset($thisfile_mpeg_audio_lame_RGAD['peak_amplitude']);
    790                         } else {
    791                             $thisfile_mpeg_audio_lame_RGAD['peak_db'] = getid3_lib::RGADamplitude2dB($thisfile_mpeg_audio_lame_RGAD['peak_amplitude']);
     746                        //if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.90') {
     747                        if ((($thisfile_mpeg_audio_lame['integer_version'][0] * 1000) + $thisfile_mpeg_audio_lame['integer_version'][1]) >= 3090) { // cannot use string version compare, may have "LAME3.90" or "LAME3.100" -- see https://github.com/JamesHeinrich/getID3/issues/207
     748
     749                            // extra 11 chars are not part of version string when LAMEtag present
     750                            unset($thisfile_mpeg_audio_lame['long_version']);
     751
     752                            // It the LAME tag was only introduced in LAME v3.90
     753                            // http://www.hydrogenaudio.org/?act=ST&f=15&t=9933
     754
     755                            // Offsets of various bytes in http://gabriel.mp3-tech.org/mp3infotag.html
     756                            // are assuming a 'Xing' identifier offset of 0x24, which is the case for
     757                            // MPEG-1 non-mono, but not for other combinations
     758                            $LAMEtagOffsetContant = $VBRidOffset - 0x24;
     759
     760                            // shortcuts
     761                            $thisfile_mpeg_audio_lame['RGAD']    = array('track'=>array(), 'album'=>array());
     762                            $thisfile_mpeg_audio_lame_RGAD       = &$thisfile_mpeg_audio_lame['RGAD'];
     763                            $thisfile_mpeg_audio_lame_RGAD_track = &$thisfile_mpeg_audio_lame_RGAD['track'];
     764                            $thisfile_mpeg_audio_lame_RGAD_album = &$thisfile_mpeg_audio_lame_RGAD['album'];
     765                            $thisfile_mpeg_audio_lame['raw'] = array();
     766                            $thisfile_mpeg_audio_lame_raw    = &$thisfile_mpeg_audio_lame['raw'];
     767
     768                            // byte $9B  VBR Quality
     769                            // This field is there to indicate a quality level, although the scale was not precised in the original Xing specifications.
     770                            // Actually overwrites original Xing bytes
     771                            unset($thisfile_mpeg_audio['VBR_scale']);
     772                            $thisfile_mpeg_audio_lame['vbr_quality'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0x9B, 1));
     773
     774                            // bytes $9C-$A4  Encoder short VersionString
     775                            $thisfile_mpeg_audio_lame['short_version'] = substr($headerstring, $LAMEtagOffsetContant + 0x9C, 9);
     776
     777                            // byte $A5  Info Tag revision + VBR method
     778                            $LAMEtagRevisionVBRmethod = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA5, 1));
     779
     780                            $thisfile_mpeg_audio_lame['tag_revision']   = ($LAMEtagRevisionVBRmethod & 0xF0) >> 4;
     781                            $thisfile_mpeg_audio_lame_raw['vbr_method'] =  $LAMEtagRevisionVBRmethod & 0x0F;
     782                            $thisfile_mpeg_audio_lame['vbr_method']     = self::LAMEvbrMethodLookup($thisfile_mpeg_audio_lame_raw['vbr_method']);
     783                            $thisfile_mpeg_audio['bitrate_mode']        = substr($thisfile_mpeg_audio_lame['vbr_method'], 0, 3); // usually either 'cbr' or 'vbr', but truncates 'vbr-old / vbr-rh' to 'vbr'
     784
     785                            // byte $A6  Lowpass filter value
     786                            $thisfile_mpeg_audio_lame['lowpass_frequency'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA6, 1)) * 100;
     787
     788                            // bytes $A7-$AE  Replay Gain
     789                            // http://privatewww.essex.ac.uk/~djmrob/replaygain/rg_data_format.html
     790                            // bytes $A7-$AA : 32 bit floating point "Peak signal amplitude"
     791                            if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.94b') {
     792                                // LAME 3.94a16 and later - 9.23 fixed point
     793                                // ie 0x0059E2EE / (2^23) = 5890798 / 8388608 = 0.7022378444671630859375
     794                                $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] = (float) ((getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4))) / 8388608);
     795                            } else {
     796                                // LAME 3.94a15 and earlier - 32-bit floating point
     797                                // Actually 3.94a16 will fall in here too and be WRONG, but is hard to detect 3.94a16 vs 3.94a15
     798                                $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] = getid3_lib::LittleEndian2Float(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4));
     799                            }
     800                            if ($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] == 0) {
     801                                unset($thisfile_mpeg_audio_lame_RGAD['peak_amplitude']);
     802                            } else {
     803                                $thisfile_mpeg_audio_lame_RGAD['peak_db'] = getid3_lib::RGADamplitude2dB($thisfile_mpeg_audio_lame_RGAD['peak_amplitude']);
     804                            }
     805
     806                            $thisfile_mpeg_audio_lame_raw['RGAD_track']      =   getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAB, 2));
     807                            $thisfile_mpeg_audio_lame_raw['RGAD_album']      =   getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAD, 2));
     808
     809
     810                            if ($thisfile_mpeg_audio_lame_raw['RGAD_track'] != 0) {
     811
     812                                $thisfile_mpeg_audio_lame_RGAD_track['raw']['name']        = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0xE000) >> 13;
     813                                $thisfile_mpeg_audio_lame_RGAD_track['raw']['originator']  = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x1C00) >> 10;
     814                                $thisfile_mpeg_audio_lame_RGAD_track['raw']['sign_bit']    = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x0200) >> 9;
     815                                $thisfile_mpeg_audio_lame_RGAD_track['raw']['gain_adjust'] =  $thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x01FF;
     816                                $thisfile_mpeg_audio_lame_RGAD_track['name']       = getid3_lib::RGADnameLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['name']);
     817                                $thisfile_mpeg_audio_lame_RGAD_track['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['originator']);
     818                                $thisfile_mpeg_audio_lame_RGAD_track['gain_db']    = getid3_lib::RGADadjustmentLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_RGAD_track['raw']['sign_bit']);
     819
     820                                if (!empty($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'])) {
     821                                    $info['replay_gain']['track']['peak']   = $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'];
     822                                }
     823                                $info['replay_gain']['track']['originator'] = $thisfile_mpeg_audio_lame_RGAD_track['originator'];
     824                                $info['replay_gain']['track']['adjustment'] = $thisfile_mpeg_audio_lame_RGAD_track['gain_db'];
     825                            } else {
     826                                unset($thisfile_mpeg_audio_lame_RGAD['track']);
     827                            }
     828                            if ($thisfile_mpeg_audio_lame_raw['RGAD_album'] != 0) {
     829
     830                                $thisfile_mpeg_audio_lame_RGAD_album['raw']['name']        = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0xE000) >> 13;
     831                                $thisfile_mpeg_audio_lame_RGAD_album['raw']['originator']  = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x1C00) >> 10;
     832                                $thisfile_mpeg_audio_lame_RGAD_album['raw']['sign_bit']    = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x0200) >> 9;
     833                                $thisfile_mpeg_audio_lame_RGAD_album['raw']['gain_adjust'] = $thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x01FF;
     834                                $thisfile_mpeg_audio_lame_RGAD_album['name']       = getid3_lib::RGADnameLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['name']);
     835                                $thisfile_mpeg_audio_lame_RGAD_album['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['originator']);
     836                                $thisfile_mpeg_audio_lame_RGAD_album['gain_db']    = getid3_lib::RGADadjustmentLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_RGAD_album['raw']['sign_bit']);
     837
     838                                if (!empty($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'])) {
     839                                    $info['replay_gain']['album']['peak']   = $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'];
     840                                }
     841                                $info['replay_gain']['album']['originator'] = $thisfile_mpeg_audio_lame_RGAD_album['originator'];
     842                                $info['replay_gain']['album']['adjustment'] = $thisfile_mpeg_audio_lame_RGAD_album['gain_db'];
     843                            } else {
     844                                unset($thisfile_mpeg_audio_lame_RGAD['album']);
     845                            }
     846                            if (empty($thisfile_mpeg_audio_lame_RGAD)) {
     847                                unset($thisfile_mpeg_audio_lame['RGAD']);
     848                            }
     849
     850
     851                            // byte $AF  Encoding flags + ATH Type
     852                            $EncodingFlagsATHtype = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAF, 1));
     853                            $thisfile_mpeg_audio_lame['encoding_flags']['nspsytune']   = (bool) ($EncodingFlagsATHtype & 0x10);
     854                            $thisfile_mpeg_audio_lame['encoding_flags']['nssafejoint'] = (bool) ($EncodingFlagsATHtype & 0x20);
     855                            $thisfile_mpeg_audio_lame['encoding_flags']['nogap_next']  = (bool) ($EncodingFlagsATHtype & 0x40);
     856                            $thisfile_mpeg_audio_lame['encoding_flags']['nogap_prev']  = (bool) ($EncodingFlagsATHtype & 0x80);
     857                            $thisfile_mpeg_audio_lame['ath_type']                      =         $EncodingFlagsATHtype & 0x0F;
     858
     859                            // byte $B0  if ABR {specified bitrate} else {minimal bitrate}
     860                            $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB0, 1));
     861                            if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 2) { // Average BitRate (ABR)
     862                                $thisfile_mpeg_audio_lame['bitrate_abr'] = $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'];
     863                            } elseif ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) { // Constant BitRate (CBR)
     864                                // ignore
     865                            } elseif ($thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] > 0) { // Variable BitRate (VBR) - minimum bitrate
     866                                $thisfile_mpeg_audio_lame['bitrate_min'] = $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'];
     867                            }
     868
     869                            // bytes $B1-$B3  Encoder delays
     870                            $EncoderDelays = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB1, 3));
     871                            $thisfile_mpeg_audio_lame['encoder_delay'] = ($EncoderDelays & 0xFFF000) >> 12;
     872                            $thisfile_mpeg_audio_lame['end_padding']   =  $EncoderDelays & 0x000FFF;
     873
     874                            // byte $B4  Misc
     875                            $MiscByte = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB4, 1));
     876                            $thisfile_mpeg_audio_lame_raw['noise_shaping']       = ($MiscByte & 0x03);
     877                            $thisfile_mpeg_audio_lame_raw['stereo_mode']         = ($MiscByte & 0x1C) >> 2;
     878                            $thisfile_mpeg_audio_lame_raw['not_optimal_quality'] = ($MiscByte & 0x20) >> 5;
     879                            $thisfile_mpeg_audio_lame_raw['source_sample_freq']  = ($MiscByte & 0xC0) >> 6;
     880                            $thisfile_mpeg_audio_lame['noise_shaping']       = $thisfile_mpeg_audio_lame_raw['noise_shaping'];
     881                            $thisfile_mpeg_audio_lame['stereo_mode']         = self::LAMEmiscStereoModeLookup($thisfile_mpeg_audio_lame_raw['stereo_mode']);
     882                            $thisfile_mpeg_audio_lame['not_optimal_quality'] = (bool) $thisfile_mpeg_audio_lame_raw['not_optimal_quality'];
     883                            $thisfile_mpeg_audio_lame['source_sample_freq']  = self::LAMEmiscSourceSampleFrequencyLookup($thisfile_mpeg_audio_lame_raw['source_sample_freq']);
     884
     885                            // byte $B5  MP3 Gain
     886                            $thisfile_mpeg_audio_lame_raw['mp3_gain'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB5, 1), false, true);
     887                            $thisfile_mpeg_audio_lame['mp3_gain_db']     = (getid3_lib::RGADamplitude2dB(2) / 4) * $thisfile_mpeg_audio_lame_raw['mp3_gain'];
     888                            $thisfile_mpeg_audio_lame['mp3_gain_factor'] = pow(2, ($thisfile_mpeg_audio_lame['mp3_gain_db'] / 6));
     889
     890                            // bytes $B6-$B7  Preset and surround info
     891                            $PresetSurroundBytes = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB6, 2));
     892                            // Reserved                                                    = ($PresetSurroundBytes & 0xC000);
     893                            $thisfile_mpeg_audio_lame_raw['surround_info'] = ($PresetSurroundBytes & 0x3800);
     894                            $thisfile_mpeg_audio_lame['surround_info']     = self::LAMEsurroundInfoLookup($thisfile_mpeg_audio_lame_raw['surround_info']);
     895                            $thisfile_mpeg_audio_lame['preset_used_id']    = ($PresetSurroundBytes & 0x07FF);
     896                            $thisfile_mpeg_audio_lame['preset_used']       = self::LAMEpresetUsedLookup($thisfile_mpeg_audio_lame);
     897                            if (!empty($thisfile_mpeg_audio_lame['preset_used_id']) && empty($thisfile_mpeg_audio_lame['preset_used'])) {
     898                                $this->warning('Unknown LAME preset used ('.$thisfile_mpeg_audio_lame['preset_used_id'].') - please report to info@getid3.org');
     899                            }
     900                            if (($thisfile_mpeg_audio_lame['short_version'] == 'LAME3.90.') && !empty($thisfile_mpeg_audio_lame['preset_used_id'])) {
     901                                // this may change if 3.90.4 ever comes out
     902                                $thisfile_mpeg_audio_lame['short_version'] = 'LAME3.90.3';
     903                            }
     904
     905                            // bytes $B8-$BB  MusicLength
     906                            $thisfile_mpeg_audio_lame['audio_bytes'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB8, 4));
     907                            $ExpectedNumberOfAudioBytes = (($thisfile_mpeg_audio_lame['audio_bytes'] > 0) ? $thisfile_mpeg_audio_lame['audio_bytes'] : $thisfile_mpeg_audio['VBR_bytes']);
     908
     909                            // bytes $BC-$BD  MusicCRC
     910                            $thisfile_mpeg_audio_lame['music_crc']    = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBC, 2));
     911
     912                            // bytes $BE-$BF  CRC-16 of Info Tag
     913                            $thisfile_mpeg_audio_lame['lame_tag_crc'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBE, 2));
     914
     915
     916                            // LAME CBR
     917                            if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) {
     918
     919                                $thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
     920                                $thisfile_mpeg_audio['bitrate'] = self::ClosestStandardMP3Bitrate($thisfile_mpeg_audio['bitrate']);
     921                                $info['audio']['bitrate'] = $thisfile_mpeg_audio['bitrate'];
     922                                //if (empty($thisfile_mpeg_audio['bitrate']) || (!empty($thisfile_mpeg_audio_lame['bitrate_min']) && ($thisfile_mpeg_audio_lame['bitrate_min'] != 255))) {
     923                                //  $thisfile_mpeg_audio['bitrate'] = $thisfile_mpeg_audio_lame['bitrate_min'];
     924                                //}
     925
     926                            }
     927
    792928                        }
    793 
    794                         $thisfile_mpeg_audio_lame_raw['RGAD_track']      =   getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAB, 2));
    795                         $thisfile_mpeg_audio_lame_raw['RGAD_album']      =   getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAD, 2));
    796 
    797 
    798                         if ($thisfile_mpeg_audio_lame_raw['RGAD_track'] != 0) {
    799 
    800                             $thisfile_mpeg_audio_lame_RGAD_track['raw']['name']        = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0xE000) >> 13;
    801                             $thisfile_mpeg_audio_lame_RGAD_track['raw']['originator']  = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x1C00) >> 10;
    802                             $thisfile_mpeg_audio_lame_RGAD_track['raw']['sign_bit']    = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x0200) >> 9;
    803                             $thisfile_mpeg_audio_lame_RGAD_track['raw']['gain_adjust'] =  $thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x01FF;
    804                             $thisfile_mpeg_audio_lame_RGAD_track['name']       = getid3_lib::RGADnameLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['name']);
    805                             $thisfile_mpeg_audio_lame_RGAD_track['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['originator']);
    806                             $thisfile_mpeg_audio_lame_RGAD_track['gain_db']    = getid3_lib::RGADadjustmentLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_RGAD_track['raw']['sign_bit']);
    807 
    808                             if (!empty($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'])) {
    809                                 $info['replay_gain']['track']['peak']   = $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'];
    810                             }
    811                             $info['replay_gain']['track']['originator'] = $thisfile_mpeg_audio_lame_RGAD_track['originator'];
    812                             $info['replay_gain']['track']['adjustment'] = $thisfile_mpeg_audio_lame_RGAD_track['gain_db'];
    813                         } else {
    814                             unset($thisfile_mpeg_audio_lame_RGAD['track']);
    815                         }
    816                         if ($thisfile_mpeg_audio_lame_raw['RGAD_album'] != 0) {
    817 
    818                             $thisfile_mpeg_audio_lame_RGAD_album['raw']['name']        = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0xE000) >> 13;
    819                             $thisfile_mpeg_audio_lame_RGAD_album['raw']['originator']  = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x1C00) >> 10;
    820                             $thisfile_mpeg_audio_lame_RGAD_album['raw']['sign_bit']    = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x0200) >> 9;
    821                             $thisfile_mpeg_audio_lame_RGAD_album['raw']['gain_adjust'] = $thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x01FF;
    822                             $thisfile_mpeg_audio_lame_RGAD_album['name']       = getid3_lib::RGADnameLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['name']);
    823                             $thisfile_mpeg_audio_lame_RGAD_album['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['originator']);
    824                             $thisfile_mpeg_audio_lame_RGAD_album['gain_db']    = getid3_lib::RGADadjustmentLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_RGAD_album['raw']['sign_bit']);
    825 
    826                             if (!empty($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'])) {
    827                                 $info['replay_gain']['album']['peak']   = $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'];
    828                             }
    829                             $info['replay_gain']['album']['originator'] = $thisfile_mpeg_audio_lame_RGAD_album['originator'];
    830                             $info['replay_gain']['album']['adjustment'] = $thisfile_mpeg_audio_lame_RGAD_album['gain_db'];
    831                         } else {
    832                             unset($thisfile_mpeg_audio_lame_RGAD['album']);
    833                         }
    834                         if (empty($thisfile_mpeg_audio_lame_RGAD)) {
    835                             unset($thisfile_mpeg_audio_lame['RGAD']);
    836                         }
    837 
    838 
    839                         // byte $AF  Encoding flags + ATH Type
    840                         $EncodingFlagsATHtype = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAF, 1));
    841                         $thisfile_mpeg_audio_lame['encoding_flags']['nspsytune']   = (bool) ($EncodingFlagsATHtype & 0x10);
    842                         $thisfile_mpeg_audio_lame['encoding_flags']['nssafejoint'] = (bool) ($EncodingFlagsATHtype & 0x20);
    843                         $thisfile_mpeg_audio_lame['encoding_flags']['nogap_next']  = (bool) ($EncodingFlagsATHtype & 0x40);
    844                         $thisfile_mpeg_audio_lame['encoding_flags']['nogap_prev']  = (bool) ($EncodingFlagsATHtype & 0x80);
    845                         $thisfile_mpeg_audio_lame['ath_type']                      =         $EncodingFlagsATHtype & 0x0F;
    846 
    847                         // byte $B0  if ABR {specified bitrate} else {minimal bitrate}
    848                         $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB0, 1));
    849                         if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 2) { // Average BitRate (ABR)
    850                             $thisfile_mpeg_audio_lame['bitrate_abr'] = $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'];
    851                         } elseif ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) { // Constant BitRate (CBR)
    852                             // ignore
    853                         } elseif ($thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] > 0) { // Variable BitRate (VBR) - minimum bitrate
    854                             $thisfile_mpeg_audio_lame['bitrate_min'] = $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'];
    855                         }
    856 
    857                         // bytes $B1-$B3  Encoder delays
    858                         $EncoderDelays = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB1, 3));
    859                         $thisfile_mpeg_audio_lame['encoder_delay'] = ($EncoderDelays & 0xFFF000) >> 12;
    860                         $thisfile_mpeg_audio_lame['end_padding']   =  $EncoderDelays & 0x000FFF;
    861 
    862                         // byte $B4  Misc
    863                         $MiscByte = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB4, 1));
    864                         $thisfile_mpeg_audio_lame_raw['noise_shaping']       = ($MiscByte & 0x03);
    865                         $thisfile_mpeg_audio_lame_raw['stereo_mode']         = ($MiscByte & 0x1C) >> 2;
    866                         $thisfile_mpeg_audio_lame_raw['not_optimal_quality'] = ($MiscByte & 0x20) >> 5;
    867                         $thisfile_mpeg_audio_lame_raw['source_sample_freq']  = ($MiscByte & 0xC0) >> 6;
    868                         $thisfile_mpeg_audio_lame['noise_shaping']       = $thisfile_mpeg_audio_lame_raw['noise_shaping'];
    869                         $thisfile_mpeg_audio_lame['stereo_mode']         = self::LAMEmiscStereoModeLookup($thisfile_mpeg_audio_lame_raw['stereo_mode']);
    870                         $thisfile_mpeg_audio_lame['not_optimal_quality'] = (bool) $thisfile_mpeg_audio_lame_raw['not_optimal_quality'];
    871                         $thisfile_mpeg_audio_lame['source_sample_freq']  = self::LAMEmiscSourceSampleFrequencyLookup($thisfile_mpeg_audio_lame_raw['source_sample_freq']);
    872 
    873                         // byte $B5  MP3 Gain
    874                         $thisfile_mpeg_audio_lame_raw['mp3_gain'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB5, 1), false, true);
    875                         $thisfile_mpeg_audio_lame['mp3_gain_db']     = (getid3_lib::RGADamplitude2dB(2) / 4) * $thisfile_mpeg_audio_lame_raw['mp3_gain'];
    876                         $thisfile_mpeg_audio_lame['mp3_gain_factor'] = pow(2, ($thisfile_mpeg_audio_lame['mp3_gain_db'] / 6));
    877 
    878                         // bytes $B6-$B7  Preset and surround info
    879                         $PresetSurroundBytes = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB6, 2));
    880                         // Reserved                                                    = ($PresetSurroundBytes & 0xC000);
    881                         $thisfile_mpeg_audio_lame_raw['surround_info'] = ($PresetSurroundBytes & 0x3800);
    882                         $thisfile_mpeg_audio_lame['surround_info']     = self::LAMEsurroundInfoLookup($thisfile_mpeg_audio_lame_raw['surround_info']);
    883                         $thisfile_mpeg_audio_lame['preset_used_id']    = ($PresetSurroundBytes & 0x07FF);
    884                         $thisfile_mpeg_audio_lame['preset_used']       = self::LAMEpresetUsedLookup($thisfile_mpeg_audio_lame);
    885                         if (!empty($thisfile_mpeg_audio_lame['preset_used_id']) && empty($thisfile_mpeg_audio_lame['preset_used'])) {
    886                             $this->warning('Unknown LAME preset used ('.$thisfile_mpeg_audio_lame['preset_used_id'].') - please report to info@getid3.org');
    887                         }
    888                         if (($thisfile_mpeg_audio_lame['short_version'] == 'LAME3.90.') && !empty($thisfile_mpeg_audio_lame['preset_used_id'])) {
    889                             // this may change if 3.90.4 ever comes out
    890                             $thisfile_mpeg_audio_lame['short_version'] = 'LAME3.90.3';
    891                         }
    892 
    893                         // bytes $B8-$BB  MusicLength
    894                         $thisfile_mpeg_audio_lame['audio_bytes'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB8, 4));
    895                         $ExpectedNumberOfAudioBytes = (($thisfile_mpeg_audio_lame['audio_bytes'] > 0) ? $thisfile_mpeg_audio_lame['audio_bytes'] : $thisfile_mpeg_audio['VBR_bytes']);
    896 
    897                         // bytes $BC-$BD  MusicCRC
    898                         $thisfile_mpeg_audio_lame['music_crc']    = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBC, 2));
    899 
    900                         // bytes $BE-$BF  CRC-16 of Info Tag
    901                         $thisfile_mpeg_audio_lame['lame_tag_crc'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBE, 2));
    902 
    903 
    904                         // LAME CBR
    905                         if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) {
    906 
    907                             $thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
    908                             $thisfile_mpeg_audio['bitrate'] = self::ClosestStandardMP3Bitrate($thisfile_mpeg_audio['bitrate']);
    909                             $info['audio']['bitrate'] = $thisfile_mpeg_audio['bitrate'];
    910                             //if (empty($thisfile_mpeg_audio['bitrate']) || (!empty($thisfile_mpeg_audio_lame['bitrate_min']) && ($thisfile_mpeg_audio_lame['bitrate_min'] != 255))) {
    911                             //  $thisfile_mpeg_audio['bitrate'] = $thisfile_mpeg_audio_lame['bitrate_min'];
    912                             //}
    913 
    914                         }
    915 
    916929                    }
    917930                }
     
    10091022            if (!$this->RecursiveFrameScanning($offset, $nextframetestoffset, $ScanAsCBR)) {
    10101023                return false;
     1024            }
     1025            if (!empty($this->getid3->info['mp3_validity_check_bitrates']) && !empty($thisfile_mpeg_audio['bitrate_mode']) && ($thisfile_mpeg_audio['bitrate_mode'] == 'vbr') && !empty($thisfile_mpeg_audio['VBR_bitrate'])) {
     1026                // https://github.com/JamesHeinrich/getID3/issues/287
     1027                if (count(array_keys($this->getid3->info['mp3_validity_check_bitrates'])) == 1) {
     1028                    list($cbr_bitrate_in_short_scan) = array_keys($this->getid3->info['mp3_validity_check_bitrates']);
     1029                    $deviation_cbr_from_header_bitrate = abs($thisfile_mpeg_audio['VBR_bitrate'] - $cbr_bitrate_in_short_scan) / $cbr_bitrate_in_short_scan;
     1030                    if ($deviation_cbr_from_header_bitrate < 0.01) {
     1031                        // VBR header bitrate may differ slightly from true bitrate of frames, perhaps accounting for overhead of VBR header frame itself?
     1032                        // If measured CBR bitrate is within 1% of specified bitrate in VBR header then assume that file is truly CBR
     1033                        $thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
     1034                        //$this->warning('VBR header ignored, assuming CBR '.round($cbr_bitrate_in_short_scan / 1000).'kbps based on scan of '.$this->mp3_valid_check_frames.' frames');
     1035                    }
     1036                }
     1037            }
     1038            if (isset($this->getid3->info['mp3_validity_check_bitrates'])) {
     1039                unset($this->getid3->info['mp3_validity_check_bitrates']);
    10111040            }
    10121041
     
    11311160        $this->decodeMPEGaudioHeader($offset, $firstframetestarray, false);
    11321161
    1133         for ($i = 0; $i < GETID3_MP3_VALID_CHECK_FRAMES; $i++) {
    1134             // check next GETID3_MP3_VALID_CHECK_FRAMES frames for validity, to make sure we haven't run across a false synch
     1162        $info['mp3_validity_check_bitrates'] = array();
     1163        for ($i = 0; $i < $this->mp3_valid_check_frames; $i++) {
     1164            // check next (default: 50) frames for validity, to make sure we haven't run across a false synch
    11351165            if (($nextframetestoffset + 4) >= $info['avdataend']) {
    11361166                // end of file
     
    11401170            $nextframetestarray = array('error' => array(), 'warning' => array(), 'avdataend' => $info['avdataend'], 'avdataoffset'=>$info['avdataoffset']);
    11411171            if ($this->decodeMPEGaudioHeader($nextframetestoffset, $nextframetestarray, false)) {
     1172                getid3_lib::safe_inc($info['mp3_validity_check_bitrates'][$nextframetestarray['mpeg']['audio']['bitrate']]);
    11421173                if ($ScanAsCBR) {
    11431174                    // force CBR mode, used for trying to pick out invalid audio streams with valid(?) VBR headers, or VBR streams with no VBR header
     
    12741305        $LongMPEGpaddingLookup        = array();
    12751306        $LongMPEGfrequencyLookup      = array();
     1307        $Distribution                 = array();
    12761308        $Distribution['bitrate']      = array();
    12771309        $Distribution['frequency']    = array();
     
    14341466        $sync_seek_buffer_size = strlen($header);
    14351467        $SynchSeekOffset = 0;
     1468        $SyncSeekAttempts = 0;
     1469        $SyncSeekAttemptsMax = 1000;
     1470        $FirstFrameThisfileInfo = null;
    14361471        while ($SynchSeekOffset < $sync_seek_buffer_size) {
    14371472            if ((($avdataoffset + $SynchSeekOffset)  < $info['avdataend']) && !feof($this->getid3->fp)) {
     
    14721507            }
    14731508
    1474             if (($header[$SynchSeekOffset] == "\xFF") && ($header[($SynchSeekOffset + 1)] > "\xE0")) { // synch detected
     1509            if (($header[$SynchSeekOffset] == "\xFF") && ($header[($SynchSeekOffset + 1)] > "\xE0")) { // possible synch detected
     1510                if (++$SyncSeekAttempts >= $SyncSeekAttemptsMax) {
     1511                    // https://github.com/JamesHeinrich/getID3/issues/286
     1512                    // corrupt files claiming to be MP3, with a large number of 0xFF bytes near the beginning, can cause this loop to take a very long time
     1513                    // should have escape condition to avoid spending too much time scanning a corrupt file
     1514                    // if a synch's not found within the first 128k bytes, then give up
     1515                    $this->error('Could not find valid MPEG audio synch after scanning '.$SyncSeekAttempts.' candidate offsets');
     1516                    if (isset($info['audio']['bitrate'])) {
     1517                        unset($info['audio']['bitrate']);
     1518                    }
     1519                    if (isset($info['mpeg']['audio'])) {
     1520                        unset($info['mpeg']['audio']);
     1521                    }
     1522                    if (empty($info['mpeg'])) {
     1523                        unset($info['mpeg']);
     1524                    }
     1525                    return false;
     1526                }
    14751527                $FirstFrameAVDataOffset = null;
    14761528                if (!isset($FirstFrameThisfileInfo) && !isset($info['mpeg']['audio'])) {
     
    15121564                                $info = $dummy;
    15131565                                $info['avdataoffset'] = $GarbageOffsetEnd;
    1514                                 $this->warning('apparently-valid VBR header not used because could not find '.GETID3_MP3_VALID_CHECK_FRAMES.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.'), but did find valid CBR stream starting at '.$GarbageOffsetEnd);
     1566                                $this->warning('apparently-valid VBR header not used because could not find '.$this->mp3_valid_check_frames.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.'), but did find valid CBR stream starting at '.$GarbageOffsetEnd);
    15151567                            } else {
    1516                                 $this->warning('using data from VBR header even though could not find '.GETID3_MP3_VALID_CHECK_FRAMES.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.')');
     1568                                $this->warning('using data from VBR header even though could not find '.$this->mp3_valid_check_frames.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.')');
    15171569                            }
    15181570                        }
     
    15591611                        for ($current_segment = 0; $current_segment < $max_scan_segments; $current_segment++) {
    15601612                            $frames_scanned_this_segment = 0;
     1613                            $scan_start_offset = array();
    15611614                            if ($this->ftell() >= $info['avdataend']) {
    15621615                                break;
     
    18881941        }
    18891942
     1943        $MPEGrawHeader = array();
    18901944        $MPEGrawHeader['synch']         = (getid3_lib::BigEndian2Int(substr($Header4Bytes, 0, 2)) & 0xFFE0) >> 4;
    18911945        $MPEGrawHeader['version']       = (ord($Header4Bytes[1]) & 0x18) >> 3; //    BB
  • trunk/src/wp-includes/ID3/module.audio.ogg.php

    r51901 r52254  
    530530    public function ParseOggPageHeader() {
    531531        // http://xiph.org/ogg/vorbis/doc/framing.html
     532        $oggheader = array();
    532533        $oggheader['page_start_offset'] = $this->ftell(); // where we started from in the file
    533534
     
    681682                $VorbisCommentPage++;
    682683
    683                 $oggpageinfo = $this->ParseOggPageHeader();
    684                 $info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
    685 
    686                 // First, save what we haven't read yet
    687                 $AsYetUnusedData = substr($commentdata, $commentdataoffset);
    688 
    689                 // Then take that data off the end
    690                 $commentdata     = substr($commentdata, 0, $commentdataoffset);
    691 
    692                 // Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct
    693                 $commentdata .= str_repeat("\x00", 27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
    694                 $commentdataoffset += (27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
    695 
    696                 // Finally, stick the unused data back on the end
    697                 $commentdata .= $AsYetUnusedData;
    698 
    699                 //$commentdata .= $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
    700                 if (!isset($info['ogg']['pageheader'][$VorbisCommentPage])) {
    701                     $this->warning('undefined Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell());
     684                if ($oggpageinfo = $this->ParseOggPageHeader()) {
     685                    $info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
     686
     687                    // First, save what we haven't read yet
     688                    $AsYetUnusedData = substr($commentdata, $commentdataoffset);
     689
     690                    // Then take that data off the end
     691                    $commentdata     = substr($commentdata, 0, $commentdataoffset);
     692
     693                    // Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct
     694                    $commentdata .= str_repeat("\x00", 27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
     695                    $commentdataoffset += (27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
     696
     697                    // Finally, stick the unused data back on the end
     698                    $commentdata .= $AsYetUnusedData;
     699
     700                    //$commentdata .= $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
     701                    if (!isset($info['ogg']['pageheader'][$VorbisCommentPage])) {
     702                        $this->warning('undefined Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell());
     703                        break;
     704                    }
     705                    $readlength = self::OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1);
     706                    if ($readlength <= 0) {
     707                        $this->warning('invalid length Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell());
     708                        break;
     709                    }
     710                    $commentdata .= $this->fread($readlength);
     711
     712                    //$filebaseoffset += $oggpageinfo['header_end_offset'] - $oggpageinfo['page_start_offset'];
     713                } else {
     714                    $this->warning('failed to ParseOggPageHeader() at offset '.$this->ftell());
    702715                    break;
    703716                }
    704                 $readlength = self::OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1);
    705                 if ($readlength <= 0) {
    706                     $this->warning('invalid length Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell());
    707                     break;
    708                 }
    709                 $commentdata .= $this->fread($readlength);
    710 
    711                 //$filebaseoffset += $oggpageinfo['header_end_offset'] - $oggpageinfo['page_start_offset'];
    712717            }
    713718            $ThisFileInfo_ogg_comments_raw[$i]['offset'] = $commentdataoffset;
  • trunk/src/wp-includes/ID3/module.tag.apetag.php

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

    r51901 r52254  
    3232        }
    3333
    34         $this->fseek(-256, SEEK_END);
    35         $preid3v1 = $this->fread(128);
    36         $id3v1tag = $this->fread(128);
     34        if($info['filesize'] < 256) {
     35            $this->fseek(-128, SEEK_END);
     36            $preid3v1 = '';
     37            $id3v1tag = $this->fread(128);
     38        } else {
     39            $this->fseek(-256, SEEK_END);
     40            $preid3v1 = $this->fread(128);
     41            $id3v1tag = $this->fread(128);
     42        }
     43
    3744
    3845        if (substr($id3v1tag, 0, 3) == 'TAG') {
     
    4047            $info['avdataend'] = $info['filesize'] - 128;
    4148
     49            $ParsedID3v1            = array();
    4250            $ParsedID3v1['title']   = $this->cutfield(substr($id3v1tag,   3, 30));
    4351            $ParsedID3v1['artist']  = $this->cutfield(substr($id3v1tag,  33, 30));
     
    298306            146  => 'JPop',
    299307            147  => 'Synthpop',
     308            148 => 'Abstract',
     309            149 => 'Art Rock',
     310            150 => 'Baroque',
     311            151 => 'Bhangra',
     312            152 => 'Big Beat',
     313            153 => 'Breakbeat',
     314            154 => 'Chillout',
     315            155 => 'Downtempo',
     316            156 => 'Dub',
     317            157 => 'EBM',
     318            158 => 'Eclectic',
     319            159 => 'Electro',
     320            160 => 'Electroclash',
     321            161 => 'Emo',
     322            162 => 'Experimental',
     323            163 => 'Garage',
     324            164 => 'Global',
     325            165 => 'IDM',
     326            166 => 'Illbient',
     327            167 => 'Industro-Goth',
     328            168 => 'Jam Band',
     329            169 => 'Krautrock',
     330            170 => 'Leftfield',
     331            171 => 'Lounge',
     332            172 => 'Math Rock',
     333            173 => 'New Romantic',
     334            174 => 'Nu-Breakz',
     335            175 => 'Post-Punk',
     336            176 => 'Post-Rock',
     337            177 => 'Psytrance',
     338            178 => 'Shoegaze',
     339            179 => 'Space Rock',
     340            180 => 'Trop Rock',
     341            181 => 'World Music',
     342            182 => 'Neoclassical',
     343            183 => 'Audiobook',
     344            184 => 'Audio Theatre',
     345            185 => 'Neue Deutsche Welle',
     346            186 => 'Podcast',
     347            187 => 'Indie-Rock',
     348            188 => 'G-Funk',
     349            189 => 'Dubstep',
     350            190 => 'Garage Rock',
     351            191 => 'Psybient',
    300352
    301353            255  => 'Unknown',
  • trunk/src/wp-includes/ID3/module.tag.id3v2.php

    r51901 r52254  
    346346                if (($frame_size <= strlen($framedata)) && ($this->IsValidID3v2FrameName($frame_name, $id3v2_majorversion))) {
    347347
    348                     unset($parsedFrame);
     348                    $parsedFrame                    = array();
    349349                    $parsedFrame['frame_name']      = $frame_name;
    350350                    $parsedFrame['frame_flags_raw'] = $frame_flags;
     
    979979
    980980        } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'USLT')) || // 4.8   USLT Unsynchronised lyric/text transcription
    981                 (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'ULT'))) {     // 4.9   ULT  Unsynchronised lyric/text transcription
     981                (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'ULT'))) {    // 4.9   ULT  Unsynchronised lyric/text transcription
    982982            //   There may be more than one 'Unsynchronised lyrics/text transcription' frame
    983983            //   in each tag, but only one with the same language and content descriptor.
     
    995995                $frame_textencoding_terminator = "\x00";
    996996            }
    997             $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
    998             $frame_offset += 3;
    999             $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
    1000             if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
    1001                 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
    1002             }
    1003             $parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
    1004             $parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']);
    1005             $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
    1006             $parsedFrame['data'] = $this->RemoveStringTerminator($parsedFrame['data'], $frame_textencoding_terminator);
    1007 
    1008             $parsedFrame['encodingid']   = $frame_textencoding;
    1009             $parsedFrame['encoding']     = $this->TextEncodingNameLookup($frame_textencoding);
    1010 
    1011             $parsedFrame['language']     = $frame_language;
    1012             $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
    1013             if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
    1014                 $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
     997            if (strlen($parsedFrame['data']) >= (4 + strlen($frame_textencoding_terminator))) {  // shouldn't be an issue but badly-written files have been spotted in the wild with not only no contents but also missing the required language field, see https://github.com/JamesHeinrich/getID3/issues/315
     998                $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
     999                $frame_offset += 3;
     1000                $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
     1001                if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
     1002                    $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
     1003                }
     1004                $parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
     1005                $parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']);
     1006                $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
     1007                $parsedFrame['data'] = $this->RemoveStringTerminator($parsedFrame['data'], $frame_textencoding_terminator);
     1008
     1009                $parsedFrame['encodingid']   = $frame_textencoding;
     1010                $parsedFrame['encoding']     = $this->TextEncodingNameLookup($frame_textencoding);
     1011
     1012                $parsedFrame['language']     = $frame_language;
     1013                $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
     1014                if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
     1015                    $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
     1016                }
     1017            } else {
     1018                $this->warning('Invalid data in frame "'.$parsedFrame['frame_name'].'" at offset '.$parsedFrame['dataoffset']);
    10151019            }
    10161020            unset($parsedFrame['data']);
     
    13711375            }
    13721376
     1377            $frame_imagetype = null;
     1378            $frame_mimetype = null;
    13731379            if ($id3v2_majorversion == 2 && strlen($parsedFrame['data']) > $frame_offset) {
    13741380                $frame_imagetype = substr($parsedFrame['data'], $frame_offset, 3);
     
    19571963            $parsedFrame['peakamplitude'] = getid3_lib::BigEndian2Float(substr($parsedFrame['data'], $frame_offset, 4));
    19581964            $frame_offset += 4;
    1959             $rg_track_adjustment = getid3_lib::Dec2Bin(substr($parsedFrame['data'], $frame_offset, 2));
    1960             $frame_offset += 2;
    1961             $rg_album_adjustment = getid3_lib::Dec2Bin(substr($parsedFrame['data'], $frame_offset, 2));
    1962             $frame_offset += 2;
    1963             $parsedFrame['raw']['track']['name']       = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 0, 3));
    1964             $parsedFrame['raw']['track']['originator'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 3, 3));
    1965             $parsedFrame['raw']['track']['signbit']    = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 6, 1));
    1966             $parsedFrame['raw']['track']['adjustment'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 7, 9));
    1967             $parsedFrame['raw']['album']['name']       = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 0, 3));
    1968             $parsedFrame['raw']['album']['originator'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 3, 3));
    1969             $parsedFrame['raw']['album']['signbit']    = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 6, 1));
    1970             $parsedFrame['raw']['album']['adjustment'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 7, 9));
     1965            foreach (array('track','album') as $rgad_entry_type) {
     1966                $rg_adjustment_word = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
     1967                $frame_offset += 2;
     1968                $parsedFrame['raw'][$rgad_entry_type]['name']       = ($rg_adjustment_word & 0xE000) >> 13;
     1969                $parsedFrame['raw'][$rgad_entry_type]['originator'] = ($rg_adjustment_word & 0x1C00) >> 10;
     1970                $parsedFrame['raw'][$rgad_entry_type]['signbit']    = ($rg_adjustment_word & 0x0200) >>  9;
     1971                $parsedFrame['raw'][$rgad_entry_type]['adjustment'] = ($rg_adjustment_word & 0x0100);
     1972            }
    19711973            $parsedFrame['track']['name']       = getid3_lib::RGADnameLookup($parsedFrame['raw']['track']['name']);
    19721974            $parsedFrame['track']['originator'] = getid3_lib::RGADoriginatorLookup($parsedFrame['raw']['track']['originator']);
     
    24452447            TND Dinars
    24462448            TOP Pa'anga
    2447             TRL Liras
     2449            TRL Liras (old)
     2450            TRY Liras
    24482451            TTD Dollars
    24492452            TVD Tuvalu Dollars
     
    26462649            TOP Tonga
    26472650            TRL Turkey
     2651            TRY Turkey
    26482652            TTD Trinidad and Tobago
    26492653            TVD Tuvalu
  • trunk/src/wp-includes/ID3/module.tag.lyrics3.php

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

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