private function ParseVorbisCommentsFilepointer()
 {
     $getid3 = $this->getid3;
     $original_offset = ftell($getid3->fp);
     $comment_start_offset = $original_offset;
     $comment_data_offset = 0;
     $vorbis_comment_page = 1;
     switch ($getid3->info['audio']['dataformat']) {
         case 'vorbis':
             $comment_start_offset = $getid3->info['ogg']['pageheader'][$vorbis_comment_page]['page_start_offset'];
             // Second Ogg page, after header block
             fseek($getid3->fp, $comment_start_offset, SEEK_SET);
             $comment_data_offset = 27 + $getid3->info['ogg']['pageheader'][$vorbis_comment_page]['page_segments'];
             $comment_data = fread($getid3->fp, getid3_xiph::OggPageSegmentLength($getid3->info['ogg']['pageheader'][$vorbis_comment_page], 1) + $comment_data_offset);
             $comment_data_offset += strlen('vorbis') + 1;
             break;
         case 'flac':
             fseek($getid3->fp, $getid3->info['flac']['VORBIS_COMMENT']['raw']['offset'] + 4, SEEK_SET);
             $comment_data = fread($getid3->fp, $getid3->info['flac']['VORBIS_COMMENT']['raw']['block_length']);
             break;
         case 'speex':
             $comment_start_offset = $getid3->info['ogg']['pageheader'][$vorbis_comment_page]['page_start_offset'];
             // Second Ogg page, after header block
             fseek($getid3->fp, $comment_start_offset, SEEK_SET);
             $comment_data_offset = 27 + $getid3->info['ogg']['pageheader'][$vorbis_comment_page]['page_segments'];
             $comment_data = fread($getid3->fp, getid3_xiph::OggPageSegmentLength($getid3->info['ogg']['pageheader'][$vorbis_comment_page], 1) + $comment_data_offset);
             break;
         default:
             return false;
     }
     $vendor_size = getid3_lib::LittleEndian2Int(substr($comment_data, $comment_data_offset, 4));
     $comment_data_offset += 4;
     $getid3->info['ogg']['vendor'] = substr($comment_data, $comment_data_offset, $vendor_size);
     $comment_data_offset += $vendor_size;
     $comments_count = getid3_lib::LittleEndian2Int(substr($comment_data, $comment_data_offset, 4));
     $comment_data_offset += 4;
     $getid3->info['avdataoffset'] = $comment_start_offset + $comment_data_offset;
     for ($i = 0; $i < $comments_count; $i++) {
         $getid3->info['ogg']['comments_raw'][$i]['dataoffset'] = $comment_start_offset + $comment_data_offset;
         if (ftell($getid3->fp) < $getid3->info['ogg']['comments_raw'][$i]['dataoffset'] + 4) {
             $vorbis_comment_page++;
             $ogg_page_info = $this->ParseOggPageHeader();
             $getid3->info['ogg']['pageheader'][$ogg_page_info['page_seqno']] = $ogg_page_info;
             // First, save what we haven't read yet
             $as_yet_unused_data = substr($comment_data, $comment_data_offset);
             // Then take that data off the end
             $comment_data = substr($comment_data, 0, $comment_data_offset);
             // Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct
             $comment_data .= str_repeat("", 27 + $getid3->info['ogg']['pageheader'][$ogg_page_info['page_seqno']]['page_segments']);
             $comment_data_offset += 27 + $getid3->info['ogg']['pageheader'][$ogg_page_info['page_seqno']]['page_segments'];
             // Finally, stick the unused data back on the end
             $comment_data .= $as_yet_unused_data;
             $comment_data .= fread($getid3->fp, getid3_xiph::OggPageSegmentLength($getid3->info['ogg']['pageheader'][$vorbis_comment_page], 1));
         }
         $getid3->info['ogg']['comments_raw'][$i]['size'] = getid3_lib::LittleEndian2Int(substr($comment_data, $comment_data_offset, 4));
         // replace avdataoffset with position just after the last vorbiscomment
         $getid3->info['avdataoffset'] = $getid3->info['ogg']['comments_raw'][$i]['dataoffset'] + $getid3->info['ogg']['comments_raw'][$i]['size'] + 4;
         $comment_data_offset += 4;
         while (strlen($comment_data) - $comment_data_offset < $getid3->info['ogg']['comments_raw'][$i]['size']) {
             if ($getid3->info['ogg']['comments_raw'][$i]['size'] > $getid3->info['avdataend'] || $getid3->info['ogg']['comments_raw'][$i]['size'] < 0) {
                 throw new getid3_exception('Invalid Ogg comment size (comment #' . $i . ', claims to be ' . number_format($getid3->info['ogg']['comments_raw'][$i]['size']) . ' bytes) - aborting reading comments');
             }
             $vorbis_comment_page++;
             $ogg_page_info = $this->ParseOggPageHeader();
             $getid3->info['ogg']['pageheader'][$ogg_page_info['page_seqno']] = $ogg_page_info;
             // First, save what we haven't read yet
             $as_yet_unused_data = substr($comment_data, $comment_data_offset);
             // Then take that data off the end
             $comment_data = substr($comment_data, 0, $comment_data_offset);
             // Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct
             $comment_data .= str_repeat("", 27 + $getid3->info['ogg']['pageheader'][$ogg_page_info['page_seqno']]['page_segments']);
             $comment_data_offset += 27 + $getid3->info['ogg']['pageheader'][$ogg_page_info['page_seqno']]['page_segments'];
             // Finally, stick the unused data back on the end
             $comment_data .= $as_yet_unused_data;
             //$comment_data .= fread($getid3->fp, $getid3->info['ogg']['pageheader'][$ogg_page_info['page_seqno']]['page_length']);
             $comment_data .= fread($getid3->fp, getid3_xiph::OggPageSegmentLength($getid3->info['ogg']['pageheader'][$vorbis_comment_page], 1));
             //$filebaseoffset += $ogg_page_info['header_end_offset'] - $ogg_page_info['page_start_offset'];
         }
         $comment_string = substr($comment_data, $comment_data_offset, $getid3->info['ogg']['comments_raw'][$i]['size']);
         $comment_data_offset += $getid3->info['ogg']['comments_raw'][$i]['size'];
         if (!$comment_string) {
             // no comment?
             $getid3->warning('Blank Ogg comment [' . $i . ']');
         } elseif (strstr($comment_string, '=')) {
             $comment_exploded = explode('=', $comment_string, 2);
             $getid3->info['ogg']['comments_raw'][$i]['key'] = strtoupper($comment_exploded[0]);
             $getid3->info['ogg']['comments_raw'][$i]['value'] = @$comment_exploded[1];
             $getid3->info['ogg']['comments_raw'][$i]['data'] = base64_decode($getid3->info['ogg']['comments_raw'][$i]['value']);
             $getid3->info['ogg']['comments'][strtolower($getid3->info['ogg']['comments_raw'][$i]['key'])][] = $getid3->info['ogg']['comments_raw'][$i]['value'];
             if ($getid3->option_tags_images) {
                 $image_chunk_check = getid3_lib_image_size::get($getid3->info['ogg']['comments_raw'][$i]['data']);
                 $getid3->info['ogg']['comments_raw'][$i]['image_mime'] = image_type_to_mime_type($image_chunk_check[2]);
             }
             if (!@$getid3->info['ogg']['comments_raw'][$i]['image_mime'] || $getid3->info['ogg']['comments_raw'][$i]['image_mime'] == 'application/octet-stream') {
                 unset($getid3->info['ogg']['comments_raw'][$i]['image_mime']);
                 unset($getid3->info['ogg']['comments_raw'][$i]['data']);
             }
         } else {
             $getid3->warning('[known problem with CDex >= v1.40, < v1.50b7] Invalid Ogg comment name/value pair [' . $i . ']: ' . $comment_string);
         }
     }
     // Replay Gain Adjustment
     // http://privatewww.essex.ac.uk/~djmrob/replaygain/
     if (isset($getid3->info['ogg']['comments']) && is_array($getid3->info['ogg']['comments'])) {
         foreach ($getid3->info['ogg']['comments'] as $index => $commentvalue) {
             switch ($index) {
                 case 'rg_audiophile':
                 case 'replaygain_album_gain':
                     $getid3->info['replay_gain']['album']['adjustment'] = (double) $commentvalue[0];
                     unset($getid3->info['ogg']['comments'][$index]);
                     break;
                 case 'rg_radio':
                 case 'replaygain_track_gain':
                     $getid3->info['replay_gain']['track']['adjustment'] = (double) $commentvalue[0];
                     unset($getid3->info['ogg']['comments'][$index]);
                     break;
                 case 'replaygain_album_peak':
                     $getid3->info['replay_gain']['album']['peak'] = (double) $commentvalue[0];
                     unset($getid3->info['ogg']['comments'][$index]);
                     break;
                 case 'rg_peak':
                 case 'replaygain_track_peak':
                     $getid3->info['replay_gain']['track']['peak'] = (double) $commentvalue[0];
                     unset($getid3->info['ogg']['comments'][$index]);
                     break;
                 case 'replaygain_reference_loudness':
                     $getid3->info['replay_gain']['reference_volume'] = (double) $commentvalue[0];
                     unset($getid3->info['ogg']['comments'][$index]);
                     break;
             }
         }
     }
     fseek($getid3->fp, $original_offset, SEEK_SET);
     return true;
 }
Esempio n. 2
0
 private function ParseID3v2Frame(&$parsed_frame)
 {
     $getid3 = $this->getid3;
     $id3v2_major_version = $getid3->info['id3v2']['majorversion'];
     $frame_name_long = getid3_id3v2::FrameNameLongLookup($parsed_frame['frame_name']);
     if ($frame_name_long) {
         $parsed_frame['framenamelong'] = $frame_name_long;
     }
     $frame_name_short = getid3_id3v2::FrameNameShortLookup($parsed_frame['frame_name']);
     if ($frame_name_short) {
         $parsed_frame['framenameshort'] = $frame_name_short;
     }
     if ($id3v2_major_version >= 3) {
         // frame flags are not part of the ID3v2.2 standard
         if ($id3v2_major_version == 3) {
             //    Frame Header Flags
             //    %abc00000 %ijk00000
             $parsed_frame['flags']['TagAlterPreservation'] = (bool) ($parsed_frame['frame_flags_raw'] & 0x8000);
             // a - Tag alter preservation
             $parsed_frame['flags']['FileAlterPreservation'] = (bool) ($parsed_frame['frame_flags_raw'] & 0x4000);
             // b - File alter preservation
             $parsed_frame['flags']['ReadOnly'] = (bool) ($parsed_frame['frame_flags_raw'] & 0x2000);
             // c - Read only
             $parsed_frame['flags']['compression'] = (bool) ($parsed_frame['frame_flags_raw'] & 0x80);
             // i - Compression
             $parsed_frame['flags']['Encryption'] = (bool) ($parsed_frame['frame_flags_raw'] & 0x40);
             // j - Encryption
             $parsed_frame['flags']['GroupingIdentity'] = (bool) ($parsed_frame['frame_flags_raw'] & 0x20);
             // k - Grouping identity
         } elseif ($id3v2_major_version == 4) {
             //    Frame Header Flags
             //    %0abc0000 %0h00kmnp
             $parsed_frame['flags']['TagAlterPreservation'] = (bool) ($parsed_frame['frame_flags_raw'] & 0x4000);
             // a - Tag alter preservation
             $parsed_frame['flags']['FileAlterPreservation'] = (bool) ($parsed_frame['frame_flags_raw'] & 0x2000);
             // b - File alter preservation
             $parsed_frame['flags']['ReadOnly'] = (bool) ($parsed_frame['frame_flags_raw'] & 0x1000);
             // c - Read only
             $parsed_frame['flags']['GroupingIdentity'] = (bool) ($parsed_frame['frame_flags_raw'] & 0x40);
             // h - Grouping identity
             $parsed_frame['flags']['compression'] = (bool) ($parsed_frame['frame_flags_raw'] & 0x8);
             // k - Compression
             $parsed_frame['flags']['Encryption'] = (bool) ($parsed_frame['frame_flags_raw'] & 0x4);
             // m - Encryption
             $parsed_frame['flags']['Unsynchronisation'] = (bool) ($parsed_frame['frame_flags_raw'] & 0x2);
             // n - Unsynchronisation
             $parsed_frame['flags']['DataLengthIndicator'] = (bool) ($parsed_frame['frame_flags_raw'] & 0x1);
             // p - Data length indicator
             // Frame-level de-unsynchronisation - ID3v2.4
             if ($parsed_frame['flags']['Unsynchronisation']) {
                 $parsed_frame['data'] = str_replace("ÿ", "ÿ", $parsed_frame['data']);
             }
         }
         //    Frame-level de-compression
         if ($parsed_frame['flags']['compression']) {
             $parsed_frame['decompressed_size'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], 0, 4));
             if (!function_exists('gzuncompress')) {
                 $getid3->warning('gzuncompress() support required to decompress ID3v2 frame "' . $parsed_frame['frame_name'] . '"');
             } elseif ($decompressed_data = @gzuncompress(substr($parsed_frame['data'], 4))) {
                 $parsed_frame['data'] = $decompressed_data;
             } else {
                 $getid3->warning('gzuncompress() failed on compressed contents of ID3v2 frame "' . $parsed_frame['frame_name'] . '"');
             }
         }
     }
     if (isset($parsed_frame['datalength']) && $parsed_frame['datalength'] == 0) {
         $warning = 'Frame "' . $parsed_frame['frame_name'] . '" at offset ' . $parsed_frame['dataoffset'] . ' has no data portion';
         switch ($parsed_frame['frame_name']) {
             case 'WCOM':
                 $warning .= ' (this is known to happen with files tagged by RioPort)';
                 break;
             default:
                 break;
         }
         $getid3->warning($warning);
         return true;
     }
     if ($id3v2_major_version >= 3 && $parsed_frame['frame_name'] == 'UFID' || $id3v2_major_version == 2 && $parsed_frame['frame_name'] == 'UFI') {
         // 4.1   UFI  Unique file identifier
         //   There may be more than one 'UFID' frame in a tag,
         //   but only one with the same 'Owner identifier'.
         // <Header for 'Unique file identifier', ID: 'UFID'>
         // Owner identifier        <text string> $00
         // Identifier              <up to 64 bytes binary data>
         $frame_terminator_pos = strpos($parsed_frame['data'], "");
         $frame_id_string = substr($parsed_frame['data'], 0, $frame_terminator_pos);
         $parsed_frame['ownerid'] = $frame_id_string;
         $parsed_frame['data'] = substr($parsed_frame['data'], $frame_terminator_pos + strlen(""));
         unset($parsed_frame['data']);
         return true;
     }
     if ($id3v2_major_version >= 3 && $parsed_frame['frame_name'] == 'TXXX' || $id3v2_major_version == 2 && $parsed_frame['frame_name'] == 'TXX') {
         // 4.2.2 TXX  User defined text information frame
         //   There may be more than one 'TXXX' frame in each tag,
         //   but only one with the same description.
         // <Header for 'User defined text information frame', ID: 'TXXX'>
         // Text encoding     $xx
         // Description       <text string according to encoding> $00 (00)
         // Value             <text string according to encoding>
         $frame_offset = 0;
         $frame_text_encoding = ord($parsed_frame['data'][$frame_offset++]);
         if ($id3v2_major_version <= 3 && $frame_text_encoding > 1 || $id3v2_major_version == 4 && $frame_text_encoding > 3) {
             $getid3->warning('Invalid text encoding byte (' . $frame_text_encoding . ') in frame "' . $parsed_frame['frame_name'] . '" - defaulting to ISO-8859-1 encoding');
         }
         $frame_terminator_pos = @strpos($parsed_frame['data'], getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding), $frame_offset);
         if (ord(substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)), 1)) === 0) {
             $frame_terminator_pos++;
             // @strpos() fooled because 2nd byte of Unicode chars are often 0x00
         }
         $frame_description = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset);
         if (ord($frame_description) === 0) {
             $frame_description = '';
         }
         $parsed_frame['encodingid'] = $frame_text_encoding;
         $parsed_frame['encoding'] = $this->TextEncodingNameLookup($frame_text_encoding);
         $parsed_frame['description'] = $frame_description;
         $parsed_frame['data'] = substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)));
         if (!empty($parsed_frame['framenameshort']) && !empty($parsed_frame['data'])) {
             $getid3->info['id3v2']['comments'][$parsed_frame['framenameshort']][] = trim($getid3->iconv($parsed_frame['encoding'], 'UTF-8', $parsed_frame['data']));
         }
         unset($parsed_frame['data']);
         return true;
     }
     if ($parsed_frame['frame_name'][0] == 'T') {
         // 4.2. T??[?] Text information frame
         //   There may only be one text information frame of its kind in an tag.
         // <Header for 'Text information frame', ID: 'T000' - 'TZZZ',
         // excluding 'TXXX' described in 4.2.6.>
         // Text encoding                $xx
         // Information                  <text string(s) according to encoding>
         $frame_offset = 0;
         $frame_text_encoding = ord($parsed_frame['data'][$frame_offset++]);
         if ($id3v2_major_version <= 3 && $frame_text_encoding > 1 || $id3v2_major_version == 4 && $frame_text_encoding > 3) {
             $getid3->warning('Invalid text encoding byte (' . $frame_text_encoding . ') in frame "' . $parsed_frame['frame_name'] . '" - defaulting to ISO-8859-1 encoding');
         }
         $parsed_frame['data'] = (string) substr($parsed_frame['data'], $frame_offset);
         $parsed_frame['encodingid'] = $frame_text_encoding;
         $parsed_frame['encoding'] = $this->TextEncodingNameLookup($frame_text_encoding);
         if (!empty($parsed_frame['framenameshort']) && !empty($parsed_frame['data'])) {
             // remove possible terminating \x00 (put by encoding id or software bug)
             $string = $getid3->iconv($parsed_frame['encoding'], 'UTF-8', $parsed_frame['data']);
             if ($string[strlen($string) - 1] = "") {
                 $string = substr($string, 0, strlen($string) - 1);
             }
             $getid3->info['id3v2']['comments'][$parsed_frame['framenameshort']][] = $string;
             unset($string);
         }
         return true;
     }
     if ($id3v2_major_version >= 3 && $parsed_frame['frame_name'] == 'WXXX' || $id3v2_major_version == 2 && $parsed_frame['frame_name'] == 'WXX') {
         // 4.3.2 WXX  User defined URL link frame
         //   There may be more than one 'WXXX' frame in each tag,
         //   but only one with the same description
         // <Header for 'User defined URL link frame', ID: 'WXXX'>
         // Text encoding     $xx
         // Description       <text string according to encoding> $00 (00)
         // URL               <text string>
         $frame_offset = 0;
         $frame_text_encoding = ord($parsed_frame['data'][$frame_offset++]);
         if ($id3v2_major_version <= 3 && $frame_text_encoding > 1 || $id3v2_major_version == 4 && $frame_text_encoding > 3) {
             $getid3->warning('Invalid text encoding byte (' . $frame_text_encoding . ') in frame "' . $parsed_frame['frame_name'] . '" - defaulting to ISO-8859-1 encoding');
         }
         $frame_terminator_pos = @strpos($parsed_frame['data'], getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding), $frame_offset);
         if (ord(substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)), 1)) === 0) {
             $frame_terminator_pos++;
             // @strpos() fooled because 2nd byte of Unicode chars are often 0x00
         }
         $frame_description = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset);
         if (ord($frame_description) === 0) {
             $frame_description = '';
         }
         $parsed_frame['data'] = substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)));
         $frame_terminator_pos = strpos($parsed_frame['data'], getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding));
         if (ord(substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)), 1)) === 0) {
             $frame_terminator_pos++;
             // strpos() fooled because 2nd byte of Unicode chars are often 0x00
         }
         if ($frame_terminator_pos) {
             // there are null bytes after the data - this is not according to spec
             // only use data up to first null byte
             $frame_urldata = (string) substr($parsed_frame['data'], 0, $frame_terminator_pos);
         } else {
             // no null bytes following data, just use all data
             $frame_urldata = (string) $parsed_frame['data'];
         }
         $parsed_frame['encodingid'] = $frame_text_encoding;
         $parsed_frame['encoding'] = $this->TextEncodingNameLookup($frame_text_encoding);
         $parsed_frame['url'] = $frame_urldata;
         $parsed_frame['description'] = $frame_description;
         if (!empty($parsed_frame['framenameshort']) && $parsed_frame['url']) {
             $getid3->info['id3v2']['comments'][$parsed_frame['framenameshort']][] = $getid3->iconv($parsed_frame['encoding'], 'UTF-8', $parsed_frame['url']);
         }
         unset($parsed_frame['data']);
         return true;
     }
     if ($parsed_frame['frame_name'][0] == 'W') {
         // 4.3. W??? URL link frames
         //   There may only be one URL link frame of its kind in a tag,
         //   except when stated otherwise in the frame description
         // <Header for 'URL link frame', ID: 'W000' - 'WZZZ', excluding 'WXXX'
         // described in 4.3.2.>
         // URL              <text string>
         $parsed_frame['url'] = trim($parsed_frame['data']);
         if (!empty($parsed_frame['framenameshort']) && $parsed_frame['url']) {
             $getid3->info['id3v2']['comments'][$parsed_frame['framenameshort']][] = $parsed_frame['url'];
         }
         unset($parsed_frame['data']);
         return true;
     }
     if ($id3v2_major_version == 3 && $parsed_frame['frame_name'] == 'IPLS' || $id3v2_major_version == 2 && $parsed_frame['frame_name'] == 'IPL') {
         // 4.4  IPL  Involved people list (ID3v2.2 only)
         //   There may only be one 'IPL' frame in each tag
         // <Header for 'User defined URL link frame', ID: 'IPL'>
         // Text encoding     $xx
         // People list strings    <textstrings>
         $frame_offset = 0;
         $frame_text_encoding = ord($parsed_frame['data'][$frame_offset++]);
         if ($id3v2_major_version <= 3 && $frame_text_encoding > 1 || $id3v2_major_version == 4 && $frame_text_encoding > 3) {
             $getid3->warning('Invalid text encoding byte (' . $frame_text_encoding . ') in frame "' . $parsed_frame['frame_name'] . '" - defaulting to ISO-8859-1 encoding');
         }
         $parsed_frame['encodingid'] = $frame_text_encoding;
         $parsed_frame['encoding'] = $this->TextEncodingNameLookup($parsed_frame['encodingid']);
         $parsed_frame['data'] = (string) substr($parsed_frame['data'], $frame_offset);
         if (!empty($parsed_frame['framenameshort']) && !empty($parsed_frame['data'])) {
             $getid3->info['id3v2']['comments'][$parsed_frame['framenameshort']][] = $getid3->iconv($parsed_frame['encoding'], 'UTF-8', $parsed_frame['data']);
         }
         return true;
     }
     if ($id3v2_major_version >= 3 && $parsed_frame['frame_name'] == 'MCDI' || $id3v2_major_version == 2 && $parsed_frame['frame_name'] == 'MCI') {
         // 4.5   MCI  Music CD identifier
         //   There may only be one 'MCDI' frame in each tag
         // <Header for 'Music CD identifier', ID: 'MCDI'>
         // CD TOC                <binary data>
         if (!empty($parsed_frame['framenameshort']) && !empty($parsed_frame['data'])) {
             $getid3->info['id3v2']['comments'][$parsed_frame['framenameshort']][] = $parsed_frame['data'];
         }
         return true;
     }
     if ($id3v2_major_version >= 3 && $parsed_frame['frame_name'] == 'ETCO' || $id3v2_major_version == 2 && $parsed_frame['frame_name'] == 'ETC') {
         // 4.6   ETC  Event timing codes
         //   There may only be one 'ETCO' frame in each tag
         // <Header for 'Event timing codes', ID: 'ETCO'>
         // Time stamp format    $xx
         //   Where time stamp format is:
         // $01  (32-bit value) MPEG frames from beginning of file
         // $02  (32-bit value) milliseconds from beginning of file
         //   Followed by a list of key events in the following format:
         // Type of event   $xx
         // Time stamp      $xx (xx ...)
         //   The 'Time stamp' is set to zero if directly at the beginning of the sound
         //   or after the previous event. All events MUST be sorted in chronological order.
         $frame_offset = 0;
         $parsed_frame['timestampformat'] = ord($parsed_frame['data'][$frame_offset++]);
         while ($frame_offset < strlen($parsed_frame['data'])) {
             $parsed_frame['typeid'] = $parsed_frame['data'][$frame_offset++];
             $parsed_frame['type'] = getid3_id3v2::ETCOEventLookup($parsed_frame['typeid']);
             $parsed_frame['timestamp'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, 4));
             $frame_offset += 4;
         }
         unset($parsed_frame['data']);
         return true;
     }
     if ($id3v2_major_version >= 3 && $parsed_frame['frame_name'] == 'MLLT' || $id3v2_major_version == 2 && $parsed_frame['frame_name'] == 'MLL') {
         // 4.7   MLL MPEG location lookup table
         //   There may only be one 'MLLT' frame in each tag
         // <Header for 'Location lookup table', ID: 'MLLT'>
         // MPEG frames between reference  $xx xx
         // Bytes between reference        $xx xx xx
         // Milliseconds between reference $xx xx xx
         // Bits for bytes deviation       $xx
         // Bits for milliseconds dev.     $xx
         //   Then for every reference the following data is included;
         // Deviation in bytes         %xxx....
         // Deviation in milliseconds  %xxx....
         $frame_offset = 0;
         $parsed_frame['framesbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], 0, 2));
         $parsed_frame['bytesbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], 2, 3));
         $parsed_frame['msbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], 5, 3));
         $parsed_frame['bitsforbytesdeviation'] = getid3_lib::BigEndian2Int($parsed_frame['data'][8]);
         $parsed_frame['bitsformsdeviation'] = getid3_lib::BigEndian2Int($parsed_frame['data'][9]);
         $parsed_frame['data'] = substr($parsed_frame['data'], 10);
         while ($frame_offset < strlen($parsed_frame['data'])) {
             $deviation_bitstream .= getid3_lib::BigEndian2Bin($parsed_frame['data'][$frame_offset++]);
         }
         $reference_counter = 0;
         while (strlen($deviation_bitstream) > 0) {
             $parsed_frame[$reference_counter]['bytedeviation'] = bindec(substr($deviation_bitstream, 0, $parsed_frame['bitsforbytesdeviation']));
             $parsed_frame[$reference_counter]['msdeviation'] = bindec(substr($deviation_bitstream, $parsed_frame['bitsforbytesdeviation'], $parsed_frame['bitsformsdeviation']));
             $deviation_bitstream = substr($deviation_bitstream, $parsed_frame['bitsforbytesdeviation'] + $parsed_frame['bitsformsdeviation']);
             $reference_counter++;
         }
         unset($parsed_frame['data']);
         return true;
     }
     if ($id3v2_major_version >= 3 && $parsed_frame['frame_name'] == 'SYTC' || $id3v2_major_version == 2 && $parsed_frame['frame_name'] == 'STC') {
         // 4.8   STC  Synchronised tempo codes
         //   There may only be one 'SYTC' frame in each tag
         // <Header for 'Synchronised tempo codes', ID: 'SYTC'>
         // Time stamp format   $xx
         // Tempo data          <binary data>
         //   Where time stamp format is:
         // $01  (32-bit value) MPEG frames from beginning of file
         // $02  (32-bit value) milliseconds from beginning of file
         $frame_offset = 0;
         $parsed_frame['timestampformat'] = ord($parsed_frame['data'][$frame_offset++]);
         $timestamp_counter = 0;
         while ($frame_offset < strlen($parsed_frame['data'])) {
             $parsed_frame[$timestamp_counter]['tempo'] = ord($parsed_frame['data'][$frame_offset++]);
             if ($parsed_frame[$timestamp_counter]['tempo'] == 255) {
                 $parsed_frame[$timestamp_counter]['tempo'] += ord($parsed_frame['data'][$frame_offset++]);
             }
             $parsed_frame[$timestamp_counter]['timestamp'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, 4));
             $frame_offset += 4;
             $timestamp_counter++;
         }
         unset($parsed_frame['data']);
         return true;
     }
     if ($id3v2_major_version >= 3 && $parsed_frame['frame_name'] == 'USLT' || $id3v2_major_version == 2 && $parsed_frame['frame_name'] == 'ULT') {
         // 4.9   ULT  Unsynchronised lyric/text transcription
         //   There may be more than one 'Unsynchronised lyrics/text transcription' frame
         //   in each tag, but only one with the same language and content descriptor.
         // <Header for 'Unsynchronised lyrics/text transcription', ID: 'USLT'>
         // Text encoding        $xx
         // Language             $xx xx xx
         // Content descriptor   <text string according to encoding> $00 (00)
         // Lyrics/text          <full text string according to encoding>
         $frame_offset = 0;
         $frame_text_encoding = ord($parsed_frame['data'][$frame_offset++]);
         if ($id3v2_major_version <= 3 && $frame_text_encoding > 1 || $id3v2_major_version == 4 && $frame_text_encoding > 3) {
             $getid3->warning('Invalid text encoding byte (' . $frame_text_encoding . ') in frame "' . $parsed_frame['frame_name'] . '" - defaulting to ISO-8859-1 encoding');
         }
         $frame_language = substr($parsed_frame['data'], $frame_offset, 3);
         $frame_offset += 3;
         if ($frame_offset > strlen($parsed_frame['data'])) {
             $frame_offset = strlen($parsed_frame['data']) - 1;
         }
         $frame_terminator_pos = @strpos($parsed_frame['data'], getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding), $frame_offset);
         if (ord(substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)), 1)) === 0) {
             $frame_terminator_pos++;
             // @strpos() fooled because 2nd byte of Unicode chars are often 0x00
         }
         $frame_description = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset);
         if (ord($frame_description) === 0) {
             $frame_description = '';
         }
         $parsed_frame['data'] = substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)));
         $parsed_frame['encodingid'] = $frame_text_encoding;
         $parsed_frame['encoding'] = $this->TextEncodingNameLookup($frame_text_encoding);
         $parsed_frame['data'] = $parsed_frame['data'];
         $parsed_frame['language'] = $frame_language;
         $parsed_frame['languagename'] = getid3_id3v2::LanguageLookup($frame_language, false);
         $parsed_frame['description'] = $frame_description;
         if (!empty($parsed_frame['framenameshort']) && !empty($parsed_frame['data'])) {
             $getid3->info['id3v2']['comments'][$parsed_frame['framenameshort']][] = $getid3->iconv($parsed_frame['encoding'], 'UTF-8', $parsed_frame['data']);
         }
         unset($parsed_frame['data']);
         return true;
     }
     if ($id3v2_major_version >= 3 && $parsed_frame['frame_name'] == 'SYLT' || $id3v2_major_version == 2 && $parsed_frame['frame_name'] == 'SLT') {
         // 4.10  SLT  Synchronised lyric/text
         //   There may be more than one 'SYLT' frame in each tag,
         //   but only one with the same language and content descriptor.
         // <Header for 'Synchronised lyrics/text', ID: 'SYLT'>
         // Text encoding        $xx
         // Language             $xx xx xx
         // Time stamp format    $xx
         //   $01  (32-bit value) MPEG frames from beginning of file
         //   $02  (32-bit value) milliseconds from beginning of file
         // Content type         $xx
         // Content descriptor   <text string according to encoding> $00 (00)
         //   Terminated text to be synced (typically a syllable)
         //   Sync identifier (terminator to above string)   $00 (00)
         //   Time stamp                                     $xx (xx ...)
         $frame_offset = 0;
         $frame_text_encoding = ord($parsed_frame['data'][$frame_offset++]);
         if ($id3v2_major_version <= 3 && $frame_text_encoding > 1 || $id3v2_major_version == 4 && $frame_text_encoding > 3) {
             $getid3->warning('Invalid text encoding byte (' . $frame_text_encoding . ') in frame "' . $parsed_frame['frame_name'] . '" - defaulting to ISO-8859-1 encoding');
         }
         $frame_language = substr($parsed_frame['data'], $frame_offset, 3);
         $frame_offset += 3;
         $parsed_frame['timestampformat'] = ord($parsed_frame['data'][$frame_offset++]);
         $parsed_frame['contenttypeid'] = ord($parsed_frame['data'][$frame_offset++]);
         $parsed_frame['contenttype'] = getid3_id3v2::SYTLContentTypeLookup($parsed_frame['contenttypeid']);
         $parsed_frame['encodingid'] = $frame_text_encoding;
         $parsed_frame['encoding'] = $this->TextEncodingNameLookup($frame_text_encoding);
         $parsed_frame['language'] = $frame_language;
         $parsed_frame['languagename'] = getid3_id3v2::LanguageLookup($frame_language, false);
         $timestamp_index = 0;
         $frame_remaining_data = substr($parsed_frame['data'], $frame_offset);
         while (strlen($frame_remaining_data)) {
             $frame_offset = 0;
             $frame_terminator_pos = strpos($frame_remaining_data, getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding));
             if ($frame_terminator_pos === false) {
                 $frame_remaining_data = '';
             } else {
                 if (ord(substr($frame_remaining_data, $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)), 1)) === 0) {
                     $frame_terminator_pos++;
                     // strpos() fooled because 2nd byte of Unicode chars are often 0x00
                 }
                 $parsed_frame['lyrics'][$timestamp_index]['data'] = substr($frame_remaining_data, $frame_offset, $frame_terminator_pos - $frame_offset);
                 $frame_remaining_data = substr($frame_remaining_data, $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)));
                 if ($timestamp_index == 0 && ord($frame_remaining_data[0]) != 0) {
                     // timestamp probably omitted for first data item
                 } else {
                     $parsed_frame['lyrics'][$timestamp_index]['timestamp'] = getid3_lib::BigEndian2Int(substr($frame_remaining_data, 0, 4));
                     $frame_remaining_data = substr($frame_remaining_data, 4);
                 }
                 $timestamp_index++;
             }
         }
         unset($parsed_frame['data']);
         return true;
     }
     if ($id3v2_major_version >= 3 && $parsed_frame['frame_name'] == 'COMM' || $id3v2_major_version == 2 && $parsed_frame['frame_name'] == 'COM') {
         // 4.11  COM  Comments
         //   There may be more than one comment frame in each tag,
         //   but only one with the same language and content descriptor.
         // <Header for 'Comment', ID: 'COMM'>
         // Text encoding          $xx
         // Language               $xx xx xx
         // Short content descrip. <text string according to encoding> $00 (00)
         // The actual text        <full text string according to encoding>
         if (strlen($parsed_frame['data']) < 5) {
             $getid3->warning('Invalid data (too short) for "' . $parsed_frame['frame_name'] . '" frame at offset ' . $parsed_frame['dataoffset']);
             return true;
         }
         $frame_offset = 0;
         $frame_text_encoding = ord($parsed_frame['data'][$frame_offset++]);
         if ($id3v2_major_version <= 3 && $frame_text_encoding > 1 || $id3v2_major_version == 4 && $frame_text_encoding > 3) {
             $getid3->warning('Invalid text encoding byte (' . $frame_text_encoding . ') in frame "' . $parsed_frame['frame_name'] . '" - defaulting to ISO-8859-1 encoding');
         }
         $frame_language = substr($parsed_frame['data'], $frame_offset, 3);
         $frame_offset += 3;
         $frame_terminator_pos = @strpos($parsed_frame['data'], getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding), $frame_offset);
         if (ord(substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)), 1)) === 0) {
             $frame_terminator_pos++;
             // @strpos() fooled because 2nd byte of Unicode chars are often 0x00
         }
         $frame_description = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset);
         if (ord($frame_description) === 0) {
             $frame_description = '';
         }
         $frame_text = (string) substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)));
         $parsed_frame['encodingid'] = $frame_text_encoding;
         $parsed_frame['encoding'] = $this->TextEncodingNameLookup($frame_text_encoding);
         $parsed_frame['language'] = $frame_language;
         $parsed_frame['languagename'] = getid3_id3v2::LanguageLookup($frame_language, false);
         $parsed_frame['description'] = $frame_description;
         $parsed_frame['data'] = $frame_text;
         if (!empty($parsed_frame['framenameshort']) && !empty($parsed_frame['data'])) {
             $getid3->info['id3v2']['comments'][$parsed_frame['framenameshort']][] = $getid3->iconv($parsed_frame['encoding'], 'UTF-8', $parsed_frame['data']);
         }
         return true;
     }
     if ($id3v2_major_version >= 4 && $parsed_frame['frame_name'] == 'RVA2') {
         // 4.11  RVA2 Relative volume adjustment (2) (ID3v2.4+ only)
         //   There may be more than one 'RVA2' frame in each tag,
         //   but only one with the same identification string
         // <Header for 'Relative volume adjustment (2)', ID: 'RVA2'>
         // Identification          <text string> $00
         //   The 'identification' string is used to identify the situation and/or
         //   device where this adjustment should apply. The following is then
         //   repeated for every channel:
         // Type of channel         $xx
         // Volume adjustment       $xx xx
         // Bits representing peak  $xx
         // Peak volume             $xx (xx ...)
         $frame_terminator_pos = strpos($parsed_frame['data'], "");
         $frame_id_string = substr($parsed_frame['data'], 0, $frame_terminator_pos);
         if (ord($frame_id_string) === 0) {
             $frame_id_string = '';
         }
         $frame_remaining_data = substr($parsed_frame['data'], $frame_terminator_pos + strlen(""));
         $parsed_frame['description'] = $frame_id_string;
         while (strlen($frame_remaining_data)) {
             $frame_offset = 0;
             $frame_channeltypeid = ord(substr($frame_remaining_data, $frame_offset++, 1));
             $parsed_frame[$frame_channeltypeid]['channeltypeid'] = $frame_channeltypeid;
             $parsed_frame[$frame_channeltypeid]['channeltype'] = getid3_id3v2::RVA2ChannelTypeLookup($frame_channeltypeid);
             $parsed_frame[$frame_channeltypeid]['volumeadjust'] = getid3_lib::BigEndian2Int(substr($frame_remaining_data, $frame_offset, 2), true);
             // 16-bit signed
             $frame_offset += 2;
             $parsed_frame[$frame_channeltypeid]['bitspeakvolume'] = ord(substr($frame_remaining_data, $frame_offset++, 1));
             $frame_bytespeakvolume = ceil($parsed_frame[$frame_channeltypeid]['bitspeakvolume'] / 8);
             $parsed_frame[$frame_channeltypeid]['peakvolume'] = getid3_lib::BigEndian2Int(substr($frame_remaining_data, $frame_offset, $frame_bytespeakvolume));
             $frame_remaining_data = substr($frame_remaining_data, $frame_offset + $frame_bytespeakvolume);
         }
         unset($parsed_frame['data']);
         return true;
     }
     if ($id3v2_major_version == 3 && $parsed_frame['frame_name'] == 'RVAD' || $id3v2_major_version == 2 && $parsed_frame['frame_name'] == 'RVA') {
         // 4.12  RVA  Relative volume adjustment (ID3v2.2 only)
         //   There may only be one 'RVA' frame in each tag
         // <Header for 'Relative volume adjustment', ID: 'RVA'>
         // ID3v2.2 => Increment/decrement     %000000ba
         // ID3v2.3 => Increment/decrement     %00fedcba
         // Bits used for volume descr.        $xx
         // Relative volume change, right      $xx xx (xx ...) // a
         // Relative volume change, left       $xx xx (xx ...) // b
         // Peak volume right                  $xx xx (xx ...)
         // Peak volume left                   $xx xx (xx ...)
         //   ID3v2.3 only, optional (not present in ID3v2.2):
         // Relative volume change, right back $xx xx (xx ...) // c
         // Relative volume change, left back  $xx xx (xx ...) // d
         // Peak volume right back             $xx xx (xx ...)
         // Peak volume left back              $xx xx (xx ...)
         //   ID3v2.3 only, optional (not present in ID3v2.2):
         // Relative volume change, center     $xx xx (xx ...) // e
         // Peak volume center                 $xx xx (xx ...)
         //   ID3v2.3 only, optional (not present in ID3v2.2):
         // Relative volume change, bass       $xx xx (xx ...) // f
         // Peak volume bass                   $xx xx (xx ...)
         $frame_offset = 0;
         $frame_incrdecrflags = getid3_lib::BigEndian2Bin($parsed_frame['data'][$frame_offset++]);
         $parsed_frame['incdec']['right'] = (bool) substr($frame_incrdecrflags, 6, 1);
         $parsed_frame['incdec']['left'] = (bool) substr($frame_incrdecrflags, 7, 1);
         $parsed_frame['bitsvolume'] = ord($parsed_frame['data'][$frame_offset++]);
         $frame_bytesvolume = ceil($parsed_frame['bitsvolume'] / 8);
         $parsed_frame['volumechange']['right'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, $frame_bytesvolume));
         if ($parsed_frame['incdec']['right'] === false) {
             $parsed_frame['volumechange']['right'] *= -1;
         }
         $frame_offset += $frame_bytesvolume;
         $parsed_frame['volumechange']['left'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, $frame_bytesvolume));
         if ($parsed_frame['incdec']['left'] === false) {
             $parsed_frame['volumechange']['left'] *= -1;
         }
         $frame_offset += $frame_bytesvolume;
         $parsed_frame['peakvolume']['right'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, $frame_bytesvolume));
         $frame_offset += $frame_bytesvolume;
         $parsed_frame['peakvolume']['left'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, $frame_bytesvolume));
         $frame_offset += $frame_bytesvolume;
         if ($id3v2_major_version == 3) {
             $parsed_frame['data'] = substr($parsed_frame['data'], $frame_offset);
             if (strlen($parsed_frame['data']) > 0) {
                 $parsed_frame['incdec']['rightrear'] = (bool) substr($frame_incrdecrflags, 4, 1);
                 $parsed_frame['incdec']['leftrear'] = (bool) substr($frame_incrdecrflags, 5, 1);
                 $parsed_frame['volumechange']['rightrear'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, $frame_bytesvolume));
                 if ($parsed_frame['incdec']['rightrear'] === false) {
                     $parsed_frame['volumechange']['rightrear'] *= -1;
                 }
                 $frame_offset += $frame_bytesvolume;
                 $parsed_frame['volumechange']['leftrear'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, $frame_bytesvolume));
                 if ($parsed_frame['incdec']['leftrear'] === false) {
                     $parsed_frame['volumechange']['leftrear'] *= -1;
                 }
                 $frame_offset += $frame_bytesvolume;
                 $parsed_frame['peakvolume']['rightrear'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, $frame_bytesvolume));
                 $frame_offset += $frame_bytesvolume;
                 $parsed_frame['peakvolume']['leftrear'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, $frame_bytesvolume));
                 $frame_offset += $frame_bytesvolume;
             }
             $parsed_frame['data'] = substr($parsed_frame['data'], $frame_offset);
             if (strlen($parsed_frame['data']) > 0) {
                 $parsed_frame['incdec']['center'] = (bool) substr($frame_incrdecrflags, 3, 1);
                 $parsed_frame['volumechange']['center'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, $frame_bytesvolume));
                 if ($parsed_frame['incdec']['center'] === false) {
                     $parsed_frame['volumechange']['center'] *= -1;
                 }
                 $frame_offset += $frame_bytesvolume;
                 $parsed_frame['peakvolume']['center'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, $frame_bytesvolume));
                 $frame_offset += $frame_bytesvolume;
             }
             $parsed_frame['data'] = substr($parsed_frame['data'], $frame_offset);
             if (strlen($parsed_frame['data']) > 0) {
                 $parsed_frame['incdec']['bass'] = (bool) substr($frame_incrdecrflags, 2, 1);
                 $parsed_frame['volumechange']['bass'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, $frame_bytesvolume));
                 if ($parsed_frame['incdec']['bass'] === false) {
                     $parsed_frame['volumechange']['bass'] *= -1;
                 }
                 $frame_offset += $frame_bytesvolume;
                 $parsed_frame['peakvolume']['bass'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, $frame_bytesvolume));
                 $frame_offset += $frame_bytesvolume;
             }
         }
         unset($parsed_frame['data']);
         return true;
     }
     if ($id3v2_major_version >= 4 && $parsed_frame['frame_name'] == 'EQU2') {
         // 4.12  EQU2 Equalisation (2) (ID3v2.4+ only)
         //   There may be more than one 'EQU2' frame in each tag,
         //   but only one with the same identification string
         // <Header of 'Equalisation (2)', ID: 'EQU2'>
         // Interpolation method  $xx
         //   $00  Band
         //   $01  Linear
         // Identification        <text string> $00
         //   The following is then repeated for every adjustment point
         // Frequency          $xx xx
         // Volume adjustment  $xx xx
         $frame_offset = 0;
         $frame_interpolationmethod = ord($parsed_frame['data'][$frame_offset++]);
         $frame_terminator_pos = @strpos($parsed_frame['data'], "", $frame_offset);
         $frame_id_string = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset);
         if (ord($frame_id_string) === 0) {
             $frame_id_string = '';
         }
         $parsed_frame['description'] = $frame_id_string;
         $frame_remaining_data = substr($parsed_frame['data'], $frame_terminator_pos + strlen(""));
         while (strlen($frame_remaining_data)) {
             $frame_frequency = getid3_lib::BigEndian2Int(substr($frame_remaining_data, 0, 2)) / 2;
             $parsed_frame['data'][$frame_frequency] = getid3_lib::BigEndian2Int(substr($frame_remaining_data, 2, 2), true);
             $frame_remaining_data = substr($frame_remaining_data, 4);
         }
         $parsed_frame['interpolationmethod'] = $frame_interpolationmethod;
         unset($parsed_frame['data']);
         return true;
     }
     if ($id3v2_major_version == 3 && $parsed_frame['frame_name'] == 'EQUA' || $id3v2_major_version == 2 && $parsed_frame['frame_name'] == 'EQU') {
         // 4.13  EQU  Equalisation (ID3v2.2 only)
         //   There may only be one 'EQUA' frame in each tag
         // <Header for 'Relative volume adjustment', ID: 'EQU'>
         // Adjustment bits    $xx
         //   This is followed by 2 bytes + ('adjustment bits' rounded up to the
         //   nearest byte) for every equalisation band in the following format,
         //   giving a frequency range of 0 - 32767Hz:
         // Increment/decrement   %x (MSB of the Frequency)
         // Frequency             (lower 15 bits)
         // Adjustment            $xx (xx ...)
         $frame_offset = 0;
         $parsed_frame['adjustmentbits'] = $parsed_frame['data'][$frame_offset++];
         $frame_adjustment_bytes = ceil($parsed_frame['adjustmentbits'] / 8);
         $frame_remaining_data = (string) substr($parsed_frame['data'], $frame_offset);
         while (strlen($frame_remaining_data) > 0) {
             $frame_frequencystr = getid3_lib::BigEndian2Bin(substr($frame_remaining_data, 0, 2));
             $frame_incdec = (bool) substr($frame_frequencystr, 0, 1);
             $frame_frequency = bindec(substr($frame_frequencystr, 1, 15));
             $parsed_frame[$frame_frequency]['incdec'] = $frame_incdec;
             $parsed_frame[$frame_frequency]['adjustment'] = getid3_lib::BigEndian2Int(substr($frame_remaining_data, 2, $frame_adjustment_bytes));
             if ($parsed_frame[$frame_frequency]['incdec'] === false) {
                 $parsed_frame[$frame_frequency]['adjustment'] *= -1;
             }
             $frame_remaining_data = substr($frame_remaining_data, 2 + $frame_adjustment_bytes);
         }
         unset($parsed_frame['data']);
         return true;
     }
     if ($id3v2_major_version >= 3 && $parsed_frame['frame_name'] == 'RVRB' || $id3v2_major_version == 2 && $parsed_frame['frame_name'] == 'REV') {
         // 4.14  REV  Reverb
         //   There may only be one 'RVRB' frame in each tag.
         // <Header for 'Reverb', ID: 'RVRB'>
         // Reverb left (ms)                 $xx xx
         // Reverb right (ms)                $xx xx
         // Reverb bounces, left             $xx
         // Reverb bounces, right            $xx
         // Reverb feedback, left to left    $xx
         // Reverb feedback, left to right   $xx
         // Reverb feedback, right to right  $xx
         // Reverb feedback, right to left   $xx
         // Premix left to right             $xx
         // Premix right to left             $xx
         $frame_offset = 0;
         $parsed_frame['left'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, 2));
         $frame_offset += 2;
         $parsed_frame['right'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, 2));
         $frame_offset += 2;
         $parsed_frame['bouncesL'] = ord($parsed_frame['data'][$frame_offset++]);
         $parsed_frame['bouncesR'] = ord($parsed_frame['data'][$frame_offset++]);
         $parsed_frame['feedbackLL'] = ord($parsed_frame['data'][$frame_offset++]);
         $parsed_frame['feedbackLR'] = ord($parsed_frame['data'][$frame_offset++]);
         $parsed_frame['feedbackRR'] = ord($parsed_frame['data'][$frame_offset++]);
         $parsed_frame['feedbackRL'] = ord($parsed_frame['data'][$frame_offset++]);
         $parsed_frame['premixLR'] = ord($parsed_frame['data'][$frame_offset++]);
         $parsed_frame['premixRL'] = ord($parsed_frame['data'][$frame_offset++]);
         unset($parsed_frame['data']);
         return true;
     }
     if ($id3v2_major_version >= 3 && $parsed_frame['frame_name'] == 'APIC' || $id3v2_major_version == 2 && $parsed_frame['frame_name'] == 'PIC') {
         // 4.15  PIC  Attached picture
         //   There may be several pictures attached to one file,
         //   each in their individual 'APIC' frame, but only one
         //   with the same content descriptor
         // <Header for 'Attached picture', ID: 'APIC'>
         // Text encoding      $xx
         // ID3v2.3+ => MIME type          <text string> $00
         // ID3v2.2  => Image format       $xx xx xx
         // Picture type       $xx
         // Description        <text string according to encoding> $00 (00)
         // Picture data       <binary data>
         $frame_offset = 0;
         $frame_text_encoding = ord($parsed_frame['data'][$frame_offset++]);
         if ($id3v2_major_version <= 3 && $frame_text_encoding > 1 || $id3v2_major_version == 4 && $frame_text_encoding > 3) {
             $getid3->warning('Invalid text encoding byte (' . $frame_text_encoding . ') in frame "' . $parsed_frame['frame_name'] . '" - defaulting to ISO-8859-1 encoding');
         }
         if ($id3v2_major_version == 2 && strlen($parsed_frame['data']) > $frame_offset) {
             $frame_imagetype = substr($parsed_frame['data'], $frame_offset, 3);
             if (strtolower($frame_imagetype) == 'ima') {
                 // complete hack for mp3Rage (www.chaoticsoftware.com) that puts ID3v2.3-formatted
                 // MIME type instead of 3-char ID3v2.2-format image type  (thanks xbhoffØpacbell*net)
                 $frame_terminator_pos = @strpos($parsed_frame['data'], "", $frame_offset);
                 $frame_mimetype = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset);
                 if (ord($frame_mimetype) === 0) {
                     $frame_mimetype = '';
                 }
                 $frame_imagetype = strtoupper(str_replace('image/', '', strtolower($frame_mimetype)));
                 if ($frame_imagetype == 'JPEG') {
                     $frame_imagetype = 'JPG';
                 }
                 $frame_offset = $frame_terminator_pos + strlen("");
             } else {
                 $frame_offset += 3;
             }
         }
         if ($id3v2_major_version > 2 && strlen($parsed_frame['data']) > $frame_offset) {
             $frame_terminator_pos = @strpos($parsed_frame['data'], "", $frame_offset);
             $frame_mimetype = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset);
             if (ord($frame_mimetype) === 0) {
                 $frame_mimetype = '';
             }
             $frame_offset = $frame_terminator_pos + strlen("");
         }
         $frame_picturetype = ord($parsed_frame['data'][$frame_offset++]);
         $frame_terminator_pos = @strpos($parsed_frame['data'], getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding), $frame_offset);
         if (ord(substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)), 1)) === 0) {
             $frame_terminator_pos++;
             // @strpos() fooled because 2nd byte of Unicode chars are often 0x00
         }
         $frame_description = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset);
         if (ord($frame_description) === 0) {
             $frame_description = '';
         }
         $parsed_frame['encodingid'] = $frame_text_encoding;
         $parsed_frame['encoding'] = $this->TextEncodingNameLookup($frame_text_encoding);
         if ($id3v2_major_version == 2) {
             $parsed_frame['imagetype'] = $frame_imagetype;
         } else {
             $parsed_frame['mime'] = $frame_mimetype;
         }
         $parsed_frame['picturetypeid'] = $frame_picturetype;
         $parsed_frame['picturetype'] = getid3_id3v2::APICPictureTypeLookup($frame_picturetype);
         $parsed_frame['description'] = $frame_description;
         $parsed_frame['data'] = substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)));
         if ($getid3->option_tags_images) {
             $image_chunk_check = getid3_lib_image_size::get($parsed_frame['data']);
             if ($image_chunk_check[2] >= 1 && $image_chunk_check[2] <= 3) {
                 $parsed_frame['image_mime'] = image_type_to_mime_type($image_chunk_check[2]);
                 if ($image_chunk_check[0]) {
                     $parsed_frame['image_width'] = $image_chunk_check[0];
                 }
                 if ($image_chunk_check[1]) {
                     $parsed_frame['image_height'] = $image_chunk_check[1];
                 }
                 $parsed_frame['image_bytes'] = strlen($parsed_frame['data']);
             }
         }
         return true;
     }
     if ($id3v2_major_version >= 3 && $parsed_frame['frame_name'] == 'GEOB' || $id3v2_major_version == 2 && $parsed_frame['frame_name'] == 'GEO') {
         // 4.16  GEO  General encapsulated object
         //   There may be more than one 'GEOB' frame in each tag,
         //   but only one with the same content descriptor
         // <Header for 'General encapsulated object', ID: 'GEOB'>
         // Text encoding          $xx
         // MIME type              <text string> $00
         // Filename               <text string according to encoding> $00 (00)
         // Content description    <text string according to encoding> $00 (00)
         // Encapsulated object    <binary data>
         $frame_offset = 0;
         $frame_text_encoding = ord($parsed_frame['data'][$frame_offset++]);
         if ($id3v2_major_version <= 3 && $frame_text_encoding > 1 || $id3v2_major_version == 4 && $frame_text_encoding > 3) {
             $getid3->warning('Invalid text encoding byte (' . $frame_text_encoding . ') in frame "' . $parsed_frame['frame_name'] . '" - defaulting to ISO-8859-1 encoding');
         }
         $frame_terminator_pos = @strpos($parsed_frame['data'], "", $frame_offset);
         $frame_mimetype = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset);
         if (ord($frame_mimetype) === 0) {
             $frame_mimetype = '';
         }
         $frame_offset = $frame_terminator_pos + strlen("");
         $frame_terminator_pos = @strpos($parsed_frame['data'], getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding), $frame_offset);
         if (ord(substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)), 1)) === 0) {
             $frame_terminator_pos++;
             // @strpos() fooled because 2nd byte of Unicode chars are often 0x00
         }
         $frame_filename = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset);
         if (ord($frame_filename) === 0) {
             $frame_filename = '';
         }
         $frame_offset = $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding));
         $frame_terminator_pos = @strpos($parsed_frame['data'], getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding), $frame_offset);
         if (ord(substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)), 1)) === 0) {
             $frame_terminator_pos++;
             // @strpos() fooled because 2nd byte of Unicode chars are often 0x00
         }
         $frame_description = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset);
         if (ord($frame_description) === 0) {
             $frame_description = '';
         }
         $frame_offset = $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding));
         $parsed_frame['objectdata'] = (string) substr($parsed_frame['data'], $frame_offset);
         $parsed_frame['encodingid'] = $frame_text_encoding;
         $parsed_frame['encoding'] = $this->TextEncodingNameLookup($frame_text_encoding);
         $parsed_frame['mime'] = $frame_mimetype;
         $parsed_frame['filename'] = $frame_filename;
         $parsed_frame['description'] = $frame_description;
         unset($parsed_frame['data']);
         return true;
     }
     if ($id3v2_major_version >= 3 && $parsed_frame['frame_name'] == 'PCNT' || $id3v2_major_version == 2 && $parsed_frame['frame_name'] == 'CNT') {
         // 4.17  CNT  Play counter
         //   There may only be one 'PCNT' frame in each tag.
         //   When the counter reaches all one's, one byte is inserted in
         //   front of the counter thus making the counter eight bits bigger
         // <Header for 'Play counter', ID: 'PCNT'>
         // Counter        $xx xx xx xx (xx ...)
         $parsed_frame['data'] = getid3_lib::BigEndian2Int($parsed_frame['data']);
         return true;
     }
     if ($id3v2_major_version >= 3 && $parsed_frame['frame_name'] == 'POPM' || $id3v2_major_version == 2 && $parsed_frame['frame_name'] == 'POP') {
         // 4.18  POP  Popularimeter
         //   There may be more than one 'POPM' frame in each tag,
         //   but only one with the same email address
         // <Header for 'Popularimeter', ID: 'POPM'>
         // Email to user   <text string> $00
         // Rating          $xx
         // Counter         $xx xx xx xx (xx ...)
         $frame_offset = 0;
         $frame_terminator_pos = @strpos($parsed_frame['data'], "", $frame_offset);
         $frame_email_address = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset);
         if (ord($frame_email_address) === 0) {
             $frame_email_address = '';
         }
         $frame_offset = $frame_terminator_pos + strlen("");
         $frame_rating = ord($parsed_frame['data'][$frame_offset++]);
         $parsed_frame['data'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset));
         $parsed_frame['email'] = $frame_email_address;
         $parsed_frame['rating'] = $frame_rating;
         unset($parsed_frame['data']);
         return true;
     }
     if ($id3v2_major_version >= 3 && $parsed_frame['frame_name'] == 'RBUF' || $id3v2_major_version == 2 && $parsed_frame['frame_name'] == 'BUF') {
         // 4.19  BUF  Recommended buffer size
         //   There may only be one 'RBUF' frame in each tag
         // <Header for 'Recommended buffer size', ID: 'RBUF'>
         // Buffer size               $xx xx xx
         // Embedded info flag        %0000000x
         // Offset to next tag        $xx xx xx xx
         $frame_offset = 0;
         $parsed_frame['buffersize'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, 3));
         $frame_offset += 3;
         $frame_embeddedinfoflags = getid3_lib::BigEndian2Bin($parsed_frame['data'][$frame_offset++]);
         $parsed_frame['flags']['embededinfo'] = (bool) substr($frame_embeddedinfoflags, 7, 1);
         $parsed_frame['nexttagoffset'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, 4));
         unset($parsed_frame['data']);
         return true;
     }
     if ($id3v2_major_version == 2 && $parsed_frame['frame_name'] == 'CRM') {
         // 4.20  Encrypted meta frame (ID3v2.2 only)
         //   There may be more than one 'CRM' frame in a tag,
         //   but only one with the same 'owner identifier'
         // <Header for 'Encrypted meta frame', ID: 'CRM'>
         // Owner identifier      <textstring> $00 (00)
         // Content/explanation   <textstring> $00 (00)
         // Encrypted datablock   <binary data>
         $frame_offset = 0;
         $frame_terminator_pos = @strpos($parsed_frame['data'], "", $frame_offset);
         $frame_owner_id = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset);
         $frame_offset = $frame_terminator_pos + strlen("");
         $frame_terminator_pos = @strpos($parsed_frame['data'], "", $frame_offset);
         $frame_description = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset);
         if (ord($frame_description) === 0) {
             $frame_description = '';
         }
         $frame_offset = $frame_terminator_pos + strlen("");
         $parsed_frame['ownerid'] = $frame_owner_id;
         $parsed_frame['data'] = (string) substr($parsed_frame['data'], $frame_offset);
         $parsed_frame['description'] = $frame_description;
         unset($parsed_frame['data']);
         return true;
     }
     if ($id3v2_major_version >= 3 && $parsed_frame['frame_name'] == 'AENC' || $id3v2_major_version == 2 && $parsed_frame['frame_name'] == 'CRA') {
         // 4.21  CRA  Audio encryption
         //   There may be more than one 'AENC' frames in a tag,
         //   but only one with the same 'Owner identifier'
         // <Header for 'Audio encryption', ID: 'AENC'>
         // Owner identifier   <text string> $00
         // Preview start      $xx xx
         // Preview length     $xx xx
         // Encryption info    <binary data>
         $frame_offset = 0;
         $frame_terminator_pos = @strpos($parsed_frame['data'], "", $frame_offset);
         $frame_owner_id = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset);
         if (ord($frame_owner_id) === 0) {
             $frame_owner_id == '';
         }
         $frame_offset = $frame_terminator_pos + strlen("");
         $parsed_frame['ownerid'] = $frame_owner_id;
         $parsed_frame['previewstart'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, 2));
         $frame_offset += 2;
         $parsed_frame['previewlength'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, 2));
         $frame_offset += 2;
         $parsed_frame['encryptioninfo'] = (string) substr($parsed_frame['data'], $frame_offset);
         unset($parsed_frame['data']);
         return true;
     }
     if ($id3v2_major_version >= 3 && $parsed_frame['frame_name'] == 'LINK' || $id3v2_major_version == 2 && $parsed_frame['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'>
         // ID3v2.3+ => Frame identifier   $xx xx xx xx
         // ID3v2.2  => Frame identifier   $xx xx xx
         // URL                            <text string> $00
         // ID and additional data         <text string(s)>
         $frame_offset = 0;
         if ($id3v2_major_version == 2) {
             $parsed_frame['frameid'] = substr($parsed_frame['data'], $frame_offset, 3);
             $frame_offset += 3;
         } else {
             $parsed_frame['frameid'] = substr($parsed_frame['data'], $frame_offset, 4);
             $frame_offset += 4;
         }
         $frame_terminator_pos = @strpos($parsed_frame['data'], "", $frame_offset);
         $frame_url = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset);
         if (ord($frame_url) === 0) {
             $frame_url = '';
         }
         $frame_offset = $frame_terminator_pos + strlen("");
         $parsed_frame['url'] = $frame_url;
         $parsed_frame['additionaldata'] = (string) substr($parsed_frame['data'], $frame_offset);
         if (!empty($parsed_frame['framenameshort']) && $parsed_frame['url']) {
             $getid3->info['id3v2']['comments'][$parsed_frame['framenameshort']][] = utf8_encode($parsed_frame['url']);
         }
         unset($parsed_frame['data']);
         return true;
     }
     if ($id3v2_major_version >= 3 && $parsed_frame['frame_name'] == 'POSS') {
         // 4.21  POSS Position synchronisation frame (ID3v2.3+ only)
         //   There may only be one 'POSS' frame in each tag
         // <Head for 'Position synchronisation', ID: 'POSS'>
         // Time stamp format         $xx
         // Position                  $xx (xx ...)
         $frame_offset = 0;
         $parsed_frame['timestampformat'] = ord($parsed_frame['data'][$frame_offset++]);
         $parsed_frame['position'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset));
         unset($parsed_frame['data']);
         return true;
     }
     if ($id3v2_major_version >= 3 && $parsed_frame['frame_name'] == 'USER') {
         // 4.22  USER Terms of use (ID3v2.3+ only)
         //   There may be more than one 'Terms of use' frame in a tag,
         //   but only one with the same 'Language'
         // <Header for 'Terms of use frame', ID: 'USER'>
         // Text encoding        $xx
         // Language             $xx xx xx
         // The actual text      <text string according to encoding>
         $frame_offset = 0;
         $frame_text_encoding = ord($parsed_frame['data'][$frame_offset++]);
         if ($id3v2_major_version <= 3 && $frame_text_encoding > 1 || $id3v2_major_version == 4 && $frame_text_encoding > 3) {
             $getid3->warning('Invalid text encoding byte (' . $frame_text_encoding . ') in frame "' . $parsed_frame['frame_name'] . '" - defaulting to ISO-8859-1 encoding');
         }
         $frame_language = substr($parsed_frame['data'], $frame_offset, 3);
         $frame_offset += 3;
         $parsed_frame['language'] = $frame_language;
         $parsed_frame['languagename'] = getid3_id3v2::LanguageLookup($frame_language, false);
         $parsed_frame['encodingid'] = $frame_text_encoding;
         $parsed_frame['encoding'] = $this->TextEncodingNameLookup($frame_text_encoding);
         $parsed_frame['data'] = (string) substr($parsed_frame['data'], $frame_offset);
         if (!empty($parsed_frame['framenameshort']) && !empty($parsed_frame['data'])) {
             $getid3->info['id3v2']['comments'][$parsed_frame['framenameshort']][] = $getid3->iconv($parsed_frame['encoding'], 'UTF-8', $parsed_frame['data']);
         }
         unset($parsed_frame['data']);
         return true;
     }
     if ($id3v2_major_version >= 3 && $parsed_frame['frame_name'] == 'OWNE') {
         // 4.23  OWNE Ownership frame (ID3v2.3+ only)
         //   There may only be one 'OWNE' frame in a tag
         // <Header for 'Ownership frame', ID: 'OWNE'>
         // Text encoding     $xx
         // Price paid        <text string> $00
         // Date of purch.    <text string>
         // Seller            <text string according to encoding>
         $frame_offset = 0;
         $frame_text_encoding = ord($parsed_frame['data'][$frame_offset++]);
         if ($id3v2_major_version <= 3 && $frame_text_encoding > 1 || $id3v2_major_version == 4 && $frame_text_encoding > 3) {
             $getid3->warning('Invalid text encoding byte (' . $frame_text_encoding . ') in frame "' . $parsed_frame['frame_name'] . '" - defaulting to ISO-8859-1 encoding');
         }
         $parsed_frame['encodingid'] = $frame_text_encoding;
         $parsed_frame['encoding'] = $this->TextEncodingNameLookup($frame_text_encoding);
         $frame_terminator_pos = @strpos($parsed_frame['data'], "", $frame_offset);
         $frame_pricepaid = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset);
         $frame_offset = $frame_terminator_pos + strlen("");
         $parsed_frame['pricepaid']['currencyid'] = substr($frame_pricepaid, 0, 3);
         $parsed_frame['pricepaid']['currency'] = getid3_id3v2::LookupCurrencyUnits($parsed_frame['pricepaid']['currencyid']);
         $parsed_frame['pricepaid']['value'] = substr($frame_pricepaid, 3);
         $parsed_frame['purchasedate'] = substr($parsed_frame['data'], $frame_offset, 8);
         if (!getid3_id3v2::IsValidDateStampString($parsed_frame['purchasedate'])) {
             $parsed_frame['purchasedateunix'] = gmmktime(0, 0, 0, substr($parsed_frame['purchasedate'], 4, 2), substr($parsed_frame['purchasedate'], 6, 2), substr($parsed_frame['purchasedate'], 0, 4));
         }
         $frame_offset += 8;
         $parsed_frame['seller'] = (string) substr($parsed_frame['data'], $frame_offset);
         unset($parsed_frame['data']);
         return true;
     }
     if ($id3v2_major_version >= 3 && $parsed_frame['frame_name'] == 'COMR') {
         // 4.24  COMR Commercial frame (ID3v2.3+ only)
         //   There may be more than one 'commercial frame' in a tag,
         //   but no two may be identical
         // <Header for 'Commercial frame', ID: 'COMR'>
         // Text encoding      $xx
         // Price string       <text string> $00
         // Valid until        <text string>
         // Contact URL        <text string> $00
         // Received as        $xx
         // Name of seller     <text string according to encoding> $00 (00)
         // Description        <text string according to encoding> $00 (00)
         // Picture MIME type  <string> $00
         // Seller logo        <binary data>
         $frame_offset = 0;
         $frame_text_encoding = ord($parsed_frame['data'][$frame_offset++]);
         if ($id3v2_major_version <= 3 && $frame_text_encoding > 1 || $id3v2_major_version == 4 && $frame_text_encoding > 3) {
             $getid3->warning('Invalid text encoding byte (' . $frame_text_encoding . ') in frame "' . $parsed_frame['frame_name'] . '" - defaulting to ISO-8859-1 encoding');
         }
         $frame_terminator_pos = @strpos($parsed_frame['data'], "", $frame_offset);
         $frame_price_string = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset);
         $frame_offset = $frame_terminator_pos + strlen("");
         $frame_rawpricearray = explode('/', $frame_price_string);
         foreach ($frame_rawpricearray as $key => $val) {
             $frame_currencyid = substr($val, 0, 3);
             $parsed_frame['price'][$frame_currencyid]['currency'] = getid3_id3v2::LookupCurrencyUnits($frame_currencyid);
             $parsed_frame['price'][$frame_currencyid]['value'] = substr($val, 3);
         }
         $frame_date_string = substr($parsed_frame['data'], $frame_offset, 8);
         $frame_offset += 8;
         $frame_terminator_pos = @strpos($parsed_frame['data'], "", $frame_offset);
         $frame_contacturl = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset);
         $frame_offset = $frame_terminator_pos + strlen("");
         $frame_received_as_id = ord($parsed_frame['data'][$frame_offset++]);
         $frame_terminator_pos = @strpos($parsed_frame['data'], getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding), $frame_offset);
         if (ord(substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)), 1)) === 0) {
             $frame_terminator_pos++;
             // @strpos() fooled because 2nd byte of Unicode chars are often 0x00
         }
         $frame_sellername = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset);
         if (ord($frame_sellername) === 0) {
             $frame_sellername = '';
         }
         $frame_offset = $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding));
         $frame_terminator_pos = @strpos($parsed_frame['data'], getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding), $frame_offset);
         if (ord(substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)), 1)) === 0) {
             $frame_terminator_pos++;
             // @strpos() fooled because 2nd byte of Unicode chars are often 0x00
         }
         $frame_description = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset);
         if (ord($frame_description) === 0) {
             $frame_description = '';
         }
         $frame_offset = $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding));
         $frame_terminator_pos = @strpos($parsed_frame['data'], "", $frame_offset);
         $frame_mimetype = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset);
         $frame_offset = $frame_terminator_pos + strlen("");
         $frame_sellerlogo = substr($parsed_frame['data'], $frame_offset);
         $parsed_frame['encodingid'] = $frame_text_encoding;
         $parsed_frame['encoding'] = $this->TextEncodingNameLookup($frame_text_encoding);
         $parsed_frame['pricevaliduntil'] = $frame_date_string;
         $parsed_frame['contacturl'] = $frame_contacturl;
         $parsed_frame['receivedasid'] = $frame_received_as_id;
         $parsed_frame['receivedas'] = getid3_id3v2::COMRReceivedAsLookup($frame_received_as_id);
         $parsed_frame['sellername'] = $frame_sellername;
         $parsed_frame['description'] = $frame_description;
         $parsed_frame['mime'] = $frame_mimetype;
         $parsed_frame['logo'] = $frame_sellerlogo;
         unset($parsed_frame['data']);
     }
     if ($id3v2_major_version >= 3 && $parsed_frame['frame_name'] == 'ENCR') {
         // 4.25  ENCR Encryption method registration (ID3v2.3+ only)
         //   There may be several 'ENCR' frames in a tag,
         //   but only one containing the same symbol
         //   and only one containing the same owner identifier
         // <Header for 'Encryption method registration', ID: 'ENCR'>
         // Owner identifier    <text string> $00
         // Method symbol       $xx
         // Encryption data     <binary data>
         $frame_offset = 0;
         $frame_terminator_pos = @strpos($parsed_frame['data'], "", $frame_offset);
         $frame_owner_id = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset);
         if (ord($frame_owner_id) === 0) {
             $frame_owner_id = '';
         }
         $frame_offset = $frame_terminator_pos + strlen("");
         $parsed_frame['ownerid'] = $frame_owner_id;
         $parsed_frame['methodsymbol'] = ord($parsed_frame['data'][$frame_offset++]);
         $parsed_frame['data'] = (string) substr($parsed_frame['data'], $frame_offset);
         return true;
     }
     if ($id3v2_major_version >= 3 && $parsed_frame['frame_name'] == 'GRID') {
         // 4.26  GRID Group identification registration (ID3v2.3+ only)
         //   There may be several 'GRID' frames in a tag,
         //   but only one containing the same symbol
         //   and only one containing the same owner identifier
         // <Header for 'Group ID registration', ID: 'GRID'>
         // Owner identifier      <text string> $00
         // Group symbol          $xx
         // Group dependent data  <binary data>
         $frame_offset = 0;
         $frame_terminator_pos = @strpos($parsed_frame['data'], "", $frame_offset);
         $frame_owner_id = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset);
         if (ord($frame_owner_id) === 0) {
             $frame_owner_id = '';
         }
         $frame_offset = $frame_terminator_pos + strlen("");
         $parsed_frame['ownerid'] = $frame_owner_id;
         $parsed_frame['groupsymbol'] = ord($parsed_frame['data'][$frame_offset++]);
         $parsed_frame['data'] = (string) substr($parsed_frame['data'], $frame_offset);
         return true;
     }
     if ($id3v2_major_version >= 3 && $parsed_frame['frame_name'] == 'PRIV') {
         // 4.27  PRIV Private frame (ID3v2.3+ only)
         //   The tag may contain more than one 'PRIV' frame
         //   but only with different contents
         // <Header for 'Private frame', ID: 'PRIV'>
         // Owner identifier      <text string> $00
         // The private data      <binary data>
         $frame_offset = 0;
         $frame_terminator_pos = @strpos($parsed_frame['data'], "", $frame_offset);
         $frame_owner_id = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset);
         if (ord($frame_owner_id) === 0) {
             $frame_owner_id = '';
         }
         $frame_offset = $frame_terminator_pos + strlen("");
         $parsed_frame['ownerid'] = $frame_owner_id;
         $parsed_frame['data'] = (string) substr($parsed_frame['data'], $frame_offset);
         return true;
     }
     if ($id3v2_major_version >= 4 && $parsed_frame['frame_name'] == 'SIGN') {
         // 4.28  SIGN Signature frame (ID3v2.4+ only)
         //   There may be more than one 'signature frame' in a tag,
         //   but no two may be identical
         // <Header for 'Signature frame', ID: 'SIGN'>
         // Group symbol      $xx
         // Signature         <binary data>
         $frame_offset = 0;
         $parsed_frame['groupsymbol'] = ord($parsed_frame['data'][$frame_offset++]);
         $parsed_frame['data'] = (string) substr($parsed_frame['data'], $frame_offset);
         return true;
     }
     if ($id3v2_major_version >= 4 && $parsed_frame['frame_name'] == 'SEEK') {
         // 4.29  SEEK Seek frame (ID3v2.4+ only)
         //   There may only be one 'seek frame' in a tag
         // <Header for 'Seek frame', ID: 'SEEK'>
         // Minimum offset to next tag       $xx xx xx xx
         $frame_offset = 0;
         $parsed_frame['data'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, 4));
         return true;
     }
     if ($id3v2_major_version >= 4 && $parsed_frame['frame_name'] == 'ASPI') {
         // 4.30  ASPI Audio seek point index (ID3v2.4+ only)
         //   There may only be one 'audio seek point index' frame in a tag
         // <Header for 'Seek Point Index', ID: 'ASPI'>
         // Indexed data start (S)         $xx xx xx xx
         // Indexed data length (L)        $xx xx xx xx
         // Number of index points (N)     $xx xx
         // Bits per index point (b)       $xx
         //   Then for every index point the following data is included:
         // Fraction at index (Fi)          $xx (xx)
         $frame_offset = 0;
         $parsed_frame['datastart'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, 4));
         $frame_offset += 4;
         $parsed_frame['indexeddatalength'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, 4));
         $frame_offset += 4;
         $parsed_frame['indexpoints'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, 2));
         $frame_offset += 2;
         $parsed_frame['bitsperpoint'] = ord($parsed_frame['data'][$frame_offset++]);
         $frame_bytesperpoint = ceil($parsed_frame['bitsperpoint'] / 8);
         for ($i = 0; $i < $frame_indexpoints; $i++) {
             $parsed_frame['indexes'][$i] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, $frame_bytesperpoint));
             $frame_offset += $frame_bytesperpoint;
         }
         unset($parsed_frame['data']);
         return true;
     }
     if ($id3v2_major_version >= 3 && $parsed_frame['frame_name'] == 'RGAD') {
         // Replay Gain Adjustment
         // http://privatewww.essex.ac.uk/~djmrob/replaygain/file_format_id3v2.html
         //   There may only be one 'RGAD' frame in a tag
         // <Header for 'Replay Gain Adjustment', ID: 'RGAD'>
         // Peak Amplitude                      $xx $xx $xx $xx
         // Radio Replay Gain Adjustment        %aaabbbcd %dddddddd
         // Audiophile Replay Gain Adjustment   %aaabbbcd %dddddddd
         //   a - name code
         //   b - originator code
         //   c - sign bit
         //   d - replay gain adjustment
         $frame_offset = 0;
         $parsed_frame['peakamplitude'] = (double) getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, 4));
         $frame_offset += 4;
         $rg_track_adjustment = decbin(substr($parsed_frame['data'], $frame_offset, 2));
         $frame_offset += 2;
         $rg_album_adjustment = decbin(substr($parsed_frame['data'], $frame_offset, 2));
         $frame_offset += 2;
         $parsed_frame['raw']['track']['name'] = bindec(substr($rg_track_adjustment, 0, 3));
         $parsed_frame['raw']['track']['originator'] = bindec(substr($rg_track_adjustment, 3, 3));
         $parsed_frame['raw']['track']['signbit'] = bindec($rg_track_adjustment[6]);
         $parsed_frame['raw']['track']['adjustment'] = bindec(substr($rg_track_adjustment, 7, 9));
         $parsed_frame['raw']['album']['name'] = bindec(substr($rg_album_adjustment, 0, 3));
         $parsed_frame['raw']['album']['originator'] = bindec(substr($rg_album_adjustment, 3, 3));
         $parsed_frame['raw']['album']['signbit'] = bindec($rg_album_adjustment[6]);
         $parsed_frame['raw']['album']['adjustment'] = bindec(substr($rg_album_adjustment, 7, 9));
         $parsed_frame['track']['name'] = getid3_lib_replaygain::NameLookup($parsed_frame['raw']['track']['name']);
         $parsed_frame['track']['originator'] = getid3_lib_replaygain::OriginatorLookup($parsed_frame['raw']['track']['originator']);
         $parsed_frame['track']['adjustment'] = getid3_lib_replaygain::AdjustmentLookup($parsed_frame['raw']['track']['adjustment'], $parsed_frame['raw']['track']['signbit']);
         $parsed_frame['album']['name'] = getid3_lib_replaygain::NameLookup($parsed_frame['raw']['album']['name']);
         $parsed_frame['album']['originator'] = getid3_lib_replaygain::OriginatorLookup($parsed_frame['raw']['album']['originator']);
         $parsed_frame['album']['adjustment'] = getid3_lib_replaygain::AdjustmentLookup($parsed_frame['raw']['album']['adjustment'], $parsed_frame['raw']['album']['signbit']);
         $getid3->info['replay_gain']['track']['peak'] = $parsed_frame['peakamplitude'];
         $getid3->info['replay_gain']['track']['originator'] = $parsed_frame['track']['originator'];
         $getid3->info['replay_gain']['track']['adjustment'] = $parsed_frame['track']['adjustment'];
         $getid3->info['replay_gain']['album']['originator'] = $parsed_frame['album']['originator'];
         $getid3->info['replay_gain']['album']['adjustment'] = $parsed_frame['album']['adjustment'];
         unset($parsed_frame['data']);
         return true;
     }
     return true;
 }