source: branches/MootoolsFileManager-Update/plugins/MootoolsFileManager/mootools-filemanager/Assets/Connector/Assets/getid3/module.tag.id3v2.php @ 1300

Last change on this file since 1300 was 1300, checked in by gogo, 8 years ago

Update the MootoolsFileManager? to the latest cpojer with some modifications.
Add a demo for the MFM examples/mootools-file-manager.php
Change the default config for ImageManager? and ExtendedFileManager? for added security.

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