Changeset 62460 in spip-zone


Ignore:
Timestamp:
Jun 13, 2012, 10:35:52 AM (7 years ago)
Author:
kent1@…
Message:

Update de la lib getID3 en 1.9.3

Location:
_plugins_/getID3/trunk/getid3
Files:
1 added
18 edited

Legend:

Unmodified
Added
Removed
  • _plugins_/getID3/trunk/getid3/extension.cache.dbm.php

    r51852 r62460  
    121121
    122122                        // Insert getID3 version number
    123                         dba_insert($this::VERSION, $this::VERSION, $this->dba);
     123                        dba_insert(getID3::VERSION, getID3::VERSION, $this->dba);
    124124                }
    125125
     
    132132
    133133                // Check version number and clear cache if changed
    134                 if (dba_fetch($this::VERSION, $this->dba) != $this::VERSION) {
     134                if (dba_fetch(getID3::VERSION, $this->dba) != getID3::VERSION) {
    135135                        $this->clear_cache();
    136136                }
     
    170170
    171171                // Insert getID3 version number
    172                 dba_insert($this::VERSION, $this::VERSION, $this->dba);
     172                dba_insert(getID3::VERSION, getID3::VERSION, $this->dba);
    173173
    174174                // Re-register shutdown function
  • _plugins_/getID3/trunk/getid3/extension.cache.mysql.php

    r51852 r62460  
    1212//                                                             //
    1313// This extension written by Allan Hansen <ahØartemis*dk>      //
     14// Table name mod by Carlo Capocasa <calroØcarlocapocasa*com>  //
    1415//                                                            ///
    1516/////////////////////////////////////////////////////////////////
     
    3435*       require_once 'getid3/getid3.php';
    3536*       require_once 'getid3/getid3/extension.cache.mysql.php';
    36 *       $getID3 = new getID3_cached_mysql('localhost', 'database',
    37 *                                         'username', 'password');
     37*       // 5th parameter (tablename) is optional, default is 'getid3_cache'
     38*       $getID3 = new getID3_cached_mysql('localhost', 'database', 'username', 'password', 'tablename');
    3839*       $getID3->encoding = 'UTF-8';
    3940*       $info1 = $getID3->analyze('file1.flac');
     
    7980
    8081        // public: constructor - see top of this file for cache type and cache_options
    81         function getID3_cached_mysql($host, $database, $username, $password) {
     82        function getID3_cached_mysql($host, $database, $username, $password, $table='getid3_cache') {
    8283
    8384                // Check for mysql support
     
    9798                }
    9899
     100                // Set table
     101                $this->table = $table;
     102
    99103                // Create cache table if not exists
    100104                $this->create_table();
     
    102106                // Check version number and clear cache if changed
    103107                $version = '';
    104                 if ($this->cursor = mysql_query("SELECT `value` FROM `getid3_cache` WHERE (`filename` = '".mysql_real_escape_string($this::VERSION)."') AND (`filesize` = '-1') AND (`filetime` = '-1') AND (`analyzetime` = '-1')", $this->connection)) {
     108                if ($this->cursor = mysql_query("SELECT `value` FROM `".mysql_real_escape_string($this->table)."` WHERE (`filename` = '".mysql_real_escape_string(getID3::VERSION)."') AND (`filesize` = '-1') AND (`filetime` = '-1') AND (`analyzetime` = '-1')", $this->connection)) {
    105109                        list($version) = mysql_fetch_array($this->cursor);
    106110                }
    107                 if ($version != $this::VERSION) {
     111                if ($version != getID3::VERSION) {
    108112                        $this->clear_cache();
    109113                }
     
    117121        function clear_cache() {
    118122
    119                 $this->cursor = mysql_query("DELETE FROM `getid3_cache`", $this->connection);
    120                 $this->cursor = mysql_query("INSERT INTO `getid3_cache` VALUES ('".$this::VERSION."', -1, -1, -1, '".$this::VERSION."')", $this->connection);
     123                $this->cursor = mysql_query("DELETE FROM `".mysql_real_escape_string($this->table)."`", $this->connection);
     124                $this->cursor = mysql_query("INSERT INTO `".mysql_real_escape_string($this->table)."` VALUES ('".getID3::VERSION."', -1, -1, -1, '".getID3::VERSION."')", $this->connection);
    121125        }
    122126
     
    132136                        $filesize = filesize($filename);
    133137
    134                         // Loopup file
    135                         $result = '';
    136                         if ($this->cursor = mysql_query("SELECT `value` FROM `getid3_cache` WHERE (`filename` = '".mysql_real_escape_string($filename)."') AND (`filesize` = '".mysql_real_escape_string($filesize)."') AND (`filetime` = '".mysql_real_escape_string($filetime)."')", $this->connection)) {
     138                        // Lookup file
     139                        $this->cursor = mysql_query("SELECT `value` FROM `".mysql_real_escape_string($this->table)."` WHERE (`filename` = '".mysql_real_escape_string($filename)."') AND (`filesize` = '".mysql_real_escape_string($filesize)."') AND (`filetime` = '".mysql_real_escape_string($filetime)."')", $this->connection);
     140                        if (mysql_num_rows($this->cursor) > 0) {
    137141                                // Hit
    138142                                list($result) = mysql_fetch_array($this->cursor);
     
    146150                // Save result
    147151                if (file_exists($filename)) {
    148                         $this->cursor = mysql_query("INSERT INTO `getid3_cache` (`filename`, `filesize`, `filetime`, `analyzetime`, `value`) VALUES ('".mysql_real_escape_string($filename)."', '".mysql_real_escape_string($filesize)."', '".mysql_real_escape_string($filetime)."', '".mysql_real_escape_string(time())."', '".mysql_real_escape_string(base64_encode(serialize($analysis)))."')", $this->connection);
     152                        $this->cursor = mysql_query("INSERT INTO `".mysql_real_escape_string($this->table)."` (`filename`, `filesize`, `filetime`, `analyzetime`, `value`) VALUES ('".mysql_real_escape_string($filename)."', '".mysql_real_escape_string($filesize)."', '".mysql_real_escape_string($filetime)."', '".mysql_real_escape_string(time())."', '".mysql_real_escape_string(base64_encode(serialize($analysis)))."')", $this->connection);
    149153                }
    150                 return $result;
     154                return $analysis;
    151155        }
    152156
     
    156160        function create_table($drop=false) {
    157161
    158                 $this->cursor = mysql_query("CREATE TABLE IF NOT EXISTS `getid3_cache` (
     162                $this->cursor = mysql_query("CREATE TABLE IF NOT EXISTS `".mysql_real_escape_string($this->table)."` (
    159163                        `filename` VARCHAR(255) NOT NULL DEFAULT '',
    160164                        `filesize` INT(11) NOT NULL DEFAULT '0',
     
    167171}
    168172
    169 
    170173?>
  • _plugins_/getID3/trunk/getid3/getid3.lib.php

    r51852 r62460  
    1515{
    1616
    17         static function PrintHexBytes($string, $hex=true, $spaces=true, $htmlsafe=true) {
     17        static function PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8') {
    1818                $returnstring = '';
    1919                for ($i = 0; $i < strlen($string); $i++) {
     
    2727                        }
    2828                }
    29                 if ($htmlsafe) {
    30                         $returnstring = htmlentities($returnstring);
     29                if (!empty($htmlencoding)) {
     30                        if ($htmlencoding === true) {
     31                                $htmlencoding = 'UTF-8'; // prior to getID3 v1.9.0 the function's 4th parameter was boolean
     32                        }
     33                        $returnstring = htmlentities($returnstring, ENT_QUOTES, $htmlencoding);
    3134                }
    3235                return $returnstring;
     
    439442
    440443
    441         static function PlaytimeString($playtimeseconds) {
    442                 $sign = (($playtimeseconds < 0) ? '-' : '');
    443                 $playtimeseconds = abs($playtimeseconds);
    444                 $contentseconds = round((($playtimeseconds / 60) - floor($playtimeseconds / 60)) * 60);
    445                 $contentminutes = floor($playtimeseconds / 60);
    446                 if ($contentseconds >= 60) {
    447                         $contentseconds -= 60;
    448                         $contentminutes++;
    449                 }
    450                 return $sign.intval($contentminutes).':'.str_pad($contentseconds, 2, 0, STR_PAD_LEFT);
     444        static function PlaytimeString($seconds) {
     445                $sign = (($seconds < 0) ? '-' : '');
     446                $seconds = abs($seconds);
     447                $H = floor( $seconds                            / 3600);
     448                $M = floor(($seconds - (3600 * $H)            ) /   60);
     449                $S = round( $seconds - (3600 * $H) - (60 * $M)        );
     450                return $sign.($H ? $H.':' : '').($H ? str_pad($M, 2, '0', STR_PAD_LEFT) : intval($M)).':'.str_pad($S, 2, 0, STR_PAD_LEFT);
    451451        }
    452452
     
    521521        }
    522522
     523        static function XML2array($XMLstring) {
     524                if (function_exists('simplexml_load_string')) {
     525                        if (function_exists('get_object_vars')) {
     526                                $XMLobject = simplexml_load_string($XMLstring);
     527                                return self::SimpleXMLelement2array($XMLobject);
     528                        }
     529                }
     530                return false;
     531        }
     532
     533        static function SimpleXMLelement2array($XMLobject) {
     534                if (!is_object($XMLobject) && !is_array($XMLobject)) {
     535                        return $XMLobject;
     536                }
     537                $XMLarray = (is_object($XMLobject) ? get_object_vars($XMLobject) : $XMLobject);
     538                foreach ($XMLarray as $key => $value) {
     539                        $XMLarray[$key] = self::SimpleXMLelement2array($value);
     540                }
     541                return $XMLarray;
     542        }
     543
    523544
    524545        // Allan Hansen <ahØartemis*dk>
     
    615636                }
    616637                if (is_readable($filename_source) && is_file($filename_source) && ($fp_src = fopen($filename_source, 'rb'))) {
    617                         if (is_writable($filename_dest) && is_file($filename_dest) && ($fp_dest = fopen($filename_dest, 'wb'))) {
     638                        if (($fp_dest = fopen($filename_dest, 'wb'))) {
    618639                                if (fseek($fp_src, $offset, SEEK_SET) == 0) {
    619640                                        $byteslefttowrite = $length;
    620                                         while (($byteslefttowrite > 0) && ($buffer = fread($fp_src, min($byteslefttowrite, $this->getid3->fread_buffer_size())))) {
     641                                        while (($byteslefttowrite > 0) && ($buffer = fread($fp_src, min($byteslefttowrite, getID3::FREAD_BUFFER_SIZE)))) {
    621642                                                $byteswritten = fwrite($fp_dest, $buffer, $byteslefttowrite);
    622643                                                $byteslefttowrite -= $byteswritten;
     
    624645                                        return true;
    625646                                } else {
    626                                         throw new Exception('failed to seek to offset '.$offset.' in '.$this->info['filenamepath']);
     647                                        throw new Exception('failed to seek to offset '.$offset.' in '.$filename_source);
    627648                                }
    628649                                fclose($fp_dest);
    629650                        } else {
    630                                 throw new Exception('failed to open file for reading '.$this->info['filenamepath']);
     651                                throw new Exception('failed to create file for writing '.$filename_dest);
    631652                        }
    632653                        fclose($fp_src);
    633654                } else {
    634                         throw new Exception('failed to create file for writing '.$dest);
     655                        throw new Exception('failed to open file for reading '.$filename_source);
    635656                }
    636657                return false;
     
    12881309        }
    12891310
     1311        public static function trimNullByte($string) {
     1312                return trim($string, "\x00");
     1313        }
     1314
    12901315}
    12911316
  • _plugins_/getID3/trunk/getid3/getid3.php

    r51852 r62460  
    7878{
    7979        // public: Settings
    80         public $encoding        = 'ISO-8859-1';   // CASE SENSITIVE! - i.e. (must be supported by iconv()). Examples:  ISO-8859-1  UTF-8  UTF-16  UTF-16BE
    81         public $encoding_id3v1  = 'ISO-8859-1';   // Should always be 'ISO-8859-1', but some tags may be written in other encodings such as 'EUC-CN'
     80        public $encoding        = 'UTF-8';        // CASE SENSITIVE! - i.e. (must be supported by iconv()). Examples:  ISO-8859-1  UTF-8  UTF-16  UTF-16BE
     81        public $encoding_id3v1  = 'ISO-8859-1';   // Should always be 'ISO-8859-1', but some tags may be written in other encodings such as 'EUC-CN' or 'CP1252'
    8282
    8383        // public: Optional tag checks - disable for speed.
     
    101101        public $option_max_2gb_check     = null;  // Check whether file is larger than 2GB and thus not supported by 32-bit PHP (null: auto-detect based on PHP_INT_MAX)
    102102
     103        // public: Read buffer size in bytes
     104        public $option_fread_buffer_size = 32768;
     105
    103106        // Public variables
    104107        public $filename;                         // Filename of file being analysed.
     
    111114        protected $memory_limit    = 0;
    112115
    113         const VERSION           = '1.9.0-20110620';
    114         const FREAD_BUFFER_SIZE = 32768;            // Read buffer size in bytes.
     116        const VERSION           = '1.9.3-20111213';
     117        const FREAD_BUFFER_SIZE = 32768;
    115118        var $tempdir            = GETID3_TEMP_DIR;
    116119
     
    119122
    120123        // public: constructor
    121         function getID3() {
     124        public function __construct() {
    122125
    123126                // Check for PHP version
    124127                $required_php_version = '5.0.5';
    125                 if (!function_exists('version_compare') || version_compare(PHP_VERSION, $required_php_version, '<')) {
    126                         // version_compare not available before PHP v4.1.0, so don't use for first version checking
     128                if (version_compare(PHP_VERSION, $required_php_version, '<')) {
    127129                        $this->startup_error .= 'getID3() requires PHP v'.$required_php_version.' or higher - you are running v'.PHP_VERSION;
    128130                        return false;
     
    154156                        $this->warning('WARNING: php.ini contains "mbstring.func_overload = '.ini_get('mbstring.func_overload').'", this may break things.');
    155157                }
    156 
    157                 /*
    158                 // Check timezone config setting
    159                 // this is needed to prevent E_STRICT warnings with any time/date functions
    160                 if (!ini_get('date.timezone')) {
    161                         if (function_exists('date_default_timezone_set')) { // exists since PHP v5.1.0
    162                                 $this->warning('php.ini should have "date.timezone" set, but it does not. Setting timezone to "'.date_default_timezone_get().'"');
    163                                 date_default_timezone_set(date_default_timezone_get());
    164                         } else {
    165                                 $this->warning('php.ini should have "date.timezone" set, but it does not.');
    166                         }
    167                 }
    168                 */
    169158
    170159                // Check for magic_quotes_runtime
     
    236225        }
    237226
    238         function version() {
    239                 $version = getID3::VERSION;
    240                 if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
    241                         // can't use this syntax, even conditionally, since it registers as a parse error before PHP v5.3.0
    242                         // wrapping the new syntax in an eval call should work without causing parse errors in old PHP
    243                         // return $this::VERSION;
    244                         eval('$version = $this::VERSION;');
    245                 }
    246                 return $version;
    247         }
    248         function fread_buffer_size() {
    249                 $fread_buffer_size = getID3::FREAD_BUFFER_SIZE;
    250                 if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
    251                         // can't use this syntax, even conditionally, since it registers as a parse error before PHP v5.3.0
    252                         // wrapping the new syntax in an eval call should work without causing parse errors in old PHP
    253                         // return $this::VERSION;
    254                         eval('$fread_buffer_size = $this::FREAD_BUFFER_SIZE;');
    255                 }
    256                 return $fread_buffer_size;
     227        public function version() {
     228                return self::VERSION;
     229        }
     230
     231        public function fread_buffer_size() {
     232                return $this->option_fread_buffer_size;
    257233        }
    258234
     
    273249
    274250
    275         function openfile($filename) {
     251        public function openfile($filename) {
    276252                try {
    277253                        if (!empty($this->startup_error)) {
    278                                 return $this->error($this->startup_error);
     254                                throw new getid3_exception($this->startup_error);
    279255                        }
    280256                        if (!empty($this->startup_warning)) {
     
    285261                        $this->filename = $filename;
    286262                        $this->info = array();
    287                         $this->info['GETID3_VERSION'] = $this->version();
     263                        $this->info['GETID3_VERSION']   = $this->version();
    288264                        $this->info['php_memory_limit'] = $this->memory_limit;
    289265
    290266                        // remote files not supported
    291267                        if (preg_match('/^(ht|f)tp:\/\//', $filename)) {
    292                                 return $this->error('Remote files are not supported - please copy the file locally first');
     268                                throw new getid3_exception('Remote files are not supported - please copy the file locally first');
    293269                        }
    294270
     
    300276                                // great
    301277                        } else {
    302                                 return $this->error('Could not open "'.$filename.'" (does not exist, or is not a file)');
     278                                throw new getid3_exception('Could not open "'.$filename.'" (does not exist, or is not a file)');
    303279                        }
    304280
    305281                        $this->info['filesize'] = filesize($filename);
    306282                        // set redundant parameters - might be needed in some include file
    307                         $this->info['filename']            = basename($filename);
    308                         $this->info['filepath']            = str_replace('\\', '/', realpath(dirname($filename)));
    309                         $this->info['filenamepath']        = $this->info['filepath'].'/'.$this->info['filename'];
     283                        $this->info['filename']     = basename($filename);
     284                        $this->info['filepath']     = str_replace('\\', '/', realpath(dirname($filename)));
     285                        $this->info['filenamepath'] = $this->info['filepath'].'/'.$this->info['filename'];
    310286
    311287
     
    336312                                                        unset($this->info['filesize']);
    337313                                                        fclose($this->fp);
    338                                                         return $this->error('Unable to determine actual filesize. File is most likely larger than '.round(PHP_INT_MAX / 1073741824).'GB and is not supported by PHP.');
     314                                                        throw new getid3_exception('Unable to determine actual filesize. File is most likely larger than '.round(PHP_INT_MAX / 1073741824).'GB and is not supported by PHP.');
    339315                                                } elseif (getid3_lib::intValueSupported($real_filesize)) {
    340316                                                        unset($this->info['filesize']);
    341317                                                        fclose($this->fp);
    342                                                         return $this->error('PHP seems to think the file is larger than '.round(PHP_INT_MAX / 1073741824).'GB, but filesystem reports it as '.number_format($real_filesize, 3).'GB, please report to info@getid3.org');
     318                                                        throw new getid3_exception('PHP seems to think the file is larger than '.round(PHP_INT_MAX / 1073741824).'GB, but filesystem reports it as '.number_format($real_filesize, 3).'GB, please report to info@getid3.org');
    343319                                                }
    344320                                                $this->info['filesize'] = $real_filesize;
     
    359335                        $this->info['encoding']            = $this->encoding;   // required by id3v2 and iso modules - can be unset at the end if desired
    360336
     337                        return true;
     338
    361339                } catch (Exception $e) {
    362                         if (isset($this->info['error'])) {
    363                                 $this->info['error'][] = 'Caught exception: '.$e->getMessage();
    364                         } else {
    365                                 $this->info['error'] = array('Caught exception: '.$e->getMessage());
    366                         }
    367                 }
     340                        $this->error($e->getMessage());
     341                }
     342                return false;
    368343        }
    369344
     
    371346        function analyze($filename) {
    372347                try {
    373                         $this->openfile($filename);
     348                        if (!$this->openfile($filename)) {
     349                                return $this->info;
     350                        }
    374351
    375352                        // Handle tags
     
    428405                                        return $this->error('ID3 tags not allowed on this file type.');
    429406                                } elseif ($determined_format['fail_id3'] === 'WARNING') {
    430                                         $this->info['warning'][] = 'ID3 tags not allowed on this file type.';
     407                                        $this->warning('ID3 tags not allowed on this file type.');
    431408                                }
    432409                        }
     
    438415                                        return $this->error('APE tags not allowed on this file type.');
    439416                                } elseif ($determined_format['fail_ape'] === 'WARNING') {
    440                                         $this->info['warning'][] = 'APE tags not allowed on this file type.';
     417                                        $this->warning('APE tags not allowed on this file type.');
    441418                                }
    442419                        }
     
    519496
    520497                } catch (Exception $e) {
    521                         if (isset($this->info['error'])) {
    522                                 $this->info['error'][] = 'Caught exception: '.$e->getMessage();
    523                         } else {
    524                                 $this->info['error'] = array('Caught exception: '.$e->getMessage());
    525                         }
     498                        $this->error('Caught exception: '.$e->getMessage());
    526499                }
    527500
     
    534507        function error($message) {
    535508                $this->CleanUp();
    536 
     509                if (!isset($this->info['error'])) {
     510                        $this->info['error'] = array();
     511                }
    537512                $this->info['error'][] = $message;
    538513                return $this->info;
     
    994969
    995970
    996                                 // TIFF  - still image - Tagged Information File Format (TIFF)
     971                                // TIFF - still image - Tagged Information File Format (TIFF)
    997972                                'tiff' => array(
    998973                                                        'pattern'   => '^(II\x2A\x00|MM\x00\x2A)',
     
    1000975                                                        'module'    => 'tiff',
    1001976                                                        'mime_type' => 'image/tiff',
     977                                                        'fail_id3'  => 'ERROR',
     978                                                        'fail_ape'  => 'ERROR',
     979                                                ),
     980
     981
     982                                // EFAX - still image - eFax (TIFF derivative)
     983                                'bmp'  => array(
     984                                                        'pattern'   => '^\xDC\xFE',
     985                                                        'group'     => 'graphic',
     986                                                        'module'    => 'efax',
     987                                                        'mime_type' => 'image/efax',
    1002988                                                        'fail_id3'  => 'ERROR',
    1003989                                                        'fail_ape'  => 'ERROR',
     
    13321318                        if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
    13331319
    1334                                 $this->info['warning'][] = 'Failed making system call to vorbiscomment.exe - '.$algorithm.'_data is incorrect - error returned: PHP running in Safe Mode (backtick operator not available)';
    1335                                 $this->info[$algorithm.'_data']  = false;
     1320                                $this->warning('Failed making system call to vorbiscomment.exe - '.$algorithm.'_data is incorrect - error returned: PHP running in Safe Mode (backtick operator not available)');
     1321                                $this->info[$algorithm.'_data'] = false;
    13361322
    13371323                        } else {
     
    15981584                                throw new Exception('cannot extract attachment, it extends beyond the '.round(PHP_INT_MAX / 1073741824).'GB limit');
    15991585                        }
    1600                         switch ($this->option_save_attachments) {
    1601                                 case getID3::ATTACHMENTS_NONE: // do not extract attachments data
    1602                                         unset($ThisFileInfoIndex); // do not set any
    1603                                         break;
    1604 
    1605                                 case getID3::ATTACHMENTS_INLINE: // extract to return array
    1606                                         // get whole data in one pass, till it is anyway stored in memory
    1607                                         $ThisFileInfoIndex = file_get_contents($this->info['filenamepath'], false, null, $offset, $length);
    1608                                         if (($ThisFileInfoIndex === false) || (strlen($ThisFileInfoIndex) != $length)) { // verify
     1586
     1587                        // do not extract at all
     1588                        if ($this->option_save_attachments === getID3::ATTACHMENTS_NONE) {
     1589
     1590                                unset($ThisFileInfoIndex); // do not set any
     1591
     1592                        // extract to return array
     1593                        } elseif ($this->option_save_attachments === getID3::ATTACHMENTS_INLINE) {
     1594
     1595                                // get whole data in one pass, till it is anyway stored in memory
     1596                                $ThisFileInfoIndex = file_get_contents($this->info['filenamepath'], false, null, $offset, $length);
     1597                                if (($ThisFileInfoIndex === false) || (strlen($ThisFileInfoIndex) != $length)) { // verify
     1598                                        throw new Exception('failed to read attachment data');
     1599                                }
     1600
     1601                        // assume directory path is given
     1602                        } else {
     1603
     1604                                $dir = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->option_save_attachments), DIRECTORY_SEPARATOR);
     1605                                // check supplied directory
     1606                                if (!is_dir($dir) || !is_writable($dir)) {
     1607                                        throw new Exception('getID3::saveAttachment() -- supplied path ('.$dir.') does not exist, or is not writable');
     1608                                }
     1609
     1610                                // set up destination path
     1611                                $dest = $dir.DIRECTORY_SEPARATOR.$filename;
     1612
     1613                                // optimize speed if read buffer size is configured to be large enough
     1614                                // here stream_copy_to_stream() may also be used. need to do speed-compare tests
     1615                                if ($length <= $this->fread_buffer_size()) {
     1616                                        $data = file_get_contents($this->info['filenamepath'], false, null, $offset, $length);
     1617                                        if (($data === false) || (strlen($data) != $length)) { // verify
    16091618                                                throw new Exception('failed to read attachment data');
    16101619                                        }
    1611                                         break;
    1612 
    1613                                 default: // assume directory path is given
    1614                                         $dir = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->option_save_attachments), DIRECTORY_SEPARATOR);
    1615                                         // check supplied directory
    1616                                         if (!is_dir($dir) || !is_writable($dir)) {
    1617                                                 throw new Exception('getID3::saveAttachment() -- supplied path ('.$dir.') does not exist, or is not writable');
     1620                                        if (!file_put_contents($dest, $data)) {
     1621                                                throw new Exception('failed to create file '.$dest);
    16181622                                        }
    1619 
    1620                                         // set up destination path
    1621                                         $dest = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $dir).DIRECTORY_SEPARATOR.$filename;
    1622 
    1623                                         // optimize speed if read buffer size is configured to be large enough
    1624                                         // here stream_copy_to_stream() may also be used. need to do speed-compare tests
    1625                                         if ($length <= $this->option_read_buffer_size) {
    1626                                                 $data = file_get_contents($this->info['filenamepath'], false, null, $offset, $length);
    1627                                                 if (($data === false) || (strlen($data) != $length)) { // verify
    1628                                                         throw new Exception('failed to read attachment data');
    1629                                                 }
    1630                                                 if (!file_put_contents($dest, $data)) {
    1631                                                         throw new Exception('failed to create file '.$dest);
    1632                                                 }
    1633                                         } else {
    1634                                                 // optimization not available - copy data in loop
    1635                                                 // here stream_copy_to_stream() shouldn't be used because it's internal read buffer may be larger than ours!
    1636 
    1637                                                 try {
    1638                                                         getid3_lib::CopyFileParts($this->info['filenamepath'], $filename, $offset, $length);
    1639                                                 } catch (Exception $e) {
    1640                                                         throw $e;
    1641                                                 }
    1642                                         }
    1643                                         $ThisFileInfoIndex = $dest;
    1644                                         break;
    1645                         }
     1623                                } else {
     1624                                        // optimization not available - copy data in loop
     1625                                        // here stream_copy_to_stream() shouldn't be used because it's internal read buffer may be larger than ours!
     1626                                        getid3_lib::CopyFileParts($this->info['filenamepath'], $dest, $offset, $length);
     1627                                }
     1628                                $ThisFileInfoIndex = $dest;
     1629                        }
     1630
    16461631                } catch (Exception $e) {
     1632
    16471633                        unset($ThisFileInfoIndex); // do not set any is case of error
    16481634                        $this->warning('Failed to extract attachment '.$filename.': '.$e->getMessage());
    16491635                        return false;
     1636
    16501637                }
    16511638                return true;
  • _plugins_/getID3/trunk/getid3/module.audio-video.asf.php

    r51852 r62460  
    284284                                        $offset += 4;
    285285                                        $thisfile_asf_headerextensionobject['extension_data']      =                              substr($ASFHeaderData, $offset, $thisfile_asf_headerextensionobject['extension_data_size']);
     286                                        $unhandled_sections = 0;
     287                                        $thisfile_asf_headerextensionobject['extension_data_parsed'] = $this->ASF_HeaderExtensionObjectDataParse($thisfile_asf_headerextensionobject['extension_data'], $unhandled_sections);
     288                                        if ($unhandled_sections === 0) {
     289                                                unset($thisfile_asf_headerextensionobject['extension_data']);
     290                                        }
    286291                                        $offset += $thisfile_asf_headerextensionobject['extension_data_size'];
    287292                                        break;
     
    728733                                                // shortcut
    729734                                                $thisfile_asf_extendedcontentdescriptionobject['content_descriptors'][$ExtendedContentDescriptorsCounter] = array();
    730                                                 $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current                                  = &$thisfile_asf_extendedcontentdescriptionobject['content_descriptors'][$ExtendedContentDescriptorsCounter];
     735                                                $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current                 = &$thisfile_asf_extendedcontentdescriptionobject['content_descriptors'][$ExtendedContentDescriptorsCounter];
    731736
    732737                                                $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['base_offset']  = $offset + 30;
     
    847852
    848853                                                        case 'wm/picture':
    849                                                                 //typedef struct _WMPicture{
    850                                                                 //  LPWSTR  pwszMIMEType;
    851                                                                 //  BYTE  bPictureType;
    852                                                                 //  LPWSTR  pwszDescription;
    853                                                                 //  DWORD  dwDataLen;
    854                                                                 //  BYTE*  pbData;
    855                                                                 //} WM_PICTURE;
    856 
     854                                                                $WMpicture = $this->ASF_WMpicture($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']);
     855                                                                foreach ($WMpicture as $key => $value) {
     856                                                                        $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current[$key] = $value;
     857                                                                }
     858                                                                unset($WMpicture);
     859/*
    857860                                                                $wm_picture_offset = 0;
    858861                                                                $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_type_id'] = getid3_lib::LittleEndian2Int(substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset, 1));
     
    890893                                                                        $thisfile_asf_comments['picture'] = array();
    891894                                                                }
    892                                                                 $thisfile_asf_comments['picture'][] = array('data'=>$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['data'], 'mime_type'=>$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime']);
     895                                                                $thisfile_asf_comments['picture'][] = array('data'=>$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['data'], 'image_mime'=>$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime']);
     896*/
    893897                                                                break;
    894898
     
    13491353                                        case 'WVP2':
    13501354                                                $thisfile_video['dataformat'] = 'wmv';
    1351                                                 $info['mime_type']    = 'video/x-ms-wmv';
     1355                                                $info['mime_type'] = 'video/x-ms-wmv';
    13521356                                                break;
    13531357
     
    13571361                                        case 'mp4s':
    13581362                                                $thisfile_video['dataformat'] = 'asf';
    1359                                                 $info['mime_type']    = 'video/x-ms-asf';
     1363                                                $info['mime_type'] = 'video/x-ms-asf';
    13601364                                                break;
    13611365
     
    14601464
    14611465        static function KnownGUIDs() {
    1462                 static $GUIDarray = array();
    1463                 if (empty($GUIDarray)) {
    1464                         $GUIDarray['GETID3_ASF_Extended_Stream_Properties_Object']   = '14E6A5CB-C672-4332-8399-A96952065B5A';
    1465                         $GUIDarray['GETID3_ASF_Padding_Object']                      = '1806D474-CADF-4509-A4BA-9AABCB96AAE8';
    1466                         $GUIDarray['GETID3_ASF_Payload_Ext_Syst_Pixel_Aspect_Ratio'] = '1B1EE554-F9EA-4BC8-821A-376B74E4C4B8';
    1467                         $GUIDarray['GETID3_ASF_Script_Command_Object']               = '1EFB1A30-0B62-11D0-A39B-00A0C90348F6';
    1468                         $GUIDarray['GETID3_ASF_No_Error_Correction']                 = '20FB5700-5B55-11CF-A8FD-00805F5C442B';
    1469                         $GUIDarray['GETID3_ASF_Content_Branding_Object']             = '2211B3FA-BD23-11D2-B4B7-00A0C955FC6E';
    1470                         $GUIDarray['GETID3_ASF_Content_Encryption_Object']           = '2211B3FB-BD23-11D2-B4B7-00A0C955FC6E';
    1471                         $GUIDarray['GETID3_ASF_Digital_Signature_Object']            = '2211B3FC-BD23-11D2-B4B7-00A0C955FC6E';
    1472                         $GUIDarray['GETID3_ASF_Extended_Content_Encryption_Object']  = '298AE614-2622-4C17-B935-DAE07EE9289C';
    1473                         $GUIDarray['GETID3_ASF_Simple_Index_Object']                 = '33000890-E5B1-11CF-89F4-00A0C90349CB';
    1474                         $GUIDarray['GETID3_ASF_Degradable_JPEG_Media']               = '35907DE0-E415-11CF-A917-00805F5C442B';
    1475                         $GUIDarray['GETID3_ASF_Payload_Extension_System_Timecode']   = '399595EC-8667-4E2D-8FDB-98814CE76C1E';
    1476                         $GUIDarray['GETID3_ASF_Binary_Media']                        = '3AFB65E2-47EF-40F2-AC2C-70A90D71D343';
    1477                         $GUIDarray['GETID3_ASF_Timecode_Index_Object']               = '3CB73FD0-0C4A-4803-953D-EDF7B6228F0C';
    1478                         $GUIDarray['GETID3_ASF_Metadata_Library_Object']             = '44231C94-9498-49D1-A141-1D134E457054';
    1479                         $GUIDarray['GETID3_ASF_Reserved_3']                          = '4B1ACBE3-100B-11D0-A39B-00A0C90348F6';
    1480                         $GUIDarray['GETID3_ASF_Reserved_4']                          = '4CFEDB20-75F6-11CF-9C0F-00A0C90349CB';
    1481                         $GUIDarray['GETID3_ASF_Command_Media']                       = '59DACFC0-59E6-11D0-A3AC-00A0C90348F6';
    1482                         $GUIDarray['GETID3_ASF_Header_Extension_Object']             = '5FBF03B5-A92E-11CF-8EE3-00C00C205365';
    1483                         $GUIDarray['GETID3_ASF_Media_Object_Index_Parameters_Obj']   = '6B203BAD-3F11-4E84-ACA8-D7613DE2CFA7';
    1484                         $GUIDarray['GETID3_ASF_Header_Object']                       = '75B22630-668E-11CF-A6D9-00AA0062CE6C';
    1485                         $GUIDarray['GETID3_ASF_Content_Description_Object']          = '75B22633-668E-11CF-A6D9-00AA0062CE6C';
    1486                         $GUIDarray['GETID3_ASF_Error_Correction_Object']             = '75B22635-668E-11CF-A6D9-00AA0062CE6C';
    1487                         $GUIDarray['GETID3_ASF_Data_Object']                         = '75B22636-668E-11CF-A6D9-00AA0062CE6C';
    1488                         $GUIDarray['GETID3_ASF_Web_Stream_Media_Subtype']            = '776257D4-C627-41CB-8F81-7AC7FF1C40CC';
    1489                         $GUIDarray['GETID3_ASF_Stream_Bitrate_Properties_Object']    = '7BF875CE-468D-11D1-8D82-006097C9A2B2';
    1490                         $GUIDarray['GETID3_ASF_Language_List_Object']                = '7C4346A9-EFE0-4BFC-B229-393EDE415C85';
    1491                         $GUIDarray['GETID3_ASF_Codec_List_Object']                   = '86D15240-311D-11D0-A3A4-00A0C90348F6';
    1492                         $GUIDarray['GETID3_ASF_Reserved_2']                          = '86D15241-311D-11D0-A3A4-00A0C90348F6';
    1493                         $GUIDarray['GETID3_ASF_File_Properties_Object']              = '8CABDCA1-A947-11CF-8EE4-00C00C205365';
    1494                         $GUIDarray['GETID3_ASF_File_Transfer_Media']                 = '91BD222C-F21C-497A-8B6D-5AA86BFC0185';
    1495                         $GUIDarray['GETID3_ASF_Old_RTP_Extension_Data']              = '96800C63-4C94-11D1-837B-0080C7A37F95';
    1496                         $GUIDarray['GETID3_ASF_Advanced_Mutual_Exclusion_Object']    = 'A08649CF-4775-4670-8A16-6E35357566CD';
    1497                         $GUIDarray['GETID3_ASF_Bandwidth_Sharing_Object']            = 'A69609E6-517B-11D2-B6AF-00C04FD908E9';
    1498                         $GUIDarray['GETID3_ASF_Reserved_1']                          = 'ABD3D211-A9BA-11cf-8EE6-00C00C205365';
    1499                         $GUIDarray['GETID3_ASF_Bandwidth_Sharing_Exclusive']         = 'AF6060AA-5197-11D2-B6AF-00C04FD908E9';
    1500                         $GUIDarray['GETID3_ASF_Bandwidth_Sharing_Partial']           = 'AF6060AB-5197-11D2-B6AF-00C04FD908E9';
    1501                         $GUIDarray['GETID3_ASF_JFIF_Media']                          = 'B61BE100-5B4E-11CF-A8FD-00805F5C442B';
    1502                         $GUIDarray['GETID3_ASF_Stream_Properties_Object']            = 'B7DC0791-A9B7-11CF-8EE6-00C00C205365';
    1503                         $GUIDarray['GETID3_ASF_Video_Media']                         = 'BC19EFC0-5B4D-11CF-A8FD-00805F5C442B';
    1504                         $GUIDarray['GETID3_ASF_Audio_Spread']                        = 'BFC3CD50-618F-11CF-8BB2-00AA00B4E220';
    1505                         $GUIDarray['GETID3_ASF_Metadata_Object']                     = 'C5F8CBEA-5BAF-4877-8467-AA8C44FA4CCA';
    1506                         $GUIDarray['GETID3_ASF_Payload_Ext_Syst_Sample_Duration']    = 'C6BD9450-867F-4907-83A3-C77921B733AD';
    1507                         $GUIDarray['GETID3_ASF_Group_Mutual_Exclusion_Object']       = 'D1465A40-5A79-4338-B71B-E36B8FD6C249';
    1508                         $GUIDarray['GETID3_ASF_Extended_Content_Description_Object'] = 'D2D0A440-E307-11D2-97F0-00A0C95EA850';
    1509                         $GUIDarray['GETID3_ASF_Stream_Prioritization_Object']        = 'D4FED15B-88D3-454F-81F0-ED5C45999E24';
    1510                         $GUIDarray['GETID3_ASF_Payload_Ext_System_Content_Type']     = 'D590DC20-07BC-436C-9CF7-F3BBFBF1A4DC';
    1511                         $GUIDarray['GETID3_ASF_Old_File_Properties_Object']          = 'D6E229D0-35DA-11D1-9034-00A0C90349BE';
    1512                         $GUIDarray['GETID3_ASF_Old_ASF_Header_Object']               = 'D6E229D1-35DA-11D1-9034-00A0C90349BE';
    1513                         $GUIDarray['GETID3_ASF_Old_ASF_Data_Object']                 = 'D6E229D2-35DA-11D1-9034-00A0C90349BE';
    1514                         $GUIDarray['GETID3_ASF_Index_Object']                        = 'D6E229D3-35DA-11D1-9034-00A0C90349BE';
    1515                         $GUIDarray['GETID3_ASF_Old_Stream_Properties_Object']        = 'D6E229D4-35DA-11D1-9034-00A0C90349BE';
    1516                         $GUIDarray['GETID3_ASF_Old_Content_Description_Object']      = 'D6E229D5-35DA-11D1-9034-00A0C90349BE';
    1517                         $GUIDarray['GETID3_ASF_Old_Script_Command_Object']           = 'D6E229D6-35DA-11D1-9034-00A0C90349BE';
    1518                         $GUIDarray['GETID3_ASF_Old_Marker_Object']                   = 'D6E229D7-35DA-11D1-9034-00A0C90349BE';
    1519                         $GUIDarray['GETID3_ASF_Old_Component_Download_Object']       = 'D6E229D8-35DA-11D1-9034-00A0C90349BE';
    1520                         $GUIDarray['GETID3_ASF_Old_Stream_Group_Object']             = 'D6E229D9-35DA-11D1-9034-00A0C90349BE';
    1521                         $GUIDarray['GETID3_ASF_Old_Scalable_Object']                 = 'D6E229DA-35DA-11D1-9034-00A0C90349BE';
    1522                         $GUIDarray['GETID3_ASF_Old_Prioritization_Object']           = 'D6E229DB-35DA-11D1-9034-00A0C90349BE';
    1523                         $GUIDarray['GETID3_ASF_Bitrate_Mutual_Exclusion_Object']     = 'D6E229DC-35DA-11D1-9034-00A0C90349BE';
    1524                         $GUIDarray['GETID3_ASF_Old_Inter_Media_Dependency_Object']   = 'D6E229DD-35DA-11D1-9034-00A0C90349BE';
    1525                         $GUIDarray['GETID3_ASF_Old_Rating_Object']                   = 'D6E229DE-35DA-11D1-9034-00A0C90349BE';
    1526                         $GUIDarray['GETID3_ASF_Index_Parameters_Object']             = 'D6E229DF-35DA-11D1-9034-00A0C90349BE';
    1527                         $GUIDarray['GETID3_ASF_Old_Color_Table_Object']              = 'D6E229E0-35DA-11D1-9034-00A0C90349BE';
    1528                         $GUIDarray['GETID3_ASF_Old_Language_List_Object']            = 'D6E229E1-35DA-11D1-9034-00A0C90349BE';
    1529                         $GUIDarray['GETID3_ASF_Old_Audio_Media']                     = 'D6E229E2-35DA-11D1-9034-00A0C90349BE';
    1530                         $GUIDarray['GETID3_ASF_Old_Video_Media']                     = 'D6E229E3-35DA-11D1-9034-00A0C90349BE';
    1531                         $GUIDarray['GETID3_ASF_Old_Image_Media']                     = 'D6E229E4-35DA-11D1-9034-00A0C90349BE';
    1532                         $GUIDarray['GETID3_ASF_Old_Timecode_Media']                  = 'D6E229E5-35DA-11D1-9034-00A0C90349BE';
    1533                         $GUIDarray['GETID3_ASF_Old_Text_Media']                      = 'D6E229E6-35DA-11D1-9034-00A0C90349BE';
    1534                         $GUIDarray['GETID3_ASF_Old_MIDI_Media']                      = 'D6E229E7-35DA-11D1-9034-00A0C90349BE';
    1535                         $GUIDarray['GETID3_ASF_Old_Command_Media']                   = 'D6E229E8-35DA-11D1-9034-00A0C90349BE';
    1536                         $GUIDarray['GETID3_ASF_Old_No_Error_Concealment']            = 'D6E229EA-35DA-11D1-9034-00A0C90349BE';
    1537                         $GUIDarray['GETID3_ASF_Old_Scrambled_Audio']                 = 'D6E229EB-35DA-11D1-9034-00A0C90349BE';
    1538                         $GUIDarray['GETID3_ASF_Old_No_Color_Table']                  = 'D6E229EC-35DA-11D1-9034-00A0C90349BE';
    1539                         $GUIDarray['GETID3_ASF_Old_SMPTE_Time']                      = 'D6E229ED-35DA-11D1-9034-00A0C90349BE';
    1540                         $GUIDarray['GETID3_ASF_Old_ASCII_Text']                      = 'D6E229EE-35DA-11D1-9034-00A0C90349BE';
    1541                         $GUIDarray['GETID3_ASF_Old_Unicode_Text']                    = 'D6E229EF-35DA-11D1-9034-00A0C90349BE';
    1542                         $GUIDarray['GETID3_ASF_Old_HTML_Text']                       = 'D6E229F0-35DA-11D1-9034-00A0C90349BE';
    1543                         $GUIDarray['GETID3_ASF_Old_URL_Command']                     = 'D6E229F1-35DA-11D1-9034-00A0C90349BE';
    1544                         $GUIDarray['GETID3_ASF_Old_Filename_Command']                = 'D6E229F2-35DA-11D1-9034-00A0C90349BE';
    1545                         $GUIDarray['GETID3_ASF_Old_ACM_Codec']                       = 'D6E229F3-35DA-11D1-9034-00A0C90349BE';
    1546                         $GUIDarray['GETID3_ASF_Old_VCM_Codec']                       = 'D6E229F4-35DA-11D1-9034-00A0C90349BE';
    1547                         $GUIDarray['GETID3_ASF_Old_QuickTime_Codec']                 = 'D6E229F5-35DA-11D1-9034-00A0C90349BE';
    1548                         $GUIDarray['GETID3_ASF_Old_DirectShow_Transform_Filter']     = 'D6E229F6-35DA-11D1-9034-00A0C90349BE';
    1549                         $GUIDarray['GETID3_ASF_Old_DirectShow_Rendering_Filter']     = 'D6E229F7-35DA-11D1-9034-00A0C90349BE';
    1550                         $GUIDarray['GETID3_ASF_Old_No_Enhancement']                  = 'D6E229F8-35DA-11D1-9034-00A0C90349BE';
    1551                         $GUIDarray['GETID3_ASF_Old_Unknown_Enhancement_Type']        = 'D6E229F9-35DA-11D1-9034-00A0C90349BE';
    1552                         $GUIDarray['GETID3_ASF_Old_Temporal_Enhancement']            = 'D6E229FA-35DA-11D1-9034-00A0C90349BE';
    1553                         $GUIDarray['GETID3_ASF_Old_Spatial_Enhancement']             = 'D6E229FB-35DA-11D1-9034-00A0C90349BE';
    1554                         $GUIDarray['GETID3_ASF_Old_Quality_Enhancement']             = 'D6E229FC-35DA-11D1-9034-00A0C90349BE';
    1555                         $GUIDarray['GETID3_ASF_Old_Number_of_Channels_Enhancement']  = 'D6E229FD-35DA-11D1-9034-00A0C90349BE';
    1556                         $GUIDarray['GETID3_ASF_Old_Frequency_Response_Enhancement']  = 'D6E229FE-35DA-11D1-9034-00A0C90349BE';
    1557                         $GUIDarray['GETID3_ASF_Old_Media_Object']                    = 'D6E229FF-35DA-11D1-9034-00A0C90349BE';
    1558                         $GUIDarray['GETID3_ASF_Mutex_Language']                      = 'D6E22A00-35DA-11D1-9034-00A0C90349BE';
    1559                         $GUIDarray['GETID3_ASF_Mutex_Bitrate']                       = 'D6E22A01-35DA-11D1-9034-00A0C90349BE';
    1560                         $GUIDarray['GETID3_ASF_Mutex_Unknown']                       = 'D6E22A02-35DA-11D1-9034-00A0C90349BE';
    1561                         $GUIDarray['GETID3_ASF_Old_ASF_Placeholder_Object']          = 'D6E22A0E-35DA-11D1-9034-00A0C90349BE';
    1562                         $GUIDarray['GETID3_ASF_Old_Data_Unit_Extension_Object']      = 'D6E22A0F-35DA-11D1-9034-00A0C90349BE';
    1563                         $GUIDarray['GETID3_ASF_Web_Stream_Format']                   = 'DA1E6B13-8359-4050-B398-388E965BF00C';
    1564                         $GUIDarray['GETID3_ASF_Payload_Ext_System_File_Name']        = 'E165EC0E-19ED-45D7-B4A7-25CBD1E28E9B';
    1565                         $GUIDarray['GETID3_ASF_Marker_Object']                       = 'F487CD01-A951-11CF-8EE6-00C00C205365';
    1566                         $GUIDarray['GETID3_ASF_Timecode_Index_Parameters_Object']    = 'F55E496D-9797-4B5D-8C8B-604DFE9BFB24';
    1567                         $GUIDarray['GETID3_ASF_Audio_Media']                         = 'F8699E40-5B4D-11CF-A8FD-00805F5C442B';
    1568                         $GUIDarray['GETID3_ASF_Media_Object_Index_Object']           = 'FEB103F8-12AD-4C64-840F-2A1D2F7AD48C';
    1569                         $GUIDarray['GETID3_ASF_Alt_Extended_Content_Encryption_Obj'] = 'FF889EF1-ADEE-40DA-9E71-98704BB928CE';
    1570                 }
     1466                static $GUIDarray = array(
     1467                        'GETID3_ASF_Extended_Stream_Properties_Object'   => '14E6A5CB-C672-4332-8399-A96952065B5A',
     1468                        'GETID3_ASF_Padding_Object'                      => '1806D474-CADF-4509-A4BA-9AABCB96AAE8',
     1469                        'GETID3_ASF_Payload_Ext_Syst_Pixel_Aspect_Ratio' => '1B1EE554-F9EA-4BC8-821A-376B74E4C4B8',
     1470                        'GETID3_ASF_Script_Command_Object'               => '1EFB1A30-0B62-11D0-A39B-00A0C90348F6',
     1471                        'GETID3_ASF_No_Error_Correction'                 => '20FB5700-5B55-11CF-A8FD-00805F5C442B',
     1472                        'GETID3_ASF_Content_Branding_Object'             => '2211B3FA-BD23-11D2-B4B7-00A0C955FC6E',
     1473                        'GETID3_ASF_Content_Encryption_Object'           => '2211B3FB-BD23-11D2-B4B7-00A0C955FC6E',
     1474                        'GETID3_ASF_Digital_Signature_Object'            => '2211B3FC-BD23-11D2-B4B7-00A0C955FC6E',
     1475                        'GETID3_ASF_Extended_Content_Encryption_Object'  => '298AE614-2622-4C17-B935-DAE07EE9289C',
     1476                        'GETID3_ASF_Simple_Index_Object'                 => '33000890-E5B1-11CF-89F4-00A0C90349CB',
     1477                        'GETID3_ASF_Degradable_JPEG_Media'               => '35907DE0-E415-11CF-A917-00805F5C442B',
     1478                        'GETID3_ASF_Payload_Extension_System_Timecode'   => '399595EC-8667-4E2D-8FDB-98814CE76C1E',
     1479                        'GETID3_ASF_Binary_Media'                        => '3AFB65E2-47EF-40F2-AC2C-70A90D71D343',
     1480                        'GETID3_ASF_Timecode_Index_Object'               => '3CB73FD0-0C4A-4803-953D-EDF7B6228F0C',
     1481                        'GETID3_ASF_Metadata_Library_Object'             => '44231C94-9498-49D1-A141-1D134E457054',
     1482                        'GETID3_ASF_Reserved_3'                          => '4B1ACBE3-100B-11D0-A39B-00A0C90348F6',
     1483                        'GETID3_ASF_Reserved_4'                          => '4CFEDB20-75F6-11CF-9C0F-00A0C90349CB',
     1484                        'GETID3_ASF_Command_Media'                       => '59DACFC0-59E6-11D0-A3AC-00A0C90348F6',
     1485                        'GETID3_ASF_Header_Extension_Object'             => '5FBF03B5-A92E-11CF-8EE3-00C00C205365',
     1486                        'GETID3_ASF_Media_Object_Index_Parameters_Obj'   => '6B203BAD-3F11-4E84-ACA8-D7613DE2CFA7',
     1487                        'GETID3_ASF_Header_Object'                       => '75B22630-668E-11CF-A6D9-00AA0062CE6C',
     1488                        'GETID3_ASF_Content_Description_Object'          => '75B22633-668E-11CF-A6D9-00AA0062CE6C',
     1489                        'GETID3_ASF_Error_Correction_Object'             => '75B22635-668E-11CF-A6D9-00AA0062CE6C',
     1490                        'GETID3_ASF_Data_Object'                         => '75B22636-668E-11CF-A6D9-00AA0062CE6C',
     1491                        'GETID3_ASF_Web_Stream_Media_Subtype'            => '776257D4-C627-41CB-8F81-7AC7FF1C40CC',
     1492                        'GETID3_ASF_Stream_Bitrate_Properties_Object'    => '7BF875CE-468D-11D1-8D82-006097C9A2B2',
     1493                        'GETID3_ASF_Language_List_Object'                => '7C4346A9-EFE0-4BFC-B229-393EDE415C85',
     1494                        'GETID3_ASF_Codec_List_Object'                   => '86D15240-311D-11D0-A3A4-00A0C90348F6',
     1495                        'GETID3_ASF_Reserved_2'                          => '86D15241-311D-11D0-A3A4-00A0C90348F6',
     1496                        'GETID3_ASF_File_Properties_Object'              => '8CABDCA1-A947-11CF-8EE4-00C00C205365',
     1497                        'GETID3_ASF_File_Transfer_Media'                 => '91BD222C-F21C-497A-8B6D-5AA86BFC0185',
     1498                        'GETID3_ASF_Old_RTP_Extension_Data'              => '96800C63-4C94-11D1-837B-0080C7A37F95',
     1499                        'GETID3_ASF_Advanced_Mutual_Exclusion_Object'    => 'A08649CF-4775-4670-8A16-6E35357566CD',
     1500                        'GETID3_ASF_Bandwidth_Sharing_Object'            => 'A69609E6-517B-11D2-B6AF-00C04FD908E9',
     1501                        'GETID3_ASF_Reserved_1'                          => 'ABD3D211-A9BA-11cf-8EE6-00C00C205365',
     1502                        'GETID3_ASF_Bandwidth_Sharing_Exclusive'         => 'AF6060AA-5197-11D2-B6AF-00C04FD908E9',
     1503                        'GETID3_ASF_Bandwidth_Sharing_Partial'           => 'AF6060AB-5197-11D2-B6AF-00C04FD908E9',
     1504                        'GETID3_ASF_JFIF_Media'                          => 'B61BE100-5B4E-11CF-A8FD-00805F5C442B',
     1505                        'GETID3_ASF_Stream_Properties_Object'            => 'B7DC0791-A9B7-11CF-8EE6-00C00C205365',
     1506                        'GETID3_ASF_Video_Media'                         => 'BC19EFC0-5B4D-11CF-A8FD-00805F5C442B',
     1507                        'GETID3_ASF_Audio_Spread'                        => 'BFC3CD50-618F-11CF-8BB2-00AA00B4E220',
     1508                        'GETID3_ASF_Metadata_Object'                     => 'C5F8CBEA-5BAF-4877-8467-AA8C44FA4CCA',
     1509                        'GETID3_ASF_Payload_Ext_Syst_Sample_Duration'    => 'C6BD9450-867F-4907-83A3-C77921B733AD',
     1510                        'GETID3_ASF_Group_Mutual_Exclusion_Object'       => 'D1465A40-5A79-4338-B71B-E36B8FD6C249',
     1511                        'GETID3_ASF_Extended_Content_Description_Object' => 'D2D0A440-E307-11D2-97F0-00A0C95EA850',
     1512                        'GETID3_ASF_Stream_Prioritization_Object'        => 'D4FED15B-88D3-454F-81F0-ED5C45999E24',
     1513                        'GETID3_ASF_Payload_Ext_System_Content_Type'     => 'D590DC20-07BC-436C-9CF7-F3BBFBF1A4DC',
     1514                        'GETID3_ASF_Old_File_Properties_Object'          => 'D6E229D0-35DA-11D1-9034-00A0C90349BE',
     1515                        'GETID3_ASF_Old_ASF_Header_Object'               => 'D6E229D1-35DA-11D1-9034-00A0C90349BE',
     1516                        'GETID3_ASF_Old_ASF_Data_Object'                 => 'D6E229D2-35DA-11D1-9034-00A0C90349BE',
     1517                        'GETID3_ASF_Index_Object'                        => 'D6E229D3-35DA-11D1-9034-00A0C90349BE',
     1518                        'GETID3_ASF_Old_Stream_Properties_Object'        => 'D6E229D4-35DA-11D1-9034-00A0C90349BE',
     1519                        'GETID3_ASF_Old_Content_Description_Object'      => 'D6E229D5-35DA-11D1-9034-00A0C90349BE',
     1520                        'GETID3_ASF_Old_Script_Command_Object'           => 'D6E229D6-35DA-11D1-9034-00A0C90349BE',
     1521                        'GETID3_ASF_Old_Marker_Object'                   => 'D6E229D7-35DA-11D1-9034-00A0C90349BE',
     1522                        'GETID3_ASF_Old_Component_Download_Object'       => 'D6E229D8-35DA-11D1-9034-00A0C90349BE',
     1523                        'GETID3_ASF_Old_Stream_Group_Object'             => 'D6E229D9-35DA-11D1-9034-00A0C90349BE',
     1524                        'GETID3_ASF_Old_Scalable_Object'                 => 'D6E229DA-35DA-11D1-9034-00A0C90349BE',
     1525                        'GETID3_ASF_Old_Prioritization_Object'           => 'D6E229DB-35DA-11D1-9034-00A0C90349BE',
     1526                        'GETID3_ASF_Bitrate_Mutual_Exclusion_Object'     => 'D6E229DC-35DA-11D1-9034-00A0C90349BE',
     1527                        'GETID3_ASF_Old_Inter_Media_Dependency_Object'   => 'D6E229DD-35DA-11D1-9034-00A0C90349BE',
     1528                        'GETID3_ASF_Old_Rating_Object'                   => 'D6E229DE-35DA-11D1-9034-00A0C90349BE',
     1529                        'GETID3_ASF_Index_Parameters_Object'             => 'D6E229DF-35DA-11D1-9034-00A0C90349BE',
     1530                        'GETID3_ASF_Old_Color_Table_Object'              => 'D6E229E0-35DA-11D1-9034-00A0C90349BE',
     1531                        'GETID3_ASF_Old_Language_List_Object'            => 'D6E229E1-35DA-11D1-9034-00A0C90349BE',
     1532                        'GETID3_ASF_Old_Audio_Media'                     => 'D6E229E2-35DA-11D1-9034-00A0C90349BE',
     1533                        'GETID3_ASF_Old_Video_Media'                     => 'D6E229E3-35DA-11D1-9034-00A0C90349BE',
     1534                        'GETID3_ASF_Old_Image_Media'                     => 'D6E229E4-35DA-11D1-9034-00A0C90349BE',
     1535                        'GETID3_ASF_Old_Timecode_Media'                  => 'D6E229E5-35DA-11D1-9034-00A0C90349BE',
     1536                        'GETID3_ASF_Old_Text_Media'                      => 'D6E229E6-35DA-11D1-9034-00A0C90349BE',
     1537                        'GETID3_ASF_Old_MIDI_Media'                      => 'D6E229E7-35DA-11D1-9034-00A0C90349BE',
     1538                        'GETID3_ASF_Old_Command_Media'                   => 'D6E229E8-35DA-11D1-9034-00A0C90349BE',
     1539                        'GETID3_ASF_Old_No_Error_Concealment'            => 'D6E229EA-35DA-11D1-9034-00A0C90349BE',
     1540                        'GETID3_ASF_Old_Scrambled_Audio'                 => 'D6E229EB-35DA-11D1-9034-00A0C90349BE',
     1541                        'GETID3_ASF_Old_No_Color_Table'                  => 'D6E229EC-35DA-11D1-9034-00A0C90349BE',
     1542                        'GETID3_ASF_Old_SMPTE_Time'                      => 'D6E229ED-35DA-11D1-9034-00A0C90349BE',
     1543                        'GETID3_ASF_Old_ASCII_Text'                      => 'D6E229EE-35DA-11D1-9034-00A0C90349BE',
     1544                        'GETID3_ASF_Old_Unicode_Text'                    => 'D6E229EF-35DA-11D1-9034-00A0C90349BE',
     1545                        'GETID3_ASF_Old_HTML_Text'                       => 'D6E229F0-35DA-11D1-9034-00A0C90349BE',
     1546                        'GETID3_ASF_Old_URL_Command'                     => 'D6E229F1-35DA-11D1-9034-00A0C90349BE',
     1547                        'GETID3_ASF_Old_Filename_Command'                => 'D6E229F2-35DA-11D1-9034-00A0C90349BE',
     1548                        'GETID3_ASF_Old_ACM_Codec'                       => 'D6E229F3-35DA-11D1-9034-00A0C90349BE',
     1549                        'GETID3_ASF_Old_VCM_Codec'                       => 'D6E229F4-35DA-11D1-9034-00A0C90349BE',
     1550                        'GETID3_ASF_Old_QuickTime_Codec'                 => 'D6E229F5-35DA-11D1-9034-00A0C90349BE',
     1551                        'GETID3_ASF_Old_DirectShow_Transform_Filter'     => 'D6E229F6-35DA-11D1-9034-00A0C90349BE',
     1552                        'GETID3_ASF_Old_DirectShow_Rendering_Filter'     => 'D6E229F7-35DA-11D1-9034-00A0C90349BE',
     1553                        'GETID3_ASF_Old_No_Enhancement'                  => 'D6E229F8-35DA-11D1-9034-00A0C90349BE',
     1554                        'GETID3_ASF_Old_Unknown_Enhancement_Type'        => 'D6E229F9-35DA-11D1-9034-00A0C90349BE',
     1555                        'GETID3_ASF_Old_Temporal_Enhancement'            => 'D6E229FA-35DA-11D1-9034-00A0C90349BE',
     1556                        'GETID3_ASF_Old_Spatial_Enhancement'             => 'D6E229FB-35DA-11D1-9034-00A0C90349BE',
     1557                        'GETID3_ASF_Old_Quality_Enhancement'             => 'D6E229FC-35DA-11D1-9034-00A0C90349BE',
     1558                        'GETID3_ASF_Old_Number_of_Channels_Enhancement'  => 'D6E229FD-35DA-11D1-9034-00A0C90349BE',
     1559                        'GETID3_ASF_Old_Frequency_Response_Enhancement'  => 'D6E229FE-35DA-11D1-9034-00A0C90349BE',
     1560                        'GETID3_ASF_Old_Media_Object'                    => 'D6E229FF-35DA-11D1-9034-00A0C90349BE',
     1561                        'GETID3_ASF_Mutex_Language'                      => 'D6E22A00-35DA-11D1-9034-00A0C90349BE',
     1562                        'GETID3_ASF_Mutex_Bitrate'                       => 'D6E22A01-35DA-11D1-9034-00A0C90349BE',
     1563                        'GETID3_ASF_Mutex_Unknown'                       => 'D6E22A02-35DA-11D1-9034-00A0C90349BE',
     1564                        'GETID3_ASF_Old_ASF_Placeholder_Object'          => 'D6E22A0E-35DA-11D1-9034-00A0C90349BE',
     1565                        'GETID3_ASF_Old_Data_Unit_Extension_Object'      => 'D6E22A0F-35DA-11D1-9034-00A0C90349BE',
     1566                        'GETID3_ASF_Web_Stream_Format'                   => 'DA1E6B13-8359-4050-B398-388E965BF00C',
     1567                        'GETID3_ASF_Payload_Ext_System_File_Name'        => 'E165EC0E-19ED-45D7-B4A7-25CBD1E28E9B',
     1568                        'GETID3_ASF_Marker_Object'                       => 'F487CD01-A951-11CF-8EE6-00C00C205365',
     1569                        'GETID3_ASF_Timecode_Index_Parameters_Object'    => 'F55E496D-9797-4B5D-8C8B-604DFE9BFB24',
     1570                        'GETID3_ASF_Audio_Media'                         => 'F8699E40-5B4D-11CF-A8FD-00805F5C442B',
     1571                        'GETID3_ASF_Media_Object_Index_Object'           => 'FEB103F8-12AD-4C64-840F-2A1D2F7AD48C',
     1572                        'GETID3_ASF_Alt_Extended_Content_Encryption_Obj' => 'FF889EF1-ADEE-40DA-9E71-98704BB928CE',
     1573                        'GETID3_ASF_Index_Placeholder_Object'            => 'D9AADE20-7C17-4F9C-BC28-8555DD98E2A2', // http://cpan.uwinnipeg.ca/htdocs/Audio-WMA/Audio/WMA.pm.html
     1574                        'GETID3_ASF_Compatibility_Object'                => '26F18B5D-4584-47EC-9F5F-0E651F0452C9', // http://cpan.uwinnipeg.ca/htdocs/Audio-WMA/Audio/WMA.pm.html
     1575                );
    15711576                return $GUIDarray;
    15721577        }
     
    16861691        }
    16871692
     1693        function ASF_HeaderExtensionObjectDataParse(&$asf_header_extension_object_data, &$unhandled_sections) {
     1694                // http://msdn.microsoft.com/en-us/library/bb643323.aspx
     1695
     1696                $offset = 0;
     1697                $objectOffset = 0;
     1698                $HeaderExtensionObjectParsed = array();
     1699                while ($objectOffset < strlen($asf_header_extension_object_data)) {
     1700                        $offset = $objectOffset;
     1701                        $thisObject = array();
     1702
     1703                        $thisObject['guid']                              =                              substr($asf_header_extension_object_data, $offset, 16);
     1704                        $offset += 16;
     1705                        $thisObject['guid_text'] = $this->BytestringToGUID($thisObject['guid']);
     1706                        $thisObject['guid_name'] = $this->GUIDname($thisObject['guid_text']);
     1707
     1708                        $thisObject['size']                              = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  8));
     1709                        $offset += 8;
     1710                        if ($thisObject['size'] <= 0) {
     1711                                break;
     1712                        }
     1713
     1714                        switch ($thisObject['guid']) {
     1715                                case GETID3_ASF_Extended_Stream_Properties_Object:
     1716                                        $thisObject['start_time']                        = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  8));
     1717                                        $offset += 8;
     1718                                        $thisObject['start_time_unix']                   = $this->FILETIMEtoUNIXtime($thisObject['start_time']);
     1719
     1720                                        $thisObject['end_time']                          = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  8));
     1721                                        $offset += 8;
     1722                                        $thisObject['end_time_unix']                     = $this->FILETIMEtoUNIXtime($thisObject['end_time']);
     1723
     1724                                        $thisObject['data_bitrate']                      = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
     1725                                        $offset += 4;
     1726
     1727                                        $thisObject['buffer_size']                       = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
     1728                                        $offset += 4;
     1729
     1730                                        $thisObject['initial_buffer_fullness']           = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
     1731                                        $offset += 4;
     1732
     1733                                        $thisObject['alternate_data_bitrate']            = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
     1734                                        $offset += 4;
     1735
     1736                                        $thisObject['alternate_buffer_size']             = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
     1737                                        $offset += 4;
     1738
     1739                                        $thisObject['alternate_initial_buffer_fullness'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
     1740                                        $offset += 4;
     1741
     1742                                        $thisObject['maximum_object_size']               = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
     1743                                        $offset += 4;
     1744
     1745                                        $thisObject['flags_raw']                         = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
     1746                                        $offset += 4;
     1747                                        $thisObject['flags']['reliable']                = (bool) $thisObject['flags_raw'] & 0x00000001;
     1748                                        $thisObject['flags']['seekable']                = (bool) $thisObject['flags_raw'] & 0x00000002;
     1749                                        $thisObject['flags']['no_cleanpoints']          = (bool) $thisObject['flags_raw'] & 0x00000004;
     1750                                        $thisObject['flags']['resend_live_cleanpoints'] = (bool) $thisObject['flags_raw'] & 0x00000008;
     1751
     1752                                        $thisObject['stream_number']                     = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
     1753                                        $offset += 2;
     1754
     1755                                        $thisObject['stream_language_id_index']          = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
     1756                                        $offset += 2;
     1757
     1758                                        $thisObject['average_time_per_frame']            = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
     1759                                        $offset += 4;
     1760
     1761                                        $thisObject['stream_name_count']                 = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
     1762                                        $offset += 2;
     1763
     1764                                        $thisObject['payload_extension_system_count']    = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
     1765                                        $offset += 2;
     1766
     1767                                        for ($i = 0; $i < $thisObject['stream_name_count']; $i++) {
     1768                                                $streamName = array();
     1769
     1770                                                $streamName['language_id_index']             = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
     1771                                                $offset += 2;
     1772
     1773                                                $streamName['stream_name_length']            = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
     1774                                                $offset += 2;
     1775
     1776                                                $streamName['stream_name']                   = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  $streamName['stream_name_length']));
     1777                                                $offset += $streamName['stream_name_length'];
     1778
     1779                                                $thisObject['stream_names'][$i] = $streamName;
     1780                                        }
     1781
     1782                                        for ($i = 0; $i < $thisObject['payload_extension_system_count']; $i++) {
     1783                                                $payloadExtensionSystem = array();
     1784
     1785                                                $payloadExtensionSystem['extension_system_id']   =                              substr($asf_header_extension_object_data, $offset, 16);
     1786                                                $offset += 16;
     1787                                                $payloadExtensionSystem['extension_system_id_text'] = $this->BytestringToGUID($payloadExtensionSystem['extension_system_id']);
     1788
     1789                                                $payloadExtensionSystem['extension_system_size'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
     1790                                                $offset += 2;
     1791                                                if ($payloadExtensionSystem['extension_system_size'] <= 0) {
     1792                                                        break 2;
     1793                                                }
     1794
     1795                                                $payloadExtensionSystem['extension_system_info_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
     1796                                                $offset += 4;
     1797
     1798                                                $payloadExtensionSystem['extension_system_info_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  $payloadExtensionSystem['extension_system_info_length']));
     1799                                                $offset += $payloadExtensionSystem['extension_system_info_length'];
     1800
     1801                                                $thisObject['payload_extension_systems'][$i] = $payloadExtensionSystem;
     1802                                        }
     1803
     1804                                        break;
     1805
     1806                                case GETID3_ASF_Padding_Object:
     1807                                        // padding, skip it
     1808                                        break;
     1809
     1810                                case GETID3_ASF_Metadata_Object:
     1811                                        $thisObject['description_record_counts'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
     1812                                        $offset += 2;
     1813
     1814                                        for ($i = 0; $i < $thisObject['description_record_counts']; $i++) {
     1815                                                $descriptionRecord = array();
     1816
     1817                                                $descriptionRecord['reserved_1']         = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2)); // must be zero
     1818                                                $offset += 2;
     1819
     1820                                                $descriptionRecord['stream_number']      = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
     1821                                                $offset += 2;
     1822
     1823                                                $descriptionRecord['name_length']        = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
     1824                                                $offset += 2;
     1825
     1826                                                $descriptionRecord['data_type']          = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
     1827                                                $offset += 2;
     1828                                                $descriptionRecord['data_type_text'] = $this->ASFmetadataLibraryObjectDataTypeLookup($descriptionRecord['data_type']);
     1829
     1830                                                $descriptionRecord['data_length']        = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
     1831                                                $offset += 4;
     1832
     1833                                                $descriptionRecord['name']               =                              substr($asf_header_extension_object_data, $offset,  $descriptionRecord['name_length']);
     1834                                                $offset += $descriptionRecord['name_length'];
     1835
     1836                                                $descriptionRecord['data']               =                              substr($asf_header_extension_object_data, $offset,  $descriptionRecord['data_length']);
     1837                                                $offset += $descriptionRecord['data_length'];
     1838                                                switch ($descriptionRecord['data_type']) {
     1839                                                        case 0x0000: // Unicode string
     1840                                                                break;
     1841
     1842                                                        case 0x0001: // BYTE array
     1843                                                                // do nothing
     1844                                                                break;
     1845
     1846                                                        case 0x0002: // BOOL
     1847                                                                $descriptionRecord['data'] = (bool) getid3_lib::LittleEndian2Int($descriptionRecord['data']);
     1848                                                                break;
     1849
     1850                                                        case 0x0003: // DWORD
     1851                                                        case 0x0004: // QWORD
     1852                                                        case 0x0005: // WORD
     1853                                                                $descriptionRecord['data'] = getid3_lib::LittleEndian2Int($descriptionRecord['data']);
     1854                                                                break;
     1855
     1856                                                        case 0x0006: // GUID
     1857                                                                $descriptionRecord['data_text'] = $this->BytestringToGUID($descriptionRecord['data']);
     1858                                                                break;
     1859                                                }
     1860
     1861                                                $thisObject['description_record'][$i] = $descriptionRecord;
     1862                                        }
     1863                                        break;
     1864
     1865                                case GETID3_ASF_Language_List_Object:
     1866                                        $thisObject['language_id_record_counts'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
     1867                                        $offset += 2;
     1868
     1869                                        for ($i = 0; $i < $thisObject['language_id_record_counts']; $i++) {
     1870                                                $languageIDrecord = array();
     1871
     1872                                                $languageIDrecord['language_id_length']         = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  1));
     1873                                                $offset += 1;
     1874
     1875                                                $languageIDrecord['language_id']                =                              substr($asf_header_extension_object_data, $offset,  $languageIDrecord['language_id_length']);
     1876                                                $offset += $languageIDrecord['language_id_length'];
     1877
     1878                                                $thisObject['language_id_record'][$i] = $languageIDrecord;
     1879                                        }
     1880                                        break;
     1881
     1882                                case GETID3_ASF_Metadata_Library_Object:
     1883                                        $thisObject['description_records_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
     1884                                        $offset += 2;
     1885
     1886                                        for ($i = 0; $i < $thisObject['description_records_count']; $i++) {
     1887                                                $descriptionRecord = array();
     1888
     1889                                                $descriptionRecord['language_list_index'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
     1890                                                $offset += 2;
     1891
     1892                                                $descriptionRecord['stream_number']       = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
     1893                                                $offset += 2;
     1894
     1895                                                $descriptionRecord['name_length']         = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
     1896                                                $offset += 2;
     1897
     1898                                                $descriptionRecord['data_type']           = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  2));
     1899                                                $offset += 2;
     1900                                                $descriptionRecord['data_type_text'] = $this->ASFmetadataLibraryObjectDataTypeLookup($descriptionRecord['data_type']);
     1901
     1902                                                $descriptionRecord['data_length']         = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset,  4));
     1903                                                $offset += 4;
     1904
     1905                                                $descriptionRecord['name']                =                              substr($asf_header_extension_object_data, $offset,  $descriptionRecord['name_length']);
     1906                                                $offset += $descriptionRecord['name_length'];
     1907
     1908                                                $descriptionRecord['data']                =                              substr($asf_header_extension_object_data, $offset,  $descriptionRecord['data_length']);
     1909                                                $offset += $descriptionRecord['data_length'];
     1910
     1911                                                if (preg_match('#^WM/Picture$#', str_replace("\x00", '', trim($descriptionRecord['name'])))) {
     1912                                                        $WMpicture = $this->ASF_WMpicture($descriptionRecord['data']);
     1913                                                        foreach ($WMpicture as $key => $value) {
     1914                                                                $descriptionRecord['data'] = $WMpicture;
     1915                                                        }
     1916                                                        unset($WMpicture);
     1917                                                }
     1918
     1919                                                $thisObject['description_record'][$i] = $descriptionRecord;
     1920                                        }
     1921                                        break;
     1922
     1923                                default:
     1924                                        $unhandled_sections++;
     1925                                        if ($this->GUIDname($thisObject['guid_text'])) {
     1926                                                $this->getid3->info['warning'][] = 'unhandled Header Extension Object GUID "'.$this->GUIDname($thisObject['guid_text']).'" {'.$thisObject['guid_text'].'} at offset '.($offset - 16 - 8);
     1927                                        } else {
     1928                                                $this->getid3->info['warning'][] = 'unknown Header Extension Object GUID {'.$thisObject['guid_text'].'} in at offset '.($offset - 16 - 8);
     1929                                        }
     1930                                        break;
     1931                        }
     1932                        $HeaderExtensionObjectParsed[] = $thisObject;
     1933
     1934                        $objectOffset += $thisObject['size'];
     1935                }
     1936                return $HeaderExtensionObjectParsed;
     1937        }
     1938
     1939
     1940        static function ASFmetadataLibraryObjectDataTypeLookup($id) {
     1941                static $ASFmetadataLibraryObjectDataTypeLookup = array(
     1942                        0x0000 => 'Unicode string', // The data consists of a sequence of Unicode characters
     1943                        0x0001 => 'BYTE array',     // The type of the data is implementation-specific
     1944                        0x0002 => 'BOOL',           // The data is 2 bytes long and should be interpreted as a 16-bit unsigned integer. Only 0x0000 or 0x0001 are permitted values
     1945                        0x0003 => 'DWORD',          // The data is 4 bytes long and should be interpreted as a 32-bit unsigned integer
     1946                        0x0004 => 'QWORD',          // The data is 8 bytes long and should be interpreted as a 64-bit unsigned integer
     1947                        0x0005 => 'WORD',           // The data is 2 bytes long and should be interpreted as a 16-bit unsigned integer
     1948                        0x0006 => 'GUID',           // The data is 16 bytes long and should be interpreted as a 128-bit GUID
     1949                );
     1950                return (isset($ASFmetadataLibraryObjectDataTypeLookup[$id]) ? $ASFmetadataLibraryObjectDataTypeLookup[$id] : 'invalid');
     1951        }
     1952
     1953        function ASF_WMpicture(&$data) {
     1954                //typedef struct _WMPicture{
     1955                //  LPWSTR  pwszMIMEType;
     1956                //  BYTE  bPictureType;
     1957                //  LPWSTR  pwszDescription;
     1958                //  DWORD  dwDataLen;
     1959                //  BYTE*  pbData;
     1960                //} WM_PICTURE;
     1961
     1962                $WMpicture = array();
     1963
     1964                $offset = 0;
     1965                $WMpicture['image_type_id'] = getid3_lib::LittleEndian2Int(substr($data, $offset, 1));
     1966                $offset += 1;
     1967                $WMpicture['image_type']    = $this->WMpictureTypeLookup($WMpicture['image_type_id']);
     1968                $WMpicture['image_size']    = getid3_lib::LittleEndian2Int(substr($data, $offset, 4));
     1969                $offset += 4;
     1970
     1971                $WMpicture['image_mime'] = '';
     1972                do {
     1973                        $next_byte_pair = substr($data, $offset, 2);
     1974                        $offset += 2;
     1975                        $WMpicture['image_mime'] .= $next_byte_pair;
     1976                } while ($next_byte_pair !== "\x00\x00");
     1977
     1978                $WMpicture['image_description'] = '';
     1979                do {
     1980                        $next_byte_pair = substr($data, $offset, 2);
     1981                        $offset += 2;
     1982                        $WMpicture['image_description'] .= $next_byte_pair;
     1983                } while ($next_byte_pair !== "\x00\x00");
     1984
     1985                $WMpicture['dataoffset'] = $offset;
     1986                $WMpicture['data'] = substr($data, $offset);
     1987
     1988                $imageinfo = array();
     1989                $WMpicture['image_mime'] = '';
     1990                $imagechunkcheck = getid3_lib::GetDataImageSize($WMpicture['data'], $imageinfo);
     1991                unset($imageinfo);
     1992                if (!empty($imagechunkcheck)) {
     1993                        $WMpicture['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]);
     1994                }
     1995                if (!isset($this->getid3->info['asf']['comments']['picture'])) {
     1996                        $this->getid3->info['asf']['comments']['picture'] = array();
     1997                }
     1998                $this->getid3->info['asf']['comments']['picture'][] = array('data'=>$WMpicture['data'], 'image_mime'=>$WMpicture['image_mime']);
     1999
     2000                return $WMpicture;
     2001        }
     2002
    16882003
    16892004        // Remove terminator 00 00 and convert UTF-16LE to Latin-1
     
    17022017        }
    17032018
    1704 
    17052019}
    17062020
  • _plugins_/getID3/trunk/getid3/module.audio-video.flv.php

    r51852 r62460  
    7070class getid3_flv extends getid3_handler
    7171{
     72        var $max_frames = 100000; // break out of the loop if too many frames have been scanned; only scan this many if meta frame does not contain useful duration
     73
    7274        function Analyze() {
    7375                $info = &$this->getid3->info;
     
    8183                $info['flv']['header']['signature'] =                           substr($FLVheader, 0, 3);
    8284                $info['flv']['header']['version']   = getid3_lib::BigEndian2Int(substr($FLVheader, 3, 1));
    83                 $TypeFlags                                  = getid3_lib::BigEndian2Int(substr($FLVheader, 4, 1));
     85                $TypeFlags                          = getid3_lib::BigEndian2Int(substr($FLVheader, 4, 1));
    8486
    8587                $magic = 'FLV';
     
    103105                $found_audio = false;
    104106                $found_meta  = false;
    105                 $tagParsed = 0;
    106                 while (((ftell($this->getid3->fp) + 16) < $info['avdataend']) && ($tagParsed <= 20 || !$found_meta))  {
     107                $found_valid_meta_playtime = false;
     108                $tagParseCount = 0;
     109                $info['flv']['framecount'] = array('total'=>0, 'audio'=>0, 'video'=>0);
     110                $flv_framecount = &$info['flv']['framecount'];
     111                while (((ftell($this->getid3->fp) + 16) < $info['avdataend']) && (($tagParseCount++ <= $this->max_frames) || !$found_valid_meta_playtime))  {
    107112                        $ThisTagHeader = fread($this->getid3->fp, 16);
    108113
     
    117122                        }
    118123
     124                        $flv_framecount['total']++;
    119125                        switch ($TagType) {
    120126                                case GETID3_FLV_TAG_AUDIO:
     127                                        $flv_framecount['audio']++;
    121128                                        if (!$found_audio) {
    122129                                                $found_audio = true;
     
    129136
    130137                                case GETID3_FLV_TAG_VIDEO:
     138                                        $flv_framecount['video']++;
    131139                                        if (!$found_video) {
    132140                                                $found_video = true;
     
    252260                                                                                break;
    253261                                                                        case 'audiodatarate':
    254                                                                                 $info['audio'][$destkey] = $info['flv']['meta']['onMetaData'][$sourcekey];
     262                                                                                $info['audio'][$destkey] = getid3_lib::CastAsInt(round($info['flv']['meta']['onMetaData'][$sourcekey] * 1000));
    255263                                                                                break;
    256264                                                                        case 'videodatarate':
     
    262270                                                        }
    263271                                                }
     272                                                if (!empty($info['flv']['meta']['onMetaData']['duration'])) {
     273                                                        $found_valid_meta_playtime = true;
     274                                                }
    264275                                        }
    265276                                        break;
     
    269280                                        break;
    270281                        }
    271 
    272282                        fseek($this->getid3->fp, $NextOffset, SEEK_SET);
    273 
    274                         // Increase parsed tag count: break out of loop if more than 20 tags parsed
    275                         $tagParsed++;
    276283                }
    277284
     
    297304
    298305                // Set information from meta
    299                 if (isset($info['flv']['meta']['onMetaData']['duration'])) {
     306                if (!empty($info['flv']['meta']['onMetaData']['duration'])) {
    300307                        $info['playtime_seconds'] = $info['flv']['meta']['onMetaData']['duration'];
    301308                        $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
  • _plugins_/getID3/trunk/getid3/module.audio-video.matroska.php

    r51852 r62460  
    113113define('EBML_ID_TAGCHAPTERUID',                 0x23C4); //         [63][C4] -- A unique ID to identify the Chapter(s) the tags belong to. If the value is 0 at this level, the tags apply to all chapters in the Segment.
    114114define('EBML_ID_TAGTRACKUID',                   0x23C5); //         [63][C5] -- A unique ID to identify the Track(s) the tags belong to. If the value is 0 at this level, the tags apply to all tracks in the Segment.
    115 define('EBML_ID_ATTACHMENTUID',                 0x23C6); //         [63][C6] -- A unique ID to identify the Attachment(s) the tags belong to. If the value is 0 at this level, the tags apply to all the attachments in the Segment.
     115define('EBML_ID_TAGATTACHMENTUID',              0x23C6); //         [63][C6] -- A unique ID to identify the Attachment(s) the tags belong to. If the value is 0 at this level, the tags apply to all the attachments in the Segment.
    116116define('EBML_ID_TAGEDITIONUID',                 0x23C9); //         [63][C9] -- A unique ID to identify the EditionEntry(s) the tags belong to. If the value is 0 at this level, the tags apply to all editions in the Segment.
    117117define('EBML_ID_TARGETTYPE',                    0x23CA); //         [63][CA] -- An informational string that can be used to display the logical level of the target like "ALBUM", "TRACK", "MOVIE", "CHAPTER", etc (see TargetType).
     
    209209class getid3_matroska extends getid3_handler
    210210{
    211         var $read_buffer_size   = 32768; // size of read buffer, 32kB is default
    212         var $hide_clusters      = true;  // if true, do not return information about CLUSTER chunks, since there's a lot of them and they're not usually useful
    213         var $warnings           = array();
    214         var $inline_attachments = true;  // true: return full data for all attachments; false: return no data for all attachments; integer: return data for attachments <= than this; string: save as file to this directory
    215 
    216         function Analyze() {
     211        // public options
     212        public static $hide_clusters      = true;  // if true, do not return information about CLUSTER chunks, since there's a lot of them and they're not usually useful [default: TRUE]
     213    public static $parse_whole_file   = false; // true to parse the whole file, not only header [default: FALSE]
     214
     215    // private parser settings/placeholders
     216    private $EBMLbuffer        = '';
     217    private $EBMLbuffer_offset = 0;
     218    private $EBMLbuffer_length = 0;
     219    private $current_offset    = 0;
     220    private $unuseful_elements = array(EBML_ID_CRC32, EBML_ID_VOID);
     221   
     222        public function Analyze()
     223        {
    217224                $info = &$this->getid3->info;
    218225
     226                // parse container
     227                try {
     228                        $this->parseEBML($info);
     229                }
     230                catch (Exception $e) {
     231                        $info['error'][] = 'EBML parser: '.$e->getMessage();
     232                }
     233
     234                // calculate playtime
     235                if (isset($info['matroska']['info']) && is_array($info['matroska']['info'])) {
     236                        foreach ($info['matroska']['info'] as $key => $infoarray) {
     237                                if (isset($infoarray['Duration'])) {
     238                                        // TimecodeScale is how many nanoseconds each Duration unit is
     239                                        $info['playtime_seconds'] = $infoarray['Duration'] * ((isset($infoarray['TimecodeScale']) ? $infoarray['TimecodeScale'] : 1000000) / 1000000000);
     240                                        break;
     241                                }
     242                        }
     243                }
     244
     245                // extract tags
     246                if (isset($info['matroska']['tags']) && is_array($info['matroska']['tags'])) {
     247                        foreach ($info['matroska']['tags'] as $key => $infoarray) {
     248                                $this->ExtractCommentsSimpleTag($infoarray);
     249                        }
     250                }
     251
     252                // process tracks
     253                if (isset($info['matroska']['tracks']['tracks']) && is_array($info['matroska']['tracks']['tracks'])) {
     254                        foreach ($info['matroska']['tracks']['tracks'] as $key => $trackarray) {
     255                               
     256                                $track_info = array();
     257                                $track_info['dataformat'] = self::MatroskaCodecIDtoCommonName($trackarray['CodecID']);
     258                                $track_info['default'] = (isset($trackarray['FlagDefault']) ? $trackarray['FlagDefault'] : true);
     259                                if (isset($trackarray['Name'])) { $track_info['name'] = $trackarray['Name']; }
     260                               
     261                                switch ($trackarray['TrackType']) {
     262                                       
     263                                        case 1: // Video
     264                                                $track_info['resolution_x'] = $trackarray['PixelWidth'];
     265                                                $track_info['resolution_y'] = $trackarray['PixelHeight'];
     266                                                if (isset($trackarray['DisplayWidth']))    { $track_info['display_x']  = $trackarray['DisplayWidth']; }
     267                                                if (isset($trackarray['DisplayHeight']))   { $track_info['display_y']  = $trackarray['DisplayHeight']; }
     268                                                if (isset($trackarray['DefaultDuration'])) { $track_info['frame_rate'] = round(1000000000 / $trackarray['DefaultDuration'], 3); }
     269                                                //if (isset($trackarray['CodecName']))       { $track_info['codec']      = $trackarray['CodecName']; }
     270                                               
     271                                                switch ($trackarray['CodecID']) {
     272                                                        case 'V_MS/VFW/FOURCC':
     273                                                                if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, false)) {
     274                                                                        $this->getid3->warning('Unable to parse codec private data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio-video.riff.php"');
     275                                                                        break;
     276                                                                }
     277                                                                $parsed = getid3_riff::ParseBITMAPINFOHEADER($trackarray['CodecPrivate']);
     278                                                                $track_info['codec'] = getid3_riff::RIFFfourccLookup($parsed['fourcc']);
     279                                                                $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $parsed;
     280                                                                break;
     281                                                }
     282                                               
     283                                                $info['video']['streams'][] = $track_info;
     284                                                break;
     285                                       
     286                                        case 2: // Audio
     287                                                $track_info['sample_rate'] = (isset($trackarray['SamplingFrequency']) ? $trackarray['SamplingFrequency'] : 8000.0);
     288                                                $track_info['channels']    = (isset($trackarray['Channels']) ? $trackarray['Channels'] : 1);
     289                                                $track_info['language']    = (isset($trackarray['Language']) ? $trackarray['Language'] : 'eng');
     290                                                if (isset($trackarray['BitDepth']))  { $track_info['bits_per_sample'] = $trackarray['BitDepth']; }
     291                                                //if (isset($trackarray['CodecName'])) { $track_info['codec']           = $trackarray['CodecName']; }
     292                                               
     293                                                switch ($trackarray['CodecID']) {
     294                                                        case 'A_PCM/INT/LIT':
     295                                                        case 'A_PCM/INT/BIG':
     296                                                                $track_info['bitrate'] = $trackarray['SamplingFrequency'] * $trackarray['Channels'] * $trackarray['BitDepth'];
     297                                                                break;
     298
     299                                                        case 'A_AC3':
     300                                                        case 'A_DTS':
     301                                                        case 'A_MPEG/L3':
     302                                                        //case 'A_FLAC':
     303                                                                if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.'.$track_info['dataformat'].'.php', __FILE__, false)) {
     304                                                                        $this->getid3->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio.'.$track_info['dataformat'].'.php"');
     305                                                                        break;
     306                                                                }
     307
     308                                                                if (!isset($info['matroska']['track_data_offsets'][$trackarray['TrackNumber']])) {
     309                                                                        $this->getid3->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because $info[matroska][track_data_offsets]['.$trackarray['TrackNumber'].'] not set');
     310                                                                        break;
     311                                                                }
     312
     313                                                                // create temp instance
     314                                                                $getid3_temp = new getID3();
     315                                                                $getid3_temp->openfile($this->getid3->filename);
     316                                                                $getid3_temp->info['avdataoffset'] = $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['offset'];
     317                                                                if ($track_info['dataformat'] == 'mp3' || $track_info['dataformat'] == 'flac') {
     318                                                                        $getid3_temp->info['avdataend'] = $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['offset'] + $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['length'];
     319                                                                }
     320
     321                                                                // analyze
     322                                                                $class = 'getid3_'.$track_info['dataformat'];
     323                                                                $header_data_key = $track_info['dataformat'] == 'mp3' ? 'mpeg' : $track_info['dataformat'];
     324                                                                $getid3_audio = new $class($getid3_temp);
     325                                                                if ($track_info['dataformat'] == 'mp3') {
     326                                                                        $getid3_audio->allow_bruteforce = true;
     327                                                                }
     328                                                                if ($track_info['dataformat'] == 'flac') {
     329                                                                        $getid3_audio->AnalyzeString($trackarray['CodecPrivate']);
     330                                                                }
     331                                                                else {
     332                                                                        $getid3_audio->Analyze();
     333                                                                }
     334                                                                if (!empty($getid3_temp->info[$header_data_key])) {
     335                                                                        unset($getid3_temp->info[$header_data_key]['GETID3_VERSION']);
     336                                                                        $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info[$header_data_key];
     337                                                                        if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) {
     338                                                                                foreach ($getid3_temp->info['audio'] as $key => $value) {
     339                                                                                        $track_info[$key] = $value;
     340                                                                                }
     341                                                                        }
     342                                                                }
     343                                                                else {
     344                                                                        $this->getid3->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because '.$class.'::Analyze() failed at offset '.$getid3_temp->info['avdataoffset']);
     345                                                                }
     346
     347                                                                // copy errors and warnings
     348                                                                if (!empty($getid3_temp->info['error'])) {
     349                                                                        foreach ($getid3_temp->info['error'] as $newerror) {
     350                                                                                $this->getid3->warning($class.'() says: ['.$newerror.']');
     351                                                                        }
     352                                                                }
     353                                                                if (!empty($getid3_temp->info['warning'])) {
     354                                                                        foreach ($getid3_temp->info['warning'] as $newerror) {
     355                                                                                if ($track_info['dataformat'] == 'mp3' && preg_match('/^Probable truncated file: expecting \d+ bytes of audio data, only found \d+ \(short by \d+ bytes\)$/', $newerror)) {
     356                                                                                        // LAME/Xing header is probably set, but audio data is chunked into Matroska file and near-impossible to verify if audio stream is complete, so ignore useless warning
     357                                                                                        continue;
     358                                                                                }
     359                                                                                $this->getid3->warning($class.'() says: ['.$newerror.']');
     360                                                                        }
     361                                                                }
     362                                                                unset($getid3_temp, $getid3_audio);
     363                                                                break;
     364
     365                                                        case 'A_AAC':
     366                                                        case 'A_AAC/MPEG2/LC':
     367                                                        case 'A_AAC/MPEG4/LC':
     368                                                        case 'A_AAC/MPEG4/LC/SBR':
     369                                                            $this->getid3->warning($trackarray['CodecID'].' audio data contains no header, audio/video bitrates can\'t be calculated');
     370                                                                break;
     371
     372                                                        case 'A_VORBIS':
     373                                                                if (!isset($trackarray['CodecPrivate'])) {
     374                                                                        $this->getid3->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because CodecPrivate data not set');
     375                                                                        break;
     376                                                                }
     377                                                                $vorbis_offset = strpos($trackarray['CodecPrivate'], 'vorbis', 1);
     378                                                                if ($vorbis_offset === false) {
     379                                                                        $this->getid3->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because CodecPrivate data does not contain "vorbis" keyword');
     380                                                                        break;
     381                                                                }
     382                                                                $vorbis_offset -= 1;
     383
     384                                                                if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ogg.php', __FILE__, false)) {
     385                                                                        $this->getid3->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio.ogg.php"');
     386                                                                }
     387
     388                                                                // create temp instance
     389                                                                $getid3_temp = new getID3();
     390                                                                $getid3_temp->openfile($this->getid3->filename);
     391
     392                                                                // analyze
     393                                                                $getid3_ogg = new getid3_ogg($getid3_temp);
     394                                                                $oggpageinfo['page_seqno'] = 0;
     395                                                                $getid3_ogg->ParseVorbisPageHeader($trackarray['CodecPrivate'], $vorbis_offset, $oggpageinfo);
     396                                                                if (!empty($getid3_temp->info['ogg'])) {
     397                                                                        $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info['ogg'];
     398                                                                        if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) {
     399                                                                                foreach ($getid3_temp->info['audio'] as $key => $value) {
     400                                                                                        $track_info[$key] = $value;
     401                                                                                }
     402                                                                        }
     403                                                                }
     404                                                               
     405                                                                // copy errors and warnings
     406                                                                if (!empty($getid3_temp->info['error'])) {
     407                                                                        foreach ($getid3_temp->info['error'] as $newerror) {
     408                                                                                $this->getid3->warning('getid3_ogg() says: ['.$newerror.']');
     409                                                                        }
     410                                                                }
     411                                                                if (!empty($getid3_temp->info['warning'])) {
     412                                                                        foreach ($getid3_temp->info['warning'] as $newerror) {
     413                                                                                $this->getid3->warning('getid3_ogg() says: ['.$newerror.']');
     414                                                                        }
     415                                                                }
     416                                                               
     417                                                                if (!empty($getid3_temp->info['ogg']['bitrate_nominal'])) {
     418                                                                        $track_info['bitrate'] = $getid3_temp->info['ogg']['bitrate_nominal'];
     419                                                                }
     420                                                                unset($getid3_temp, $getid3_ogg, $oggpageinfo, $vorbis_offset);
     421                                                                break;
     422
     423                                                        case 'A_MS/ACM':
     424                                                                if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, false)) {
     425                                                                        $this->getid3->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio-video.riff.php"');
     426                                                                        break;
     427                                                                }
     428                                                               
     429                                                                $parsed = getid3_riff::RIFFparseWAVEFORMATex($trackarray['CodecPrivate']);
     430                                                                foreach ($parsed as $key => $value) {
     431                                                                        if ($key != 'raw') {
     432                                                                                $track_info[$key] = $value;
     433                                                                        }
     434                                                                }
     435                                                                $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $parsed;
     436                                                                break;
     437                                                               
     438                                                        default:
     439                                                                $this->getid3->warning('Unhandled audio type "'.(isset($trackarray['CodecID']) ? $trackarray['CodecID'] : '').'"');
     440                                                }
     441
     442                                                $info['audio']['streams'][] = $track_info;
     443                                                break;
     444                                }
     445                        }
     446               
     447                        if (!empty($info['video']['streams'])) {
     448                                $info['video'] = self::getDefaultStreamInfo($info['video']['streams']);
     449                        }
     450                        if (!empty($info['audio']['streams'])) {
     451                                $info['audio'] = self::getDefaultStreamInfo($info['audio']['streams']);
     452                        }
     453                }
     454
     455        // determine mime type
     456                if (!empty($info['video']['streams'])) {
     457                        $info['mime_type'] = ($info['matroska']['doctype'] == 'webm' ? 'video/webm' : 'video/x-matroska');
     458                } elseif (!empty($info['audio']['streams'])) {
     459                        $info['mime_type'] = ($info['matroska']['doctype'] == 'webm' ? 'audio/webm' : 'audio/x-matroska');
     460                } elseif (isset($info['mime_type'])) {
     461                        unset($info['mime_type']);
     462                }
     463
     464                return true;
     465        }
     466
     467
     468///////////////////////////////////////
     469
     470    private function parseEBML(&$info)
     471    {
    219472                // http://www.matroska.org/technical/specs/index.html#EBMLBasics
    220                 $offset = $info['avdataoffset'];
    221                 $EBMLdata = '';
    222                 $EBMLdata_offset = $offset;
    223 
    224                 if (!getid3_lib::intValueSupported($info['avdataend'])) {
    225                         $this->warnings[] = 'This version of getID3() ['.$this->getid3->version().'] may or may not correctly handle Matroska files larger than '.round(PHP_INT_MAX / 1073741824).'GB';
    226                 }
    227 
    228                 while ($offset < $info['avdataend']) {
    229                         $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
    230 
    231                         $top_element_offset    = $offset;
    232                         $top_element_id        = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    233                         $top_element_length    = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    234                         if ($top_element_length === false) {
    235                                 $this->warnings[] = 'invalid chunk length at '.$top_element_offset;
    236                                 $offset = PHP_INT_MAX + 1;
    237                                 break;
    238                         }
    239                         $top_element_endoffset = $offset + $top_element_length;
    240                         switch ($top_element_id) {
     473                $this->current_offset = $info['avdataoffset'];
     474
     475                while ($this->getEBMLelement($top_element, $info['avdataend'])) {
     476                        switch ($top_element['id']) {
     477
    241478                                case EBML_ID_EBML:
    242479                                        $info['fileformat'] = 'matroska';
    243                                         $info['matroska']['header']['offset'] = $top_element_offset;
    244                                         $info['matroska']['header']['length'] = $top_element_length;
    245 
    246                                         while ($offset < $top_element_endoffset) {
    247                                                 $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
    248                                                 $element_data = array();
    249                                                 $element_data_offset     = $offset;
    250                                                 $element_data['id']      = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    251                                                 $element_data['id_name'] = $this->EBMLidName($element_data['id']);
    252                                                 $element_data['length']     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    253                                                 $end_offset              = $offset + $element_data['length'];
    254 
     480                                        $info['matroska']['header']['offset'] = $top_element['offset'];
     481                                        $info['matroska']['header']['length'] = $top_element['length'];
     482
     483                                        while ($this->getEBMLelement($element_data, $top_element['end'], true)) {
    255484                                                switch ($element_data['id']) {
    256                                                         case EBML_ID_VOID:    // padding, ignore
    257                                                                 break;
     485
    258486                                                        case EBML_ID_EBMLVERSION:
    259487                                                        case EBML_ID_EBMLREADVERSION:
     
    262490                                                        case EBML_ID_DOCTYPEVERSION:
    263491                                                        case EBML_ID_DOCTYPEREADVERSION:
    264                                                                 $element_data['data'] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $element_data['length']));
     492                                                                $element_data['data'] = getid3_lib::BigEndian2Int($element_data['data']);
    265493                                                                break;
     494
    266495                                                        case EBML_ID_DOCTYPE:
    267                                                                 $element_data['data'] =                      trim(substr($EBMLdata, $offset - $EBMLdata_offset, $element_data['length']), "\x00");
     496                                                                $element_data['data'] = getid3_lib::trimNullByte($element_data['data']);
     497                                                                $info['matroska']['doctype'] = $element_data['data'];
    268498                                                                break;
    269                                                         case EBML_ID_CRC32:
    270                                                                 // probably not useful, ignore
     499
     500                                                        case EBML_ID_CRC32: // not useful, ignore
     501                                                                $this->current_offset = $element_data['end'];
    271502                                                                unset($element_data);
    272503                                                                break;
     504
    273505                                                        default:
    274                                                                 $this->warnings[] = 'Unhandled track.video element ['.basename(__FILE__).':'.__LINE__.'] ('.$element_data['id'].'::'.$element_data['id_name'].') at '.$element_data_offset;
    275                                                                 break;
     506                                                                $this->unhandledElement('header', __LINE__, $element_data);
    276507                                                }
    277                                                 $offset = $end_offset;
    278508                                                if (!empty($element_data)) {
     509                                                        unset($element_data['offset'], $element_data['end']);
    279510                                                        $info['matroska']['header']['elements'][] = $element_data;
    280511                                                }
     
    282513                                        break;
    283514
    284 
    285515                                case EBML_ID_SEGMENT:
    286                                         $info['matroska']['segment'][0]['offset'] = $top_element_offset;
    287                                         $info['matroska']['segment'][0]['length'] = $top_element_length;
    288 
    289                                         $segment_key = -1;
    290                                         while ($offset < $info['avdataend']) {
    291                                                 $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
    292 
    293                                                 $element_data = array();
    294                                                 $element_data['offset']  = $offset;
    295                                                 $element_data['id']      = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    296                                                 $element_data['id_name'] = $this->EBMLidName($element_data['id']);
    297                                                 $element_data['length']  = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    298                                                 if ($element_data['length'] === false) {
    299                                                         $this->warnings[] = 'invalid chunk length at '.$element_data['offset'];
    300                                                         //$offset = PHP_INT_MAX + 1;
    301                                                         $offset = $info['avdataend'];
    302                                                         break;
     516                                        $info['matroska']['segment'][0]['offset'] = $top_element['offset'];
     517                                        $info['matroska']['segment'][0]['length'] = $top_element['length'];
     518
     519                                        while ($this->getEBMLelement($element_data, $top_element['end'])) {
     520                                                if ($element_data['id'] != EBML_ID_CLUSTER || !self::$hide_clusters) { // collect clusters only if required
     521                                                        $info['matroska']['segments'][] = $element_data;
    303522                                                }
    304                                                 $element_end             = $offset + $element_data['length'];
    305523                                                switch ($element_data['id']) {
    306                                                         //case EBML_ID_CLUSTER:
    307                                                         //      // too many cluster entries, probably not useful
    308                                                         //      break;
    309                                                         case false:
    310                                                                 $this->warnings[] = 'invalid ID at '.$element_data['offset'];
    311                                                                 $offset = $element_end;
    312                                                                 continue 3;
    313                                                         default:
    314                                                                 $info['matroska']['segments'][] = $element_data;
    315                                                                 break;
    316                                                 }
    317                                                 $segment_key++;
    318 
    319                                                 switch ($element_data['id']) {
    320                                                         case EBML_ID_SEEKHEAD: // Contains the position of other level 1 elements
    321                                                                 while ($offset < $element_end) {
    322                                                                         $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
    323                                                                         $seek_entry = array();
    324                                                                         $seek_entry['offset']  = $offset;
    325                                                                         $seek_entry['id']      = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    326                                                                         $seek_entry['id_name'] = $this->EBMLidName($seek_entry['id']);
    327                                                                         $seek_entry['length']  = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    328                                                                         $seek_end_offset       = $offset + $seek_entry['length'];
     524
     525                                                        case EBML_ID_SEEKHEAD: // Contains the position of other level 1 elements.
     526
     527                                                                while ($this->getEBMLelement($seek_entry, $element_data['end'])) {
    329528                                                                        switch ($seek_entry['id']) {
     529
    330530                                                                                case EBML_ID_SEEK: // Contains a single seek entry to an EBML element
    331                                                                                         while ($offset < $seek_end_offset) {
    332                                                                                                 $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
    333                                                                                                 $id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    334                                                                                                 $length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    335                                                                                                 $value  =             substr($EBMLdata, $offset - $EBMLdata_offset, $length);
    336                                                                                                 $offset += $length;
    337                                                                                                 switch ($id) {
     531                                                                                        while ($this->getEBMLelement($sub_seek_entry, $seek_entry['end'], true)) {
     532
     533                                                                                                switch ($sub_seek_entry['id']) {
     534
    338535                                                                                                        case EBML_ID_SEEKID:
    339                                                                                                                 $dummy = 0;
    340                                                                                                                 $seek_entry['target_id']   = $this->readEBMLint($value, $dummy);
    341                                                                                                                 $seek_entry['target_name'] = $this->EBMLidName($seek_entry['target_id']);
    342                                                                                                                 break;
     536                                                                                                                $seek_entry['target_id']   = self::EBML2Int($sub_seek_entry['data']);
     537                                                                                                                $seek_entry['target_name'] = self::EBMLidName($seek_entry['target_id']);
     538                                                                                                                break;
     539
    343540                                                                                                        case EBML_ID_SEEKPOSITION:
    344                                                                                                                 $seek_entry['target_offset'] = $element_data['offset'] + getid3_lib::BigEndian2Int($value);
    345                                                                                                                 break;
    346                                                                                                         case EBML_ID_CRC32:
    347                                                                                                                 // probably not useful, ignore
    348                                                                                                                 //$seek_entry['crc32'] = getid3_lib::PrintHexBytes($value, true, false, false);
    349                                                                                                                 unset($seek_entry);
    350                                                                                                                 break;
     541                                                                                                                $seek_entry['target_offset'] = $element_data['offset'] + getid3_lib::BigEndian2Int($sub_seek_entry['data']);
     542                                                                                                                break;
     543
    351544                                                                                                        default:
    352                                                                                                                 $info['error'][] = 'Unhandled segment ['.basename(__FILE__).':'.__LINE__.'] ('.$id.') at '.$offset;
    353                                                                                                                 break;
    354                                                                                                 }
     545                                                                                                                $this->unhandledElement('seekhead.seek', __LINE__, $sub_seek_entry);                                                                                            }
    355546                                                                                        }
    356                                                                                         if (!empty($seek_entry)) {
     547
     548                                                                                        if ($seek_entry['target_id'] != EBML_ID_CLUSTER || !self::$hide_clusters) { // collect clusters only if required
    357549                                                                                                $info['matroska']['seek'][] = $seek_entry;
    358550                                                                                        }
    359                                                                                         //switch ($seek_entry['target_id']) {
    360                                                                                         //      case EBML_ID_CLUSTER:
    361                                                                                         //              // too many cluster seek points, probably not useful
    362                                                                                         //              break;
    363                                                                                         //      default:
    364                                                                                         //              $info['matroska']['seek'][] = $seek_entry;
    365                                                                                         //              break;
    366                                                                                         //}
    367551                                                                                        break;
    368                                                                                 case EBML_ID_CRC32:
    369                                                                                         // probably not useful, ignore
    370                                                                                         break;
     552
    371553                                                                                default:
    372                                                                                         $this->warnings[] = 'Unhandled seekhead element ['.basename(__FILE__).':'.__LINE__.'] ('.$seek_entry['id'].'::'.$seek_entry['id_name'].') at '.$offset;
    373                                                                                         break;
     554                                                                                        $this->unhandledElement('seekhead', __LINE__, $seek_entry);
    374555                                                                        }
    375                                                                         $offset = $seek_end_offset;
    376556                                                                }
    377557                                                                break;
    378558
    379                                                         case EBML_ID_TRACKS: // information about all tracks in segment
     559                                                        case EBML_ID_TRACKS: // A top-level block of information with many tracks described.
    380560                                                                $info['matroska']['tracks'] = $element_data;
    381                                                                 while ($offset < $element_end) {
    382                                                                         $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
    383                                                                         $track_entry = array();
    384                                                                         $track_entry['offset']  = $offset;
    385                                                                         $track_entry['id']      = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    386                                                                         $track_entry['id_name'] = $this->EBMLidName($track_entry['id']);
    387                                                                         $track_entry['length']  = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    388                                                                         $track_entry_endoffset  = $offset + $track_entry['length']; // $track_entry['offset'] is not the same as $offset, even though they were set equal a few lines up: $offset has been automagically incremented by readEMLint()
     561
     562                                                                while ($this->getEBMLelement($track_entry, $element_data['end'])) {
    389563                                                                        switch ($track_entry['id']) {
     564
    390565                                                                                case EBML_ID_TRACKENTRY: //subelements: Describes a track with all elements.
    391                                                                                         while ($offset < $track_entry_endoffset) {
    392                                                                                                 $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
    393                                                                                                 $subelement_offset = $offset;
    394                                                                                                 $subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    395                                                                                                 $subelement_idname = $this->EBMLidName($subelement_id);
    396                                                                                                 $subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    397                                                                                                 $subelement_end    = $offset + $subelement_length;
    398                                                                                                 switch ($subelement_id) {
     566
     567                                                                                        while ($this->getEBMLelement($subelement, $track_entry['end'], array(EBML_ID_VIDEO, EBML_ID_AUDIO, EBML_ID_CONTENTENCODINGS))) {
     568                                                                                                switch ($subelement['id']) {
     569
    399570                                                                                                        case EBML_ID_TRACKNUMBER:
    400571                                                                                                        case EBML_ID_TRACKUID:
     
    404575                                                                                                        case EBML_ID_MAXBLOCKADDITIONID:
    405576                                                                                                        case EBML_ID_DEFAULTDURATION: // nanoseconds per frame
    406                                                                                                                 $track_entry[$subelement_idname] =        getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length));
     577                                                                                                                $track_entry[$subelement['id_name']] = getid3_lib::BigEndian2Int($subelement['data']);
    407578                                                                                                                break;
    408579
    409580                                                                                                        case EBML_ID_TRACKTIMECODESCALE:
    410                                                                                                                 $track_entry[$subelement_idname] =      getid3_lib::BigEndian2Float(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length));
     581                                                                                                                $track_entry[$subelement['id_name']] = getid3_lib::BigEndian2Float($subelement['data']);
    411582                                                                                                                break;
    412583
     
    415586                                                                                                        case EBML_ID_NAME:
    416587                                                                                                        case EBML_ID_CODECNAME:
     588                                                                                                                $track_entry[$subelement['id_name']] = getid3_lib::trimNullByte($subelement['data']);
     589                                                                                                                break;
     590                                                                                                               
    417591                                                                                                        case EBML_ID_CODECPRIVATE:
    418                                                                                                                 $track_entry[$subelement_idname] =                             trim(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length), "\x00");
    419                                                                                                                 break;
    420 
    421                                                                                                         // thought maybe it was a nice wFormatTag entry, but it's not :(
    422                                                                                                         //case EBML_ID_CODECPRIVATE:
    423                                                                                                                 //$track_entry[$subelement_idname] =                             trim(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length), "\x00");
    424                                                                                                                 //if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, false)) {
    425                                                                                                                 //      $track_entry[$subelement_idname.'_decoded'] = getid3_riff::RIFFparseWAVEFORMATex($track_entry[$subelement_idname]);
    426                                                                                                                 //      if (isset($track_entry[$subelement_idname.'_decoded']['raw']['wFormatTag'])) {
    427                                                                                                                 //      }
    428                                                                                                                 //} else {
    429                                                                                                                 //      $this->warnings[] = 'failed to include "module.audio-video.riff.php" for parsing codec private data';
    430                                                                                                                 //}
    431                                                                                                                 //break;
     592                                                                                                                $track_entry[$subelement['id_name']] = $subelement['data'];
     593                                                                                                                break;
    432594
    433595                                                                                                        case EBML_ID_FLAGENABLED:
     
    436598                                                                                                        case EBML_ID_FLAGLACING:
    437599                                                                                                        case EBML_ID_CODECDECODEALL:
    438                                                                                                                 $track_entry[$subelement_idname] = (bool) getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length));
     600                                                                                                                $track_entry[$subelement['id_name']] = (bool) getid3_lib::BigEndian2Int($subelement['data']);
    439601                                                                                                                break;
    440602
    441603                                                                                                        case EBML_ID_VIDEO:
    442                                                                                                                 while ($offset < $subelement_end) {
    443                                                                                                                         $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
    444                                                                                                                         $sub_subelement_offset = $offset;
    445                                                                                                                         $sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    446                                                                                                                         $sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
    447                                                                                                                         $sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    448                                                                                                                         $sub_subelement_end    = $offset + $sub_subelement_length;
    449                                                                                                                         switch ($sub_subelement_id) {
     604
     605                                                                                                                while ($this->getEBMLelement($sub_subelement, $subelement['end'], true)) {
     606                                                                                                                        switch ($sub_subelement['id']) {
     607
    450608                                                                                                                                case EBML_ID_PIXELWIDTH:
    451609                                                                                                                                case EBML_ID_PIXELHEIGHT:
     
    459617                                                                                                                                case EBML_ID_DISPLAYUNIT:
    460618                                                                                                                                case EBML_ID_ASPECTRATIOTYPE:
    461                                                                                                                                         $track_entry[$sub_subelement_idname] =        getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
     619                                                                                                                                        $track_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
    462620                                                                                                                                        break;
     621
    463622                                                                                                                                case EBML_ID_FLAGINTERLACED:
    464                                                                                                                                         $track_entry[$sub_subelement_idname] = (bool) getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
     623                                                                                                                                        $track_entry[$sub_subelement['id_name']] = (bool)getid3_lib::BigEndian2Int($sub_subelement['data']);
    465624                                                                                                                                        break;
     625
    466626                                                                                                                                case EBML_ID_GAMMAVALUE:
    467                                                                                                                                         $track_entry[$sub_subelement_idname] =      getid3_lib::BigEndian2Float(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
     627                                                                                                                                        $track_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Float($sub_subelement['data']);
    468628                                                                                                                                        break;
     629
    469630                                                                                                                                case EBML_ID_COLOURSPACE:
    470                                                                                                                                         $track_entry[$sub_subelement_idname] =                             trim(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length), "\x00");
     631                                                                                                                                        $track_entry[$sub_subelement['id_name']] = getid3_lib::trimNullByte($sub_subelement['data']);
    471632                                                                                                                                        break;
     633
    472634                                                                                                                                default:
    473                                                                                                                                         $this->warnings[] = 'Unhandled track.video element ['.basename(__FILE__).':'.__LINE__.'] ('.$sub_subelement_id.'::'.$sub_subelement_idname.') at '.$sub_subelement_offset;
    474                                                                                                                                         break;
    475                                                                                                                         }
    476                                                                                                                         $offset = $sub_subelement_end;
    477                                                                                                                 }
    478 
    479                                                                                                                 if (isset($track_entry[$this->EBMLidName(EBML_ID_CODECID)]) && ($track_entry[$this->EBMLidName(EBML_ID_CODECID)] == 'V_MS/VFW/FOURCC') && isset($track_entry[$this->EBMLidName(EBML_ID_CODECPRIVATE)])) {
    480                                                                                                                         if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, false)) {
    481                                                                                                                                 $track_entry['codec_private_parsed'] = getid3_riff::ParseBITMAPINFOHEADER($track_entry[$this->EBMLidName(EBML_ID_CODECPRIVATE)]);
    482                                                                                                                         } else {
    483                                                                                                                                 $this->warnings[] = 'Unable to parse codec private data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio-video.riff.php"';
     635                                                                                                                                        $this->unhandledElement('track.video', __LINE__, $sub_subelement);
    484636                                                                                                                        }
    485637                                                                                                                }
     
    487639
    488640                                                                                                        case EBML_ID_AUDIO:
    489                                                                                                                 while ($offset < $subelement_end) {
    490                                                                                                                         $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
    491                                                                                                                         $sub_subelement_offset = $offset;
    492                                                                                                                         $sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    493                                                                                                                         $sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
    494                                                                                                                         $sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    495                                                                                                                         $sub_subelement_end    = $offset + $sub_subelement_length;
    496                                                                                                                         switch ($sub_subelement_id) {
     641
     642                                                                                                                while ($this->getEBMLelement($sub_subelement, $subelement['end'], true)) {
     643                                                                                                                        switch ($sub_subelement['id']) {
     644
    497645                                                                                                                                case EBML_ID_CHANNELS:
    498646                                                                                                                                case EBML_ID_BITDEPTH:
    499                                                                                                                                         $track_entry[$sub_subelement_idname] =        getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
     647                                                                                                                                        $track_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
    500648                                                                                                                                        break;
     649
    501650                                                                                                                                case EBML_ID_SAMPLINGFREQUENCY:
    502651                                                                                                                                case EBML_ID_OUTPUTSAMPLINGFREQUENCY:
    503                                                                                                                                         $track_entry[$sub_subelement_idname] =      getid3_lib::BigEndian2Float(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
     652                                                                                                                                        $track_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Float($sub_subelement['data']);
    504653                                                                                                                                        break;
     654
    505655                                                                                                                                case EBML_ID_CHANNELPOSITIONS:
    506                                                                                                                                         $track_entry[$sub_subelement_idname] =                             trim(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length), "\x00");
     656                                                                                                                                        $track_entry[$sub_subelement['id_name']] = getid3_lib::trimNullByte($sub_subelement['data']);
    507657                                                                                                                                        break;
     658
    508659                                                                                                                                default:
    509                                                                                                                                         $this->warnings[] = 'Unhandled track.audio element ['.basename(__FILE__).':'.__LINE__.'] ('.$sub_subelement_id.'::'.$sub_subelement_idname.') at '.$sub_subelement_offset;
    510                                                                                                                                         break;
     660                                                                                                                                        $this->unhandledElement('track.audio', __LINE__, $sub_subelement);
    511661                                                                                                                        }
    512                                                                                                                         $offset = $sub_subelement_end;
    513662                                                                                                                }
    514663                                                                                                                break;
    515664
    516665                                                                                                        case EBML_ID_CONTENTENCODINGS:
    517                                                                                                                 while ($offset < $subelement_end) {
    518                                                                                                                         $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
    519                                                                                                                         $sub_subelement_offset = $offset;
    520                                                                                                                         $sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    521                                                                                                                         $sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
    522                                                                                                                         $sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    523                                                                                                                         $sub_subelement_end    = $offset + $sub_subelement_length;
    524                                                                                                                         switch ($sub_subelement_id) {
     666
     667                                                                                                                while ($this->getEBMLelement($sub_subelement, $subelement['end'])) {
     668                                                                                                                        switch ($sub_subelement['id']) {
     669
    525670                                                                                                                                case EBML_ID_CONTENTENCODING:
    526                                                                                                                                         while ($offset < $sub_subelement_end) {
    527                                                                                                                                                 $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
    528                                                                                                                                                 $sub_sub_subelement_offset = $offset;
    529                                                                                                                                                 $sub_sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    530                                                                                                                                                 $sub_sub_subelement_idname = $this->EBMLidName($sub_sub_subelement_id);
    531                                                                                                                                                 $sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    532                                                                                                                                                 $sub_sub_subelement_end    = $offset + $sub_sub_subelement_length;
    533                                                                                                                                                 switch ($sub_sub_subelement_id) {
     671
     672                                                                                                                                        while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], array(EBML_ID_CONTENTCOMPRESSION, EBML_ID_CONTENTENCRYPTION))) {
     673                                                                                                                                                switch ($sub_sub_subelement['id']) {
     674
    534675                                                                                                                                                        case EBML_ID_CONTENTENCODINGORDER:
    535676                                                                                                                                                        case EBML_ID_CONTENTENCODINGSCOPE:
    536677                                                                                                                                                        case EBML_ID_CONTENTENCODINGTYPE:
    537                                                                                                                                                                 $track_entry[$sub_subelement_idname][$sub_sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length));
     678                                                                                                                                                                $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
    538679                                                                                                                                                                break;
     680
    539681                                                                                                                                                        case EBML_ID_CONTENTCOMPRESSION:
    540                                                                                                                                                                 while ($offset < $sub_sub_subelement_end) {
    541                                                                                                                                                                         $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
    542                                                                                                                                                                         $sub_sub_sub_subelement_offset = $offset;
    543                                                                                                                                                                         $sub_sub_sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    544                                                                                                                                                                         $sub_sub_sub_subelement_idname = $this->EBMLidName($sub_sub_subelement_id);
    545                                                                                                                                                                         $sub_sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    546                                                                                                                                                                         $sub_sub_sub_subelement_end    = $offset + $sub_sub_sub_subelement_length;
    547                                                                                                                                                                         switch ($sub_sub_sub_subelement_id) {
     682
     683                                                                                                                                                                while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) {
     684                                                                                                                                                                        switch ($sub_sub_sub_subelement['id']) {
     685
    548686                                                                                                                                                                                case EBML_ID_CONTENTCOMPALGO:
    549                                                                                                                                                                                         $track_entry[$sub_subelement_idname][$sub_sub_subelement_idname][$sub_sub_sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_sub_subelement_length));
     687                                                                                                                                                                                        $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']][$sub_sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_sub_subelement['data']);
    550688                                                                                                                                                                                        break;
     689
    551690                                                                                                                                                                                case EBML_ID_CONTENTCOMPSETTINGS:
    552                                                                                                                                                                                         $track_entry[$sub_subelement_idname][$sub_sub_subelement_idname][$sub_sub_sub_subelement_idname] =                           substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_sub_subelement_length);
     691                                                                                                                                                                                        $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']][$sub_sub_sub_subelement['id_name']] = $sub_sub_sub_subelement['data'];
    553692                                                                                                                                                                                        break;
     693
    554694                                                                                                                                                                                default:
    555                                                                                                                                                                                         $this->warnings[] = 'Unhandled track.contentencodings.contentencoding.contentcompression element ['.basename(__FILE__).':'.__LINE__.'] ('.$subelement_id.'::'.$subelement_idname.' ['.$subelement_length.' bytes]) at '.$subelement_offset;
    556                                                                                                                                                                                         break;
     695                                                                                                                                                                                        $this->unhandledElement('track.contentencodings.contentencoding.contentcompression', __LINE__, $sub_sub_sub_subelement);
    557696                                                                                                                                                                        }
    558                                                                                                                                                                         $offset = $sub_sub_sub_subelement_end;
    559697                                                                                                                                                                }
    560698                                                                                                                                                                break;
    561699
    562700                                                                                                                                                        case EBML_ID_CONTENTENCRYPTION:
    563                                                                                                                                                                 while ($offset < $sub_sub_subelement_end) {
    564                                                                                                                                                                         $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
    565                                                                                                                                                                         $sub_sub_sub_subelement_offset = $offset;
    566                                                                                                                                                                         $sub_sub_sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    567                                                                                                                                                                         $sub_sub_sub_subelement_idname = $this->EBMLidName($sub_sub_subelement_id);
    568                                                                                                                                                                         $sub_sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    569                                                                                                                                                                         $sub_sub_sub_subelement_end    = $offset + $sub_sub_sub_subelement_length;
    570                                                                                                                                                                         switch ($sub_sub_sub_subelement_id) {
     701
     702                                                                                                                                                                while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) {
     703                                                                                                                                                                        switch ($sub_sub_sub_subelement['id']) {
     704
    571705                                                                                                                                                                                case EBML_ID_CONTENTENCALGO:
    572706                                                                                                                                                                                case EBML_ID_CONTENTSIGALGO:
    573707                                                                                                                                                                                case EBML_ID_CONTENTSIGHASHALGO:
    574                                                                                                                                                                                         $track_entry[$sub_subelement_idname][$sub_sub_subelement_idname][$sub_sub_sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_sub_subelement_length));
     708                                                                                                                                                                                        $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']][$sub_sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_sub_subelement['data']);
    575709                                                                                                                                                                                        break;
     710
    576711                                                                                                                                                                                case EBML_ID_CONTENTENCKEYID:
    577712                                                                                                                                                                                case EBML_ID_CONTENTSIGNATURE:
    578713                                                                                                                                                                                case EBML_ID_CONTENTSIGKEYID:
    579                                                                                                                                                                                         $track_entry[$sub_subelement_idname][$sub_sub_subelement_idname][$sub_sub_sub_subelement_idname] =                           substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_sub_subelement_length);
     714                                                                                                                                                                                        $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']][$sub_sub_sub_subelement['id_name']] = $sub_sub_sub_subelement['data'];
    580715                                                                                                                                                                                        break;
     716
    581717                                                                                                                                                                                default:
    582                                                                                                                                                                                         $this->warnings[] = 'Unhandled track.contentencodings.contentencoding.contentcompression element ['.basename(__FILE__).':'.__LINE__.'] ('.$subelement_id.'::'.$subelement_idname.' ['.$subelement_length.' bytes]) at '.$subelement_offset;
    583                                                                                                                                                                                         break;
     718                                                                                                                                                                                        $this->unhandledElement('track.contentencodings.contentencoding.contentcompression', __LINE__, $sub_sub_sub_subelement);
    584719                                                                                                                                                                        }
    585                                                                                                                                                                         $offset = $sub_sub_sub_subelement_end;
    586720                                                                                                                                                                }
    587721                                                                                                                                                                break;
    588722
    589723                                                                                                                                                        default:
    590                                                                                                                                                                 $this->warnings[] = 'Unhandled track.contentencodings.contentencoding element ['.basename(__FILE__).':'.__LINE__.'] ('.$subelement_id.'::'.$subelement_idname.' ['.$subelement_length.' bytes]) at '.$subelement_offset;
    591                                                                                                                                                                 break;
     724                                                                                                                                                                $this->unhandledElement('track.contentencodings.contentencoding', __LINE__, $sub_sub_subelement);
    592725                                                                                                                                                }
    593                                                                                                                                                 $offset = $sub_sub_subelement_end;
    594726                                                                                                                                        }
    595727                                                                                                                                        break;
     728
    596729                                                                                                                                default:
    597                                                                                                                                         $this->warnings[] = 'Unhandled track.contentencodings element ['.basename(__FILE__).':'.__LINE__.'] ('.$subelement_id.'::'.$subelement_idname.' ['.$subelement_length.' bytes]) at '.$subelement_offset;
    598                                                                                                                                         break;
     730                                                                                                                                        $this->unhandledElement('track.contentencodings', __LINE__, $sub_subelement);
    599731                                                                                                                        }
    600                                                                                                                         $offset = $sub_subelement_end;
    601732                                                                                                                }
    602733                                                                                                                break;
    603734
    604                                                                                                         case EBML_ID_CRC32:
    605                                                                                                                 // probably not useful, ignore
    606                                                                                                                 break;
    607 
    608735                                                                                                        default:
    609                                                                                                                 $this->warnings[] = 'Unhandled track element ['.basename(__FILE__).':'.__LINE__.'] ('.$subelement_id.'::'.$subelement_idname.' ['.$subelement_length.' bytes]) at '.$subelement_offset;
    610                                                                                                                 break;
     736                                                                                                                $this->unhandledElement('track', __LINE__, $subelement);
    611737                                                                                                }
    612                                                                                                 $offset = $subelement_end;
    613738                                                                                        }
     739
     740                                                                                        $info['matroska']['tracks']['tracks'][] = $track_entry;
    614741                                                                                        break;
    615742
    616                                                                                 case EBML_ID_CRC32:
    617                                                                                         // probably not useful, ignore
    618                                                                                         $offset = $track_entry_endoffset;
    619                                                                                         break;
    620 
    621743                                                                                default:
    622                                                                                         $this->warnings[] = 'Unhandled track element ['.basename(__FILE__).':'.__LINE__.'] ('.$track_entry['id'].'::'.$track_entry['id_name'].') at '.$track_entry['offset'];
    623                                                                                         $offset = $track_entry_endoffset;
    624                                                                                         break;
     744                                                                                        $this->unhandledElement('tracks', __LINE__, $track_entry);
    625745                                                                        }
    626                                                                         $info['matroska']['tracks']['tracks'][] = $track_entry;
    627746                                                                }
    628747                                                                break;
    629748
    630                                                         case EBML_ID_INFO: // Contains the position of other level 1 elements
     749                                                        case EBML_ID_INFO: // Contains miscellaneous general information and statistics on the file.
    631750                                                                $info_entry = array();
    632                                                                 while ($offset < $element_end) {
    633                                                                         $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
    634                                                                         $subelement_offset = $offset;
    635                                                                         $subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    636                                                                         $subelement_idname = $this->EBMLidName($subelement_id);
    637                                                                         $subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    638                                                                         $subelement_end    = $offset + $subelement_length;
    639                                                                         switch ($subelement_id) {
     751
     752                                                                while ($this->getEBMLelement($subelement, $element_data['end'], true)) {
     753                                                                        switch ($subelement['id']) {
     754
    640755                                                                                case EBML_ID_CHAPTERTRANSLATEEDITIONUID:
    641756                                                                                case EBML_ID_CHAPTERTRANSLATECODEC:
    642757                                                                                case EBML_ID_TIMECODESCALE:
    643                                                                                         $info_entry[$subelement_idname] =        getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length));
     758                                                                                        $info_entry[$subelement['id_name']] = getid3_lib::BigEndian2Int($subelement['data']);
    644759                                                                                        break;
     760
    645761                                                                                case EBML_ID_DURATION:
    646                                                                                         $info_entry[$subelement_idname] =      getid3_lib::BigEndian2Float(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length));
     762                                                                                        $info_entry[$subelement['id_name']] = getid3_lib::BigEndian2Float($subelement['data']);
    647763                                                                                        break;
     764
    648765                                                                                case EBML_ID_DATEUTC:
    649                                                                                         $info_entry[$subelement_idname] =        getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length));
    650                                                                                         $info_entry[$subelement_idname.'_unix'] = $this->EBMLdate2unix($info_entry[$subelement_idname]);
     766                                                                                        $info_entry[$subelement['id_name']]         = getid3_lib::BigEndian2Int($subelement['data']);
     767                                                                                        $info_entry[$subelement['id_name'].'_unix'] = self::EBMLdate2unix($info_entry[$subelement['id_name']]);
    651768                                                                                        break;
     769
    652770                                                                                case EBML_ID_SEGMENTUID:
    653771                                                                                case EBML_ID_PREVUID:
     
    655773                                                                                case EBML_ID_SEGMENTFAMILY:
    656774                                                                                case EBML_ID_CHAPTERTRANSLATEID:
    657                                                                                         $info_entry[$subelement_idname] =                             trim(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length), "\x00");
     775                                                                                        $info_entry[$subelement['id_name']] = getid3_lib::trimNullByte($subelement['data']);
    658776                                                                                        break;
     777
    659778                                                                                case EBML_ID_SEGMENTFILENAME:
    660779                                                                                case EBML_ID_PREVFILENAME:
     
    663782                                                                                case EBML_ID_MUXINGAPP:
    664783                                                                                case EBML_ID_WRITINGAPP:
    665                                                                                         $info_entry[$subelement_idname] =                             trim(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length), "\x00");
    666                                                                                         $info['matroska']['comments'][strtolower($subelement_idname)][] = $info_entry[$subelement_idname];
     784                                                                                        $info_entry[$subelement['id_name']] = getid3_lib::trimNullByte($subelement['data']);
     785                                                                                        $info['matroska']['comments'][strtolower($subelement['id_name'])][] = $info_entry[$subelement['id_name']];
    667786                                                                                        break;
    668                                                                                 case EBML_ID_CRC32:
    669                                                                                         // probably not useful, ignore
    670                                                                                         break;
     787
    671788                                                                                default:
    672                                                                                         $this->warnings[] = 'Unhandled info element ['.basename(__FILE__).':'.__LINE__.'] ('.$subelement_id.'::'.$subelement_idname.' ['.$subelement_length.' bytes]) at '.$subelement_offset;
    673                                                                                         break;
     789                                                                                        $this->unhandledElement('info', __LINE__, $subelement);
    674790                                                                        }
    675                                                                         $offset = $subelement_end;
    676791                                                                }
    677792                                                                $info['matroska']['info'][] = $info_entry;
    678793                                                                break;
    679794
    680                                                         case EBML_ID_CUES:
     795                                                        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.
     796                                                                if (self::$hide_clusters) { // do not parse cues if hide clusters is "ON" till they point to clusters anyway
     797                                                                        $this->current_offset = $element_data['end'];
     798                                                                        break;
     799                                                                }
    681800                                                                $cues_entry = array();
    682                                                                 while ($offset < $element_end) {
    683                                                                         $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
    684                                                                         $subelement_offset = $offset;
    685                                                                         $subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    686                                                                         $subelement_idname = $this->EBMLidName($subelement_id);
    687                                                                         $subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    688                                                                         $subelement_end    = $offset + $subelement_length;
    689                                                                         switch ($subelement_id) {
     801
     802                                                                while ($this->getEBMLelement($subelement, $element_data['end'])) {
     803                                                                        switch ($subelement['id']) {
     804
    690805                                                                                case EBML_ID_CUEPOINT:
    691806                                                                                        $cuepoint_entry = array();
    692                                                                                         while ($offset < $subelement_end) {
    693                                                                                                 $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
    694                                                                                                 $sub_subelement_offset = $offset;
    695                                                                                                 $sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    696                                                                                                 $sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
    697                                                                                                 $sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    698                                                                                                 $sub_subelement_end    = $offset + $sub_subelement_length;
    699                                                                                                 switch ($sub_subelement_id) {
     807
     808                                                                                        while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_CUETRACKPOSITIONS))) {
     809                                                                                                switch ($sub_subelement['id']) {
     810
    700811                                                                                                        case EBML_ID_CUETRACKPOSITIONS:
    701                                                                                                                 while ($offset < $sub_subelement_end) {
    702                                                                                                                         $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
    703                                                                                                                         $sub_sub_subelement_offset = $offset;
    704                                                                                                                         $sub_sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    705                                                                                                                         $sub_sub_subelement_idname = $this->EBMLidName($sub_sub_subelement_id);
    706                                                                                                                         $sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    707                                                                                                                         $sub_sub_subelement_end    = $offset + $sub_sub_subelement_length;
    708                                                                                                                         switch ($sub_sub_subelement_id) {
     812                                                        $cuetrackpositions_entry = array();
     813                                                                                                       
     814                                                                                                                while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], true)) {
     815                                                                                                                        switch ($sub_sub_subelement['id']) {
     816
    709817                                                                                                                                case EBML_ID_CUETRACK:
    710                                                                                                                                         $cuepoint_entry[$sub_sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length));
     818                                                                                                                                case EBML_ID_CUECLUSTERPOSITION:
     819                                                                                                                                case EBML_ID_CUEBLOCKNUMBER:
     820                                                                                                                                case EBML_ID_CUECODECSTATE:
     821                                                                                                                                        $cuetrackpositions_entry[$sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
    711822                                                                                                                                        break;
     823
    712824                                                                                                                                default:
    713                                                                                                                                         $this->warnings[] = 'Unhandled cues.cuepoint.cuetrackpositions element ['.basename(__FILE__).':'.__LINE__.'] ('.$sub_sub_subelement_id.'::'.$sub_sub_subelement_idname.') at '.$sub_sub_subelement_offset;
    714                                                                                                                                         break;
     825                                                                                                                                        $this->unhandledElement('cues.cuepoint.cuetrackpositions', __LINE__, $sub_sub_subelement);
    715826                                                                                                                        }
    716                                                                                                                         $offset = $sub_subelement_end;
    717827                                                                                                                }
    718                                                                                                                 break;
     828                                                                                                                $cuepoint_entry[$sub_subelement['id_name']][] = $cuetrackpositions_entry;
     829                                                                                                                break;
     830
    719831                                                                                                        case EBML_ID_CUETIME:
    720                                                                                                                 $cuepoint_entry[$subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
    721                                                                                                                 break;
     832                                                                                                                $cuepoint_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
     833                                                                                                                break;
     834
    722835                                                                                                        default:
    723                                                                                                                 $this->warnings[] = 'Unhandled cues.cuepoint element ['.basename(__FILE__).':'.__LINE__.'] ('.$sub_subelement_id.'::'.$sub_subelement_idname.') at '.$sub_subelement_offset;
    724                                                                                                                 break;
     836                                                                                                                $this->unhandledElement('cues.cuepoint', __LINE__, $sub_subelement);
    725837                                                                                                }
    726                                                                                                 $offset = $sub_subelement_end;
    727838                                                                                        }
    728839                                                                                        $cues_entry[] = $cuepoint_entry;
    729                                                                                         $offset = $sub_subelement_end;
    730840                                                                                        break;
    731841
    732                                                                                 case EBML_ID_CRC32:
    733                                                                                         // probably not useful, ignore
    734                                                                                         break;
    735 
    736842                                                                                default:
    737                                                                                         $this->warnings[] = 'Unhandled cues element ['.basename(__FILE__).':'.__LINE__.'] ('.$subelement_id.'::'.$subelement_idname.' ['.$subelement_length.' bytes]) at '.$subelement_offset;
    738                                                                                         break;
     843                                                                                        $this->unhandledElement('cues', __LINE__, $subelement);
    739844                                                                        }
    740                                                                         $offset = $subelement_end;
    741845                                                                }
    742846                                                                $info['matroska']['cues'] = $cues_entry;
    743847                                                                break;
    744848
    745                                                         case EBML_ID_TAGS:
    746                                                                 $tags_entry = array();
    747                                                                 while ($offset < $element_end) {
    748                                                                         $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
    749                                                                         $subelement_offset = $offset;
    750                                                                         $subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    751                                                                         $subelement_idname = $this->EBMLidName($subelement_id);
    752                                                                         $subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    753                                                                         $subelement_end    = $offset + $subelement_length;
    754                                                                         $tag_entry = array();
    755                                                                         switch ($subelement_id) {
    756                                                                                 case EBML_ID_WRITINGAPP:
    757                                                                                         $tag_entry[$subelement_idname] = substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length);
    758                                                                                         break;
     849                                                        case EBML_ID_TAGS: // Element containing elements specific to Tracks/Chapters.
     850                                $tags_entry = array();
     851                                                       
     852                                                                while ($this->getEBMLelement($subelement, $element_data['end'], false)) {
     853                                                                        switch ($subelement['id']) {
     854
    759855                                                                                case EBML_ID_TAG:
    760                                                                                         while ($offset < $subelement_end) {
    761                                                                                                 $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
    762                                                                                                 $sub_subelement_offset = $offset;
    763                                                                                                 $sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    764                                                                                                 $sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
    765                                                                                                 $sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    766                                                                                                 $sub_subelement_end    = $offset + $sub_subelement_length;
    767                                                                                                 switch ($sub_subelement_id) {
     856                                                                                        $tag_entry = array();
     857                                                                               
     858                                                                                        while ($this->getEBMLelement($sub_subelement, $subelement['end'], false)) {
     859                                                                                                switch ($sub_subelement['id']) {
     860
    768861                                                                                                        case EBML_ID_TARGETS:
    769862                                                                                                                $targets_entry = array();
    770                                                                                                                 while ($offset < $sub_subelement_end) {
    771                                                                                                                         $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
    772                                                                                                                         $sub_sub_subelement_offset = $offset;
    773                                                                                                                         $sub_sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    774                                                                                                                         $sub_sub_subelement_idname = $this->EBMLidName($sub_sub_subelement_id);
    775                                                                                                                         $sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    776                                                                                                                         $sub_sub_subelement_end    = $offset + $sub_sub_subelement_length;
    777                                                                                                                         switch ($sub_sub_subelement_id) {
     863
     864                                                                                                                while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], true)) {
     865                                                                                                                        switch ($sub_sub_subelement['id']) {
     866
    778867                                                                                                                                case EBML_ID_TARGETTYPEVALUE:
    779                                                                                                                                         $targets_entry[$sub_sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length));
    780                                                                                                                                         $targets_entry[strtolower($sub_sub_subelement_idname).'_long'] = $this->MatroskaTargetTypeValue($targets_entry[$sub_sub_subelement_idname]);
     868                                                                                                                                        $targets_entry[$sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
     869                                                                                                                                        $targets_entry[strtolower($sub_sub_subelement['id_name']).'_long'] = self::MatroskaTargetTypeValue($targets_entry[$sub_sub_subelement['id_name']]);
    781870                                                                                                                                        break;
    782                                                                                                                                 case EBML_ID_EDITIONUID:
    783                                                                                                                                 case EBML_ID_CHAPTERUID:
    784                                                                                                                                 case EBML_ID_ATTACHMENTUID:
    785                                                                                                                                 case EBML_ID_TAGTRACKUID:
     871
     872                                                                                                                                case EBML_ID_TARGETTYPE:
     873                                                                                                                                        $targets_entry[$sub_sub_subelement['id_name']] = $sub_sub_subelement['data'];
     874                                                                                                                                        break;
     875                                                                                                                               
     876                                                                                                                                case EBML_ID_TAGTRACKUID:       
     877                                                                                                                                case EBML_ID_TAGEDITIONUID:
    786878                                                                                                                                case EBML_ID_TAGCHAPTERUID:
    787                                                                                                                                         $targets_entry[$sub_sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length));
     879                                                                                                                                case EBML_ID_TAGATTACHMENTUID:
     880                                                                                                                                        $targets_entry[$sub_sub_subelement['id_name']][] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
    788881                                                                                                                                        break;
     882
    789883                                                                                                                                default:
    790                                                                                                                                         $this->warnings[] = 'Unhandled tag.targets element ['.basename(__FILE__).':'.__LINE__.'] ('.$sub_sub_subelement_id.'::'.$sub_sub_subelement_idname.') at '.$sub_sub_subelement_offset;
    791                                                                                                                                         break;
     884                                                                                                                                        $this->unhandledElement('tags.tag.targets', __LINE__, $sub_sub_subelement);
    792885                                                                                                                        }
    793                                                                                                                         $offset = $sub_sub_subelement_end;
    794886                                                                                                                }
    795                                                                                                                 $tag_entry[$sub_subelement_idname][] = $targets_entry;
     887                                                                                                                $tag_entry[$sub_subelement['id_name']] = $targets_entry;
    796888                                                                                                                break;
    797889
    798890                                                                                                        case EBML_ID_SIMPLETAG:
    799                                                                                                                 //$tag_entry[$sub_subelement_idname][] = $simpletag_entry;
    800                                                                                                                 $tag_entry[$sub_subelement_idname][] = $this->Handle_EMBL_ID_SIMPLETAG($offset, $sub_subelement_end);
    801                                                                                                                 break;
    802 
    803                                                                                                         case EBML_ID_TARGETTYPE:
    804                                                                                                                 $tag_entry[$sub_subelement_idname] =                           substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length);
    805                                                                                                                 break;
    806 
    807                                                                                                         case EBML_ID_TRACKUID:
    808                                                                                                                 $tag_entry[$sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
     891                                                                                                                $tag_entry[$sub_subelement['id_name']][] = $this->HandleEMBLSimpleTag($sub_subelement['end']);
    809892                                                                                                                break;
    810893
    811894                                                                                                        default:
    812                                                                                                                 $this->warnings[] = 'Unhandled tags.tag element ['.basename(__FILE__).':'.__LINE__.'] ('.$sub_subelement_id.'::'.$sub_subelement_idname.') at '.$sub_subelement_offset;
    813                                                                                                                 break;
     895                                                                                                                $this->unhandledElement('tags.tag', __LINE__, $sub_subelement);
    814896                                                                                                }
    815                                                                                                 $offset = $sub_subelement_end;
    816897                                                                                        }
    817                                                                                         $offset = $sub_subelement_end;
     898                                                                                        $tags_entry[] = $tag_entry;
    818899                                                                                        break;
    819900
    820                                                                                 case EBML_ID_CRC32:
    821                                                                                         // probably not useful, ignore
    822                                                                                         break;
    823 
    824901                                                                                default:
    825                                                                                         $this->warnings[] = 'Unhandled tags element ['.basename(__FILE__).':'.__LINE__.'] ('.$subelement_id.'::'.$subelement_idname.' ['.$subelement_length.' bytes]) at '.$subelement_offset;
    826                                                                                         break;
     902                                                                                        $this->unhandledElement('tags', __LINE__, $subelement);
    827903                                                                        }
    828                                                                         $tags_entry['tags'][] = $tag_entry;
    829                                                                         $offset = $subelement_end;
    830                                                                 }
    831                                                                 $info['matroska']['tags'] = $tags_entry['tags'];
     904                                                                }
     905                                                                $info['matroska']['tags'] = $tags_entry;
    832906                                                                break;
    833907
    834 
    835                                                         case EBML_ID_ATTACHMENTS:
    836                                                                 while ($offset < $element_end) {
    837                                                                         $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
    838                                                                         $subelement_offset = $offset;
    839                                                                         $subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    840                                                                         $subelement_idname = $this->EBMLidName($subelement_id);
    841                                                                         $subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    842                                                                         $subelement_end    = $offset + $subelement_length;
    843                                                                         switch ($subelement_id) {
     908                                                        case EBML_ID_ATTACHMENTS: // Contain attached files.
     909
     910                                                                while ($this->getEBMLelement($subelement, $element_data['end'])) {
     911                                                                        switch ($subelement['id']) {
     912
    844913                                                                                case EBML_ID_ATTACHEDFILE:
    845914                                                                                        $attachedfile_entry = array();
    846                                                                                         while ($offset < $subelement_end) {
    847                                                                                                 $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
    848                                                                                                 $sub_subelement_offset = $offset;
    849                                                                                                 $sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    850                                                                                                 $sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
    851                                                                                                 $sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    852                                                                                                 $sub_subelement_end    = $offset + $sub_subelement_length;
    853                                                                                                 switch ($sub_subelement_id) {
     915
     916                                                                                        while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_FILEDATA))) {
     917                                                                                                switch ($sub_subelement['id']) {
     918
    854919                                                                                                        case EBML_ID_FILEDESCRIPTION:
    855920                                                                                                        case EBML_ID_FILENAME:
    856921                                                                                                        case EBML_ID_FILEMIMETYPE:
    857                                                                                                                 $attachedfile_entry[$sub_subelement_idname] = substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length);
     922                                                                                                                $attachedfile_entry[$sub_subelement['id_name']] = $sub_subelement['data'];
    858923                                                                                                                break;
    859924
    860925                                                                                                        case EBML_ID_FILEDATA:
    861                                                                                                                 $attachedfile_entry['data_offset'] = $offset;
    862                                                                                                                 $attachedfile_entry['data_length'] = $sub_subelement_length;
    863                                                                                                                 do {
    864                                                                                                                         if ($this->inline_attachments === false) {
    865                                                                                                                                 // skip entirely
    866                                                                                                                                 break;
    867                                                                                                                         }
    868                                                                                                                         if ($this->inline_attachments === true) {
    869                                                                                                                                 // great
    870                                                                                                                         } elseif (is_int($this->inline_attachments)) {
    871                                                                                                                                 if ($this->inline_attachments < $sub_subelement_length) {
    872                                                                                                                                         // too big, skip
    873                                                                                                                                         $this->warnings[] = 'attachment at '.$sub_subelement_offset.' is too large to process inline ('.number_format($sub_subelement_length).' bytes)';
    874                                                                                                                                         break;
    875                                                                                                                                 }
    876                                                                                                                         } elseif (is_string($this->inline_attachments)) {
    877                                                                                                                                 $this->inline_attachments = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->inline_attachments), DIRECTORY_SEPARATOR);
    878                                                                                                                                 if (!is_dir($this->inline_attachments) || !is_writable($this->inline_attachments)) {
    879                                                                                                                                         // cannot write, skip
    880                                                                                                                                         $this->warnings[] = 'attachment at '.$sub_subelement_offset.' cannot be saved to "'.$this->inline_attachments.'" (not writable)';
    881                                                                                                                                         break;
    882                                                                                                                                 }
    883                                                                                                                         }
    884                                                                                                                         // if we get this far, must be OK
    885                                                                                                                         $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset, $sub_subelement_length);
    886                                                                                                                         $attachedfile_entry[$sub_subelement_idname] = substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length);
    887                                                                                                                         if (is_string($this->inline_attachments)) {
    888                                                                                                                                 $destination_filename = $this->inline_attachments.DIRECTORY_SEPARATOR.md5($info['filenamepath']).'_'.$attachedfile_entry['data_offset'];
    889                                                                                                                                 if (!file_exists($destination_filename) || is_writable($destination_filename)) {
    890                                                                                                                                         file_put_contents($destination_filename, $attachedfile_entry[$sub_subelement_idname]);
    891                                                                                                                                 } else {
    892                                                                                                                                         $this->warnings[] = 'attachment at '.$sub_subelement_offset.' cannot be saved to "'.$destination_filename.'" (not writable)';
    893                                                                                                                                 }
    894                                                                                                                                 $attachedfile_entry[$sub_subelement_idname.'_filename'] = $destination_filename;
    895                                                                                                                                 unset($attachedfile_entry[$sub_subelement_idname]);
    896                                                                                                                         }
    897                                                                                                                 } while (false);
     926                                                                                                                $attachedfile_entry['data_offset'] = $this->current_offset;
     927                                                                                                                $attachedfile_entry['data_length'] = $sub_subelement['length'];
     928
     929                                                                                                                $this->getid3->saveAttachment(
     930                                                                                                                        $attachedfile_entry[$sub_subelement['id_name']],
     931                                                                                                                        $attachedfile_entry['FileName'],
     932                                                                                                                        $attachedfile_entry['data_offset'],
     933                                                                                                                        $attachedfile_entry['data_length']);
     934
     935                                                                                                                if (@$attachedfile_entry[$sub_subelement['id_name']] && is_file($attachedfile_entry[$sub_subelement['id_name']])) {
     936                                                                                                                        $attachedfile_entry[$sub_subelement['id_name'].'_filename'] = $attachedfile_entry[$sub_subelement['id_name']];
     937                                                                                                                        unset($attachedfile_entry[$sub_subelement['id_name']]);
     938                                                                                                                }
     939
     940                                                                                                                $this->current_offset = $sub_subelement['end'];
    898941                                                                                                                break;
    899942
    900943                                                                                                        case EBML_ID_FILEUID:
    901                                                                                                                 $attachedfile_entry[$sub_subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
     944                                                                                                                $attachedfile_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
    902945                                                                                                                break;
    903946
    904947                                                                                                        default:
    905                                                                                                                 $this->warnings[] = 'Unhandled attachment.attachedfile element ['.basename(__FILE__).':'.__LINE__.'] ('.$sub_subelement_id.'::'.$sub_subelement_idname.') at '.$sub_subelement_offset;
    906                                                                                                                 break;
     948                                                                                                                $this->unhandledElement('attachments.attachedfile', __LINE__, $sub_subelement);
    907949                                                                                                }
    908                                                                                                 $offset = $sub_subelement_end;
    909950                                                                                        }
    910                                                                                         if (!empty($attachedfile_entry[$this->EBMLidName(EBML_ID_FILEDATA)]) && !empty($attachedfile_entry[$this->EBMLidName(EBML_ID_FILEMIMETYPE)]) && preg_match('#^image/#i', $attachedfile_entry[$this->EBMLidName(EBML_ID_FILEMIMETYPE)])) {
    911                                                                                                 if (($this->inline_attachments === true) || (is_int($this->inline_attachments) && ($this->inline_attachments >= strlen($attachedfile_entry[$this->EBMLidName(EBML_ID_FILEDATA)])))) {
    912                                                                                                         $attachedfile_entry['data']       = $attachedfile_entry[$this->EBMLidName(EBML_ID_FILEDATA)];
    913                                                                                                         $attachedfile_entry['image_mime'] = $attachedfile_entry[$this->EBMLidName(EBML_ID_FILEMIMETYPE)];
    914                                                                                                         $info['matroska']['comments']['picture'][] = array('data'=>$attachedfile_entry['data'], 'image_mime'=>$attachedfile_entry['image_mime'], 'filename'=>(!empty($attachedfile_entry[$this->EBMLidName(EBML_ID_FILENAME)]) ? $attachedfile_entry[$this->EBMLidName(EBML_ID_FILENAME)] : ''));
    915                                                                                                         unset($attachedfile_entry[$this->EBMLidName(EBML_ID_FILEDATA)], $attachedfile_entry[$this->EBMLidName(EBML_ID_FILEMIMETYPE)]);
     951                                                                                        if (!empty($attachedfile_entry['FileData']) && !empty($attachedfile_entry['FileMimeType']) && preg_match('#^image/#i', $attachedfile_entry['FileMimeType'])) {
     952                                                                                                if ($this->getid3->option_save_attachments === getID3::ATTACHMENTS_INLINE) {
     953                                                                                                        $attachedfile_entry['data']       = $attachedfile_entry['FileData'];
     954                                                                                                        $attachedfile_entry['image_mime'] = $attachedfile_entry['FileMimeType'];
     955                                                                                                        $info['matroska']['comments']['picture'][] = array('data' => $attachedfile_entry['data'], 'image_mime' => $attachedfile_entry['image_mime'], 'filename' => (!empty($attachedfile_entry['FileName']) ? $attachedfile_entry['FileName'] : ''));
     956                                                                                                        unset($attachedfile_entry['FileData'], $attachedfile_entry['FileMimeType']);
    916957                                                                                                }
    917958                                                                                        }
     
    921962                                                                                                $info['matroska']['attachments'][] = $attachedfile_entry;
    922963                                                                                        }
    923                                                                                         $offset = $sub_subelement_end;
    924964                                                                                        break;
    925965
    926                                                                                 case EBML_ID_CRC32:
    927                                                                                         // probably not useful, ignore
    928                                                                                         break;
    929 
    930966                                                                                default:
    931                                                                                         $this->warnings[] = 'Unhandled tags element ['.basename(__FILE__).':'.__LINE__.'] ('.$subelement_id.'::'.$subelement_idname.' ['.$subelement_length.' bytes]) at '.$subelement_offset;
    932                                                                                         break;
     967                                                                                        $this->unhandledElement('attachments', __LINE__, $subelement);
    933968                                                                        }
    934                                                                         $offset = $subelement_end;
    935969                                                                }
    936970                                                                break;
    937971
    938 
    939                                                         case EBML_ID_CHAPTERS: // not important to us, contains mostly actual audio/video data, ignore
    940                                                                 while ($offset < $element_end) {
    941                                                                         $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
    942                                                                         $subelement_offset = $offset;
    943                                                                         $subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    944                                                                         $subelement_idname = $this->EBMLidName($subelement_id);
    945                                                                         $subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    946                                                                         $subelement_end    = $offset + $subelement_length;
    947                                                                         switch ($subelement_id) {
     972                                                        case EBML_ID_CHAPTERS:
     973
     974                                                                while ($this->getEBMLelement($subelement, $element_data['end'])) {
     975                                                                        switch ($subelement['id']) {
     976
    948977                                                                                case EBML_ID_EDITIONENTRY:
    949978                                                                                        $editionentry_entry = array();
    950                                                                                         while ($offset < $subelement_end) {
    951                                                                                                 $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
    952                                                                                                 $sub_subelement_offset = $offset;
    953                                                                                                 $sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    954                                                                                                 $sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
    955                                                                                                 $sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    956                                                                                                 $sub_subelement_end    = $offset + $sub_subelement_length;
    957                                                                                                 switch ($sub_subelement_id) {
     979
     980                                                                                        while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_CHAPTERATOM))) {
     981                                                                                                switch ($sub_subelement['id']) {
     982
    958983                                                                                                        case EBML_ID_EDITIONUID:
    959                                                                                                                 $editionentry_entry[$sub_subelement_idname] =        getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
    960                                                                                                                 break;
     984                                                                                                                $editionentry_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
     985                                                                                                                break;
     986
    961987                                                                                                        case EBML_ID_EDITIONFLAGHIDDEN:
    962988                                                                                                        case EBML_ID_EDITIONFLAGDEFAULT:
    963989                                                                                                        case EBML_ID_EDITIONFLAGORDERED:
    964                                                                                                                 $editionentry_entry[$sub_subelement_idname] = (bool) getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
    965                                                                                                                 break;
     990                                                                                                                $editionentry_entry[$sub_subelement['id_name']] = (bool)getid3_lib::BigEndian2Int($sub_subelement['data']);
     991                                                                                                                break;
     992
    966993                                                                                                        case EBML_ID_CHAPTERATOM:
    967994                                                                                                                $chapteratom_entry = array();
    968                                                                                                                 while ($offset < $sub_subelement_end) {
    969                                                                                                                         $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
    970                                                                                                                         $sub_sub_subelement_offset = $offset;
    971                                                                                                                         $sub_sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    972                                                                                                                         $sub_sub_subelement_idname = $this->EBMLidName($sub_sub_subelement_id);
    973                                                                                                                         $sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    974                                                                                                                         $sub_sub_subelement_end    = $offset + $sub_sub_subelement_length;
    975                                                                                                                         switch ($sub_sub_subelement_id) {
     995
     996                                                                                                                while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], array(EBML_ID_CHAPTERTRACK, EBML_ID_CHAPTERDISPLAY))) {
     997                                                                                                                        switch ($sub_sub_subelement['id']) {
     998
    976999                                                                                                                                case EBML_ID_CHAPTERSEGMENTUID:
    9771000                                                                                                                                case EBML_ID_CHAPTERSEGMENTEDITIONUID:
    978                                                                                                                                         $chapteratom_entry[$sub_sub_subelement_idname] =                                  substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length);
     1001                                                                                                                                        $chapteratom_entry[$sub_sub_subelement['id_name']] = $sub_sub_subelement['data'];
    9791002                                                                                                                                        break;
     1003
    9801004                                                                                                                                case EBML_ID_CHAPTERFLAGENABLED:
    9811005                                                                                                                                case EBML_ID_CHAPTERFLAGHIDDEN:
    982                                                                                                                                         $chapteratom_entry[$sub_sub_subelement_idname] = (bool) getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length));
     1006                                                                                                                                        $chapteratom_entry[$sub_sub_subelement['id_name']] = (bool)getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
    9831007                                                                                                                                        break;
     1008
    9841009                                                                                                                                case EBML_ID_CHAPTERUID:
    9851010                                                                                                                                case EBML_ID_CHAPTERTIMESTART:
    9861011                                                                                                                                case EBML_ID_CHAPTERTIMEEND:
    987                                                                                                                                         $chapteratom_entry[$sub_sub_subelement_idname] =        getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_subelement_length));
     1012                                                                                                                                        $chapteratom_entry[$sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
    9881013                                                                                                                                        break;
     1014
    9891015                                                                                                                                case EBML_ID_CHAPTERTRACK:
    9901016                                                                                                                                        $chaptertrack_entry = array();
    991                                                                                                                                         while ($offset < $sub_sub_subelement_end) {
    992                                                                                                                                                 $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
    993                                                                                                                                                 $sub_sub_sub_subelement_offset = $offset;
    994                                                                                                                                                 $sub_sub_sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    995                                                                                                                                                 $sub_sub_sub_subelement_idname = $this->EBMLidName($sub_sub_subelement_id);
    996                                                                                                                                                 $sub_sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    997                                                                                                                                                 $sub_sub_sub_subelement_end    = $offset + $sub_sub_sub_subelement_length;
    998                                                                                                                                                 switch ($sub_sub_sub_subelement_id) {
     1017
     1018                                                                                                                                        while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) {
     1019                                                                                                                                                switch ($sub_sub_sub_subelement['id']) {
     1020
    9991021                                                                                                                                                        case EBML_ID_CHAPTERTRACKNUMBER:
    1000                                                                                                                                                                 $chaptertrack_entry[$sub_sub_sub_subelement_idname] =        getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_sub_subelement_length));
     1022                                                                                                                                                                $chaptertrack_entry[$sub_sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_sub_subelement['data']);
    10011023                                                                                                                                                                break;
     1024
    10021025                                                                                                                                                        default:
    1003                                                                                                                                                                 $this->warnings[] = 'Unhandled chapters.editionentry.chapteratom.chaptertrack element ['.basename(__FILE__).':'.__LINE__.'] ('.$sub_sub_sub_subelement_id.'::'.$sub_sub_sub_subelement_idname.') at '.$sub_sub_sub_subelement_offset;
    1004                                                                                                                                                                 break;
     1026                                                                                                                                                                $this->unhandledElement('chapters.editionentry.chapteratom.chaptertrack', __LINE__, $sub_sub_sub_subelement);
    10051027                                                                                                                                                }
    1006                                                                                                                                                 $offset = $sub_sub_sub_subelement_end;
    10071028                                                                                                                                        }
    1008                                                                                                                                         $chapteratom_entry[$sub_sub_subelement_idname][] = $chaptertrack_entry;
     1029                                                                                                                                        $chapteratom_entry[$sub_sub_subelement['id_name']][] = $chaptertrack_entry;
    10091030                                                                                                                                        break;
     1031
    10101032                                                                                                                                case EBML_ID_CHAPTERDISPLAY:
    10111033                                                                                                                                        $chapterdisplay_entry = array();
    1012                                                                                                                                         while ($offset < $sub_sub_subelement_end) {
    1013                                                                                                                                                 $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
    1014                                                                                                                                                 $sub_sub_sub_subelement_offset = $offset;
    1015                                                                                                                                                 $sub_sub_sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    1016                                                                                                                                                 $sub_sub_sub_subelement_idname = $this->EBMLidName($sub_sub_sub_subelement_id);
    1017                                                                                                                                                 $sub_sub_sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    1018                                                                                                                                                 $sub_sub_sub_subelement_end    = $offset + $sub_sub_sub_subelement_length;
    1019                                                                                                                                                 switch ($sub_sub_sub_subelement_id) {
     1034
     1035                                                                                                                                        while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) {
     1036                                                                                                                                                switch ($sub_sub_sub_subelement['id']) {
     1037
    10201038                                                                                                                                                        case EBML_ID_CHAPSTRING:
    10211039                                                                                                                                                        case EBML_ID_CHAPLANGUAGE:
    10221040                                                                                                                                                        case EBML_ID_CHAPCOUNTRY:
    1023                                                                                                                                                                 $chapterdisplay_entry[$sub_sub_sub_subelement_idname] =                                  substr($EBMLdata, $offset - $EBMLdata_offset, $sub_sub_sub_subelement_length);
     1041                                                                                                                                                                $chapterdisplay_entry[$sub_sub_sub_subelement['id_name']] = $sub_sub_sub_subelement['data'];
    10241042                                                                                                                                                                break;
     1043
    10251044                                                                                                                                                        default:
    1026                                                                                                                                                                 $this->warnings[] = 'Unhandled chapters.editionentry.chapteratom.chapterdisplay element ['.basename(__FILE__).':'.__LINE__.'] ('.$sub_sub_sub_subelement_id.'::'.$sub_sub_sub_subelement_idname.') at '.$sub_sub_sub_subelement_offset;
    1027                                                                                                                                                                 break;
     1045                                                                                                                                                                $this->unhandledElement('chapters.editionentry.chapteratom.chapterdisplay', __LINE__, $sub_sub_sub_subelement);
    10281046                                                                                                                                                }
    1029                                                                                                                                                 $offset = $sub_sub_sub_subelement_end;
    10301047                                                                                                                                        }
    1031                                                                                                                                         $chapteratom_entry[$sub_sub_subelement_idname][] = $chapterdisplay_entry;
     1048                                                                                                                                        $chapteratom_entry[$sub_sub_subelement['id_name']][] = $chapterdisplay_entry;
    10321049                                                                                                                                        break;
     1050
    10331051                                                                                                                                default:
    1034                                                                                                                                         $this->warnings[] = 'Unhandled chapters.editionentry.chapteratom element ['.basename(__FILE__).':'.__LINE__.'] ('.$sub_sub_subelement_id.'::'.$sub_sub_subelement_idname.') at '.$sub_sub_subelement_offset;
    1035                                                                                                                                         break;
     1052                                                                                                                                        $this->unhandledElement('chapters.editionentry.chapteratom', __LINE__, $sub_sub_subelement);
    10361053                                                                                                                        }
    1037                                                                                                                         $offset = $sub_sub_subelement_end;
    10381054                                                                                                                }
    1039                                                                                                                 $editionentry_entry[$sub_subelement_idname][] = $chapteratom_entry;
    1040                                                                                                                 break;
     1055                                                                                                                $editionentry_entry[$sub_subelement['id_name']][] = $chapteratom_entry;
     1056                                                                                                                break;
     1057
    10411058                                                                                                        default:
    1042                                                                                                                 $this->warnings[] = 'Unhandled chapters.editionentry element ['.basename(__FILE__).':'.__LINE__.'] ('.$sub_subelement_id.'::'.$sub_subelement_idname.') at '.$sub_subelement_offset;
    1043                                                                                                                 break;
     1059                                                                                                                $this->unhandledElement('chapters.editionentry', __LINE__, $sub_subelement);
    10441060                                                                                                }
    1045                                                                                                 $offset = $sub_subelement_end;
    10461061                                                                                        }
    10471062                                                                                        $info['matroska']['chapters'][] = $editionentry_entry;
    1048                                                                                         $offset = $sub_subelement_end;
    10491063                                                                                        break;
     1064
    10501065                                                                                default:
    1051                                                                                         $this->warnings[] = 'Unhandled chapters element ['.basename(__FILE__).':'.__LINE__.'] ('.$subelement_id.'::'.$subelement_idname.' ['.$subelement_length.' bytes]) at '.$subelement_offset;
    1052                                                                                         break;
     1066                                                                                        $this->unhandledElement('chapters', __LINE__, $subelement);
    10531067                                                                        }
    1054                                                                         $offset = $subelement_end;
    10551068                                                                }
    10561069                                                                break;
    10571070
    1058 
    1059                                                         case EBML_ID_VOID:    // padding, ignore
    1060                                                                 $void_entry = array();
    1061                                                                 $void_entry['offset'] = $offset;
    1062                                                                 $info['matroska']['void'][] = $void_entry;
    1063                                                                 break;
    1064 
    1065                                                         case EBML_ID_CLUSTER: // not important to us, contains mostly actual audio/video data, ignore
     1071                                                        case EBML_ID_CLUSTER: // The lower level element containing the (monolithic) Block structure.
    10661072                                                                $cluster_entry = array();
    1067                                                                 while ($offset < $element_end) {
    1068                                                                         $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
    1069                                                                         $subelement_offset = $offset;
    1070                                                                         $subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    1071                                                                         $subelement_idname = $this->EBMLidName($subelement_id);
    1072                                                                         $subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    1073                                                                         $subelement_end    = $offset + $subelement_length;
    1074                                                                         switch ($subelement_id) {
     1073
     1074                                                                while ($this->getEBMLelement($subelement, $element_data['end'], array(EBML_ID_CLUSTERSILENTTRACKS, EBML_ID_CLUSTERBLOCKGROUP, EBML_ID_CLUSTERSIMPLEBLOCK))) {
     1075                                                                        switch ($subelement['id']) {
     1076
    10751077                                                                                case EBML_ID_CLUSTERTIMECODE:
    10761078                                                                                case EBML_ID_CLUSTERPOSITION:
    10771079                                                                                case EBML_ID_CLUSTERPREVSIZE:
    1078                                                                                         $cluster_entry[$subelement_idname] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $subelement_length));
     1080                                                                                        $cluster_entry[$subelement['id_name']] = getid3_lib::BigEndian2Int($subelement['data']);
    10791081                                                                                        break;
    10801082
    10811083                                                                                case EBML_ID_CLUSTERSILENTTRACKS:
    10821084                                                                                        $cluster_silent_tracks = array();
    1083                                                                                         while ($offset < $subelement_end) {
    1084                                                                                                 $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
    1085                                                                                                 $sub_subelement_offset = $offset;
    1086                                                                                                 $sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    1087                                                                                                 $sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
    1088                                                                                                 $sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    1089                                                                                                 $sub_subelement_end    = $offset + $sub_subelement_length;
    1090                                                                                                 switch ($sub_subelement_id) {
     1085
     1086                                                                                        while ($this->getEBMLelement($sub_subelement, $subelement['end'], true)) {
     1087                                                                                                switch ($sub_subelement['id']) {
     1088
    10911089                                                                                                        case EBML_ID_CLUSTERSILENTTRACKNUMBER:
    1092                                                                                                                 $cluster_silent_tracks[] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset - $EBMLdata_offset, $sub_subelement_length));
    1093                                                                                                                 break;
     1090                                                                                                                $cluster_silent_tracks[] = getid3_lib::BigEndian2Int($sub_subelement['data']);
     1091                                                                                                                break;
     1092
    10941093                                                                                                        default:
    1095                                                                                                                 $this->warnings[] = 'Unhandled clusters.silenttracks element ['.basename(__FILE__).':'.__LINE__.'] ('.$sub_subelement_id.'::'.$sub_subelement_idname.') at '.$sub_subelement_offset;
    1096                                                                                                                 break;
     1094                                                                                                                $this->unhandledElement('cluster.silenttracks', __LINE__, $sub_subelement);
    10971095                                                                                                }
    1098                                                                                                 $offset = $sub_subelement_end;
    10991096                                                                                        }
    1100                                                                                         $cluster_entry[$subelement_idname][] = $cluster_silent_tracks;
    1101                                                                                         $offset = $sub_subelement_end;
     1097                                                                                        $cluster_entry[$subelement['id_name']][] = $cluster_silent_tracks;
    11021098                                                                                        break;
    11031099
    11041100                                                                                case EBML_ID_CLUSTERBLOCKGROUP:
    1105                                                                                         $cluster_block_group = array('offset'=>$offset);
    1106                                                                                         while ($offset < $subelement_end) {
    1107                                                                                                 $this->EnsureBufferHasEnoughData($EBMLdata, $offset, $EBMLdata_offset);
    1108                                                                                                 $sub_subelement_offset = $offset;
    1109                                                                                                 $sub_subelement_id     = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    1110                                                                                                 $sub_subelement_idname = $this->EBMLidName($sub_subelement_id);
    1111                                                                                                 $sub_subelement_length = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    1112                                                                                                 $sub_subelement_end    = $offset + $sub_subelement_length;
    1113                                                                                                 switch ($sub_subelement_id) {
     1101                                                                                        $cluster_block_group = array('offset' => $this->current_offset);
     1102
     1103                                                                                        while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_CLUSTERBLOCK))) {
     1104                                                                                                switch ($sub_subelement['id']) {
     1105
    11141106                                                                                                        case EBML_ID_CLUSTERBLOCK:
    1115                                                                                                                 $cluster_block_data = array();
    1116                                                                                                                 $cluster_block_data['tracknumber'] = $this->readEBMLint($EBMLdata, $offset, $EBMLdata_offset);
    1117                                                                                                                 $cluster_block_data['timecode'] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset, 2));
    1118                                                                                                                 $offset += 2;
    1119                                                                                                                 // unsure whether this is 1 octect or 2 octets? (http://matroska.org/technical/specs/index.html#block_structure)
    1120                                                                                                                 $cluster_block_data['flags_raw'] = getid3_lib::BigEndian2Int(substr($EBMLdata, $offset, 1));
    1121                                                                                                                 $offset += 1;
    1122                                                                                                                 //$cluster_block_data['flags']['reserved1'] =      (($cluster_block_data['flags_raw'] & 0xF0) >> 4);
    1123                                                                                                                 $cluster_block_data['flags']['invisible'] = (bool) (($cluster_block_data['flags_raw'] & 0x08) >> 3);
    1124                                                                                               &nb