source: extensions/piwigo_videojs/include/getid3/module.tag.id3v2.php @ 24676

Last change on this file since 24676 was 24676, checked in by ddtddt, 11 years ago

[extensions] - piwigo_videojs - add file for translate

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