public function QuicktimeLanguageLookup($languageid)
 {
     // http://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap4/qtff4.html#//apple_ref/doc/uid/TP40000939-CH206-34353
     static $QuicktimeLanguageLookup = array();
     if (empty($QuicktimeLanguageLookup)) {
         $QuicktimeLanguageLookup[0] = 'English';
         $QuicktimeLanguageLookup[1] = 'French';
         $QuicktimeLanguageLookup[2] = 'German';
         $QuicktimeLanguageLookup[3] = 'Italian';
         $QuicktimeLanguageLookup[4] = 'Dutch';
         $QuicktimeLanguageLookup[5] = 'Swedish';
         $QuicktimeLanguageLookup[6] = 'Spanish';
         $QuicktimeLanguageLookup[7] = 'Danish';
         $QuicktimeLanguageLookup[8] = 'Portuguese';
         $QuicktimeLanguageLookup[9] = 'Norwegian';
         $QuicktimeLanguageLookup[10] = 'Hebrew';
         $QuicktimeLanguageLookup[11] = 'Japanese';
         $QuicktimeLanguageLookup[12] = 'Arabic';
         $QuicktimeLanguageLookup[13] = 'Finnish';
         $QuicktimeLanguageLookup[14] = 'Greek';
         $QuicktimeLanguageLookup[15] = 'Icelandic';
         $QuicktimeLanguageLookup[16] = 'Maltese';
         $QuicktimeLanguageLookup[17] = 'Turkish';
         $QuicktimeLanguageLookup[18] = 'Croatian';
         $QuicktimeLanguageLookup[19] = 'Chinese (Traditional)';
         $QuicktimeLanguageLookup[20] = 'Urdu';
         $QuicktimeLanguageLookup[21] = 'Hindi';
         $QuicktimeLanguageLookup[22] = 'Thai';
         $QuicktimeLanguageLookup[23] = 'Korean';
         $QuicktimeLanguageLookup[24] = 'Lithuanian';
         $QuicktimeLanguageLookup[25] = 'Polish';
         $QuicktimeLanguageLookup[26] = 'Hungarian';
         $QuicktimeLanguageLookup[27] = 'Estonian';
         $QuicktimeLanguageLookup[28] = 'Lettish';
         $QuicktimeLanguageLookup[28] = 'Latvian';
         $QuicktimeLanguageLookup[29] = 'Saamisk';
         $QuicktimeLanguageLookup[29] = 'Lappish';
         $QuicktimeLanguageLookup[30] = 'Faeroese';
         $QuicktimeLanguageLookup[31] = 'Farsi';
         $QuicktimeLanguageLookup[31] = 'Persian';
         $QuicktimeLanguageLookup[32] = 'Russian';
         $QuicktimeLanguageLookup[33] = 'Chinese (Simplified)';
         $QuicktimeLanguageLookup[34] = 'Flemish';
         $QuicktimeLanguageLookup[35] = 'Irish';
         $QuicktimeLanguageLookup[36] = 'Albanian';
         $QuicktimeLanguageLookup[37] = 'Romanian';
         $QuicktimeLanguageLookup[38] = 'Czech';
         $QuicktimeLanguageLookup[39] = 'Slovak';
         $QuicktimeLanguageLookup[40] = 'Slovenian';
         $QuicktimeLanguageLookup[41] = 'Yiddish';
         $QuicktimeLanguageLookup[42] = 'Serbian';
         $QuicktimeLanguageLookup[43] = 'Macedonian';
         $QuicktimeLanguageLookup[44] = 'Bulgarian';
         $QuicktimeLanguageLookup[45] = 'Ukrainian';
         $QuicktimeLanguageLookup[46] = 'Byelorussian';
         $QuicktimeLanguageLookup[47] = 'Uzbek';
         $QuicktimeLanguageLookup[48] = 'Kazakh';
         $QuicktimeLanguageLookup[49] = 'Azerbaijani';
         $QuicktimeLanguageLookup[50] = 'AzerbaijanAr';
         $QuicktimeLanguageLookup[51] = 'Armenian';
         $QuicktimeLanguageLookup[52] = 'Georgian';
         $QuicktimeLanguageLookup[53] = 'Moldavian';
         $QuicktimeLanguageLookup[54] = 'Kirghiz';
         $QuicktimeLanguageLookup[55] = 'Tajiki';
         $QuicktimeLanguageLookup[56] = 'Turkmen';
         $QuicktimeLanguageLookup[57] = 'Mongolian';
         $QuicktimeLanguageLookup[58] = 'MongolianCyr';
         $QuicktimeLanguageLookup[59] = 'Pashto';
         $QuicktimeLanguageLookup[60] = 'Kurdish';
         $QuicktimeLanguageLookup[61] = 'Kashmiri';
         $QuicktimeLanguageLookup[62] = 'Sindhi';
         $QuicktimeLanguageLookup[63] = 'Tibetan';
         $QuicktimeLanguageLookup[64] = 'Nepali';
         $QuicktimeLanguageLookup[65] = 'Sanskrit';
         $QuicktimeLanguageLookup[66] = 'Marathi';
         $QuicktimeLanguageLookup[67] = 'Bengali';
         $QuicktimeLanguageLookup[68] = 'Assamese';
         $QuicktimeLanguageLookup[69] = 'Gujarati';
         $QuicktimeLanguageLookup[70] = 'Punjabi';
         $QuicktimeLanguageLookup[71] = 'Oriya';
         $QuicktimeLanguageLookup[72] = 'Malayalam';
         $QuicktimeLanguageLookup[73] = 'Kannada';
         $QuicktimeLanguageLookup[74] = 'Tamil';
         $QuicktimeLanguageLookup[75] = 'Telugu';
         $QuicktimeLanguageLookup[76] = 'Sinhalese';
         $QuicktimeLanguageLookup[77] = 'Burmese';
         $QuicktimeLanguageLookup[78] = 'Khmer';
         $QuicktimeLanguageLookup[79] = 'Lao';
         $QuicktimeLanguageLookup[80] = 'Vietnamese';
         $QuicktimeLanguageLookup[81] = 'Indonesian';
         $QuicktimeLanguageLookup[82] = 'Tagalog';
         $QuicktimeLanguageLookup[83] = 'MalayRoman';
         $QuicktimeLanguageLookup[84] = 'MalayArabic';
         $QuicktimeLanguageLookup[85] = 'Amharic';
         $QuicktimeLanguageLookup[86] = 'Tigrinya';
         $QuicktimeLanguageLookup[87] = 'Galla';
         $QuicktimeLanguageLookup[87] = 'Oromo';
         $QuicktimeLanguageLookup[88] = 'Somali';
         $QuicktimeLanguageLookup[89] = 'Swahili';
         $QuicktimeLanguageLookup[90] = 'Ruanda';
         $QuicktimeLanguageLookup[91] = 'Rundi';
         $QuicktimeLanguageLookup[92] = 'Chewa';
         $QuicktimeLanguageLookup[93] = 'Malagasy';
         $QuicktimeLanguageLookup[94] = 'Esperanto';
         $QuicktimeLanguageLookup[128] = 'Welsh';
         $QuicktimeLanguageLookup[129] = 'Basque';
         $QuicktimeLanguageLookup[130] = 'Catalan';
         $QuicktimeLanguageLookup[131] = 'Latin';
         $QuicktimeLanguageLookup[132] = 'Quechua';
         $QuicktimeLanguageLookup[133] = 'Guarani';
         $QuicktimeLanguageLookup[134] = 'Aymara';
         $QuicktimeLanguageLookup[135] = 'Tatar';
         $QuicktimeLanguageLookup[136] = 'Uighur';
         $QuicktimeLanguageLookup[137] = 'Dzongkha';
         $QuicktimeLanguageLookup[138] = 'JavaneseRom';
         $QuicktimeLanguageLookup[32767] = 'Unspecified';
     }
     if ($languageid > 138 && $languageid < 32767) {
         /*
         ISO Language Codes - http://www.loc.gov/standards/iso639-2/php/code_list.php
         Because the language codes specified by ISO 639-2/T are three characters long, they must be packed to fit into a 16-bit field.
         The packing algorithm must map each of the three characters, which are always lowercase, into a 5-bit integer and then concatenate
         these integers into the least significant 15 bits of a 16-bit integer, leaving the 16-bit integer's most significant bit set to zero.
         
         One algorithm for performing this packing is to treat each ISO character as a 16-bit integer. Subtract 0x60 from the first character
         and multiply by 2^10 (0x400), subtract 0x60 from the second character and multiply by 2^5 (0x20), subtract 0x60 from the third character,
         and add the three 16-bit values. This will result in a single 16-bit value with the three codes correctly packed into the 15 least
         significant bits and the most significant bit set to zero.
         */
         $iso_language_id = '';
         $iso_language_id .= chr((($languageid & 0x7c00) >> 10) + 0x60);
         $iso_language_id .= chr((($languageid & 0x3e0) >> 5) + 0x60);
         $iso_language_id .= chr((($languageid & 0x1f) >> 0) + 0x60);
         $QuicktimeLanguageLookup[$languageid] = getid3_id3v2::LanguageLookup($iso_language_id);
     }
     return isset($QuicktimeLanguageLookup[$languageid]) ? $QuicktimeLanguageLookup[$languageid] : 'invalid';
 }
Ejemplo 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;
 }
Ejemplo n.º 3
0
 function ID3v2IsValidPriceString($pricestring)
 {
     if (getid3_id3v2::LanguageLookup(substr($pricestring, 0, 3), true) == '') {
         return false;
     } elseif (!$this->IsANumber(substr($pricestring, 3), true)) {
         return false;
     }
     return true;
 }