wp/wp-includes/ID3/module.audio.ogg.php
changeset 7 cf61fcea0001
parent 5 5e2f62d02dcd
child 16 a86126ab1dd4
equal deleted inserted replaced
6:490d5cc509ed 7:cf61fcea0001
    24 
    24 
    25 		$info['fileformat'] = 'ogg';
    25 		$info['fileformat'] = 'ogg';
    26 
    26 
    27 		// Warn about illegal tags - only vorbiscomments are allowed
    27 		// Warn about illegal tags - only vorbiscomments are allowed
    28 		if (isset($info['id3v2'])) {
    28 		if (isset($info['id3v2'])) {
    29 			$info['warning'][] = 'Illegal ID3v2 tag present.';
    29 			$this->warning('Illegal ID3v2 tag present.');
    30 		}
    30 		}
    31 		if (isset($info['id3v1'])) {
    31 		if (isset($info['id3v1'])) {
    32 			$info['warning'][] = 'Illegal ID3v1 tag present.';
    32 			$this->warning('Illegal ID3v1 tag present.');
    33 		}
    33 		}
    34 		if (isset($info['ape'])) {
    34 		if (isset($info['ape'])) {
    35 			$info['warning'][] = 'Illegal APE tag present.';
    35 			$this->warning('Illegal APE tag present.');
    36 		}
    36 		}
    37 
    37 
    38 
    38 
    39 		// Page 1 - Stream Header
    39 		// Page 1 - Stream Header
    40 
    40 
    42 
    42 
    43 		$oggpageinfo = $this->ParseOggPageHeader();
    43 		$oggpageinfo = $this->ParseOggPageHeader();
    44 		$info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
    44 		$info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
    45 
    45 
    46 		if ($this->ftell() >= $this->getid3->fread_buffer_size()) {
    46 		if ($this->ftell() >= $this->getid3->fread_buffer_size()) {
    47 			$info['error'][] = 'Could not find start of Ogg page in the first '.$this->getid3->fread_buffer_size().' bytes (this might not be an Ogg-Vorbis file?)';
    47 			$this->error('Could not find start of Ogg page in the first '.$this->getid3->fread_buffer_size().' bytes (this might not be an Ogg-Vorbis file?)');
    48 			unset($info['fileformat']);
    48 			unset($info['fileformat']);
    49 			unset($info['ogg']);
    49 			unset($info['ogg']);
    50 			return false;
    50 			return false;
    51 		}
    51 		}
    52 
    52 
    60 			$info['audio']['lossless']     = true;
    60 			$info['audio']['lossless']     = true;
    61 
    61 
    62 		} elseif (substr($filedata, 1, 6) == 'vorbis') {
    62 		} elseif (substr($filedata, 1, 6) == 'vorbis') {
    63 
    63 
    64 			$this->ParseVorbisPageHeader($filedata, $filedataoffset, $oggpageinfo);
    64 			$this->ParseVorbisPageHeader($filedata, $filedataoffset, $oggpageinfo);
       
    65 
       
    66 		} elseif (substr($filedata, 0, 8) == 'OpusHead') {
       
    67 
       
    68 			if( $this->ParseOpusPageHeader($filedata, $filedataoffset, $oggpageinfo) == false ) {
       
    69 				return false;
       
    70 			}
    65 
    71 
    66 		} elseif (substr($filedata, 0, 8) == 'Speex   ') {
    72 		} elseif (substr($filedata, 0, 8) == 'Speex   ') {
    67 
    73 
    68 			// http://www.speex.org/manual/node10.html
    74 			// http://www.speex.org/manual/node10.html
    69 
    75 
   171 				$info['video']['frame_rate'] = (float) $info['ogg']['pageheader']['theora']['frame_rate_numerator'] / $info['ogg']['pageheader']['theora']['frame_rate_denominator'];
   177 				$info['video']['frame_rate'] = (float) $info['ogg']['pageheader']['theora']['frame_rate_numerator'] / $info['ogg']['pageheader']['theora']['frame_rate_denominator'];
   172 			}
   178 			}
   173 			if ($info['ogg']['pageheader']['theora']['pixel_aspect_denominator'] > 0) {
   179 			if ($info['ogg']['pageheader']['theora']['pixel_aspect_denominator'] > 0) {
   174 				$info['video']['pixel_aspect_ratio'] = (float) $info['ogg']['pageheader']['theora']['pixel_aspect_numerator'] / $info['ogg']['pageheader']['theora']['pixel_aspect_denominator'];
   180 				$info['video']['pixel_aspect_ratio'] = (float) $info['ogg']['pageheader']['theora']['pixel_aspect_numerator'] / $info['ogg']['pageheader']['theora']['pixel_aspect_denominator'];
   175 			}
   181 			}
   176 $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of getID3 ['.$this->getid3->version().'] -- bitrate, playtime and all audio data are currently unavailable';
   182 $this->warning('Ogg Theora (v3) not fully supported in this version of getID3 ['.$this->getid3->version().'] -- bitrate, playtime and all audio data are currently unavailable');
   177 
   183 
   178 
   184 
   179 		} elseif (substr($filedata, 0, 8) == "fishead\x00") {
   185 		} elseif (substr($filedata, 0, 8) == "fishead\x00") {
   180 
   186 
   181 			// Ogg Skeleton version 3.0 Format Specification
   187 			// Ogg Skeleton version 3.0 Format Specification
   232 					$filedataoffset += 3;
   238 					$filedataoffset += 3;
   233 
   239 
   234 				} elseif (substr($filedata, 1, 6) == 'theora') {
   240 				} elseif (substr($filedata, 1, 6) == 'theora') {
   235 
   241 
   236 					$info['video']['dataformat'] = 'theora1';
   242 					$info['video']['dataformat'] = 'theora1';
   237 					$info['error'][] = 'Ogg Theora (v1) not correctly handled in this version of getID3 ['.$this->getid3->version().']';
   243 					$this->error('Ogg Theora (v1) not correctly handled in this version of getID3 ['.$this->getid3->version().']');
   238 					//break;
   244 					//break;
   239 
   245 
   240 				} elseif (substr($filedata, 1, 6) == 'vorbis') {
   246 				} elseif (substr($filedata, 1, 6) == 'vorbis') {
   241 
   247 
   242 					$this->ParseVorbisPageHeader($filedata, $filedataoffset, $oggpageinfo);
   248 					$this->ParseVorbisPageHeader($filedata, $filedataoffset, $oggpageinfo);
   243 
   249 
   244 				} else {
   250 				} else {
   245 					$info['error'][] = 'unexpected';
   251 					$this->error('unexpected');
   246 					//break;
   252 					//break;
   247 				}
   253 				}
   248 			//} while ($oggpageinfo['page_seqno'] == 0);
   254 			//} while ($oggpageinfo['page_seqno'] == 0);
   249 			} while (($oggpageinfo['page_seqno'] == 0) && (substr($filedata, 0, 8) != "fisbone\x00"));
   255 			} while (($oggpageinfo['page_seqno'] == 0) && (substr($filedata, 0, 8) != "fisbone\x00"));
   250 
   256 
   251 			$this->fseek($oggpageinfo['page_start_offset']);
   257 			$this->fseek($oggpageinfo['page_start_offset']);
   252 
   258 
   253 			$info['error'][] = 'Ogg Skeleton not correctly handled in this version of getID3 ['.$this->getid3->version().']';
   259 			$this->error('Ogg Skeleton not correctly handled in this version of getID3 ['.$this->getid3->version().']');
   254 			//return false;
   260 			//return false;
   255 
   261 
   256 		} else {
   262 		} else {
   257 
   263 
   258 			$info['error'][] = 'Expecting either "Speex   " or "vorbis" identifier strings, found "'.substr($filedata, 0, 8).'"';
   264 			$this->error('Expecting either "Speex   ", "OpusHead" or "vorbis" identifier strings, found "'.substr($filedata, 0, 8).'"');
   259 			unset($info['ogg']);
   265 			unset($info['ogg']);
   260 			unset($info['mime_type']);
   266 			unset($info['mime_type']);
   261 			return false;
   267 			return false;
   262 
   268 
   263 		}
   269 		}
   276 				break;
   282 				break;
   277 
   283 
   278 			case 'flac':
   284 			case 'flac':
   279 				$flac = new getid3_flac($this->getid3);
   285 				$flac = new getid3_flac($this->getid3);
   280 				if (!$flac->parseMETAdata()) {
   286 				if (!$flac->parseMETAdata()) {
   281 					$info['error'][] = 'Failed to parse FLAC headers';
   287 					$this->error('Failed to parse FLAC headers');
   282 					return false;
   288 					return false;
   283 				}
   289 				}
   284 				unset($flac);
   290 				unset($flac);
   285 				break;
   291 				break;
   286 
   292 
   287 			case 'speex':
   293 			case 'speex':
   288 				$this->fseek($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length'], SEEK_CUR);
   294 				$this->fseek($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length'], SEEK_CUR);
   289 				$this->ParseVorbisComments();
   295 				$this->ParseVorbisComments();
   290 				break;
   296 				break;
   291 		}
   297 
   292 
   298 			case 'opus':
       
   299 				$filedata = $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
       
   300 				$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['stream_type'] = substr($filedata, 0, 8); // hard-coded to 'OpusTags'
       
   301 				if(substr($filedata, 0, 8)  != 'OpusTags') {
       
   302 					$this->error('Expected "OpusTags" as header but got "'.substr($filedata, 0, 8).'"');
       
   303 					return false;
       
   304 				}
       
   305 
       
   306 				$this->ParseVorbisComments();
       
   307 				break;
       
   308 
       
   309 		}
   293 
   310 
   294 		// Last Page - Number of Samples
   311 		// Last Page - Number of Samples
   295 		if (!getid3_lib::intValueSupported($info['avdataend'])) {
   312 		if (!getid3_lib::intValueSupported($info['avdataend'])) {
   296 
   313 
   297 			$info['warning'][] = 'Unable to parse Ogg end chunk file (PHP does not support file operations beyond '.round(PHP_INT_MAX / 1073741824).'GB)';
   314 			$this->warning('Unable to parse Ogg end chunk file (PHP does not support file operations beyond '.round(PHP_INT_MAX / 1073741824).'GB)');
   298 
   315 
   299 		} else {
   316 		} else {
   300 
   317 
   301 			$this->fseek(max($info['avdataend'] - $this->getid3->fread_buffer_size(), 0));
   318 			$this->fseek(max($info['avdataend'] - $this->getid3->fread_buffer_size(), 0));
   302 			$LastChunkOfOgg = strrev($this->fread($this->getid3->fread_buffer_size()));
   319 			$LastChunkOfOgg = strrev($this->fread($this->getid3->fread_buffer_size()));
   304 				$this->fseek($info['avdataend'] - ($LastOggSpostion + strlen('SggO')));
   321 				$this->fseek($info['avdataend'] - ($LastOggSpostion + strlen('SggO')));
   305 				$info['avdataend'] = $this->ftell();
   322 				$info['avdataend'] = $this->ftell();
   306 				$info['ogg']['pageheader']['eos'] = $this->ParseOggPageHeader();
   323 				$info['ogg']['pageheader']['eos'] = $this->ParseOggPageHeader();
   307 				$info['ogg']['samples']   = $info['ogg']['pageheader']['eos']['pcm_abs_position'];
   324 				$info['ogg']['samples']   = $info['ogg']['pageheader']['eos']['pcm_abs_position'];
   308 				if ($info['ogg']['samples'] == 0) {
   325 				if ($info['ogg']['samples'] == 0) {
   309 					$info['error'][] = 'Corrupt Ogg file: eos.number of samples == zero';
   326 					$this->error('Corrupt Ogg file: eos.number of samples == zero');
   310 					return false;
   327 					return false;
   311 				}
   328 				}
   312 				if (!empty($info['audio']['sample_rate'])) {
   329 				if (!empty($info['audio']['sample_rate'])) {
   313 					$info['ogg']['bitrate_average'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / ($info['ogg']['samples'] / $info['audio']['sample_rate']);
   330 					$info['ogg']['bitrate_average'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / ($info['ogg']['samples'] / $info['audio']['sample_rate']);
   314 				}
   331 				}
   323 		} elseif (!empty($info['ogg']['bitrate_min']) && !empty($info['ogg']['bitrate_max'])) {
   340 		} elseif (!empty($info['ogg']['bitrate_min']) && !empty($info['ogg']['bitrate_max'])) {
   324 			$info['audio']['bitrate'] = ($info['ogg']['bitrate_min'] + $info['ogg']['bitrate_max']) / 2;
   341 			$info['audio']['bitrate'] = ($info['ogg']['bitrate_min'] + $info['ogg']['bitrate_max']) / 2;
   325 		}
   342 		}
   326 		if (isset($info['audio']['bitrate']) && !isset($info['playtime_seconds'])) {
   343 		if (isset($info['audio']['bitrate']) && !isset($info['playtime_seconds'])) {
   327 			if ($info['audio']['bitrate'] == 0) {
   344 			if ($info['audio']['bitrate'] == 0) {
   328 				$info['error'][] = 'Corrupt Ogg file: bitrate_audio == zero';
   345 				$this->error('Corrupt Ogg file: bitrate_audio == zero');
   329 				return false;
   346 				return false;
   330 			}
   347 			}
   331 			$info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $info['audio']['bitrate']);
   348 			$info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $info['audio']['bitrate']);
   332 		}
   349 		}
   333 
   350 
   376 		$filedataoffset += 1;
   393 		$filedataoffset += 1;
   377 		$info['audio']['channels']       = $info['ogg']['numberofchannels'];
   394 		$info['audio']['channels']       = $info['ogg']['numberofchannels'];
   378 		$info['ogg']['samplerate']       = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
   395 		$info['ogg']['samplerate']       = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
   379 		$filedataoffset += 4;
   396 		$filedataoffset += 4;
   380 		if ($info['ogg']['samplerate'] == 0) {
   397 		if ($info['ogg']['samplerate'] == 0) {
   381 			$info['error'][] = 'Corrupt Ogg file: sample rate == zero';
   398 			$this->error('Corrupt Ogg file: sample rate == zero');
   382 			return false;
   399 			return false;
   383 		}
   400 		}
   384 		$info['audio']['sample_rate']    = $info['ogg']['samplerate'];
   401 		$info['audio']['sample_rate']    = $info['ogg']['samplerate'];
   385 		$info['ogg']['samples']          = 0; // filled in later
   402 		$info['ogg']['samples']          = 0; // filled in later
   386 		$info['ogg']['bitrate_average']  = 0; // filled in later
   403 		$info['ogg']['bitrate_average']  = 0; // filled in later
   406 			unset($info['ogg']['bitrate_min']);
   423 			unset($info['ogg']['bitrate_min']);
   407 			$info['audio']['bitrate_mode'] = 'abr';
   424 			$info['audio']['bitrate_mode'] = 'abr';
   408 		}
   425 		}
   409 		return true;
   426 		return true;
   410 	}
   427 	}
       
   428 
       
   429 	// http://tools.ietf.org/html/draft-ietf-codec-oggopus-03
       
   430 	public function ParseOpusPageHeader(&$filedata, &$filedataoffset, &$oggpageinfo) {
       
   431 		$info = &$this->getid3->info;
       
   432 		$info['audio']['dataformat']   = 'opus';
       
   433 		$info['mime_type']             = 'audio/ogg; codecs=opus';
       
   434 
       
   435 		/** @todo find a usable way to detect abr (vbr that is padded to be abr) */
       
   436 		$info['audio']['bitrate_mode'] = 'vbr';
       
   437 
       
   438 		$info['audio']['lossless']     = false;
       
   439 
       
   440 		$info['ogg']['pageheader']['opus']['opus_magic'] = substr($filedata, $filedataoffset, 8); // hard-coded to 'OpusHead'
       
   441 		$filedataoffset += 8;
       
   442 		$info['ogg']['pageheader']['opus']['version']    = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset,  1));
       
   443 		$filedataoffset += 1;
       
   444 
       
   445 		if ($info['ogg']['pageheader']['opus']['version'] < 1 || $info['ogg']['pageheader']['opus']['version'] > 15) {
       
   446 			$this->error('Unknown opus version number (only accepting 1-15)');
       
   447 			return false;
       
   448 		}
       
   449 
       
   450 		$info['ogg']['pageheader']['opus']['out_channel_count'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset,  1));
       
   451 		$filedataoffset += 1;
       
   452 
       
   453 		if ($info['ogg']['pageheader']['opus']['out_channel_count'] == 0) {
       
   454 			$this->error('Invalid channel count in opus header (must not be zero)');
       
   455 			return false;
       
   456 		}
       
   457 
       
   458 		$info['ogg']['pageheader']['opus']['pre_skip'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset,  2));
       
   459 		$filedataoffset += 2;
       
   460 
       
   461 		$info['ogg']['pageheader']['opus']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset,  4));
       
   462 		$filedataoffset += 4;
       
   463 
       
   464 		//$info['ogg']['pageheader']['opus']['output_gain'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset,  2));
       
   465 		//$filedataoffset += 2;
       
   466 
       
   467 		//$info['ogg']['pageheader']['opus']['channel_mapping_family'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset,  1));
       
   468 		//$filedataoffset += 1;
       
   469 
       
   470 		$info['opus']['opus_version']      = $info['ogg']['pageheader']['opus']['version'];
       
   471 		$info['opus']['sample_rate']       = $info['ogg']['pageheader']['opus']['sample_rate'];
       
   472 		$info['opus']['out_channel_count'] = $info['ogg']['pageheader']['opus']['out_channel_count'];
       
   473 
       
   474 		$info['audio']['channels']      = $info['opus']['out_channel_count'];
       
   475 		$info['audio']['sample_rate']   = $info['opus']['sample_rate'];
       
   476 		return true;
       
   477 	}
       
   478 
   411 
   479 
   412 	public function ParseOggPageHeader() {
   480 	public function ParseOggPageHeader() {
   413 		// http://xiph.org/ogg/vorbis/doc/framing.html
   481 		// http://xiph.org/ogg/vorbis/doc/framing.html
   414 		$oggheader['page_start_offset'] = $this->ftell(); // where we started from in the file
   482 		$oggheader['page_start_offset'] = $this->ftell(); // where we started from in the file
   415 
   483 
   469 		$VorbisCommentPage = 1;
   537 		$VorbisCommentPage = 1;
   470 
   538 
   471 		switch ($info['audio']['dataformat']) {
   539 		switch ($info['audio']['dataformat']) {
   472 			case 'vorbis':
   540 			case 'vorbis':
   473 			case 'speex':
   541 			case 'speex':
       
   542 			case 'opus':
   474 				$CommentStartOffset = $info['ogg']['pageheader'][$VorbisCommentPage]['page_start_offset'];  // Second Ogg page, after header block
   543 				$CommentStartOffset = $info['ogg']['pageheader'][$VorbisCommentPage]['page_start_offset'];  // Second Ogg page, after header block
   475 				$this->fseek($CommentStartOffset);
   544 				$this->fseek($CommentStartOffset);
   476 				$commentdataoffset = 27 + $info['ogg']['pageheader'][$VorbisCommentPage]['page_segments'];
   545 				$commentdataoffset = 27 + $info['ogg']['pageheader'][$VorbisCommentPage]['page_segments'];
   477 				$commentdata = $this->fread(self::OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1) + $commentdataoffset);
   546 				$commentdata = $this->fread(self::OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1) + $commentdataoffset);
   478 
   547 
   479 				if ($info['audio']['dataformat'] == 'vorbis') {
   548 				if ($info['audio']['dataformat'] == 'vorbis') {
   480 					$commentdataoffset += (strlen('vorbis') + 1);
   549 					$commentdataoffset += (strlen('vorbis') + 1);
   481 				}
   550 				}
       
   551 				else if ($info['audio']['dataformat'] == 'opus') {
       
   552 					$commentdataoffset += strlen('OpusTags');
       
   553 				}
       
   554 
   482 				break;
   555 				break;
   483 
   556 
   484 			case 'flac':
   557 			case 'flac':
   485 				$CommentStartOffset = $info['flac']['VORBIS_COMMENT']['raw']['offset'] + 4;
   558 				$CommentStartOffset = $info['flac']['VORBIS_COMMENT']['raw']['offset'] + 4;
   486 				$this->fseek($CommentStartOffset);
   559 				$this->fseek($CommentStartOffset);
   487 				$commentdata = $this->fread($info['flac']['VORBIS_COMMENT']['raw']['block_length']);
   560 				$commentdata = $this->fread($info['flac']['VORBIS_COMMENT']['raw']['block_length']);
   488 				break;
   561 				break;
   489 
   562 
   490 			default:
   563 			default:
   491 				return false;
   564 				return false;
       
   565 				break;
   492 		}
   566 		}
   493 
   567 
   494 		$VendorSize = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4));
   568 		$VendorSize = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4));
   495 		$commentdataoffset += 4;
   569 		$commentdataoffset += 4;
   496 
   570 
   503 
   577 
   504 		$basicfields = array('TITLE', 'ARTIST', 'ALBUM', 'TRACKNUMBER', 'GENRE', 'DATE', 'DESCRIPTION', 'COMMENT');
   578 		$basicfields = array('TITLE', 'ARTIST', 'ALBUM', 'TRACKNUMBER', 'GENRE', 'DATE', 'DESCRIPTION', 'COMMENT');
   505 		$ThisFileInfo_ogg_comments_raw = &$info['ogg']['comments_raw'];
   579 		$ThisFileInfo_ogg_comments_raw = &$info['ogg']['comments_raw'];
   506 		for ($i = 0; $i < $CommentsCount; $i++) {
   580 		for ($i = 0; $i < $CommentsCount; $i++) {
   507 
   581 
       
   582 			if ($i >= 10000) {
       
   583 				// https://github.com/owncloud/music/issues/212#issuecomment-43082336
       
   584 				$this->warning('Unexpectedly large number ('.$CommentsCount.') of Ogg comments - breaking after reading '.$i.' comments');
       
   585 				break;
       
   586 			}
       
   587 
   508 			$ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] = $CommentStartOffset + $commentdataoffset;
   588 			$ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] = $CommentStartOffset + $commentdataoffset;
   509 
   589 
   510 			if ($this->ftell() < ($ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] + 4)) {
   590 			if ($this->ftell() < ($ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] + 4)) {
   511 				if ($oggpageinfo = $this->ParseOggPageHeader()) {
   591 				if ($oggpageinfo = $this->ParseOggPageHeader()) {
   512 					$info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
   592 					$info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
   537 			$info['avdataoffset'] = $ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] + $ThisFileInfo_ogg_comments_raw[$i]['size'] + 4;
   617 			$info['avdataoffset'] = $ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] + $ThisFileInfo_ogg_comments_raw[$i]['size'] + 4;
   538 
   618 
   539 			$commentdataoffset += 4;
   619 			$commentdataoffset += 4;
   540 			while ((strlen($commentdata) - $commentdataoffset) < $ThisFileInfo_ogg_comments_raw[$i]['size']) {
   620 			while ((strlen($commentdata) - $commentdataoffset) < $ThisFileInfo_ogg_comments_raw[$i]['size']) {
   541 				if (($ThisFileInfo_ogg_comments_raw[$i]['size'] > $info['avdataend']) || ($ThisFileInfo_ogg_comments_raw[$i]['size'] < 0)) {
   621 				if (($ThisFileInfo_ogg_comments_raw[$i]['size'] > $info['avdataend']) || ($ThisFileInfo_ogg_comments_raw[$i]['size'] < 0)) {
   542 					$info['warning'][] = 'Invalid Ogg comment size (comment #'.$i.', claims to be '.number_format($ThisFileInfo_ogg_comments_raw[$i]['size']).' bytes) - aborting reading comments';
   622 					$this->warning('Invalid Ogg comment size (comment #'.$i.', claims to be '.number_format($ThisFileInfo_ogg_comments_raw[$i]['size']).' bytes) - aborting reading comments');
   543 					break 2;
   623 					break 2;
   544 				}
   624 				}
   545 
   625 
   546 				$VorbisCommentPage++;
   626 				$VorbisCommentPage++;
   547 
   627 
   561 				// Finally, stick the unused data back on the end
   641 				// Finally, stick the unused data back on the end
   562 				$commentdata .= $AsYetUnusedData;
   642 				$commentdata .= $AsYetUnusedData;
   563 
   643 
   564 				//$commentdata .= $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
   644 				//$commentdata .= $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
   565 				if (!isset($info['ogg']['pageheader'][$VorbisCommentPage])) {
   645 				if (!isset($info['ogg']['pageheader'][$VorbisCommentPage])) {
   566 					$info['warning'][] = 'undefined Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell();
   646 					$this->warning('undefined Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell());
   567 					break;
   647 					break;
   568 				}
   648 				}
   569 				$readlength = self::OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1);
   649 				$readlength = self::OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1);
   570 				if ($readlength <= 0) {
   650 				if ($readlength <= 0) {
   571 					$info['warning'][] = 'invalid length Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell();
   651 					$this->warning('invalid length Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell());
   572 					break;
   652 					break;
   573 				}
   653 				}
   574 				$commentdata .= $this->fread($readlength);
   654 				$commentdata .= $this->fread($readlength);
   575 
   655 
   576 				//$filebaseoffset += $oggpageinfo['header_end_offset'] - $oggpageinfo['page_start_offset'];
   656 				//$filebaseoffset += $oggpageinfo['header_end_offset'] - $oggpageinfo['page_start_offset'];
   580 			$commentdataoffset += $ThisFileInfo_ogg_comments_raw[$i]['size'];
   660 			$commentdataoffset += $ThisFileInfo_ogg_comments_raw[$i]['size'];
   581 
   661 
   582 			if (!$commentstring) {
   662 			if (!$commentstring) {
   583 
   663 
   584 				// no comment?
   664 				// no comment?
   585 				$info['warning'][] = 'Blank Ogg comment ['.$i.']';
   665 				$this->warning('Blank Ogg comment ['.$i.']');
   586 
   666 
   587 			} elseif (strstr($commentstring, '=')) {
   667 			} elseif (strstr($commentstring, '=')) {
   588 
   668 
   589 				$commentexploded = explode('=', $commentstring, 2);
   669 				$commentexploded = explode('=', $commentstring, 2);
   590 				$ThisFileInfo_ogg_comments_raw[$i]['key']   = strtoupper($commentexploded[0]);
   670 				$ThisFileInfo_ogg_comments_raw[$i]['key']   = strtoupper($commentexploded[0]);
   613 					}
   693 					}
   614 
   694 
   615 					$ogg = new self($this->getid3);
   695 					$ogg = new self($this->getid3);
   616 					$ogg->setStringMode($data);
   696 					$ogg->setStringMode($data);
   617 					$info['ogg']['comments']['picture'][] = array(
   697 					$info['ogg']['comments']['picture'][] = array(
   618 						'image_mime' => $imageinfo['mime'],
   698 						'image_mime'   => $imageinfo['mime'],
   619 						'data'       => $ogg->saveAttachment('coverart', 0, strlen($data), $imageinfo['mime']),
   699 						'datalength'   => strlen($data),
       
   700 						'picturetype'  => 'cover art',
       
   701 						'image_height' => $imageinfo['height'],
       
   702 						'image_width'  => $imageinfo['width'],
       
   703 						'data'         => $ogg->saveAttachment('coverart', 0, strlen($data), $imageinfo['mime']),
   620 					);
   704 					);
   621 					unset($ogg);
   705 					unset($ogg);
   622 
   706 
   623 				} else {
   707 				} else {
   624 
   708 
   626 
   710 
   627 				}
   711 				}
   628 
   712 
   629 			} else {
   713 			} else {
   630 
   714 
   631 				$info['warning'][] = '[known problem with CDex >= v1.40, < v1.50b7] Invalid Ogg comment name/value pair ['.$i.']: '.$commentstring;
   715 				$this->warning('[known problem with CDex >= v1.40, < v1.50b7] Invalid Ogg comment name/value pair ['.$i.']: '.$commentstring);
   632 
   716 
   633 			}
   717 			}
   634 			unset($ThisFileInfo_ogg_comments_raw[$i]);
   718 			unset($ThisFileInfo_ogg_comments_raw[$i]);
   635 		}
   719 		}
   636 		unset($ThisFileInfo_ogg_comments_raw);
   720 		unset($ThisFileInfo_ogg_comments_raw);