source: extensions/charlies_content/getid3/getid3/module.tag.id3v2.php

Last change on this file was 3544, checked in by vdigital, 15 years ago

Change: getid3 upgraded to -> 1.7.9

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