|
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 |