~canonical-sysadmins/wordpress/4.7.2

« back to all changes in this revision

Viewing changes to wp-includes/ID3/module.tag.id3v2.php

  • Committer: Jacek Nykis
  • Date: 2015-01-05 16:17:05 UTC
  • Revision ID: jacek.nykis@canonical.com-20150105161705-w544l1h5mcg7u4w9
Initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
16
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v1.php', __FILE__, true);
 
17
 
 
18
class 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 artist 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