wp/wp-includes/ID3/module.audio.flac.php
changeset 16 a86126ab1dd4
parent 7 cf61fcea0001
child 19 3d72ae0968f4
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
     1 <?php
     1 <?php
       
     2 
     2 /////////////////////////////////////////////////////////////////
     3 /////////////////////////////////////////////////////////////////
     3 /// getID3() by James Heinrich <info@getid3.org>               //
     4 /// getID3() by James Heinrich <info@getid3.org>               //
     4 //  available at http://getid3.sourceforge.net                 //
     5 //  available at https://github.com/JamesHeinrich/getID3       //
     5 //            or http://www.getid3.org                         //
     6 //            or https://www.getid3.org                        //
     6 //          also https://github.com/JamesHeinrich/getID3       //
     7 //            or http://getid3.sourceforge.net                 //
     7 /////////////////////////////////////////////////////////////////
     8 //  see readme.txt for more details                            //
     8 // See readme.txt for more details                             //
       
     9 /////////////////////////////////////////////////////////////////
     9 /////////////////////////////////////////////////////////////////
    10 //                                                             //
    10 //                                                             //
    11 // module.audio.flac.php                                       //
    11 // module.audio.flac.php                                       //
    12 // module for analyzing FLAC and OggFLAC audio files           //
    12 // module for analyzing FLAC and OggFLAC audio files           //
    13 // dependencies: module.audio.ogg.php                          //
    13 // dependencies: module.audio.ogg.php                          //
    14 //                                                            ///
    14 //                                                            ///
    15 /////////////////////////////////////////////////////////////////
    15 /////////////////////////////////////////////////////////////////
    16 
    16 
    17 
    17 if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
       
    18 	exit;
       
    19 }
    18 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ogg.php', __FILE__, true);
    20 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ogg.php', __FILE__, true);
    19 
    21 
    20 /**
    22 /**
    21 * @tutorial http://flac.sourceforge.net/format.html
    23 * @tutorial http://flac.sourceforge.net/format.html
    22 */
    24 */
    23 class getid3_flac extends getid3_handler
    25 class getid3_flac extends getid3_handler
    24 {
    26 {
    25 	const syncword = 'fLaC';
    27 	const syncword = 'fLaC';
    26 
    28 
       
    29 	/**
       
    30 	 * @return bool
       
    31 	 */
    27 	public function Analyze() {
    32 	public function Analyze() {
    28 		$info = &$this->getid3->info;
    33 		$info = &$this->getid3->info;
    29 
    34 
    30 		$this->fseek($info['avdataoffset']);
    35 		$this->fseek($info['avdataoffset']);
    31 		$StreamMarker = $this->fread(4);
    36 		$StreamMarker = $this->fread(4);
    39 
    44 
    40 		// parse flac container
    45 		// parse flac container
    41 		return $this->parseMETAdata();
    46 		return $this->parseMETAdata();
    42 	}
    47 	}
    43 
    48 
       
    49 	/**
       
    50 	 * @return bool
       
    51 	 */
    44 	public function parseMETAdata() {
    52 	public function parseMETAdata() {
    45 		$info = &$this->getid3->info;
    53 		$info = &$this->getid3->info;
    46 		do {
    54 		do {
    47 			$BlockOffset   = $this->ftell();
    55 			$BlockOffset   = $this->ftell();
    48 			$BlockHeader   = $this->fread(4);
    56 			$BlockHeader   = $this->fread(4);
    49 			$LBFBT         = getid3_lib::BigEndian2Int(substr($BlockHeader, 0, 1));
    57 			$LBFBT         = getid3_lib::BigEndian2Int(substr($BlockHeader, 0, 1));  // LBFBT = LastBlockFlag + BlockType
    50 			$LastBlockFlag = (bool) ($LBFBT & 0x80);
    58 			$LastBlockFlag = (bool) ($LBFBT & 0x80);
    51 			$BlockType     =        ($LBFBT & 0x7F);
    59 			$BlockType     =        ($LBFBT & 0x7F);
    52 			$BlockLength   = getid3_lib::BigEndian2Int(substr($BlockHeader, 1, 3));
    60 			$BlockLength   = getid3_lib::BigEndian2Int(substr($BlockHeader, 1, 3));
    53 			$BlockTypeText = self::metaBlockTypeLookup($BlockType);
    61 			$BlockTypeText = self::metaBlockTypeLookup($BlockType);
    54 
    62 
    55 			if (($BlockOffset + 4 + $BlockLength) > $info['avdataend']) {
    63 			if (($BlockOffset + 4 + $BlockLength) > $info['avdataend']) {
    56 				$this->error('METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$BlockTypeText.') at offset '.$BlockOffset.' extends beyond end of file');
    64 				$this->warning('METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$BlockTypeText.') at offset '.$BlockOffset.' extends beyond end of file');
    57 				break;
    65 				break;
    58 			}
    66 			}
    59 			if ($BlockLength < 1) {
    67 			if ($BlockLength < 1) {
       
    68 				if ($BlockTypeText != 'reserved') {
       
    69 					// probably supposed to be zero-length
       
    70 					$this->warning('METADATA_BLOCK_HEADER.BLOCK_LENGTH ('.$BlockTypeText.') at offset '.$BlockOffset.' is zero bytes');
       
    71 					continue;
       
    72 				}
    60 				$this->error('METADATA_BLOCK_HEADER.BLOCK_LENGTH ('.$BlockLength.') at offset '.$BlockOffset.' is invalid');
    73 				$this->error('METADATA_BLOCK_HEADER.BLOCK_LENGTH ('.$BlockLength.') at offset '.$BlockOffset.' is invalid');
    61 				break;
    74 				break;
    62 			}
    75 			}
    63 
    76 
    64 			$info['flac'][$BlockTypeText]['raw'] = array();
    77 			$info['flac'][$BlockTypeText]['raw'] = array();
   165 
   178 
   166 		// set md5_data_source - built into flac 0.5+
   179 		// set md5_data_source - built into flac 0.5+
   167 		if (isset($info['flac']['STREAMINFO']['audio_signature'])) {
   180 		if (isset($info['flac']['STREAMINFO']['audio_signature'])) {
   168 
   181 
   169 			if ($info['flac']['STREAMINFO']['audio_signature'] === str_repeat("\x00", 16)) {
   182 			if ($info['flac']['STREAMINFO']['audio_signature'] === str_repeat("\x00", 16)) {
   170                 $this->warning('FLAC STREAMINFO.audio_signature is null (known issue with libOggFLAC)');
   183 				$this->warning('FLAC STREAMINFO.audio_signature is null (known issue with libOggFLAC)');
   171 			}
   184 			}
   172 			else {
   185 			else {
   173 				$info['md5_data_source'] = '';
   186 				$info['md5_data_source'] = '';
   174 				$md5 = $info['flac']['STREAMINFO']['audio_signature'];
   187 				$md5 = $info['flac']['STREAMINFO']['audio_signature'];
   175 				for ($i = 0; $i < strlen($md5); $i++) {
   188 				for ($i = 0; $i < strlen($md5); $i++) {
   192 		}
   205 		}
   193 
   206 
   194 		return true;
   207 		return true;
   195 	}
   208 	}
   196 
   209 
   197 	private function parseSTREAMINFO($BlockData) {
   210 
   198 		$info = &$this->getid3->info;
   211 	/**
   199 
   212 	 * @param string $BlockData
   200 		$info['flac']['STREAMINFO'] = array();
   213 	 *
   201 		$streaminfo = &$info['flac']['STREAMINFO'];
   214 	 * @return array
   202 
   215 	 */
       
   216 	public static function parseSTREAMINFOdata($BlockData) {
       
   217 		$streaminfo = array();
   203 		$streaminfo['min_block_size']  = getid3_lib::BigEndian2Int(substr($BlockData, 0, 2));
   218 		$streaminfo['min_block_size']  = getid3_lib::BigEndian2Int(substr($BlockData, 0, 2));
   204 		$streaminfo['max_block_size']  = getid3_lib::BigEndian2Int(substr($BlockData, 2, 2));
   219 		$streaminfo['max_block_size']  = getid3_lib::BigEndian2Int(substr($BlockData, 2, 2));
   205 		$streaminfo['min_frame_size']  = getid3_lib::BigEndian2Int(substr($BlockData, 4, 3));
   220 		$streaminfo['min_frame_size']  = getid3_lib::BigEndian2Int(substr($BlockData, 4, 3));
   206 		$streaminfo['max_frame_size']  = getid3_lib::BigEndian2Int(substr($BlockData, 7, 3));
   221 		$streaminfo['max_frame_size']  = getid3_lib::BigEndian2Int(substr($BlockData, 7, 3));
   207 
   222 
   209 		$streaminfo['sample_rate']     = getid3_lib::Bin2Dec(substr($SRCSBSS,  0, 20));
   224 		$streaminfo['sample_rate']     = getid3_lib::Bin2Dec(substr($SRCSBSS,  0, 20));
   210 		$streaminfo['channels']        = getid3_lib::Bin2Dec(substr($SRCSBSS, 20,  3)) + 1;
   225 		$streaminfo['channels']        = getid3_lib::Bin2Dec(substr($SRCSBSS, 20,  3)) + 1;
   211 		$streaminfo['bits_per_sample'] = getid3_lib::Bin2Dec(substr($SRCSBSS, 23,  5)) + 1;
   226 		$streaminfo['bits_per_sample'] = getid3_lib::Bin2Dec(substr($SRCSBSS, 23,  5)) + 1;
   212 		$streaminfo['samples_stream']  = getid3_lib::Bin2Dec(substr($SRCSBSS, 28, 36));
   227 		$streaminfo['samples_stream']  = getid3_lib::Bin2Dec(substr($SRCSBSS, 28, 36));
   213 
   228 
   214 		$streaminfo['audio_signature'] = substr($BlockData, 18, 16);
   229 		$streaminfo['audio_signature'] =                           substr($BlockData, 18, 16);
   215 
   230 
   216 		if (!empty($streaminfo['sample_rate'])) {
   231 		return $streaminfo;
       
   232 	}
       
   233 
       
   234 	/**
       
   235 	 * @param string $BlockData
       
   236 	 *
       
   237 	 * @return bool
       
   238 	 */
       
   239 	private function parseSTREAMINFO($BlockData) {
       
   240 		$info = &$this->getid3->info;
       
   241 
       
   242 		$info['flac']['STREAMINFO'] = self::parseSTREAMINFOdata($BlockData);
       
   243 
       
   244 		if (!empty($info['flac']['STREAMINFO']['sample_rate'])) {
   217 
   245 
   218 			$info['audio']['bitrate_mode']    = 'vbr';
   246 			$info['audio']['bitrate_mode']    = 'vbr';
   219 			$info['audio']['sample_rate']     = $streaminfo['sample_rate'];
   247 			$info['audio']['sample_rate']     = $info['flac']['STREAMINFO']['sample_rate'];
   220 			$info['audio']['channels']        = $streaminfo['channels'];
   248 			$info['audio']['channels']        = $info['flac']['STREAMINFO']['channels'];
   221 			$info['audio']['bits_per_sample'] = $streaminfo['bits_per_sample'];
   249 			$info['audio']['bits_per_sample'] = $info['flac']['STREAMINFO']['bits_per_sample'];
   222 			$info['playtime_seconds']         = $streaminfo['samples_stream'] / $streaminfo['sample_rate'];
   250 			$info['playtime_seconds']         = $info['flac']['STREAMINFO']['samples_stream'] / $info['flac']['STREAMINFO']['sample_rate'];
   223 			if ($info['playtime_seconds'] > 0) {
   251 			if ($info['playtime_seconds'] > 0) {
   224 				if (!$this->isDependencyFor('matroska')) {
   252 				if (!$this->isDependencyFor('matroska')) {
   225 					$info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
   253 					$info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
   226 				}
   254 				}
   227 				else {
   255 				else {
   234 		}
   262 		}
   235 
   263 
   236 		return true;
   264 		return true;
   237 	}
   265 	}
   238 
   266 
       
   267 	/**
       
   268 	 * @param string $BlockData
       
   269 	 *
       
   270 	 * @return bool
       
   271 	 */
   239 	private function parseAPPLICATION($BlockData) {
   272 	private function parseAPPLICATION($BlockData) {
   240 		$info = &$this->getid3->info;
   273 		$info = &$this->getid3->info;
   241 
   274 
   242 		$ApplicationID = getid3_lib::BigEndian2Int(substr($BlockData, 0, 4));
   275 		$ApplicationID = getid3_lib::BigEndian2Int(substr($BlockData, 0, 4));
   243 		$info['flac']['APPLICATION'][$ApplicationID]['name'] = self::applicationIDLookup($ApplicationID);
   276 		$info['flac']['APPLICATION'][$ApplicationID]['name'] = self::applicationIDLookup($ApplicationID);
   244 		$info['flac']['APPLICATION'][$ApplicationID]['data'] = substr($BlockData, 4);
   277 		$info['flac']['APPLICATION'][$ApplicationID]['data'] = substr($BlockData, 4);
   245 
   278 
   246 		return true;
   279 		return true;
   247 	}
   280 	}
   248 
   281 
       
   282 	/**
       
   283 	 * @param string $BlockData
       
   284 	 *
       
   285 	 * @return bool
       
   286 	 */
   249 	private function parseSEEKTABLE($BlockData) {
   287 	private function parseSEEKTABLE($BlockData) {
   250 		$info = &$this->getid3->info;
   288 		$info = &$this->getid3->info;
   251 
   289 
   252 		$offset = 0;
   290 		$offset = 0;
   253 		$BlockLength = strlen($BlockData);
   291 		$BlockLength = strlen($BlockData);
   273 		}
   311 		}
   274 
   312 
   275 		return true;
   313 		return true;
   276 	}
   314 	}
   277 
   315 
       
   316 	/**
       
   317 	 * @param string $BlockData
       
   318 	 *
       
   319 	 * @return bool
       
   320 	 */
   278 	private function parseVORBIS_COMMENT($BlockData) {
   321 	private function parseVORBIS_COMMENT($BlockData) {
   279 		$info = &$this->getid3->info;
   322 		$info = &$this->getid3->info;
   280 
   323 
   281 		$getid3_ogg = new getid3_ogg($this->getid3);
   324 		$getid3_ogg = new getid3_ogg($this->getid3);
   282 		if ($this->isDependencyFor('matroska')) {
   325 		if ($this->isDependencyFor('matroska')) {
   292 		unset($getid3_ogg);
   335 		unset($getid3_ogg);
   293 
   336 
   294 		return true;
   337 		return true;
   295 	}
   338 	}
   296 
   339 
       
   340 	/**
       
   341 	 * @param string $BlockData
       
   342 	 *
       
   343 	 * @return bool
       
   344 	 */
   297 	private function parseCUESHEET($BlockData) {
   345 	private function parseCUESHEET($BlockData) {
   298 		$info = &$this->getid3->info;
   346 		$info = &$this->getid3->info;
   299 		$offset = 0;
   347 		$offset = 0;
   300 		$info['flac']['CUESHEET']['media_catalog_number'] =                              trim(substr($BlockData, $offset, 128), "\0");
   348 		$info['flac']['CUESHEET']['media_catalog_number'] =                              trim(substr($BlockData, $offset, 128), "\0");
   301 		$offset += 128;
   349 		$offset += 128;
   344 
   392 
   345 		return true;
   393 		return true;
   346 	}
   394 	}
   347 
   395 
   348 	/**
   396 	/**
   349 	* Parse METADATA_BLOCK_PICTURE flac structure and extract attachment
   397 	 * Parse METADATA_BLOCK_PICTURE flac structure and extract attachment
   350 	* External usage: audio.ogg
   398 	 * External usage: audio.ogg
   351 	*/
   399 	 *
       
   400 	 * @return bool
       
   401 	 */
   352 	public function parsePICTURE() {
   402 	public function parsePICTURE() {
   353 		$info = &$this->getid3->info;
   403 		$info = &$this->getid3->info;
   354 
   404 
   355 		$picture['typeid']         = getid3_lib::BigEndian2Int($this->fread(4));
   405 		$picture['typeid']         = getid3_lib::BigEndian2Int($this->fread(4));
   356 		$picture['picturetype']    = self::pictureTypeLookup($picture['typeid']);
   406 		$picture['picturetype']    = self::pictureTypeLookup($picture['typeid']);
   378 		$info['flac']['PICTURE'][] = $picture;
   428 		$info['flac']['PICTURE'][] = $picture;
   379 
   429 
   380 		return true;
   430 		return true;
   381 	}
   431 	}
   382 
   432 
       
   433 	/**
       
   434 	 * @param int $blocktype
       
   435 	 *
       
   436 	 * @return string
       
   437 	 */
   383 	public static function metaBlockTypeLookup($blocktype) {
   438 	public static function metaBlockTypeLookup($blocktype) {
   384 		static $lookup = array(
   439 		static $lookup = array(
   385 			0 => 'STREAMINFO',
   440 			0 => 'STREAMINFO',
   386 			1 => 'PADDING',
   441 			1 => 'PADDING',
   387 			2 => 'APPLICATION',
   442 			2 => 'APPLICATION',
   391 			6 => 'PICTURE',
   446 			6 => 'PICTURE',
   392 		);
   447 		);
   393 		return (isset($lookup[$blocktype]) ? $lookup[$blocktype] : 'reserved');
   448 		return (isset($lookup[$blocktype]) ? $lookup[$blocktype] : 'reserved');
   394 	}
   449 	}
   395 
   450 
       
   451 	/**
       
   452 	 * @param int $applicationid
       
   453 	 *
       
   454 	 * @return string
       
   455 	 */
   396 	public static function applicationIDLookup($applicationid) {
   456 	public static function applicationIDLookup($applicationid) {
   397 		// http://flac.sourceforge.net/id.html
   457 		// http://flac.sourceforge.net/id.html
   398 		static $lookup = array(
   458 		static $lookup = array(
   399 			0x41544348 => 'FlacFile',                                                                           // "ATCH"
   459 			0x41544348 => 'FlacFile',                                                                           // "ATCH"
   400 			0x42534F4C => 'beSolo',                                                                             // "BSOL"
   460 			0x42534F4C => 'beSolo',                                                                             // "BSOL"
   421 			0x786D6364 => 'xmcd',                                                                               // "xmcd"
   481 			0x786D6364 => 'xmcd',                                                                               // "xmcd"
   422 		);
   482 		);
   423 		return (isset($lookup[$applicationid]) ? $lookup[$applicationid] : 'reserved');
   483 		return (isset($lookup[$applicationid]) ? $lookup[$applicationid] : 'reserved');
   424 	}
   484 	}
   425 
   485 
       
   486 	/**
       
   487 	 * @param int $type_id
       
   488 	 *
       
   489 	 * @return string
       
   490 	 */
   426 	public static function pictureTypeLookup($type_id) {
   491 	public static function pictureTypeLookup($type_id) {
   427 		static $lookup = array (
   492 		static $lookup = array (
   428 			 0 => 'Other',
   493 			 0 => 'Other',
   429 			 1 => '32x32 pixels \'file icon\' (PNG only)',
   494 			 1 => '32x32 pixels \'file icon\' (PNG only)',
   430 			 2 => 'Other file icon',
   495 			 2 => 'Other file icon',