/public/library/xinha/plugins/MootoolsFileManager/mootools-filemanager/Backend/Assets/getid3/module.tag.id3v2.php
PHP | 3280 lines | 2413 code | 448 blank | 419 comment | 514 complexity | b99db99587ced953cf875a1cba49d90e MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, BSD-3-Clause, LGPL-2.0, CC-BY-SA-3.0, MIT
Large files files are truncated, but you can click here to view the full file
- <?php
- // +----------------------------------------------------------------------+
- // | PHP version 5 |
- // +----------------------------------------------------------------------+
- // | Copyright (c) 2002-2006 James Heinrich, Allan Hansen |
- // +----------------------------------------------------------------------+
- // | This source file is subject to version 2 of the GPL license, |
- // | that is bundled with this package in the file license.txt and is |
- // | available through the world-wide-web at the following url: |
- // | http://www.gnu.org/copyleft/gpl.html |
- // +----------------------------------------------------------------------+
- // | getID3() - http://getid3.sourceforge.net or http://www.getid3.org |
- // +----------------------------------------------------------------------+
- // | Authors: James Heinrich <infoŘgetid3*org> |
- // | Allan Hansen <ahŘartemis*dk> |
- // +----------------------------------------------------------------------+
- // | module.tag.id3v2.php |
- // | module for analyzing ID3v2 tags |
- // | dependencies: module.tag.id3v1.php |
- // | module.lib.image_size.php (optional) |
- // | zlib support in PHP (optional) |
- // +----------------------------------------------------------------------+
- //
- // $Id: module.tag.id3v2.php,v 1.15 2006/12/03 23:47:29 ah Exp $
-
-
-
-
- class getid3_id3v2 extends getid3_handler
- {
-
- public $option_starting_offset = 0;
-
-
- public function Analyze() {
-
- $getid3 = $this->getid3;
-
- // dependency
- $getid3->include_module('tag.id3v1');
-
- if ($getid3->option_tags_images) {
- $getid3->include_module('lib.image_size');
- }
-
-
- // Overall tag structure:
- // +-----------------------------+
- // | Header (10 bytes) |
- // +-----------------------------+
- // | Extended Header |
- // | (variable length, OPTIONAL) |
- // +-----------------------------+
- // | Frames (variable length) |
- // +-----------------------------+
- // | Padding |
- // | (variable length, OPTIONAL) |
- // +-----------------------------+
- // | Footer (10 bytes, OPTIONAL) |
- // +-----------------------------+
- //
- // Header
- // ID3v2/file identifier "ID3"
- // ID3v2 version $04 00
- // ID3v2 flags (%ab000000 in v2.2, %abc00000 in v2.3, %abcd0000 in v2.4.x)
- // ID3v2 size 4 * %0xxxxxxx
-
-
- // shortcuts
- $getid3->info['id3v2']['header'] = true;
- $info_id3v2 = &$getid3->info['id3v2'];
- $info_id3v2['flags'] = array ();
- $info_id3v2_flags = &$info_id3v2['flags'];
-
-
- $this->fseek($this->option_starting_offset, SEEK_SET);
- $header = $this->fread(10);
- if (substr($header, 0, 3) == 'ID3' && strlen($header) == 10) {
-
- $info_id3v2['majorversion'] = ord($header{3});
- $info_id3v2['minorversion'] = ord($header{4});
-
- // shortcut
- $id3v2_major_version = &$info_id3v2['majorversion'];
-
- } else {
- unset($getid3->info['id3v2']);
- return false;
-
- }
-
- if ($id3v2_major_version > 4) { // this script probably won't correctly parse ID3v2.5.x and above (if it ever exists)
- throw new getid3_exception('this script only parses up to ID3v2.4.x - this tag is ID3v2.'.$id3v2_major_version.'.'.$info_id3v2['minorversion']);
- }
-
- $id3_flags = ord($header{5});
- switch ($id3v2_major_version) {
- case 2:
- // %ab000000 in v2.2
- $info_id3v2_flags['unsynch'] = (bool)($id3_flags & 0x80); // a - Unsynchronisation
- $info_id3v2_flags['compression'] = (bool)($id3_flags & 0x40); // b - Compression
- break;
-
- case 3:
- // %abc00000 in v2.3
- $info_id3v2_flags['unsynch'] = (bool)($id3_flags & 0x80); // a - Unsynchronisation
- $info_id3v2_flags['exthead'] = (bool)($id3_flags & 0x40); // b - Extended header
- $info_id3v2_flags['experim'] = (bool)($id3_flags & 0x20); // c - Experimental indicator
- break;
-
- case 4:
- // %abcd0000 in v2.4
- $info_id3v2_flags['unsynch'] = (bool)($id3_flags & 0x80); // a - Unsynchronisation
- $info_id3v2_flags['exthead'] = (bool)($id3_flags & 0x40); // b - Extended header
- $info_id3v2_flags['experim'] = (bool)($id3_flags & 0x20); // c - Experimental indicator
- $info_id3v2_flags['isfooter'] = (bool)($id3_flags & 0x10); // d - Footer present
- break;
- }
-
- $info_id3v2['headerlength'] = getid3_lib::BigEndianSyncSafe2Int(substr($header, 6, 4)) + 10; // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length
-
- $info_id3v2['tag_offset_start'] = $this->option_starting_offset;
- $info_id3v2['tag_offset_end'] = $info_id3v2['tag_offset_start'] + $info_id3v2['headerlength'];
-
-
- // Frames
-
- // All ID3v2 frames consists of one frame header followed by one or more
- // fields containing the actual information. The header is always 10
- // bytes and laid out as follows:
- //
- // Frame ID $xx xx xx xx (four characters)
- // Size 4 * %0xxxxxxx
- // Flags $xx xx
-
- $size_of_frames = $info_id3v2['headerlength'] - 10; // not including 10-byte initial header
- if (@$info_id3v2['exthead']['length']) {
- $size_of_frames -= ($info_id3v2['exthead']['length'] + 4);
- }
-
- if (@$info_id3v2_flags['isfooter']) {
- $size_of_frames -= 10; // footer takes last 10 bytes of ID3v2 header, after frame data, before audio
- }
-
- if ($size_of_frames > 0) {
- $frame_data = $this->fread($size_of_frames); // read all frames from file into $frame_data variable
-
- // if entire frame data is unsynched, de-unsynch it now (ID3v2.3.x)
- if (@$info_id3v2_flags['unsynch'] && ($id3v2_major_version <= 3)) {
- $frame_data = str_replace("\xFF\x00", "\xFF", $frame_data);
- }
-
- // [in ID3v2.4.0] Unsynchronisation [S:6.1] is done on frame level, instead
- // of on tag level, making it easier to skip frames, increasing the streamability
- // of the tag. The unsynchronisation flag in the header [S:3.1] indicates that
- // there exists an unsynchronised frame, while the new unsynchronisation flag in
- // the frame header [S:4.1.2] indicates unsynchronisation.
-
- //$frame_data_offset = 10 + (@$info_id3v2['exthead']['length'] ? $info_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)
- $frame_data_offset = 10; // how many bytes into the stream - start from after the 10-byte header
-
- // Extended Header
- if (@$info_id3v2_flags['exthead']) {
- $extended_header_offset = 0;
-
- if ($id3v2_major_version == 3) {
-
- // v2.3 definition:
- //Extended header size $xx xx xx xx // 32-bit integer
- //Extended Flags $xx xx
- // %x0000000 %00000000 // v2.3
- // x - CRC data present
- //Size of padding $xx xx xx xx
-
- $info_id3v2['exthead']['length'] = getid3_lib::BigEndian2Int(substr($frame_data, $extended_header_offset, 4), 0);
- $extended_header_offset += 4;
-
- $info_id3v2['exthead']['flag_bytes'] = 2;
- $info_id3v2['exthead']['flag_raw'] = getid3_lib::BigEndian2Int(substr($frame_data, $extended_header_offset, $info_id3v2['exthead']['flag_bytes']));
- $extended_header_offset += $info_id3v2['exthead']['flag_bytes'];
-
- $info_id3v2['exthead']['flags']['crc'] = (bool) ($info_id3v2['exthead']['flag_raw'] & 0x8000);
-
- $info_id3v2['exthead']['padding_size'] = getid3_lib::BigEndian2Int(substr($frame_data, $extended_header_offset, 4));
- $extended_header_offset += 4;
-
- if ($info_id3v2['exthead']['flags']['crc']) {
- $info_id3v2['exthead']['flag_data']['crc'] = getid3_lib::BigEndian2Int(substr($frame_data, $extended_header_offset, 4));
- $extended_header_offset += 4;
- }
- $extended_header_offset += $info_id3v2['exthead']['padding_size'];
-
- }
-
- elseif ($id3v2_major_version == 4) {
-
- // v2.4 definition:
- //Extended header size 4 * %0xxxxxxx // 28-bit synchsafe integer
- //Number of flag bytes $01
- //Extended Flags $xx
- // %0bcd0000 // v2.4
- // b - Tag is an update
- // Flag data length $00
- // c - CRC data present
- // Flag data length $05
- // Total frame CRC 5 * %0xxxxxxx
- // d - Tag restrictions
- // Flag data length $01
-
- $info_id3v2['exthead']['length'] = getid3_lib::BigEndian2Int(substr($frame_data, $extended_header_offset, 4), 1);
- $extended_header_offset += 4;
-
- $info_id3v2['exthead']['flag_bytes'] = 1;
- $info_id3v2['exthead']['flag_raw'] = getid3_lib::BigEndian2Int(substr($frame_data, $extended_header_offset, $info_id3v2['exthead']['flag_bytes']));
- $extended_header_offset += $info_id3v2['exthead']['flag_bytes'];
-
- $info_id3v2['exthead']['flags']['update'] = (bool) ($info_id3v2['exthead']['flag_raw'] & 0x4000);
- $info_id3v2['exthead']['flags']['crc'] = (bool) ($info_id3v2['exthead']['flag_raw'] & 0x2000);
- $info_id3v2['exthead']['flags']['restrictions'] = (bool) ($info_id3v2['exthead']['flag_raw'] & 0x1000);
-
- if ($info_id3v2['exthead']['flags']['crc']) {
- $info_id3v2['exthead']['flag_data']['crc'] = getid3_lib::BigEndian2Int(substr($frame_data, $extended_header_offset, 5), 1);
- $extended_header_offset += 5;
- }
- if ($info_id3v2['exthead']['flags']['restrictions']) {
- // %ppqrrstt
- $restrictions_raw = getid3_lib::BigEndian2Int(substr($frame_data, $extended_header_offset, 1));
- $extended_header_offset += 1;
- $info_id3v2['exthead']['flags']['restrictions']['tagsize'] = ($restrictions_raw && 0xC0) >> 6; // p - Tag size restrictions
- $info_id3v2['exthead']['flags']['restrictions']['textenc'] = ($restrictions_raw && 0x20) >> 5; // q - Text encoding restrictions
- $info_id3v2['exthead']['flags']['restrictions']['textsize'] = ($restrictions_raw && 0x18) >> 3; // r - Text fields size restrictions
- $info_id3v2['exthead']['flags']['restrictions']['imgenc'] = ($restrictions_raw && 0x04) >> 2; // s - Image encoding restrictions
- $info_id3v2['exthead']['flags']['restrictions']['imgsize'] = ($restrictions_raw && 0x03) >> 0; // t - Image size restrictions
- }
-
- }
- $frame_data_offset += $extended_header_offset;
- $frame_data = substr($frame_data, $extended_header_offset);
- } // end extended header
-
-
-
-
-
-
- while (isset($frame_data) && (strlen($frame_data) > 0)) { // cycle through until no more frame data is left to parse
- if (strlen($frame_data) <= ($id3v2_major_version == 2 ? 6 : 10)) {
- // insufficient room left in ID3v2 header for actual data - must be padding
- $info_id3v2['padding']['start'] = $frame_data_offset;
- $info_id3v2['padding']['length'] = strlen($frame_data);
- $info_id3v2['padding']['valid'] = true;
- for ($i = 0; $i < $info_id3v2['padding']['length']; $i++) {
- if ($frame_data{$i} != "\x00") {
- $info_id3v2['padding']['valid'] = false;
- $info_id3v2['padding']['errorpos'] = $info_id3v2['padding']['start'] + $i;
- $getid3->warning('Invalid ID3v2 padding found at offset '.$info_id3v2['padding']['errorpos'].' (the remaining '.($info_id3v2['padding']['length'] - $i).' bytes are considered invalid)');
- break;
- }
- }
- break; // skip rest of ID3v2 header
- }
-
- if ($id3v2_major_version == 2) {
- // Frame ID $xx xx xx (three characters)
- // Size $xx xx xx (24-bit integer)
- // Flags $xx xx
-
- $frame_header = substr($frame_data, 0, 6); // take next 6 bytes for header
- $frame_data = substr($frame_data, 6); // and leave the rest in $frame_data
- $frame_name = substr($frame_header, 0, 3);
- $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 3, 3));
- $frame_flags = 0; // not used for anything in ID3v2.2, just set to avoid E_NOTICEs
-
-
- } elseif ($id3v2_major_version > 2) {
-
- // Frame ID $xx xx xx xx (four characters)
- // Size $xx xx xx xx (32-bit integer in v2.3, 28-bit synchsafe in v2.4+)
- // Flags $xx xx
-
- $frame_header = substr($frame_data, 0, 10); // take next 10 bytes for header
- $frame_data = substr($frame_data, 10); // and leave the rest in $frame_data
-
- $frame_name = substr($frame_header, 0, 4);
-
- if ($id3v2_major_version == 3) {
- $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4)); // 32-bit integer
-
- } else { // ID3v2.4+
- $frame_size = getid3_lib::BigEndianSyncSafe2Int(substr($frame_header, 4, 4)); // 32-bit synchsafe integer (28-bit value)
- }
-
- if ($frame_size < (strlen($frame_data) + 4)) {
- $nextFrameID = substr($frame_data, $frame_size, 4);
- if (getid3_id3v2::IsValidID3v2FrameName($nextFrameID, $id3v2_major_version)) {
- // next frame is OK
- } elseif (($frame_name == "\x00".'MP3') || ($frame_name == "\x00\x00".'MP') || ($frame_name == ' MP3') || ($frame_name == 'MP3e')) {
- // MP3ext known broken frames - "ok" for the purposes of this test
- } elseif (($id3v2_major_version == 4) && (getid3_id3v2::IsValidID3v2FrameName(substr($frame_data, getid3_lib::BigEndian2Int(substr($frame_header, 4, 4)), 4), 3))) {
- $getid3->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');
- $id3v2_major_version = 3;
- $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4)); // 32-bit integer
- }
- }
-
-
- $frame_flags = getid3_lib::BigEndian2Int(substr($frame_header, 8, 2));
- }
-
- if ((($id3v2_major_version == 2) && ($frame_name == "\x00\x00\x00")) || ($frame_name == "\x00\x00\x00\x00")) {
- // padding encountered
-
- $info_id3v2['padding']['start'] = $frame_data_offset;
- $info_id3v2['padding']['length'] = strlen($frame_header) + strlen($frame_data);
- $info_id3v2['padding']['valid'] = true;
-
- $len = strlen($frame_data);
- for ($i = 0; $i < $len; $i++) {
- if ($frame_data{$i} != "\x00") {
- $info_id3v2['padding']['valid'] = false;
- $info_id3v2['padding']['errorpos'] = $info_id3v2['padding']['start'] + $i;
- $getid3->warning('Invalid ID3v2 padding found at offset '.$info_id3v2['padding']['errorpos'].' (the remaining '.($info_id3v2['padding']['length'] - $i).' bytes are considered invalid)');
- break;
- }
- }
- break; // skip rest of ID3v2 header
- }
-
- if ($frame_name == 'COM ') {
- $getid3->warning('error parsing "'.$frame_name.'" ('.$frame_data_offset.' bytes into the ID3v2.'.$id3v2_major_version.' tag). (ERROR: IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_major_version.'))). [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)]');
- $frame_name = 'COMM';
- }
- if (($frame_size <= strlen($frame_data)) && (getid3_id3v2::IsValidID3v2FrameName($frame_name, $id3v2_major_version))) {
-
- unset($parsed_frame);
- $parsed_frame['frame_name'] = $frame_name;
- $parsed_frame['frame_flags_raw'] = $frame_flags;
- $parsed_frame['data'] = substr($frame_data, 0, $frame_size);
- $parsed_frame['datalength'] = (int)($frame_size);
- $parsed_frame['dataoffset'] = $frame_data_offset;
-
- $this->ParseID3v2Frame($parsed_frame);
- $info_id3v2[$frame_name][] = $parsed_frame;
-
- $frame_data = substr($frame_data, $frame_size);
-
- } else { // invalid frame length or FrameID
-
- if ($frame_size <= strlen($frame_data)) {
-
- if (getid3_id3v2::IsValidID3v2FrameName(substr($frame_data, $frame_size, 4), $id3v2_major_version)) {
-
- // next frame is valid, just skip the current frame
- $frame_data = substr($frame_data, $frame_size);
- $getid3->warning('Next ID3v2 frame is valid, skipping current frame.');
-
- } else {
-
- // next frame is invalid too, abort processing
- throw new getid3_exception('Next ID3v2 frame is also invalid, aborting processing.');
-
- }
-
- } elseif ($frame_size == strlen($frame_data)) {
-
- // this is the last frame, just skip
- $getid3->warning('This was the last ID3v2 frame.');
-
- } else {
-
- // next frame is invalid too, abort processing
- $frame_data = null;
- $getid3->warning('Invalid ID3v2 frame size, aborting.');
-
- }
- if (!getid3_id3v2::IsValidID3v2FrameName($frame_name, $id3v2_major_version)) {
-
- switch ($frame_name) {
-
- case "\x00\x00".'MP':
- case "\x00".'MP3':
- case ' MP3':
- case 'MP3e':
- case "\x00".'MP':
- case ' MP':
- case 'MP3':
- $getid3->warning('error parsing "'.$frame_name.'" ('.$frame_data_offset.' bytes into the ID3v2.'.$id3v2_major_version.' tag). (ERROR: !IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_major_version.'))). [Note: this particular error has been known to happen with tags edited by "MP3ext (www.mutschler.de/mp3ext/)"]');
- break;
-
- default:
- $getid3->warning('error parsing "'.$frame_name.'" ('.$frame_data_offset.' bytes into the ID3v2.'.$id3v2_major_version.' tag). (ERROR: !IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_major_version.'))).');
- break;
- }
-
- } elseif ($frame_size > strlen(@$frame_data)){
-
- throw new getid3_exception('error parsing "'.$frame_name.'" ('.$frame_data_offset.' bytes into the ID3v2.'.$id3v2_major_version.' tag). (ERROR: $frame_size ('.$frame_size.') > strlen($frame_data) ('.strlen($frame_data).')).');
-
- } else {
-
- throw new getid3_exception('error parsing "'.$frame_name.'" ('.$frame_data_offset.' bytes into the ID3v2.'.$id3v2_major_version.' tag).');
-
- }
-
- }
- $frame_data_offset += ($frame_size + ($id3v2_major_version == 2 ? 6 : 10));
-
- }
-
- }
-
-
- // Footer
-
- // The footer is a copy of the header, but with a different identifier.
- // ID3v2 identifier "3DI"
- // ID3v2 version $04 00
- // ID3v2 flags %abcd0000
- // ID3v2 size 4 * %0xxxxxxx
-
- if (isset($info_id3v2_flags['isfooter']) && $info_id3v2_flags['isfooter']) {
- $footer = fread ($getid3->fp, 10);
- if (substr($footer, 0, 3) == '3DI') {
- $info_id3v2['footer'] = true;
- $info_id3v2['majorversion_footer'] = ord($footer{3});
- $info_id3v2['minorversion_footer'] = ord($footer{4});
- }
- if ($info_id3v2['majorversion_footer'] <= 4) {
- $id3_flags = ord($footer{5});
- $info_id3v2_flags['unsynch_footer'] = (bool)($id3_flags & 0x80);
- $info_id3v2_flags['extfoot_footer'] = (bool)($id3_flags & 0x40);
- $info_id3v2_flags['experim_footer'] = (bool)($id3_flags & 0x20);
- $info_id3v2_flags['isfooter_footer'] = (bool)($id3_flags & 0x10);
-
- $info_id3v2['footerlength'] = getid3_lib::BigEndianSyncSafe2Int(substr($footer, 6, 4));
- }
- } // end footer
-
- if (isset($info_id3v2['comments']['genre'])) {
- foreach ($info_id3v2['comments']['genre'] as $key => $value) {
- unset($info_id3v2['comments']['genre'][$key]);
- $info_id3v2['comments'] = getid3_id3v2::array_merge_noclobber($info_id3v2['comments'], getid3_id3v2::ParseID3v2GenreString($value));
- }
- }
-
- if (isset($info_id3v2['comments']['track'])) {
- foreach ($info_id3v2['comments']['track'] as $key => $value) {
- if (strstr($value, '/')) {
- list($info_id3v2['comments']['track'][$key], $info_id3v2['comments']['totaltracks'][$key]) = explode('/', $info_id3v2['comments']['track'][$key]);
- }
- }
- }
-
- // Use year from recording time if year not set
- if (!isset($info_id3v2['comments']['year']) && ereg('^([0-9]{4})', @$info_id3v2['comments']['recording_time'][0], $matches)) {
- $info_id3v2['comments']['year'] = array ($matches[1]);
- }
-
- // Set avdataoffset
- $getid3->info['avdataoffset'] = $info_id3v2['headerlength'];
- if (isset($info_id3v2['footer'])) {
- $getid3->info['avdataoffset'] += 10;
- }
-
- return true;
- }
-
-
-
- private function ParseID3v2Frame(&$parsed_frame) {
-
- $getid3 = $this->getid3;
-
- $id3v2_major_version = $getid3->info['id3v2']['majorversion'];
-
- $frame_name_long = getid3_id3v2::FrameNameLongLookup($parsed_frame['frame_name']);
- if ($frame_name_long) {
- $parsed_frame['framenamelong'] = $frame_name_long;
- }
-
- $frame_name_short = getid3_id3v2::FrameNameShortLookup($parsed_frame['frame_name']);
- if ($frame_name_short) {
- $parsed_frame['framenameshort'] = $frame_name_short;
- }
-
- if ($id3v2_major_version >= 3) { // frame flags are not part of the ID3v2.2 standard
-
- if ($id3v2_major_version == 3) {
-
- // Frame Header Flags
- // %abc00000 %ijk00000
-
- $parsed_frame['flags']['TagAlterPreservation'] = (bool)($parsed_frame['frame_flags_raw'] & 0x8000); // a - Tag alter preservation
- $parsed_frame['flags']['FileAlterPreservation'] = (bool)($parsed_frame['frame_flags_raw'] & 0x4000); // b - File alter preservation
- $parsed_frame['flags']['ReadOnly'] = (bool)($parsed_frame['frame_flags_raw'] & 0x2000); // c - Read only
- $parsed_frame['flags']['compression'] = (bool)($parsed_frame['frame_flags_raw'] & 0x0080); // i - Compression
- $parsed_frame['flags']['Encryption'] = (bool)($parsed_frame['frame_flags_raw'] & 0x0040); // j - Encryption
- $parsed_frame['flags']['GroupingIdentity'] = (bool)($parsed_frame['frame_flags_raw'] & 0x0020); // k - Grouping identity
-
-
- } elseif ($id3v2_major_version == 4) {
-
- // Frame Header Flags
- // %0abc0000 %0h00kmnp
-
- $parsed_frame['flags']['TagAlterPreservation'] = (bool)($parsed_frame['frame_flags_raw'] & 0x4000); // a - Tag alter preservation
- $parsed_frame['flags']['FileAlterPreservation'] = (bool)($parsed_frame['frame_flags_raw'] & 0x2000); // b - File alter preservation
- $parsed_frame['flags']['ReadOnly'] = (bool)($parsed_frame['frame_flags_raw'] & 0x1000); // c - Read only
- $parsed_frame['flags']['GroupingIdentity'] = (bool)($parsed_frame['frame_flags_raw'] & 0x0040); // h - Grouping identity
- $parsed_frame['flags']['compression'] = (bool)($parsed_frame['frame_flags_raw'] & 0x0008); // k - Compression
- $parsed_frame['flags']['Encryption'] = (bool)($parsed_frame['frame_flags_raw'] & 0x0004); // m - Encryption
- $parsed_frame['flags']['Unsynchronisation'] = (bool)($parsed_frame['frame_flags_raw'] & 0x0002); // n - Unsynchronisation
- $parsed_frame['flags']['DataLengthIndicator'] = (bool)($parsed_frame['frame_flags_raw'] & 0x0001); // p - Data length indicator
-
- // Frame-level de-unsynchronisation - ID3v2.4
- if ($parsed_frame['flags']['Unsynchronisation']) {
- $parsed_frame['data'] = str_replace("\xFF\x00", "\xFF", $parsed_frame['data']);
- }
- }
-
- // Frame-level de-compression
- if ($parsed_frame['flags']['compression']) {
- $parsed_frame['decompressed_size'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], 0, 4));
-
- if (!function_exists('gzuncompress')) {
- $getid3->warning('gzuncompress() support required to decompress ID3v2 frame "'.$parsed_frame['frame_name'].'"');
- } elseif ($decompressed_data = @gzuncompress(substr($parsed_frame['data'], 4))) {
- $parsed_frame['data'] = $decompressed_data;
- } else {
- $getid3->warning('gzuncompress() failed on compressed contents of ID3v2 frame "'.$parsed_frame['frame_name'].'"');
- }
- }
- }
-
-
- if (isset($parsed_frame['datalength']) && ($parsed_frame['datalength'] == 0)) {
-
- $warning = 'Frame "'.$parsed_frame['frame_name'].'" at offset '.$parsed_frame['dataoffset'].' has no data portion';
- switch ($parsed_frame['frame_name']) {
- case 'WCOM':
- $warning .= ' (this is known to happen with files tagged by RioPort)';
- break;
-
- default:
- break;
- }
- $getid3->warning($warning);
- return true;
- }
-
-
- if ((($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'UFID')) || // 4.1 UFID Unique file identifier
- (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'UFI'))) { // 4.1 UFI Unique file identifier
-
- // There may be more than one 'UFID' frame in a tag,
- // but only one with the same 'Owner identifier'.
- // <Header for 'Unique file identifier', ID: 'UFID'>
- // Owner identifier <text string> $00
- // Identifier <up to 64 bytes binary data>
-
- $frame_terminator_pos = strpos($parsed_frame['data'], "\x00");
- $frame_id_string = substr($parsed_frame['data'], 0, $frame_terminator_pos);
- $parsed_frame['ownerid'] = $frame_id_string;
- $parsed_frame['data'] = substr($parsed_frame['data'], $frame_terminator_pos + strlen("\x00"));
- unset($parsed_frame['data']);
- return true;
- }
-
-
- if ((($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'TXXX')) || // 4.2.2 TXXX User defined text information frame
- (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'TXX'))) { // 4.2.2 TXX User defined text information frame
-
- // There may be more than one 'TXXX' frame in each tag,
- // but only one with the same description.
- // <Header for 'User defined text information frame', ID: 'TXXX'>
- // Text encoding $xx
- // Description <text string according to encoding> $00 (00)
- // Value <text string according to encoding>
-
- $frame_offset = 0;
- $frame_text_encoding = ord($parsed_frame['data']{$frame_offset++});
-
- if ((($id3v2_major_version <= 3) && ($frame_text_encoding > 1)) || (($id3v2_major_version == 4) && ($frame_text_encoding > 3))) {
- $getid3->warning('Invalid text encoding byte ('.$frame_text_encoding.') in frame "'.$parsed_frame['frame_name'].'" - defaulting to ISO-8859-1 encoding');
- }
- $frame_terminator_pos = @strpos($parsed_frame['data'], getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding), $frame_offset);
- if (ord(substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)), 1)) === 0) {
- $frame_terminator_pos++; // @strpos() fooled because 2nd byte of Unicode chars are often 0x00
- }
- $frame_description = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset);
- if (ord($frame_description) === 0) {
- $frame_description = '';
- }
- $parsed_frame['encodingid'] = $frame_text_encoding;
- $parsed_frame['encoding'] = $this->TextEncodingNameLookup($frame_text_encoding);
-
- $parsed_frame['description'] = $frame_description;
- $parsed_frame['data'] = substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)));
- if (!empty($parsed_frame['framenameshort']) && !empty($parsed_frame['data'])) {
- $getid3->info['id3v2']['comments'][$parsed_frame['framenameshort']][] = trim($getid3->iconv($parsed_frame['encoding'], 'UTF-8', $parsed_frame['data']));
- }
- unset($parsed_frame['data']);
- return true;
- }
-
-
- if ($parsed_frame['frame_name']{0} == 'T') { // 4.2. T??[?] Text information frame
-
- // There may only be one text information frame of its kind in an tag.
- // <Header for 'Text information frame', ID: 'T000' - 'TZZZ',
- // excluding 'TXXX' described in 4.2.6.>
- // Text encoding $xx
- // Information <text string(s) according to encoding>
-
- $frame_offset = 0;
- $frame_text_encoding = ord($parsed_frame['data']{$frame_offset++});
- if ((($id3v2_major_version <= 3) && ($frame_text_encoding > 1)) || (($id3v2_major_version == 4) && ($frame_text_encoding > 3))) {
- $getid3->warning('Invalid text encoding byte ('.$frame_text_encoding.') in frame "'.$parsed_frame['frame_name'].'" - defaulting to ISO-8859-1 encoding');
- }
-
- $parsed_frame['data'] = (string)substr($parsed_frame['data'], $frame_offset);
-
- $parsed_frame['encodingid'] = $frame_text_encoding;
- $parsed_frame['encoding'] = $this->TextEncodingNameLookup($frame_text_encoding);
-
- if (!empty($parsed_frame['framenameshort']) && !empty($parsed_frame['data'])) {
-
- // remove possible terminating \x00 (put by encoding id or software bug)
- $string = $getid3->iconv($parsed_frame['encoding'], 'UTF-8', $parsed_frame['data']);
- if ($string[strlen($string)-1] = "\x00") {
- $string = substr($string, 0, strlen($string)-1);
- }
- $getid3->info['id3v2']['comments'][$parsed_frame['framenameshort']][] = $string;
- unset($string);
- }
- return true;
- }
-
-
- if ((($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'WXXX')) || // 4.3.2 WXXX User defined URL link frame
- (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'WXX'))) { // 4.3.2 WXX User defined URL link frame
-
- // There may be more than one 'WXXX' frame in each tag,
- // but only one with the same description
- // <Header for 'User defined URL link frame', ID: 'WXXX'>
- // Text encoding $xx
- // Description <text string according to encoding> $00 (00)
- // URL <text string>
-
- $frame_offset = 0;
- $frame_text_encoding = ord($parsed_frame['data']{$frame_offset++});
- if ((($id3v2_major_version <= 3) && ($frame_text_encoding > 1)) || (($id3v2_major_version == 4) && ($frame_text_encoding > 3))) {
- $getid3->warning('Invalid text encoding byte ('.$frame_text_encoding.') in frame "'.$parsed_frame['frame_name'].'" - defaulting to ISO-8859-1 encoding');
- }
- $frame_terminator_pos = @strpos($parsed_frame['data'], getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding), $frame_offset);
- if (ord(substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)), 1)) === 0) {
- $frame_terminator_pos++; // @strpos() fooled because 2nd byte of Unicode chars are often 0x00
- }
- $frame_description = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset);
-
- if (ord($frame_description) === 0) {
- $frame_description = '';
- }
- $parsed_frame['data'] = substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)));
-
- $frame_terminator_pos = strpos($parsed_frame['data'], getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding));
- if (ord(substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)), 1)) === 0) {
- $frame_terminator_pos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
- }
- if ($frame_terminator_pos) {
- // there are null bytes after the data - this is not according to spec
- // only use data up to first null byte
- $frame_urldata = (string)substr($parsed_frame['data'], 0, $frame_terminator_pos);
- } else {
- // no null bytes following data, just use all data
- $frame_urldata = (string)$parsed_frame['data'];
- }
-
- $parsed_frame['encodingid'] = $frame_text_encoding;
- $parsed_frame['encoding'] = $this->TextEncodingNameLookup($frame_text_encoding);
-
- $parsed_frame['url'] = $frame_urldata;
- $parsed_frame['description'] = $frame_description;
- if (!empty($parsed_frame['framenameshort']) && $parsed_frame['url']) {
- $getid3->info['id3v2']['comments'][$parsed_frame['framenameshort']][] = $getid3->iconv($parsed_frame['encoding'], 'UTF-8', $parsed_frame['url']);
- }
- unset($parsed_frame['data']);
- return true;
- }
-
-
- if ($parsed_frame['frame_name']{0} == 'W') { // 4.3. W??? URL link frames
-
- // There may only be one URL link frame of its kind in a tag,
- // except when stated otherwise in the frame description
- // <Header for 'URL link frame', ID: 'W000' - 'WZZZ', excluding 'WXXX'
- // described in 4.3.2.>
- // URL <text string>
-
- $parsed_frame['url'] = trim($parsed_frame['data']);
- if (!empty($parsed_frame['framenameshort']) && $parsed_frame['url']) {
- $getid3->info['id3v2']['comments'][$parsed_frame['framenameshort']][] = $parsed_frame['url'];
- }
- unset($parsed_frame['data']);
- return true;
- }
-
-
- if ((($id3v2_major_version == 3) && ($parsed_frame['frame_name'] == 'IPLS')) || // 4.4 IPLS Involved people list (ID3v2.3 only)
- (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'IPL'))) { // 4.4 IPL Involved people list (ID3v2.2 only)
-
- // There may only be one 'IPL' frame in each tag
- // <Header for 'User defined URL link frame', ID: 'IPL'>
- // Text encoding $xx
- // People list strings <textstrings>
-
- $frame_offset = 0;
- $frame_text_encoding = ord($parsed_frame['data']{$frame_offset++});
- if ((($id3v2_major_version <= 3) && ($frame_text_encoding > 1)) || (($id3v2_major_version == 4) && ($frame_text_encoding > 3))) {
- $getid3->warning('Invalid text encoding byte ('.$frame_text_encoding.') in frame "'.$parsed_frame['frame_name'].'" - defaulting to ISO-8859-1 encoding');
- }
- $parsed_frame['encodingid'] = $frame_text_encoding;
- $parsed_frame['encoding'] = $this->TextEncodingNameLookup($parsed_frame['encodingid']);
-
- $parsed_frame['data'] = (string)substr($parsed_frame['data'], $frame_offset);
- if (!empty($parsed_frame['framenameshort']) && !empty($parsed_frame['data'])) {
- $getid3->info['id3v2']['comments'][$parsed_frame['framenameshort']][] = $getid3->iconv($parsed_frame['encoding'], 'UTF-8', $parsed_frame['data']);
- }
- return true;
- }
-
-
- if ((($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'MCDI')) || // 4.4 MCDI Music CD identifier
- (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'MCI'))) { // 4.5 MCI Music CD identifier
-
- // There may only be one 'MCDI' frame in each tag
- // <Header for 'Music CD identifier', ID: 'MCDI'>
- // CD TOC <binary data>
-
- if (!empty($parsed_frame['framenameshort']) && !empty($parsed_frame['data'])) {
- $getid3->info['id3v2']['comments'][$parsed_frame['framenameshort']][] = $parsed_frame['data'];
- }
- return true;
- }
-
-
- if ((($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'ETCO')) || // 4.5 ETCO Event timing codes
- (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'ETC'))) { // 4.6 ETC Event timing codes
-
- // There may only be one 'ETCO' frame in each tag
- // <Header for 'Event timing codes', ID: 'ETCO'>
- // Time stamp format $xx
- // Where time stamp format is:
- // $01 (32-bit value) MPEG frames from beginning of file
- // $02 (32-bit value) milliseconds from beginning of file
- // Followed by a list of key events in the following format:
- // Type of event $xx
- // Time stamp $xx (xx ...)
- // The 'Time stamp' is set to zero if directly at the beginning of the sound
- // or after the previous event. All events MUST be sorted in chronological order.
-
- $frame_offset = 0;
- $parsed_frame['timestampformat'] = ord($parsed_frame['data']{$frame_offset++});
-
- while ($frame_offset < strlen($parsed_frame['data'])) {
- $parsed_frame['typeid'] = $parsed_frame['data']{$frame_offset++};
- $parsed_frame['type'] = getid3_id3v2::ETCOEventLookup($parsed_frame['typeid']);
- $parsed_frame['timestamp'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, 4));
- $frame_offset += 4;
- }
- unset($parsed_frame['data']);
- return true;
- }
-
-
- if ((($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'MLLT')) || // 4.6 MLLT MPEG location lookup table
- (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'MLL'))) { // 4.7 MLL MPEG location lookup table
-
- // There may only be one 'MLLT' frame in each tag
- // <Header for 'Location lookup table', ID: 'MLLT'>
- // MPEG frames between reference $xx xx
- // Bytes between reference $xx xx xx
- // Milliseconds between reference $xx xx xx
- // Bits for bytes deviation $xx
- // Bits for milliseconds dev. $xx
- // Then for every reference the following data is included;
- // Deviation in bytes %xxx....
- // Deviation in milliseconds %xxx....
-
- $frame_offset = 0;
- $parsed_frame['framesbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], 0, 2));
- $parsed_frame['bytesbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], 2, 3));
- $parsed_frame['msbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], 5, 3));
- $parsed_frame['bitsforbytesdeviation'] = getid3_lib::BigEndian2Int($parsed_frame['data'][8]);
- $parsed_frame['bitsformsdeviation'] = getid3_lib::BigEndian2Int($parsed_frame['data'][9]);
- $parsed_frame['data'] = substr($parsed_frame['data'], 10);
-
- while ($frame_offset < strlen($parsed_frame['data'])) {
- $deviation_bitstream .= getid3_lib::BigEndian2Bin($parsed_frame['data']{$frame_offset++});
- }
- $reference_counter = 0;
- while (strlen($deviation_bitstream) > 0) {
- $parsed_frame[$reference_counter]['bytedeviation'] = bindec(substr($deviation_bitstream, 0, $parsed_frame['bitsforbytesdeviation']));
- $parsed_frame[$reference_counter]['msdeviation'] = bindec(substr($deviation_bitstream, $parsed_frame['bitsforbytesdeviation'], $parsed_frame['bitsformsdeviation']));
- $deviation_bitstream = substr($deviation_bitstream, $parsed_frame['bitsforbytesdeviation'] + $parsed_frame['bitsformsdeviation']);
- $reference_counter++;
- }
- unset($parsed_frame['data']);
- return true;
- }
-
-
- if ((($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'SYTC')) || // 4.7 SYTC Synchronised tempo codes
- (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'STC'))) { // 4.8 STC Synchronised tempo codes
-
- // There may only be one 'SYTC' frame in each tag
- // <Header for 'Synchronised tempo codes', ID: 'SYTC'>
- // Time stamp format $xx
- // Tempo data <binary data>
- // Where time stamp format is:
- // $01 (32-bit value) MPEG frames from beginning of file
- // $02 (32-bit value) milliseconds from beginning of file
-
- $frame_offset = 0;
- $parsed_frame['timestampformat'] = ord($parsed_frame['data']{$frame_offset++});
- $timestamp_counter = 0;
- while ($frame_offset < strlen($parsed_frame['data'])) {
- $parsed_frame[$timestamp_counter]['tempo'] = ord($parsed_frame['data']{$frame_offset++});
- if ($parsed_frame[$timestamp_counter]['tempo'] == 255) {
- $parsed_frame[$timestamp_counter]['tempo'] += ord($parsed_frame['data']{$frame_offset++});
- }
- $parsed_frame[$timestamp_counter]['timestamp'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, 4));
- $frame_offset += 4;
- $timestamp_counter++;
- }
- unset($parsed_frame['data']);
- return true;
- }
-
-
- if ((($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'USLT')) || // 4.8 USLT Unsynchronised lyric/text transcription
- (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'ULT'))) { // 4.9 ULT Unsynchronised lyric/text transcription
-
- // There may be more than one 'Unsynchronised lyrics/text transcription' frame
- // in each tag, but only one with the same language and content descriptor.
- // <Header for 'Unsynchronised lyrics/text transcription', ID: 'USLT'>
- // Text encoding $xx
- // Language $xx xx xx
- // Content descriptor <text string according to encoding> $00 (00)
- // Lyrics/text <full text string according to encoding>
-
- $frame_offset = 0;
- $frame_text_encoding = ord($parsed_frame['data']{$frame_offset++});
- if ((($id3v2_major_version <= 3) && ($frame_text_encoding > 1)) || (($id3v2_major_version == 4) && ($frame_text_encoding > 3))) {
- $getid3->warning('Invalid text encoding byte ('.$frame_text_encoding.') in frame "'.$parsed_frame['frame_name'].'" - defaulting to ISO-8859-1 encoding');
- }
- $frame_language = substr($parsed_frame['data'], $frame_offset, 3);
- $frame_offset += 3;
- if ($frame_offset > strlen($parsed_frame['data'])) {
- $frame_offset = strlen($parsed_frame['data']) - 1;
- }
- $frame_terminator_pos = @strpos($parsed_frame['data'], getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding), $frame_offset);
- if (ord(substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)), 1)) === 0) {
- $frame_terminator_pos++; // @strpos() fooled because 2nd byte of Unicode chars are often 0x00
- }
- $frame_description = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset);
- if (ord($frame_description) === 0) {
- $frame_description = '';
- }
- $parsed_frame['data'] = substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)));
-
- $parsed_frame['encodingid'] = $frame_text_encoding;
- $parsed_frame['encoding'] = $this->TextEncodingNameLookup($frame_text_encoding);
-
- $parsed_frame['data'] = $parsed_frame['data'];
- $parsed_frame['language'] = $frame_language;
- …
Large files files are truncated, but you can click here to view the full file