/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
+// also https://github.com/JamesHeinrich/getID3 //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
$thisfile_id3v2_flags = &$thisfile_id3v2['flags'];
- fseek($this->getid3->fp, $this->StartingOffset, SEEK_SET);
- $header = fread($this->getid3->fp, 10);
+ $this->fseek($this->StartingOffset);
+ $header = $this->fread(10);
if (substr($header, 0, 3) == 'ID3' && strlen($header) == 10) {
$thisfile_id3v2['majorversion'] = ord($header{3});
}
if ($sizeofframes > 0) {
- $framedata = fread($this->getid3->fp, $sizeofframes); // read all frames from file into $framedata variable
+ $framedata = $this->fread($sizeofframes); // read all frames from file into $framedata variable
// if entire frame data is unsynched, de-unsynch it now (ID3v2.3.x)
if (!empty($thisfile_id3v2_flags['unsynch']) && ($id3v2_majorversion <= 3)) {
// ID3v2 size 4 * %0xxxxxxx
if (isset($thisfile_id3v2_flags['isfooter']) && $thisfile_id3v2_flags['isfooter']) {
- $footer = fread($this->getid3->fp, 10);
+ $footer = $this->fread(10);
if (substr($footer, 0, 3) == '3DI') {
$thisfile_id3v2['footer'] = true;
$thisfile_id3v2['majorversion_footer'] = ord($footer{3});
$frame_offset = 0;
$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))) {
$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);
- if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
+ 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_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
$parsedFrame['encodingid'] = $frame_textencoding;
$parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
- $parsedFrame['description'] = $frame_description;
- $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
+ $parsedFrame['description'] = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $frame_description));
+ $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
- $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']));
+ $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']])) {
+ $info['id3v2']['comments'][$parsedFrame['framenameshort']][$commentkey] = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']));
+ } else {
+ $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']));
+ }
}
//unset($parsedFrame['data']); do not unset, may be needed elsewhere, e.g. for replaygain
$frame_offset = 0;
$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))) {
$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);
- if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
+ 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_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
if (ord($frame_description) === 0) {
$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));
- if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator);
+ 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
}
if ($frame_terminatorpos) {
$frame_offset = 0;
$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))) {
$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_offset += 3;
- $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
- if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
+ 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_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
if (ord($frame_description) === 0) {
$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['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
$frame_offset = 0;
$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))) {
$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_offset += 3;
$frame_remainingdata = substr($parsedFrame['data'], $frame_offset);
while (strlen($frame_remainingdata)) {
$frame_offset = 0;
- $frame_terminatorpos = strpos($frame_remainingdata, $this->TextEncodingTerminatorLookup($frame_textencoding));
+ $frame_terminatorpos = strpos($frame_remainingdata, $frame_textencoding_terminator);
if ($frame_terminatorpos === false) {
$frame_remainingdata = '';
} 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
}
$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)) {
// timestamp probably omitted for first data item
} else {
$frame_offset = 0;
$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))) {
$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_offset += 3;
- $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
- if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
+ 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_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
if (ord($frame_description) === 0) {
$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['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
$parsedFrame['description'] = $frame_description;
$parsedFrame['data'] = $frame_text;
if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
- $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
+ $commentkey = ($parsedFrame['description'] ? $parsedFrame['description'] : (!empty($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']])) {
+ $info['id3v2']['comments'][$parsedFrame['framenameshort']][$commentkey] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
+ } else {
+ $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
+ }
}
}
$frame_offset = 0;
$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))) {
$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 ($frame_offset >= $parsedFrame['datalength']) {
$info['warning'][] = 'data portion of APIC frame is missing at offset '.($parsedFrame['dataoffset'] + 8 + $frame_offset);
} else {
- $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
- if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
+ 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_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
$parsedFrame['picturetypeid'] = $frame_picturetype;
$parsedFrame['picturetype'] = $this->APICPictureTypeLookup($frame_picturetype);
$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['image_mime'] = '';
if (!isset($info['id3v2']['comments']['picture'])) {
$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);
$frame_offset = 0;
$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))) {
$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_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
}
$frame_offset = $frame_terminatorpos + strlen("\x00");
- $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
- if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
+ 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_filename = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
if (ord($frame_filename) === 0) {
$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);
- if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
+ 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_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
if (ord($frame_description) === 0) {
$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['encodingid'] = $frame_textencoding;
} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'LINK')) || // 4.20 LINK Linked information
- (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'LNK'))) { // 4.22 LNK Linked information
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'LNK'))) { // 4.22 LNK Linked information
// There may be more than one 'LINK' frame in a tag,
// but only one with the same contents
// <Header for 'Linked information', ID: 'LINK'>
$parsedFrame['additionaldata'] = (string) substr($parsedFrame['data'], $frame_offset);
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']);
$frame_offset = 0;
$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))) {
$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_receivedasid = ord(substr($parsedFrame['data'], $frame_offset++, 1));
- $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
- if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
+ 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_sellername = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
if (ord($frame_sellername) === 0) {
$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);
- if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
+ 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_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
if (ord($frame_description) === 0) {
$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_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
$frame_offset += 2;
$parsedFrame['bitsperpoint'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
$frame_bytesperpoint = ceil($parsedFrame['bitsperpoint'] / 8);
- for ($i = 0; $i < $frame_indexpoints; $i++) {
+ for ($i = 0; $i < $parsedFrame['indexpoints']; $i++) {
$parsedFrame['indexes'][$i] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesperpoint));
$frame_offset += $frame_bytesperpoint;
}
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;
3 => "\x00", // $03 UTF-8 encoded Unicode. Terminated with $00.
255 => "\x00\x00"
);
- return (isset($TextEncodingTerminatorLookup[$encoding]) ? $TextEncodingTerminatorLookup[$encoding] : '');
+ return (isset($TextEncodingTerminatorLookup[$encoding]) ? $TextEncodingTerminatorLookup[$encoding] : "\x00");
}
public static function TextEncodingNameLookup($encoding) {