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