Scott Taylor 2015-06-28 00:17:25 +00:00
parent f077b3c511
commit a59b2ffcae
18 changed files with 465 additions and 120 deletions

View File

@ -519,11 +519,13 @@ class getid3_lib
} }
public static function XML2array($XMLstring) { public static function XML2array($XMLstring) {
if ( function_exists( 'simplexml_load_string' ) && function_exists( 'libxml_disable_entity_loader' ) ) { if (function_exists('simplexml_load_string') && function_exists('libxml_disable_entity_loader')) {
$loader = libxml_disable_entity_loader( true ); // http://websec.io/2012/08/27/Preventing-XEE-in-PHP.html
$XMLobject = simplexml_load_string( $XMLstring, 'SimpleXMLElement', LIBXML_NOENT ); // https://core.trac.wordpress.org/changeset/29378
$return = self::SimpleXMLelement2array( $XMLobject ); $loader = libxml_disable_entity_loader(true);
libxml_disable_entity_loader( $loader ); $XMLobject = simplexml_load_string($XMLstring, 'SimpleXMLElement', LIBXML_NOENT);
$return = self::SimpleXMLelement2array($XMLobject);
libxml_disable_entity_loader($loader);
return $return; return $return;
} }
return false; return false;
@ -1163,6 +1165,8 @@ class getid3_lib
fwrite($tmp, $imgData); fwrite($tmp, $imgData);
fclose($tmp); fclose($tmp);
$GetDataImageSize = @getimagesize($tempfilename, $imageinfo); $GetDataImageSize = @getimagesize($tempfilename, $imageinfo);
$GetDataImageSize['height'] = $GetDataImageSize[0];
$GetDataImageSize['width'] = $GetDataImageSize[1];
} }
unlink($tempfilename); unlink($tempfilename);
} }

View File

@ -28,7 +28,7 @@ $temp_dir = ini_get('upload_tmp_dir');
if ($temp_dir && (!is_dir($temp_dir) || !is_readable($temp_dir))) { if ($temp_dir && (!is_dir($temp_dir) || !is_readable($temp_dir))) {
$temp_dir = ''; $temp_dir = '';
} }
if (!$temp_dir) { if (!$temp_dir && function_exists('sys_get_temp_dir')) { // sys_get_temp_dir added in PHP v5.2.1
// sys_get_temp_dir() may give inaccessible temp dir, e.g. with open_basedir on virtual hosts // sys_get_temp_dir() may give inaccessible temp dir, e.g. with open_basedir on virtual hosts
$temp_dir = sys_get_temp_dir(); $temp_dir = sys_get_temp_dir();
} }
@ -109,7 +109,7 @@ class getID3
protected $startup_error = ''; protected $startup_error = '';
protected $startup_warning = ''; protected $startup_warning = '';
const VERSION = '1.9.8-20140511'; const VERSION = '1.9.9-20141121';
const FREAD_BUFFER_SIZE = 32768; const FREAD_BUFFER_SIZE = 32768;
const ATTACHMENTS_NONE = false; const ATTACHMENTS_NONE = false;
@ -249,7 +249,7 @@ class getID3
$this->filename = $filename; $this->filename = $filename;
$this->info = array(); $this->info = array();
$this->info['GETID3_VERSION'] = $this->version(); $this->info['GETID3_VERSION'] = $this->version();
$this->info['php_memory_limit'] = $this->memory_limit; $this->info['php_memory_limit'] = (($this->memory_limit > 0) ? $this->memory_limit : false);
// remote files not supported // remote files not supported
if (preg_match('/^(ht|f)tp:\/\//', $filename)) { if (preg_match('/^(ht|f)tp:\/\//', $filename)) {

View File

@ -35,7 +35,7 @@ class getid3_quicktime extends getid3_handler
$offset = 0; $offset = 0;
$atomcounter = 0; $atomcounter = 0;
$atom_data_read_buffer_size = ($info['php_memory_limit'] ? round($info['php_memory_limit'] / 2) : $this->getid3->option_fread_buffer_size * 1024); // allow [default: 32MB] if PHP configured with no memory_limit
while ($offset < $info['avdataend']) { while ($offset < $info['avdataend']) {
if (!getid3_lib::intValueSupported($offset)) { if (!getid3_lib::intValueSupported($offset)) {
$info['error'][] = 'Unable to parse atom at offset '.$offset.' because beyond '.round(PHP_INT_MAX / 1073741824).'GB limit of PHP filesystem functions'; $info['error'][] = 'Unable to parse atom at offset '.$offset.' because beyond '.round(PHP_INT_MAX / 1073741824).'GB limit of PHP filesystem functions';
@ -68,7 +68,7 @@ class getid3_quicktime extends getid3_handler
break; break;
} }
$atomHierarchy = array(); $atomHierarchy = array();
$info['quicktime'][$atomname] = $this->QuicktimeParseAtom($atomname, $atomsize, $this->fread(min($atomsize, round($this->getid3->memory_limit / 2))), $offset, $atomHierarchy, $this->ParseAllPossibleAtoms); $info['quicktime'][$atomname] = $this->QuicktimeParseAtom($atomname, $atomsize, $this->fread(min($atomsize, $atom_data_read_buffer_size)), $offset, $atomHierarchy, $this->ParseAllPossibleAtoms);
$offset += $atomsize; $offset += $atomsize;
$atomcounter++; $atomcounter++;
@ -799,9 +799,9 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
//$FrameRateCalculatorArray = array(); //$FrameRateCalculatorArray = array();
$frames_count = 0; $frames_count = 0;
$max_stts_entries_to_scan = min(floor($this->getid3->memory_limit / 10000), $atom_structure['number_entries']); $max_stts_entries_to_scan = ($info['php_memory_limit'] ? min(floor($this->getid3->memory_limit / 10000), $atom_structure['number_entries']) : $atom_structure['number_entries']);
if ($max_stts_entries_to_scan < $atom_structure['number_entries']) { if ($max_stts_entries_to_scan < $atom_structure['number_entries']) {
$info['warning'][] = 'QuickTime atom "stts" has '.$atom_structure['number_entries'].' but only scanning the first '.$max_stts_entries_to_scan.' entries due to limited PHP memory available ('.floor($this->getid3->memory_limit / 1048576).'MB).'; $info['warning'][] = 'QuickTime atom "stts" has '.$atom_structure['number_entries'].' but only scanning the first '.$max_stts_entries_to_scan.' entries due to limited PHP memory available ('.floor($atom_structure['number_entries'] / 1048576).'MB).';
} }
for ($i = 0; $i < $max_stts_entries_to_scan; $i++) { for ($i = 0; $i < $max_stts_entries_to_scan; $i++) {
$atom_structure['time_to_sample_table'][$i]['sample_count'] = getid3_lib::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4)); $atom_structure['time_to_sample_table'][$i]['sample_count'] = getid3_lib::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4));
@ -1399,7 +1399,7 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
case "\x00\x00\x00\x00": case "\x00\x00\x00\x00":
case 'meta': // METAdata atom case 'meta': // METAdata atom
// some kind of metacontainer, may contain a big data dump such as: // some kind of metacontainer, may contain a big data dump such as:
// mdta keys  mdtacom.apple.quicktime.make (mdtacom.apple.quicktime.creationdate ,mdtacom.apple.quicktime.location.ISO6709 $mdtacom.apple.quicktime.software !mdtacom.apple.quicktime.model ilst   data DEApple 0  (data DE2011-05-11T17:54:04+0200 2  *data DE+52.4936+013.3897+040.247/   data DE4.3.1  data DEiPhone 4 // mdta keys \005 mdtacom.apple.quicktime.make (mdtacom.apple.quicktime.creationdate ,mdtacom.apple.quicktime.location.ISO6709 $mdtacom.apple.quicktime.software !mdtacom.apple.quicktime.model ilst \01D \001 \015data \001DE\010Apple 0 \002 (data \001DE\0102011-05-11T17:54:04+0200 2 \003 *data \001DE\010+52.4936+013.3897+040.247/ \01D \004 \015data \001DE\0104.3.1 \005 \018data \001DE\010iPhone 4
// http://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt // http://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt
$atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));

View File

@ -135,7 +135,17 @@ class getid3_flac extends getid3_handler
if (isset($info['flac']['PICTURE']) && ($this->getid3->option_save_attachments !== getID3::ATTACHMENTS_NONE)) { if (isset($info['flac']['PICTURE']) && ($this->getid3->option_save_attachments !== getID3::ATTACHMENTS_NONE)) {
foreach ($info['flac']['PICTURE'] as $entry) { foreach ($info['flac']['PICTURE'] as $entry) {
if (!empty($entry['data'])) { if (!empty($entry['data'])) {
$info['flac']['comments']['picture'][] = array('image_mime'=>$entry['image_mime'], 'data'=>$entry['data']); if (!isset($info['flac']['comments']['picture'])) {
$info['flac']['comments']['picture'] = array();
}
$comments_picture_data = array();
foreach (array('data', 'image_mime', 'image_width', 'image_height', 'imagetype', 'picturetype', 'description', 'datalength') as $picture_key) {
if (isset($entry[$picture_key])) {
$comments_picture_data[$picture_key] = $entry[$picture_key];
}
}
$info['flac']['comments']['picture'][] = $comments_picture_data;
unset($comments_picture_data);
} }
} }
} }
@ -343,25 +353,25 @@ class getid3_flac extends getid3_handler
$info = &$this->getid3->info; $info = &$this->getid3->info;
$picture['typeid'] = getid3_lib::BigEndian2Int($this->fread(4)); $picture['typeid'] = getid3_lib::BigEndian2Int($this->fread(4));
$picture['type'] = self::pictureTypeLookup($picture['typeid']); $picture['picturetype'] = self::pictureTypeLookup($picture['typeid']);
$picture['image_mime'] = $this->fread(getid3_lib::BigEndian2Int($this->fread(4))); $picture['image_mime'] = $this->fread(getid3_lib::BigEndian2Int($this->fread(4)));
$descr_length = getid3_lib::BigEndian2Int($this->fread(4)); $descr_length = getid3_lib::BigEndian2Int($this->fread(4));
if ($descr_length) { if ($descr_length) {
$picture['description'] = $this->fread($descr_length); $picture['description'] = $this->fread($descr_length);
} }
$picture['width'] = getid3_lib::BigEndian2Int($this->fread(4)); $picture['image_width'] = getid3_lib::BigEndian2Int($this->fread(4));
$picture['height'] = getid3_lib::BigEndian2Int($this->fread(4)); $picture['image_height'] = getid3_lib::BigEndian2Int($this->fread(4));
$picture['color_depth'] = getid3_lib::BigEndian2Int($this->fread(4)); $picture['color_depth'] = getid3_lib::BigEndian2Int($this->fread(4));
$picture['colors_indexed'] = getid3_lib::BigEndian2Int($this->fread(4)); $picture['colors_indexed'] = getid3_lib::BigEndian2Int($this->fread(4));
$data_length = getid3_lib::BigEndian2Int($this->fread(4)); $picture['datalength'] = getid3_lib::BigEndian2Int($this->fread(4));
if ($picture['image_mime'] == '-->') { if ($picture['image_mime'] == '-->') {
$picture['data'] = $this->fread($data_length); $picture['data'] = $this->fread($picture['datalength']);
} else { } else {
$picture['data'] = $this->saveAttachment( $picture['data'] = $this->saveAttachment(
str_replace('/', '_', $picture['type']).'_'.$this->ftell(), str_replace('/', '_', $picture['picturetype']).'_'.$this->ftell(),
$this->ftell(), $this->ftell(),
$data_length, $picture['datalength'],
$picture['image_mime']); $picture['image_mime']);
} }

View File

@ -63,6 +63,12 @@ class getid3_ogg extends getid3_handler
$this->ParseVorbisPageHeader($filedata, $filedataoffset, $oggpageinfo); $this->ParseVorbisPageHeader($filedata, $filedataoffset, $oggpageinfo);
} elseif (substr($filedata, 0, 8) == 'OpusHead') {
if( $this->ParseOpusPageHeader($filedata, $filedataoffset, $oggpageinfo) == false ) {
return false;
}
} elseif (substr($filedata, 0, 8) == 'Speex ') { } elseif (substr($filedata, 0, 8) == 'Speex ') {
// http://www.speex.org/manual/node10.html // http://www.speex.org/manual/node10.html
@ -255,7 +261,7 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
} else { } else {
$info['error'][] = 'Expecting either "Speex " or "vorbis" identifier strings, found "'.substr($filedata, 0, 8).'"'; $info['error'][] = 'Expecting either "Speex ", "OpusHead" or "vorbis" identifier strings, found "'.substr($filedata, 0, 8).'"';
unset($info['ogg']); unset($info['ogg']);
unset($info['mime_type']); unset($info['mime_type']);
return false; return false;
@ -288,8 +294,19 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
$this->fseek($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length'], SEEK_CUR); $this->fseek($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length'], SEEK_CUR);
$this->ParseVorbisComments(); $this->ParseVorbisComments();
break; break;
case 'opus':
$filedata = $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
$info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['stream_type'] = substr($filedata, 0, 8); // hard-coded to 'OpusTags'
if(substr($filedata, 0, 8) != 'OpusTags') {
$info['error'][] = 'Expected "OpusTags" as header but got "'.substr($filedata, 0, 8).'"';
return false;
} }
$this->ParseVorbisComments();
break;
}
// Last Page - Number of Samples // Last Page - Number of Samples
if (!getid3_lib::intValueSupported($info['avdataend'])) { if (!getid3_lib::intValueSupported($info['avdataend'])) {
@ -409,6 +426,57 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
return true; return true;
} }
// http://tools.ietf.org/html/draft-ietf-codec-oggopus-03
public function ParseOpusPageHeader(&$filedata, &$filedataoffset, &$oggpageinfo) {
$info = &$this->getid3->info;
$info['audio']['dataformat'] = 'opus';
$info['mime_type'] = 'audio/ogg; codecs=opus';
/** @todo find a usable way to detect abr (vbr that is padded to be abr) */
$info['audio']['bitrate_mode'] = 'vbr';
$info['audio']['lossless'] = false;
$info['ogg']['pageheader']['opus']['opus_magic'] = substr($filedata, $filedataoffset, 8); // hard-coded to 'OpusHead'
$filedataoffset += 8;
$info['ogg']['pageheader']['opus']['version'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
$filedataoffset += 1;
if ($info['ogg']['pageheader']['opus']['version'] < 1 || $info['ogg']['pageheader']['opus']['version'] > 15) {
$info['error'][] = 'Unknown opus version number (only accepting 1-15)';
return false;
}
$info['ogg']['pageheader']['opus']['out_channel_count'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
$filedataoffset += 1;
if ($info['ogg']['pageheader']['opus']['out_channel_count'] == 0) {
$info['error'][] = 'Invalid channel count in opus header (must not be zero)';
return false;
}
$info['ogg']['pageheader']['opus']['pre_skip'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 2));
$filedataoffset += 2;
$info['ogg']['pageheader']['opus']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
//$info['ogg']['pageheader']['opus']['output_gain'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 2));
//$filedataoffset += 2;
//$info['ogg']['pageheader']['opus']['channel_mapping_family'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
//$filedataoffset += 1;
$info['opus']['opus_version'] = $info['ogg']['pageheader']['opus']['version'];
$info['opus']['sample_rate'] = $info['ogg']['pageheader']['opus']['sample_rate'];
$info['opus']['out_channel_count'] = $info['ogg']['pageheader']['opus']['out_channel_count'];
$info['audio']['channels'] = $info['opus']['out_channel_count'];
$info['audio']['sample_rate'] = $info['opus']['sample_rate'];
return true;
}
public function ParseOggPageHeader() { public function ParseOggPageHeader() {
// http://xiph.org/ogg/vorbis/doc/framing.html // http://xiph.org/ogg/vorbis/doc/framing.html
$oggheader['page_start_offset'] = $this->ftell(); // where we started from in the file $oggheader['page_start_offset'] = $this->ftell(); // where we started from in the file
@ -471,6 +539,7 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
switch ($info['audio']['dataformat']) { switch ($info['audio']['dataformat']) {
case 'vorbis': case 'vorbis':
case 'speex': case 'speex':
case 'opus':
$CommentStartOffset = $info['ogg']['pageheader'][$VorbisCommentPage]['page_start_offset']; // Second Ogg page, after header block $CommentStartOffset = $info['ogg']['pageheader'][$VorbisCommentPage]['page_start_offset']; // Second Ogg page, after header block
$this->fseek($CommentStartOffset); $this->fseek($CommentStartOffset);
$commentdataoffset = 27 + $info['ogg']['pageheader'][$VorbisCommentPage]['page_segments']; $commentdataoffset = 27 + $info['ogg']['pageheader'][$VorbisCommentPage]['page_segments'];
@ -479,6 +548,10 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
if ($info['audio']['dataformat'] == 'vorbis') { if ($info['audio']['dataformat'] == 'vorbis') {
$commentdataoffset += (strlen('vorbis') + 1); $commentdataoffset += (strlen('vorbis') + 1);
} }
else if ($info['audio']['dataformat'] == 'opus') {
$commentdataoffset += strlen('OpusTags');
}
break; break;
case 'flac': case 'flac':
@ -505,6 +578,12 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
$ThisFileInfo_ogg_comments_raw = &$info['ogg']['comments_raw']; $ThisFileInfo_ogg_comments_raw = &$info['ogg']['comments_raw'];
for ($i = 0; $i < $CommentsCount; $i++) { for ($i = 0; $i < $CommentsCount; $i++) {
if ($i >= 10000) {
// https://github.com/owncloud/music/issues/212#issuecomment-43082336
$info['warning'][] = 'Unexpectedly large number ('.$CommentsCount.') of Ogg comments - breaking after reading '.$i.' comments';
break;
}
$ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] = $CommentStartOffset + $commentdataoffset; $ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] = $CommentStartOffset + $commentdataoffset;
if ($this->ftell() < ($ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] + 4)) { if ($this->ftell() < ($ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] + 4)) {
@ -616,6 +695,10 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
$ogg->setStringMode($data); $ogg->setStringMode($data);
$info['ogg']['comments']['picture'][] = array( $info['ogg']['comments']['picture'][] = array(
'image_mime' => $imageinfo['mime'], 'image_mime' => $imageinfo['mime'],
'datalength' => strlen($data),
'picturetype' => 'cover art',
'image_height' => $imageinfo['height'],
'image_width' => $imageinfo['width'],
'data' => $ogg->saveAttachment('coverart', 0, strlen($data), $imageinfo['mime']), 'data' => $ogg->saveAttachment('coverart', 0, strlen($data), $imageinfo['mime']),
); );
unset($ogg); unset($ogg);

View File

@ -138,58 +138,88 @@ class getid3_apetag extends getid3_handler
$thisfile_ape_items_current['flags'] = $this->parseAPEtagFlags($item_flags); $thisfile_ape_items_current['flags'] = $this->parseAPEtagFlags($item_flags);
switch ($thisfile_ape_items_current['flags']['item_contents_raw']) { switch ($thisfile_ape_items_current['flags']['item_contents_raw']) {
case 0: // UTF-8 case 0: // UTF-8
case 3: // Locator (URL, filename, etc), UTF-8 encoded case 2: // Locator (URL, filename, etc), UTF-8 encoded
$thisfile_ape_items_current['data'] = explode("\x00", trim($thisfile_ape_items_current['data'])); $thisfile_ape_items_current['data'] = explode("\x00", $thisfile_ape_items_current['data']);
break; break;
default: // binary data case 1: // binary data
default:
break; break;
} }
switch (strtolower($item_key)) { switch (strtolower($item_key)) {
// http://wiki.hydrogenaud.io/index.php?title=ReplayGain#MP3Gain
case 'replaygain_track_gain': case 'replaygain_track_gain':
if (preg_match('#^[\\-\\+][0-9\\.,]{8}$#', $thisfile_ape_items_current['data'][0])) {
$thisfile_replaygain['track']['adjustment'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero! $thisfile_replaygain['track']['adjustment'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
$thisfile_replaygain['track']['originator'] = 'unspecified'; $thisfile_replaygain['track']['originator'] = 'unspecified';
} else {
$info['warning'][] = 'MP3gainTrackGain value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"';
}
break; break;
case 'replaygain_track_peak': case 'replaygain_track_peak':
if (preg_match('#^[0-9\\.,]{8}$#', $thisfile_ape_items_current['data'][0])) {
$thisfile_replaygain['track']['peak'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero! $thisfile_replaygain['track']['peak'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
$thisfile_replaygain['track']['originator'] = 'unspecified'; $thisfile_replaygain['track']['originator'] = 'unspecified';
if ($thisfile_replaygain['track']['peak'] <= 0) { if ($thisfile_replaygain['track']['peak'] <= 0) {
$info['warning'][] = 'ReplayGain Track peak from APEtag appears invalid: '.$thisfile_replaygain['track']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")'; $info['warning'][] = 'ReplayGain Track peak from APEtag appears invalid: '.$thisfile_replaygain['track']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")';
} }
} else {
$info['warning'][] = 'MP3gainTrackPeak value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"';
}
break; break;
case 'replaygain_album_gain': case 'replaygain_album_gain':
if (preg_match('#^[\\-\\+][0-9\\.,]{8}$#', $thisfile_ape_items_current['data'][0])) {
$thisfile_replaygain['album']['adjustment'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero! $thisfile_replaygain['album']['adjustment'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
$thisfile_replaygain['album']['originator'] = 'unspecified'; $thisfile_replaygain['album']['originator'] = 'unspecified';
} else {
$info['warning'][] = 'MP3gainAlbumGain value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"';
}
break; break;
case 'replaygain_album_peak': case 'replaygain_album_peak':
if (preg_match('#^[0-9\\.,]{8}$#', $thisfile_ape_items_current['data'][0])) {
$thisfile_replaygain['album']['peak'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero! $thisfile_replaygain['album']['peak'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
$thisfile_replaygain['album']['originator'] = 'unspecified'; $thisfile_replaygain['album']['originator'] = 'unspecified';
if ($thisfile_replaygain['album']['peak'] <= 0) { if ($thisfile_replaygain['album']['peak'] <= 0) {
$info['warning'][] = 'ReplayGain Album peak from APEtag appears invalid: '.$thisfile_replaygain['album']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")'; $info['warning'][] = 'ReplayGain Album peak from APEtag appears invalid: '.$thisfile_replaygain['album']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")';
} }
} else {
$info['warning'][] = 'MP3gainAlbumPeak value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"';
}
break; break;
case 'mp3gain_undo': case 'mp3gain_undo':
if (preg_match('#^[\\-\\+][0-9]{3},[\\-\\+][0-9]{3},[NW]$#', $thisfile_ape_items_current['data'][0])) {
list($mp3gain_undo_left, $mp3gain_undo_right, $mp3gain_undo_wrap) = explode(',', $thisfile_ape_items_current['data'][0]); list($mp3gain_undo_left, $mp3gain_undo_right, $mp3gain_undo_wrap) = explode(',', $thisfile_ape_items_current['data'][0]);
$thisfile_replaygain['mp3gain']['undo_left'] = intval($mp3gain_undo_left); $thisfile_replaygain['mp3gain']['undo_left'] = intval($mp3gain_undo_left);
$thisfile_replaygain['mp3gain']['undo_right'] = intval($mp3gain_undo_right); $thisfile_replaygain['mp3gain']['undo_right'] = intval($mp3gain_undo_right);
$thisfile_replaygain['mp3gain']['undo_wrap'] = (($mp3gain_undo_wrap == 'Y') ? true : false); $thisfile_replaygain['mp3gain']['undo_wrap'] = (($mp3gain_undo_wrap == 'Y') ? true : false);
} else {
$info['warning'][] = 'MP3gainUndo value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"';
}
break; break;
case 'mp3gain_minmax': case 'mp3gain_minmax':
if (preg_match('#^[0-9]{3},[0-9]{3}$#', $thisfile_ape_items_current['data'][0])) {
list($mp3gain_globalgain_min, $mp3gain_globalgain_max) = explode(',', $thisfile_ape_items_current['data'][0]); list($mp3gain_globalgain_min, $mp3gain_globalgain_max) = explode(',', $thisfile_ape_items_current['data'][0]);
$thisfile_replaygain['mp3gain']['globalgain_track_min'] = intval($mp3gain_globalgain_min); $thisfile_replaygain['mp3gain']['globalgain_track_min'] = intval($mp3gain_globalgain_min);
$thisfile_replaygain['mp3gain']['globalgain_track_max'] = intval($mp3gain_globalgain_max); $thisfile_replaygain['mp3gain']['globalgain_track_max'] = intval($mp3gain_globalgain_max);
} else {
$info['warning'][] = 'MP3gainMinMax value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"';
}
break; break;
case 'mp3gain_album_minmax': case 'mp3gain_album_minmax':
if (preg_match('#^[0-9]{3},[0-9]{3}$#', $thisfile_ape_items_current['data'][0])) {
list($mp3gain_globalgain_album_min, $mp3gain_globalgain_album_max) = explode(',', $thisfile_ape_items_current['data'][0]); list($mp3gain_globalgain_album_min, $mp3gain_globalgain_album_max) = explode(',', $thisfile_ape_items_current['data'][0]);
$thisfile_replaygain['mp3gain']['globalgain_album_min'] = intval($mp3gain_globalgain_album_min); $thisfile_replaygain['mp3gain']['globalgain_album_min'] = intval($mp3gain_globalgain_album_min);
$thisfile_replaygain['mp3gain']['globalgain_album_max'] = intval($mp3gain_globalgain_album_max); $thisfile_replaygain['mp3gain']['globalgain_album_max'] = intval($mp3gain_globalgain_album_max);
} else {
$info['warning'][] = 'MP3gainAlbumMinMax value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"';
}
break; break;
case 'tracknumber': case 'tracknumber':
@ -222,6 +252,10 @@ class getid3_apetag extends getid3_handler
case 'cover art (recording)': case 'cover art (recording)':
case 'cover art (studio)': case 'cover art (studio)':
// list of possible cover arts from http://taglib-sharp.sourcearchive.com/documentation/2.0.3.0-2/Ape_2Tag_8cs-source.html // list of possible cover arts from http://taglib-sharp.sourcearchive.com/documentation/2.0.3.0-2/Ape_2Tag_8cs-source.html
if (is_array($thisfile_ape_items_current['data'])) {
$info['warning'][] = 'APEtag "'.$item_key.'" should be flagged as Binary data, but was incorrectly flagged as UTF-8';
$thisfile_ape_items_current['data'] = implode("\x00", $thisfile_ape_items_current['data']);
}
list($thisfile_ape_items_current['filename'], $thisfile_ape_items_current['data']) = explode("\x00", $thisfile_ape_items_current['data'], 2); list($thisfile_ape_items_current['filename'], $thisfile_ape_items_current['data']) = explode("\x00", $thisfile_ape_items_current['data'], 2);
$thisfile_ape_items_current['data_offset'] = $thisfile_ape_items_current['offset'] + strlen($thisfile_ape_items_current['filename']."\x00"); $thisfile_ape_items_current['data_offset'] = $thisfile_ape_items_current['offset'] + strlen($thisfile_ape_items_current['filename']."\x00");
$thisfile_ape_items_current['data_length'] = strlen($thisfile_ape_items_current['data']); $thisfile_ape_items_current['data_length'] = strlen($thisfile_ape_items_current['data']);
@ -269,7 +303,14 @@ class getid3_apetag extends getid3_handler
if (!isset($info['ape']['comments']['picture'])) { if (!isset($info['ape']['comments']['picture'])) {
$info['ape']['comments']['picture'] = array(); $info['ape']['comments']['picture'] = array();
} }
$info['ape']['comments']['picture'][] = array('data'=>$thisfile_ape_items_current['data'], 'image_mime'=>$thisfile_ape_items_current['image_mime']); $comments_picture_data = array();
foreach (array('data', 'image_mime', 'image_width', 'image_height', 'imagetype', 'picturetype', 'description', 'datalength') as $picture_key) {
if (isset($thisfile_ape_items_current[$picture_key])) {
$comments_picture_data[$picture_key] = $thisfile_ape_items_current[$picture_key];
}
}
$info['ape']['comments']['picture'][] = $comments_picture_data;
unset($comments_picture_data);
} }
} while (false); } while (false);
break; break;
@ -317,7 +358,7 @@ class getid3_apetag extends getid3_handler
public function parseAPEtagFlags($rawflagint) { public function parseAPEtagFlags($rawflagint) {
// "Note: APE Tags 1.0 do not use any of the APE Tag flags. // "Note: APE Tags 1.0 do not use any of the APE Tag flags.
// All are set to zero on creation and ignored on reading." // All are set to zero on creation and ignored on reading."
// http://www.uni-jena.de/~pfk/mpp/sv8/apetagflags.html // http://wiki.hydrogenaud.io/index.php?title=Ape_Tags_Flags
$flags['header'] = (bool) ($rawflagint & 0x80000000); $flags['header'] = (bool) ($rawflagint & 0x80000000);
$flags['footer'] = (bool) ($rawflagint & 0x40000000); $flags['footer'] = (bool) ($rawflagint & 0x40000000);
$flags['this_is_header'] = (bool) ($rawflagint & 0x20000000); $flags['this_is_header'] = (bool) ($rawflagint & 0x20000000);

View File

@ -625,12 +625,13 @@ class getid3_id3v2 extends getid3_handler
$frame_offset = 0; $frame_offset = 0;
$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
$frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
$info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
$frame_textencoding_terminator = "\x00";
} }
$frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset); $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
} }
$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
@ -640,8 +641,8 @@ class getid3_id3v2 extends getid3_handler
$parsedFrame['encodingid'] = $frame_textencoding; $parsedFrame['encodingid'] = $frame_textencoding;
$parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
$parsedFrame['description'] = $frame_description; $parsedFrame['description'] = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $frame_description));
$parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding))); $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) { if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
$commentkey = ($parsedFrame['description'] ? $parsedFrame['description'] : (isset($info['id3v2']['comments'][$parsedFrame['framenameshort']]) ? count($info['id3v2']['comments'][$parsedFrame['framenameshort']]) : 0)); $commentkey = ($parsedFrame['description'] ? $parsedFrame['description'] : (isset($info['id3v2']['comments'][$parsedFrame['framenameshort']]) ? count($info['id3v2']['comments'][$parsedFrame['framenameshort']]) : 0));
if (!isset($info['id3v2']['comments'][$parsedFrame['framenameshort']]) || !array_key_exists($commentkey, $info['id3v2']['comments'][$parsedFrame['framenameshort']])) { if (!isset($info['id3v2']['comments'][$parsedFrame['framenameshort']]) || !array_key_exists($commentkey, $info['id3v2']['comments'][$parsedFrame['framenameshort']])) {
@ -717,11 +718,13 @@ class getid3_id3v2 extends getid3_handler
$frame_offset = 0; $frame_offset = 0;
$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
$frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
$info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
$frame_textencoding_terminator = "\x00";
} }
$frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset); $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
} }
$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
@ -729,10 +732,10 @@ class getid3_id3v2 extends getid3_handler
if (ord($frame_description) === 0) { if (ord($frame_description) === 0) {
$frame_description = ''; $frame_description = '';
} }
$parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding))); $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
$frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding)); $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator);
if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
} }
if ($frame_terminatorpos) { if ($frame_terminatorpos) {
@ -956,20 +959,22 @@ class getid3_id3v2 extends getid3_handler
$frame_offset = 0; $frame_offset = 0;
$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
$frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
$info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
$frame_textencoding_terminator = "\x00";
} }
$frame_language = substr($parsedFrame['data'], $frame_offset, 3); $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
$frame_offset += 3; $frame_offset += 3;
$frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset); $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
} }
$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
if (ord($frame_description) === 0) { if (ord($frame_description) === 0) {
$frame_description = ''; $frame_description = '';
} }
$parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding))); $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
$parsedFrame['encodingid'] = $frame_textencoding; $parsedFrame['encodingid'] = $frame_textencoding;
$parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
@ -1002,8 +1007,10 @@ class getid3_id3v2 extends getid3_handler
$frame_offset = 0; $frame_offset = 0;
$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
$frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
$info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
$frame_textencoding_terminator = "\x00";
} }
$frame_language = substr($parsedFrame['data'], $frame_offset, 3); $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
$frame_offset += 3; $frame_offset += 3;
@ -1020,16 +1027,16 @@ class getid3_id3v2 extends getid3_handler
$frame_remainingdata = substr($parsedFrame['data'], $frame_offset); $frame_remainingdata = substr($parsedFrame['data'], $frame_offset);
while (strlen($frame_remainingdata)) { while (strlen($frame_remainingdata)) {
$frame_offset = 0; $frame_offset = 0;
$frame_terminatorpos = strpos($frame_remainingdata, $this->TextEncodingTerminatorLookup($frame_textencoding)); $frame_terminatorpos = strpos($frame_remainingdata, $frame_textencoding_terminator);
if ($frame_terminatorpos === false) { if ($frame_terminatorpos === false) {
$frame_remainingdata = ''; $frame_remainingdata = '';
} else { } else {
if (ord(substr($frame_remainingdata, $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { if (ord(substr($frame_remainingdata, $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
} }
$parsedFrame['lyrics'][$timestampindex]['data'] = substr($frame_remainingdata, $frame_offset, $frame_terminatorpos - $frame_offset); $parsedFrame['lyrics'][$timestampindex]['data'] = substr($frame_remainingdata, $frame_offset, $frame_terminatorpos - $frame_offset);
$frame_remainingdata = substr($frame_remainingdata, $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding))); $frame_remainingdata = substr($frame_remainingdata, $frame_terminatorpos + strlen($frame_textencoding_terminator));
if (($timestampindex == 0) && (ord($frame_remainingdata{0}) != 0)) { if (($timestampindex == 0) && (ord($frame_remainingdata{0}) != 0)) {
// timestamp probably omitted for first data item // timestamp probably omitted for first data item
} else { } else {
@ -1060,20 +1067,22 @@ class getid3_id3v2 extends getid3_handler
$frame_offset = 0; $frame_offset = 0;
$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
$frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
$info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
$frame_textencoding_terminator = "\x00";
} }
$frame_language = substr($parsedFrame['data'], $frame_offset, 3); $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
$frame_offset += 3; $frame_offset += 3;
$frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset); $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
} }
$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
if (ord($frame_description) === 0) { if (ord($frame_description) === 0) {
$frame_description = ''; $frame_description = '';
} }
$frame_text = (string) substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding))); $frame_text = (string) substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
$parsedFrame['encodingid'] = $frame_textencoding; $parsedFrame['encodingid'] = $frame_textencoding;
$parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
@ -1330,8 +1339,10 @@ class getid3_id3v2 extends getid3_handler
$frame_offset = 0; $frame_offset = 0;
$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
$frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
$info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
$frame_textencoding_terminator = "\x00";
} }
if ($id3v2_majorversion == 2 && strlen($parsedFrame['data']) > $frame_offset) { if ($id3v2_majorversion == 2 && strlen($parsedFrame['data']) > $frame_offset) {
@ -1367,8 +1378,8 @@ class getid3_id3v2 extends getid3_handler
if ($frame_offset >= $parsedFrame['datalength']) { if ($frame_offset >= $parsedFrame['datalength']) {
$info['warning'][] = 'data portion of APIC frame is missing at offset '.($parsedFrame['dataoffset'] + 8 + $frame_offset); $info['warning'][] = 'data portion of APIC frame is missing at offset '.($parsedFrame['dataoffset'] + 8 + $frame_offset);
} else { } else {
$frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset); $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
} }
$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
@ -1386,7 +1397,7 @@ class getid3_id3v2 extends getid3_handler
$parsedFrame['picturetypeid'] = $frame_picturetype; $parsedFrame['picturetypeid'] = $frame_picturetype;
$parsedFrame['picturetype'] = $this->APICPictureTypeLookup($frame_picturetype); $parsedFrame['picturetype'] = $this->APICPictureTypeLookup($frame_picturetype);
$parsedFrame['description'] = $frame_description; $parsedFrame['description'] = $frame_description;
$parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding))); $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
$parsedFrame['datalength'] = strlen($parsedFrame['data']); $parsedFrame['datalength'] = strlen($parsedFrame['data']);
$parsedFrame['image_mime'] = ''; $parsedFrame['image_mime'] = '';
@ -1443,7 +1454,14 @@ class getid3_id3v2 extends getid3_handler
if (!isset($info['id3v2']['comments']['picture'])) { if (!isset($info['id3v2']['comments']['picture'])) {
$info['id3v2']['comments']['picture'] = array(); $info['id3v2']['comments']['picture'] = array();
} }
$info['id3v2']['comments']['picture'][] = array('data'=>$parsedFrame['data'], 'image_mime'=>$parsedFrame['image_mime']); $comments_picture_data = array();
foreach (array('data', 'image_mime', 'image_width', 'image_height', 'imagetype', 'picturetype', 'description', 'datalength') as $picture_key) {
if (isset($parsedFrame[$picture_key])) {
$comments_picture_data[$picture_key] = $parsedFrame[$picture_key];
}
}
$info['id3v2']['comments']['picture'][] = $comments_picture_data;
unset($comments_picture_data);
} }
} }
} while (false); } while (false);
@ -1462,8 +1480,10 @@ class getid3_id3v2 extends getid3_handler
$frame_offset = 0; $frame_offset = 0;
$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
$frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
$info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
$frame_textencoding_terminator = "\x00";
} }
$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
$frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
@ -1472,25 +1492,25 @@ class getid3_id3v2 extends getid3_handler
} }
$frame_offset = $frame_terminatorpos + strlen("\x00"); $frame_offset = $frame_terminatorpos + strlen("\x00");
$frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset); $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
} }
$frame_filename = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); $frame_filename = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
if (ord($frame_filename) === 0) { if (ord($frame_filename) === 0) {
$frame_filename = ''; $frame_filename = '';
} }
$frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)); $frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator);
$frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset); $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
} }
$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
if (ord($frame_description) === 0) { if (ord($frame_description) === 0) {
$frame_description = ''; $frame_description = '';
} }
$frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)); $frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator);
$parsedFrame['objectdata'] = (string) substr($parsedFrame['data'], $frame_offset); $parsedFrame['objectdata'] = (string) substr($parsedFrame['data'], $frame_offset);
$parsedFrame['encodingid'] = $frame_textencoding; $parsedFrame['encodingid'] = $frame_textencoding;
@ -1635,7 +1655,7 @@ class getid3_id3v2 extends getid3_handler
$parsedFrame['additionaldata'] = (string) substr($parsedFrame['data'], $frame_offset); $parsedFrame['additionaldata'] = (string) substr($parsedFrame['data'], $frame_offset);
if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) { if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) {
$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = utf8_encode($parsedFrame['url']); $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback_iso88591_utf8($parsedFrame['url']);
} }
unset($parsedFrame['data']); unset($parsedFrame['data']);
@ -1729,8 +1749,10 @@ class getid3_id3v2 extends getid3_handler
$frame_offset = 0; $frame_offset = 0;
$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
$frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
$info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
$frame_textencoding_terminator = "\x00";
} }
$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
@ -1752,25 +1774,25 @@ class getid3_id3v2 extends getid3_handler
$frame_receivedasid = ord(substr($parsedFrame['data'], $frame_offset++, 1)); $frame_receivedasid = ord(substr($parsedFrame['data'], $frame_offset++, 1));
$frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset); $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
} }
$frame_sellername = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); $frame_sellername = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
if (ord($frame_sellername) === 0) { if (ord($frame_sellername) === 0) {
$frame_sellername = ''; $frame_sellername = '';
} }
$frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)); $frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator);
$frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset); $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
} }
$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
if (ord($frame_description) === 0) { if (ord($frame_description) === 0) {
$frame_description = ''; $frame_description = '';
} }
$frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)); $frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator);
$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
$frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
@ -1944,6 +1966,186 @@ class getid3_id3v2 extends getid3_handler
unset($parsedFrame['data']); unset($parsedFrame['data']);
} elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'CHAP')) { // CHAP Chapters frame (ID3v2.3+ only)
// http://id3.org/id3v2-chapters-1.0
// <ID3v2.3 or ID3v2.4 frame header, ID: "CHAP"> (10 bytes)
// Element ID <text string> $00
// Start time $xx xx xx xx
// End time $xx xx xx xx
// Start offset $xx xx xx xx
// End offset $xx xx xx xx
// <Optional embedded sub-frames>
$frame_offset = 0;
@list($parsedFrame['element_id']) = explode("\x00", $parsedFrame['data'], 2);
$frame_offset += strlen($parsedFrame['element_id']."\x00");
$parsedFrame['time_begin'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
$frame_offset += 4;
$parsedFrame['time_end'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
$frame_offset += 4;
if (substr($parsedFrame['data'], $frame_offset, 4) != "\xFF\xFF\xFF\xFF") {
// "If these bytes are all set to 0xFF then the value should be ignored and the start time value should be utilized."
$parsedFrame['offset_begin'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
}
$frame_offset += 4;
if (substr($parsedFrame['data'], $frame_offset, 4) != "\xFF\xFF\xFF\xFF") {
// "If these bytes are all set to 0xFF then the value should be ignored and the start time value should be utilized."
$parsedFrame['offset_end'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
}
$frame_offset += 4;
if ($frame_offset < strlen($parsedFrame['data'])) {
$parsedFrame['subframes'] = array();
while ($frame_offset < strlen($parsedFrame['data'])) {
// <Optional embedded sub-frames>
$subframe = array();
$subframe['name'] = substr($parsedFrame['data'], $frame_offset, 4);
$frame_offset += 4;
$subframe['size'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
$frame_offset += 4;
$subframe['flags_raw'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
$frame_offset += 2;
if ($subframe['size'] > (strlen($parsedFrame['data']) - $frame_offset)) {
$info['warning'][] = 'CHAP subframe "'.$subframe['name'].'" at frame offset '.$frame_offset.' claims to be "'.$subframe['size'].'" bytes, which is more than the available data ('.(strlen($parsedFrame['data']) - $frame_offset).' bytes)';
break;
}
$subframe_rawdata = substr($parsedFrame['data'], $frame_offset, $subframe['size']);
$frame_offset += $subframe['size'];
$subframe['encodingid'] = ord(substr($subframe_rawdata, 0, 1));
$subframe['text'] = substr($subframe_rawdata, 1);
$subframe['encoding'] = $this->TextEncodingNameLookup($subframe['encodingid']);
$encoding_converted_text = trim(getid3_lib::iconv_fallback($subframe['encoding'], $info['encoding'], $subframe['text']));;
switch (substr($encoding_converted_text, 0, 2)) {
case "\xFF\xFE":
case "\xFE\xFF":
switch (strtoupper($info['id3v2']['encoding'])) {
case 'ISO-8859-1':
case 'UTF-8':
$encoding_converted_text = substr($encoding_converted_text, 2);
// remove unwanted byte-order-marks
break;
default:
// ignore
break;
}
break;
default:
// do not remove BOM
break;
}
if (($subframe['name'] == 'TIT2') || ($subframe['name'] == 'TIT3')) {
if ($subframe['name'] == 'TIT2') {
$parsedFrame['chapter_name'] = $encoding_converted_text;
} elseif ($subframe['name'] == 'TIT3') {
$parsedFrame['chapter_description'] = $encoding_converted_text;
}
$parsedFrame['subframes'][] = $subframe;
} else {
$info['warning'][] = 'ID3v2.CHAP subframe "'.$subframe['name'].'" not handled (only TIT2 and TIT3)';
}
}
unset($subframe_rawdata, $subframe, $encoding_converted_text);
}
$id3v2_chapter_entry = array();
foreach (array('id', 'time_begin', 'time_end', 'offset_begin', 'offset_end', 'chapter_name', 'chapter_description') as $id3v2_chapter_key) {
if (isset($parsedFrame[$id3v2_chapter_key])) {
$id3v2_chapter_entry[$id3v2_chapter_key] = $parsedFrame[$id3v2_chapter_key];
}
}
if (!isset($info['id3v2']['chapters'])) {
$info['id3v2']['chapters'] = array();
}
$info['id3v2']['chapters'][] = $id3v2_chapter_entry;
unset($id3v2_chapter_entry, $id3v2_chapter_key);
} elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'CTOC')) { // CTOC Chapters Table Of Contents frame (ID3v2.3+ only)
// http://id3.org/id3v2-chapters-1.0
// <ID3v2.3 or ID3v2.4 frame header, ID: "CTOC"> (10 bytes)
// Element ID <text string> $00
// CTOC flags %xx
// Entry count $xx
// Child Element ID <string>$00 /* zero or more child CHAP or CTOC entries */
// <Optional embedded sub-frames>
$frame_offset = 0;
@list($parsedFrame['element_id']) = explode("\x00", $parsedFrame['data'], 2);
$frame_offset += strlen($parsedFrame['element_id']."\x00");
$ctoc_flags_raw = ord(substr($parsedFrame['data'], $frame_offset, 1));
$frame_offset += 1;
$parsedFrame['entry_count'] = ord(substr($parsedFrame['data'], $frame_offset, 1));
$frame_offset += 1;
$terminator_position = null;
for ($i = 0; $i < $parsedFrame['entry_count']; $i++) {
$terminator_position = strpos($parsedFrame['data'], "\x00", $frame_offset);
$parsedFrame['child_element_ids'][$i] = substr($parsedFrame['data'], $frame_offset, $terminator_position - $frame_offset);
$frame_offset = $terminator_position + 1;
}
$parsedFrame['ctoc_flags']['ordered'] = (bool) ($ctoc_flags_raw & 0x01);
$parsedFrame['ctoc_flags']['top_level'] = (bool) ($ctoc_flags_raw & 0x03);
unset($ctoc_flags_raw, $terminator_position);
if ($frame_offset < strlen($parsedFrame['data'])) {
$parsedFrame['subframes'] = array();
while ($frame_offset < strlen($parsedFrame['data'])) {
// <Optional embedded sub-frames>
$subframe = array();
$subframe['name'] = substr($parsedFrame['data'], $frame_offset, 4);
$frame_offset += 4;
$subframe['size'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
$frame_offset += 4;
$subframe['flags_raw'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
$frame_offset += 2;
if ($subframe['size'] > (strlen($parsedFrame['data']) - $frame_offset)) {
$info['warning'][] = 'CTOS subframe "'.$subframe['name'].'" at frame offset '.$frame_offset.' claims to be "'.$subframe['size'].'" bytes, which is more than the available data ('.(strlen($parsedFrame['data']) - $frame_offset).' bytes)';
break;
}
$subframe_rawdata = substr($parsedFrame['data'], $frame_offset, $subframe['size']);
$frame_offset += $subframe['size'];
$subframe['encodingid'] = ord(substr($subframe_rawdata, 0, 1));
$subframe['text'] = substr($subframe_rawdata, 1);
$subframe['encoding'] = $this->TextEncodingNameLookup($subframe['encodingid']);
$encoding_converted_text = trim(getid3_lib::iconv_fallback($subframe['encoding'], $info['encoding'], $subframe['text']));;
switch (substr($encoding_converted_text, 0, 2)) {
case "\xFF\xFE":
case "\xFE\xFF":
switch (strtoupper($info['id3v2']['encoding'])) {
case 'ISO-8859-1':
case 'UTF-8':
$encoding_converted_text = substr($encoding_converted_text, 2);
// remove unwanted byte-order-marks
break;
default:
// ignore
break;
}
break;
default:
// do not remove BOM
break;
}
if (($subframe['name'] == 'TIT2') || ($subframe['name'] == 'TIT3')) {
if ($subframe['name'] == 'TIT2') {
$parsedFrame['toc_name'] = $encoding_converted_text;
} elseif ($subframe['name'] == 'TIT3') {
$parsedFrame['toc_description'] = $encoding_converted_text;
}
$parsedFrame['subframes'][] = $subframe;
} else {
$info['warning'][] = 'ID3v2.CTOC subframe "'.$subframe['name'].'" not handled (only TIT2 and TIT3)';
}
}
unset($subframe_rawdata, $subframe, $encoding_converted_text);
}
} }
return true; return true;
@ -3344,7 +3546,7 @@ class getid3_id3v2 extends getid3_handler
3 => "\x00", // $03 UTF-8 encoded Unicode. Terminated with $00. 3 => "\x00", // $03 UTF-8 encoded Unicode. Terminated with $00.
255 => "\x00\x00" 255 => "\x00\x00"
); );
return (isset($TextEncodingTerminatorLookup[$encoding]) ? $TextEncodingTerminatorLookup[$encoding] : ''); return (isset($TextEncodingTerminatorLookup[$encoding]) ? $TextEncodingTerminatorLookup[$encoding] : "\x00");
} }
public static function TextEncodingNameLookup($encoding) { public static function TextEncodingNameLookup($encoding) {
@ -3422,3 +3624,4 @@ class getid3_id3v2 extends getid3_handler
} }
} }

View File

@ -101,6 +101,7 @@ class getid3_lyrics3 extends getid3_handler
$this->getLyrics3Data($lyrics3offset, $lyrics3version, $lyrics3size); $this->getLyrics3Data($lyrics3offset, $lyrics3version, $lyrics3size);
if (!isset($info['ape'])) { if (!isset($info['ape'])) {
if (isset($info['lyrics3']['tag_offset_start'])) {
$GETID3_ERRORARRAY = &$info['warning']; $GETID3_ERRORARRAY = &$info['warning'];
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.apetag.php', __FILE__, true); getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.apetag.php', __FILE__, true);
$getid3_temp = new getID3(); $getid3_temp = new getID3();
@ -115,6 +116,9 @@ class getid3_lyrics3 extends getid3_handler
$info['replay_gain'] = $getid3_temp->info['replay_gain']; $info['replay_gain'] = $getid3_temp->info['replay_gain'];
} }
unset($getid3_temp, $getid3_apetag); unset($getid3_temp, $getid3_apetag);
} else {
$info['warning'][] = 'Lyrics3 and APE tags appear to have become entangled (most likely due to updating the APE tags with a non-Lyrics3-aware tagger)';
}
} }
} }

View File

@ -4,7 +4,7 @@
* *
* @global string $wp_version * @global string $wp_version
*/ */
$wp_version = '4.3-alpha-32978'; $wp_version = '4.3-alpha-32979';
/** /**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema. * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.