wp/wp-includes/ID3/module.tag.id3v2.php
changeset 0 d970ebf37754
child 5 5e2f62d02dcd
equal deleted inserted replaced
-1:000000000000 0:d970ebf37754
       
     1 <?php
       
     2 /////////////////////////////////////////////////////////////////
       
     3 /// getID3() by James Heinrich <info@getid3.org>               //
       
     4 //  available at http://getid3.sourceforge.net                 //
       
     5 //            or http://www.getid3.org                         //
       
     6 /////////////////////////////////////////////////////////////////
       
     7 // See readme.txt for more details                             //
       
     8 /////////////////////////////////////////////////////////////////
       
     9 ///                                                            //
       
    10 // module.tag.id3v2.php                                        //
       
    11 // module for analyzing ID3v2 tags                             //
       
    12 // dependencies: module.tag.id3v1.php                          //
       
    13 //                                                            ///
       
    14 /////////////////////////////////////////////////////////////////
       
    15 
       
    16 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v1.php', __FILE__, true);
       
    17 
       
    18 class getid3_id3v2 extends getid3_handler
       
    19 {
       
    20 	public $StartingOffset = 0;
       
    21 
       
    22 	public function Analyze() {
       
    23 		$info = &$this->getid3->info;
       
    24 
       
    25 		//    Overall tag structure:
       
    26 		//        +-----------------------------+
       
    27 		//        |      Header (10 bytes)      |
       
    28 		//        +-----------------------------+
       
    29 		//        |       Extended Header       |
       
    30 		//        | (variable length, OPTIONAL) |
       
    31 		//        +-----------------------------+
       
    32 		//        |   Frames (variable length)  |
       
    33 		//        +-----------------------------+
       
    34 		//        |           Padding           |
       
    35 		//        | (variable length, OPTIONAL) |
       
    36 		//        +-----------------------------+
       
    37 		//        | Footer (10 bytes, OPTIONAL) |
       
    38 		//        +-----------------------------+
       
    39 
       
    40 		//    Header
       
    41 		//        ID3v2/file identifier      "ID3"
       
    42 		//        ID3v2 version              $04 00
       
    43 		//        ID3v2 flags                (%ab000000 in v2.2, %abc00000 in v2.3, %abcd0000 in v2.4.x)
       
    44 		//        ID3v2 size             4 * %0xxxxxxx
       
    45 
       
    46 
       
    47 		// shortcuts
       
    48 		$info['id3v2']['header'] = true;
       
    49 		$thisfile_id3v2                  = &$info['id3v2'];
       
    50 		$thisfile_id3v2['flags']         =  array();
       
    51 		$thisfile_id3v2_flags            = &$thisfile_id3v2['flags'];
       
    52 
       
    53 
       
    54 		fseek($this->getid3->fp, $this->StartingOffset, SEEK_SET);
       
    55 		$header = fread($this->getid3->fp, 10);
       
    56 		if (substr($header, 0, 3) == 'ID3'  &&  strlen($header) == 10) {
       
    57 
       
    58 			$thisfile_id3v2['majorversion'] = ord($header{3});
       
    59 			$thisfile_id3v2['minorversion'] = ord($header{4});
       
    60 
       
    61 			// shortcut
       
    62 			$id3v2_majorversion = &$thisfile_id3v2['majorversion'];
       
    63 
       
    64 		} else {
       
    65 
       
    66 			unset($info['id3v2']);
       
    67 			return false;
       
    68 
       
    69 		}
       
    70 
       
    71 		if ($id3v2_majorversion > 4) { // this script probably won't correctly parse ID3v2.5.x and above (if it ever exists)
       
    72 
       
    73 			$info['error'][] = 'this script only parses up to ID3v2.4.x - this tag is ID3v2.'.$id3v2_majorversion.'.'.$thisfile_id3v2['minorversion'];
       
    74 			return false;
       
    75 
       
    76 		}
       
    77 
       
    78 		$id3_flags = ord($header{5});
       
    79 		switch ($id3v2_majorversion) {
       
    80 			case 2:
       
    81 				// %ab000000 in v2.2
       
    82 				$thisfile_id3v2_flags['unsynch']     = (bool) ($id3_flags & 0x80); // a - Unsynchronisation
       
    83 				$thisfile_id3v2_flags['compression'] = (bool) ($id3_flags & 0x40); // b - Compression
       
    84 				break;
       
    85 
       
    86 			case 3:
       
    87 				// %abc00000 in v2.3
       
    88 				$thisfile_id3v2_flags['unsynch']     = (bool) ($id3_flags & 0x80); // a - Unsynchronisation
       
    89 				$thisfile_id3v2_flags['exthead']     = (bool) ($id3_flags & 0x40); // b - Extended header
       
    90 				$thisfile_id3v2_flags['experim']     = (bool) ($id3_flags & 0x20); // c - Experimental indicator
       
    91 				break;
       
    92 
       
    93 			case 4:
       
    94 				// %abcd0000 in v2.4
       
    95 				$thisfile_id3v2_flags['unsynch']     = (bool) ($id3_flags & 0x80); // a - Unsynchronisation
       
    96 				$thisfile_id3v2_flags['exthead']     = (bool) ($id3_flags & 0x40); // b - Extended header
       
    97 				$thisfile_id3v2_flags['experim']     = (bool) ($id3_flags & 0x20); // c - Experimental indicator
       
    98 				$thisfile_id3v2_flags['isfooter']    = (bool) ($id3_flags & 0x10); // d - Footer present
       
    99 				break;
       
   100 		}
       
   101 
       
   102 		$thisfile_id3v2['headerlength'] = getid3_lib::BigEndian2Int(substr($header, 6, 4), 1) + 10; // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length
       
   103 
       
   104 		$thisfile_id3v2['tag_offset_start'] = $this->StartingOffset;
       
   105 		$thisfile_id3v2['tag_offset_end']   = $thisfile_id3v2['tag_offset_start'] + $thisfile_id3v2['headerlength'];
       
   106 
       
   107 
       
   108 
       
   109 		// create 'encoding' key - used by getid3::HandleAllTags()
       
   110 		// in ID3v2 every field can have it's own encoding type
       
   111 		// so force everything to UTF-8 so it can be handled consistantly
       
   112 		$thisfile_id3v2['encoding'] = 'UTF-8';
       
   113 
       
   114 
       
   115 	//    Frames
       
   116 
       
   117 	//        All ID3v2 frames consists of one frame header followed by one or more
       
   118 	//        fields containing the actual information. The header is always 10
       
   119 	//        bytes and laid out as follows:
       
   120 	//
       
   121 	//        Frame ID      $xx xx xx xx  (four characters)
       
   122 	//        Size      4 * %0xxxxxxx
       
   123 	//        Flags         $xx xx
       
   124 
       
   125 		$sizeofframes = $thisfile_id3v2['headerlength'] - 10; // not including 10-byte initial header
       
   126 		if (!empty($thisfile_id3v2['exthead']['length'])) {
       
   127 			$sizeofframes -= ($thisfile_id3v2['exthead']['length'] + 4);
       
   128 		}
       
   129 		if (!empty($thisfile_id3v2_flags['isfooter'])) {
       
   130 			$sizeofframes -= 10; // footer takes last 10 bytes of ID3v2 header, after frame data, before audio
       
   131 		}
       
   132 		if ($sizeofframes > 0) {
       
   133 
       
   134 			$framedata = fread($this->getid3->fp, $sizeofframes); // read all frames from file into $framedata variable
       
   135 
       
   136 			//    if entire frame data is unsynched, de-unsynch it now (ID3v2.3.x)
       
   137 			if (!empty($thisfile_id3v2_flags['unsynch']) && ($id3v2_majorversion <= 3)) {
       
   138 				$framedata = $this->DeUnsynchronise($framedata);
       
   139 			}
       
   140 			//        [in ID3v2.4.0] Unsynchronisation [S:6.1] is done on frame level, instead
       
   141 			//        of on tag level, making it easier to skip frames, increasing the streamability
       
   142 			//        of the tag. The unsynchronisation flag in the header [S:3.1] indicates that
       
   143 			//        there exists an unsynchronised frame, while the new unsynchronisation flag in
       
   144 			//        the frame header [S:4.1.2] indicates unsynchronisation.
       
   145 
       
   146 
       
   147 			//$framedataoffset = 10 + ($thisfile_id3v2['exthead']['length'] ? $thisfile_id3v2['exthead']['length'] + 4 : 0); // how many bytes into the stream - start from after the 10-byte header (and extended header length+4, if present)
       
   148 			$framedataoffset = 10; // how many bytes into the stream - start from after the 10-byte header
       
   149 
       
   150 
       
   151 			//    Extended Header
       
   152 			if (!empty($thisfile_id3v2_flags['exthead'])) {
       
   153 				$extended_header_offset = 0;
       
   154 
       
   155 				if ($id3v2_majorversion == 3) {
       
   156 
       
   157 					// v2.3 definition:
       
   158 					//Extended header size  $xx xx xx xx   // 32-bit integer
       
   159 					//Extended Flags        $xx xx
       
   160 					//     %x0000000 %00000000 // v2.3
       
   161 					//     x - CRC data present
       
   162 					//Size of padding       $xx xx xx xx
       
   163 
       
   164 					$thisfile_id3v2['exthead']['length'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4), 0);
       
   165 					$extended_header_offset += 4;
       
   166 
       
   167 					$thisfile_id3v2['exthead']['flag_bytes'] = 2;
       
   168 					$thisfile_id3v2['exthead']['flag_raw'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, $thisfile_id3v2['exthead']['flag_bytes']));
       
   169 					$extended_header_offset += $thisfile_id3v2['exthead']['flag_bytes'];
       
   170 
       
   171 					$thisfile_id3v2['exthead']['flags']['crc'] = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x8000);
       
   172 
       
   173 					$thisfile_id3v2['exthead']['padding_size'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4));
       
   174 					$extended_header_offset += 4;
       
   175 
       
   176 					if ($thisfile_id3v2['exthead']['flags']['crc']) {
       
   177 						$thisfile_id3v2['exthead']['flag_data']['crc'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4));
       
   178 						$extended_header_offset += 4;
       
   179 					}
       
   180 					$extended_header_offset += $thisfile_id3v2['exthead']['padding_size'];
       
   181 
       
   182 				} elseif ($id3v2_majorversion == 4) {
       
   183 
       
   184 					// v2.4 definition:
       
   185 					//Extended header size   4 * %0xxxxxxx // 28-bit synchsafe integer
       
   186 					//Number of flag bytes       $01
       
   187 					//Extended Flags             $xx
       
   188 					//     %0bcd0000 // v2.4
       
   189 					//     b - Tag is an update
       
   190 					//         Flag data length       $00
       
   191 					//     c - CRC data present
       
   192 					//         Flag data length       $05
       
   193 					//         Total frame CRC    5 * %0xxxxxxx
       
   194 					//     d - Tag restrictions
       
   195 					//         Flag data length       $01
       
   196 
       
   197 					$thisfile_id3v2['exthead']['length'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4), true);
       
   198 					$extended_header_offset += 4;
       
   199 
       
   200 					$thisfile_id3v2['exthead']['flag_bytes'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should always be 1
       
   201 					$extended_header_offset += 1;
       
   202 
       
   203 					$thisfile_id3v2['exthead']['flag_raw'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, $thisfile_id3v2['exthead']['flag_bytes']));
       
   204 					$extended_header_offset += $thisfile_id3v2['exthead']['flag_bytes'];
       
   205 
       
   206 					$thisfile_id3v2['exthead']['flags']['update']       = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x40);
       
   207 					$thisfile_id3v2['exthead']['flags']['crc']          = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x20);
       
   208 					$thisfile_id3v2['exthead']['flags']['restrictions'] = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x10);
       
   209 
       
   210 					if ($thisfile_id3v2['exthead']['flags']['update']) {
       
   211 						$ext_header_chunk_length = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should be 0
       
   212 						$extended_header_offset += 1;
       
   213 					}
       
   214 
       
   215 					if ($thisfile_id3v2['exthead']['flags']['crc']) {
       
   216 						$ext_header_chunk_length = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should be 5
       
   217 						$extended_header_offset += 1;
       
   218 						$thisfile_id3v2['exthead']['flag_data']['crc'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, $ext_header_chunk_length), true, false);
       
   219 						$extended_header_offset += $ext_header_chunk_length;
       
   220 					}
       
   221 
       
   222 					if ($thisfile_id3v2['exthead']['flags']['restrictions']) {
       
   223 						$ext_header_chunk_length = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should be 1
       
   224 						$extended_header_offset += 1;
       
   225 
       
   226 						// %ppqrrstt
       
   227 						$restrictions_raw = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1));
       
   228 						$extended_header_offset += 1;
       
   229 						$thisfile_id3v2['exthead']['flags']['restrictions']['tagsize']  = ($restrictions_raw & 0xC0) >> 6; // p - Tag size restrictions
       
   230 						$thisfile_id3v2['exthead']['flags']['restrictions']['textenc']  = ($restrictions_raw & 0x20) >> 5; // q - Text encoding restrictions
       
   231 						$thisfile_id3v2['exthead']['flags']['restrictions']['textsize'] = ($restrictions_raw & 0x18) >> 3; // r - Text fields size restrictions
       
   232 						$thisfile_id3v2['exthead']['flags']['restrictions']['imgenc']   = ($restrictions_raw & 0x04) >> 2; // s - Image encoding restrictions
       
   233 						$thisfile_id3v2['exthead']['flags']['restrictions']['imgsize']  = ($restrictions_raw & 0x03) >> 0; // t - Image size restrictions
       
   234 
       
   235 						$thisfile_id3v2['exthead']['flags']['restrictions_text']['tagsize']  = $this->LookupExtendedHeaderRestrictionsTagSizeLimits($thisfile_id3v2['exthead']['flags']['restrictions']['tagsize']);
       
   236 						$thisfile_id3v2['exthead']['flags']['restrictions_text']['textenc']  = $this->LookupExtendedHeaderRestrictionsTextEncodings($thisfile_id3v2['exthead']['flags']['restrictions']['textenc']);
       
   237 						$thisfile_id3v2['exthead']['flags']['restrictions_text']['textsize'] = $this->LookupExtendedHeaderRestrictionsTextFieldSize($thisfile_id3v2['exthead']['flags']['restrictions']['textsize']);
       
   238 						$thisfile_id3v2['exthead']['flags']['restrictions_text']['imgenc']   = $this->LookupExtendedHeaderRestrictionsImageEncoding($thisfile_id3v2['exthead']['flags']['restrictions']['imgenc']);
       
   239 						$thisfile_id3v2['exthead']['flags']['restrictions_text']['imgsize']  = $this->LookupExtendedHeaderRestrictionsImageSizeSize($thisfile_id3v2['exthead']['flags']['restrictions']['imgsize']);
       
   240 					}
       
   241 
       
   242 					if ($thisfile_id3v2['exthead']['length'] != $extended_header_offset) {
       
   243 						$info['warning'][] = 'ID3v2.4 extended header length mismatch (expecting '.intval($thisfile_id3v2['exthead']['length']).', found '.intval($extended_header_offset).')';
       
   244 					}
       
   245 				}
       
   246 
       
   247 				$framedataoffset += $extended_header_offset;
       
   248 				$framedata = substr($framedata, $extended_header_offset);
       
   249 			} // end extended header
       
   250 
       
   251 
       
   252 			while (isset($framedata) && (strlen($framedata) > 0)) { // cycle through until no more frame data is left to parse
       
   253 				if (strlen($framedata) <= $this->ID3v2HeaderLength($id3v2_majorversion)) {
       
   254 					// insufficient room left in ID3v2 header for actual data - must be padding
       
   255 					$thisfile_id3v2['padding']['start']  = $framedataoffset;
       
   256 					$thisfile_id3v2['padding']['length'] = strlen($framedata);
       
   257 					$thisfile_id3v2['padding']['valid']  = true;
       
   258 					for ($i = 0; $i < $thisfile_id3v2['padding']['length']; $i++) {
       
   259 						if ($framedata{$i} != "\x00") {
       
   260 							$thisfile_id3v2['padding']['valid'] = false;
       
   261 							$thisfile_id3v2['padding']['errorpos'] = $thisfile_id3v2['padding']['start'] + $i;
       
   262 							$info['warning'][] = 'Invalid ID3v2 padding found at offset '.$thisfile_id3v2['padding']['errorpos'].' (the remaining '.($thisfile_id3v2['padding']['length'] - $i).' bytes are considered invalid)';
       
   263 							break;
       
   264 						}
       
   265 					}
       
   266 					break; // skip rest of ID3v2 header
       
   267 				}
       
   268 				if ($id3v2_majorversion == 2) {
       
   269 					// Frame ID  $xx xx xx (three characters)
       
   270 					// Size      $xx xx xx (24-bit integer)
       
   271 					// Flags     $xx xx
       
   272 
       
   273 					$frame_header = substr($framedata, 0, 6); // take next 6 bytes for header
       
   274 					$framedata    = substr($framedata, 6);    // and leave the rest in $framedata
       
   275 					$frame_name   = substr($frame_header, 0, 3);
       
   276 					$frame_size   = getid3_lib::BigEndian2Int(substr($frame_header, 3, 3), 0);
       
   277 					$frame_flags  = 0; // not used for anything in ID3v2.2, just set to avoid E_NOTICEs
       
   278 
       
   279 				} elseif ($id3v2_majorversion > 2) {
       
   280 
       
   281 					// Frame ID  $xx xx xx xx (four characters)
       
   282 					// Size      $xx xx xx xx (32-bit integer in v2.3, 28-bit synchsafe in v2.4+)
       
   283 					// Flags     $xx xx
       
   284 
       
   285 					$frame_header = substr($framedata, 0, 10); // take next 10 bytes for header
       
   286 					$framedata    = substr($framedata, 10);    // and leave the rest in $framedata
       
   287 
       
   288 					$frame_name = substr($frame_header, 0, 4);
       
   289 					if ($id3v2_majorversion == 3) {
       
   290 						$frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0); // 32-bit integer
       
   291 					} else { // ID3v2.4+
       
   292 						$frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 1); // 32-bit synchsafe integer (28-bit value)
       
   293 					}
       
   294 
       
   295 					if ($frame_size < (strlen($framedata) + 4)) {
       
   296 						$nextFrameID = substr($framedata, $frame_size, 4);
       
   297 						if ($this->IsValidID3v2FrameName($nextFrameID, $id3v2_majorversion)) {
       
   298 							// next frame is OK
       
   299 						} elseif (($frame_name == "\x00".'MP3') || ($frame_name == "\x00\x00".'MP') || ($frame_name == ' MP3') || ($frame_name == 'MP3e')) {
       
   300 							// MP3ext known broken frames - "ok" for the purposes of this test
       
   301 						} elseif (($id3v2_majorversion == 4) && ($this->IsValidID3v2FrameName(substr($framedata, getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0), 4), 3))) {
       
   302 							$info['warning'][] = 'ID3v2 tag written as ID3v2.4, but with non-synchsafe integers (ID3v2.3 style). Older versions of (Helium2; iTunes) are known culprits of this. Tag has been parsed as ID3v2.3';
       
   303 							$id3v2_majorversion = 3;
       
   304 							$frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0); // 32-bit integer
       
   305 						}
       
   306 					}
       
   307 
       
   308 
       
   309 					$frame_flags = getid3_lib::BigEndian2Int(substr($frame_header, 8, 2));
       
   310 				}
       
   311 
       
   312 				if ((($id3v2_majorversion == 2) && ($frame_name == "\x00\x00\x00")) || ($frame_name == "\x00\x00\x00\x00")) {
       
   313 					// padding encountered
       
   314 
       
   315 					$thisfile_id3v2['padding']['start']  = $framedataoffset;
       
   316 					$thisfile_id3v2['padding']['length'] = strlen($frame_header) + strlen($framedata);
       
   317 					$thisfile_id3v2['padding']['valid']  = true;
       
   318 
       
   319 					$len = strlen($framedata);
       
   320 					for ($i = 0; $i < $len; $i++) {
       
   321 						if ($framedata{$i} != "\x00") {
       
   322 							$thisfile_id3v2['padding']['valid'] = false;
       
   323 							$thisfile_id3v2['padding']['errorpos'] = $thisfile_id3v2['padding']['start'] + $i;
       
   324 							$info['warning'][] = 'Invalid ID3v2 padding found at offset '.$thisfile_id3v2['padding']['errorpos'].' (the remaining '.($thisfile_id3v2['padding']['length'] - $i).' bytes are considered invalid)';
       
   325 							break;
       
   326 						}
       
   327 					}
       
   328 					break; // skip rest of ID3v2 header
       
   329 				}
       
   330 
       
   331 				if ($frame_name == 'COM ') {
       
   332 					$info['warning'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))). [Note: this particular error has been known to happen with tags edited by iTunes (versions "X v2.0.3", "v3.0.1" are known-guilty, probably others too)]';
       
   333 					$frame_name = 'COMM';
       
   334 				}
       
   335 				if (($frame_size <= strlen($framedata)) && ($this->IsValidID3v2FrameName($frame_name, $id3v2_majorversion))) {
       
   336 
       
   337 					unset($parsedFrame);
       
   338 					$parsedFrame['frame_name']      = $frame_name;
       
   339 					$parsedFrame['frame_flags_raw'] = $frame_flags;
       
   340 					$parsedFrame['data']            = substr($framedata, 0, $frame_size);
       
   341 					$parsedFrame['datalength']      = getid3_lib::CastAsInt($frame_size);
       
   342 					$parsedFrame['dataoffset']      = $framedataoffset;
       
   343 
       
   344 					$this->ParseID3v2Frame($parsedFrame);
       
   345 					$thisfile_id3v2[$frame_name][] = $parsedFrame;
       
   346 
       
   347 					$framedata = substr($framedata, $frame_size);
       
   348 
       
   349 				} else { // invalid frame length or FrameID
       
   350 
       
   351 					if ($frame_size <= strlen($framedata)) {
       
   352 
       
   353 						if ($this->IsValidID3v2FrameName(substr($framedata, $frame_size, 4), $id3v2_majorversion)) {
       
   354 
       
   355 							// next frame is valid, just skip the current frame
       
   356 							$framedata = substr($framedata, $frame_size);
       
   357 							$info['warning'][] = 'Next ID3v2 frame is valid, skipping current frame.';
       
   358 
       
   359 						} else {
       
   360 
       
   361 							// next frame is invalid too, abort processing
       
   362 							//unset($framedata);
       
   363 							$framedata = null;
       
   364 							$info['error'][] = 'Next ID3v2 frame is also invalid, aborting processing.';
       
   365 
       
   366 						}
       
   367 
       
   368 					} elseif ($frame_size == strlen($framedata)) {
       
   369 
       
   370 						// this is the last frame, just skip
       
   371 						$info['warning'][] = 'This was the last ID3v2 frame.';
       
   372 
       
   373 					} else {
       
   374 
       
   375 						// next frame is invalid too, abort processing
       
   376 						//unset($framedata);
       
   377 						$framedata = null;
       
   378 						$info['warning'][] = 'Invalid ID3v2 frame size, aborting.';
       
   379 
       
   380 					}
       
   381 					if (!$this->IsValidID3v2FrameName($frame_name, $id3v2_majorversion)) {
       
   382 
       
   383 						switch ($frame_name) {
       
   384 							case "\x00\x00".'MP':
       
   385 							case "\x00".'MP3':
       
   386 							case ' MP3':
       
   387 							case 'MP3e':
       
   388 							case "\x00".'MP':
       
   389 							case ' MP':
       
   390 							case 'MP3':
       
   391 								$info['warning'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: !IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))). [Note: this particular error has been known to happen with tags edited by "MP3ext (www.mutschler.de/mp3ext/)"]';
       
   392 								break;
       
   393 
       
   394 							default:
       
   395 								$info['warning'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: !IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))).';
       
   396 								break;
       
   397 						}
       
   398 
       
   399 					} elseif (!isset($framedata) || ($frame_size > strlen($framedata))) {
       
   400 
       
   401 						$info['error'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: $frame_size ('.$frame_size.') > strlen($framedata) ('.(isset($framedata) ? strlen($framedata) : 'null').')).';
       
   402 
       
   403 					} else {
       
   404 
       
   405 						$info['error'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag).';
       
   406 
       
   407 					}
       
   408 
       
   409 				}
       
   410 				$framedataoffset += ($frame_size + $this->ID3v2HeaderLength($id3v2_majorversion));
       
   411 
       
   412 			}
       
   413 
       
   414 		}
       
   415 
       
   416 
       
   417 	//    Footer
       
   418 
       
   419 	//    The footer is a copy of the header, but with a different identifier.
       
   420 	//        ID3v2 identifier           "3DI"
       
   421 	//        ID3v2 version              $04 00
       
   422 	//        ID3v2 flags                %abcd0000
       
   423 	//        ID3v2 size             4 * %0xxxxxxx
       
   424 
       
   425 		if (isset($thisfile_id3v2_flags['isfooter']) && $thisfile_id3v2_flags['isfooter']) {
       
   426 			$footer = fread($this->getid3->fp, 10);
       
   427 			if (substr($footer, 0, 3) == '3DI') {
       
   428 				$thisfile_id3v2['footer'] = true;
       
   429 				$thisfile_id3v2['majorversion_footer'] = ord($footer{3});
       
   430 				$thisfile_id3v2['minorversion_footer'] = ord($footer{4});
       
   431 			}
       
   432 			if ($thisfile_id3v2['majorversion_footer'] <= 4) {
       
   433 				$id3_flags = ord(substr($footer{5}));
       
   434 				$thisfile_id3v2_flags['unsynch_footer']  = (bool) ($id3_flags & 0x80);
       
   435 				$thisfile_id3v2_flags['extfoot_footer']  = (bool) ($id3_flags & 0x40);
       
   436 				$thisfile_id3v2_flags['experim_footer']  = (bool) ($id3_flags & 0x20);
       
   437 				$thisfile_id3v2_flags['isfooter_footer'] = (bool) ($id3_flags & 0x10);
       
   438 
       
   439 				$thisfile_id3v2['footerlength'] = getid3_lib::BigEndian2Int(substr($footer, 6, 4), 1);
       
   440 			}
       
   441 		} // end footer
       
   442 
       
   443 		if (isset($thisfile_id3v2['comments']['genre'])) {
       
   444 			foreach ($thisfile_id3v2['comments']['genre'] as $key => $value) {
       
   445 				unset($thisfile_id3v2['comments']['genre'][$key]);
       
   446 				$thisfile_id3v2['comments'] = getid3_lib::array_merge_noclobber($thisfile_id3v2['comments'], array('genre'=>$this->ParseID3v2GenreString($value)));
       
   447 			}
       
   448 		}
       
   449 
       
   450 		if (isset($thisfile_id3v2['comments']['track'])) {
       
   451 			foreach ($thisfile_id3v2['comments']['track'] as $key => $value) {
       
   452 				if (strstr($value, '/')) {
       
   453 					list($thisfile_id3v2['comments']['tracknum'][$key], $thisfile_id3v2['comments']['totaltracks'][$key]) = explode('/', $thisfile_id3v2['comments']['track'][$key]);
       
   454 				}
       
   455 			}
       
   456 		}
       
   457 
       
   458 		if (!isset($thisfile_id3v2['comments']['year']) && !empty($thisfile_id3v2['comments']['recording_time'][0]) && preg_match('#^([0-9]{4})#', trim($thisfile_id3v2['comments']['recording_time'][0]), $matches)) {
       
   459 			$thisfile_id3v2['comments']['year'] = array($matches[1]);
       
   460 		}
       
   461 
       
   462 
       
   463 		if (!empty($thisfile_id3v2['TXXX'])) {
       
   464 			// MediaMonkey does this, maybe others: write a blank RGAD frame, but put replay-gain adjustment values in TXXX frames
       
   465 			foreach ($thisfile_id3v2['TXXX'] as $txxx_array) {
       
   466 				switch ($txxx_array['description']) {
       
   467 					case 'replaygain_track_gain':
       
   468 						if (empty($info['replay_gain']['track']['adjustment']) && !empty($txxx_array['data'])) {
       
   469 							$info['replay_gain']['track']['adjustment'] = floatval(trim(str_replace('dB', '', $txxx_array['data'])));
       
   470 						}
       
   471 						break;
       
   472 					case 'replaygain_track_peak':
       
   473 						if (empty($info['replay_gain']['track']['peak']) && !empty($txxx_array['data'])) {
       
   474 							$info['replay_gain']['track']['peak'] = floatval($txxx_array['data']);
       
   475 						}
       
   476 						break;
       
   477 					case 'replaygain_album_gain':
       
   478 						if (empty($info['replay_gain']['album']['adjustment']) && !empty($txxx_array['data'])) {
       
   479 							$info['replay_gain']['album']['adjustment'] = floatval(trim(str_replace('dB', '', $txxx_array['data'])));
       
   480 						}
       
   481 						break;
       
   482 				}
       
   483 			}
       
   484 		}
       
   485 
       
   486 
       
   487 		// Set avdataoffset
       
   488 		$info['avdataoffset'] = $thisfile_id3v2['headerlength'];
       
   489 		if (isset($thisfile_id3v2['footer'])) {
       
   490 			$info['avdataoffset'] += 10;
       
   491 		}
       
   492 
       
   493 		return true;
       
   494 	}
       
   495 
       
   496 
       
   497 	public function ParseID3v2GenreString($genrestring) {
       
   498 		// Parse genres into arrays of genreName and genreID
       
   499 		// ID3v2.2.x, ID3v2.3.x: '(21)' or '(4)Eurodisco' or '(51)(39)' or '(55)((I think...)'
       
   500 		// ID3v2.4.x: '21' $00 'Eurodisco' $00
       
   501 		$clean_genres = array();
       
   502 		if (strpos($genrestring, "\x00") === false) {
       
   503 			$genrestring = preg_replace('#\(([0-9]{1,3})\)#', '$1'."\x00", $genrestring);
       
   504 		}
       
   505 		$genre_elements = explode("\x00", $genrestring);
       
   506 		foreach ($genre_elements as $element) {
       
   507 			$element = trim($element);
       
   508 			if ($element) {
       
   509 				if (preg_match('#^[0-9]{1,3}#', $element)) {
       
   510 					$clean_genres[] = getid3_id3v1::LookupGenreName($element);
       
   511 				} else {
       
   512 					$clean_genres[] = str_replace('((', '(', $element);
       
   513 				}
       
   514 			}
       
   515 		}
       
   516 		return $clean_genres;
       
   517 	}
       
   518 
       
   519 
       
   520 	public function ParseID3v2Frame(&$parsedFrame) {
       
   521 
       
   522 		// shortcuts
       
   523 		$info = &$this->getid3->info;
       
   524 		$id3v2_majorversion = $info['id3v2']['majorversion'];
       
   525 
       
   526 		$parsedFrame['framenamelong']  = $this->FrameNameLongLookup($parsedFrame['frame_name']);
       
   527 		if (empty($parsedFrame['framenamelong'])) {
       
   528 			unset($parsedFrame['framenamelong']);
       
   529 		}
       
   530 		$parsedFrame['framenameshort'] = $this->FrameNameShortLookup($parsedFrame['frame_name']);
       
   531 		if (empty($parsedFrame['framenameshort'])) {
       
   532 			unset($parsedFrame['framenameshort']);
       
   533 		}
       
   534 
       
   535 		if ($id3v2_majorversion >= 3) { // frame flags are not part of the ID3v2.2 standard
       
   536 			if ($id3v2_majorversion == 3) {
       
   537 				//    Frame Header Flags
       
   538 				//    %abc00000 %ijk00000
       
   539 				$parsedFrame['flags']['TagAlterPreservation']  = (bool) ($parsedFrame['frame_flags_raw'] & 0x8000); // a - Tag alter preservation
       
   540 				$parsedFrame['flags']['FileAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x4000); // b - File alter preservation
       
   541 				$parsedFrame['flags']['ReadOnly']              = (bool) ($parsedFrame['frame_flags_raw'] & 0x2000); // c - Read only
       
   542 				$parsedFrame['flags']['compression']           = (bool) ($parsedFrame['frame_flags_raw'] & 0x0080); // i - Compression
       
   543 				$parsedFrame['flags']['Encryption']            = (bool) ($parsedFrame['frame_flags_raw'] & 0x0040); // j - Encryption
       
   544 				$parsedFrame['flags']['GroupingIdentity']      = (bool) ($parsedFrame['frame_flags_raw'] & 0x0020); // k - Grouping identity
       
   545 
       
   546 			} elseif ($id3v2_majorversion == 4) {
       
   547 				//    Frame Header Flags
       
   548 				//    %0abc0000 %0h00kmnp
       
   549 				$parsedFrame['flags']['TagAlterPreservation']  = (bool) ($parsedFrame['frame_flags_raw'] & 0x4000); // a - Tag alter preservation
       
   550 				$parsedFrame['flags']['FileAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x2000); // b - File alter preservation
       
   551 				$parsedFrame['flags']['ReadOnly']              = (bool) ($parsedFrame['frame_flags_raw'] & 0x1000); // c - Read only
       
   552 				$parsedFrame['flags']['GroupingIdentity']      = (bool) ($parsedFrame['frame_flags_raw'] & 0x0040); // h - Grouping identity
       
   553 				$parsedFrame['flags']['compression']           = (bool) ($parsedFrame['frame_flags_raw'] & 0x0008); // k - Compression
       
   554 				$parsedFrame['flags']['Encryption']            = (bool) ($parsedFrame['frame_flags_raw'] & 0x0004); // m - Encryption
       
   555 				$parsedFrame['flags']['Unsynchronisation']     = (bool) ($parsedFrame['frame_flags_raw'] & 0x0002); // n - Unsynchronisation
       
   556 				$parsedFrame['flags']['DataLengthIndicator']   = (bool) ($parsedFrame['frame_flags_raw'] & 0x0001); // p - Data length indicator
       
   557 
       
   558 				// Frame-level de-unsynchronisation - ID3v2.4
       
   559 				if ($parsedFrame['flags']['Unsynchronisation']) {
       
   560 					$parsedFrame['data'] = $this->DeUnsynchronise($parsedFrame['data']);
       
   561 				}
       
   562 
       
   563 				if ($parsedFrame['flags']['DataLengthIndicator']) {
       
   564 					$parsedFrame['data_length_indicator'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 0, 4), 1);
       
   565 					$parsedFrame['data']                  =                           substr($parsedFrame['data'], 4);
       
   566 				}
       
   567 			}
       
   568 
       
   569 			//    Frame-level de-compression
       
   570 			if ($parsedFrame['flags']['compression']) {
       
   571 				$parsedFrame['decompressed_size'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 0, 4));
       
   572 				if (!function_exists('gzuncompress')) {
       
   573 					$info['warning'][] = 'gzuncompress() support required to decompress ID3v2 frame "'.$parsedFrame['frame_name'].'"';
       
   574 				} else {
       
   575 					if ($decompresseddata = @gzuncompress(substr($parsedFrame['data'], 4))) {
       
   576 					//if ($decompresseddata = @gzuncompress($parsedFrame['data'])) {
       
   577 						$parsedFrame['data'] = $decompresseddata;
       
   578 						unset($decompresseddata);
       
   579 					} else {
       
   580 						$info['warning'][] = 'gzuncompress() failed on compressed contents of ID3v2 frame "'.$parsedFrame['frame_name'].'"';
       
   581 					}
       
   582 				}
       
   583 			}
       
   584 		}
       
   585 
       
   586 		if (!empty($parsedFrame['flags']['DataLengthIndicator'])) {
       
   587 			if ($parsedFrame['data_length_indicator'] != strlen($parsedFrame['data'])) {
       
   588 				$info['warning'][] = 'ID3v2 frame "'.$parsedFrame['frame_name'].'" should be '.$parsedFrame['data_length_indicator'].' bytes long according to DataLengthIndicator, but found '.strlen($parsedFrame['data']).' bytes of data';
       
   589 			}
       
   590 		}
       
   591 
       
   592 		if (isset($parsedFrame['datalength']) && ($parsedFrame['datalength'] == 0)) {
       
   593 
       
   594 			$warning = 'Frame "'.$parsedFrame['frame_name'].'" at offset '.$parsedFrame['dataoffset'].' has no data portion';
       
   595 			switch ($parsedFrame['frame_name']) {
       
   596 				case 'WCOM':
       
   597 					$warning .= ' (this is known to happen with files tagged by RioPort)';
       
   598 					break;
       
   599 
       
   600 				default:
       
   601 					break;
       
   602 			}
       
   603 			$info['warning'][] = $warning;
       
   604 
       
   605 		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'UFID')) || // 4.1   UFID Unique file identifier
       
   606 			(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'UFI'))) {  // 4.1   UFI  Unique file identifier
       
   607 			//   There may be more than one 'UFID' frame in a tag,
       
   608 			//   but only one with the same 'Owner identifier'.
       
   609 			// <Header for 'Unique file identifier', ID: 'UFID'>
       
   610 			// Owner identifier        <text string> $00
       
   611 			// Identifier              <up to 64 bytes binary data>
       
   612 			$exploded = explode("\x00", $parsedFrame['data'], 2);
       
   613 			$parsedFrame['ownerid'] = (isset($exploded[0]) ? $exploded[0] : '');
       
   614 			$parsedFrame['data']    = (isset($exploded[1]) ? $exploded[1] : '');
       
   615 
       
   616 		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'TXXX')) || // 4.2.2 TXXX User defined text information frame
       
   617 				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'TXX'))) {    // 4.2.2 TXX  User defined text information frame
       
   618 			//   There may be more than one 'TXXX' frame in each tag,
       
   619 			//   but only one with the same description.
       
   620 			// <Header for 'User defined text information frame', ID: 'TXXX'>
       
   621 			// Text encoding     $xx
       
   622 			// Description       <text string according to encoding> $00 (00)
       
   623 			// Value             <text string according to encoding>
       
   624 
       
   625 			$frame_offset = 0;
       
   626 			$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
   627 
       
   628 			if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
       
   629 				$info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
       
   630 			}
       
   631 			$frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
       
   632 			if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
       
   633 				$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
       
   634 			}
       
   635 			$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
       
   636 			if (ord($frame_description) === 0) {
       
   637 				$frame_description = '';
       
   638 			}
       
   639 			$parsedFrame['encodingid']  = $frame_textencoding;
       
   640 			$parsedFrame['encoding']    = $this->TextEncodingNameLookup($frame_textencoding);
       
   641 
       
   642 			$parsedFrame['description'] = $frame_description;
       
   643 			$parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
       
   644 			if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
       
   645 				$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']));
       
   646 			}
       
   647 			//unset($parsedFrame['data']); do not unset, may be needed elsewhere, e.g. for replaygain
       
   648 
       
   649 
       
   650 		} elseif ($parsedFrame['frame_name']{0} == 'T') { // 4.2. T??[?] Text information frame
       
   651 			//   There may only be one text information frame of its kind in an tag.
       
   652 			// <Header for 'Text information frame', ID: 'T000' - 'TZZZ',
       
   653 			// excluding 'TXXX' described in 4.2.6.>
       
   654 			// Text encoding                $xx
       
   655 			// Information                  <text string(s) according to encoding>
       
   656 
       
   657 			$frame_offset = 0;
       
   658 			$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
   659 			if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
       
   660 				$info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
       
   661 			}
       
   662 
       
   663 			$parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
       
   664 
       
   665 			$parsedFrame['encodingid'] = $frame_textencoding;
       
   666 			$parsedFrame['encoding']   = $this->TextEncodingNameLookup($frame_textencoding);
       
   667 
       
   668 			if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
       
   669 				// ID3v2.3 specs say that TPE1 (and others) can contain multiple artist values separated with /
       
   670 				// This of course breaks when an artist name contains slash character, e.g. "AC/DC"
       
   671 				// MP3tag (maybe others) implement alternative system where multiple artists are null-separated, which makes more sense
       
   672 				// getID3 will split null-separated artists into multiple artists and leave slash-separated ones to the user
       
   673 				switch ($parsedFrame['encoding']) {
       
   674 					case 'UTF-16':
       
   675 					case 'UTF-16BE':
       
   676 					case 'UTF-16LE':
       
   677 						$wordsize = 2;
       
   678 						break;
       
   679 					case 'ISO-8859-1':
       
   680 					case 'UTF-8':
       
   681 					default:
       
   682 						$wordsize = 1;
       
   683 						break;
       
   684 				}
       
   685 				$Txxx_elements = array();
       
   686 				$Txxx_elements_start_offset = 0;
       
   687 				for ($i = 0; $i < strlen($parsedFrame['data']); $i += $wordsize) {
       
   688 					if (substr($parsedFrame['data'], $i, $wordsize) == str_repeat("\x00", $wordsize)) {
       
   689 						$Txxx_elements[] = substr($parsedFrame['data'], $Txxx_elements_start_offset, $i - $Txxx_elements_start_offset);
       
   690 						$Txxx_elements_start_offset = $i + $wordsize;
       
   691 					}
       
   692 				}
       
   693 				$Txxx_elements[] = substr($parsedFrame['data'], $Txxx_elements_start_offset, $i - $Txxx_elements_start_offset);
       
   694 				foreach ($Txxx_elements as $Txxx_element) {
       
   695 					$string = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $Txxx_element);
       
   696 					if (!empty($string)) {
       
   697 						$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $string;
       
   698 					}
       
   699 				}
       
   700 				unset($string, $wordsize, $i, $Txxx_elements, $Txxx_element, $Txxx_elements_start_offset);
       
   701 			}
       
   702 
       
   703 		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'WXXX')) || // 4.3.2 WXXX User defined URL link frame
       
   704 				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'WXX'))) {    // 4.3.2 WXX  User defined URL link frame
       
   705 			//   There may be more than one 'WXXX' frame in each tag,
       
   706 			//   but only one with the same description
       
   707 			// <Header for 'User defined URL link frame', ID: 'WXXX'>
       
   708 			// Text encoding     $xx
       
   709 			// Description       <text string according to encoding> $00 (00)
       
   710 			// URL               <text string>
       
   711 
       
   712 			$frame_offset = 0;
       
   713 			$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
   714 			if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
       
   715 				$info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
       
   716 			}
       
   717 			$frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
       
   718 			if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
       
   719 				$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
       
   720 			}
       
   721 			$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
       
   722 
       
   723 			if (ord($frame_description) === 0) {
       
   724 				$frame_description = '';
       
   725 			}
       
   726 			$parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
       
   727 
       
   728 			$frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding));
       
   729 			if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
       
   730 				$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
       
   731 			}
       
   732 			if ($frame_terminatorpos) {
       
   733 				// there are null bytes after the data - this is not according to spec
       
   734 				// only use data up to first null byte
       
   735 				$frame_urldata = (string) substr($parsedFrame['data'], 0, $frame_terminatorpos);
       
   736 			} else {
       
   737 				// no null bytes following data, just use all data
       
   738 				$frame_urldata = (string) $parsedFrame['data'];
       
   739 			}
       
   740 
       
   741 			$parsedFrame['encodingid']  = $frame_textencoding;
       
   742 			$parsedFrame['encoding']    = $this->TextEncodingNameLookup($frame_textencoding);
       
   743 
       
   744 			$parsedFrame['url']         = $frame_urldata;
       
   745 			$parsedFrame['description'] = $frame_description;
       
   746 			if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) {
       
   747 				$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['url']);
       
   748 			}
       
   749 			unset($parsedFrame['data']);
       
   750 
       
   751 
       
   752 		} elseif ($parsedFrame['frame_name']{0} == 'W') { // 4.3. W??? URL link frames
       
   753 			//   There may only be one URL link frame of its kind in a tag,
       
   754 			//   except when stated otherwise in the frame description
       
   755 			// <Header for 'URL link frame', ID: 'W000' - 'WZZZ', excluding 'WXXX'
       
   756 			// described in 4.3.2.>
       
   757 			// URL              <text string>
       
   758 
       
   759 			$parsedFrame['url'] = trim($parsedFrame['data']);
       
   760 			if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) {
       
   761 				$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['url'];
       
   762 			}
       
   763 			unset($parsedFrame['data']);
       
   764 
       
   765 
       
   766 		} elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'IPLS')) || // 4.4  IPLS Involved people list (ID3v2.3 only)
       
   767 				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'IPL'))) {     // 4.4  IPL  Involved people list (ID3v2.2 only)
       
   768 			// http://id3.org/id3v2.3.0#sec4.4
       
   769 			//   There may only be one 'IPL' frame in each tag
       
   770 			// <Header for 'User defined URL link frame', ID: 'IPL'>
       
   771 			// Text encoding     $xx
       
   772 			// People list strings    <textstrings>
       
   773 
       
   774 			$frame_offset = 0;
       
   775 			$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
   776 			if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
       
   777 				$info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
       
   778 			}
       
   779 			$parsedFrame['encodingid'] = $frame_textencoding;
       
   780 			$parsedFrame['encoding']   = $this->TextEncodingNameLookup($parsedFrame['encodingid']);
       
   781 			$parsedFrame['data_raw']   = (string) substr($parsedFrame['data'], $frame_offset);
       
   782 
       
   783 			// http://www.getid3.org/phpBB3/viewtopic.php?t=1369
       
   784 			// "this tag typically contains null terminated strings, which are associated in pairs"
       
   785 			// "there are users that use the tag incorrectly"
       
   786 			$IPLS_parts = array();
       
   787 			if (strpos($parsedFrame['data_raw'], "\x00") !== false) {
       
   788 				$IPLS_parts_unsorted = array();
       
   789 				if (((strlen($parsedFrame['data_raw']) % 2) == 0) && ((substr($parsedFrame['data_raw'], 0, 2) == "\xFF\xFE") || (substr($parsedFrame['data_raw'], 0, 2) == "\xFE\xFF"))) {
       
   790 					// UTF-16, be careful looking for null bytes since most 2-byte characters may contain one; you need to find twin null bytes, and on even padding
       
   791 					$thisILPS  = '';
       
   792 					for ($i = 0; $i < strlen($parsedFrame['data_raw']); $i += 2) {
       
   793 						$twobytes = substr($parsedFrame['data_raw'], $i, 2);
       
   794 						if ($twobytes === "\x00\x00") {
       
   795 							$IPLS_parts_unsorted[] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $thisILPS);
       
   796 							$thisILPS  = '';
       
   797 						} else {
       
   798 							$thisILPS .= $twobytes;
       
   799 						}
       
   800 					}
       
   801 					if (strlen($thisILPS) > 2) { // 2-byte BOM
       
   802 						$IPLS_parts_unsorted[] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $thisILPS);
       
   803 					}
       
   804 				} else {
       
   805 					// ISO-8859-1 or UTF-8 or other single-byte-null character set
       
   806 					$IPLS_parts_unsorted = explode("\x00", $parsedFrame['data_raw']);
       
   807 				}
       
   808 				if (count($IPLS_parts_unsorted) == 1) {
       
   809 					// just a list of names, e.g. "Dino Baptiste, Jimmy Copley, John Gordon, Bernie Marsden, Sharon Watson"
       
   810 					foreach ($IPLS_parts_unsorted as $key => $value) {
       
   811 						$IPLS_parts_sorted = preg_split('#[;,\\r\\n\\t]#', $value);
       
   812 						$position = '';
       
   813 						foreach ($IPLS_parts_sorted as $person) {
       
   814 							$IPLS_parts[] = array('position'=>$position, 'person'=>$person);
       
   815 						}
       
   816 					}
       
   817 				} elseif ((count($IPLS_parts_unsorted) % 2) == 0) {
       
   818 					$position = '';
       
   819 					$person   = '';
       
   820 					foreach ($IPLS_parts_unsorted as $key => $value) {
       
   821 						if (($key % 2) == 0) {
       
   822 							$position = $value;
       
   823 						} else {
       
   824 							$person   = $value;
       
   825 							$IPLS_parts[] = array('position'=>$position, 'person'=>$person);
       
   826 							$position = '';
       
   827 							$person   = '';
       
   828 						}
       
   829 					}
       
   830 				} else {
       
   831 					foreach ($IPLS_parts_unsorted as $key => $value) {
       
   832 						$IPLS_parts[] = array($value);
       
   833 					}
       
   834 				}
       
   835 
       
   836 			} else {
       
   837 				$IPLS_parts = preg_split('#[;,\\r\\n\\t]#', $parsedFrame['data_raw']);
       
   838 			}
       
   839 			$parsedFrame['data'] = $IPLS_parts;
       
   840 
       
   841 			if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
       
   842 				$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['data'];
       
   843 			}
       
   844 
       
   845 
       
   846 		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'MCDI')) || // 4.4   MCDI Music CD identifier
       
   847 				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'MCI'))) {     // 4.5   MCI  Music CD identifier
       
   848 			//   There may only be one 'MCDI' frame in each tag
       
   849 			// <Header for 'Music CD identifier', ID: 'MCDI'>
       
   850 			// CD TOC                <binary data>
       
   851 
       
   852 			if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
       
   853 				$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['data'];
       
   854 			}
       
   855 
       
   856 
       
   857 		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'ETCO')) || // 4.5   ETCO Event timing codes
       
   858 				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'ETC'))) {     // 4.6   ETC  Event timing codes
       
   859 			//   There may only be one 'ETCO' frame in each tag
       
   860 			// <Header for 'Event timing codes', ID: 'ETCO'>
       
   861 			// Time stamp format    $xx
       
   862 			//   Where time stamp format is:
       
   863 			// $01  (32-bit value) MPEG frames from beginning of file
       
   864 			// $02  (32-bit value) milliseconds from beginning of file
       
   865 			//   Followed by a list of key events in the following format:
       
   866 			// Type of event   $xx
       
   867 			// Time stamp      $xx (xx ...)
       
   868 			//   The 'Time stamp' is set to zero if directly at the beginning of the sound
       
   869 			//   or after the previous event. All events MUST be sorted in chronological order.
       
   870 
       
   871 			$frame_offset = 0;
       
   872 			$parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
   873 
       
   874 			while ($frame_offset < strlen($parsedFrame['data'])) {
       
   875 				$parsedFrame['typeid']    = substr($parsedFrame['data'], $frame_offset++, 1);
       
   876 				$parsedFrame['type']      = $this->ETCOEventLookup($parsedFrame['typeid']);
       
   877 				$parsedFrame['timestamp'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
       
   878 				$frame_offset += 4;
       
   879 			}
       
   880 			unset($parsedFrame['data']);
       
   881 
       
   882 
       
   883 		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'MLLT')) || // 4.6   MLLT MPEG location lookup table
       
   884 				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'MLL'))) {     // 4.7   MLL MPEG location lookup table
       
   885 			//   There may only be one 'MLLT' frame in each tag
       
   886 			// <Header for 'Location lookup table', ID: 'MLLT'>
       
   887 			// MPEG frames between reference  $xx xx
       
   888 			// Bytes between reference        $xx xx xx
       
   889 			// Milliseconds between reference $xx xx xx
       
   890 			// Bits for bytes deviation       $xx
       
   891 			// Bits for milliseconds dev.     $xx
       
   892 			//   Then for every reference the following data is included;
       
   893 			// Deviation in bytes         %xxx....
       
   894 			// Deviation in milliseconds  %xxx....
       
   895 
       
   896 			$frame_offset = 0;
       
   897 			$parsedFrame['framesbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 0, 2));
       
   898 			$parsedFrame['bytesbetweenreferences']  = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 2, 3));
       
   899 			$parsedFrame['msbetweenreferences']     = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 5, 3));
       
   900 			$parsedFrame['bitsforbytesdeviation']   = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 8, 1));
       
   901 			$parsedFrame['bitsformsdeviation']      = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 9, 1));
       
   902 			$parsedFrame['data'] = substr($parsedFrame['data'], 10);
       
   903 			while ($frame_offset < strlen($parsedFrame['data'])) {
       
   904 				$deviationbitstream .= getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1));
       
   905 			}
       
   906 			$reference_counter = 0;
       
   907 			while (strlen($deviationbitstream) > 0) {
       
   908 				$parsedFrame[$reference_counter]['bytedeviation'] = bindec(substr($deviationbitstream, 0, $parsedFrame['bitsforbytesdeviation']));
       
   909 				$parsedFrame[$reference_counter]['msdeviation']   = bindec(substr($deviationbitstream, $parsedFrame['bitsforbytesdeviation'], $parsedFrame['bitsformsdeviation']));
       
   910 				$deviationbitstream = substr($deviationbitstream, $parsedFrame['bitsforbytesdeviation'] + $parsedFrame['bitsformsdeviation']);
       
   911 				$reference_counter++;
       
   912 			}
       
   913 			unset($parsedFrame['data']);
       
   914 
       
   915 
       
   916 		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'SYTC')) || // 4.7   SYTC Synchronised tempo codes
       
   917 				  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'STC'))) {  // 4.8   STC  Synchronised tempo codes
       
   918 			//   There may only be one 'SYTC' frame in each tag
       
   919 			// <Header for 'Synchronised tempo codes', ID: 'SYTC'>
       
   920 			// Time stamp format   $xx
       
   921 			// Tempo data          <binary data>
       
   922 			//   Where time stamp format is:
       
   923 			// $01  (32-bit value) MPEG frames from beginning of file
       
   924 			// $02  (32-bit value) milliseconds from beginning of file
       
   925 
       
   926 			$frame_offset = 0;
       
   927 			$parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
   928 			$timestamp_counter = 0;
       
   929 			while ($frame_offset < strlen($parsedFrame['data'])) {
       
   930 				$parsedFrame[$timestamp_counter]['tempo'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
   931 				if ($parsedFrame[$timestamp_counter]['tempo'] == 255) {
       
   932 					$parsedFrame[$timestamp_counter]['tempo'] += ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
   933 				}
       
   934 				$parsedFrame[$timestamp_counter]['timestamp'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
       
   935 				$frame_offset += 4;
       
   936 				$timestamp_counter++;
       
   937 			}
       
   938 			unset($parsedFrame['data']);
       
   939 
       
   940 
       
   941 		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'USLT')) || // 4.8   USLT Unsynchronised lyric/text transcription
       
   942 				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'ULT'))) {     // 4.9   ULT  Unsynchronised lyric/text transcription
       
   943 			//   There may be more than one 'Unsynchronised lyrics/text transcription' frame
       
   944 			//   in each tag, but only one with the same language and content descriptor.
       
   945 			// <Header for 'Unsynchronised lyrics/text transcription', ID: 'USLT'>
       
   946 			// Text encoding        $xx
       
   947 			// Language             $xx xx xx
       
   948 			// Content descriptor   <text string according to encoding> $00 (00)
       
   949 			// Lyrics/text          <full text string according to encoding>
       
   950 
       
   951 			$frame_offset = 0;
       
   952 			$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
   953 			if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
       
   954 				$info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
       
   955 			}
       
   956 			$frame_language = substr($parsedFrame['data'], $frame_offset, 3);
       
   957 			$frame_offset += 3;
       
   958 			$frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
       
   959 			if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
       
   960 				$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
       
   961 			}
       
   962 			$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
       
   963 			if (ord($frame_description) === 0) {
       
   964 				$frame_description = '';
       
   965 			}
       
   966 			$parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
       
   967 
       
   968 			$parsedFrame['encodingid']   = $frame_textencoding;
       
   969 			$parsedFrame['encoding']     = $this->TextEncodingNameLookup($frame_textencoding);
       
   970 
       
   971 			$parsedFrame['data']         = $parsedFrame['data'];
       
   972 			$parsedFrame['language']     = $frame_language;
       
   973 			$parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
       
   974 			$parsedFrame['description']  = $frame_description;
       
   975 			if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
       
   976 				$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
       
   977 			}
       
   978 			unset($parsedFrame['data']);
       
   979 
       
   980 
       
   981 		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'SYLT')) || // 4.9   SYLT Synchronised lyric/text
       
   982 				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'SLT'))) {     // 4.10  SLT  Synchronised lyric/text
       
   983 			//   There may be more than one 'SYLT' frame in each tag,
       
   984 			//   but only one with the same language and content descriptor.
       
   985 			// <Header for 'Synchronised lyrics/text', ID: 'SYLT'>
       
   986 			// Text encoding        $xx
       
   987 			// Language             $xx xx xx
       
   988 			// Time stamp format    $xx
       
   989 			//   $01  (32-bit value) MPEG frames from beginning of file
       
   990 			//   $02  (32-bit value) milliseconds from beginning of file
       
   991 			// Content type         $xx
       
   992 			// Content descriptor   <text string according to encoding> $00 (00)
       
   993 			//   Terminated text to be synced (typically a syllable)
       
   994 			//   Sync identifier (terminator to above string)   $00 (00)
       
   995 			//   Time stamp                                     $xx (xx ...)
       
   996 
       
   997 			$frame_offset = 0;
       
   998 			$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
   999 			if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
       
  1000 				$info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
       
  1001 			}
       
  1002 			$frame_language = substr($parsedFrame['data'], $frame_offset, 3);
       
  1003 			$frame_offset += 3;
       
  1004 			$parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
  1005 			$parsedFrame['contenttypeid']   = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
  1006 			$parsedFrame['contenttype']     = $this->SYTLContentTypeLookup($parsedFrame['contenttypeid']);
       
  1007 			$parsedFrame['encodingid']      = $frame_textencoding;
       
  1008 			$parsedFrame['encoding']        = $this->TextEncodingNameLookup($frame_textencoding);
       
  1009 
       
  1010 			$parsedFrame['language']        = $frame_language;
       
  1011 			$parsedFrame['languagename']    = $this->LanguageLookup($frame_language, false);
       
  1012 
       
  1013 			$timestampindex = 0;
       
  1014 			$frame_remainingdata = substr($parsedFrame['data'], $frame_offset);
       
  1015 			while (strlen($frame_remainingdata)) {
       
  1016 				$frame_offset = 0;
       
  1017 				$frame_terminatorpos = strpos($frame_remainingdata, $this->TextEncodingTerminatorLookup($frame_textencoding));
       
  1018 				if ($frame_terminatorpos === false) {
       
  1019 					$frame_remainingdata = '';
       
  1020 				} else {
       
  1021 					if (ord(substr($frame_remainingdata, $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
       
  1022 						$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
       
  1023 					}
       
  1024 					$parsedFrame['lyrics'][$timestampindex]['data'] = substr($frame_remainingdata, $frame_offset, $frame_terminatorpos - $frame_offset);
       
  1025 
       
  1026 					$frame_remainingdata = substr($frame_remainingdata, $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
       
  1027 					if (($timestampindex == 0) && (ord($frame_remainingdata{0}) != 0)) {
       
  1028 						// timestamp probably omitted for first data item
       
  1029 					} else {
       
  1030 						$parsedFrame['lyrics'][$timestampindex]['timestamp'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 0, 4));
       
  1031 						$frame_remainingdata = substr($frame_remainingdata, 4);
       
  1032 					}
       
  1033 					$timestampindex++;
       
  1034 				}
       
  1035 			}
       
  1036 			unset($parsedFrame['data']);
       
  1037 
       
  1038 
       
  1039 		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'COMM')) || // 4.10  COMM Comments
       
  1040 				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'COM'))) {     // 4.11  COM  Comments
       
  1041 			//   There may be more than one comment frame in each tag,
       
  1042 			//   but only one with the same language and content descriptor.
       
  1043 			// <Header for 'Comment', ID: 'COMM'>
       
  1044 			// Text encoding          $xx
       
  1045 			// Language               $xx xx xx
       
  1046 			// Short content descrip. <text string according to encoding> $00 (00)
       
  1047 			// The actual text        <full text string according to encoding>
       
  1048 
       
  1049 			if (strlen($parsedFrame['data']) < 5) {
       
  1050 
       
  1051 				$info['warning'][] = 'Invalid data (too short) for "'.$parsedFrame['frame_name'].'" frame at offset '.$parsedFrame['dataoffset'];
       
  1052 
       
  1053 			} else {
       
  1054 
       
  1055 				$frame_offset = 0;
       
  1056 				$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
  1057 				if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
       
  1058 					$info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
       
  1059 				}
       
  1060 				$frame_language = substr($parsedFrame['data'], $frame_offset, 3);
       
  1061 				$frame_offset += 3;
       
  1062 				$frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
       
  1063 				if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
       
  1064 					$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
       
  1065 				}
       
  1066 				$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
       
  1067 				if (ord($frame_description) === 0) {
       
  1068 					$frame_description = '';
       
  1069 				}
       
  1070 				$frame_text = (string) substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
       
  1071 
       
  1072 				$parsedFrame['encodingid']   = $frame_textencoding;
       
  1073 				$parsedFrame['encoding']     = $this->TextEncodingNameLookup($frame_textencoding);
       
  1074 
       
  1075 				$parsedFrame['language']     = $frame_language;
       
  1076 				$parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
       
  1077 				$parsedFrame['description']  = $frame_description;
       
  1078 				$parsedFrame['data']         = $frame_text;
       
  1079 				if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
       
  1080 					$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
       
  1081 				}
       
  1082 
       
  1083 			}
       
  1084 
       
  1085 		} elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'RVA2')) { // 4.11  RVA2 Relative volume adjustment (2) (ID3v2.4+ only)
       
  1086 			//   There may be more than one 'RVA2' frame in each tag,
       
  1087 			//   but only one with the same identification string
       
  1088 			// <Header for 'Relative volume adjustment (2)', ID: 'RVA2'>
       
  1089 			// Identification          <text string> $00
       
  1090 			//   The 'identification' string is used to identify the situation and/or
       
  1091 			//   device where this adjustment should apply. The following is then
       
  1092 			//   repeated for every channel:
       
  1093 			// Type of channel         $xx
       
  1094 			// Volume adjustment       $xx xx
       
  1095 			// Bits representing peak  $xx
       
  1096 			// Peak volume             $xx (xx ...)
       
  1097 
       
  1098 			$frame_terminatorpos = strpos($parsedFrame['data'], "\x00");
       
  1099 			$frame_idstring = substr($parsedFrame['data'], 0, $frame_terminatorpos);
       
  1100 			if (ord($frame_idstring) === 0) {
       
  1101 				$frame_idstring = '';
       
  1102 			}
       
  1103 			$frame_remainingdata = substr($parsedFrame['data'], $frame_terminatorpos + strlen("\x00"));
       
  1104 			$parsedFrame['description'] = $frame_idstring;
       
  1105 			$RVA2channelcounter = 0;
       
  1106 			while (strlen($frame_remainingdata) >= 5) {
       
  1107 				$frame_offset = 0;
       
  1108 				$frame_channeltypeid = ord(substr($frame_remainingdata, $frame_offset++, 1));
       
  1109 				$parsedFrame[$RVA2channelcounter]['channeltypeid']  = $frame_channeltypeid;
       
  1110 				$parsedFrame[$RVA2channelcounter]['channeltype']    = $this->RVA2ChannelTypeLookup($frame_channeltypeid);
       
  1111 				$parsedFrame[$RVA2channelcounter]['volumeadjust']   = getid3_lib::BigEndian2Int(substr($frame_remainingdata, $frame_offset, 2), false, true); // 16-bit signed
       
  1112 				$frame_offset += 2;
       
  1113 				$parsedFrame[$RVA2channelcounter]['bitspeakvolume'] = ord(substr($frame_remainingdata, $frame_offset++, 1));
       
  1114 				if (($parsedFrame[$RVA2channelcounter]['bitspeakvolume'] < 1) || ($parsedFrame[$RVA2channelcounter]['bitspeakvolume'] > 4)) {
       
  1115 					$info['warning'][] = 'ID3v2::RVA2 frame['.$RVA2channelcounter.'] contains invalid '.$parsedFrame[$RVA2channelcounter]['bitspeakvolume'].'-byte bits-representing-peak value';
       
  1116 					break;
       
  1117 				}
       
  1118 				$frame_bytespeakvolume = ceil($parsedFrame[$RVA2channelcounter]['bitspeakvolume'] / 8);
       
  1119 				$parsedFrame[$RVA2channelcounter]['peakvolume']     = getid3_lib::BigEndian2Int(substr($frame_remainingdata, $frame_offset, $frame_bytespeakvolume));
       
  1120 				$frame_remainingdata = substr($frame_remainingdata, $frame_offset + $frame_bytespeakvolume);
       
  1121 				$RVA2channelcounter++;
       
  1122 			}
       
  1123 			unset($parsedFrame['data']);
       
  1124 
       
  1125 
       
  1126 		} elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'RVAD')) || // 4.12  RVAD Relative volume adjustment (ID3v2.3 only)
       
  1127 				  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'RVA'))) {  // 4.12  RVA  Relative volume adjustment (ID3v2.2 only)
       
  1128 			//   There may only be one 'RVA' frame in each tag
       
  1129 			// <Header for 'Relative volume adjustment', ID: 'RVA'>
       
  1130 			// ID3v2.2 => Increment/decrement     %000000ba
       
  1131 			// ID3v2.3 => Increment/decrement     %00fedcba
       
  1132 			// Bits used for volume descr.        $xx
       
  1133 			// Relative volume change, right      $xx xx (xx ...) // a
       
  1134 			// Relative volume change, left       $xx xx (xx ...) // b
       
  1135 			// Peak volume right                  $xx xx (xx ...)
       
  1136 			// Peak volume left                   $xx xx (xx ...)
       
  1137 			//   ID3v2.3 only, optional (not present in ID3v2.2):
       
  1138 			// Relative volume change, right back $xx xx (xx ...) // c
       
  1139 			// Relative volume change, left back  $xx xx (xx ...) // d
       
  1140 			// Peak volume right back             $xx xx (xx ...)
       
  1141 			// Peak volume left back              $xx xx (xx ...)
       
  1142 			//   ID3v2.3 only, optional (not present in ID3v2.2):
       
  1143 			// Relative volume change, center     $xx xx (xx ...) // e
       
  1144 			// Peak volume center                 $xx xx (xx ...)
       
  1145 			//   ID3v2.3 only, optional (not present in ID3v2.2):
       
  1146 			// Relative volume change, bass       $xx xx (xx ...) // f
       
  1147 			// Peak volume bass                   $xx xx (xx ...)
       
  1148 
       
  1149 			$frame_offset = 0;
       
  1150 			$frame_incrdecrflags = getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1));
       
  1151 			$parsedFrame['incdec']['right'] = (bool) substr($frame_incrdecrflags, 6, 1);
       
  1152 			$parsedFrame['incdec']['left']  = (bool) substr($frame_incrdecrflags, 7, 1);
       
  1153 			$parsedFrame['bitsvolume'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
  1154 			$frame_bytesvolume = ceil($parsedFrame['bitsvolume'] / 8);
       
  1155 			$parsedFrame['volumechange']['right'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
       
  1156 			if ($parsedFrame['incdec']['right'] === false) {
       
  1157 				$parsedFrame['volumechange']['right'] *= -1;
       
  1158 			}
       
  1159 			$frame_offset += $frame_bytesvolume;
       
  1160 			$parsedFrame['volumechange']['left'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
       
  1161 			if ($parsedFrame['incdec']['left'] === false) {
       
  1162 				$parsedFrame['volumechange']['left'] *= -1;
       
  1163 			}
       
  1164 			$frame_offset += $frame_bytesvolume;
       
  1165 			$parsedFrame['peakvolume']['right'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
       
  1166 			$frame_offset += $frame_bytesvolume;
       
  1167 			$parsedFrame['peakvolume']['left']  = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
       
  1168 			$frame_offset += $frame_bytesvolume;
       
  1169 			if ($id3v2_majorversion == 3) {
       
  1170 				$parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset);
       
  1171 				if (strlen($parsedFrame['data']) > 0) {
       
  1172 					$parsedFrame['incdec']['rightrear'] = (bool) substr($frame_incrdecrflags, 4, 1);
       
  1173 					$parsedFrame['incdec']['leftrear']  = (bool) substr($frame_incrdecrflags, 5, 1);
       
  1174 					$parsedFrame['volumechange']['rightrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
       
  1175 					if ($parsedFrame['incdec']['rightrear'] === false) {
       
  1176 						$parsedFrame['volumechange']['rightrear'] *= -1;
       
  1177 					}
       
  1178 					$frame_offset += $frame_bytesvolume;
       
  1179 					$parsedFrame['volumechange']['leftrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
       
  1180 					if ($parsedFrame['incdec']['leftrear'] === false) {
       
  1181 						$parsedFrame['volumechange']['leftrear'] *= -1;
       
  1182 					}
       
  1183 					$frame_offset += $frame_bytesvolume;
       
  1184 					$parsedFrame['peakvolume']['rightrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
       
  1185 					$frame_offset += $frame_bytesvolume;
       
  1186 					$parsedFrame['peakvolume']['leftrear']  = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
       
  1187 					$frame_offset += $frame_bytesvolume;
       
  1188 				}
       
  1189 				$parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset);
       
  1190 				if (strlen($parsedFrame['data']) > 0) {
       
  1191 					$parsedFrame['incdec']['center'] = (bool) substr($frame_incrdecrflags, 3, 1);
       
  1192 					$parsedFrame['volumechange']['center'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
       
  1193 					if ($parsedFrame['incdec']['center'] === false) {
       
  1194 						$parsedFrame['volumechange']['center'] *= -1;
       
  1195 					}
       
  1196 					$frame_offset += $frame_bytesvolume;
       
  1197 					$parsedFrame['peakvolume']['center'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
       
  1198 					$frame_offset += $frame_bytesvolume;
       
  1199 				}
       
  1200 				$parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset);
       
  1201 				if (strlen($parsedFrame['data']) > 0) {
       
  1202 					$parsedFrame['incdec']['bass'] = (bool) substr($frame_incrdecrflags, 2, 1);
       
  1203 					$parsedFrame['volumechange']['bass'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
       
  1204 					if ($parsedFrame['incdec']['bass'] === false) {
       
  1205 						$parsedFrame['volumechange']['bass'] *= -1;
       
  1206 					}
       
  1207 					$frame_offset += $frame_bytesvolume;
       
  1208 					$parsedFrame['peakvolume']['bass'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
       
  1209 					$frame_offset += $frame_bytesvolume;
       
  1210 				}
       
  1211 			}
       
  1212 			unset($parsedFrame['data']);
       
  1213 
       
  1214 
       
  1215 		} elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'EQU2')) { // 4.12  EQU2 Equalisation (2) (ID3v2.4+ only)
       
  1216 			//   There may be more than one 'EQU2' frame in each tag,
       
  1217 			//   but only one with the same identification string
       
  1218 			// <Header of 'Equalisation (2)', ID: 'EQU2'>
       
  1219 			// Interpolation method  $xx
       
  1220 			//   $00  Band
       
  1221 			//   $01  Linear
       
  1222 			// Identification        <text string> $00
       
  1223 			//   The following is then repeated for every adjustment point
       
  1224 			// Frequency          $xx xx
       
  1225 			// Volume adjustment  $xx xx
       
  1226 
       
  1227 			$frame_offset = 0;
       
  1228 			$frame_interpolationmethod = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
  1229 			$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
       
  1230 			$frame_idstring = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
       
  1231 			if (ord($frame_idstring) === 0) {
       
  1232 				$frame_idstring = '';
       
  1233 			}
       
  1234 			$parsedFrame['description'] = $frame_idstring;
       
  1235 			$frame_remainingdata = substr($parsedFrame['data'], $frame_terminatorpos + strlen("\x00"));
       
  1236 			while (strlen($frame_remainingdata)) {
       
  1237 				$frame_frequency = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 0, 2)) / 2;
       
  1238 				$parsedFrame['data'][$frame_frequency] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 2, 2), false, true);
       
  1239 				$frame_remainingdata = substr($frame_remainingdata, 4);
       
  1240 			}
       
  1241 			$parsedFrame['interpolationmethod'] = $frame_interpolationmethod;
       
  1242 			unset($parsedFrame['data']);
       
  1243 
       
  1244 
       
  1245 		} elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'EQUA')) || // 4.12  EQUA Equalisation (ID3v2.3 only)
       
  1246 				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'EQU'))) {     // 4.13  EQU  Equalisation (ID3v2.2 only)
       
  1247 			//   There may only be one 'EQUA' frame in each tag
       
  1248 			// <Header for 'Relative volume adjustment', ID: 'EQU'>
       
  1249 			// Adjustment bits    $xx
       
  1250 			//   This is followed by 2 bytes + ('adjustment bits' rounded up to the
       
  1251 			//   nearest byte) for every equalisation band in the following format,
       
  1252 			//   giving a frequency range of 0 - 32767Hz:
       
  1253 			// Increment/decrement   %x (MSB of the Frequency)
       
  1254 			// Frequency             (lower 15 bits)
       
  1255 			// Adjustment            $xx (xx ...)
       
  1256 
       
  1257 			$frame_offset = 0;
       
  1258 			$parsedFrame['adjustmentbits'] = substr($parsedFrame['data'], $frame_offset++, 1);
       
  1259 			$frame_adjustmentbytes = ceil($parsedFrame['adjustmentbits'] / 8);
       
  1260 
       
  1261 			$frame_remainingdata = (string) substr($parsedFrame['data'], $frame_offset);
       
  1262 			while (strlen($frame_remainingdata) > 0) {
       
  1263 				$frame_frequencystr = getid3_lib::BigEndian2Bin(substr($frame_remainingdata, 0, 2));
       
  1264 				$frame_incdec    = (bool) substr($frame_frequencystr, 0, 1);
       
  1265 				$frame_frequency = bindec(substr($frame_frequencystr, 1, 15));
       
  1266 				$parsedFrame[$frame_frequency]['incdec'] = $frame_incdec;
       
  1267 				$parsedFrame[$frame_frequency]['adjustment'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 2, $frame_adjustmentbytes));
       
  1268 				if ($parsedFrame[$frame_frequency]['incdec'] === false) {
       
  1269 					$parsedFrame[$frame_frequency]['adjustment'] *= -1;
       
  1270 				}
       
  1271 				$frame_remainingdata = substr($frame_remainingdata, 2 + $frame_adjustmentbytes);
       
  1272 			}
       
  1273 			unset($parsedFrame['data']);
       
  1274 
       
  1275 
       
  1276 		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RVRB')) || // 4.13  RVRB Reverb
       
  1277 				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'REV'))) {     // 4.14  REV  Reverb
       
  1278 			//   There may only be one 'RVRB' frame in each tag.
       
  1279 			// <Header for 'Reverb', ID: 'RVRB'>
       
  1280 			// Reverb left (ms)                 $xx xx
       
  1281 			// Reverb right (ms)                $xx xx
       
  1282 			// Reverb bounces, left             $xx
       
  1283 			// Reverb bounces, right            $xx
       
  1284 			// Reverb feedback, left to left    $xx
       
  1285 			// Reverb feedback, left to right   $xx
       
  1286 			// Reverb feedback, right to right  $xx
       
  1287 			// Reverb feedback, right to left   $xx
       
  1288 			// Premix left to right             $xx
       
  1289 			// Premix right to left             $xx
       
  1290 
       
  1291 			$frame_offset = 0;
       
  1292 			$parsedFrame['left']  = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
       
  1293 			$frame_offset += 2;
       
  1294 			$parsedFrame['right'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
       
  1295 			$frame_offset += 2;
       
  1296 			$parsedFrame['bouncesL']      = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
  1297 			$parsedFrame['bouncesR']      = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
  1298 			$parsedFrame['feedbackLL']    = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
  1299 			$parsedFrame['feedbackLR']    = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
  1300 			$parsedFrame['feedbackRR']    = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
  1301 			$parsedFrame['feedbackRL']    = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
  1302 			$parsedFrame['premixLR']      = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
  1303 			$parsedFrame['premixRL']      = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
  1304 			unset($parsedFrame['data']);
       
  1305 
       
  1306 
       
  1307 		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'APIC')) || // 4.14  APIC Attached picture
       
  1308 				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'PIC'))) {     // 4.15  PIC  Attached picture
       
  1309 			//   There may be several pictures attached to one file,
       
  1310 			//   each in their individual 'APIC' frame, but only one
       
  1311 			//   with the same content descriptor
       
  1312 			// <Header for 'Attached picture', ID: 'APIC'>
       
  1313 			// Text encoding      $xx
       
  1314 			// ID3v2.3+ => MIME type          <text string> $00
       
  1315 			// ID3v2.2  => Image format       $xx xx xx
       
  1316 			// Picture type       $xx
       
  1317 			// Description        <text string according to encoding> $00 (00)
       
  1318 			// Picture data       <binary data>
       
  1319 
       
  1320 			$frame_offset = 0;
       
  1321 			$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
  1322 			if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
       
  1323 				$info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
       
  1324 			}
       
  1325 
       
  1326 			if ($id3v2_majorversion == 2 && strlen($parsedFrame['data']) > $frame_offset) {
       
  1327 				$frame_imagetype = substr($parsedFrame['data'], $frame_offset, 3);
       
  1328 				if (strtolower($frame_imagetype) == 'ima') {
       
  1329 					// complete hack for mp3Rage (www.chaoticsoftware.com) that puts ID3v2.3-formatted
       
  1330 					// MIME type instead of 3-char ID3v2.2-format image type  (thanks xbhoffØpacbell*net)
       
  1331 					$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
       
  1332 					$frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
       
  1333 					if (ord($frame_mimetype) === 0) {
       
  1334 						$frame_mimetype = '';
       
  1335 					}
       
  1336 					$frame_imagetype = strtoupper(str_replace('image/', '', strtolower($frame_mimetype)));
       
  1337 					if ($frame_imagetype == 'JPEG') {
       
  1338 						$frame_imagetype = 'JPG';
       
  1339 					}
       
  1340 					$frame_offset = $frame_terminatorpos + strlen("\x00");
       
  1341 				} else {
       
  1342 					$frame_offset += 3;
       
  1343 				}
       
  1344 			}
       
  1345 			if ($id3v2_majorversion > 2 && strlen($parsedFrame['data']) > $frame_offset) {
       
  1346 				$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
       
  1347 				$frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
       
  1348 				if (ord($frame_mimetype) === 0) {
       
  1349 					$frame_mimetype = '';
       
  1350 				}
       
  1351 				$frame_offset = $frame_terminatorpos + strlen("\x00");
       
  1352 			}
       
  1353 
       
  1354 			$frame_picturetype = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
  1355 
       
  1356 			if ($frame_offset >= $parsedFrame['datalength']) {
       
  1357 				$info['warning'][] = 'data portion of APIC frame is missing at offset '.($parsedFrame['dataoffset'] + 8 + $frame_offset);
       
  1358 			} else {
       
  1359 				$frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
       
  1360 				if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
       
  1361 					$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
       
  1362 				}
       
  1363 				$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
       
  1364 				if (ord($frame_description) === 0) {
       
  1365 					$frame_description = '';
       
  1366 				}
       
  1367 				$parsedFrame['encodingid']       = $frame_textencoding;
       
  1368 				$parsedFrame['encoding']         = $this->TextEncodingNameLookup($frame_textencoding);
       
  1369 
       
  1370 				if ($id3v2_majorversion == 2) {
       
  1371 					$parsedFrame['imagetype']    = $frame_imagetype;
       
  1372 				} else {
       
  1373 					$parsedFrame['mime']         = $frame_mimetype;
       
  1374 				}
       
  1375 				$parsedFrame['picturetypeid']    = $frame_picturetype;
       
  1376 				$parsedFrame['picturetype']      = $this->APICPictureTypeLookup($frame_picturetype);
       
  1377 				$parsedFrame['description']      = $frame_description;
       
  1378 				$parsedFrame['data']             = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
       
  1379 				$parsedFrame['datalength']       = strlen($parsedFrame['data']);
       
  1380 
       
  1381 				$parsedFrame['image_mime'] = '';
       
  1382 				$imageinfo = array();
       
  1383 				$imagechunkcheck = getid3_lib::GetDataImageSize($parsedFrame['data'], $imageinfo);
       
  1384 				if (($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3)) {
       
  1385 					$parsedFrame['image_mime']       = 'image/'.getid3_lib::ImageTypesLookup($imagechunkcheck[2]);
       
  1386 					if ($imagechunkcheck[0]) {
       
  1387 						$parsedFrame['image_width']  = $imagechunkcheck[0];
       
  1388 					}
       
  1389 					if ($imagechunkcheck[1]) {
       
  1390 						$parsedFrame['image_height'] = $imagechunkcheck[1];
       
  1391 					}
       
  1392 				}
       
  1393 
       
  1394 				do {
       
  1395 					if ($this->getid3->option_save_attachments === false) {
       
  1396 						// skip entirely
       
  1397 						unset($parsedFrame['data']);
       
  1398 						break;
       
  1399 					}
       
  1400 					if ($this->getid3->option_save_attachments === true) {
       
  1401 						// great
       
  1402 /*
       
  1403 					} elseif (is_int($this->getid3->option_save_attachments)) {
       
  1404 						if ($this->getid3->option_save_attachments < $parsedFrame['data_length']) {
       
  1405 							// too big, skip
       
  1406 							$info['warning'][] = 'attachment at '.$frame_offset.' is too large to process inline ('.number_format($parsedFrame['data_length']).' bytes)';
       
  1407 							unset($parsedFrame['data']);
       
  1408 							break;
       
  1409 						}
       
  1410 */
       
  1411 					} elseif (is_string($this->getid3->option_save_attachments)) {
       
  1412 						$dir = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->getid3->option_save_attachments), DIRECTORY_SEPARATOR);
       
  1413 						if (!is_dir($dir) || !is_writable($dir)) {
       
  1414 							// cannot write, skip
       
  1415 							$info['warning'][] = 'attachment at '.$frame_offset.' cannot be saved to "'.$dir.'" (not writable)';
       
  1416 							unset($parsedFrame['data']);
       
  1417 							break;
       
  1418 						}
       
  1419 					}
       
  1420 					// if we get this far, must be OK
       
  1421 					if (is_string($this->getid3->option_save_attachments)) {
       
  1422 						$destination_filename = $dir.DIRECTORY_SEPARATOR.md5($info['filenamepath']).'_'.$frame_offset;
       
  1423 						if (!file_exists($destination_filename) || is_writable($destination_filename)) {
       
  1424 							file_put_contents($destination_filename, $parsedFrame['data']);
       
  1425 						} else {
       
  1426 							$info['warning'][] = 'attachment at '.$frame_offset.' cannot be saved to "'.$destination_filename.'" (not writable)';
       
  1427 						}
       
  1428 						$parsedFrame['data_filename'] = $destination_filename;
       
  1429 						unset($parsedFrame['data']);
       
  1430 					} else {
       
  1431 						if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
       
  1432 							if (!isset($info['id3v2']['comments']['picture'])) {
       
  1433 								$info['id3v2']['comments']['picture'] = array();
       
  1434 							}
       
  1435 							$info['id3v2']['comments']['picture'][] = array('data'=>$parsedFrame['data'], 'image_mime'=>$parsedFrame['image_mime']);
       
  1436 						}
       
  1437 					}
       
  1438 				} while (false);
       
  1439 			}
       
  1440 
       
  1441 		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'GEOB')) || // 4.15  GEOB General encapsulated object
       
  1442 				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'GEO'))) {     // 4.16  GEO  General encapsulated object
       
  1443 			//   There may be more than one 'GEOB' frame in each tag,
       
  1444 			//   but only one with the same content descriptor
       
  1445 			// <Header for 'General encapsulated object', ID: 'GEOB'>
       
  1446 			// Text encoding          $xx
       
  1447 			// MIME type              <text string> $00
       
  1448 			// Filename               <text string according to encoding> $00 (00)
       
  1449 			// Content description    <text string according to encoding> $00 (00)
       
  1450 			// Encapsulated object    <binary data>
       
  1451 
       
  1452 			$frame_offset = 0;
       
  1453 			$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
  1454 			if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
       
  1455 				$info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
       
  1456 			}
       
  1457 			$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
       
  1458 			$frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
       
  1459 			if (ord($frame_mimetype) === 0) {
       
  1460 				$frame_mimetype = '';
       
  1461 			}
       
  1462 			$frame_offset = $frame_terminatorpos + strlen("\x00");
       
  1463 
       
  1464 			$frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
       
  1465 			if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
       
  1466 				$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
       
  1467 			}
       
  1468 			$frame_filename = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
       
  1469 			if (ord($frame_filename) === 0) {
       
  1470 				$frame_filename = '';
       
  1471 			}
       
  1472 			$frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding));
       
  1473 
       
  1474 			$frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
       
  1475 			if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
       
  1476 				$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
       
  1477 			}
       
  1478 			$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
       
  1479 			if (ord($frame_description) === 0) {
       
  1480 				$frame_description = '';
       
  1481 			}
       
  1482 			$frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding));
       
  1483 
       
  1484 			$parsedFrame['objectdata']  = (string) substr($parsedFrame['data'], $frame_offset);
       
  1485 			$parsedFrame['encodingid']  = $frame_textencoding;
       
  1486 			$parsedFrame['encoding']    = $this->TextEncodingNameLookup($frame_textencoding);
       
  1487 
       
  1488 			$parsedFrame['mime']        = $frame_mimetype;
       
  1489 			$parsedFrame['filename']    = $frame_filename;
       
  1490 			$parsedFrame['description'] = $frame_description;
       
  1491 			unset($parsedFrame['data']);
       
  1492 
       
  1493 
       
  1494 		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'PCNT')) || // 4.16  PCNT Play counter
       
  1495 				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CNT'))) {     // 4.17  CNT  Play counter
       
  1496 			//   There may only be one 'PCNT' frame in each tag.
       
  1497 			//   When the counter reaches all one's, one byte is inserted in
       
  1498 			//   front of the counter thus making the counter eight bits bigger
       
  1499 			// <Header for 'Play counter', ID: 'PCNT'>
       
  1500 			// Counter        $xx xx xx xx (xx ...)
       
  1501 
       
  1502 			$parsedFrame['data']          = getid3_lib::BigEndian2Int($parsedFrame['data']);
       
  1503 
       
  1504 
       
  1505 		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'POPM')) || // 4.17  POPM Popularimeter
       
  1506 				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'POP'))) {    // 4.18  POP  Popularimeter
       
  1507 			//   There may be more than one 'POPM' frame in each tag,
       
  1508 			//   but only one with the same email address
       
  1509 			// <Header for 'Popularimeter', ID: 'POPM'>
       
  1510 			// Email to user   <text string> $00
       
  1511 			// Rating          $xx
       
  1512 			// Counter         $xx xx xx xx (xx ...)
       
  1513 
       
  1514 			$frame_offset = 0;
       
  1515 			$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
       
  1516 			$frame_emailaddress = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
       
  1517 			if (ord($frame_emailaddress) === 0) {
       
  1518 				$frame_emailaddress = '';
       
  1519 			}
       
  1520 			$frame_offset = $frame_terminatorpos + strlen("\x00");
       
  1521 			$frame_rating = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
  1522 			$parsedFrame['counter'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset));
       
  1523 			$parsedFrame['email']   = $frame_emailaddress;
       
  1524 			$parsedFrame['rating']  = $frame_rating;
       
  1525 			unset($parsedFrame['data']);
       
  1526 
       
  1527 
       
  1528 		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RBUF')) || // 4.18  RBUF Recommended buffer size
       
  1529 				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'BUF'))) {     // 4.19  BUF  Recommended buffer size
       
  1530 			//   There may only be one 'RBUF' frame in each tag
       
  1531 			// <Header for 'Recommended buffer size', ID: 'RBUF'>
       
  1532 			// Buffer size               $xx xx xx
       
  1533 			// Embedded info flag        %0000000x
       
  1534 			// Offset to next tag        $xx xx xx xx
       
  1535 
       
  1536 			$frame_offset = 0;
       
  1537 			$parsedFrame['buffersize'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 3));
       
  1538 			$frame_offset += 3;
       
  1539 
       
  1540 			$frame_embeddedinfoflags = getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1));
       
  1541 			$parsedFrame['flags']['embededinfo'] = (bool) substr($frame_embeddedinfoflags, 7, 1);
       
  1542 			$parsedFrame['nexttagoffset'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
       
  1543 			unset($parsedFrame['data']);
       
  1544 
       
  1545 
       
  1546 		} elseif (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CRM')) { // 4.20  Encrypted meta frame (ID3v2.2 only)
       
  1547 			//   There may be more than one 'CRM' frame in a tag,
       
  1548 			//   but only one with the same 'owner identifier'
       
  1549 			// <Header for 'Encrypted meta frame', ID: 'CRM'>
       
  1550 			// Owner identifier      <textstring> $00 (00)
       
  1551 			// Content/explanation   <textstring> $00 (00)
       
  1552 			// Encrypted datablock   <binary data>
       
  1553 
       
  1554 			$frame_offset = 0;
       
  1555 			$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
       
  1556 			$frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
       
  1557 			$frame_offset = $frame_terminatorpos + strlen("\x00");
       
  1558 
       
  1559 			$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
       
  1560 			$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
       
  1561 			if (ord($frame_description) === 0) {
       
  1562 				$frame_description = '';
       
  1563 			}
       
  1564 			$frame_offset = $frame_terminatorpos + strlen("\x00");
       
  1565 
       
  1566 			$parsedFrame['ownerid']     = $frame_ownerid;
       
  1567 			$parsedFrame['data']        = (string) substr($parsedFrame['data'], $frame_offset);
       
  1568 			$parsedFrame['description'] = $frame_description;
       
  1569 			unset($parsedFrame['data']);
       
  1570 
       
  1571 
       
  1572 		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'AENC')) || // 4.19  AENC Audio encryption
       
  1573 				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CRA'))) {     // 4.21  CRA  Audio encryption
       
  1574 			//   There may be more than one 'AENC' frames in a tag,
       
  1575 			//   but only one with the same 'Owner identifier'
       
  1576 			// <Header for 'Audio encryption', ID: 'AENC'>
       
  1577 			// Owner identifier   <text string> $00
       
  1578 			// Preview start      $xx xx
       
  1579 			// Preview length     $xx xx
       
  1580 			// Encryption info    <binary data>
       
  1581 
       
  1582 			$frame_offset = 0;
       
  1583 			$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
       
  1584 			$frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
       
  1585 			if (ord($frame_ownerid) === 0) {
       
  1586 				$frame_ownerid == '';
       
  1587 			}
       
  1588 			$frame_offset = $frame_terminatorpos + strlen("\x00");
       
  1589 			$parsedFrame['ownerid'] = $frame_ownerid;
       
  1590 			$parsedFrame['previewstart'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
       
  1591 			$frame_offset += 2;
       
  1592 			$parsedFrame['previewlength'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
       
  1593 			$frame_offset += 2;
       
  1594 			$parsedFrame['encryptioninfo'] = (string) substr($parsedFrame['data'], $frame_offset);
       
  1595 			unset($parsedFrame['data']);
       
  1596 
       
  1597 
       
  1598 		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'LINK')) || // 4.20  LINK Linked information
       
  1599 				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'LNK'))) {     // 4.22  LNK  Linked information
       
  1600 			//   There may be more than one 'LINK' frame in a tag,
       
  1601 			//   but only one with the same contents
       
  1602 			// <Header for 'Linked information', ID: 'LINK'>
       
  1603 			// ID3v2.3+ => Frame identifier   $xx xx xx xx
       
  1604 			// ID3v2.2  => Frame identifier   $xx xx xx
       
  1605 			// URL                            <text string> $00
       
  1606 			// ID and additional data         <text string(s)>
       
  1607 
       
  1608 			$frame_offset = 0;
       
  1609 			if ($id3v2_majorversion == 2) {
       
  1610 				$parsedFrame['frameid'] = substr($parsedFrame['data'], $frame_offset, 3);
       
  1611 				$frame_offset += 3;
       
  1612 			} else {
       
  1613 				$parsedFrame['frameid'] = substr($parsedFrame['data'], $frame_offset, 4);
       
  1614 				$frame_offset += 4;
       
  1615 			}
       
  1616 
       
  1617 			$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
       
  1618 			$frame_url = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
       
  1619 			if (ord($frame_url) === 0) {
       
  1620 				$frame_url = '';
       
  1621 			}
       
  1622 			$frame_offset = $frame_terminatorpos + strlen("\x00");
       
  1623 			$parsedFrame['url'] = $frame_url;
       
  1624 
       
  1625 			$parsedFrame['additionaldata'] = (string) substr($parsedFrame['data'], $frame_offset);
       
  1626 			if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) {
       
  1627 				$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = utf8_encode($parsedFrame['url']);
       
  1628 			}
       
  1629 			unset($parsedFrame['data']);
       
  1630 
       
  1631 
       
  1632 		} elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'POSS')) { // 4.21  POSS Position synchronisation frame (ID3v2.3+ only)
       
  1633 			//   There may only be one 'POSS' frame in each tag
       
  1634 			// <Head for 'Position synchronisation', ID: 'POSS'>
       
  1635 			// Time stamp format         $xx
       
  1636 			// Position                  $xx (xx ...)
       
  1637 
       
  1638 			$frame_offset = 0;
       
  1639 			$parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
  1640 			$parsedFrame['position']        = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset));
       
  1641 			unset($parsedFrame['data']);
       
  1642 
       
  1643 
       
  1644 		} elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'USER')) { // 4.22  USER Terms of use (ID3v2.3+ only)
       
  1645 			//   There may be more than one 'Terms of use' frame in a tag,
       
  1646 			//   but only one with the same 'Language'
       
  1647 			// <Header for 'Terms of use frame', ID: 'USER'>
       
  1648 			// Text encoding        $xx
       
  1649 			// Language             $xx xx xx
       
  1650 			// The actual text      <text string according to encoding>
       
  1651 
       
  1652 			$frame_offset = 0;
       
  1653 			$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
  1654 			if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
       
  1655 				$info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
       
  1656 			}
       
  1657 			$frame_language = substr($parsedFrame['data'], $frame_offset, 3);
       
  1658 			$frame_offset += 3;
       
  1659 			$parsedFrame['language']     = $frame_language;
       
  1660 			$parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
       
  1661 			$parsedFrame['encodingid']   = $frame_textencoding;
       
  1662 			$parsedFrame['encoding']     = $this->TextEncodingNameLookup($frame_textencoding);
       
  1663 
       
  1664 			$parsedFrame['data']         = (string) substr($parsedFrame['data'], $frame_offset);
       
  1665 			if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
       
  1666 				$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
       
  1667 			}
       
  1668 			unset($parsedFrame['data']);
       
  1669 
       
  1670 
       
  1671 		} elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'OWNE')) { // 4.23  OWNE Ownership frame (ID3v2.3+ only)
       
  1672 			//   There may only be one 'OWNE' frame in a tag
       
  1673 			// <Header for 'Ownership frame', ID: 'OWNE'>
       
  1674 			// Text encoding     $xx
       
  1675 			// Price paid        <text string> $00
       
  1676 			// Date of purch.    <text string>
       
  1677 			// Seller            <text string according to encoding>
       
  1678 
       
  1679 			$frame_offset = 0;
       
  1680 			$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
  1681 			if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
       
  1682 				$info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
       
  1683 			}
       
  1684 			$parsedFrame['encodingid'] = $frame_textencoding;
       
  1685 			$parsedFrame['encoding']   = $this->TextEncodingNameLookup($frame_textencoding);
       
  1686 
       
  1687 			$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
       
  1688 			$frame_pricepaid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
       
  1689 			$frame_offset = $frame_terminatorpos + strlen("\x00");
       
  1690 
       
  1691 			$parsedFrame['pricepaid']['currencyid'] = substr($frame_pricepaid, 0, 3);
       
  1692 			$parsedFrame['pricepaid']['currency']   = $this->LookupCurrencyUnits($parsedFrame['pricepaid']['currencyid']);
       
  1693 			$parsedFrame['pricepaid']['value']      = substr($frame_pricepaid, 3);
       
  1694 
       
  1695 			$parsedFrame['purchasedate'] = substr($parsedFrame['data'], $frame_offset, 8);
       
  1696 			if (!$this->IsValidDateStampString($parsedFrame['purchasedate'])) {
       
  1697 				$parsedFrame['purchasedateunix'] = mktime (0, 0, 0, substr($parsedFrame['purchasedate'], 4, 2), substr($parsedFrame['purchasedate'], 6, 2), substr($parsedFrame['purchasedate'], 0, 4));
       
  1698 			}
       
  1699 			$frame_offset += 8;
       
  1700 
       
  1701 			$parsedFrame['seller'] = (string) substr($parsedFrame['data'], $frame_offset);
       
  1702 			unset($parsedFrame['data']);
       
  1703 
       
  1704 
       
  1705 		} elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'COMR')) { // 4.24  COMR Commercial frame (ID3v2.3+ only)
       
  1706 			//   There may be more than one 'commercial frame' in a tag,
       
  1707 			//   but no two may be identical
       
  1708 			// <Header for 'Commercial frame', ID: 'COMR'>
       
  1709 			// Text encoding      $xx
       
  1710 			// Price string       <text string> $00
       
  1711 			// Valid until        <text string>
       
  1712 			// Contact URL        <text string> $00
       
  1713 			// Received as        $xx
       
  1714 			// Name of seller     <text string according to encoding> $00 (00)
       
  1715 			// Description        <text string according to encoding> $00 (00)
       
  1716 			// Picture MIME type  <string> $00
       
  1717 			// Seller logo        <binary data>
       
  1718 
       
  1719 			$frame_offset = 0;
       
  1720 			$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
  1721 			if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
       
  1722 				$info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
       
  1723 			}
       
  1724 
       
  1725 			$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
       
  1726 			$frame_pricestring = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
       
  1727 			$frame_offset = $frame_terminatorpos + strlen("\x00");
       
  1728 			$frame_rawpricearray = explode('/', $frame_pricestring);
       
  1729 			foreach ($frame_rawpricearray as $key => $val) {
       
  1730 				$frame_currencyid = substr($val, 0, 3);
       
  1731 				$parsedFrame['price'][$frame_currencyid]['currency'] = $this->LookupCurrencyUnits($frame_currencyid);
       
  1732 				$parsedFrame['price'][$frame_currencyid]['value']    = substr($val, 3);
       
  1733 			}
       
  1734 
       
  1735 			$frame_datestring = substr($parsedFrame['data'], $frame_offset, 8);
       
  1736 			$frame_offset += 8;
       
  1737 
       
  1738 			$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
       
  1739 			$frame_contacturl = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
       
  1740 			$frame_offset = $frame_terminatorpos + strlen("\x00");
       
  1741 
       
  1742 			$frame_receivedasid = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
  1743 
       
  1744 			$frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
       
  1745 			if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
       
  1746 				$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
       
  1747 			}
       
  1748 			$frame_sellername = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
       
  1749 			if (ord($frame_sellername) === 0) {
       
  1750 				$frame_sellername = '';
       
  1751 			}
       
  1752 			$frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding));
       
  1753 
       
  1754 			$frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
       
  1755 			if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
       
  1756 				$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
       
  1757 			}
       
  1758 			$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
       
  1759 			if (ord($frame_description) === 0) {
       
  1760 				$frame_description = '';
       
  1761 			}
       
  1762 			$frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding));
       
  1763 
       
  1764 			$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
       
  1765 			$frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
       
  1766 			$frame_offset = $frame_terminatorpos + strlen("\x00");
       
  1767 
       
  1768 			$frame_sellerlogo = substr($parsedFrame['data'], $frame_offset);
       
  1769 
       
  1770 			$parsedFrame['encodingid']        = $frame_textencoding;
       
  1771 			$parsedFrame['encoding']          = $this->TextEncodingNameLookup($frame_textencoding);
       
  1772 
       
  1773 			$parsedFrame['pricevaliduntil']   = $frame_datestring;
       
  1774 			$parsedFrame['contacturl']        = $frame_contacturl;
       
  1775 			$parsedFrame['receivedasid']      = $frame_receivedasid;
       
  1776 			$parsedFrame['receivedas']        = $this->COMRReceivedAsLookup($frame_receivedasid);
       
  1777 			$parsedFrame['sellername']        = $frame_sellername;
       
  1778 			$parsedFrame['description']       = $frame_description;
       
  1779 			$parsedFrame['mime']              = $frame_mimetype;
       
  1780 			$parsedFrame['logo']              = $frame_sellerlogo;
       
  1781 			unset($parsedFrame['data']);
       
  1782 
       
  1783 
       
  1784 		} elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'ENCR')) { // 4.25  ENCR Encryption method registration (ID3v2.3+ only)
       
  1785 			//   There may be several 'ENCR' frames in a tag,
       
  1786 			//   but only one containing the same symbol
       
  1787 			//   and only one containing the same owner identifier
       
  1788 			// <Header for 'Encryption method registration', ID: 'ENCR'>
       
  1789 			// Owner identifier    <text string> $00
       
  1790 			// Method symbol       $xx
       
  1791 			// Encryption data     <binary data>
       
  1792 
       
  1793 			$frame_offset = 0;
       
  1794 			$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
       
  1795 			$frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
       
  1796 			if (ord($frame_ownerid) === 0) {
       
  1797 				$frame_ownerid = '';
       
  1798 			}
       
  1799 			$frame_offset = $frame_terminatorpos + strlen("\x00");
       
  1800 
       
  1801 			$parsedFrame['ownerid']      = $frame_ownerid;
       
  1802 			$parsedFrame['methodsymbol'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
  1803 			$parsedFrame['data']         = (string) substr($parsedFrame['data'], $frame_offset);
       
  1804 
       
  1805 
       
  1806 		} elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'GRID')) { // 4.26  GRID Group identification registration (ID3v2.3+ only)
       
  1807 
       
  1808 			//   There may be several 'GRID' frames in a tag,
       
  1809 			//   but only one containing the same symbol
       
  1810 			//   and only one containing the same owner identifier
       
  1811 			// <Header for 'Group ID registration', ID: 'GRID'>
       
  1812 			// Owner identifier      <text string> $00
       
  1813 			// Group symbol          $xx
       
  1814 			// Group dependent data  <binary data>
       
  1815 
       
  1816 			$frame_offset = 0;
       
  1817 			$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
       
  1818 			$frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
       
  1819 			if (ord($frame_ownerid) === 0) {
       
  1820 				$frame_ownerid = '';
       
  1821 			}
       
  1822 			$frame_offset = $frame_terminatorpos + strlen("\x00");
       
  1823 
       
  1824 			$parsedFrame['ownerid']       = $frame_ownerid;
       
  1825 			$parsedFrame['groupsymbol']   = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
  1826 			$parsedFrame['data']          = (string) substr($parsedFrame['data'], $frame_offset);
       
  1827 
       
  1828 
       
  1829 		} elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'PRIV')) { // 4.27  PRIV Private frame (ID3v2.3+ only)
       
  1830 			//   The tag may contain more than one 'PRIV' frame
       
  1831 			//   but only with different contents
       
  1832 			// <Header for 'Private frame', ID: 'PRIV'>
       
  1833 			// Owner identifier      <text string> $00
       
  1834 			// The private data      <binary data>
       
  1835 
       
  1836 			$frame_offset = 0;
       
  1837 			$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
       
  1838 			$frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
       
  1839 			if (ord($frame_ownerid) === 0) {
       
  1840 				$frame_ownerid = '';
       
  1841 			}
       
  1842 			$frame_offset = $frame_terminatorpos + strlen("\x00");
       
  1843 
       
  1844 			$parsedFrame['ownerid'] = $frame_ownerid;
       
  1845 			$parsedFrame['data']    = (string) substr($parsedFrame['data'], $frame_offset);
       
  1846 
       
  1847 
       
  1848 		} elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'SIGN')) { // 4.28  SIGN Signature frame (ID3v2.4+ only)
       
  1849 			//   There may be more than one 'signature frame' in a tag,
       
  1850 			//   but no two may be identical
       
  1851 			// <Header for 'Signature frame', ID: 'SIGN'>
       
  1852 			// Group symbol      $xx
       
  1853 			// Signature         <binary data>
       
  1854 
       
  1855 			$frame_offset = 0;
       
  1856 			$parsedFrame['groupsymbol'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
  1857 			$parsedFrame['data']        = (string) substr($parsedFrame['data'], $frame_offset);
       
  1858 
       
  1859 
       
  1860 		} elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'SEEK')) { // 4.29  SEEK Seek frame (ID3v2.4+ only)
       
  1861 			//   There may only be one 'seek frame' in a tag
       
  1862 			// <Header for 'Seek frame', ID: 'SEEK'>
       
  1863 			// Minimum offset to next tag       $xx xx xx xx
       
  1864 
       
  1865 			$frame_offset = 0;
       
  1866 			$parsedFrame['data']          = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
       
  1867 
       
  1868 
       
  1869 		} elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'ASPI')) { // 4.30  ASPI Audio seek point index (ID3v2.4+ only)
       
  1870 			//   There may only be one 'audio seek point index' frame in a tag
       
  1871 			// <Header for 'Seek Point Index', ID: 'ASPI'>
       
  1872 			// Indexed data start (S)         $xx xx xx xx
       
  1873 			// Indexed data length (L)        $xx xx xx xx
       
  1874 			// Number of index points (N)     $xx xx
       
  1875 			// Bits per index point (b)       $xx
       
  1876 			//   Then for every index point the following data is included:
       
  1877 			// Fraction at index (Fi)          $xx (xx)
       
  1878 
       
  1879 			$frame_offset = 0;
       
  1880 			$parsedFrame['datastart'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
       
  1881 			$frame_offset += 4;
       
  1882 			$parsedFrame['indexeddatalength'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
       
  1883 			$frame_offset += 4;
       
  1884 			$parsedFrame['indexpoints'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
       
  1885 			$frame_offset += 2;
       
  1886 			$parsedFrame['bitsperpoint'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
       
  1887 			$frame_bytesperpoint = ceil($parsedFrame['bitsperpoint'] / 8);
       
  1888 			for ($i = 0; $i < $frame_indexpoints; $i++) {
       
  1889 				$parsedFrame['indexes'][$i] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesperpoint));
       
  1890 				$frame_offset += $frame_bytesperpoint;
       
  1891 			}
       
  1892 			unset($parsedFrame['data']);
       
  1893 
       
  1894 		} elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RGAD')) { // Replay Gain Adjustment
       
  1895 			// http://privatewww.essex.ac.uk/~djmrob/replaygain/file_format_id3v2.html
       
  1896 			//   There may only be one 'RGAD' frame in a tag
       
  1897 			// <Header for 'Replay Gain Adjustment', ID: 'RGAD'>
       
  1898 			// Peak Amplitude                      $xx $xx $xx $xx
       
  1899 			// Radio Replay Gain Adjustment        %aaabbbcd %dddddddd
       
  1900 			// Audiophile Replay Gain Adjustment   %aaabbbcd %dddddddd
       
  1901 			//   a - name code
       
  1902 			//   b - originator code
       
  1903 			//   c - sign bit
       
  1904 			//   d - replay gain adjustment
       
  1905 
       
  1906 			$frame_offset = 0;
       
  1907 			$parsedFrame['peakamplitude'] = getid3_lib::BigEndian2Float(substr($parsedFrame['data'], $frame_offset, 4));
       
  1908 			$frame_offset += 4;
       
  1909 			$rg_track_adjustment = getid3_lib::Dec2Bin(substr($parsedFrame['data'], $frame_offset, 2));
       
  1910 			$frame_offset += 2;
       
  1911 			$rg_album_adjustment = getid3_lib::Dec2Bin(substr($parsedFrame['data'], $frame_offset, 2));
       
  1912 			$frame_offset += 2;
       
  1913 			$parsedFrame['raw']['track']['name']       = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 0, 3));
       
  1914 			$parsedFrame['raw']['track']['originator'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 3, 3));
       
  1915 			$parsedFrame['raw']['track']['signbit']    = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 6, 1));
       
  1916 			$parsedFrame['raw']['track']['adjustment'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 7, 9));
       
  1917 			$parsedFrame['raw']['album']['name']       = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 0, 3));
       
  1918 			$parsedFrame['raw']['album']['originator'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 3, 3));
       
  1919 			$parsedFrame['raw']['album']['signbit']    = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 6, 1));
       
  1920 			$parsedFrame['raw']['album']['adjustment'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 7, 9));
       
  1921 			$parsedFrame['track']['name']       = getid3_lib::RGADnameLookup($parsedFrame['raw']['track']['name']);
       
  1922 			$parsedFrame['track']['originator'] = getid3_lib::RGADoriginatorLookup($parsedFrame['raw']['track']['originator']);
       
  1923 			$parsedFrame['track']['adjustment'] = getid3_lib::RGADadjustmentLookup($parsedFrame['raw']['track']['adjustment'], $parsedFrame['raw']['track']['signbit']);
       
  1924 			$parsedFrame['album']['name']       = getid3_lib::RGADnameLookup($parsedFrame['raw']['album']['name']);
       
  1925 			$parsedFrame['album']['originator'] = getid3_lib::RGADoriginatorLookup($parsedFrame['raw']['album']['originator']);
       
  1926 			$parsedFrame['album']['adjustment'] = getid3_lib::RGADadjustmentLookup($parsedFrame['raw']['album']['adjustment'], $parsedFrame['raw']['album']['signbit']);
       
  1927 
       
  1928 			$info['replay_gain']['track']['peak']       = $parsedFrame['peakamplitude'];
       
  1929 			$info['replay_gain']['track']['originator'] = $parsedFrame['track']['originator'];
       
  1930 			$info['replay_gain']['track']['adjustment'] = $parsedFrame['track']['adjustment'];
       
  1931 			$info['replay_gain']['album']['originator'] = $parsedFrame['album']['originator'];
       
  1932 			$info['replay_gain']['album']['adjustment'] = $parsedFrame['album']['adjustment'];
       
  1933 
       
  1934 			unset($parsedFrame['data']);
       
  1935 
       
  1936 		}
       
  1937 
       
  1938 		return true;
       
  1939 	}
       
  1940 
       
  1941 
       
  1942 	public function DeUnsynchronise($data) {
       
  1943 		return str_replace("\xFF\x00", "\xFF", $data);
       
  1944 	}
       
  1945 
       
  1946 	public function LookupExtendedHeaderRestrictionsTagSizeLimits($index) {
       
  1947 		static $LookupExtendedHeaderRestrictionsTagSizeLimits = array(
       
  1948 			0x00 => 'No more than 128 frames and 1 MB total tag size',
       
  1949 			0x01 => 'No more than 64 frames and 128 KB total tag size',
       
  1950 			0x02 => 'No more than 32 frames and 40 KB total tag size',
       
  1951 			0x03 => 'No more than 32 frames and 4 KB total tag size',
       
  1952 		);
       
  1953 		return (isset($LookupExtendedHeaderRestrictionsTagSizeLimits[$index]) ? $LookupExtendedHeaderRestrictionsTagSizeLimits[$index] : '');
       
  1954 	}
       
  1955 
       
  1956 	public function LookupExtendedHeaderRestrictionsTextEncodings($index) {
       
  1957 		static $LookupExtendedHeaderRestrictionsTextEncodings = array(
       
  1958 			0x00 => 'No restrictions',
       
  1959 			0x01 => 'Strings are only encoded with ISO-8859-1 or UTF-8',
       
  1960 		);
       
  1961 		return (isset($LookupExtendedHeaderRestrictionsTextEncodings[$index]) ? $LookupExtendedHeaderRestrictionsTextEncodings[$index] : '');
       
  1962 	}
       
  1963 
       
  1964 	public function LookupExtendedHeaderRestrictionsTextFieldSize($index) {
       
  1965 		static $LookupExtendedHeaderRestrictionsTextFieldSize = array(
       
  1966 			0x00 => 'No restrictions',
       
  1967 			0x01 => 'No string is longer than 1024 characters',
       
  1968 			0x02 => 'No string is longer than 128 characters',
       
  1969 			0x03 => 'No string is longer than 30 characters',
       
  1970 		);
       
  1971 		return (isset($LookupExtendedHeaderRestrictionsTextFieldSize[$index]) ? $LookupExtendedHeaderRestrictionsTextFieldSize[$index] : '');
       
  1972 	}
       
  1973 
       
  1974 	public function LookupExtendedHeaderRestrictionsImageEncoding($index) {
       
  1975 		static $LookupExtendedHeaderRestrictionsImageEncoding = array(
       
  1976 			0x00 => 'No restrictions',
       
  1977 			0x01 => 'Images are encoded only with PNG or JPEG',
       
  1978 		);
       
  1979 		return (isset($LookupExtendedHeaderRestrictionsImageEncoding[$index]) ? $LookupExtendedHeaderRestrictionsImageEncoding[$index] : '');
       
  1980 	}
       
  1981 
       
  1982 	public function LookupExtendedHeaderRestrictionsImageSizeSize($index) {
       
  1983 		static $LookupExtendedHeaderRestrictionsImageSizeSize = array(
       
  1984 			0x00 => 'No restrictions',
       
  1985 			0x01 => 'All images are 256x256 pixels or smaller',
       
  1986 			0x02 => 'All images are 64x64 pixels or smaller',
       
  1987 			0x03 => 'All images are exactly 64x64 pixels, unless required otherwise',
       
  1988 		);
       
  1989 		return (isset($LookupExtendedHeaderRestrictionsImageSizeSize[$index]) ? $LookupExtendedHeaderRestrictionsImageSizeSize[$index] : '');
       
  1990 	}
       
  1991 
       
  1992 	public function LookupCurrencyUnits($currencyid) {
       
  1993 
       
  1994 		$begin = __LINE__;
       
  1995 
       
  1996 		/** This is not a comment!
       
  1997 
       
  1998 
       
  1999 			AED	Dirhams
       
  2000 			AFA	Afghanis
       
  2001 			ALL	Leke
       
  2002 			AMD	Drams
       
  2003 			ANG	Guilders
       
  2004 			AOA	Kwanza
       
  2005 			ARS	Pesos
       
  2006 			ATS	Schillings
       
  2007 			AUD	Dollars
       
  2008 			AWG	Guilders
       
  2009 			AZM	Manats
       
  2010 			BAM	Convertible Marka
       
  2011 			BBD	Dollars
       
  2012 			BDT	Taka
       
  2013 			BEF	Francs
       
  2014 			BGL	Leva
       
  2015 			BHD	Dinars
       
  2016 			BIF	Francs
       
  2017 			BMD	Dollars
       
  2018 			BND	Dollars
       
  2019 			BOB	Bolivianos
       
  2020 			BRL	Brazil Real
       
  2021 			BSD	Dollars
       
  2022 			BTN	Ngultrum
       
  2023 			BWP	Pulas
       
  2024 			BYR	Rubles
       
  2025 			BZD	Dollars
       
  2026 			CAD	Dollars
       
  2027 			CDF	Congolese Francs
       
  2028 			CHF	Francs
       
  2029 			CLP	Pesos
       
  2030 			CNY	Yuan Renminbi
       
  2031 			COP	Pesos
       
  2032 			CRC	Colones
       
  2033 			CUP	Pesos
       
  2034 			CVE	Escudos
       
  2035 			CYP	Pounds
       
  2036 			CZK	Koruny
       
  2037 			DEM	Deutsche Marks
       
  2038 			DJF	Francs
       
  2039 			DKK	Kroner
       
  2040 			DOP	Pesos
       
  2041 			DZD	Algeria Dinars
       
  2042 			EEK	Krooni
       
  2043 			EGP	Pounds
       
  2044 			ERN	Nakfa
       
  2045 			ESP	Pesetas
       
  2046 			ETB	Birr
       
  2047 			EUR	Euro
       
  2048 			FIM	Markkaa
       
  2049 			FJD	Dollars
       
  2050 			FKP	Pounds
       
  2051 			FRF	Francs
       
  2052 			GBP	Pounds
       
  2053 			GEL	Lari
       
  2054 			GGP	Pounds
       
  2055 			GHC	Cedis
       
  2056 			GIP	Pounds
       
  2057 			GMD	Dalasi
       
  2058 			GNF	Francs
       
  2059 			GRD	Drachmae
       
  2060 			GTQ	Quetzales
       
  2061 			GYD	Dollars
       
  2062 			HKD	Dollars
       
  2063 			HNL	Lempiras
       
  2064 			HRK	Kuna
       
  2065 			HTG	Gourdes
       
  2066 			HUF	Forints
       
  2067 			IDR	Rupiahs
       
  2068 			IEP	Pounds
       
  2069 			ILS	New Shekels
       
  2070 			IMP	Pounds
       
  2071 			INR	Rupees
       
  2072 			IQD	Dinars
       
  2073 			IRR	Rials
       
  2074 			ISK	Kronur
       
  2075 			ITL	Lire
       
  2076 			JEP	Pounds
       
  2077 			JMD	Dollars
       
  2078 			JOD	Dinars
       
  2079 			JPY	Yen
       
  2080 			KES	Shillings
       
  2081 			KGS	Soms
       
  2082 			KHR	Riels
       
  2083 			KMF	Francs
       
  2084 			KPW	Won
       
  2085 			KWD	Dinars
       
  2086 			KYD	Dollars
       
  2087 			KZT	Tenge
       
  2088 			LAK	Kips
       
  2089 			LBP	Pounds
       
  2090 			LKR	Rupees
       
  2091 			LRD	Dollars
       
  2092 			LSL	Maloti
       
  2093 			LTL	Litai
       
  2094 			LUF	Francs
       
  2095 			LVL	Lati
       
  2096 			LYD	Dinars
       
  2097 			MAD	Dirhams
       
  2098 			MDL	Lei
       
  2099 			MGF	Malagasy Francs
       
  2100 			MKD	Denars
       
  2101 			MMK	Kyats
       
  2102 			MNT	Tugriks
       
  2103 			MOP	Patacas
       
  2104 			MRO	Ouguiyas
       
  2105 			MTL	Liri
       
  2106 			MUR	Rupees
       
  2107 			MVR	Rufiyaa
       
  2108 			MWK	Kwachas
       
  2109 			MXN	Pesos
       
  2110 			MYR	Ringgits
       
  2111 			MZM	Meticais
       
  2112 			NAD	Dollars
       
  2113 			NGN	Nairas
       
  2114 			NIO	Gold Cordobas
       
  2115 			NLG	Guilders
       
  2116 			NOK	Krone
       
  2117 			NPR	Nepal Rupees
       
  2118 			NZD	Dollars
       
  2119 			OMR	Rials
       
  2120 			PAB	Balboa
       
  2121 			PEN	Nuevos Soles
       
  2122 			PGK	Kina
       
  2123 			PHP	Pesos
       
  2124 			PKR	Rupees
       
  2125 			PLN	Zlotych
       
  2126 			PTE	Escudos
       
  2127 			PYG	Guarani
       
  2128 			QAR	Rials
       
  2129 			ROL	Lei
       
  2130 			RUR	Rubles
       
  2131 			RWF	Rwanda Francs
       
  2132 			SAR	Riyals
       
  2133 			SBD	Dollars
       
  2134 			SCR	Rupees
       
  2135 			SDD	Dinars
       
  2136 			SEK	Kronor
       
  2137 			SGD	Dollars
       
  2138 			SHP	Pounds
       
  2139 			SIT	Tolars
       
  2140 			SKK	Koruny
       
  2141 			SLL	Leones
       
  2142 			SOS	Shillings
       
  2143 			SPL	Luigini
       
  2144 			SRG	Guilders
       
  2145 			STD	Dobras
       
  2146 			SVC	Colones
       
  2147 			SYP	Pounds
       
  2148 			SZL	Emalangeni
       
  2149 			THB	Baht
       
  2150 			TJR	Rubles
       
  2151 			TMM	Manats
       
  2152 			TND	Dinars
       
  2153 			TOP	Pa'anga
       
  2154 			TRL	Liras
       
  2155 			TTD	Dollars
       
  2156 			TVD	Tuvalu Dollars
       
  2157 			TWD	New Dollars
       
  2158 			TZS	Shillings
       
  2159 			UAH	Hryvnia
       
  2160 			UGX	Shillings
       
  2161 			USD	Dollars
       
  2162 			UYU	Pesos
       
  2163 			UZS	Sums
       
  2164 			VAL	Lire
       
  2165 			VEB	Bolivares
       
  2166 			VND	Dong
       
  2167 			VUV	Vatu
       
  2168 			WST	Tala
       
  2169 			XAF	Francs
       
  2170 			XAG	Ounces
       
  2171 			XAU	Ounces
       
  2172 			XCD	Dollars
       
  2173 			XDR	Special Drawing Rights
       
  2174 			XPD	Ounces
       
  2175 			XPF	Francs
       
  2176 			XPT	Ounces
       
  2177 			YER	Rials
       
  2178 			YUM	New Dinars
       
  2179 			ZAR	Rand
       
  2180 			ZMK	Kwacha
       
  2181 			ZWD	Zimbabwe Dollars
       
  2182 
       
  2183 		*/
       
  2184 
       
  2185 		return getid3_lib::EmbeddedLookup($currencyid, $begin, __LINE__, __FILE__, 'id3v2-currency-units');
       
  2186 	}
       
  2187 
       
  2188 
       
  2189 	public function LookupCurrencyCountry($currencyid) {
       
  2190 
       
  2191 		$begin = __LINE__;
       
  2192 
       
  2193 		/** This is not a comment!
       
  2194 
       
  2195 			AED	United Arab Emirates
       
  2196 			AFA	Afghanistan
       
  2197 			ALL	Albania
       
  2198 			AMD	Armenia
       
  2199 			ANG	Netherlands Antilles
       
  2200 			AOA	Angola
       
  2201 			ARS	Argentina
       
  2202 			ATS	Austria
       
  2203 			AUD	Australia
       
  2204 			AWG	Aruba
       
  2205 			AZM	Azerbaijan
       
  2206 			BAM	Bosnia and Herzegovina
       
  2207 			BBD	Barbados
       
  2208 			BDT	Bangladesh
       
  2209 			BEF	Belgium
       
  2210 			BGL	Bulgaria
       
  2211 			BHD	Bahrain
       
  2212 			BIF	Burundi
       
  2213 			BMD	Bermuda
       
  2214 			BND	Brunei Darussalam
       
  2215 			BOB	Bolivia
       
  2216 			BRL	Brazil
       
  2217 			BSD	Bahamas
       
  2218 			BTN	Bhutan
       
  2219 			BWP	Botswana
       
  2220 			BYR	Belarus
       
  2221 			BZD	Belize
       
  2222 			CAD	Canada
       
  2223 			CDF	Congo/Kinshasa
       
  2224 			CHF	Switzerland
       
  2225 			CLP	Chile
       
  2226 			CNY	China
       
  2227 			COP	Colombia
       
  2228 			CRC	Costa Rica
       
  2229 			CUP	Cuba
       
  2230 			CVE	Cape Verde
       
  2231 			CYP	Cyprus
       
  2232 			CZK	Czech Republic
       
  2233 			DEM	Germany
       
  2234 			DJF	Djibouti
       
  2235 			DKK	Denmark
       
  2236 			DOP	Dominican Republic
       
  2237 			DZD	Algeria
       
  2238 			EEK	Estonia
       
  2239 			EGP	Egypt
       
  2240 			ERN	Eritrea
       
  2241 			ESP	Spain
       
  2242 			ETB	Ethiopia
       
  2243 			EUR	Euro Member Countries
       
  2244 			FIM	Finland
       
  2245 			FJD	Fiji
       
  2246 			FKP	Falkland Islands (Malvinas)
       
  2247 			FRF	France
       
  2248 			GBP	United Kingdom
       
  2249 			GEL	Georgia
       
  2250 			GGP	Guernsey
       
  2251 			GHC	Ghana
       
  2252 			GIP	Gibraltar
       
  2253 			GMD	Gambia
       
  2254 			GNF	Guinea
       
  2255 			GRD	Greece
       
  2256 			GTQ	Guatemala
       
  2257 			GYD	Guyana
       
  2258 			HKD	Hong Kong
       
  2259 			HNL	Honduras
       
  2260 			HRK	Croatia
       
  2261 			HTG	Haiti
       
  2262 			HUF	Hungary
       
  2263 			IDR	Indonesia
       
  2264 			IEP	Ireland (Eire)
       
  2265 			ILS	Israel
       
  2266 			IMP	Isle of Man
       
  2267 			INR	India
       
  2268 			IQD	Iraq
       
  2269 			IRR	Iran
       
  2270 			ISK	Iceland
       
  2271 			ITL	Italy
       
  2272 			JEP	Jersey
       
  2273 			JMD	Jamaica
       
  2274 			JOD	Jordan
       
  2275 			JPY	Japan
       
  2276 			KES	Kenya
       
  2277 			KGS	Kyrgyzstan
       
  2278 			KHR	Cambodia
       
  2279 			KMF	Comoros
       
  2280 			KPW	Korea
       
  2281 			KWD	Kuwait
       
  2282 			KYD	Cayman Islands
       
  2283 			KZT	Kazakstan
       
  2284 			LAK	Laos
       
  2285 			LBP	Lebanon
       
  2286 			LKR	Sri Lanka
       
  2287 			LRD	Liberia
       
  2288 			LSL	Lesotho
       
  2289 			LTL	Lithuania
       
  2290 			LUF	Luxembourg
       
  2291 			LVL	Latvia
       
  2292 			LYD	Libya
       
  2293 			MAD	Morocco
       
  2294 			MDL	Moldova
       
  2295 			MGF	Madagascar
       
  2296 			MKD	Macedonia
       
  2297 			MMK	Myanmar (Burma)
       
  2298 			MNT	Mongolia
       
  2299 			MOP	Macau
       
  2300 			MRO	Mauritania
       
  2301 			MTL	Malta
       
  2302 			MUR	Mauritius
       
  2303 			MVR	Maldives (Maldive Islands)
       
  2304 			MWK	Malawi
       
  2305 			MXN	Mexico
       
  2306 			MYR	Malaysia
       
  2307 			MZM	Mozambique
       
  2308 			NAD	Namibia
       
  2309 			NGN	Nigeria
       
  2310 			NIO	Nicaragua
       
  2311 			NLG	Netherlands (Holland)
       
  2312 			NOK	Norway
       
  2313 			NPR	Nepal
       
  2314 			NZD	New Zealand
       
  2315 			OMR	Oman
       
  2316 			PAB	Panama
       
  2317 			PEN	Peru
       
  2318 			PGK	Papua New Guinea
       
  2319 			PHP	Philippines
       
  2320 			PKR	Pakistan
       
  2321 			PLN	Poland
       
  2322 			PTE	Portugal
       
  2323 			PYG	Paraguay
       
  2324 			QAR	Qatar
       
  2325 			ROL	Romania
       
  2326 			RUR	Russia
       
  2327 			RWF	Rwanda
       
  2328 			SAR	Saudi Arabia
       
  2329 			SBD	Solomon Islands
       
  2330 			SCR	Seychelles
       
  2331 			SDD	Sudan
       
  2332 			SEK	Sweden
       
  2333 			SGD	Singapore
       
  2334 			SHP	Saint Helena
       
  2335 			SIT	Slovenia
       
  2336 			SKK	Slovakia
       
  2337 			SLL	Sierra Leone
       
  2338 			SOS	Somalia
       
  2339 			SPL	Seborga
       
  2340 			SRG	Suriname
       
  2341 			STD	São Tome and Principe
       
  2342 			SVC	El Salvador
       
  2343 			SYP	Syria
       
  2344 			SZL	Swaziland
       
  2345 			THB	Thailand
       
  2346 			TJR	Tajikistan
       
  2347 			TMM	Turkmenistan
       
  2348 			TND	Tunisia
       
  2349 			TOP	Tonga
       
  2350 			TRL	Turkey
       
  2351 			TTD	Trinidad and Tobago
       
  2352 			TVD	Tuvalu
       
  2353 			TWD	Taiwan
       
  2354 			TZS	Tanzania
       
  2355 			UAH	Ukraine
       
  2356 			UGX	Uganda
       
  2357 			USD	United States of America
       
  2358 			UYU	Uruguay
       
  2359 			UZS	Uzbekistan
       
  2360 			VAL	Vatican City
       
  2361 			VEB	Venezuela
       
  2362 			VND	Viet Nam
       
  2363 			VUV	Vanuatu
       
  2364 			WST	Samoa
       
  2365 			XAF	Communauté Financière Africaine
       
  2366 			XAG	Silver
       
  2367 			XAU	Gold
       
  2368 			XCD	East Caribbean
       
  2369 			XDR	International Monetary Fund
       
  2370 			XPD	Palladium
       
  2371 			XPF	Comptoirs Français du Pacifique
       
  2372 			XPT	Platinum
       
  2373 			YER	Yemen
       
  2374 			YUM	Yugoslavia
       
  2375 			ZAR	South Africa
       
  2376 			ZMK	Zambia
       
  2377 			ZWD	Zimbabwe
       
  2378 
       
  2379 		*/
       
  2380 
       
  2381 		return getid3_lib::EmbeddedLookup($currencyid, $begin, __LINE__, __FILE__, 'id3v2-currency-country');
       
  2382 	}
       
  2383 
       
  2384 
       
  2385 
       
  2386 	public static function LanguageLookup($languagecode, $casesensitive=false) {
       
  2387 
       
  2388 		if (!$casesensitive) {
       
  2389 			$languagecode = strtolower($languagecode);
       
  2390 		}
       
  2391 
       
  2392 		// http://www.id3.org/id3v2.4.0-structure.txt
       
  2393 		// [4.   ID3v2 frame overview]
       
  2394 		// The three byte language field, present in several frames, is used to
       
  2395 		// describe the language of the frame's content, according to ISO-639-2
       
  2396 		// [ISO-639-2]. The language should be represented in lower case. If the
       
  2397 		// language is not known the string "XXX" should be used.
       
  2398 
       
  2399 
       
  2400 		// ISO 639-2 - http://www.id3.org/iso639-2.html
       
  2401 
       
  2402 		$begin = __LINE__;
       
  2403 
       
  2404 		/** This is not a comment!
       
  2405 
       
  2406 			XXX	unknown
       
  2407 			xxx	unknown
       
  2408 			aar	Afar
       
  2409 			abk	Abkhazian
       
  2410 			ace	Achinese
       
  2411 			ach	Acoli
       
  2412 			ada	Adangme
       
  2413 			afa	Afro-Asiatic (Other)
       
  2414 			afh	Afrihili
       
  2415 			afr	Afrikaans
       
  2416 			aka	Akan
       
  2417 			akk	Akkadian
       
  2418 			alb	Albanian
       
  2419 			ale	Aleut
       
  2420 			alg	Algonquian Languages
       
  2421 			amh	Amharic
       
  2422 			ang	English, Old (ca. 450-1100)
       
  2423 			apa	Apache Languages
       
  2424 			ara	Arabic
       
  2425 			arc	Aramaic
       
  2426 			arm	Armenian
       
  2427 			arn	Araucanian
       
  2428 			arp	Arapaho
       
  2429 			art	Artificial (Other)
       
  2430 			arw	Arawak
       
  2431 			asm	Assamese
       
  2432 			ath	Athapascan Languages
       
  2433 			ava	Avaric
       
  2434 			ave	Avestan
       
  2435 			awa	Awadhi
       
  2436 			aym	Aymara
       
  2437 			aze	Azerbaijani
       
  2438 			bad	Banda
       
  2439 			bai	Bamileke Languages
       
  2440 			bak	Bashkir
       
  2441 			bal	Baluchi
       
  2442 			bam	Bambara
       
  2443 			ban	Balinese
       
  2444 			baq	Basque
       
  2445 			bas	Basa
       
  2446 			bat	Baltic (Other)
       
  2447 			bej	Beja
       
  2448 			bel	Byelorussian
       
  2449 			bem	Bemba
       
  2450 			ben	Bengali
       
  2451 			ber	Berber (Other)
       
  2452 			bho	Bhojpuri
       
  2453 			bih	Bihari
       
  2454 			bik	Bikol
       
  2455 			bin	Bini
       
  2456 			bis	Bislama
       
  2457 			bla	Siksika
       
  2458 			bnt	Bantu (Other)
       
  2459 			bod	Tibetan
       
  2460 			bra	Braj
       
  2461 			bre	Breton
       
  2462 			bua	Buriat
       
  2463 			bug	Buginese
       
  2464 			bul	Bulgarian
       
  2465 			bur	Burmese
       
  2466 			cad	Caddo
       
  2467 			cai	Central American Indian (Other)
       
  2468 			car	Carib
       
  2469 			cat	Catalan
       
  2470 			cau	Caucasian (Other)
       
  2471 			ceb	Cebuano
       
  2472 			cel	Celtic (Other)
       
  2473 			ces	Czech
       
  2474 			cha	Chamorro
       
  2475 			chb	Chibcha
       
  2476 			che	Chechen
       
  2477 			chg	Chagatai
       
  2478 			chi	Chinese
       
  2479 			chm	Mari
       
  2480 			chn	Chinook jargon
       
  2481 			cho	Choctaw
       
  2482 			chr	Cherokee
       
  2483 			chu	Church Slavic
       
  2484 			chv	Chuvash
       
  2485 			chy	Cheyenne
       
  2486 			cop	Coptic
       
  2487 			cor	Cornish
       
  2488 			cos	Corsican
       
  2489 			cpe	Creoles and Pidgins, English-based (Other)
       
  2490 			cpf	Creoles and Pidgins, French-based (Other)
       
  2491 			cpp	Creoles and Pidgins, Portuguese-based (Other)
       
  2492 			cre	Cree
       
  2493 			crp	Creoles and Pidgins (Other)
       
  2494 			cus	Cushitic (Other)
       
  2495 			cym	Welsh
       
  2496 			cze	Czech
       
  2497 			dak	Dakota
       
  2498 			dan	Danish
       
  2499 			del	Delaware
       
  2500 			deu	German
       
  2501 			din	Dinka
       
  2502 			div	Divehi
       
  2503 			doi	Dogri
       
  2504 			dra	Dravidian (Other)
       
  2505 			dua	Duala
       
  2506 			dum	Dutch, Middle (ca. 1050-1350)
       
  2507 			dut	Dutch
       
  2508 			dyu	Dyula
       
  2509 			dzo	Dzongkha
       
  2510 			efi	Efik
       
  2511 			egy	Egyptian (Ancient)
       
  2512 			eka	Ekajuk
       
  2513 			ell	Greek, Modern (1453-)
       
  2514 			elx	Elamite
       
  2515 			eng	English
       
  2516 			enm	English, Middle (ca. 1100-1500)
       
  2517 			epo	Esperanto
       
  2518 			esk	Eskimo (Other)
       
  2519 			esl	Spanish
       
  2520 			est	Estonian
       
  2521 			eus	Basque
       
  2522 			ewe	Ewe
       
  2523 			ewo	Ewondo
       
  2524 			fan	Fang
       
  2525 			fao	Faroese
       
  2526 			fas	Persian
       
  2527 			fat	Fanti
       
  2528 			fij	Fijian
       
  2529 			fin	Finnish
       
  2530 			fiu	Finno-Ugrian (Other)
       
  2531 			fon	Fon
       
  2532 			fra	French
       
  2533 			fre	French
       
  2534 			frm	French, Middle (ca. 1400-1600)
       
  2535 			fro	French, Old (842- ca. 1400)
       
  2536 			fry	Frisian
       
  2537 			ful	Fulah
       
  2538 			gaa	Ga
       
  2539 			gae	Gaelic (Scots)
       
  2540 			gai	Irish
       
  2541 			gay	Gayo
       
  2542 			gdh	Gaelic (Scots)
       
  2543 			gem	Germanic (Other)
       
  2544 			geo	Georgian
       
  2545 			ger	German
       
  2546 			gez	Geez
       
  2547 			gil	Gilbertese
       
  2548 			glg	Gallegan
       
  2549 			gmh	German, Middle High (ca. 1050-1500)
       
  2550 			goh	German, Old High (ca. 750-1050)
       
  2551 			gon	Gondi
       
  2552 			got	Gothic
       
  2553 			grb	Grebo
       
  2554 			grc	Greek, Ancient (to 1453)
       
  2555 			gre	Greek, Modern (1453-)
       
  2556 			grn	Guarani
       
  2557 			guj	Gujarati
       
  2558 			hai	Haida
       
  2559 			hau	Hausa
       
  2560 			haw	Hawaiian
       
  2561 			heb	Hebrew
       
  2562 			her	Herero
       
  2563 			hil	Hiligaynon
       
  2564 			him	Himachali
       
  2565 			hin	Hindi
       
  2566 			hmo	Hiri Motu
       
  2567 			hun	Hungarian
       
  2568 			hup	Hupa
       
  2569 			hye	Armenian
       
  2570 			iba	Iban
       
  2571 			ibo	Igbo
       
  2572 			ice	Icelandic
       
  2573 			ijo	Ijo
       
  2574 			iku	Inuktitut
       
  2575 			ilo	Iloko
       
  2576 			ina	Interlingua (International Auxiliary language Association)
       
  2577 			inc	Indic (Other)
       
  2578 			ind	Indonesian
       
  2579 			ine	Indo-European (Other)
       
  2580 			ine	Interlingue
       
  2581 			ipk	Inupiak
       
  2582 			ira	Iranian (Other)
       
  2583 			iri	Irish
       
  2584 			iro	Iroquoian uages
       
  2585 			isl	Icelandic
       
  2586 			ita	Italian
       
  2587 			jav	Javanese
       
  2588 			jaw	Javanese
       
  2589 			jpn	Japanese
       
  2590 			jpr	Judeo-Persian
       
  2591 			jrb	Judeo-Arabic
       
  2592 			kaa	Kara-Kalpak
       
  2593 			kab	Kabyle
       
  2594 			kac	Kachin
       
  2595 			kal	Greenlandic
       
  2596 			kam	Kamba
       
  2597 			kan	Kannada
       
  2598 			kar	Karen
       
  2599 			kas	Kashmiri
       
  2600 			kat	Georgian
       
  2601 			kau	Kanuri
       
  2602 			kaw	Kawi
       
  2603 			kaz	Kazakh
       
  2604 			kha	Khasi
       
  2605 			khi	Khoisan (Other)
       
  2606 			khm	Khmer
       
  2607 			kho	Khotanese
       
  2608 			kik	Kikuyu
       
  2609 			kin	Kinyarwanda
       
  2610 			kir	Kirghiz
       
  2611 			kok	Konkani
       
  2612 			kom	Komi
       
  2613 			kon	Kongo
       
  2614 			kor	Korean
       
  2615 			kpe	Kpelle
       
  2616 			kro	Kru
       
  2617 			kru	Kurukh
       
  2618 			kua	Kuanyama
       
  2619 			kum	Kumyk
       
  2620 			kur	Kurdish
       
  2621 			kus	Kusaie
       
  2622 			kut	Kutenai
       
  2623 			lad	Ladino
       
  2624 			lah	Lahnda
       
  2625 			lam	Lamba
       
  2626 			lao	Lao
       
  2627 			lat	Latin
       
  2628 			lav	Latvian
       
  2629 			lez	Lezghian
       
  2630 			lin	Lingala
       
  2631 			lit	Lithuanian
       
  2632 			lol	Mongo
       
  2633 			loz	Lozi
       
  2634 			ltz	Letzeburgesch
       
  2635 			lub	Luba-Katanga
       
  2636 			lug	Ganda
       
  2637 			lui	Luiseno
       
  2638 			lun	Lunda
       
  2639 			luo	Luo (Kenya and Tanzania)
       
  2640 			mac	Macedonian
       
  2641 			mad	Madurese
       
  2642 			mag	Magahi
       
  2643 			mah	Marshall
       
  2644 			mai	Maithili
       
  2645 			mak	Macedonian
       
  2646 			mak	Makasar
       
  2647 			mal	Malayalam
       
  2648 			man	Mandingo
       
  2649 			mao	Maori
       
  2650 			map	Austronesian (Other)
       
  2651 			mar	Marathi
       
  2652 			mas	Masai
       
  2653 			max	Manx
       
  2654 			may	Malay
       
  2655 			men	Mende
       
  2656 			mga	Irish, Middle (900 - 1200)
       
  2657 			mic	Micmac
       
  2658 			min	Minangkabau
       
  2659 			mis	Miscellaneous (Other)
       
  2660 			mkh	Mon-Kmer (Other)
       
  2661 			mlg	Malagasy
       
  2662 			mlt	Maltese
       
  2663 			mni	Manipuri
       
  2664 			mno	Manobo Languages
       
  2665 			moh	Mohawk
       
  2666 			mol	Moldavian
       
  2667 			mon	Mongolian
       
  2668 			mos	Mossi
       
  2669 			mri	Maori
       
  2670 			msa	Malay
       
  2671 			mul	Multiple Languages
       
  2672 			mun	Munda Languages
       
  2673 			mus	Creek
       
  2674 			mwr	Marwari
       
  2675 			mya	Burmese
       
  2676 			myn	Mayan Languages
       
  2677 			nah	Aztec
       
  2678 			nai	North American Indian (Other)
       
  2679 			nau	Nauru
       
  2680 			nav	Navajo
       
  2681 			nbl	Ndebele, South
       
  2682 			nde	Ndebele, North
       
  2683 			ndo	Ndongo
       
  2684 			nep	Nepali
       
  2685 			new	Newari
       
  2686 			nic	Niger-Kordofanian (Other)
       
  2687 			niu	Niuean
       
  2688 			nla	Dutch
       
  2689 			nno	Norwegian (Nynorsk)
       
  2690 			non	Norse, Old
       
  2691 			nor	Norwegian
       
  2692 			nso	Sotho, Northern
       
  2693 			nub	Nubian Languages
       
  2694 			nya	Nyanja
       
  2695 			nym	Nyamwezi
       
  2696 			nyn	Nyankole
       
  2697 			nyo	Nyoro
       
  2698 			nzi	Nzima
       
  2699 			oci	Langue d'Oc (post 1500)
       
  2700 			oji	Ojibwa
       
  2701 			ori	Oriya
       
  2702 			orm	Oromo
       
  2703 			osa	Osage
       
  2704 			oss	Ossetic
       
  2705 			ota	Turkish, Ottoman (1500 - 1928)
       
  2706 			oto	Otomian Languages
       
  2707 			paa	Papuan-Australian (Other)
       
  2708 			pag	Pangasinan
       
  2709 			pal	Pahlavi
       
  2710 			pam	Pampanga
       
  2711 			pan	Panjabi
       
  2712 			pap	Papiamento
       
  2713 			pau	Palauan
       
  2714 			peo	Persian, Old (ca 600 - 400 B.C.)
       
  2715 			per	Persian
       
  2716 			phn	Phoenician
       
  2717 			pli	Pali
       
  2718 			pol	Polish
       
  2719 			pon	Ponape
       
  2720 			por	Portuguese
       
  2721 			pra	Prakrit uages
       
  2722 			pro	Provencal, Old (to 1500)
       
  2723 			pus	Pushto
       
  2724 			que	Quechua
       
  2725 			raj	Rajasthani
       
  2726 			rar	Rarotongan
       
  2727 			roa	Romance (Other)
       
  2728 			roh	Rhaeto-Romance
       
  2729 			rom	Romany
       
  2730 			ron	Romanian
       
  2731 			rum	Romanian
       
  2732 			run	Rundi
       
  2733 			rus	Russian
       
  2734 			sad	Sandawe
       
  2735 			sag	Sango
       
  2736 			sah	Yakut
       
  2737 			sai	South American Indian (Other)
       
  2738 			sal	Salishan Languages
       
  2739 			sam	Samaritan Aramaic
       
  2740 			san	Sanskrit
       
  2741 			sco	Scots
       
  2742 			scr	Serbo-Croatian
       
  2743 			sel	Selkup
       
  2744 			sem	Semitic (Other)
       
  2745 			sga	Irish, Old (to 900)
       
  2746 			shn	Shan
       
  2747 			sid	Sidamo
       
  2748 			sin	Singhalese
       
  2749 			sio	Siouan Languages
       
  2750 			sit	Sino-Tibetan (Other)
       
  2751 			sla	Slavic (Other)
       
  2752 			slk	Slovak
       
  2753 			slo	Slovak
       
  2754 			slv	Slovenian
       
  2755 			smi	Sami Languages
       
  2756 			smo	Samoan
       
  2757 			sna	Shona
       
  2758 			snd	Sindhi
       
  2759 			sog	Sogdian
       
  2760 			som	Somali
       
  2761 			son	Songhai
       
  2762 			sot	Sotho, Southern
       
  2763 			spa	Spanish
       
  2764 			sqi	Albanian
       
  2765 			srd	Sardinian
       
  2766 			srr	Serer
       
  2767 			ssa	Nilo-Saharan (Other)
       
  2768 			ssw	Siswant
       
  2769 			ssw	Swazi
       
  2770 			suk	Sukuma
       
  2771 			sun	Sudanese
       
  2772 			sus	Susu
       
  2773 			sux	Sumerian
       
  2774 			sve	Swedish
       
  2775 			swa	Swahili
       
  2776 			swe	Swedish
       
  2777 			syr	Syriac
       
  2778 			tah	Tahitian
       
  2779 			tam	Tamil
       
  2780 			tat	Tatar
       
  2781 			tel	Telugu
       
  2782 			tem	Timne
       
  2783 			ter	Tereno
       
  2784 			tgk	Tajik
       
  2785 			tgl	Tagalog
       
  2786 			tha	Thai
       
  2787 			tib	Tibetan
       
  2788 			tig	Tigre
       
  2789 			tir	Tigrinya
       
  2790 			tiv	Tivi
       
  2791 			tli	Tlingit
       
  2792 			tmh	Tamashek
       
  2793 			tog	Tonga (Nyasa)
       
  2794 			ton	Tonga (Tonga Islands)
       
  2795 			tru	Truk
       
  2796 			tsi	Tsimshian
       
  2797 			tsn	Tswana
       
  2798 			tso	Tsonga
       
  2799 			tuk	Turkmen
       
  2800 			tum	Tumbuka
       
  2801 			tur	Turkish
       
  2802 			tut	Altaic (Other)
       
  2803 			twi	Twi
       
  2804 			tyv	Tuvinian
       
  2805 			uga	Ugaritic
       
  2806 			uig	Uighur
       
  2807 			ukr	Ukrainian
       
  2808 			umb	Umbundu
       
  2809 			und	Undetermined
       
  2810 			urd	Urdu
       
  2811 			uzb	Uzbek
       
  2812 			vai	Vai
       
  2813 			ven	Venda
       
  2814 			vie	Vietnamese
       
  2815 			vol	Volapük
       
  2816 			vot	Votic
       
  2817 			wak	Wakashan Languages
       
  2818 			wal	Walamo
       
  2819 			war	Waray
       
  2820 			was	Washo
       
  2821 			wel	Welsh
       
  2822 			wen	Sorbian Languages
       
  2823 			wol	Wolof
       
  2824 			xho	Xhosa
       
  2825 			yao	Yao
       
  2826 			yap	Yap
       
  2827 			yid	Yiddish
       
  2828 			yor	Yoruba
       
  2829 			zap	Zapotec
       
  2830 			zen	Zenaga
       
  2831 			zha	Zhuang
       
  2832 			zho	Chinese
       
  2833 			zul	Zulu
       
  2834 			zun	Zuni
       
  2835 
       
  2836 		*/
       
  2837 
       
  2838 		return getid3_lib::EmbeddedLookup($languagecode, $begin, __LINE__, __FILE__, 'id3v2-languagecode');
       
  2839 	}
       
  2840 
       
  2841 
       
  2842 	public static function ETCOEventLookup($index) {
       
  2843 		if (($index >= 0x17) && ($index <= 0xDF)) {
       
  2844 			return 'reserved for future use';
       
  2845 		}
       
  2846 		if (($index >= 0xE0) && ($index <= 0xEF)) {
       
  2847 			return 'not predefined synch 0-F';
       
  2848 		}
       
  2849 		if (($index >= 0xF0) && ($index <= 0xFC)) {
       
  2850 			return 'reserved for future use';
       
  2851 		}
       
  2852 
       
  2853 		static $EventLookup = array(
       
  2854 			0x00 => 'padding (has no meaning)',
       
  2855 			0x01 => 'end of initial silence',
       
  2856 			0x02 => 'intro start',
       
  2857 			0x03 => 'main part start',
       
  2858 			0x04 => 'outro start',
       
  2859 			0x05 => 'outro end',
       
  2860 			0x06 => 'verse start',
       
  2861 			0x07 => 'refrain start',
       
  2862 			0x08 => 'interlude start',
       
  2863 			0x09 => 'theme start',
       
  2864 			0x0A => 'variation start',
       
  2865 			0x0B => 'key change',
       
  2866 			0x0C => 'time change',
       
  2867 			0x0D => 'momentary unwanted noise (Snap, Crackle & Pop)',
       
  2868 			0x0E => 'sustained noise',
       
  2869 			0x0F => 'sustained noise end',
       
  2870 			0x10 => 'intro end',
       
  2871 			0x11 => 'main part end',
       
  2872 			0x12 => 'verse end',
       
  2873 			0x13 => 'refrain end',
       
  2874 			0x14 => 'theme end',
       
  2875 			0x15 => 'profanity',
       
  2876 			0x16 => 'profanity end',
       
  2877 			0xFD => 'audio end (start of silence)',
       
  2878 			0xFE => 'audio file ends',
       
  2879 			0xFF => 'one more byte of events follows'
       
  2880 		);
       
  2881 
       
  2882 		return (isset($EventLookup[$index]) ? $EventLookup[$index] : '');
       
  2883 	}
       
  2884 
       
  2885 	public static function SYTLContentTypeLookup($index) {
       
  2886 		static $SYTLContentTypeLookup = array(
       
  2887 			0x00 => 'other',
       
  2888 			0x01 => 'lyrics',
       
  2889 			0x02 => 'text transcription',
       
  2890 			0x03 => 'movement/part name', // (e.g. 'Adagio')
       
  2891 			0x04 => 'events',             // (e.g. 'Don Quijote enters the stage')
       
  2892 			0x05 => 'chord',              // (e.g. 'Bb F Fsus')
       
  2893 			0x06 => 'trivia/\'pop up\' information',
       
  2894 			0x07 => 'URLs to webpages',
       
  2895 			0x08 => 'URLs to images'
       
  2896 		);
       
  2897 
       
  2898 		return (isset($SYTLContentTypeLookup[$index]) ? $SYTLContentTypeLookup[$index] : '');
       
  2899 	}
       
  2900 
       
  2901 	public static function APICPictureTypeLookup($index, $returnarray=false) {
       
  2902 		static $APICPictureTypeLookup = array(
       
  2903 			0x00 => 'Other',
       
  2904 			0x01 => '32x32 pixels \'file icon\' (PNG only)',
       
  2905 			0x02 => 'Other file icon',
       
  2906 			0x03 => 'Cover (front)',
       
  2907 			0x04 => 'Cover (back)',
       
  2908 			0x05 => 'Leaflet page',
       
  2909 			0x06 => 'Media (e.g. label side of CD)',
       
  2910 			0x07 => 'Lead artist/lead performer/soloist',
       
  2911 			0x08 => 'Artist/performer',
       
  2912 			0x09 => 'Conductor',
       
  2913 			0x0A => 'Band/Orchestra',
       
  2914 			0x0B => 'Composer',
       
  2915 			0x0C => 'Lyricist/text writer',
       
  2916 			0x0D => 'Recording Location',
       
  2917 			0x0E => 'During recording',
       
  2918 			0x0F => 'During performance',
       
  2919 			0x10 => 'Movie/video screen capture',
       
  2920 			0x11 => 'A bright coloured fish',
       
  2921 			0x12 => 'Illustration',
       
  2922 			0x13 => 'Band/artist logotype',
       
  2923 			0x14 => 'Publisher/Studio logotype'
       
  2924 		);
       
  2925 		if ($returnarray) {
       
  2926 			return $APICPictureTypeLookup;
       
  2927 		}
       
  2928 		return (isset($APICPictureTypeLookup[$index]) ? $APICPictureTypeLookup[$index] : '');
       
  2929 	}
       
  2930 
       
  2931 	public static function COMRReceivedAsLookup($index) {
       
  2932 		static $COMRReceivedAsLookup = array(
       
  2933 			0x00 => 'Other',
       
  2934 			0x01 => 'Standard CD album with other songs',
       
  2935 			0x02 => 'Compressed audio on CD',
       
  2936 			0x03 => 'File over the Internet',
       
  2937 			0x04 => 'Stream over the Internet',
       
  2938 			0x05 => 'As note sheets',
       
  2939 			0x06 => 'As note sheets in a book with other sheets',
       
  2940 			0x07 => 'Music on other media',
       
  2941 			0x08 => 'Non-musical merchandise'
       
  2942 		);
       
  2943 
       
  2944 		return (isset($COMRReceivedAsLookup[$index]) ? $COMRReceivedAsLookup[$index] : '');
       
  2945 	}
       
  2946 
       
  2947 	public static function RVA2ChannelTypeLookup($index) {
       
  2948 		static $RVA2ChannelTypeLookup = array(
       
  2949 			0x00 => 'Other',
       
  2950 			0x01 => 'Master volume',
       
  2951 			0x02 => 'Front right',
       
  2952 			0x03 => 'Front left',
       
  2953 			0x04 => 'Back right',
       
  2954 			0x05 => 'Back left',
       
  2955 			0x06 => 'Front centre',
       
  2956 			0x07 => 'Back centre',
       
  2957 			0x08 => 'Subwoofer'
       
  2958 		);
       
  2959 
       
  2960 		return (isset($RVA2ChannelTypeLookup[$index]) ? $RVA2ChannelTypeLookup[$index] : '');
       
  2961 	}
       
  2962 
       
  2963 	public static function FrameNameLongLookup($framename) {
       
  2964 
       
  2965 		$begin = __LINE__;
       
  2966 
       
  2967 		/** This is not a comment!
       
  2968 
       
  2969 			AENC	Audio encryption
       
  2970 			APIC	Attached picture
       
  2971 			ASPI	Audio seek point index
       
  2972 			BUF	Recommended buffer size
       
  2973 			CNT	Play counter
       
  2974 			COM	Comments
       
  2975 			COMM	Comments
       
  2976 			COMR	Commercial frame
       
  2977 			CRA	Audio encryption
       
  2978 			CRM	Encrypted meta frame
       
  2979 			ENCR	Encryption method registration
       
  2980 			EQU	Equalisation
       
  2981 			EQU2	Equalisation (2)
       
  2982 			EQUA	Equalisation
       
  2983 			ETC	Event timing codes
       
  2984 			ETCO	Event timing codes
       
  2985 			GEO	General encapsulated object
       
  2986 			GEOB	General encapsulated object
       
  2987 			GRID	Group identification registration
       
  2988 			IPL	Involved people list
       
  2989 			IPLS	Involved people list
       
  2990 			LINK	Linked information
       
  2991 			LNK	Linked information
       
  2992 			MCDI	Music CD identifier
       
  2993 			MCI	Music CD Identifier
       
  2994 			MLL	MPEG location lookup table
       
  2995 			MLLT	MPEG location lookup table
       
  2996 			OWNE	Ownership frame
       
  2997 			PCNT	Play counter
       
  2998 			PIC	Attached picture
       
  2999 			POP	Popularimeter
       
  3000 			POPM	Popularimeter
       
  3001 			POSS	Position synchronisation frame
       
  3002 			PRIV	Private frame
       
  3003 			RBUF	Recommended buffer size
       
  3004 			REV	Reverb
       
  3005 			RVA	Relative volume adjustment
       
  3006 			RVA2	Relative volume adjustment (2)
       
  3007 			RVAD	Relative volume adjustment
       
  3008 			RVRB	Reverb
       
  3009 			SEEK	Seek frame
       
  3010 			SIGN	Signature frame
       
  3011 			SLT	Synchronised lyric/text
       
  3012 			STC	Synced tempo codes
       
  3013 			SYLT	Synchronised lyric/text
       
  3014 			SYTC	Synchronised tempo codes
       
  3015 			TAL	Album/Movie/Show title
       
  3016 			TALB	Album/Movie/Show title
       
  3017 			TBP	BPM (Beats Per Minute)
       
  3018 			TBPM	BPM (beats per minute)
       
  3019 			TCM	Composer
       
  3020 			TCMP	Part of a compilation
       
  3021 			TCO	Content type
       
  3022 			TCOM	Composer
       
  3023 			TCON	Content type
       
  3024 			TCOP	Copyright message
       
  3025 			TCP	Part of a compilation
       
  3026 			TCR	Copyright message
       
  3027 			TDA	Date
       
  3028 			TDAT	Date
       
  3029 			TDEN	Encoding time
       
  3030 			TDLY	Playlist delay
       
  3031 			TDOR	Original release time
       
  3032 			TDRC	Recording time
       
  3033 			TDRL	Release time
       
  3034 			TDTG	Tagging time
       
  3035 			TDY	Playlist delay
       
  3036 			TEN	Encoded by
       
  3037 			TENC	Encoded by
       
  3038 			TEXT	Lyricist/Text writer
       
  3039 			TFLT	File type
       
  3040 			TFT	File type
       
  3041 			TIM	Time
       
  3042 			TIME	Time
       
  3043 			TIPL	Involved people list
       
  3044 			TIT1	Content group description
       
  3045 			TIT2	Title/songname/content description
       
  3046 			TIT3	Subtitle/Description refinement
       
  3047 			TKE	Initial key
       
  3048 			TKEY	Initial key
       
  3049 			TLA	Language(s)
       
  3050 			TLAN	Language(s)
       
  3051 			TLE	Length
       
  3052 			TLEN	Length
       
  3053 			TMCL	Musician credits list
       
  3054 			TMED	Media type
       
  3055 			TMOO	Mood
       
  3056 			TMT	Media type
       
  3057 			TOA	Original artist(s)/performer(s)
       
  3058 			TOAL	Original album/movie/show title
       
  3059 			TOF	Original filename
       
  3060 			TOFN	Original filename
       
  3061 			TOL	Original Lyricist(s)/text writer(s)
       
  3062 			TOLY	Original lyricist(s)/text writer(s)
       
  3063 			TOPE	Original artist(s)/performer(s)
       
  3064 			TOR	Original release year
       
  3065 			TORY	Original release year
       
  3066 			TOT	Original album/Movie/Show title
       
  3067 			TOWN	File owner/licensee
       
  3068 			TP1	Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group
       
  3069 			TP2	Band/Orchestra/Accompaniment
       
  3070 			TP3	Conductor/Performer refinement
       
  3071 			TP4	Interpreted, remixed, or otherwise modified by
       
  3072 			TPA	Part of a set
       
  3073 			TPB	Publisher
       
  3074 			TPE1	Lead performer(s)/Soloist(s)
       
  3075 			TPE2	Band/orchestra/accompaniment
       
  3076 			TPE3	Conductor/performer refinement
       
  3077 			TPE4	Interpreted, remixed, or otherwise modified by
       
  3078 			TPOS	Part of a set
       
  3079 			TPRO	Produced notice
       
  3080 			TPUB	Publisher
       
  3081 			TRC	ISRC (International Standard Recording Code)
       
  3082 			TRCK	Track number/Position in set
       
  3083 			TRD	Recording dates
       
  3084 			TRDA	Recording dates
       
  3085 			TRK	Track number/Position in set
       
  3086 			TRSN	Internet radio station name
       
  3087 			TRSO	Internet radio station owner
       
  3088 			TS2	Album-Artist sort order
       
  3089 			TSA	Album sort order
       
  3090 			TSC	Composer sort order
       
  3091 			TSI	Size
       
  3092 			TSIZ	Size
       
  3093 			TSO2	Album-Artist sort order
       
  3094 			TSOA	Album sort order
       
  3095 			TSOC	Composer sort order
       
  3096 			TSOP	Performer sort order
       
  3097 			TSOT	Title sort order
       
  3098 			TSP	Performer sort order
       
  3099 			TSRC	ISRC (international standard recording code)
       
  3100 			TSS	Software/hardware and settings used for encoding
       
  3101 			TSSE	Software/Hardware and settings used for encoding
       
  3102 			TSST	Set subtitle
       
  3103 			TST	Title sort order
       
  3104 			TT1	Content group description
       
  3105 			TT2	Title/Songname/Content description
       
  3106 			TT3	Subtitle/Description refinement
       
  3107 			TXT	Lyricist/text writer
       
  3108 			TXX	User defined text information frame
       
  3109 			TXXX	User defined text information frame
       
  3110 			TYE	Year
       
  3111 			TYER	Year
       
  3112 			UFI	Unique file identifier
       
  3113 			UFID	Unique file identifier
       
  3114 			ULT	Unsychronised lyric/text transcription
       
  3115 			USER	Terms of use
       
  3116 			USLT	Unsynchronised lyric/text transcription
       
  3117 			WAF	Official audio file webpage
       
  3118 			WAR	Official artist/performer webpage
       
  3119 			WAS	Official audio source webpage
       
  3120 			WCM	Commercial information
       
  3121 			WCOM	Commercial information
       
  3122 			WCOP	Copyright/Legal information
       
  3123 			WCP	Copyright/Legal information
       
  3124 			WOAF	Official audio file webpage
       
  3125 			WOAR	Official artist/performer webpage
       
  3126 			WOAS	Official audio source webpage
       
  3127 			WORS	Official Internet radio station homepage
       
  3128 			WPAY	Payment
       
  3129 			WPB	Publishers official webpage
       
  3130 			WPUB	Publishers official webpage
       
  3131 			WXX	User defined URL link frame
       
  3132 			WXXX	User defined URL link frame
       
  3133 			TFEA	Featured Artist
       
  3134 			TSTU	Recording Studio
       
  3135 			rgad	Replay Gain Adjustment
       
  3136 
       
  3137 		*/
       
  3138 
       
  3139 		return getid3_lib::EmbeddedLookup($framename, $begin, __LINE__, __FILE__, 'id3v2-framename_long');
       
  3140 
       
  3141 		// Last three:
       
  3142 		// from Helium2 [www.helium2.com]
       
  3143 		// from http://privatewww.essex.ac.uk/~djmrob/replaygain/file_format_id3v2.html
       
  3144 	}
       
  3145 
       
  3146 
       
  3147 	public static function FrameNameShortLookup($framename) {
       
  3148 
       
  3149 		$begin = __LINE__;
       
  3150 
       
  3151 		/** This is not a comment!
       
  3152 
       
  3153 			AENC	audio_encryption
       
  3154 			APIC	attached_picture
       
  3155 			ASPI	audio_seek_point_index
       
  3156 			BUF	recommended_buffer_size
       
  3157 			CNT	play_counter
       
  3158 			COM	comment
       
  3159 			COMM	comment
       
  3160 			COMR	commercial_frame
       
  3161 			CRA	audio_encryption
       
  3162 			CRM	encrypted_meta_frame
       
  3163 			ENCR	encryption_method_registration
       
  3164 			EQU	equalisation
       
  3165 			EQU2	equalisation
       
  3166 			EQUA	equalisation
       
  3167 			ETC	event_timing_codes
       
  3168 			ETCO	event_timing_codes
       
  3169 			GEO	general_encapsulated_object
       
  3170 			GEOB	general_encapsulated_object
       
  3171 			GRID	group_identification_registration
       
  3172 			IPL	involved_people_list
       
  3173 			IPLS	involved_people_list
       
  3174 			LINK	linked_information
       
  3175 			LNK	linked_information
       
  3176 			MCDI	music_cd_identifier
       
  3177 			MCI	music_cd_identifier
       
  3178 			MLL	mpeg_location_lookup_table
       
  3179 			MLLT	mpeg_location_lookup_table
       
  3180 			OWNE	ownership_frame
       
  3181 			PCNT	play_counter
       
  3182 			PIC	attached_picture
       
  3183 			POP	popularimeter
       
  3184 			POPM	popularimeter
       
  3185 			POSS	position_synchronisation_frame
       
  3186 			PRIV	private_frame
       
  3187 			RBUF	recommended_buffer_size
       
  3188 			REV	reverb
       
  3189 			RVA	relative_volume_adjustment
       
  3190 			RVA2	relative_volume_adjustment
       
  3191 			RVAD	relative_volume_adjustment
       
  3192 			RVRB	reverb
       
  3193 			SEEK	seek_frame
       
  3194 			SIGN	signature_frame
       
  3195 			SLT	synchronised_lyric
       
  3196 			STC	synced_tempo_codes
       
  3197 			SYLT	synchronised_lyric
       
  3198 			SYTC	synchronised_tempo_codes
       
  3199 			TAL	album
       
  3200 			TALB	album
       
  3201 			TBP	bpm
       
  3202 			TBPM	bpm
       
  3203 			TCM	composer
       
  3204 			TCMP	part_of_a_compilation
       
  3205 			TCO	genre
       
  3206 			TCOM	composer
       
  3207 			TCON	genre
       
  3208 			TCOP	copyright_message
       
  3209 			TCP	part_of_a_compilation
       
  3210 			TCR	copyright_message
       
  3211 			TDA	date
       
  3212 			TDAT	date
       
  3213 			TDEN	encoding_time
       
  3214 			TDLY	playlist_delay
       
  3215 			TDOR	original_release_time
       
  3216 			TDRC	recording_time
       
  3217 			TDRL	release_time
       
  3218 			TDTG	tagging_time
       
  3219 			TDY	playlist_delay
       
  3220 			TEN	encoded_by
       
  3221 			TENC	encoded_by
       
  3222 			TEXT	lyricist
       
  3223 			TFLT	file_type
       
  3224 			TFT	file_type
       
  3225 			TIM	time
       
  3226 			TIME	time
       
  3227 			TIPL	involved_people_list
       
  3228 			TIT1	content_group_description
       
  3229 			TIT2	title
       
  3230 			TIT3	subtitle
       
  3231 			TKE	initial_key
       
  3232 			TKEY	initial_key
       
  3233 			TLA	language
       
  3234 			TLAN	language
       
  3235 			TLE	length
       
  3236 			TLEN	length
       
  3237 			TMCL	musician_credits_list
       
  3238 			TMED	media_type
       
  3239 			TMOO	mood
       
  3240 			TMT	media_type
       
  3241 			TOA	original_artist
       
  3242 			TOAL	original_album
       
  3243 			TOF	original_filename
       
  3244 			TOFN	original_filename
       
  3245 			TOL	original_lyricist
       
  3246 			TOLY	original_lyricist
       
  3247 			TOPE	original_artist
       
  3248 			TOR	original_year
       
  3249 			TORY	original_year
       
  3250 			TOT	original_album
       
  3251 			TOWN	file_owner
       
  3252 			TP1	artist
       
  3253 			TP2	band
       
  3254 			TP3	conductor
       
  3255 			TP4	remixer
       
  3256 			TPA	part_of_a_set
       
  3257 			TPB	publisher
       
  3258 			TPE1	artist
       
  3259 			TPE2	band
       
  3260 			TPE3	conductor
       
  3261 			TPE4	remixer
       
  3262 			TPOS	part_of_a_set
       
  3263 			TPRO	produced_notice
       
  3264 			TPUB	publisher
       
  3265 			TRC	isrc
       
  3266 			TRCK	track_number
       
  3267 			TRD	recording_dates
       
  3268 			TRDA	recording_dates
       
  3269 			TRK	track_number
       
  3270 			TRSN	internet_radio_station_name
       
  3271 			TRSO	internet_radio_station_owner
       
  3272 			TS2	album_artist_sort_order
       
  3273 			TSA	album_sort_order
       
  3274 			TSC	composer_sort_order
       
  3275 			TSI	size
       
  3276 			TSIZ	size
       
  3277 			TSO2	album_artist_sort_order
       
  3278 			TSOA	album_sort_order
       
  3279 			TSOC	composer_sort_order
       
  3280 			TSOP	performer_sort_order
       
  3281 			TSOT	title_sort_order
       
  3282 			TSP	performer_sort_order
       
  3283 			TSRC	isrc
       
  3284 			TSS	encoder_settings
       
  3285 			TSSE	encoder_settings
       
  3286 			TSST	set_subtitle
       
  3287 			TST	title_sort_order
       
  3288 			TT1	content_group_description
       
  3289 			TT2	title
       
  3290 			TT3	subtitle
       
  3291 			TXT	lyricist
       
  3292 			TXX	text
       
  3293 			TXXX	text
       
  3294 			TYE	year
       
  3295 			TYER	year
       
  3296 			UFI	unique_file_identifier
       
  3297 			UFID	unique_file_identifier
       
  3298 			ULT	unsychronised_lyric
       
  3299 			USER	terms_of_use
       
  3300 			USLT	unsynchronised_lyric
       
  3301 			WAF	url_file
       
  3302 			WAR	url_artist
       
  3303 			WAS	url_source
       
  3304 			WCM	commercial_information
       
  3305 			WCOM	commercial_information
       
  3306 			WCOP	copyright
       
  3307 			WCP	copyright
       
  3308 			WOAF	url_file
       
  3309 			WOAR	url_artist
       
  3310 			WOAS	url_source
       
  3311 			WORS	url_station
       
  3312 			WPAY	url_payment
       
  3313 			WPB	url_publisher
       
  3314 			WPUB	url_publisher
       
  3315 			WXX	url_user
       
  3316 			WXXX	url_user
       
  3317 			TFEA	featured_artist
       
  3318 			TSTU	recording_studio
       
  3319 			rgad	replay_gain_adjustment
       
  3320 
       
  3321 		*/
       
  3322 
       
  3323 		return getid3_lib::EmbeddedLookup($framename, $begin, __LINE__, __FILE__, 'id3v2-framename_short');
       
  3324 	}
       
  3325 
       
  3326 	public static function TextEncodingTerminatorLookup($encoding) {
       
  3327 		// http://www.id3.org/id3v2.4.0-structure.txt
       
  3328 		// Frames that allow different types of text encoding contains a text encoding description byte. Possible encodings:
       
  3329 		static $TextEncodingTerminatorLookup = array(
       
  3330 			0   => "\x00",     // $00  ISO-8859-1. Terminated with $00.
       
  3331 			1   => "\x00\x00", // $01  UTF-16 encoded Unicode with BOM. All strings in the same frame SHALL have the same byteorder. Terminated with $00 00.
       
  3332 			2   => "\x00\x00", // $02  UTF-16BE encoded Unicode without BOM. Terminated with $00 00.
       
  3333 			3   => "\x00",     // $03  UTF-8 encoded Unicode. Terminated with $00.
       
  3334 			255 => "\x00\x00"
       
  3335 		);
       
  3336 		return (isset($TextEncodingTerminatorLookup[$encoding]) ? $TextEncodingTerminatorLookup[$encoding] : '');
       
  3337 	}
       
  3338 
       
  3339 	public static function TextEncodingNameLookup($encoding) {
       
  3340 		// http://www.id3.org/id3v2.4.0-structure.txt
       
  3341 		// Frames that allow different types of text encoding contains a text encoding description byte. Possible encodings:
       
  3342 		static $TextEncodingNameLookup = array(
       
  3343 			0   => 'ISO-8859-1', // $00  ISO-8859-1. Terminated with $00.
       
  3344 			1   => 'UTF-16',     // $01  UTF-16 encoded Unicode with BOM. All strings in the same frame SHALL have the same byteorder. Terminated with $00 00.
       
  3345 			2   => 'UTF-16BE',   // $02  UTF-16BE encoded Unicode without BOM. Terminated with $00 00.
       
  3346 			3   => 'UTF-8',      // $03  UTF-8 encoded Unicode. Terminated with $00.
       
  3347 			255 => 'UTF-16BE'
       
  3348 		);
       
  3349 		return (isset($TextEncodingNameLookup[$encoding]) ? $TextEncodingNameLookup[$encoding] : 'ISO-8859-1');
       
  3350 	}
       
  3351 
       
  3352 	public static function IsValidID3v2FrameName($framename, $id3v2majorversion) {
       
  3353 		switch ($id3v2majorversion) {
       
  3354 			case 2:
       
  3355 				return preg_match('#[A-Z][A-Z0-9]{2}#', $framename);
       
  3356 				break;
       
  3357 
       
  3358 			case 3:
       
  3359 			case 4:
       
  3360 				return preg_match('#[A-Z][A-Z0-9]{3}#', $framename);
       
  3361 				break;
       
  3362 		}
       
  3363 		return false;
       
  3364 	}
       
  3365 
       
  3366 	public static function IsANumber($numberstring, $allowdecimal=false, $allownegative=false) {
       
  3367 		for ($i = 0; $i < strlen($numberstring); $i++) {
       
  3368 			if ((chr($numberstring{$i}) < chr('0')) || (chr($numberstring{$i}) > chr('9'))) {
       
  3369 				if (($numberstring{$i} == '.') && $allowdecimal) {
       
  3370 					// allowed
       
  3371 				} elseif (($numberstring{$i} == '-') && $allownegative && ($i == 0)) {
       
  3372 					// allowed
       
  3373 				} else {
       
  3374 					return false;
       
  3375 				}
       
  3376 			}
       
  3377 		}
       
  3378 		return true;
       
  3379 	}
       
  3380 
       
  3381 	public static function IsValidDateStampString($datestamp) {
       
  3382 		if (strlen($datestamp) != 8) {
       
  3383 			return false;
       
  3384 		}
       
  3385 		if (!self::IsANumber($datestamp, false)) {
       
  3386 			return false;
       
  3387 		}
       
  3388 		$year  = substr($datestamp, 0, 4);
       
  3389 		$month = substr($datestamp, 4, 2);
       
  3390 		$day   = substr($datestamp, 6, 2);
       
  3391 		if (($year == 0) || ($month == 0) || ($day == 0)) {
       
  3392 			return false;
       
  3393 		}
       
  3394 		if ($month > 12) {
       
  3395 			return false;
       
  3396 		}
       
  3397 		if ($day > 31) {
       
  3398 			return false;
       
  3399 		}
       
  3400 		if (($day > 30) && (($month == 4) || ($month == 6) || ($month == 9) || ($month == 11))) {
       
  3401 			return false;
       
  3402 		}
       
  3403 		if (($day > 29) && ($month == 2)) {
       
  3404 			return false;
       
  3405 		}
       
  3406 		return true;
       
  3407 	}
       
  3408 
       
  3409 	public static function ID3v2HeaderLength($majorversion) {
       
  3410 		return (($majorversion == 2) ? 6 : 10);
       
  3411 	}
       
  3412 
       
  3413 }
       
  3414