1: <?php
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17: getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v1.php', __FILE__, true);
18:
19: class getid3_id3v2 extends getid3_handler
20: {
21: public $StartingOffset = 0;
22:
23: public function Analyze() {
24: $info = &$this->getid3->info;
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49: $info['id3v2']['header'] = true;
50: $thisfile_id3v2 = &$info['id3v2'];
51: $thisfile_id3v2['flags'] = array();
52: $thisfile_id3v2_flags = &$thisfile_id3v2['flags'];
53:
54:
55: $this->fseek($this->StartingOffset);
56: $header = $this->fread(10);
57: if (substr($header, 0, 3) == 'ID3' && strlen($header) == 10) {
58:
59: $thisfile_id3v2['majorversion'] = ord($header{3});
60: $thisfile_id3v2['minorversion'] = ord($header{4});
61:
62:
63: $id3v2_majorversion = &$thisfile_id3v2['majorversion'];
64:
65: } else {
66:
67: unset($info['id3v2']);
68: return false;
69:
70: }
71:
72: if ($id3v2_majorversion > 4) {
73:
74: $info['error'][] = 'this script only parses up to ID3v2.4.x - this tag is ID3v2.'.$id3v2_majorversion.'.'.$thisfile_id3v2['minorversion'];
75: return false;
76:
77: }
78:
79: $id3_flags = ord($header{5});
80: switch ($id3v2_majorversion) {
81: case 2:
82:
83: $thisfile_id3v2_flags['unsynch'] = (bool) ($id3_flags & 0x80);
84: $thisfile_id3v2_flags['compression'] = (bool) ($id3_flags & 0x40);
85: break;
86:
87: case 3:
88:
89: $thisfile_id3v2_flags['unsynch'] = (bool) ($id3_flags & 0x80);
90: $thisfile_id3v2_flags['exthead'] = (bool) ($id3_flags & 0x40);
91: $thisfile_id3v2_flags['experim'] = (bool) ($id3_flags & 0x20);
92: break;
93:
94: case 4:
95:
96: $thisfile_id3v2_flags['unsynch'] = (bool) ($id3_flags & 0x80);
97: $thisfile_id3v2_flags['exthead'] = (bool) ($id3_flags & 0x40);
98: $thisfile_id3v2_flags['experim'] = (bool) ($id3_flags & 0x20);
99: $thisfile_id3v2_flags['isfooter'] = (bool) ($id3_flags & 0x10);
100: break;
101: }
102:
103: $thisfile_id3v2['headerlength'] = getid3_lib::BigEndian2Int(substr($header, 6, 4), 1) + 10;
104:
105: $thisfile_id3v2['tag_offset_start'] = $this->StartingOffset;
106: $thisfile_id3v2['tag_offset_end'] = $thisfile_id3v2['tag_offset_start'] + $thisfile_id3v2['headerlength'];
107:
108:
109:
110:
111:
112:
113: $thisfile_id3v2['encoding'] = 'UTF-8';
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126: $sizeofframes = $thisfile_id3v2['headerlength'] - 10;
127: if (!empty($thisfile_id3v2['exthead']['length'])) {
128: $sizeofframes -= ($thisfile_id3v2['exthead']['length'] + 4);
129: }
130: if (!empty($thisfile_id3v2_flags['isfooter'])) {
131: $sizeofframes -= 10;
132: }
133: if ($sizeofframes > 0) {
134:
135: $framedata = $this->fread($sizeofframes);
136:
137:
138: if (!empty($thisfile_id3v2_flags['unsynch']) && ($id3v2_majorversion <= 3)) {
139: $framedata = $this->DeUnsynchronise($framedata);
140: }
141:
142:
143:
144:
145:
146:
147:
148:
149: $framedataoffset = 10;
150:
151:
152:
153: if (!empty($thisfile_id3v2_flags['exthead'])) {
154: $extended_header_offset = 0;
155:
156: if ($id3v2_majorversion == 3) {
157:
158:
159:
160:
161:
162:
163:
164:
165: $thisfile_id3v2['exthead']['length'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4), 0);
166: $extended_header_offset += 4;
167:
168: $thisfile_id3v2['exthead']['flag_bytes'] = 2;
169: $thisfile_id3v2['exthead']['flag_raw'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, $thisfile_id3v2['exthead']['flag_bytes']));
170: $extended_header_offset += $thisfile_id3v2['exthead']['flag_bytes'];
171:
172: $thisfile_id3v2['exthead']['flags']['crc'] = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x8000);
173:
174: $thisfile_id3v2['exthead']['padding_size'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4));
175: $extended_header_offset += 4;
176:
177: if ($thisfile_id3v2['exthead']['flags']['crc']) {
178: $thisfile_id3v2['exthead']['flag_data']['crc'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4));
179: $extended_header_offset += 4;
180: }
181: $extended_header_offset += $thisfile_id3v2['exthead']['padding_size'];
182:
183: } elseif ($id3v2_majorversion == 4) {
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198: $thisfile_id3v2['exthead']['length'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4), true);
199: $extended_header_offset += 4;
200:
201: $thisfile_id3v2['exthead']['flag_bytes'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1));
202: $extended_header_offset += 1;
203:
204: $thisfile_id3v2['exthead']['flag_raw'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, $thisfile_id3v2['exthead']['flag_bytes']));
205: $extended_header_offset += $thisfile_id3v2['exthead']['flag_bytes'];
206:
207: $thisfile_id3v2['exthead']['flags']['update'] = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x40);
208: $thisfile_id3v2['exthead']['flags']['crc'] = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x20);
209: $thisfile_id3v2['exthead']['flags']['restrictions'] = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x10);
210:
211: if ($thisfile_id3v2['exthead']['flags']['update']) {
212: $ext_header_chunk_length = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1));
213: $extended_header_offset += 1;
214: }
215:
216: if ($thisfile_id3v2['exthead']['flags']['crc']) {
217: $ext_header_chunk_length = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1));
218: $extended_header_offset += 1;
219: $thisfile_id3v2['exthead']['flag_data']['crc'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, $ext_header_chunk_length), true, false);
220: $extended_header_offset += $ext_header_chunk_length;
221: }
222:
223: if ($thisfile_id3v2['exthead']['flags']['restrictions']) {
224: $ext_header_chunk_length = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1));
225: $extended_header_offset += 1;
226:
227:
228: $restrictions_raw = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1));
229: $extended_header_offset += 1;
230: $thisfile_id3v2['exthead']['flags']['restrictions']['tagsize'] = ($restrictions_raw & 0xC0) >> 6;
231: $thisfile_id3v2['exthead']['flags']['restrictions']['textenc'] = ($restrictions_raw & 0x20) >> 5;
232: $thisfile_id3v2['exthead']['flags']['restrictions']['textsize'] = ($restrictions_raw & 0x18) >> 3;
233: $thisfile_id3v2['exthead']['flags']['restrictions']['imgenc'] = ($restrictions_raw & 0x04) >> 2;
234: $thisfile_id3v2['exthead']['flags']['restrictions']['imgsize'] = ($restrictions_raw & 0x03) >> 0;
235:
236: $thisfile_id3v2['exthead']['flags']['restrictions_text']['tagsize'] = $this->LookupExtendedHeaderRestrictionsTagSizeLimits($thisfile_id3v2['exthead']['flags']['restrictions']['tagsize']);
237: $thisfile_id3v2['exthead']['flags']['restrictions_text']['textenc'] = $this->LookupExtendedHeaderRestrictionsTextEncodings($thisfile_id3v2['exthead']['flags']['restrictions']['textenc']);
238: $thisfile_id3v2['exthead']['flags']['restrictions_text']['textsize'] = $this->LookupExtendedHeaderRestrictionsTextFieldSize($thisfile_id3v2['exthead']['flags']['restrictions']['textsize']);
239: $thisfile_id3v2['exthead']['flags']['restrictions_text']['imgenc'] = $this->LookupExtendedHeaderRestrictionsImageEncoding($thisfile_id3v2['exthead']['flags']['restrictions']['imgenc']);
240: $thisfile_id3v2['exthead']['flags']['restrictions_text']['imgsize'] = $this->LookupExtendedHeaderRestrictionsImageSizeSize($thisfile_id3v2['exthead']['flags']['restrictions']['imgsize']);
241: }
242:
243: if ($thisfile_id3v2['exthead']['length'] != $extended_header_offset) {
244: $info['warning'][] = 'ID3v2.4 extended header length mismatch (expecting '.intval($thisfile_id3v2['exthead']['length']).', found '.intval($extended_header_offset).')';
245: }
246: }
247:
248: $framedataoffset += $extended_header_offset;
249: $framedata = substr($framedata, $extended_header_offset);
250: }
251:
252:
253: while (isset($framedata) && (strlen($framedata) > 0)) {
254: if (strlen($framedata) <= $this->ID3v2HeaderLength($id3v2_majorversion)) {
255:
256: $thisfile_id3v2['padding']['start'] = $framedataoffset;
257: $thisfile_id3v2['padding']['length'] = strlen($framedata);
258: $thisfile_id3v2['padding']['valid'] = true;
259: for ($i = 0; $i < $thisfile_id3v2['padding']['length']; $i++) {
260: if ($framedata{$i} != "\x00") {
261: $thisfile_id3v2['padding']['valid'] = false;
262: $thisfile_id3v2['padding']['errorpos'] = $thisfile_id3v2['padding']['start'] + $i;
263: $info['warning'][] = 'Invalid ID3v2 padding found at offset '.$thisfile_id3v2['padding']['errorpos'].' (the remaining '.($thisfile_id3v2['padding']['length'] - $i).' bytes are considered invalid)';
264: break;
265: }
266: }
267: break;
268: }
269: if ($id3v2_majorversion == 2) {
270:
271:
272:
273:
274: $frame_header = substr($framedata, 0, 6);
275: $framedata = substr($framedata, 6);
276: $frame_name = substr($frame_header, 0, 3);
277: $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 3, 3), 0);
278: $frame_flags = 0;
279:
280: } elseif ($id3v2_majorversion > 2) {
281:
282:
283:
284:
285:
286: $frame_header = substr($framedata, 0, 10);
287: $framedata = substr($framedata, 10);
288:
289: $frame_name = substr($frame_header, 0, 4);
290: if ($id3v2_majorversion == 3) {
291: $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0);
292: } else {
293: $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 1);
294: }
295:
296: if ($frame_size < (strlen($framedata) + 4)) {
297: $nextFrameID = substr($framedata, $frame_size, 4);
298: if ($this->IsValidID3v2FrameName($nextFrameID, $id3v2_majorversion)) {
299:
300: } elseif (($frame_name == "\x00".'MP3') || ($frame_name == "\x00\x00".'MP') || ($frame_name == ' MP3') || ($frame_name == 'MP3e')) {
301:
302: } elseif (($id3v2_majorversion == 4) && ($this->IsValidID3v2FrameName(substr($framedata, getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0), 4), 3))) {
303: $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';
304: $id3v2_majorversion = 3;
305: $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0);
306: }
307: }
308:
309:
310: $frame_flags = getid3_lib::BigEndian2Int(substr($frame_header, 8, 2));
311: }
312:
313: if ((($id3v2_majorversion == 2) && ($frame_name == "\x00\x00\x00")) || ($frame_name == "\x00\x00\x00\x00")) {
314:
315:
316: $thisfile_id3v2['padding']['start'] = $framedataoffset;
317: $thisfile_id3v2['padding']['length'] = strlen($frame_header) + strlen($framedata);
318: $thisfile_id3v2['padding']['valid'] = true;
319:
320: $len = strlen($framedata);
321: for ($i = 0; $i < $len; $i++) {
322: if ($framedata{$i} != "\x00") {
323: $thisfile_id3v2['padding']['valid'] = false;
324: $thisfile_id3v2['padding']['errorpos'] = $thisfile_id3v2['padding']['start'] + $i;
325: $info['warning'][] = 'Invalid ID3v2 padding found at offset '.$thisfile_id3v2['padding']['errorpos'].' (the remaining '.($thisfile_id3v2['padding']['length'] - $i).' bytes are considered invalid)';
326: break;
327: }
328: }
329: break;
330: }
331:
332: if ($frame_name == 'COM ') {
333: $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)]';
334: $frame_name = 'COMM';
335: }
336: if (($frame_size <= strlen($framedata)) && ($this->IsValidID3v2FrameName($frame_name, $id3v2_majorversion))) {
337:
338: unset($parsedFrame);
339: $parsedFrame['frame_name'] = $frame_name;
340: $parsedFrame['frame_flags_raw'] = $frame_flags;
341: $parsedFrame['data'] = substr($framedata, 0, $frame_size);
342: $parsedFrame['datalength'] = getid3_lib::CastAsInt($frame_size);
343: $parsedFrame['dataoffset'] = $framedataoffset;
344:
345: $this->ParseID3v2Frame($parsedFrame);
346: $thisfile_id3v2[$frame_name][] = $parsedFrame;
347:
348: $framedata = substr($framedata, $frame_size);
349:
350: } else {
351:
352: if ($frame_size <= strlen($framedata)) {
353:
354: if ($this->IsValidID3v2FrameName(substr($framedata, $frame_size, 4), $id3v2_majorversion)) {
355:
356:
357: $framedata = substr($framedata, $frame_size);
358: $info['warning'][] = 'Next ID3v2 frame is valid, skipping current frame.';
359:
360: } else {
361:
362:
363:
364: $framedata = null;
365: $info['error'][] = 'Next ID3v2 frame is also invalid, aborting processing.';
366:
367: }
368:
369: } elseif ($frame_size == strlen($framedata)) {
370:
371:
372: $info['warning'][] = 'This was the last ID3v2 frame.';
373:
374: } else {
375:
376:
377:
378: $framedata = null;
379: $info['warning'][] = 'Invalid ID3v2 frame size, aborting.';
380:
381: }
382: if (!$this->IsValidID3v2FrameName($frame_name, $id3v2_majorversion)) {
383:
384: switch ($frame_name) {
385: case "\x00\x00".'MP':
386: case "\x00".'MP3':
387: case ' MP3':
388: case 'MP3e':
389: case "\x00".'MP':
390: case ' MP':
391: case 'MP3':
392: $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/)"]';
393: break;
394:
395: default:
396: $info['warning'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: !IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))).';
397: break;
398: }
399:
400: } elseif (!isset($framedata) || ($frame_size > strlen($framedata))) {
401:
402: $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').')).';
403:
404: } else {
405:
406: $info['error'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag).';
407:
408: }
409:
410: }
411: $framedataoffset += ($frame_size + $this->ID3v2HeaderLength($id3v2_majorversion));
412:
413: }
414:
415: }
416:
417:
418:
419:
420:
421:
422:
423:
424:
425:
426: if (isset($thisfile_id3v2_flags['isfooter']) && $thisfile_id3v2_flags['isfooter']) {
427: $footer = $this->fread(10);
428: if (substr($footer, 0, 3) == '3DI') {
429: $thisfile_id3v2['footer'] = true;
430: $thisfile_id3v2['majorversion_footer'] = ord($footer{3});
431: $thisfile_id3v2['minorversion_footer'] = ord($footer{4});
432: }
433: if ($thisfile_id3v2['majorversion_footer'] <= 4) {
434: $id3_flags = ord(substr($footer{5}));
435: $thisfile_id3v2_flags['unsynch_footer'] = (bool) ($id3_flags & 0x80);
436: $thisfile_id3v2_flags['extfoot_footer'] = (bool) ($id3_flags & 0x40);
437: $thisfile_id3v2_flags['experim_footer'] = (bool) ($id3_flags & 0x20);
438: $thisfile_id3v2_flags['isfooter_footer'] = (bool) ($id3_flags & 0x10);
439:
440: $thisfile_id3v2['footerlength'] = getid3_lib::BigEndian2Int(substr($footer, 6, 4), 1);
441: }
442: }
443:
444: if (isset($thisfile_id3v2['comments']['genre'])) {
445: $genres = array();
446: foreach ($thisfile_id3v2['comments']['genre'] as $key => $value) {
447: foreach ($this->ParseID3v2GenreString($value) as $genre) {
448: $genres[] = $genre;
449: }
450: }
451: $thisfile_id3v2['comments']['genre'] = array_unique($genres);
452: unset($key, $value, $genres, $genre);
453: }
454:
455: if (isset($thisfile_id3v2['comments']['track'])) {
456: foreach ($thisfile_id3v2['comments']['track'] as $key => $value) {
457: if (strstr($value, '/')) {
458: list($thisfile_id3v2['comments']['tracknum'][$key], $thisfile_id3v2['comments']['totaltracks'][$key]) = explode('/', $thisfile_id3v2['comments']['track'][$key]);
459: }
460: }
461: }
462:
463: 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)) {
464: $thisfile_id3v2['comments']['year'] = array($matches[1]);
465: }
466:
467:
468: if (!empty($thisfile_id3v2['TXXX'])) {
469:
470: foreach ($thisfile_id3v2['TXXX'] as $txxx_array) {
471: switch ($txxx_array['description']) {
472: case 'replaygain_track_gain':
473: if (empty($info['replay_gain']['track']['adjustment']) && !empty($txxx_array['data'])) {
474: $info['replay_gain']['track']['adjustment'] = floatval(trim(str_replace('dB', '', $txxx_array['data'])));
475: }
476: break;
477: case 'replaygain_track_peak':
478: if (empty($info['replay_gain']['track']['peak']) && !empty($txxx_array['data'])) {
479: $info['replay_gain']['track']['peak'] = floatval($txxx_array['data']);
480: }
481: break;
482: case 'replaygain_album_gain':
483: if (empty($info['replay_gain']['album']['adjustment']) && !empty($txxx_array['data'])) {
484: $info['replay_gain']['album']['adjustment'] = floatval(trim(str_replace('dB', '', $txxx_array['data'])));
485: }
486: break;
487: }
488: }
489: }
490:
491:
492:
493: $info['avdataoffset'] = $thisfile_id3v2['headerlength'];
494: if (isset($thisfile_id3v2['footer'])) {
495: $info['avdataoffset'] += 10;
496: }
497:
498: return true;
499: }
500:
501:
502: public function ParseID3v2GenreString($genrestring) {
503:
504:
505:
506: $clean_genres = array();
507: if (strpos($genrestring, "\x00") === false) {
508: $genrestring = preg_replace('#\(([0-9]{1,3})\)#', '$1'."\x00", $genrestring);
509: }
510:
511:
512:
513: $genrestring = str_replace('/', "\x00", $genrestring);
514: $genrestring = str_replace('Pop'."\x00".'Funk', 'Pop/Funk', $genrestring);
515: $genrestring = str_replace('Rock'."\x00".'Rock', 'Folk/Rock', $genrestring);
516:
517:
518: $genrestring = str_replace(';', "\x00", $genrestring);
519:
520: $genre_elements = explode("\x00", $genrestring);
521: foreach ($genre_elements as $element) {
522: $element = trim($element);
523: if ($element) {
524: if (preg_match('#^[0-9]{1,3}#', $element)) {
525: $clean_genres[] = getid3_id3v1::LookupGenreName($element);
526: } else {
527: $clean_genres[] = str_replace('((', '(', $element);
528: }
529: }
530: }
531: return $clean_genres;
532: }
533:
534:
535: public function ParseID3v2Frame(&$parsedFrame) {
536:
537:
538: $info = &$this->getid3->info;
539: $id3v2_majorversion = $info['id3v2']['majorversion'];
540:
541: $parsedFrame['framenamelong'] = $this->FrameNameLongLookup($parsedFrame['frame_name']);
542: if (empty($parsedFrame['framenamelong'])) {
543: unset($parsedFrame['framenamelong']);
544: }
545: $parsedFrame['framenameshort'] = $this->FrameNameShortLookup($parsedFrame['frame_name']);
546: if (empty($parsedFrame['framenameshort'])) {
547: unset($parsedFrame['framenameshort']);
548: }
549:
550: if ($id3v2_majorversion >= 3) {
551: if ($id3v2_majorversion == 3) {
552:
553:
554: $parsedFrame['flags']['TagAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x8000);
555: $parsedFrame['flags']['FileAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x4000);
556: $parsedFrame['flags']['ReadOnly'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x2000);
557: $parsedFrame['flags']['compression'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0080);
558: $parsedFrame['flags']['Encryption'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0040);
559: $parsedFrame['flags']['GroupingIdentity'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0020);
560:
561: } elseif ($id3v2_majorversion == 4) {
562:
563:
564: $parsedFrame['flags']['TagAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x4000);
565: $parsedFrame['flags']['FileAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x2000);
566: $parsedFrame['flags']['ReadOnly'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x1000);
567: $parsedFrame['flags']['GroupingIdentity'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0040);
568: $parsedFrame['flags']['compression'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0008);
569: $parsedFrame['flags']['Encryption'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0004);
570: $parsedFrame['flags']['Unsynchronisation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0002);
571: $parsedFrame['flags']['DataLengthIndicator'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0001);
572:
573:
574: if ($parsedFrame['flags']['Unsynchronisation']) {
575: $parsedFrame['data'] = $this->DeUnsynchronise($parsedFrame['data']);
576: }
577:
578: if ($parsedFrame['flags']['DataLengthIndicator']) {
579: $parsedFrame['data_length_indicator'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 0, 4), 1);
580: $parsedFrame['data'] = substr($parsedFrame['data'], 4);
581: }
582: }
583:
584:
585: if ($parsedFrame['flags']['compression']) {
586: $parsedFrame['decompressed_size'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 0, 4));
587: if (!function_exists('gzuncompress')) {
588: $info['warning'][] = 'gzuncompress() support required to decompress ID3v2 frame "'.$parsedFrame['frame_name'].'"';
589: } else {
590: if ($decompresseddata = @gzuncompress(substr($parsedFrame['data'], 4))) {
591:
592: $parsedFrame['data'] = $decompresseddata;
593: unset($decompresseddata);
594: } else {
595: $info['warning'][] = 'gzuncompress() failed on compressed contents of ID3v2 frame "'.$parsedFrame['frame_name'].'"';
596: }
597: }
598: }
599: }
600:
601: if (!empty($parsedFrame['flags']['DataLengthIndicator'])) {
602: if ($parsedFrame['data_length_indicator'] != strlen($parsedFrame['data'])) {
603: $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';
604: }
605: }
606:
607: if (isset($parsedFrame['datalength']) && ($parsedFrame['datalength'] == 0)) {
608:
609: $warning = 'Frame "'.$parsedFrame['frame_name'].'" at offset '.$parsedFrame['dataoffset'].' has no data portion';
610: switch ($parsedFrame['frame_name']) {
611: case 'WCOM':
612: $warning .= ' (this is known to happen with files tagged by RioPort)';
613: break;
614:
615: default:
616: break;
617: }
618: $info['warning'][] = $warning;
619:
620: } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'UFID')) ||
621: (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'UFI'))) {
622:
623:
624:
625:
626:
627: $exploded = explode("\x00", $parsedFrame['data'], 2);
628: $parsedFrame['ownerid'] = (isset($exploded[0]) ? $exploded[0] : '');
629: $parsedFrame['data'] = (isset($exploded[1]) ? $exploded[1] : '');
630:
631: } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'TXXX')) ||
632: (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'TXX'))) {
633:
634:
635:
636:
637:
638:
639:
640: $frame_offset = 0;
641: $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
642: $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
643: if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
644: $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
645: $frame_textencoding_terminator = "\x00";
646: }
647: $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
648: if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
649: $frame_terminatorpos++;
650: }
651: $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
652: if (ord($frame_description) === 0) {
653: $frame_description = '';
654: }
655: $parsedFrame['encodingid'] = $frame_textencoding;
656: $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
657:
658: $parsedFrame['description'] = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $frame_description));
659: $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
660: if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
661: $commentkey = ($parsedFrame['description'] ? $parsedFrame['description'] : (isset($info['id3v2']['comments'][$parsedFrame['framenameshort']]) ? count($info['id3v2']['comments'][$parsedFrame['framenameshort']]) : 0));
662: if (!isset($info['id3v2']['comments'][$parsedFrame['framenameshort']]) || !array_key_exists($commentkey, $info['id3v2']['comments'][$parsedFrame['framenameshort']])) {
663: $info['id3v2']['comments'][$parsedFrame['framenameshort']][$commentkey] = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']));
664: } else {
665: $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']));
666: }
667: }
668:
669:
670:
671: } elseif ($parsedFrame['frame_name']{0} == 'T') {
672:
673:
674:
675:
676:
677:
678: $frame_offset = 0;
679: $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
680: if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
681: $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
682: }
683:
684: $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
685:
686: $parsedFrame['encodingid'] = $frame_textencoding;
687: $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
688:
689: if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
690:
691:
692:
693:
694: switch ($parsedFrame['encoding']) {
695: case 'UTF-16':
696: case 'UTF-16BE':
697: case 'UTF-16LE':
698: $wordsize = 2;
699: break;
700: case 'ISO-8859-1':
701: case 'UTF-8':
702: default:
703: $wordsize = 1;
704: break;
705: }
706: $Txxx_elements = array();
707: $Txxx_elements_start_offset = 0;
708: for ($i = 0; $i < strlen($parsedFrame['data']); $i += $wordsize) {
709: if (substr($parsedFrame['data'], $i, $wordsize) == str_repeat("\x00", $wordsize)) {
710: $Txxx_elements[] = substr($parsedFrame['data'], $Txxx_elements_start_offset, $i - $Txxx_elements_start_offset);
711: $Txxx_elements_start_offset = $i + $wordsize;
712: }
713: }
714: $Txxx_elements[] = substr($parsedFrame['data'], $Txxx_elements_start_offset, $i - $Txxx_elements_start_offset);
715: foreach ($Txxx_elements as $Txxx_element) {
716: $string = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $Txxx_element);
717: if (!empty($string)) {
718: $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $string;
719: }
720: }
721: unset($string, $wordsize, $i, $Txxx_elements, $Txxx_element, $Txxx_elements_start_offset);
722: }
723:
724: } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'WXXX')) ||
725: (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'WXX'))) {
726:
727:
728:
729:
730:
731:
732:
733: $frame_offset = 0;
734: $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
735: $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
736: if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
737: $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
738: $frame_textencoding_terminator = "\x00";
739: }
740: $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
741: if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
742: $frame_terminatorpos++;
743: }
744: $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
745:
746: if (ord($frame_description) === 0) {
747: $frame_description = '';
748: }
749: $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
750:
751: $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator);
752: if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
753: $frame_terminatorpos++;
754: }
755: if ($frame_terminatorpos) {
756:
757:
758: $frame_urldata = (string) substr($parsedFrame['data'], 0, $frame_terminatorpos);
759: } else {
760:
761: $frame_urldata = (string) $parsedFrame['data'];
762: }
763:
764: $parsedFrame['encodingid'] = $frame_textencoding;
765: $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
766:
767: $parsedFrame['url'] = $frame_urldata;
768: $parsedFrame['description'] = $frame_description;
769: if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) {
770: $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['url']);
771: }
772: unset($parsedFrame['data']);
773:
774:
775: } elseif ($parsedFrame['frame_name']{0} == 'W') {
776:
777:
778:
779:
780:
781:
782: $parsedFrame['url'] = trim($parsedFrame['data']);
783: if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) {
784: $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['url'];
785: }
786: unset($parsedFrame['data']);
787:
788:
789: } elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'IPLS')) ||
790: (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'IPL'))) {
791:
792:
793:
794:
795:
796:
797: $frame_offset = 0;
798: $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
799: if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
800: $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
801: }
802: $parsedFrame['encodingid'] = $frame_textencoding;
803: $parsedFrame['encoding'] = $this->TextEncodingNameLookup($parsedFrame['encodingid']);
804: $parsedFrame['data_raw'] = (string) substr($parsedFrame['data'], $frame_offset);
805:
806:
807:
808:
809: $IPLS_parts = array();
810: if (strpos($parsedFrame['data_raw'], "\x00") !== false) {
811: $IPLS_parts_unsorted = array();
812: if (((strlen($parsedFrame['data_raw']) % 2) == 0) && ((substr($parsedFrame['data_raw'], 0, 2) == "\xFF\xFE") || (substr($parsedFrame['data_raw'], 0, 2) == "\xFE\xFF"))) {
813:
814: $thisILPS = '';
815: for ($i = 0; $i < strlen($parsedFrame['data_raw']); $i += 2) {
816: $twobytes = substr($parsedFrame['data_raw'], $i, 2);
817: if ($twobytes === "\x00\x00") {
818: $IPLS_parts_unsorted[] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $thisILPS);
819: $thisILPS = '';
820: } else {
821: $thisILPS .= $twobytes;
822: }
823: }
824: if (strlen($thisILPS) > 2) {
825: $IPLS_parts_unsorted[] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $thisILPS);
826: }
827: } else {
828:
829: $IPLS_parts_unsorted = explode("\x00", $parsedFrame['data_raw']);
830: }
831: if (count($IPLS_parts_unsorted) == 1) {
832:
833: foreach ($IPLS_parts_unsorted as $key => $value) {
834: $IPLS_parts_sorted = preg_split('#[;,\\r\\n\\t]#', $value);
835: $position = '';
836: foreach ($IPLS_parts_sorted as $person) {
837: $IPLS_parts[] = array('position'=>$position, 'person'=>$person);
838: }
839: }
840: } elseif ((count($IPLS_parts_unsorted) % 2) == 0) {
841: $position = '';
842: $person = '';
843: foreach ($IPLS_parts_unsorted as $key => $value) {
844: if (($key % 2) == 0) {
845: $position = $value;
846: } else {
847: $person = $value;
848: $IPLS_parts[] = array('position'=>$position, 'person'=>$person);
849: $position = '';
850: $person = '';
851: }
852: }
853: } else {
854: foreach ($IPLS_parts_unsorted as $key => $value) {
855: $IPLS_parts[] = array($value);
856: }
857: }
858:
859: } else {
860: $IPLS_parts = preg_split('#[;,\\r\\n\\t]#', $parsedFrame['data_raw']);
861: }
862: $parsedFrame['data'] = $IPLS_parts;
863:
864: if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
865: $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['data'];
866: }
867:
868:
869: } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'MCDI')) ||
870: (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'MCI'))) {
871:
872:
873:
874:
875: if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
876: $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['data'];
877: }
878:
879:
880: } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'ETCO')) ||
881: (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'ETC'))) {
882:
883:
884:
885:
886:
887:
888:
889:
890:
891:
892:
893:
894: $frame_offset = 0;
895: $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
896:
897: while ($frame_offset < strlen($parsedFrame['data'])) {
898: $parsedFrame['typeid'] = substr($parsedFrame['data'], $frame_offset++, 1);
899: $parsedFrame['type'] = $this->ETCOEventLookup($parsedFrame['typeid']);
900: $parsedFrame['timestamp'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
901: $frame_offset += 4;
902: }
903: unset($parsedFrame['data']);
904:
905:
906: } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'MLLT')) ||
907: (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'MLL'))) {
908:
909:
910:
911:
912:
913:
914:
915:
916:
917:
918:
919: $frame_offset = 0;
920: $parsedFrame['framesbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 0, 2));
921: $parsedFrame['bytesbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 2, 3));
922: $parsedFrame['msbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 5, 3));
923: $parsedFrame['bitsforbytesdeviation'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 8, 1));
924: $parsedFrame['bitsformsdeviation'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 9, 1));
925: $parsedFrame['data'] = substr($parsedFrame['data'], 10);
926: while ($frame_offset < strlen($parsedFrame['data'])) {
927: $deviationbitstream .= getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1));
928: }
929: $reference_counter = 0;
930: while (strlen($deviationbitstream) > 0) {
931: $parsedFrame[$reference_counter]['bytedeviation'] = bindec(substr($deviationbitstream, 0, $parsedFrame['bitsforbytesdeviation']));
932: $parsedFrame[$reference_counter]['msdeviation'] = bindec(substr($deviationbitstream, $parsedFrame['bitsforbytesdeviation'], $parsedFrame['bitsformsdeviation']));
933: $deviationbitstream = substr($deviationbitstream, $parsedFrame['bitsforbytesdeviation'] + $parsedFrame['bitsformsdeviation']);
934: $reference_counter++;
935: }
936: unset($parsedFrame['data']);
937:
938:
939: } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'SYTC')) ||
940: (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'STC'))) {
941:
942:
943:
944:
945:
946:
947:
948:
949: $frame_offset = 0;
950: $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
951: $timestamp_counter = 0;
952: while ($frame_offset < strlen($parsedFrame['data'])) {
953: $parsedFrame[$timestamp_counter]['tempo'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
954: if ($parsedFrame[$timestamp_counter]['tempo'] == 255) {
955: $parsedFrame[$timestamp_counter]['tempo'] += ord(substr($parsedFrame['data'], $frame_offset++, 1));
956: }
957: $parsedFrame[$timestamp_counter]['timestamp'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
958: $frame_offset += 4;
959: $timestamp_counter++;
960: }
961: unset($parsedFrame['data']);
962:
963:
964: } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'USLT')) ||
965: (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'ULT'))) {
966:
967:
968:
969:
970:
971:
972:
973:
974: $frame_offset = 0;
975: $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
976: $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
977: if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
978: $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
979: $frame_textencoding_terminator = "\x00";
980: }
981: $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
982: $frame_offset += 3;
983: $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
984: if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
985: $frame_terminatorpos++;
986: }
987: $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
988: if (ord($frame_description) === 0) {
989: $frame_description = '';
990: }
991: $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
992:
993: $parsedFrame['encodingid'] = $frame_textencoding;
994: $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
995:
996: $parsedFrame['language'] = $frame_language;
997: $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
998: $parsedFrame['description'] = $frame_description;
999: if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
1000: $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
1001: }
1002: unset($parsedFrame['data']);
1003:
1004:
1005: } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'SYLT')) ||
1006: (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'SLT'))) {
1007:
1008:
1009:
1010:
1011:
1012:
1013:
1014:
1015:
1016:
1017:
1018:
1019:
1020:
1021: $frame_offset = 0;
1022: $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1023: $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
1024: if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
1025: $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
1026: $frame_textencoding_terminator = "\x00";
1027: }
1028: $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
1029: $frame_offset += 3;
1030: $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1031: $parsedFrame['contenttypeid'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1032: $parsedFrame['contenttype'] = $this->SYTLContentTypeLookup($parsedFrame['contenttypeid']);
1033: $parsedFrame['encodingid'] = $frame_textencoding;
1034: $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
1035:
1036: $parsedFrame['language'] = $frame_language;
1037: $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
1038:
1039: $timestampindex = 0;
1040: $frame_remainingdata = substr($parsedFrame['data'], $frame_offset);
1041: while (strlen($frame_remainingdata)) {
1042: $frame_offset = 0;
1043: $frame_terminatorpos = strpos($frame_remainingdata, $frame_textencoding_terminator);
1044: if ($frame_terminatorpos === false) {
1045: $frame_remainingdata = '';
1046: } else {
1047: if (ord(substr($frame_remainingdata, $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
1048: $frame_terminatorpos++;
1049: }
1050: $parsedFrame['lyrics'][$timestampindex]['data'] = substr($frame_remainingdata, $frame_offset, $frame_terminatorpos - $frame_offset);
1051:
1052: $frame_remainingdata = substr($frame_remainingdata, $frame_terminatorpos + strlen($frame_textencoding_terminator));
1053: if (($timestampindex == 0) && (ord($frame_remainingdata{0}) != 0)) {
1054:
1055: } else {
1056: $parsedFrame['lyrics'][$timestampindex]['timestamp'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 0, 4));
1057: $frame_remainingdata = substr($frame_remainingdata, 4);
1058: }
1059: $timestampindex++;
1060: }
1061: }
1062: unset($parsedFrame['data']);
1063:
1064:
1065: } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'COMM')) ||
1066: (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'COM'))) {
1067:
1068:
1069:
1070:
1071:
1072:
1073:
1074:
1075: if (strlen($parsedFrame['data']) < 5) {
1076:
1077: $info['warning'][] = 'Invalid data (too short) for "'.$parsedFrame['frame_name'].'" frame at offset '.$parsedFrame['dataoffset'];
1078:
1079: } else {
1080:
1081: $frame_offset = 0;
1082: $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1083: $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
1084: if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
1085: $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
1086: $frame_textencoding_terminator = "\x00";
1087: }
1088: $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
1089: $frame_offset += 3;
1090: $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
1091: if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
1092: $frame_terminatorpos++;
1093: }
1094: $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1095: if (ord($frame_description) === 0) {
1096: $frame_description = '';
1097: }
1098: $frame_text = (string) substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
1099:
1100: $parsedFrame['encodingid'] = $frame_textencoding;
1101: $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
1102:
1103: $parsedFrame['language'] = $frame_language;
1104: $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
1105: $parsedFrame['description'] = $frame_description;
1106: $parsedFrame['data'] = $frame_text;
1107: if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
1108: $commentkey = ($parsedFrame['description'] ? $parsedFrame['description'] : (!empty($info['id3v2']['comments'][$parsedFrame['framenameshort']]) ? count($info['id3v2']['comments'][$parsedFrame['framenameshort']]) : 0));
1109: if (!isset($info['id3v2']['comments'][$parsedFrame['framenameshort']]) || !array_key_exists($commentkey, $info['id3v2']['comments'][$parsedFrame['framenameshort']])) {
1110: $info['id3v2']['comments'][$parsedFrame['framenameshort']][$commentkey] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
1111: } else {
1112: $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
1113: }
1114: }
1115:
1116: }
1117:
1118: } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'RVA2')) {
1119:
1120:
1121:
1122:
1123:
1124:
1125:
1126:
1127:
1128:
1129:
1130:
1131: $frame_terminatorpos = strpos($parsedFrame['data'], "\x00");
1132: $frame_idstring = substr($parsedFrame['data'], 0, $frame_terminatorpos);
1133: if (ord($frame_idstring) === 0) {
1134: $frame_idstring = '';
1135: }
1136: $frame_remainingdata = substr($parsedFrame['data'], $frame_terminatorpos + strlen("\x00"));
1137: $parsedFrame['description'] = $frame_idstring;
1138: $RVA2channelcounter = 0;
1139: while (strlen($frame_remainingdata) >= 5) {
1140: $frame_offset = 0;
1141: $frame_channeltypeid = ord(substr($frame_remainingdata, $frame_offset++, 1));
1142: $parsedFrame[$RVA2channelcounter]['channeltypeid'] = $frame_channeltypeid;
1143: $parsedFrame[$RVA2channelcounter]['channeltype'] = $this->RVA2ChannelTypeLookup($frame_channeltypeid);
1144: $parsedFrame[$RVA2channelcounter]['volumeadjust'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, $frame_offset, 2), false, true);
1145: $frame_offset += 2;
1146: $parsedFrame[$RVA2channelcounter]['bitspeakvolume'] = ord(substr($frame_remainingdata, $frame_offset++, 1));
1147: if (($parsedFrame[$RVA2channelcounter]['bitspeakvolume'] < 1) || ($parsedFrame[$RVA2channelcounter]['bitspeakvolume'] > 4)) {
1148: $info['warning'][] = 'ID3v2::RVA2 frame['.$RVA2channelcounter.'] contains invalid '.$parsedFrame[$RVA2channelcounter]['bitspeakvolume'].'-byte bits-representing-peak value';
1149: break;
1150: }
1151: $frame_bytespeakvolume = ceil($parsedFrame[$RVA2channelcounter]['bitspeakvolume'] / 8);
1152: $parsedFrame[$RVA2channelcounter]['peakvolume'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, $frame_offset, $frame_bytespeakvolume));
1153: $frame_remainingdata = substr($frame_remainingdata, $frame_offset + $frame_bytespeakvolume);
1154: $RVA2channelcounter++;
1155: }
1156: unset($parsedFrame['data']);
1157:
1158:
1159: } elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'RVAD')) ||
1160: (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'RVA'))) {
1161:
1162:
1163:
1164:
1165:
1166:
1167:
1168:
1169:
1170:
1171:
1172:
1173:
1174:
1175:
1176:
1177:
1178:
1179:
1180:
1181:
1182: $frame_offset = 0;
1183: $frame_incrdecrflags = getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1));
1184: $parsedFrame['incdec']['right'] = (bool) substr($frame_incrdecrflags, 6, 1);
1185: $parsedFrame['incdec']['left'] = (bool) substr($frame_incrdecrflags, 7, 1);
1186: $parsedFrame['bitsvolume'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1187: $frame_bytesvolume = ceil($parsedFrame['bitsvolume'] / 8);
1188: $parsedFrame['volumechange']['right'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1189: if ($parsedFrame['incdec']['right'] === false) {
1190: $parsedFrame['volumechange']['right'] *= -1;
1191: }
1192: $frame_offset += $frame_bytesvolume;
1193: $parsedFrame['volumechange']['left'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1194: if ($parsedFrame['incdec']['left'] === false) {
1195: $parsedFrame['volumechange']['left'] *= -1;
1196: }
1197: $frame_offset += $frame_bytesvolume;
1198: $parsedFrame['peakvolume']['right'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1199: $frame_offset += $frame_bytesvolume;
1200: $parsedFrame['peakvolume']['left'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1201: $frame_offset += $frame_bytesvolume;
1202: if ($id3v2_majorversion == 3) {
1203: $parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset);
1204: if (strlen($parsedFrame['data']) > 0) {
1205: $parsedFrame['incdec']['rightrear'] = (bool) substr($frame_incrdecrflags, 4, 1);
1206: $parsedFrame['incdec']['leftrear'] = (bool) substr($frame_incrdecrflags, 5, 1);
1207: $parsedFrame['volumechange']['rightrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1208: if ($parsedFrame['incdec']['rightrear'] === false) {
1209: $parsedFrame['volumechange']['rightrear'] *= -1;
1210: }
1211: $frame_offset += $frame_bytesvolume;
1212: $parsedFrame['volumechange']['leftrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1213: if ($parsedFrame['incdec']['leftrear'] === false) {
1214: $parsedFrame['volumechange']['leftrear'] *= -1;
1215: }
1216: $frame_offset += $frame_bytesvolume;
1217: $parsedFrame['peakvolume']['rightrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1218: $frame_offset += $frame_bytesvolume;
1219: $parsedFrame['peakvolume']['leftrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1220: $frame_offset += $frame_bytesvolume;
1221: }
1222: $parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset);
1223: if (strlen($parsedFrame['data']) > 0) {
1224: $parsedFrame['incdec']['center'] = (bool) substr($frame_incrdecrflags, 3, 1);
1225: $parsedFrame['volumechange']['center'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1226: if ($parsedFrame['incdec']['center'] === false) {
1227: $parsedFrame['volumechange']['center'] *= -1;
1228: }
1229: $frame_offset += $frame_bytesvolume;
1230: $parsedFrame['peakvolume']['center'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1231: $frame_offset += $frame_bytesvolume;
1232: }
1233: $parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset);
1234: if (strlen($parsedFrame['data']) > 0) {
1235: $parsedFrame['incdec']['bass'] = (bool) substr($frame_incrdecrflags, 2, 1);
1236: $parsedFrame['volumechange']['bass'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1237: if ($parsedFrame['incdec']['bass'] === false) {
1238: $parsedFrame['volumechange']['bass'] *= -1;
1239: }
1240: $frame_offset += $frame_bytesvolume;
1241: $parsedFrame['peakvolume']['bass'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1242: $frame_offset += $frame_bytesvolume;
1243: }
1244: }
1245: unset($parsedFrame['data']);
1246:
1247:
1248: } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'EQU2')) {
1249:
1250:
1251:
1252:
1253:
1254:
1255:
1256:
1257:
1258:
1259:
1260: $frame_offset = 0;
1261: $frame_interpolationmethod = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1262: $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1263: $frame_idstring = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1264: if (ord($frame_idstring) === 0) {
1265: $frame_idstring = '';
1266: }
1267: $parsedFrame['description'] = $frame_idstring;
1268: $frame_remainingdata = substr($parsedFrame['data'], $frame_terminatorpos + strlen("\x00"));
1269: while (strlen($frame_remainingdata)) {
1270: $frame_frequency = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 0, 2)) / 2;
1271: $parsedFrame['data'][$frame_frequency] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 2, 2), false, true);
1272: $frame_remainingdata = substr($frame_remainingdata, 4);
1273: }
1274: $parsedFrame['interpolationmethod'] = $frame_interpolationmethod;
1275: unset($parsedFrame['data']);
1276:
1277:
1278: } elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'EQUA')) ||
1279: (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'EQU'))) {
1280:
1281:
1282:
1283:
1284:
1285:
1286:
1287:
1288:
1289:
1290: $frame_offset = 0;
1291: $parsedFrame['adjustmentbits'] = substr($parsedFrame['data'], $frame_offset++, 1);
1292: $frame_adjustmentbytes = ceil($parsedFrame['adjustmentbits'] / 8);
1293:
1294: $frame_remainingdata = (string) substr($parsedFrame['data'], $frame_offset);
1295: while (strlen($frame_remainingdata) > 0) {
1296: $frame_frequencystr = getid3_lib::BigEndian2Bin(substr($frame_remainingdata, 0, 2));
1297: $frame_incdec = (bool) substr($frame_frequencystr, 0, 1);
1298: $frame_frequency = bindec(substr($frame_frequencystr, 1, 15));
1299: $parsedFrame[$frame_frequency]['incdec'] = $frame_incdec;
1300: $parsedFrame[$frame_frequency]['adjustment'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 2, $frame_adjustmentbytes));
1301: if ($parsedFrame[$frame_frequency]['incdec'] === false) {
1302: $parsedFrame[$frame_frequency]['adjustment'] *= -1;
1303: }
1304: $frame_remainingdata = substr($frame_remainingdata, 2 + $frame_adjustmentbytes);
1305: }
1306: unset($parsedFrame['data']);
1307:
1308:
1309: } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RVRB')) ||
1310: (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'REV'))) {
1311:
1312:
1313:
1314:
1315:
1316:
1317:
1318:
1319:
1320:
1321:
1322:
1323:
1324: $frame_offset = 0;
1325: $parsedFrame['left'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
1326: $frame_offset += 2;
1327: $parsedFrame['right'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
1328: $frame_offset += 2;
1329: $parsedFrame['bouncesL'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1330: $parsedFrame['bouncesR'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1331: $parsedFrame['feedbackLL'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1332: $parsedFrame['feedbackLR'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1333: $parsedFrame['feedbackRR'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1334: $parsedFrame['feedbackRL'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1335: $parsedFrame['premixLR'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1336: $parsedFrame['premixRL'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1337: unset($parsedFrame['data']);
1338:
1339:
1340: } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'APIC')) ||
1341: (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'PIC'))) {
1342:
1343:
1344:
1345:
1346:
1347:
1348:
1349:
1350:
1351:
1352:
1353: $frame_offset = 0;
1354: $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1355: $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
1356: if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
1357: $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
1358: $frame_textencoding_terminator = "\x00";
1359: }
1360:
1361: if ($id3v2_majorversion == 2 && strlen($parsedFrame['data']) > $frame_offset) {
1362: $frame_imagetype = substr($parsedFrame['data'], $frame_offset, 3);
1363: if (strtolower($frame_imagetype) == 'ima') {
1364:
1365:
1366: $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1367: $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1368: if (ord($frame_mimetype) === 0) {
1369: $frame_mimetype = '';
1370: }
1371: $frame_imagetype = strtoupper(str_replace('image/', '', strtolower($frame_mimetype)));
1372: if ($frame_imagetype == 'JPEG') {
1373: $frame_imagetype = 'JPG';
1374: }
1375: $frame_offset = $frame_terminatorpos + strlen("\x00");
1376: } else {
1377: $frame_offset += 3;
1378: }
1379: }
1380: if ($id3v2_majorversion > 2 && strlen($parsedFrame['data']) > $frame_offset) {
1381: $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1382: $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1383: if (ord($frame_mimetype) === 0) {
1384: $frame_mimetype = '';
1385: }
1386: $frame_offset = $frame_terminatorpos + strlen("\x00");
1387: }
1388:
1389: $frame_picturetype = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1390:
1391: if ($frame_offset >= $parsedFrame['datalength']) {
1392: $info['warning'][] = 'data portion of APIC frame is missing at offset '.($parsedFrame['dataoffset'] + 8 + $frame_offset);
1393: } else {
1394: $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
1395: if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
1396: $frame_terminatorpos++;
1397: }
1398: $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1399: if (ord($frame_description) === 0) {
1400: $frame_description = '';
1401: }
1402: $parsedFrame['encodingid'] = $frame_textencoding;
1403: $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
1404:
1405: if ($id3v2_majorversion == 2) {
1406: $parsedFrame['imagetype'] = $frame_imagetype;
1407: } else {
1408: $parsedFrame['mime'] = $frame_mimetype;
1409: }
1410: $parsedFrame['picturetypeid'] = $frame_picturetype;
1411: $parsedFrame['picturetype'] = $this->APICPictureTypeLookup($frame_picturetype);
1412: $parsedFrame['description'] = $frame_description;
1413: $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
1414: $parsedFrame['datalength'] = strlen($parsedFrame['data']);
1415:
1416: $parsedFrame['image_mime'] = '';
1417: $imageinfo = array();
1418: if ($imagechunkcheck = getid3_lib::GetDataImageSize($parsedFrame['data'], $imageinfo)) {
1419: if (($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3)) {
1420: $parsedFrame['image_mime'] = 'image/'.getid3_lib::ImageTypesLookup($imagechunkcheck[2]);
1421: if ($imagechunkcheck[0]) {
1422: $parsedFrame['image_width'] = $imagechunkcheck[0];
1423: }
1424: if ($imagechunkcheck[1]) {
1425: $parsedFrame['image_height'] = $imagechunkcheck[1];
1426: }
1427: }
1428: }
1429:
1430: do {
1431: if ($this->getid3->option_save_attachments === false) {
1432:
1433: unset($parsedFrame['data']);
1434: break;
1435: }
1436: if ($this->getid3->option_save_attachments === true) {
1437:
1438: 1439: 1440: 1441: 1442: 1443: 1444: 1445: 1446:
1447: } elseif (is_string($this->getid3->option_save_attachments)) {
1448: $dir = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->getid3->option_save_attachments), DIRECTORY_SEPARATOR);
1449: if (!is_dir($dir) || !is_writable($dir)) {
1450:
1451: $info['warning'][] = 'attachment at '.$frame_offset.' cannot be saved to "'.$dir.'" (not writable)';
1452: unset($parsedFrame['data']);
1453: break;
1454: }
1455: }
1456:
1457: if (is_string($this->getid3->option_save_attachments)) {
1458: $destination_filename = $dir.DIRECTORY_SEPARATOR.md5($info['filenamepath']).'_'.$frame_offset;
1459: if (!file_exists($destination_filename) || is_writable($destination_filename)) {
1460: file_put_contents($destination_filename, $parsedFrame['data']);
1461: } else {
1462: $info['warning'][] = 'attachment at '.$frame_offset.' cannot be saved to "'.$destination_filename.'" (not writable)';
1463: }
1464: $parsedFrame['data_filename'] = $destination_filename;
1465: unset($parsedFrame['data']);
1466: } else {
1467: if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
1468: if (!isset($info['id3v2']['comments']['picture'])) {
1469: $info['id3v2']['comments']['picture'] = array();
1470: }
1471: $comments_picture_data = array();
1472: foreach (array('data', 'image_mime', 'image_width', 'image_height', 'imagetype', 'picturetype', 'description', 'datalength') as $picture_key) {
1473: if (isset($parsedFrame[$picture_key])) {
1474: $comments_picture_data[$picture_key] = $parsedFrame[$picture_key];
1475: }
1476: }
1477: $info['id3v2']['comments']['picture'][] = $comments_picture_data;
1478: unset($comments_picture_data);
1479: }
1480: }
1481: } while (false);
1482: }
1483:
1484: } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'GEOB')) ||
1485: (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'GEO'))) {
1486:
1487:
1488:
1489:
1490:
1491:
1492:
1493:
1494:
1495: $frame_offset = 0;
1496: $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1497: $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
1498: if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
1499: $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
1500: $frame_textencoding_terminator = "\x00";
1501: }
1502: $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1503: $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1504: if (ord($frame_mimetype) === 0) {
1505: $frame_mimetype = '';
1506: }
1507: $frame_offset = $frame_terminatorpos + strlen("\x00");
1508:
1509: $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
1510: if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
1511: $frame_terminatorpos++;
1512: }
1513: $frame_filename = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1514: if (ord($frame_filename) === 0) {
1515: $frame_filename = '';
1516: }
1517: $frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator);
1518:
1519: $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
1520: if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
1521: $frame_terminatorpos++;
1522: }
1523: $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1524: if (ord($frame_description) === 0) {
1525: $frame_description = '';
1526: }
1527: $frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator);
1528:
1529: $parsedFrame['objectdata'] = (string) substr($parsedFrame['data'], $frame_offset);
1530: $parsedFrame['encodingid'] = $frame_textencoding;
1531: $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
1532:
1533: $parsedFrame['mime'] = $frame_mimetype;
1534: $parsedFrame['filename'] = $frame_filename;
1535: $parsedFrame['description'] = $frame_description;
1536: unset($parsedFrame['data']);
1537:
1538:
1539: } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'PCNT')) ||
1540: (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CNT'))) {
1541:
1542:
1543:
1544:
1545:
1546:
1547: $parsedFrame['data'] = getid3_lib::BigEndian2Int($parsedFrame['data']);
1548:
1549:
1550: } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'POPM')) ||
1551: (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'POP'))) {
1552:
1553:
1554:
1555:
1556:
1557:
1558:
1559: $frame_offset = 0;
1560: $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1561: $frame_emailaddress = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1562: if (ord($frame_emailaddress) === 0) {
1563: $frame_emailaddress = '';
1564: }
1565: $frame_offset = $frame_terminatorpos + strlen("\x00");
1566: $frame_rating = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1567: $parsedFrame['counter'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset));
1568: $parsedFrame['email'] = $frame_emailaddress;
1569: $parsedFrame['rating'] = $frame_rating;
1570: unset($parsedFrame['data']);
1571:
1572:
1573: } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RBUF')) ||
1574: (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'BUF'))) {
1575:
1576:
1577:
1578:
1579:
1580:
1581: $frame_offset = 0;
1582: $parsedFrame['buffersize'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 3));
1583: $frame_offset += 3;
1584:
1585: $frame_embeddedinfoflags = getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1));
1586: $parsedFrame['flags']['embededinfo'] = (bool) substr($frame_embeddedinfoflags, 7, 1);
1587: $parsedFrame['nexttagoffset'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
1588: unset($parsedFrame['data']);
1589:
1590:
1591: } elseif (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CRM')) {
1592:
1593:
1594:
1595:
1596:
1597:
1598:
1599: $frame_offset = 0;
1600: $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1601: $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1602: $frame_offset = $frame_terminatorpos + strlen("\x00");
1603:
1604: $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1605: $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1606: if (ord($frame_description) === 0) {
1607: $frame_description = '';
1608: }
1609: $frame_offset = $frame_terminatorpos + strlen("\x00");
1610:
1611: $parsedFrame['ownerid'] = $frame_ownerid;
1612: $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
1613: $parsedFrame['description'] = $frame_description;
1614: unset($parsedFrame['data']);
1615:
1616:
1617: } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'AENC')) ||
1618: (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CRA'))) {
1619:
1620:
1621:
1622:
1623:
1624:
1625:
1626:
1627: $frame_offset = 0;
1628: $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1629: $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1630: if (ord($frame_ownerid) === 0) {
1631: $frame_ownerid = '';
1632: }
1633: $frame_offset = $frame_terminatorpos + strlen("\x00");
1634: $parsedFrame['ownerid'] = $frame_ownerid;
1635: $parsedFrame['previewstart'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
1636: $frame_offset += 2;
1637: $parsedFrame['previewlength'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
1638: $frame_offset += 2;
1639: $parsedFrame['encryptioninfo'] = (string) substr($parsedFrame['data'], $frame_offset);
1640: unset($parsedFrame['data']);
1641:
1642:
1643: } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'LINK')) ||
1644: (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'LNK'))) {
1645:
1646:
1647:
1648:
1649:
1650:
1651:
1652:
1653: $frame_offset = 0;
1654: if ($id3v2_majorversion == 2) {
1655: $parsedFrame['frameid'] = substr($parsedFrame['data'], $frame_offset, 3);
1656: $frame_offset += 3;
1657: } else {
1658: $parsedFrame['frameid'] = substr($parsedFrame['data'], $frame_offset, 4);
1659: $frame_offset += 4;
1660: }
1661:
1662: $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1663: $frame_url = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1664: if (ord($frame_url) === 0) {
1665: $frame_url = '';
1666: }
1667: $frame_offset = $frame_terminatorpos + strlen("\x00");
1668: $parsedFrame['url'] = $frame_url;
1669:
1670: $parsedFrame['additionaldata'] = (string) substr($parsedFrame['data'], $frame_offset);
1671: if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) {
1672: $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback_iso88591_utf8($parsedFrame['url']);
1673: }
1674: unset($parsedFrame['data']);
1675:
1676:
1677: } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'POSS')) {
1678:
1679:
1680:
1681:
1682:
1683: $frame_offset = 0;
1684: $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1685: $parsedFrame['position'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset));
1686: unset($parsedFrame['data']);
1687:
1688:
1689: } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'USER')) {
1690:
1691:
1692:
1693:
1694:
1695:
1696:
1697: $frame_offset = 0;
1698: $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1699: if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
1700: $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
1701: }
1702: $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
1703: $frame_offset += 3;
1704: $parsedFrame['language'] = $frame_language;
1705: $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
1706: $parsedFrame['encodingid'] = $frame_textencoding;
1707: $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
1708:
1709: $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
1710: if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
1711: $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
1712: }
1713: unset($parsedFrame['data']);
1714:
1715:
1716: } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'OWNE')) {
1717:
1718:
1719:
1720:
1721:
1722:
1723:
1724: $frame_offset = 0;
1725: $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1726: if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
1727: $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
1728: }
1729: $parsedFrame['encodingid'] = $frame_textencoding;
1730: $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
1731:
1732: $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1733: $frame_pricepaid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1734: $frame_offset = $frame_terminatorpos + strlen("\x00");
1735:
1736: $parsedFrame['pricepaid']['currencyid'] = substr($frame_pricepaid, 0, 3);
1737: $parsedFrame['pricepaid']['currency'] = $this->LookupCurrencyUnits($parsedFrame['pricepaid']['currencyid']);
1738: $parsedFrame['pricepaid']['value'] = substr($frame_pricepaid, 3);
1739:
1740: $parsedFrame['purchasedate'] = substr($parsedFrame['data'], $frame_offset, 8);
1741: if (!$this->IsValidDateStampString($parsedFrame['purchasedate'])) {
1742: $parsedFrame['purchasedateunix'] = mktime (0, 0, 0, substr($parsedFrame['purchasedate'], 4, 2), substr($parsedFrame['purchasedate'], 6, 2), substr($parsedFrame['purchasedate'], 0, 4));
1743: }
1744: $frame_offset += 8;
1745:
1746: $parsedFrame['seller'] = (string) substr($parsedFrame['data'], $frame_offset);
1747: unset($parsedFrame['data']);
1748:
1749:
1750: } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'COMR')) {
1751:
1752:
1753:
1754:
1755:
1756:
1757:
1758:
1759:
1760:
1761:
1762:
1763:
1764: $frame_offset = 0;
1765: $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1766: $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
1767: if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
1768: $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
1769: $frame_textencoding_terminator = "\x00";
1770: }
1771:
1772: $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1773: $frame_pricestring = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1774: $frame_offset = $frame_terminatorpos + strlen("\x00");
1775: $frame_rawpricearray = explode('/', $frame_pricestring);
1776: foreach ($frame_rawpricearray as $key => $val) {
1777: $frame_currencyid = substr($val, 0, 3);
1778: $parsedFrame['price'][$frame_currencyid]['currency'] = $this->LookupCurrencyUnits($frame_currencyid);
1779: $parsedFrame['price'][$frame_currencyid]['value'] = substr($val, 3);
1780: }
1781:
1782: $frame_datestring = substr($parsedFrame['data'], $frame_offset, 8);
1783: $frame_offset += 8;
1784:
1785: $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1786: $frame_contacturl = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1787: $frame_offset = $frame_terminatorpos + strlen("\x00");
1788:
1789: $frame_receivedasid = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1790:
1791: $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
1792: if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
1793: $frame_terminatorpos++;
1794: }
1795: $frame_sellername = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1796: if (ord($frame_sellername) === 0) {
1797: $frame_sellername = '';
1798: }
1799: $frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator);
1800:
1801: $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
1802: if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
1803: $frame_terminatorpos++;
1804: }
1805: $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1806: if (ord($frame_description) === 0) {
1807: $frame_description = '';
1808: }
1809: $frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator);
1810:
1811: $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1812: $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1813: $frame_offset = $frame_terminatorpos + strlen("\x00");
1814:
1815: $frame_sellerlogo = substr($parsedFrame['data'], $frame_offset);
1816:
1817: $parsedFrame['encodingid'] = $frame_textencoding;
1818: $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
1819:
1820: $parsedFrame['pricevaliduntil'] = $frame_datestring;
1821: $parsedFrame['contacturl'] = $frame_contacturl;
1822: $parsedFrame['receivedasid'] = $frame_receivedasid;
1823: $parsedFrame['receivedas'] = $this->COMRReceivedAsLookup($frame_receivedasid);
1824: $parsedFrame['sellername'] = $frame_sellername;
1825: $parsedFrame['description'] = $frame_description;
1826: $parsedFrame['mime'] = $frame_mimetype;
1827: $parsedFrame['logo'] = $frame_sellerlogo;
1828: unset($parsedFrame['data']);
1829:
1830:
1831: } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'ENCR')) {
1832:
1833:
1834:
1835:
1836:
1837:
1838:
1839:
1840: $frame_offset = 0;
1841: $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1842: $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1843: if (ord($frame_ownerid) === 0) {
1844: $frame_ownerid = '';
1845: }
1846: $frame_offset = $frame_terminatorpos + strlen("\x00");
1847:
1848: $parsedFrame['ownerid'] = $frame_ownerid;
1849: $parsedFrame['methodsymbol'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1850: $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
1851:
1852:
1853: } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'GRID')) {
1854:
1855:
1856:
1857:
1858:
1859:
1860:
1861:
1862:
1863: $frame_offset = 0;
1864: $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1865: $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1866: if (ord($frame_ownerid) === 0) {
1867: $frame_ownerid = '';
1868: }
1869: $frame_offset = $frame_terminatorpos + strlen("\x00");
1870:
1871: $parsedFrame['ownerid'] = $frame_ownerid;
1872: $parsedFrame['groupsymbol'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1873: $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
1874:
1875:
1876: } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'PRIV')) {
1877:
1878:
1879:
1880:
1881:
1882:
1883: $frame_offset = 0;
1884: $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1885: $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1886: if (ord($frame_ownerid) === 0) {
1887: $frame_ownerid = '';
1888: }
1889: $frame_offset = $frame_terminatorpos + strlen("\x00");
1890:
1891: $parsedFrame['ownerid'] = $frame_ownerid;
1892: $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
1893:
1894:
1895: } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'SIGN')) {
1896:
1897:
1898:
1899:
1900:
1901:
1902: $frame_offset = 0;
1903: $parsedFrame['groupsymbol'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1904: $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
1905:
1906:
1907: } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'SEEK')) {
1908:
1909:
1910:
1911:
1912: $frame_offset = 0;
1913: $parsedFrame['data'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
1914:
1915:
1916: } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'ASPI')) {
1917:
1918:
1919:
1920:
1921:
1922:
1923:
1924:
1925:
1926: $frame_offset = 0;
1927: $parsedFrame['datastart'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
1928: $frame_offset += 4;
1929: $parsedFrame['indexeddatalength'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
1930: $frame_offset += 4;
1931: $parsedFrame['indexpoints'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
1932: $frame_offset += 2;
1933: $parsedFrame['bitsperpoint'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1934: $frame_bytesperpoint = ceil($parsedFrame['bitsperpoint'] / 8);
1935: for ($i = 0; $i < $parsedFrame['indexpoints']; $i++) {
1936: $parsedFrame['indexes'][$i] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesperpoint));
1937: $frame_offset += $frame_bytesperpoint;
1938: }
1939: unset($parsedFrame['data']);
1940:
1941: } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RGAD')) {
1942:
1943:
1944:
1945:
1946:
1947:
1948:
1949:
1950:
1951:
1952:
1953: $frame_offset = 0;
1954: $parsedFrame['peakamplitude'] = getid3_lib::BigEndian2Float(substr($parsedFrame['data'], $frame_offset, 4));
1955: $frame_offset += 4;
1956: $rg_track_adjustment = getid3_lib::Dec2Bin(substr($parsedFrame['data'], $frame_offset, 2));
1957: $frame_offset += 2;
1958: $rg_album_adjustment = getid3_lib::Dec2Bin(substr($parsedFrame['data'], $frame_offset, 2));
1959: $frame_offset += 2;
1960: $parsedFrame['raw']['track']['name'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 0, 3));
1961: $parsedFrame['raw']['track']['originator'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 3, 3));
1962: $parsedFrame['raw']['track']['signbit'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 6, 1));
1963: $parsedFrame['raw']['track']['adjustment'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 7, 9));
1964: $parsedFrame['raw']['album']['name'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 0, 3));
1965: $parsedFrame['raw']['album']['originator'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 3, 3));
1966: $parsedFrame['raw']['album']['signbit'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 6, 1));
1967: $parsedFrame['raw']['album']['adjustment'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 7, 9));
1968: $parsedFrame['track']['name'] = getid3_lib::RGADnameLookup($parsedFrame['raw']['track']['name']);
1969: $parsedFrame['track']['originator'] = getid3_lib::RGADoriginatorLookup($parsedFrame['raw']['track']['originator']);
1970: $parsedFrame['track']['adjustment'] = getid3_lib::RGADadjustmentLookup($parsedFrame['raw']['track']['adjustment'], $parsedFrame['raw']['track']['signbit']);
1971: $parsedFrame['album']['name'] = getid3_lib::RGADnameLookup($parsedFrame['raw']['album']['name']);
1972: $parsedFrame['album']['originator'] = getid3_lib::RGADoriginatorLookup($parsedFrame['raw']['album']['originator']);
1973: $parsedFrame['album']['adjustment'] = getid3_lib::RGADadjustmentLookup($parsedFrame['raw']['album']['adjustment'], $parsedFrame['raw']['album']['signbit']);
1974:
1975: $info['replay_gain']['track']['peak'] = $parsedFrame['peakamplitude'];
1976: $info['replay_gain']['track']['originator'] = $parsedFrame['track']['originator'];
1977: $info['replay_gain']['track']['adjustment'] = $parsedFrame['track']['adjustment'];
1978: $info['replay_gain']['album']['originator'] = $parsedFrame['album']['originator'];
1979: $info['replay_gain']['album']['adjustment'] = $parsedFrame['album']['adjustment'];
1980:
1981: unset($parsedFrame['data']);
1982:
1983: } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'CHAP')) {
1984:
1985:
1986:
1987:
1988:
1989:
1990:
1991:
1992:
1993: $frame_offset = 0;
1994: @list($parsedFrame['element_id']) = explode("\x00", $parsedFrame['data'], 2);
1995: $frame_offset += strlen($parsedFrame['element_id']."\x00");
1996: $parsedFrame['time_begin'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
1997: $frame_offset += 4;
1998: $parsedFrame['time_end'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
1999: $frame_offset += 4;
2000: if (substr($parsedFrame['data'], $frame_offset, 4) != "\xFF\xFF\xFF\xFF") {
2001:
2002: $parsedFrame['offset_begin'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
2003: }
2004: $frame_offset += 4;
2005: if (substr($parsedFrame['data'], $frame_offset, 4) != "\xFF\xFF\xFF\xFF") {
2006:
2007: $parsedFrame['offset_end'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
2008: }
2009: $frame_offset += 4;
2010:
2011: if ($frame_offset < strlen($parsedFrame['data'])) {
2012: $parsedFrame['subframes'] = array();
2013: while ($frame_offset < strlen($parsedFrame['data'])) {
2014:
2015: $subframe = array();
2016: $subframe['name'] = substr($parsedFrame['data'], $frame_offset, 4);
2017: $frame_offset += 4;
2018: $subframe['size'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
2019: $frame_offset += 4;
2020: $subframe['flags_raw'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
2021: $frame_offset += 2;
2022: if ($subframe['size'] > (strlen($parsedFrame['data']) - $frame_offset)) {
2023: $info['warning'][] = 'CHAP subframe "'.$subframe['name'].'" at frame offset '.$frame_offset.' claims to be "'.$subframe['size'].'" bytes, which is more than the available data ('.(strlen($parsedFrame['data']) - $frame_offset).' bytes)';
2024: break;
2025: }
2026: $subframe_rawdata = substr($parsedFrame['data'], $frame_offset, $subframe['size']);
2027: $frame_offset += $subframe['size'];
2028:
2029: $subframe['encodingid'] = ord(substr($subframe_rawdata, 0, 1));
2030: $subframe['text'] = substr($subframe_rawdata, 1);
2031: $subframe['encoding'] = $this->TextEncodingNameLookup($subframe['encodingid']);
2032: $encoding_converted_text = trim(getid3_lib::iconv_fallback($subframe['encoding'], $info['encoding'], $subframe['text']));;
2033: switch (substr($encoding_converted_text, 0, 2)) {
2034: case "\xFF\xFE":
2035: case "\xFE\xFF":
2036: switch (strtoupper($info['id3v2']['encoding'])) {
2037: case 'ISO-8859-1':
2038: case 'UTF-8':
2039: $encoding_converted_text = substr($encoding_converted_text, 2);
2040:
2041: break;
2042: default:
2043:
2044: break;
2045: }
2046: break;
2047: default:
2048:
2049: break;
2050: }
2051:
2052: if (($subframe['name'] == 'TIT2') || ($subframe['name'] == 'TIT3')) {
2053: if ($subframe['name'] == 'TIT2') {
2054: $parsedFrame['chapter_name'] = $encoding_converted_text;
2055: } elseif ($subframe['name'] == 'TIT3') {
2056: $parsedFrame['chapter_description'] = $encoding_converted_text;
2057: }
2058: $parsedFrame['subframes'][] = $subframe;
2059: } else {
2060: $info['warning'][] = 'ID3v2.CHAP subframe "'.$subframe['name'].'" not handled (only TIT2 and TIT3)';
2061: }
2062: }
2063: unset($subframe_rawdata, $subframe, $encoding_converted_text);
2064: }
2065:
2066: $id3v2_chapter_entry = array();
2067: foreach (array('id', 'time_begin', 'time_end', 'offset_begin', 'offset_end', 'chapter_name', 'chapter_description') as $id3v2_chapter_key) {
2068: if (isset($parsedFrame[$id3v2_chapter_key])) {
2069: $id3v2_chapter_entry[$id3v2_chapter_key] = $parsedFrame[$id3v2_chapter_key];
2070: }
2071: }
2072: if (!isset($info['id3v2']['chapters'])) {
2073: $info['id3v2']['chapters'] = array();
2074: }
2075: $info['id3v2']['chapters'][] = $id3v2_chapter_entry;
2076: unset($id3v2_chapter_entry, $id3v2_chapter_key);
2077:
2078:
2079: } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'CTOC')) {
2080:
2081:
2082:
2083:
2084:
2085:
2086:
2087:
2088: $frame_offset = 0;
2089: @list($parsedFrame['element_id']) = explode("\x00", $parsedFrame['data'], 2);
2090: $frame_offset += strlen($parsedFrame['element_id']."\x00");
2091: $ctoc_flags_raw = ord(substr($parsedFrame['data'], $frame_offset, 1));
2092: $frame_offset += 1;
2093: $parsedFrame['entry_count'] = ord(substr($parsedFrame['data'], $frame_offset, 1));
2094: $frame_offset += 1;
2095:
2096: $terminator_position = null;
2097: for ($i = 0; $i < $parsedFrame['entry_count']; $i++) {
2098: $terminator_position = strpos($parsedFrame['data'], "\x00", $frame_offset);
2099: $parsedFrame['child_element_ids'][$i] = substr($parsedFrame['data'], $frame_offset, $terminator_position - $frame_offset);
2100: $frame_offset = $terminator_position + 1;
2101: }
2102:
2103: $parsedFrame['ctoc_flags']['ordered'] = (bool) ($ctoc_flags_raw & 0x01);
2104: $parsedFrame['ctoc_flags']['top_level'] = (bool) ($ctoc_flags_raw & 0x03);
2105:
2106: unset($ctoc_flags_raw, $terminator_position);
2107:
2108: if ($frame_offset < strlen($parsedFrame['data'])) {
2109: $parsedFrame['subframes'] = array();
2110: while ($frame_offset < strlen($parsedFrame['data'])) {
2111:
2112: $subframe = array();
2113: $subframe['name'] = substr($parsedFrame['data'], $frame_offset, 4);
2114: $frame_offset += 4;
2115: $subframe['size'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
2116: $frame_offset += 4;
2117: $subframe['flags_raw'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
2118: $frame_offset += 2;
2119: if ($subframe['size'] > (strlen($parsedFrame['data']) - $frame_offset)) {
2120: $info['warning'][] = 'CTOS subframe "'.$subframe['name'].'" at frame offset '.$frame_offset.' claims to be "'.$subframe['size'].'" bytes, which is more than the available data ('.(strlen($parsedFrame['data']) - $frame_offset).' bytes)';
2121: break;
2122: }
2123: $subframe_rawdata = substr($parsedFrame['data'], $frame_offset, $subframe['size']);
2124: $frame_offset += $subframe['size'];
2125:
2126: $subframe['encodingid'] = ord(substr($subframe_rawdata, 0, 1));
2127: $subframe['text'] = substr($subframe_rawdata, 1);
2128: $subframe['encoding'] = $this->TextEncodingNameLookup($subframe['encodingid']);
2129: $encoding_converted_text = trim(getid3_lib::iconv_fallback($subframe['encoding'], $info['encoding'], $subframe['text']));;
2130: switch (substr($encoding_converted_text, 0, 2)) {
2131: case "\xFF\xFE":
2132: case "\xFE\xFF":
2133: switch (strtoupper($info['id3v2']['encoding'])) {
2134: case 'ISO-8859-1':
2135: case 'UTF-8':
2136: $encoding_converted_text = substr($encoding_converted_text, 2);
2137:
2138: break;
2139: default:
2140:
2141: break;
2142: }
2143: break;
2144: default:
2145:
2146: break;
2147: }
2148:
2149: if (($subframe['name'] == 'TIT2') || ($subframe['name'] == 'TIT3')) {
2150: if ($subframe['name'] == 'TIT2') {
2151: $parsedFrame['toc_name'] = $encoding_converted_text;
2152: } elseif ($subframe['name'] == 'TIT3') {
2153: $parsedFrame['toc_description'] = $encoding_converted_text;
2154: }
2155: $parsedFrame['subframes'][] = $subframe;
2156: } else {
2157: $info['warning'][] = 'ID3v2.CTOC subframe "'.$subframe['name'].'" not handled (only TIT2 and TIT3)';
2158: }
2159: }
2160: unset($subframe_rawdata, $subframe, $encoding_converted_text);
2161: }
2162:
2163: }
2164:
2165: return true;
2166: }
2167:
2168:
2169: public function DeUnsynchronise($data) {
2170: return str_replace("\xFF\x00", "\xFF", $data);
2171: }
2172:
2173: public function LookupExtendedHeaderRestrictionsTagSizeLimits($index) {
2174: static $LookupExtendedHeaderRestrictionsTagSizeLimits = array(
2175: 0x00 => 'No more than 128 frames and 1 MB total tag size',
2176: 0x01 => 'No more than 64 frames and 128 KB total tag size',
2177: 0x02 => 'No more than 32 frames and 40 KB total tag size',
2178: 0x03 => 'No more than 32 frames and 4 KB total tag size',
2179: );
2180: return (isset($LookupExtendedHeaderRestrictionsTagSizeLimits[$index]) ? $LookupExtendedHeaderRestrictionsTagSizeLimits[$index] : '');
2181: }
2182:
2183: public function LookupExtendedHeaderRestrictionsTextEncodings($index) {
2184: static $LookupExtendedHeaderRestrictionsTextEncodings = array(
2185: 0x00 => 'No restrictions',
2186: 0x01 => 'Strings are only encoded with ISO-8859-1 or UTF-8',
2187: );
2188: return (isset($LookupExtendedHeaderRestrictionsTextEncodings[$index]) ? $LookupExtendedHeaderRestrictionsTextEncodings[$index] : '');
2189: }
2190:
2191: public function LookupExtendedHeaderRestrictionsTextFieldSize($index) {
2192: static $LookupExtendedHeaderRestrictionsTextFieldSize = array(
2193: 0x00 => 'No restrictions',
2194: 0x01 => 'No string is longer than 1024 characters',
2195: 0x02 => 'No string is longer than 128 characters',
2196: 0x03 => 'No string is longer than 30 characters',
2197: );
2198: return (isset($LookupExtendedHeaderRestrictionsTextFieldSize[$index]) ? $LookupExtendedHeaderRestrictionsTextFieldSize[$index] : '');
2199: }
2200:
2201: public function LookupExtendedHeaderRestrictionsImageEncoding($index) {
2202: static $LookupExtendedHeaderRestrictionsImageEncoding = array(
2203: 0x00 => 'No restrictions',
2204: 0x01 => 'Images are encoded only with PNG or JPEG',
2205: );
2206: return (isset($LookupExtendedHeaderRestrictionsImageEncoding[$index]) ? $LookupExtendedHeaderRestrictionsImageEncoding[$index] : '');
2207: }
2208:
2209: public function LookupExtendedHeaderRestrictionsImageSizeSize($index) {
2210: static $LookupExtendedHeaderRestrictionsImageSizeSize = array(
2211: 0x00 => 'No restrictions',
2212: 0x01 => 'All images are 256x256 pixels or smaller',
2213: 0x02 => 'All images are 64x64 pixels or smaller',
2214: 0x03 => 'All images are exactly 64x64 pixels, unless required otherwise',
2215: );
2216: return (isset($LookupExtendedHeaderRestrictionsImageSizeSize[$index]) ? $LookupExtendedHeaderRestrictionsImageSizeSize[$index] : '');
2217: }
2218:
2219: public function LookupCurrencyUnits($currencyid) {
2220:
2221: $begin = __LINE__;
2222:
2223: 2224: 2225: 2226: 2227: 2228: 2229: 2230: 2231: 2232: 2233: 2234: 2235: 2236: 2237: 2238: 2239: 2240: 2241: 2242: 2243: 2244: 2245: 2246: 2247: 2248: 2249: 2250: 2251: 2252: 2253: 2254: 2255: 2256: 2257: 2258: 2259: 2260: 2261: 2262: 2263: 2264: 2265: 2266: 2267: 2268: 2269: 2270: 2271: 2272: 2273: 2274: 2275: 2276: 2277: 2278: 2279: 2280: 2281: 2282: 2283: 2284: 2285: 2286: 2287: 2288: 2289: 2290: 2291: 2292: 2293: 2294: 2295: 2296: 2297: 2298: 2299: 2300: 2301: 2302: 2303: 2304: 2305: 2306: 2307: 2308: 2309: 2310: 2311: 2312: 2313: 2314: 2315: 2316: 2317: 2318: 2319: 2320: 2321: 2322: 2323: 2324: 2325: 2326: 2327: 2328: 2329: 2330: 2331: 2332: 2333: 2334: 2335: 2336: 2337: 2338: 2339: 2340: 2341: 2342: 2343: 2344: 2345: 2346: 2347: 2348: 2349: 2350: 2351: 2352: 2353: 2354: 2355: 2356: 2357: 2358: 2359: 2360: 2361: 2362: 2363: 2364: 2365: 2366: 2367: 2368: 2369: 2370: 2371: 2372: 2373: 2374: 2375: 2376: 2377: 2378: 2379: 2380: 2381: 2382: 2383: 2384: 2385: 2386: 2387: 2388: 2389: 2390: 2391: 2392: 2393: 2394: 2395: 2396: 2397: 2398: 2399: 2400: 2401: 2402: 2403: 2404: 2405: 2406: 2407: 2408: 2409: 2410:
2411:
2412: return getid3_lib::EmbeddedLookup($currencyid, $begin, __LINE__, __FILE__, 'id3v2-currency-units');
2413: }
2414:
2415:
2416: public function LookupCurrencyCountry($currencyid) {
2417:
2418: $begin = __LINE__;
2419:
2420: 2421: 2422: 2423: 2424: 2425: 2426: 2427: 2428: 2429: 2430: 2431: 2432: 2433: 2434: 2435: 2436: 2437: 2438: 2439: 2440: 2441: 2442: 2443: 2444: 2445: 2446: 2447: 2448: 2449: 2450: 2451: 2452: 2453: 2454: 2455: 2456: 2457: 2458: 2459: 2460: 2461: 2462: 2463: 2464: 2465: 2466: 2467: 2468: 2469: 2470: 2471: 2472: 2473: 2474: 2475: 2476: 2477: 2478: 2479: 2480: 2481: 2482: 2483: 2484: 2485: 2486: 2487: 2488: 2489: 2490: 2491: 2492: 2493: 2494: 2495: 2496: 2497: 2498: 2499: 2500: 2501: 2502: 2503: 2504: 2505: 2506: 2507: 2508: 2509: 2510: 2511: 2512: 2513: 2514: 2515: 2516: 2517: 2518: 2519: 2520: 2521: 2522: 2523: 2524: 2525: 2526: 2527: 2528: 2529: 2530: 2531: 2532: 2533: 2534: 2535: 2536: 2537: 2538: 2539: 2540: 2541: 2542: 2543: 2544: 2545: 2546: 2547: 2548: 2549: 2550: 2551: 2552: 2553: 2554: 2555: 2556: 2557: 2558: 2559: 2560: 2561: 2562: 2563: 2564: 2565: 2566: 2567: 2568: 2569: 2570: 2571: 2572: 2573: 2574: 2575: 2576: 2577: 2578: 2579: 2580: 2581: 2582: 2583: 2584: 2585: 2586: 2587: 2588: 2589: 2590: 2591: 2592: 2593: 2594: 2595: 2596: 2597: 2598: 2599: 2600: 2601: 2602: 2603: 2604: 2605: 2606:
2607:
2608: return getid3_lib::EmbeddedLookup($currencyid, $begin, __LINE__, __FILE__, 'id3v2-currency-country');
2609: }
2610:
2611:
2612:
2613: public static function LanguageLookup($languagecode, $casesensitive=false) {
2614:
2615: if (!$casesensitive) {
2616: $languagecode = strtolower($languagecode);
2617: }
2618:
2619:
2620:
2621:
2622:
2623:
2624:
2625:
2626:
2627:
2628:
2629: $begin = __LINE__;
2630:
2631: 2632: 2633: 2634: 2635: 2636: 2637: 2638: 2639: 2640: 2641: 2642: 2643: 2644: 2645: 2646: 2647: 2648: 2649: 2650: 2651: 2652: 2653: 2654: 2655: 2656: 2657: 2658: 2659: 2660: 2661: 2662: 2663: 2664: 2665: 2666: 2667: 2668: 2669: 2670: 2671: 2672: 2673: 2674: 2675: 2676: 2677: 2678: 2679: 2680: 2681: 2682: 2683: 2684: 2685: 2686: 2687: 2688: 2689: 2690: 2691: 2692: 2693: 2694: 2695: 2696: 2697: 2698: 2699: 2700: 2701: 2702: 2703: 2704: 2705: 2706: 2707: 2708: 2709: 2710: 2711: 2712: 2713: 2714: 2715: 2716: 2717: 2718: 2719: 2720: 2721: 2722: 2723: 2724: 2725: 2726: 2727: 2728: 2729: 2730: 2731: 2732: 2733: 2734: 2735: 2736: 2737: 2738: 2739: 2740: 2741: 2742: 2743: 2744: 2745: 2746: 2747: 2748: 2749: 2750: 2751: 2752: 2753: 2754: 2755: 2756: 2757: 2758: 2759: 2760: 2761: 2762: 2763: 2764: 2765: 2766: 2767: 2768: 2769: 2770: 2771: 2772: 2773: 2774: 2775: 2776: 2777: 2778: 2779: 2780: 2781: 2782: 2783: 2784: 2785: 2786: 2787: 2788: 2789: 2790: 2791: 2792: 2793: 2794: 2795: 2796: 2797: 2798: 2799: 2800: 2801: 2802: 2803: 2804: 2805: 2806: 2807: 2808: 2809: 2810: 2811: 2812: 2813: 2814: 2815: 2816: 2817: 2818: 2819: 2820: 2821: 2822: 2823: 2824: 2825: 2826: 2827: 2828: 2829: 2830: 2831: 2832: 2833: 2834: 2835: 2836: 2837: 2838: 2839: 2840: 2841: 2842: 2843: 2844: 2845: 2846: 2847: 2848: 2849: 2850: 2851: 2852: 2853: 2854: 2855: 2856: 2857: 2858: 2859: 2860: 2861: 2862: 2863: 2864: 2865: 2866: 2867: 2868: 2869: 2870: 2871: 2872: 2873: 2874: 2875: 2876: 2877: 2878: 2879: 2880: 2881: 2882: 2883: 2884: 2885: 2886: 2887: 2888: 2889: 2890: 2891: 2892: 2893: 2894: 2895: 2896: 2897: 2898: 2899: 2900: 2901: 2902: 2903: 2904: 2905: 2906: 2907: 2908: 2909: 2910: 2911: 2912: 2913: 2914: 2915: 2916: 2917: 2918: 2919: 2920: 2921: 2922: 2923: 2924: 2925: 2926: 2927: 2928: 2929: 2930: 2931: 2932: 2933: 2934: 2935: 2936: 2937: 2938: 2939: 2940: 2941: 2942: 2943: 2944: 2945: 2946: 2947: 2948: 2949: 2950: 2951: 2952: 2953: 2954: 2955: 2956: 2957: 2958: 2959: 2960: 2961: 2962: 2963: 2964: 2965: 2966: 2967: 2968: 2969: 2970: 2971: 2972: 2973: 2974: 2975: 2976: 2977: 2978: 2979: 2980: 2981: 2982: 2983: 2984: 2985: 2986: 2987: 2988: 2989: 2990: 2991: 2992: 2993: 2994: 2995: 2996: 2997: 2998: 2999: 3000: 3001: 3002: 3003: 3004: 3005: 3006: 3007: 3008: 3009: 3010: 3011: 3012: 3013: 3014: 3015: 3016: 3017: 3018: 3019: 3020: 3021: 3022: 3023: 3024: 3025: 3026: 3027: 3028: 3029: 3030: 3031: 3032: 3033: 3034: 3035: 3036: 3037: 3038: 3039: 3040: 3041: 3042: 3043: 3044: 3045: 3046: 3047: 3048: 3049: 3050: 3051: 3052: 3053: 3054: 3055: 3056: 3057: 3058: 3059: 3060: 3061: 3062: 3063:
3064:
3065: return getid3_lib::EmbeddedLookup($languagecode, $begin, __LINE__, __FILE__, 'id3v2-languagecode');
3066: }
3067:
3068:
3069: public static function ETCOEventLookup($index) {
3070: if (($index >= 0x17) && ($index <= 0xDF)) {
3071: return 'reserved for future use';
3072: }
3073: if (($index >= 0xE0) && ($index <= 0xEF)) {
3074: return 'not predefined synch 0-F';
3075: }
3076: if (($index >= 0xF0) && ($index <= 0xFC)) {
3077: return 'reserved for future use';
3078: }
3079:
3080: static $EventLookup = array(
3081: 0x00 => 'padding (has no meaning)',
3082: 0x01 => 'end of initial silence',
3083: 0x02 => 'intro start',
3084: 0x03 => 'main part start',
3085: 0x04 => 'outro start',
3086: 0x05 => 'outro end',
3087: 0x06 => 'verse start',
3088: 0x07 => 'refrain start',
3089: 0x08 => 'interlude start',
3090: 0x09 => 'theme start',
3091: 0x0A => 'variation start',
3092: 0x0B => 'key change',
3093: 0x0C => 'time change',
3094: 0x0D => 'momentary unwanted noise (Snap, Crackle & Pop)',
3095: 0x0E => 'sustained noise',
3096: 0x0F => 'sustained noise end',
3097: 0x10 => 'intro end',
3098: 0x11 => 'main part end',
3099: 0x12 => 'verse end',
3100: 0x13 => 'refrain end',
3101: 0x14 => 'theme end',
3102: 0x15 => 'profanity',
3103: 0x16 => 'profanity end',
3104: 0xFD => 'audio end (start of silence)',
3105: 0xFE => 'audio file ends',
3106: 0xFF => 'one more byte of events follows'
3107: );
3108:
3109: return (isset($EventLookup[$index]) ? $EventLookup[$index] : '');
3110: }
3111:
3112: public static function SYTLContentTypeLookup($index) {
3113: static $SYTLContentTypeLookup = array(
3114: 0x00 => 'other',
3115: 0x01 => 'lyrics',
3116: 0x02 => 'text transcription',
3117: 0x03 => 'movement/part name',
3118: 0x04 => 'events',
3119: 0x05 => 'chord',
3120: 0x06 => 'trivia/\'pop up\' information',
3121: 0x07 => 'URLs to webpages',
3122: 0x08 => 'URLs to images'
3123: );
3124:
3125: return (isset($SYTLContentTypeLookup[$index]) ? $SYTLContentTypeLookup[$index] : '');
3126: }
3127:
3128: public static function APICPictureTypeLookup($index, $returnarray=false) {
3129: static $APICPictureTypeLookup = array(
3130: 0x00 => 'Other',
3131: 0x01 => '32x32 pixels \'file icon\' (PNG only)',
3132: 0x02 => 'Other file icon',
3133: 0x03 => 'Cover (front)',
3134: 0x04 => 'Cover (back)',
3135: 0x05 => 'Leaflet page',
3136: 0x06 => 'Media (e.g. label side of CD)',
3137: 0x07 => 'Lead artist/lead performer/soloist',
3138: 0x08 => 'Artist/performer',
3139: 0x09 => 'Conductor',
3140: 0x0A => 'Band/Orchestra',
3141: 0x0B => 'Composer',
3142: 0x0C => 'Lyricist/text writer',
3143: 0x0D => 'Recording Location',
3144: 0x0E => 'During recording',
3145: 0x0F => 'During performance',
3146: 0x10 => 'Movie/video screen capture',
3147: 0x11 => 'A bright coloured fish',
3148: 0x12 => 'Illustration',
3149: 0x13 => 'Band/artist logotype',
3150: 0x14 => 'Publisher/Studio logotype'
3151: );
3152: if ($returnarray) {
3153: return $APICPictureTypeLookup;
3154: }
3155: return (isset($APICPictureTypeLookup[$index]) ? $APICPictureTypeLookup[$index] : '');
3156: }
3157:
3158: public static function COMRReceivedAsLookup($index) {
3159: static $COMRReceivedAsLookup = array(
3160: 0x00 => 'Other',
3161: 0x01 => 'Standard CD album with other songs',
3162: 0x02 => 'Compressed audio on CD',
3163: 0x03 => 'File over the Internet',
3164: 0x04 => 'Stream over the Internet',
3165: 0x05 => 'As note sheets',
3166: 0x06 => 'As note sheets in a book with other sheets',
3167: 0x07 => 'Music on other media',
3168: 0x08 => 'Non-musical merchandise'
3169: );
3170:
3171: return (isset($COMRReceivedAsLookup[$index]) ? $COMRReceivedAsLookup[$index] : '');
3172: }
3173:
3174: public static function RVA2ChannelTypeLookup($index) {
3175: static $RVA2ChannelTypeLookup = array(
3176: 0x00 => 'Other',
3177: 0x01 => 'Master volume',
3178: 0x02 => 'Front right',
3179: 0x03 => 'Front left',
3180: 0x04 => 'Back right',
3181: 0x05 => 'Back left',
3182: 0x06 => 'Front centre',
3183: 0x07 => 'Back centre',
3184: 0x08 => 'Subwoofer'
3185: );
3186:
3187: return (isset($RVA2ChannelTypeLookup[$index]) ? $RVA2ChannelTypeLookup[$index] : '');
3188: }
3189:
3190: public static function FrameNameLongLookup($framename) {
3191:
3192: $begin = __LINE__;
3193:
3194: 3195: 3196: 3197: 3198: 3199: 3200: 3201: 3202: 3203: 3204: 3205: 3206: 3207: 3208: 3209: 3210: 3211: 3212: 3213: 3214: 3215: 3216: 3217: 3218: 3219: 3220: 3221: 3222: 3223: 3224: 3225: 3226: 3227: 3228: 3229: 3230: 3231: 3232: 3233: 3234: 3235: 3236: 3237: 3238: 3239: 3240: 3241: 3242: 3243: 3244: 3245: 3246: 3247: 3248: 3249: 3250: 3251: 3252: 3253: 3254: 3255: 3256: 3257: 3258: 3259: 3260: 3261: 3262: 3263: 3264: 3265: 3266: 3267: 3268: 3269: 3270: 3271: 3272: 3273: 3274: 3275: 3276: 3277: 3278: 3279: 3280: 3281: 3282: 3283: 3284: 3285: 3286: 3287: 3288: 3289: 3290: 3291: 3292: 3293: 3294: 3295: 3296: 3297: 3298: 3299: 3300: 3301: 3302: 3303: 3304: 3305: 3306: 3307: 3308: 3309: 3310: 3311: 3312: 3313: 3314: 3315: 3316: 3317: 3318: 3319: 3320: 3321: 3322: 3323: 3324: 3325: 3326: 3327: 3328: 3329: 3330: 3331: 3332: 3333: 3334: 3335: 3336: 3337: 3338: 3339: 3340: 3341: 3342: 3343: 3344: 3345: 3346: 3347: 3348: 3349: 3350: 3351: 3352: 3353: 3354: 3355: 3356: 3357: 3358: 3359: 3360: 3361: 3362: 3363: 3364:
3365:
3366: return getid3_lib::EmbeddedLookup($framename, $begin, __LINE__, __FILE__, 'id3v2-framename_long');
3367:
3368:
3369:
3370:
3371: }
3372:
3373:
3374: public static function FrameNameShortLookup($framename) {
3375:
3376: $begin = __LINE__;
3377:
3378: 3379: 3380: 3381: 3382: 3383: 3384: 3385: 3386: 3387: 3388: 3389: 3390: 3391: 3392: 3393: 3394: 3395: 3396: 3397: 3398: 3399: 3400: 3401: 3402: 3403: 3404: 3405: 3406: 3407: 3408: 3409: 3410: 3411: 3412: 3413: 3414: 3415: 3416: 3417: 3418: 3419: 3420: 3421: 3422: 3423: 3424: 3425: 3426: 3427: 3428: 3429: 3430: 3431: 3432: 3433: 3434: 3435: 3436: 3437: 3438: 3439: 3440: 3441: 3442: 3443: 3444: 3445: 3446: 3447: 3448: 3449: 3450: 3451: 3452: 3453: 3454: 3455: 3456: 3457: 3458: 3459: 3460: 3461: 3462: 3463: 3464: 3465: 3466: 3467: 3468: 3469: 3470: 3471: 3472: 3473: 3474: 3475: 3476: 3477: 3478: 3479: 3480: 3481: 3482: 3483: 3484: 3485: 3486: 3487: 3488: 3489: 3490: 3491: 3492: 3493: 3494: 3495: 3496: 3497: 3498: 3499: 3500: 3501: 3502: 3503: 3504: 3505: 3506: 3507: 3508: 3509: 3510: 3511: 3512: 3513: 3514: 3515: 3516: 3517: 3518: 3519: 3520: 3521: 3522: 3523: 3524: 3525: 3526: 3527: 3528: 3529: 3530: 3531: 3532: 3533: 3534: 3535: 3536: 3537: 3538: 3539: 3540: 3541: 3542: 3543: 3544: 3545: 3546: 3547: 3548:
3549:
3550: return getid3_lib::EmbeddedLookup($framename, $begin, __LINE__, __FILE__, 'id3v2-framename_short');
3551: }
3552:
3553: public static function TextEncodingTerminatorLookup($encoding) {
3554:
3555:
3556: static $TextEncodingTerminatorLookup = array(
3557: 0 => "\x00",
3558: 1 => "\x00\x00",
3559: 2 => "\x00\x00",
3560: 3 => "\x00",
3561: 255 => "\x00\x00"
3562: );
3563: return (isset($TextEncodingTerminatorLookup[$encoding]) ? $TextEncodingTerminatorLookup[$encoding] : "\x00");
3564: }
3565:
3566: public static function TextEncodingNameLookup($encoding) {
3567:
3568:
3569: static $TextEncodingNameLookup = array(
3570: 0 => 'ISO-8859-1',
3571: 1 => 'UTF-16',
3572: 2 => 'UTF-16BE',
3573: 3 => 'UTF-8',
3574: 255 => 'UTF-16BE'
3575: );
3576: return (isset($TextEncodingNameLookup[$encoding]) ? $TextEncodingNameLookup[$encoding] : 'ISO-8859-1');
3577: }
3578:
3579: public static function IsValidID3v2FrameName($framename, $id3v2majorversion) {
3580: switch ($id3v2majorversion) {
3581: case 2:
3582: return preg_match('#[A-Z][A-Z0-9]{2}#', $framename);
3583: break;
3584:
3585: case 3:
3586: case 4:
3587: return preg_match('#[A-Z][A-Z0-9]{3}#', $framename);
3588: break;
3589: }
3590: return false;
3591: }
3592:
3593: public static function IsANumber($numberstring, $allowdecimal=false, $allownegative=false) {
3594: for ($i = 0; $i < strlen($numberstring); $i++) {
3595: if ((chr($numberstring{$i}) < chr('0')) || (chr($numberstring{$i}) > chr('9'))) {
3596: if (($numberstring{$i} == '.') && $allowdecimal) {
3597:
3598: } elseif (($numberstring{$i} == '-') && $allownegative && ($i == 0)) {
3599:
3600: } else {
3601: return false;
3602: }
3603: }
3604: }
3605: return true;
3606: }
3607:
3608: public static function IsValidDateStampString($datestamp) {
3609: if (strlen($datestamp) != 8) {
3610: return false;
3611: }
3612: if (!self::IsANumber($datestamp, false)) {
3613: return false;
3614: }
3615: $year = substr($datestamp, 0, 4);
3616: $month = substr($datestamp, 4, 2);
3617: $day = substr($datestamp, 6, 2);
3618: if (($year == 0) || ($month == 0) || ($day == 0)) {
3619: return false;
3620: }
3621: if ($month > 12) {
3622: return false;
3623: }
3624: if ($day > 31) {
3625: return false;
3626: }
3627: if (($day > 30) && (($month == 4) || ($month == 6) || ($month == 9) || ($month == 11))) {
3628: return false;
3629: }
3630: if (($day > 29) && ($month == 2)) {
3631: return false;
3632: }
3633: return true;
3634: }
3635:
3636: public static function ID3v2HeaderLength($majorversion) {
3637: return (($majorversion == 2) ? 6 : 10);
3638: }
3639:
3640: }
3641:
3642: