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