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