ILIAS  release_5-1 Revision 5.0.0-5477-g43f3e3fab5f
getid3_id3v2 Class Reference
+ Inheritance diagram for getid3_id3v2:
+ Collaboration diagram for getid3_id3v2:

Public Member Functions

 getid3_id3v2 (&$fd, &$ThisFileInfo, $StartingOffset=0)
 
 ParseID3v2GenreString ($genrestring)
 
 ParseID3v2Frame (&$parsedFrame, &$ThisFileInfo)
 
 DeUnsynchronise ($data)
 
 LookupCurrencyUnits ($currencyid)
 
 LookupCurrencyCountry ($currencyid)
 
 LanguageLookup ($languagecode, $casesensitive=false)
 
 ETCOEventLookup ($index)
 
 SYTLContentTypeLookup ($index)
 
 APICPictureTypeLookup ($index, $returnarray=false)
 
 COMRReceivedAsLookup ($index)
 
 RVA2ChannelTypeLookup ($index)
 
 FrameNameLongLookup ($framename)
 
 FrameNameShortLookup ($framename)
 
 TextEncodingTerminatorLookup ($encoding)
 
 TextEncodingNameLookup ($encoding)
 
 IsValidID3v2FrameName ($framename, $id3v2majorversion)
 
 IsANumber ($numberstring, $allowdecimal=false, $allownegative=false)
 
 IsValidDateStampString ($datestamp)
 
 ID3v2HeaderLength ($majorversion)
 
 Analyze ()
 
 ParseID3v2GenreString ($genrestring)
 
 ParseID3v2Frame (&$parsedFrame)
 
 DeUnsynchronise ($data)
 
 LookupExtendedHeaderRestrictionsTagSizeLimits ($index)
 
 LookupExtendedHeaderRestrictionsTextEncodings ($index)
 
 LookupExtendedHeaderRestrictionsTextFieldSize ($index)
 
 LookupExtendedHeaderRestrictionsImageEncoding ($index)
 
 LookupExtendedHeaderRestrictionsImageSizeSize ($index)
 
 LookupCurrencyUnits ($currencyid)
 
 LookupCurrencyCountry ($currencyid)
 
- Public Member Functions inherited from getid3_handler
 __construct (getID3 $getid3, $call_module=null)
 
 Analyze ()
 
 AnalyzeString ($string)
 
 setStringMode ($string)
 
 saveAttachment ($name, $offset, $length, $image_mime=null)
 

Static Public Member Functions

static LanguageLookup ($languagecode, $casesensitive=false)
 
static ETCOEventLookup ($index)
 
static SYTLContentTypeLookup ($index)
 
static APICPictureTypeLookup ($index, $returnarray=false)
 
static COMRReceivedAsLookup ($index)
 
static RVA2ChannelTypeLookup ($index)
 
static FrameNameLongLookup ($framename)
 
static FrameNameShortLookup ($framename)
 
static TextEncodingTerminatorLookup ($encoding)
 
static TextEncodingNameLookup ($encoding)
 
static IsValidID3v2FrameName ($framename, $id3v2majorversion)
 
static IsANumber ($numberstring, $allowdecimal=false, $allownegative=false)
 
static IsValidDateStampString ($datestamp)
 
static ID3v2HeaderLength ($majorversion)
 

Data Fields

 $StartingOffset = 0
 

Additional Inherited Members

- Protected Member Functions inherited from getid3_handler
 ftell ()
 
 fread ($bytes)
 
 fseek ($bytes, $whence=SEEK_SET)
 
 feof ()
 
 isDependencyFor ($module)
 
 error ($text)
 
 warning ($text)
 
 notice ($text)
 
- Protected Attributes inherited from getid3_handler
 $getid3
 
 $data_string_flag = false
 
 $data_string = ''
 
 $data_string_position = 0
 
 $data_string_length = 0
 

Detailed Description

Definition at line 18 of file module.tag.id3v2.php.

Member Function Documentation

◆ Analyze()

getid3_id3v2::Analyze ( )

Definition at line 23 of file module.tag.id3v2.php.

References $header, $info, $StartingOffset, getid3_lib\BigEndian2Int(), getid3_lib\CastAsInt(), DeUnsynchronise(), getid3_handler\fread(), getid3_handler\fseek(), ID3v2HeaderLength(), IsValidID3v2FrameName(), LookupExtendedHeaderRestrictionsImageEncoding(), LookupExtendedHeaderRestrictionsImageSizeSize(), LookupExtendedHeaderRestrictionsTagSizeLimits(), LookupExtendedHeaderRestrictionsTextEncodings(), LookupExtendedHeaderRestrictionsTextFieldSize(), ParseID3v2Frame(), and ParseID3v2GenreString().

23  {
24  $info = &$this->getid3->info;
25 
26  // Overall tag structure:
27  // +-----------------------------+
28  // | Header (10 bytes) |
29  // +-----------------------------+
30  // | Extended Header |
31  // | (variable length, OPTIONAL) |
32  // +-----------------------------+
33  // | Frames (variable length) |
34  // +-----------------------------+
35  // | Padding |
36  // | (variable length, OPTIONAL) |
37  // +-----------------------------+
38  // | Footer (10 bytes, OPTIONAL) |
39  // +-----------------------------+
40 
41  // Header
42  // ID3v2/file identifier "ID3"
43  // ID3v2 version $04 00
44  // ID3v2 flags (%ab000000 in v2.2, %abc00000 in v2.3, %abcd0000 in v2.4.x)
45  // ID3v2 size 4 * %0xxxxxxx
46 
47 
48  // shortcuts
49  $info['id3v2']['header'] = true;
50  $thisfile_id3v2 = &$info['id3v2'];
51  $thisfile_id3v2['flags'] = array();
52  $thisfile_id3v2_flags = &$thisfile_id3v2['flags'];
53 
54 
55  $this->fseek($this->StartingOffset);
56  $header = $this->fread(10);
57  if (substr($header, 0, 3) == 'ID3' && strlen($header) == 10) {
58 
59  $thisfile_id3v2['majorversion'] = ord($header{3});
60  $thisfile_id3v2['minorversion'] = ord($header{4});
61 
62  // shortcut
63  $id3v2_majorversion = &$thisfile_id3v2['majorversion'];
64 
65  } else {
66 
67  unset($info['id3v2']);
68  return false;
69 
70  }
71 
72  if ($id3v2_majorversion > 4) { // this script probably won't correctly parse ID3v2.5.x and above (if it ever exists)
73 
74  $info['error'][] = 'this script only parses up to ID3v2.4.x - this tag is ID3v2.'.$id3v2_majorversion.'.'.$thisfile_id3v2['minorversion'];
75  return false;
76 
77  }
78 
79  $id3_flags = ord($header{5});
80  switch ($id3v2_majorversion) {
81  case 2:
82  // %ab000000 in v2.2
83  $thisfile_id3v2_flags['unsynch'] = (bool) ($id3_flags & 0x80); // a - Unsynchronisation
84  $thisfile_id3v2_flags['compression'] = (bool) ($id3_flags & 0x40); // b - Compression
85  break;
86 
87  case 3:
88  // %abc00000 in v2.3
89  $thisfile_id3v2_flags['unsynch'] = (bool) ($id3_flags & 0x80); // a - Unsynchronisation
90  $thisfile_id3v2_flags['exthead'] = (bool) ($id3_flags & 0x40); // b - Extended header
91  $thisfile_id3v2_flags['experim'] = (bool) ($id3_flags & 0x20); // c - Experimental indicator
92  break;
93 
94  case 4:
95  // %abcd0000 in v2.4
96  $thisfile_id3v2_flags['unsynch'] = (bool) ($id3_flags & 0x80); // a - Unsynchronisation
97  $thisfile_id3v2_flags['exthead'] = (bool) ($id3_flags & 0x40); // b - Extended header
98  $thisfile_id3v2_flags['experim'] = (bool) ($id3_flags & 0x20); // c - Experimental indicator
99  $thisfile_id3v2_flags['isfooter'] = (bool) ($id3_flags & 0x10); // d - Footer present
100  break;
101  }
102 
103  $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
104 
105  $thisfile_id3v2['tag_offset_start'] = $this->StartingOffset;
106  $thisfile_id3v2['tag_offset_end'] = $thisfile_id3v2['tag_offset_start'] + $thisfile_id3v2['headerlength'];
107 
108 
109 
110  // create 'encoding' key - used by getid3::HandleAllTags()
111  // in ID3v2 every field can have it's own encoding type
112  // so force everything to UTF-8 so it can be handled consistantly
113  $thisfile_id3v2['encoding'] = 'UTF-8';
114 
115 
116  // Frames
117 
118  // All ID3v2 frames consists of one frame header followed by one or more
119  // fields containing the actual information. The header is always 10
120  // bytes and laid out as follows:
121  //
122  // Frame ID $xx xx xx xx (four characters)
123  // Size 4 * %0xxxxxxx
124  // Flags $xx xx
125 
126  $sizeofframes = $thisfile_id3v2['headerlength'] - 10; // not including 10-byte initial header
127  if (!empty($thisfile_id3v2['exthead']['length'])) {
128  $sizeofframes -= ($thisfile_id3v2['exthead']['length'] + 4);
129  }
130  if (!empty($thisfile_id3v2_flags['isfooter'])) {
131  $sizeofframes -= 10; // footer takes last 10 bytes of ID3v2 header, after frame data, before audio
132  }
133  if ($sizeofframes > 0) {
134 
135  $framedata = $this->fread($sizeofframes); // read all frames from file into $framedata variable
136 
137  // if entire frame data is unsynched, de-unsynch it now (ID3v2.3.x)
138  if (!empty($thisfile_id3v2_flags['unsynch']) && ($id3v2_majorversion <= 3)) {
139  $framedata = $this->DeUnsynchronise($framedata);
140  }
141  // [in ID3v2.4.0] Unsynchronisation [S:6.1] is done on frame level, instead
142  // of on tag level, making it easier to skip frames, increasing the streamability
143  // of the tag. The unsynchronisation flag in the header [S:3.1] indicates that
144  // there exists an unsynchronised frame, while the new unsynchronisation flag in
145  // the frame header [S:4.1.2] indicates unsynchronisation.
146 
147 
148  //$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)
149  $framedataoffset = 10; // how many bytes into the stream - start from after the 10-byte header
150 
151 
152  // Extended Header
153  if (!empty($thisfile_id3v2_flags['exthead'])) {
154  $extended_header_offset = 0;
155 
156  if ($id3v2_majorversion == 3) {
157 
158  // v2.3 definition:
159  //Extended header size $xx xx xx xx // 32-bit integer
160  //Extended Flags $xx xx
161  // %x0000000 %00000000 // v2.3
162  // x - CRC data present
163  //Size of padding $xx xx xx xx
164 
165  $thisfile_id3v2['exthead']['length'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4), 0);
166  $extended_header_offset += 4;
167 
168  $thisfile_id3v2['exthead']['flag_bytes'] = 2;
169  $thisfile_id3v2['exthead']['flag_raw'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, $thisfile_id3v2['exthead']['flag_bytes']));
170  $extended_header_offset += $thisfile_id3v2['exthead']['flag_bytes'];
171 
172  $thisfile_id3v2['exthead']['flags']['crc'] = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x8000);
173 
174  $thisfile_id3v2['exthead']['padding_size'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4));
175  $extended_header_offset += 4;
176 
177  if ($thisfile_id3v2['exthead']['flags']['crc']) {
178  $thisfile_id3v2['exthead']['flag_data']['crc'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4));
179  $extended_header_offset += 4;
180  }
181  $extended_header_offset += $thisfile_id3v2['exthead']['padding_size'];
182 
183  } elseif ($id3v2_majorversion == 4) {
184 
185  // v2.4 definition:
186  //Extended header size 4 * %0xxxxxxx // 28-bit synchsafe integer
187  //Number of flag bytes $01
188  //Extended Flags $xx
189  // %0bcd0000 // v2.4
190  // b - Tag is an update
191  // Flag data length $00
192  // c - CRC data present
193  // Flag data length $05
194  // Total frame CRC 5 * %0xxxxxxx
195  // d - Tag restrictions
196  // Flag data length $01
197 
198  $thisfile_id3v2['exthead']['length'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4), true);
199  $extended_header_offset += 4;
200 
201  $thisfile_id3v2['exthead']['flag_bytes'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should always be 1
202  $extended_header_offset += 1;
203 
204  $thisfile_id3v2['exthead']['flag_raw'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, $thisfile_id3v2['exthead']['flag_bytes']));
205  $extended_header_offset += $thisfile_id3v2['exthead']['flag_bytes'];
206 
207  $thisfile_id3v2['exthead']['flags']['update'] = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x40);
208  $thisfile_id3v2['exthead']['flags']['crc'] = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x20);
209  $thisfile_id3v2['exthead']['flags']['restrictions'] = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x10);
210 
211  if ($thisfile_id3v2['exthead']['flags']['update']) {
212  $ext_header_chunk_length = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should be 0
213  $extended_header_offset += 1;
214  }
215 
216  if ($thisfile_id3v2['exthead']['flags']['crc']) {
217  $ext_header_chunk_length = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should be 5
218  $extended_header_offset += 1;
219  $thisfile_id3v2['exthead']['flag_data']['crc'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, $ext_header_chunk_length), true, false);
220  $extended_header_offset += $ext_header_chunk_length;
221  }
222 
223  if ($thisfile_id3v2['exthead']['flags']['restrictions']) {
224  $ext_header_chunk_length = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should be 1
225  $extended_header_offset += 1;
226 
227  // %ppqrrstt
228  $restrictions_raw = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1));
229  $extended_header_offset += 1;
230  $thisfile_id3v2['exthead']['flags']['restrictions']['tagsize'] = ($restrictions_raw & 0xC0) >> 6; // p - Tag size restrictions
231  $thisfile_id3v2['exthead']['flags']['restrictions']['textenc'] = ($restrictions_raw & 0x20) >> 5; // q - Text encoding restrictions
232  $thisfile_id3v2['exthead']['flags']['restrictions']['textsize'] = ($restrictions_raw & 0x18) >> 3; // r - Text fields size restrictions
233  $thisfile_id3v2['exthead']['flags']['restrictions']['imgenc'] = ($restrictions_raw & 0x04) >> 2; // s - Image encoding restrictions
234  $thisfile_id3v2['exthead']['flags']['restrictions']['imgsize'] = ($restrictions_raw & 0x03) >> 0; // t - Image size restrictions
235 
236  $thisfile_id3v2['exthead']['flags']['restrictions_text']['tagsize'] = $this->LookupExtendedHeaderRestrictionsTagSizeLimits($thisfile_id3v2['exthead']['flags']['restrictions']['tagsize']);
237  $thisfile_id3v2['exthead']['flags']['restrictions_text']['textenc'] = $this->LookupExtendedHeaderRestrictionsTextEncodings($thisfile_id3v2['exthead']['flags']['restrictions']['textenc']);
238  $thisfile_id3v2['exthead']['flags']['restrictions_text']['textsize'] = $this->LookupExtendedHeaderRestrictionsTextFieldSize($thisfile_id3v2['exthead']['flags']['restrictions']['textsize']);
239  $thisfile_id3v2['exthead']['flags']['restrictions_text']['imgenc'] = $this->LookupExtendedHeaderRestrictionsImageEncoding($thisfile_id3v2['exthead']['flags']['restrictions']['imgenc']);
240  $thisfile_id3v2['exthead']['flags']['restrictions_text']['imgsize'] = $this->LookupExtendedHeaderRestrictionsImageSizeSize($thisfile_id3v2['exthead']['flags']['restrictions']['imgsize']);
241  }
242 
243  if ($thisfile_id3v2['exthead']['length'] != $extended_header_offset) {
244  $info['warning'][] = 'ID3v2.4 extended header length mismatch (expecting '.intval($thisfile_id3v2['exthead']['length']).', found '.intval($extended_header_offset).')';
245  }
246  }
247 
248  $framedataoffset += $extended_header_offset;
249  $framedata = substr($framedata, $extended_header_offset);
250  } // end extended header
251 
252 
253  while (isset($framedata) && (strlen($framedata) > 0)) { // cycle through until no more frame data is left to parse
254  if (strlen($framedata) <= $this->ID3v2HeaderLength($id3v2_majorversion)) {
255  // insufficient room left in ID3v2 header for actual data - must be padding
256  $thisfile_id3v2['padding']['start'] = $framedataoffset;
257  $thisfile_id3v2['padding']['length'] = strlen($framedata);
258  $thisfile_id3v2['padding']['valid'] = true;
259  for ($i = 0; $i < $thisfile_id3v2['padding']['length']; $i++) {
260  if ($framedata{$i} != "\x00") {
261  $thisfile_id3v2['padding']['valid'] = false;
262  $thisfile_id3v2['padding']['errorpos'] = $thisfile_id3v2['padding']['start'] + $i;
263  $info['warning'][] = 'Invalid ID3v2 padding found at offset '.$thisfile_id3v2['padding']['errorpos'].' (the remaining '.($thisfile_id3v2['padding']['length'] - $i).' bytes are considered invalid)';
264  break;
265  }
266  }
267  break; // skip rest of ID3v2 header
268  }
269  if ($id3v2_majorversion == 2) {
270  // Frame ID $xx xx xx (three characters)
271  // Size $xx xx xx (24-bit integer)
272  // Flags $xx xx
273 
274  $frame_header = substr($framedata, 0, 6); // take next 6 bytes for header
275  $framedata = substr($framedata, 6); // and leave the rest in $framedata
276  $frame_name = substr($frame_header, 0, 3);
277  $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 3, 3), 0);
278  $frame_flags = 0; // not used for anything in ID3v2.2, just set to avoid E_NOTICEs
279 
280  } elseif ($id3v2_majorversion > 2) {
281 
282  // Frame ID $xx xx xx xx (four characters)
283  // Size $xx xx xx xx (32-bit integer in v2.3, 28-bit synchsafe in v2.4+)
284  // Flags $xx xx
285 
286  $frame_header = substr($framedata, 0, 10); // take next 10 bytes for header
287  $framedata = substr($framedata, 10); // and leave the rest in $framedata
288 
289  $frame_name = substr($frame_header, 0, 4);
290  if ($id3v2_majorversion == 3) {
291  $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0); // 32-bit integer
292  } else { // ID3v2.4+
293  $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 1); // 32-bit synchsafe integer (28-bit value)
294  }
295 
296  if ($frame_size < (strlen($framedata) + 4)) {
297  $nextFrameID = substr($framedata, $frame_size, 4);
298  if ($this->IsValidID3v2FrameName($nextFrameID, $id3v2_majorversion)) {
299  // next frame is OK
300  } elseif (($frame_name == "\x00".'MP3') || ($frame_name == "\x00\x00".'MP') || ($frame_name == ' MP3') || ($frame_name == 'MP3e')) {
301  // MP3ext known broken frames - "ok" for the purposes of this test
302  } elseif (($id3v2_majorversion == 4) && ($this->IsValidID3v2FrameName(substr($framedata, getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0), 4), 3))) {
303  $info['warning'][] = 'ID3v2 tag written as ID3v2.4, but with non-synchsafe integers (ID3v2.3 style). Older versions of (Helium2; iTunes) are known culprits of this. Tag has been parsed as ID3v2.3';
304  $id3v2_majorversion = 3;
305  $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0); // 32-bit integer
306  }
307  }
308 
309 
310  $frame_flags = getid3_lib::BigEndian2Int(substr($frame_header, 8, 2));
311  }
312 
313  if ((($id3v2_majorversion == 2) && ($frame_name == "\x00\x00\x00")) || ($frame_name == "\x00\x00\x00\x00")) {
314  // padding encountered
315 
316  $thisfile_id3v2['padding']['start'] = $framedataoffset;
317  $thisfile_id3v2['padding']['length'] = strlen($frame_header) + strlen($framedata);
318  $thisfile_id3v2['padding']['valid'] = true;
319 
320  $len = strlen($framedata);
321  for ($i = 0; $i < $len; $i++) {
322  if ($framedata{$i} != "\x00") {
323  $thisfile_id3v2['padding']['valid'] = false;
324  $thisfile_id3v2['padding']['errorpos'] = $thisfile_id3v2['padding']['start'] + $i;
325  $info['warning'][] = 'Invalid ID3v2 padding found at offset '.$thisfile_id3v2['padding']['errorpos'].' (the remaining '.($thisfile_id3v2['padding']['length'] - $i).' bytes are considered invalid)';
326  break;
327  }
328  }
329  break; // skip rest of ID3v2 header
330  }
331 
332  if ($frame_name == 'COM ') {
333  $info['warning'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))). [Note: this particular error has been known to happen with tags edited by iTunes (versions "X v2.0.3", "v3.0.1" are known-guilty, probably others too)]';
334  $frame_name = 'COMM';
335  }
336  if (($frame_size <= strlen($framedata)) && ($this->IsValidID3v2FrameName($frame_name, $id3v2_majorversion))) {
337 
338  unset($parsedFrame);
339  $parsedFrame['frame_name'] = $frame_name;
340  $parsedFrame['frame_flags_raw'] = $frame_flags;
341  $parsedFrame['data'] = substr($framedata, 0, $frame_size);
342  $parsedFrame['datalength'] = getid3_lib::CastAsInt($frame_size);
343  $parsedFrame['dataoffset'] = $framedataoffset;
344 
345  $this->ParseID3v2Frame($parsedFrame);
346  $thisfile_id3v2[$frame_name][] = $parsedFrame;
347 
348  $framedata = substr($framedata, $frame_size);
349 
350  } else { // invalid frame length or FrameID
351 
352  if ($frame_size <= strlen($framedata)) {
353 
354  if ($this->IsValidID3v2FrameName(substr($framedata, $frame_size, 4), $id3v2_majorversion)) {
355 
356  // next frame is valid, just skip the current frame
357  $framedata = substr($framedata, $frame_size);
358  $info['warning'][] = 'Next ID3v2 frame is valid, skipping current frame.';
359 
360  } else {
361 
362  // next frame is invalid too, abort processing
363  //unset($framedata);
364  $framedata = null;
365  $info['error'][] = 'Next ID3v2 frame is also invalid, aborting processing.';
366 
367  }
368 
369  } elseif ($frame_size == strlen($framedata)) {
370 
371  // this is the last frame, just skip
372  $info['warning'][] = 'This was the last ID3v2 frame.';
373 
374  } else {
375 
376  // next frame is invalid too, abort processing
377  //unset($framedata);
378  $framedata = null;
379  $info['warning'][] = 'Invalid ID3v2 frame size, aborting.';
380 
381  }
382  if (!$this->IsValidID3v2FrameName($frame_name, $id3v2_majorversion)) {
383 
384  switch ($frame_name) {
385  case "\x00\x00".'MP':
386  case "\x00".'MP3':
387  case ' MP3':
388  case 'MP3e':
389  case "\x00".'MP':
390  case ' MP':
391  case 'MP3':
392  $info['warning'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: !IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))). [Note: this particular error has been known to happen with tags edited by "MP3ext (www.mutschler.de/mp3ext/)"]';
393  break;
394 
395  default:
396  $info['warning'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: !IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))).';
397  break;
398  }
399 
400  } elseif (!isset($framedata) || ($frame_size > strlen($framedata))) {
401 
402  $info['error'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: $frame_size ('.$frame_size.') > strlen($framedata) ('.(isset($framedata) ? strlen($framedata) : 'null').')).';
403 
404  } else {
405 
406  $info['error'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag).';
407 
408  }
409 
410  }
411  $framedataoffset += ($frame_size + $this->ID3v2HeaderLength($id3v2_majorversion));
412 
413  }
414 
415  }
416 
417 
418  // Footer
419 
420  // The footer is a copy of the header, but with a different identifier.
421  // ID3v2 identifier "3DI"
422  // ID3v2 version $04 00
423  // ID3v2 flags %abcd0000
424  // ID3v2 size 4 * %0xxxxxxx
425 
426  if (isset($thisfile_id3v2_flags['isfooter']) && $thisfile_id3v2_flags['isfooter']) {
427  $footer = $this->fread(10);
428  if (substr($footer, 0, 3) == '3DI') {
429  $thisfile_id3v2['footer'] = true;
430  $thisfile_id3v2['majorversion_footer'] = ord($footer{3});
431  $thisfile_id3v2['minorversion_footer'] = ord($footer{4});
432  }
433  if ($thisfile_id3v2['majorversion_footer'] <= 4) {
434  $id3_flags = ord(substr($footer{5}));
435  $thisfile_id3v2_flags['unsynch_footer'] = (bool) ($id3_flags & 0x80);
436  $thisfile_id3v2_flags['extfoot_footer'] = (bool) ($id3_flags & 0x40);
437  $thisfile_id3v2_flags['experim_footer'] = (bool) ($id3_flags & 0x20);
438  $thisfile_id3v2_flags['isfooter_footer'] = (bool) ($id3_flags & 0x10);
439 
440  $thisfile_id3v2['footerlength'] = getid3_lib::BigEndian2Int(substr($footer, 6, 4), 1);
441  }
442  } // end footer
443 
444  if (isset($thisfile_id3v2['comments']['genre'])) {
445  $genres = array();
446  foreach ($thisfile_id3v2['comments']['genre'] as $key => $value) {
447  foreach ($this->ParseID3v2GenreString($value) as $genre) {
448  $genres[] = $genre;
449  }
450  }
451  $thisfile_id3v2['comments']['genre'] = array_unique($genres);
452  unset($key, $value, $genres, $genre);
453  }
454 
455  if (isset($thisfile_id3v2['comments']['track'])) {
456  foreach ($thisfile_id3v2['comments']['track'] as $key => $value) {
457  if (strstr($value, '/')) {
458  list($thisfile_id3v2['comments']['tracknum'][$key], $thisfile_id3v2['comments']['totaltracks'][$key]) = explode('/', $thisfile_id3v2['comments']['track'][$key]);
459  }
460  }
461  }
462 
463  if (!isset($thisfile_id3v2['comments']['year']) && !empty($thisfile_id3v2['comments']['recording_time'][0]) && preg_match('#^([0-9]{4})#', trim($thisfile_id3v2['comments']['recording_time'][0]), $matches)) {
464  $thisfile_id3v2['comments']['year'] = array($matches[1]);
465  }
466 
467 
468  if (!empty($thisfile_id3v2['TXXX'])) {
469  // MediaMonkey does this, maybe others: write a blank RGAD frame, but put replay-gain adjustment values in TXXX frames
470  foreach ($thisfile_id3v2['TXXX'] as $txxx_array) {
471  switch ($txxx_array['description']) {
472  case 'replaygain_track_gain':
473  if (empty($info['replay_gain']['track']['adjustment']) && !empty($txxx_array['data'])) {
474  $info['replay_gain']['track']['adjustment'] = floatval(trim(str_replace('dB', '', $txxx_array['data'])));
475  }
476  break;
477  case 'replaygain_track_peak':
478  if (empty($info['replay_gain']['track']['peak']) && !empty($txxx_array['data'])) {
479  $info['replay_gain']['track']['peak'] = floatval($txxx_array['data']);
480  }
481  break;
482  case 'replaygain_album_gain':
483  if (empty($info['replay_gain']['album']['adjustment']) && !empty($txxx_array['data'])) {
484  $info['replay_gain']['album']['adjustment'] = floatval(trim(str_replace('dB', '', $txxx_array['data'])));
485  }
486  break;
487  }
488  }
489  }
490 
491 
492  // Set avdataoffset
493  $info['avdataoffset'] = $thisfile_id3v2['headerlength'];
494  if (isset($thisfile_id3v2['footer'])) {
495  $info['avdataoffset'] += 10;
496  }
497 
498  return true;
499  }
ParseID3v2GenreString($genrestring)
ID3v2HeaderLength($majorversion)
LookupExtendedHeaderRestrictionsTextEncodings($index)
ParseID3v2Frame(&$parsedFrame, &$ThisFileInfo)
LookupExtendedHeaderRestrictionsTagSizeLimits($index)
LookupExtendedHeaderRestrictionsTextFieldSize($index)
$info
Definition: example_052.php:80
$header
IsValidID3v2FrameName($framename, $id3v2majorversion)
fread($bytes)
Definition: getid3.php:1685
BigEndian2Int($byteword, $synchsafe=false, $signed=false)
Definition: getid3.lib.php:234
CastAsInt($floatnum)
Definition: getid3.lib.php:60
LookupExtendedHeaderRestrictionsImageSizeSize($index)
fseek($bytes, $whence=SEEK_SET)
Definition: getid3.php:1697
LookupExtendedHeaderRestrictionsImageEncoding($index)
+ Here is the call graph for this function:

◆ APICPictureTypeLookup() [1/2]

getid3_id3v2::APICPictureTypeLookup (   $index,
  $returnarray = false 
)

Definition at line 2641 of file module.tag.id3v2.php.

Referenced by ParseID3v2Frame().

2641  {
2642  static $APICPictureTypeLookup = array(
2643  0x00 => 'Other',
2644  0x01 => '32x32 pixels \'file icon\' (PNG only)',
2645  0x02 => 'Other file icon',
2646  0x03 => 'Cover (front)',
2647  0x04 => 'Cover (back)',
2648  0x05 => 'Leaflet page',
2649  0x06 => 'Media (e.g. label side of CD)',
2650  0x07 => 'Lead artist/lead performer/soloist',
2651  0x08 => 'Artist/performer',
2652  0x09 => 'Conductor',
2653  0x0A => 'Band/Orchestra',
2654  0x0B => 'Composer',
2655  0x0C => 'Lyricist/text writer',
2656  0x0D => 'Recording Location',
2657  0x0E => 'During recording',
2658  0x0F => 'During performance',
2659  0x10 => 'Movie/video screen capture',
2660  0x11 => 'A bright coloured fish',
2661  0x12 => 'Illustration',
2662  0x13 => 'Band/artist logotype',
2663  0x14 => 'Publisher/Studio logotype'
2664  );
2665  if ($returnarray) {
2666  return $APICPictureTypeLookup;
2667  }
2668  return (isset($APICPictureTypeLookup[$index]) ? $APICPictureTypeLookup[$index] : '');
2669  }
+ Here is the caller graph for this function:

◆ APICPictureTypeLookup() [2/2]

static getid3_id3v2::APICPictureTypeLookup (   $index,
  $returnarray = false 
)
static

Definition at line 3125 of file module.tag.id3v2.php.

3125  {
3126  static $APICPictureTypeLookup = array(
3127  0x00 => 'Other',
3128  0x01 => '32x32 pixels \'file icon\' (PNG only)',
3129  0x02 => 'Other file icon',
3130  0x03 => 'Cover (front)',
3131  0x04 => 'Cover (back)',
3132  0x05 => 'Leaflet page',
3133  0x06 => 'Media (e.g. label side of CD)',
3134  0x07 => 'Lead artist/lead performer/soloist',
3135  0x08 => 'Artist/performer',
3136  0x09 => 'Conductor',
3137  0x0A => 'Band/Orchestra',
3138  0x0B => 'Composer',
3139  0x0C => 'Lyricist/text writer',
3140  0x0D => 'Recording Location',
3141  0x0E => 'During recording',
3142  0x0F => 'During performance',
3143  0x10 => 'Movie/video screen capture',
3144  0x11 => 'A bright coloured fish',
3145  0x12 => 'Illustration',
3146  0x13 => 'Band/artist logotype',
3147  0x14 => 'Publisher/Studio logotype'
3148  );
3149  if ($returnarray) {
3150  return $APICPictureTypeLookup;
3151  }
3152  return (isset($APICPictureTypeLookup[$index]) ? $APICPictureTypeLookup[$index] : '');
3153  }

◆ COMRReceivedAsLookup() [1/2]

getid3_id3v2::COMRReceivedAsLookup (   $index)

Definition at line 2671 of file module.tag.id3v2.php.

Referenced by ParseID3v2Frame().

2671  {
2672  static $COMRReceivedAsLookup = array(
2673  0x00 => 'Other',
2674  0x01 => 'Standard CD album with other songs',
2675  0x02 => 'Compressed audio on CD',
2676  0x03 => 'File over the Internet',
2677  0x04 => 'Stream over the Internet',
2678  0x05 => 'As note sheets',
2679  0x06 => 'As note sheets in a book with other sheets',
2680  0x07 => 'Music on other media',
2681  0x08 => 'Non-musical merchandise'
2682  );
2683 
2684  return (isset($COMRReceivedAsLookup[$index]) ? $COMRReceivedAsLookup[$index] : '');
2685  }
+ Here is the caller graph for this function:

◆ COMRReceivedAsLookup() [2/2]

static getid3_id3v2::COMRReceivedAsLookup (   $index)
static

Definition at line 3155 of file module.tag.id3v2.php.

3155  {
3156  static $COMRReceivedAsLookup = array(
3157  0x00 => 'Other',
3158  0x01 => 'Standard CD album with other songs',
3159  0x02 => 'Compressed audio on CD',
3160  0x03 => 'File over the Internet',
3161  0x04 => 'Stream over the Internet',
3162  0x05 => 'As note sheets',
3163  0x06 => 'As note sheets in a book with other sheets',
3164  0x07 => 'Music on other media',
3165  0x08 => 'Non-musical merchandise'
3166  );
3167 
3168  return (isset($COMRReceivedAsLookup[$index]) ? $COMRReceivedAsLookup[$index] : '');
3169  }

◆ DeUnsynchronise() [1/2]

getid3_id3v2::DeUnsynchronise (   $data)

Definition at line 1728 of file module.tag.id3v2.php.

References $data.

Referenced by Analyze(), getid3_id3v2(), and ParseID3v2Frame().

1728  {
1729  return str_replace("\xFF\x00", "\xFF", $data);
1730  }
$data
+ Here is the caller graph for this function:

◆ DeUnsynchronise() [2/2]

getid3_id3v2::DeUnsynchronise (   $data)

Definition at line 2166 of file module.tag.id3v2.php.

References $data.

2166  {
2167  return str_replace("\xFF\x00", "\xFF", $data);
2168  }
$data

◆ ETCOEventLookup() [1/2]

getid3_id3v2::ETCOEventLookup (   $index)

Definition at line 2582 of file module.tag.id3v2.php.

Referenced by ParseID3v2Frame().

2582  {
2583  if (($index >= 0x17) && ($index <= 0xDF)) {
2584  return 'reserved for future use';
2585  }
2586  if (($index >= 0xE0) && ($index <= 0xEF)) {
2587  return 'not predefined synch 0-F';
2588  }
2589  if (($index >= 0xF0) && ($index <= 0xFC)) {
2590  return 'reserved for future use';
2591  }
2592 
2593  static $EventLookup = array(
2594  0x00 => 'padding (has no meaning)',
2595  0x01 => 'end of initial silence',
2596  0x02 => 'intro start',
2597  0x03 => 'main part start',
2598  0x04 => 'outro start',
2599  0x05 => 'outro end',
2600  0x06 => 'verse start',
2601  0x07 => 'refrain start',
2602  0x08 => 'interlude start',
2603  0x09 => 'theme start',
2604  0x0A => 'variation start',
2605  0x0B => 'key change',
2606  0x0C => 'time change',
2607  0x0D => 'momentary unwanted noise (Snap, Crackle & Pop)',
2608  0x0E => 'sustained noise',
2609  0x0F => 'sustained noise end',
2610  0x10 => 'intro end',
2611  0x11 => 'main part end',
2612  0x12 => 'verse end',
2613  0x13 => 'refrain end',
2614  0x14 => 'theme end',
2615  0x15 => 'profanity',
2616  0x16 => 'profanity end',
2617  0xFD => 'audio end (start of silence)',
2618  0xFE => 'audio file ends',
2619  0xFF => 'one more byte of events follows'
2620  );
2621 
2622  return (isset($EventLookup[$index]) ? $EventLookup[$index] : '');
2623  }
+ Here is the caller graph for this function:

◆ ETCOEventLookup() [2/2]

static getid3_id3v2::ETCOEventLookup (   $index)
static

Definition at line 3066 of file module.tag.id3v2.php.

3066  {
3067  if (($index >= 0x17) && ($index <= 0xDF)) {
3068  return 'reserved for future use';
3069  }
3070  if (($index >= 0xE0) && ($index <= 0xEF)) {
3071  return 'not predefined synch 0-F';
3072  }
3073  if (($index >= 0xF0) && ($index <= 0xFC)) {
3074  return 'reserved for future use';
3075  }
3076 
3077  static $EventLookup = array(
3078  0x00 => 'padding (has no meaning)',
3079  0x01 => 'end of initial silence',
3080  0x02 => 'intro start',
3081  0x03 => 'main part start',
3082  0x04 => 'outro start',
3083  0x05 => 'outro end',
3084  0x06 => 'verse start',
3085  0x07 => 'refrain start',
3086  0x08 => 'interlude start',
3087  0x09 => 'theme start',
3088  0x0A => 'variation start',
3089  0x0B => 'key change',
3090  0x0C => 'time change',
3091  0x0D => 'momentary unwanted noise (Snap, Crackle & Pop)',
3092  0x0E => 'sustained noise',
3093  0x0F => 'sustained noise end',
3094  0x10 => 'intro end',
3095  0x11 => 'main part end',
3096  0x12 => 'verse end',
3097  0x13 => 'refrain end',
3098  0x14 => 'theme end',
3099  0x15 => 'profanity',
3100  0x16 => 'profanity end',
3101  0xFD => 'audio end (start of silence)',
3102  0xFE => 'audio file ends',
3103  0xFF => 'one more byte of events follows'
3104  );
3105 
3106  return (isset($EventLookup[$index]) ? $EventLookup[$index] : '');
3107  }

◆ FrameNameLongLookup() [1/2]

getid3_id3v2::FrameNameLongLookup (   $framename)

This is not a comment!

AENC        Audio encryption
APIC        Attached picture
ASPI        Audio seek point index
BUF Recommended buffer size
CNT Play counter
COM Comments
COMM        Comments
COMR        Commercial frame
CRA Audio encryption
CRM Encrypted meta frame
ENCR        Encryption method registration
EQU Equalisation
EQU2        Equalisation (2)
EQUA        Equalisation
ETC Event timing codes
ETCO        Event timing codes
GEO General encapsulated object
GEOB        General encapsulated object
GRID        Group identification registration
IPL Involved people list
IPLS        Involved people list
LINK        Linked information
LNK Linked information
MCDI        Music CD identifier
MCI Music CD Identifier
MLL MPEG location lookup table
MLLT        MPEG location lookup table
OWNE        Ownership frame
PCNT        Play counter
PIC Attached picture
POP Popularimeter
POPM        Popularimeter
POSS        Position synchronisation frame
PRIV        Private frame
RBUF        Recommended buffer size
REV Reverb
RVA Relative volume adjustment
RVA2        Relative volume adjustment (2)
RVAD        Relative volume adjustment
RVRB        Reverb
SEEK        Seek frame
SIGN        Signature frame
SLT Synchronised lyric/text
STC Synced tempo codes
SYLT        Synchronised lyric/text
SYTC        Synchronised tempo codes
TAL Album/Movie/Show title
TALB        Album/Movie/Show title
TBP BPM (Beats Per Minute)
TBPM        BPM (beats per minute)
TCM Composer
TCO Content type
TCOM        Composer
TCON        Content type
TCOP        Copyright message
TCR Copyright message
TDA Date
TDAT        Date
TDEN        Encoding time
TDLY        Playlist delay
TDOR        Original release time
TDRC        Recording time
TDRL        Release time
TDTG        Tagging time
TDY Playlist delay
TEN Encoded by
TENC        Encoded by
TEXT        Lyricist/Text writer
TFLT        File type
TFT File type
TIM Time
TIME        Time
TIPL        Involved people list
TIT1        Content group description
TIT2        Title/songname/content description
TIT3        Subtitle/Description refinement
TKE Initial key
TKEY        Initial key
TLA Language(s)
TLAN        Language(s)
TLE Length
TLEN        Length
TMCL        Musician credits list
TMED        Media type
TMOO        Mood
TMT Media type
TOA Original artist(s)/performer(s)
TOAL        Original album/movie/show title
TOF Original filename
TOFN        Original filename
TOL Original Lyricist(s)/text writer(s)
TOLY        Original lyricist(s)/text writer(s)
TOPE        Original artist(s)/performer(s)
TOR Original release year
TORY        Original release year
TOT Original album/Movie/Show title
TOWN        File owner/licensee
TP1 Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group
TP2 Band/Orchestra/Accompaniment
TP3 Conductor/Performer refinement
TP4 Interpreted, remixed, or otherwise modified by
TPA Part of a set
TPB Publisher
TPE1        Lead performer(s)/Soloist(s)
TPE2        Band/orchestra/accompaniment
TPE3        Conductor/performer refinement
TPE4        Interpreted, remixed, or otherwise modified by
TPOS        Part of a set
TPRO        Produced notice
TPUB        Publisher
TRC ISRC (International Standard Recording Code)
TRCK        Track number/Position in set
TRD Recording dates
TRDA        Recording dates
TRK Track number/Position in set
TRSN        Internet radio station name
TRSO        Internet radio station owner
TSI Size
TSIZ        Size
TSOA        Album sort order
TSOP        Performer sort order
TSOT        Title sort order
TSRC        ISRC (international standard recording code)
TSS Software/hardware and settings used for encoding
TSSE        Software/Hardware and settings used for encoding
TSST        Set subtitle
TT1 Content group description
TT2 Title/Songname/Content description
TT3 Subtitle/Description refinement
TXT Lyricist/text writer
TXX User defined text information frame
TXXX        User defined text information frame
TYE Year
TYER        Year
UFI Unique file identifier
UFID        Unique file identifier
ULT Unsychronised lyric/text transcription
USER        Terms of use
USLT        Unsynchronised lyric/text transcription
WAF Official audio file webpage
WAR Official artist/performer webpage
WAS Official audio source webpage
WCM Commercial information
WCOM        Commercial information
WCOP        Copyright/Legal information
WCP Copyright/Legal information
WOAF        Official audio file webpage
WOAR        Official artist/performer webpage
WOAS        Official audio source webpage
WORS        Official Internet radio station homepage
WPAY        Payment
WPB Publishers official webpage
WPUB        Publishers official webpage
WXX User defined URL link frame
WXXX        User defined URL link frame
TFEA        Featured Artist
TSTU        Recording Studio
rgad        Replay Gain Adjustment

Definition at line 2703 of file module.tag.id3v2.php.

References getid3_lib\EmbeddedLookup().

Referenced by ParseID3v2Frame().

2703  {
2704 
2705  $begin = __LINE__;
2706 
2870  return getid3_lib::EmbeddedLookup($framename, $begin, __LINE__, __FILE__, 'id3v2-framename_long');
2871 
2872  // Last three:
2873  // from Helium2 [www.helium2.com]
2874  // from http://privatewww.essex.ac.uk/~djmrob/replaygain/file_format_id3v2.html
2875  }
EmbeddedLookup($key, $begin, $end, $file, $name)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ FrameNameLongLookup() [2/2]

static getid3_id3v2::FrameNameLongLookup (   $framename)
static

This is not a comment!

AENC        Audio encryption
APIC        Attached picture
ASPI        Audio seek point index
BUF Recommended buffer size
CNT Play counter
COM Comments
COMM        Comments
COMR        Commercial frame
CRA Audio encryption
CRM Encrypted meta frame
ENCR        Encryption method registration
EQU Equalisation
EQU2        Equalisation (2)
EQUA        Equalisation
ETC Event timing codes
ETCO        Event timing codes
GEO General encapsulated object
GEOB        General encapsulated object
GRID        Group identification registration
IPL Involved people list
IPLS        Involved people list
LINK        Linked information
LNK Linked information
MCDI        Music CD identifier
MCI Music CD Identifier
MLL MPEG location lookup table
MLLT        MPEG location lookup table
OWNE        Ownership frame
PCNT        Play counter
PIC Attached picture
POP Popularimeter
POPM        Popularimeter
POSS        Position synchronisation frame
PRIV        Private frame
RBUF        Recommended buffer size
REV Reverb
RVA Relative volume adjustment
RVA2        Relative volume adjustment (2)
RVAD        Relative volume adjustment
RVRB        Reverb
SEEK        Seek frame
SIGN        Signature frame
SLT Synchronised lyric/text
STC Synced tempo codes
SYLT        Synchronised lyric/text
SYTC        Synchronised tempo codes
TAL Album/Movie/Show title
TALB        Album/Movie/Show title
TBP BPM (Beats Per Minute)
TBPM        BPM (beats per minute)
TCM Composer
TCMP        Part of a compilation
TCO Content type
TCOM        Composer
TCON        Content type
TCOP        Copyright message
TCP Part of a compilation
TCR Copyright message
TDA Date
TDAT        Date
TDEN        Encoding time
TDLY        Playlist delay
TDOR        Original release time
TDRC        Recording time
TDRL        Release time
TDTG        Tagging time
TDY Playlist delay
TEN Encoded by
TENC        Encoded by
TEXT        Lyricist/Text writer
TFLT        File type
TFT File type
TIM Time
TIME        Time
TIPL        Involved people list
TIT1        Content group description
TIT2        Title/songname/content description
TIT3        Subtitle/Description refinement
TKE Initial key
TKEY        Initial key
TLA Language(s)
TLAN        Language(s)
TLE Length
TLEN        Length
TMCL        Musician credits list
TMED        Media type
TMOO        Mood
TMT Media type
TOA Original artist(s)/performer(s)
TOAL        Original album/movie/show title
TOF Original filename
TOFN        Original filename
TOL Original Lyricist(s)/text writer(s)
TOLY        Original lyricist(s)/text writer(s)
TOPE        Original artist(s)/performer(s)
TOR Original release year
TORY        Original release year
TOT Original album/Movie/Show title
TOWN        File owner/licensee
TP1 Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group
TP2 Band/Orchestra/Accompaniment
TP3 Conductor/Performer refinement
TP4 Interpreted, remixed, or otherwise modified by
TPA Part of a set
TPB Publisher
TPE1        Lead performer(s)/Soloist(s)
TPE2        Band/orchestra/accompaniment
TPE3        Conductor/performer refinement
TPE4        Interpreted, remixed, or otherwise modified by
TPOS        Part of a set
TPRO        Produced notice
TPUB        Publisher
TRC ISRC (International Standard Recording Code)
TRCK        Track number/Position in set
TRD Recording dates
TRDA        Recording dates
TRK Track number/Position in set
TRSN        Internet radio station name
TRSO        Internet radio station owner
TS2 Album-Artist sort order
TSA Album sort order
TSC Composer sort order
TSI Size
TSIZ        Size
TSO2        Album-Artist sort order
TSOA        Album sort order
TSOC        Composer sort order
TSOP        Performer sort order
TSOT        Title sort order
TSP Performer sort order
TSRC        ISRC (international standard recording code)
TSS Software/hardware and settings used for encoding
TSSE        Software/Hardware and settings used for encoding
TSST        Set subtitle
TST Title sort order
TT1 Content group description
TT2 Title/Songname/Content description
TT3 Subtitle/Description refinement
TXT Lyricist/text writer
TXX User defined text information frame
TXXX        User defined text information frame
TYE Year
TYER        Year
UFI Unique file identifier
UFID        Unique file identifier
ULT Unsychronised lyric/text transcription
USER        Terms of use
USLT        Unsynchronised lyric/text transcription
WAF Official audio file webpage
WAR Official artist/performer webpage
WAS Official audio source webpage
WCM Commercial information
WCOM        Commercial information
WCOP        Copyright/Legal information
WCP Copyright/Legal information
WOAF        Official audio file webpage
WOAR        Official artist/performer webpage
WOAS        Official audio source webpage
WORS        Official Internet radio station homepage
WPAY        Payment
WPB Publishers official webpage
WPUB        Publishers official webpage
WXX User defined URL link frame
WXXX        User defined URL link frame
TFEA        Featured Artist
TSTU        Recording Studio
rgad        Replay Gain Adjustment

Definition at line 3187 of file module.tag.id3v2.php.

References getid3_lib\EmbeddedLookup().

3187  {
3188 
3189  $begin = __LINE__;
3190 
3363  return getid3_lib::EmbeddedLookup($framename, $begin, __LINE__, __FILE__, 'id3v2-framename_long');
3364 
3365  // Last three:
3366  // from Helium2 [www.helium2.com]
3367  // from http://privatewww.essex.ac.uk/~djmrob/replaygain/file_format_id3v2.html
3368  }
EmbeddedLookup($key, $begin, $end, $file, $name)
+ Here is the call graph for this function:

◆ FrameNameShortLookup() [1/2]

getid3_id3v2::FrameNameShortLookup (   $framename)

This is not a comment!

AENC        audio_encryption
APIC        attached_picture
ASPI        audio_seek_point_index
BUF recommended_buffer_size
CNT play_counter
COM comments
COMM        comments
COMR        commercial_frame
CRA audio_encryption
CRM encrypted_meta_frame
ENCR        encryption_method_registration
EQU equalisation
EQU2        equalisation
EQUA        equalisation
ETC event_timing_codes
ETCO        event_timing_codes
GEO general_encapsulated_object
GEOB        general_encapsulated_object
GRID        group_identification_registration
IPL involved_people_list
IPLS        involved_people_list
LINK        linked_information
LNK linked_information
MCDI        music_cd_identifier
MCI music_cd_identifier
MLL mpeg_location_lookup_table
MLLT        mpeg_location_lookup_table
OWNE        ownership_frame
PCNT        play_counter
PIC attached_picture
POP popularimeter
POPM        popularimeter
POSS        position_synchronisation_frame
PRIV        private_frame
RBUF        recommended_buffer_size
REV reverb
RVA relative_volume_adjustment
RVA2        relative_volume_adjustment
RVAD        relative_volume_adjustment
RVRB        reverb
SEEK        seek_frame
SIGN        signature_frame
SLT synchronised_lyric
STC synced_tempo_codes
SYLT        synchronised_lyric
SYTC        synchronised_tempo_codes
TAL album
TALB        album
TBP bpm
TBPM        bpm
TCM composer
TCO content_type
TCOM        composer
TCON        content_type
TCOP        copyright_message
TCR copyright_message
TDA date
TDAT        date
TDEN        encoding_time
TDLY        playlist_delay
TDOR        original_release_time
TDRC        recording_time
TDRL        release_time
TDTG        tagging_time
TDY playlist_delay
TEN encoded_by
TENC        encoded_by
TEXT        lyricist
TFLT        file_type
TFT file_type
TIM time
TIME        time
TIPL        involved_people_list
TIT1        content_group_description
TIT2        title
TIT3        subtitle
TKE initial_key
TKEY        initial_key
TLA language
TLAN        language
TLE length
TLEN        length
TMCL        musician_credits_list
TMED        media_type
TMOO        mood
TMT media_type
TOA original_artist
TOAL        original_album
TOF original_filename
TOFN        original_filename
TOL original_lyricist
TOLY        original_lyricist
TOPE        original_artist
TOR original_year
TORY        original_year
TOT original_album
TOWN        file_owner
TP1 artist
TP2 band
TP3 conductor
TP4 remixer
TPA part_of_a_set
TPB publisher
TPE1        artist
TPE2        band
TPE3        conductor
TPE4        remixer
TPOS        part_of_a_set
TPRO        produced_notice
TPUB        publisher
TRC isrc
TRCK        track_number
TRD recording_dates
TRDA        recording_dates
TRK track_number
TRSN        internet_radio_station_name
TRSO        internet_radio_station_owner
TSI size
TSIZ        size
TSOA        album_sort_order
TSOP        performer_sort_order
TSOT        title_sort_order
TSRC        isrc
TSS encoder_settings
TSSE        encoder_settings
TSST        set_subtitle
TT1 description
TT2 title
TT3 subtitle
TXT lyricist
TXX text
TXXX        text
TYE year
TYER        year
UFI unique_file_identifier
UFID        unique_file_identifier
ULT unsychronised_lyric
USER        terms_of_use
USLT        unsynchronised_lyric
WAF url_file
WAR url_artist
WAS url_source
WCM commercial_information
WCOM        commercial_information
WCOP        copyright
WCP copyright
WOAF        url_file
WOAR        url_artist
WOAS        url_source
WORS        url_station
WPAY        url_payment
WPB url_publisher
WPUB        url_publisher
WXX url_user
WXXX        url_user
TFEA        featured_artist
TSTU        recording_studio
rgad        replay_gain_adjustment

Definition at line 2878 of file module.tag.id3v2.php.

References getid3_lib\EmbeddedLookup().

Referenced by ParseID3v2Frame().

2878  {
2879 
2880  $begin = __LINE__;
2881 
3044 
3045  return getid3_lib::EmbeddedLookup($framename, $begin, __LINE__, __FILE__, 'id3v2-framename_short');
3046  }
EmbeddedLookup($key, $begin, $end, $file, $name)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ FrameNameShortLookup() [2/2]

static getid3_id3v2::FrameNameShortLookup (   $framename)
static

This is not a comment!

AENC        audio_encryption
APIC        attached_picture
ASPI        audio_seek_point_index
BUF recommended_buffer_size
CNT play_counter
COM comment
COMM        comment
COMR        commercial_frame
CRA audio_encryption
CRM encrypted_meta_frame
ENCR        encryption_method_registration
EQU equalisation
EQU2        equalisation
EQUA        equalisation
ETC event_timing_codes
ETCO        event_timing_codes
GEO general_encapsulated_object
GEOB        general_encapsulated_object
GRID        group_identification_registration
IPL involved_people_list
IPLS        involved_people_list
LINK        linked_information
LNK linked_information
MCDI        music_cd_identifier
MCI music_cd_identifier
MLL mpeg_location_lookup_table
MLLT        mpeg_location_lookup_table
OWNE        ownership_frame
PCNT        play_counter
PIC attached_picture
POP popularimeter
POPM        popularimeter
POSS        position_synchronisation_frame
PRIV        private_frame
RBUF        recommended_buffer_size
REV reverb
RVA relative_volume_adjustment
RVA2        relative_volume_adjustment
RVAD        relative_volume_adjustment
RVRB        reverb
SEEK        seek_frame
SIGN        signature_frame
SLT synchronised_lyric
STC synced_tempo_codes
SYLT        synchronised_lyric
SYTC        synchronised_tempo_codes
TAL album
TALB        album
TBP bpm
TBPM        bpm
TCM composer
TCMP        part_of_a_compilation
TCO genre
TCOM        composer
TCON        genre
TCOP        copyright_message
TCP part_of_a_compilation
TCR copyright_message
TDA date
TDAT        date
TDEN        encoding_time
TDLY        playlist_delay
TDOR        original_release_time
TDRC        recording_time
TDRL        release_time
TDTG        tagging_time
TDY playlist_delay
TEN encoded_by
TENC        encoded_by
TEXT        lyricist
TFLT        file_type
TFT file_type
TIM time
TIME        time
TIPL        involved_people_list
TIT1        content_group_description
TIT2        title
TIT3        subtitle
TKE initial_key
TKEY        initial_key
TLA language
TLAN        language
TLE length
TLEN        length
TMCL        musician_credits_list
TMED        media_type
TMOO        mood
TMT media_type
TOA original_artist
TOAL        original_album
TOF original_filename
TOFN        original_filename
TOL original_lyricist
TOLY        original_lyricist
TOPE        original_artist
TOR original_year
TORY        original_year
TOT original_album
TOWN        file_owner
TP1 artist
TP2 band
TP3 conductor
TP4 remixer
TPA part_of_a_set
TPB publisher
TPE1        artist
TPE2        band
TPE3        conductor
TPE4        remixer
TPOS        part_of_a_set
TPRO        produced_notice
TPUB        publisher
TRC isrc
TRCK        track_number
TRD recording_dates
TRDA        recording_dates
TRK track_number
TRSN        internet_radio_station_name
TRSO        internet_radio_station_owner
TS2 album_artist_sort_order
TSA album_sort_order
TSC composer_sort_order
TSI size
TSIZ        size
TSO2        album_artist_sort_order
TSOA        album_sort_order
TSOC        composer_sort_order
TSOP        performer_sort_order
TSOT        title_sort_order
TSP performer_sort_order
TSRC        isrc
TSS encoder_settings
TSSE        encoder_settings
TSST        set_subtitle
TST title_sort_order
TT1 content_group_description
TT2 title
TT3 subtitle
TXT lyricist
TXX text
TXXX        text
TYE year
TYER        year
UFI unique_file_identifier
UFID        unique_file_identifier
ULT unsychronised_lyric
USER        terms_of_use
USLT        unsynchronised_lyric
WAF url_file
WAR url_artist
WAS url_source
WCM commercial_information
WCOM        commercial_information
WCOP        copyright
WCP copyright
WOAF        url_file
WOAR        url_artist
WOAS        url_source
WORS        url_station
WPAY        url_payment
WPB url_publisher
WPUB        url_publisher
WXX url_user
WXXX        url_user
TFEA        featured_artist
TSTU        recording_studio
rgad        replay_gain_adjustment

Definition at line 3371 of file module.tag.id3v2.php.

References getid3_lib\EmbeddedLookup().

3371  {
3372 
3373  $begin = __LINE__;
3374 
3547  return getid3_lib::EmbeddedLookup($framename, $begin, __LINE__, __FILE__, 'id3v2-framename_short');
3548  }
EmbeddedLookup($key, $begin, $end, $file, $name)
+ Here is the call graph for this function:

◆ getid3_id3v2()

getid3_id3v2::getid3_id3v2 ( $fd,
$ThisFileInfo,
  $StartingOffset = 0 
)

Definition at line 21 of file module.tag.id3v2.php.

References $header, $StartingOffset, getid3_lib\array_merge_noclobber(), getid3_lib\BigEndian2Bin(), getid3_lib\BigEndian2Int(), getid3_lib\CastAsInt(), DeUnsynchronise(), getid3_handler\fread(), getid3_handler\fseek(), ID3v2HeaderLength(), IsValidID3v2FrameName(), ParseID3v2Frame(), and ParseID3v2GenreString().

21  {
22  // Overall tag structure:
23  // +-----------------------------+
24  // | Header (10 bytes) |
25  // +-----------------------------+
26  // | Extended Header |
27  // | (variable length, OPTIONAL) |
28  // +-----------------------------+
29  // | Frames (variable length) |
30  // +-----------------------------+
31  // | Padding |
32  // | (variable length, OPTIONAL) |
33  // +-----------------------------+
34  // | Footer (10 bytes, OPTIONAL) |
35  // +-----------------------------+
36 
37  // Header
38  // ID3v2/file identifier "ID3"
39  // ID3v2 version $04 00
40  // ID3v2 flags (%ab000000 in v2.2, %abc00000 in v2.3, %abcd0000 in v2.4.x)
41  // ID3v2 size 4 * %0xxxxxxx
42 
43 
44  // shortcuts
45  $ThisFileInfo['id3v2']['header'] = true;
46  $thisfile_id3v2 = &$ThisFileInfo['id3v2'];
47  $thisfile_id3v2['flags'] = array();
48  $thisfile_id3v2_flags = &$thisfile_id3v2['flags'];
49 
50 
51  fseek($fd, $StartingOffset, SEEK_SET);
52  $header = fread($fd, 10);
53  if (substr($header, 0, 3) == 'ID3') {
54 
55  $thisfile_id3v2['majorversion'] = ord($header{3});
56  $thisfile_id3v2['minorversion'] = ord($header{4});
57 
58  // shortcut
59  $id3v2_majorversion = &$thisfile_id3v2['majorversion'];
60 
61  } else {
62 
63  unset($ThisFileInfo['id3v2']);
64  return false;
65 
66  }
67 
68  if ($id3v2_majorversion > 4) { // this script probably won't correctly parse ID3v2.5.x and above (if it ever exists)
69 
70  $ThisFileInfo['error'][] = 'this script only parses up to ID3v2.4.x - this tag is ID3v2.'.$id3v2_majorversion.'.'.$thisfile_id3v2['minorversion'];
71  return false;
72 
73  }
74 
75  $id3_flags = ord($header{5});
76  switch ($id3v2_majorversion) {
77  case 2:
78  // %ab000000 in v2.2
79  $thisfile_id3v2_flags['unsynch'] = (bool) ($id3_flags & 0x80); // a - Unsynchronisation
80  $thisfile_id3v2_flags['compression'] = (bool) ($id3_flags & 0x40); // b - Compression
81  break;
82 
83  case 3:
84  // %abc00000 in v2.3
85  $thisfile_id3v2_flags['unsynch'] = (bool) ($id3_flags & 0x80); // a - Unsynchronisation
86  $thisfile_id3v2_flags['exthead'] = (bool) ($id3_flags & 0x40); // b - Extended header
87  $thisfile_id3v2_flags['experim'] = (bool) ($id3_flags & 0x20); // c - Experimental indicator
88  break;
89 
90  case 4:
91  // %abcd0000 in v2.4
92  $thisfile_id3v2_flags['unsynch'] = (bool) ($id3_flags & 0x80); // a - Unsynchronisation
93  $thisfile_id3v2_flags['exthead'] = (bool) ($id3_flags & 0x40); // b - Extended header
94  $thisfile_id3v2_flags['experim'] = (bool) ($id3_flags & 0x20); // c - Experimental indicator
95  $thisfile_id3v2_flags['isfooter'] = (bool) ($id3_flags & 0x10); // d - Footer present
96  break;
97  }
98 
99  $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
100 
101  $thisfile_id3v2['tag_offset_start'] = $StartingOffset;
102  $thisfile_id3v2['tag_offset_end'] = $thisfile_id3v2['tag_offset_start'] + $thisfile_id3v2['headerlength'];
103 
104  // Extended Header
105  if (isset($thisfile_id3v2_flags['exthead']) && $thisfile_id3v2_flags['exthead']) {
106  // Extended header size 4 * %0xxxxxxx
107  // Number of flag bytes $01
108  // Extended Flags $xx
109  // Where the 'Extended header size' is the size of the whole extended header, stored as a 32 bit synchsafe integer.
110  $thisfile_id3v2['exthead_length'] = getid3_lib::BigEndian2Int(fread($fd, 4), 1);
111 
112  $thisfile_id3v2['exthead_flag_bytes'] = ord(fread($fd, 1));
113  if ($thisfile_id3v2['exthead_flag_bytes'] == 1) {
114  // The extended flags field, with its size described by 'number of flag bytes', is defined as:
115  // %0bcd0000
116  // b - Tag is an update
117  // Flag data length $00
118  // c - CRC data present
119  // Flag data length $05
120  // Total frame CRC 5 * %0xxxxxxx
121  // d - Tag restrictions
122  // Flag data length $01
123  $extheaderflags = fread($fd, $thisfile_id3v2['exthead_flag_bytes']);
124  $id3_exthead_flags = getid3_lib::BigEndian2Bin(substr($header, 5, 1));
125  $thisfile_id3v2['exthead_flags']['update'] = substr($id3_exthead_flags, 1, 1);
126  $thisfile_id3v2['exthead_flags']['CRC'] = substr($id3_exthead_flags, 2, 1);
127  if ($thisfile_id3v2['exthead_flags']['CRC']) {
128  $extheaderrawCRC = fread($fd, 5);
129  $thisfile_id3v2['exthead_flags']['CRC'] = getid3_lib::BigEndian2Int($extheaderrawCRC, 1);
130  }
131  $thisfile_id3v2['exthead_flags']['restrictions'] = substr($id3_exthead_flags, 3, 1);
132  if ($thisfile_id3v2['exthead_flags']['restrictions']) {
133  // Restrictions %ppqrrstt
134  $extheaderrawrestrictions = fread($fd, 1);
135  $thisfile_id3v2['exthead_flags']['restrictions_tagsize'] = (bindec('11000000') & ord($extheaderrawrestrictions)) >> 6; // p - Tag size restrictions
136  $thisfile_id3v2['exthead_flags']['restrictions_textenc'] = (bindec('00100000') & ord($extheaderrawrestrictions)) >> 5; // q - Text encoding restrictions
137  $thisfile_id3v2['exthead_flags']['restrictions_textsize'] = (bindec('00011000') & ord($extheaderrawrestrictions)) >> 3; // r - Text fields size restrictions
138  $thisfile_id3v2['exthead_flags']['restrictions_imgenc'] = (bindec('00000100') & ord($extheaderrawrestrictions)) >> 2; // s - Image encoding restrictions
139  $thisfile_id3v2['exthead_flags']['restrictions_imgsize'] = (bindec('00000011') & ord($extheaderrawrestrictions)) >> 0; // t - Image size restrictions
140  }
141  } else {
142  $ThisFileInfo['warning'][] = '$thisfile_id3v2[exthead_flag_bytes] = "'.$thisfile_id3v2['exthead_flag_bytes'].'" (expecting "1")';
143  fseek($fd, $thisfile_id3v2['exthead_length'] - 1, SEEK_CUR);
144  //return false;
145  }
146  } // end extended header
147 
148 
149  // create 'encoding' key - used by getid3::HandleAllTags()
150  // in ID3v2 every field can have it's own encoding type
151  // so force everything to UTF-8 so it can be handled consistantly
152  $thisfile_id3v2['encoding'] = 'UTF-8';
153 
154 
155  // Frames
156 
157  // All ID3v2 frames consists of one frame header followed by one or more
158  // fields containing the actual information. The header is always 10
159  // bytes and laid out as follows:
160  //
161  // Frame ID $xx xx xx xx (four characters)
162  // Size 4 * %0xxxxxxx
163  // Flags $xx xx
164 
165  $sizeofframes = $thisfile_id3v2['headerlength'] - 10; // not including 10-byte initial header
166  if (@$thisfile_id3v2['exthead_length']) {
167  $sizeofframes -= ($thisfile_id3v2['exthead_length'] + 4);
168  }
169  if (@$thisfile_id3v2_flags['isfooter']) {
170  $sizeofframes -= 10; // footer takes last 10 bytes of ID3v2 header, after frame data, before audio
171  }
172  if ($sizeofframes > 0) {
173 
174  $framedata = fread($fd, $sizeofframes); // read all frames from file into $framedata variable
175 
176  // if entire frame data is unsynched, de-unsynch it now (ID3v2.3.x)
177  if (@$thisfile_id3v2_flags['unsynch'] && ($id3v2_majorversion <= 3)) {
178  $framedata = $this->DeUnsynchronise($framedata);
179  }
180  // [in ID3v2.4.0] Unsynchronisation [S:6.1] is done on frame level, instead
181  // of on tag level, making it easier to skip frames, increasing the streamability
182  // of the tag. The unsynchronisation flag in the header [S:3.1] indicates that
183  // there exists an unsynchronised frame, while the new unsynchronisation flag in
184  // the frame header [S:4.1.2] indicates unsynchronisation.
185 
186  $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)
187  while (isset($framedata) && (strlen($framedata) > 0)) { // cycle through until no more frame data is left to parse
188  if (strlen($framedata) <= $this->ID3v2HeaderLength($id3v2_majorversion)) {
189  // insufficient room left in ID3v2 header for actual data - must be padding
190  $thisfile_id3v2['padding']['start'] = $framedataoffset;
191  $thisfile_id3v2['padding']['length'] = strlen($framedata);
192  $thisfile_id3v2['padding']['valid'] = true;
193  for ($i = 0; $i < $thisfile_id3v2['padding']['length']; $i++) {
194  if ($framedata{$i} != "\x00") {
195  $thisfile_id3v2['padding']['valid'] = false;
196  $thisfile_id3v2['padding']['errorpos'] = $thisfile_id3v2['padding']['start'] + $i;
197  $ThisFileInfo['warning'][] = 'Invalid ID3v2 padding found at offset '.$thisfile_id3v2['padding']['errorpos'].' (the remaining '.($thisfile_id3v2['padding']['length'] - $i).' bytes are considered invalid)';
198  break;
199  }
200  }
201  break; // skip rest of ID3v2 header
202  }
203  if ($id3v2_majorversion == 2) {
204  // Frame ID $xx xx xx (three characters)
205  // Size $xx xx xx (24-bit integer)
206  // Flags $xx xx
207 
208  $frame_header = substr($framedata, 0, 6); // take next 6 bytes for header
209  $framedata = substr($framedata, 6); // and leave the rest in $framedata
210  $frame_name = substr($frame_header, 0, 3);
211  $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 3, 3), 0);
212  $frame_flags = 0; // not used for anything in ID3v2.2, just set to avoid E_NOTICEs
213 
214  } elseif ($id3v2_majorversion > 2) {
215 
216  // Frame ID $xx xx xx xx (four characters)
217  // Size $xx xx xx xx (32-bit integer in v2.3, 28-bit synchsafe in v2.4+)
218  // Flags $xx xx
219 
220  $frame_header = substr($framedata, 0, 10); // take next 10 bytes for header
221  $framedata = substr($framedata, 10); // and leave the rest in $framedata
222 
223  $frame_name = substr($frame_header, 0, 4);
224  if ($id3v2_majorversion == 3) {
225  $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0); // 32-bit integer
226  } else { // ID3v2.4+
227  $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 1); // 32-bit synchsafe integer (28-bit value)
228  }
229 
230  if ($frame_size < (strlen($framedata) + 4)) {
231  $nextFrameID = substr($framedata, $frame_size, 4);
232  if ($this->IsValidID3v2FrameName($nextFrameID, $id3v2_majorversion)) {
233  // next frame is OK
234  } elseif (($frame_name == "\x00".'MP3') || ($frame_name == "\x00\x00".'MP') || ($frame_name == ' MP3') || ($frame_name == 'MP3e')) {
235  // MP3ext known broken frames - "ok" for the purposes of this test
236  } elseif (($id3v2_majorversion == 4) && ($this->IsValidID3v2FrameName(substr($framedata, getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0), 4), 3))) {
237  $ThisFileInfo['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';
238  $id3v2_majorversion = 3;
239  $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0); // 32-bit integer
240  }
241  }
242 
243 
244  $frame_flags = getid3_lib::BigEndian2Int(substr($frame_header, 8, 2));
245  }
246 
247  if ((($id3v2_majorversion == 2) && ($frame_name == "\x00\x00\x00")) || ($frame_name == "\x00\x00\x00\x00")) {
248  // padding encountered
249 
250  $thisfile_id3v2['padding']['start'] = $framedataoffset;
251  $thisfile_id3v2['padding']['length'] = strlen($framedata);
252  $thisfile_id3v2['padding']['valid'] = true;
253  for ($i = 0; $i < $thisfile_id3v2['padding']['length']; $i++) {
254  if ($framedata{$i} != "\x00") {
255  $thisfile_id3v2['padding']['valid'] = false;
256  $thisfile_id3v2['padding']['errorpos'] = $thisfile_id3v2['padding']['start'] + $i;
257  $ThisFileInfo['warning'][] = 'Invalid ID3v2 padding found at offset '.$thisfile_id3v2['padding']['errorpos'].' (the remaining '.($thisfile_id3v2['padding']['length'] - $i).' bytes are considered invalid)';
258  break;
259  }
260  }
261  break; // skip rest of ID3v2 header
262  }
263 
264  if ($frame_name == 'COM ') {
265  $ThisFileInfo['warning'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))). [Note: this particular error has been known to happen with tags edited by iTunes (versions "X v2.0.3", "v3.0.1" are known-guilty, probably others too)]';
266  $frame_name = 'COMM';
267  }
268  if (($frame_size <= strlen($framedata)) && ($this->IsValidID3v2FrameName($frame_name, $id3v2_majorversion))) {
269 
270  unset($parsedFrame);
271  $parsedFrame['frame_name'] = $frame_name;
272  $parsedFrame['frame_flags_raw'] = $frame_flags;
273  $parsedFrame['data'] = substr($framedata, 0, $frame_size);
274  $parsedFrame['datalength'] = getid3_lib::CastAsInt($frame_size);
275  $parsedFrame['dataoffset'] = $framedataoffset;
276 
277  $this->ParseID3v2Frame($parsedFrame, $ThisFileInfo);
278  $thisfile_id3v2[$frame_name][] = $parsedFrame;
279 
280  $framedata = substr($framedata, $frame_size);
281 
282  } else { // invalid frame length or FrameID
283 
284  if ($frame_size <= strlen($framedata)) {
285 
286  if ($this->IsValidID3v2FrameName(substr($framedata, $frame_size, 4), $id3v2_majorversion)) {
287 
288  // next frame is valid, just skip the current frame
289  $framedata = substr($framedata, $frame_size);
290  $ThisFileInfo['warning'][] = 'Next ID3v2 frame is valid, skipping current frame.';
291 
292  } else {
293 
294  // next frame is invalid too, abort processing
295  //unset($framedata);
296  $framedata = null;
297  $ThisFileInfo['error'][] = 'Next ID3v2 frame is also invalid, aborting processing.';
298 
299  }
300 
301  } elseif ($frame_size == strlen($framedata)) {
302 
303  // this is the last frame, just skip
304  $ThisFileInfo['warning'][] = 'This was the last ID3v2 frame.';
305 
306  } else {
307 
308  // next frame is invalid too, abort processing
309  //unset($framedata);
310  $framedata = null;
311  $ThisFileInfo['warning'][] = 'Invalid ID3v2 frame size, aborting.';
312 
313  }
314  if (!$this->IsValidID3v2FrameName($frame_name, $id3v2_majorversion)) {
315 
316  switch ($frame_name) {
317  case "\x00\x00".'MP':
318  case "\x00".'MP3':
319  case ' MP3':
320  case 'MP3e':
321  case "\x00".'MP':
322  case ' MP':
323  case 'MP3':
324  $ThisFileInfo['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/)"]';
325  break;
326 
327  default:
328  $ThisFileInfo['warning'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: !IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))).';
329  break;
330  }
331 
332  } elseif ($frame_size > strlen($framedata)){
333 
334  $ThisFileInfo['error'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: $frame_size ('.$frame_size.') > strlen($framedata) ('.strlen($framedata).')).';
335 
336  } else {
337 
338  $ThisFileInfo['error'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag).';
339 
340  }
341 
342  }
343  $framedataoffset += ($frame_size + $this->ID3v2HeaderLength($id3v2_majorversion));
344 
345  }
346 
347  }
348 
349 
350  // Footer
351 
352  // The footer is a copy of the header, but with a different identifier.
353  // ID3v2 identifier "3DI"
354  // ID3v2 version $04 00
355  // ID3v2 flags %abcd0000
356  // ID3v2 size 4 * %0xxxxxxx
357 
358  if (isset($thisfile_id3v2_flags['isfooter']) && $thisfile_id3v2_flags['isfooter']) {
359  $footer = fread($fd, 10);
360  if (substr($footer, 0, 3) == '3DI') {
361  $thisfile_id3v2['footer'] = true;
362  $thisfile_id3v2['majorversion_footer'] = ord($footer{3});
363  $thisfile_id3v2['minorversion_footer'] = ord($footer{4});
364  }
365  if ($thisfile_id3v2['majorversion_footer'] <= 4) {
366  $id3_flags = ord(substr($footer{5}));
367  $thisfile_id3v2_flags['unsynch_footer'] = (bool) ($id3_flags & 0x80);
368  $thisfile_id3v2_flags['extfoot_footer'] = (bool) ($id3_flags & 0x40);
369  $thisfile_id3v2_flags['experim_footer'] = (bool) ($id3_flags & 0x20);
370  $thisfile_id3v2_flags['isfooter_footer'] = (bool) ($id3_flags & 0x10);
371 
372  $thisfile_id3v2['footerlength'] = getid3_lib::BigEndian2Int(substr($footer, 6, 4), 1);
373  }
374  } // end footer
375 
376  if (isset($thisfile_id3v2['comments']['genre'])) {
377  foreach ($thisfile_id3v2['comments']['genre'] as $key => $value) {
378  unset($thisfile_id3v2['comments']['genre'][$key]);
379  $thisfile_id3v2['comments'] = getid3_lib::array_merge_noclobber($thisfile_id3v2['comments'], $this->ParseID3v2GenreString($value));
380  }
381  }
382 
383  if (isset($thisfile_id3v2['comments']['track'])) {
384  foreach ($thisfile_id3v2['comments']['track'] as $key => $value) {
385  if (strstr($value, '/')) {
386  list($thisfile_id3v2['comments']['tracknum'][$key], $thisfile_id3v2['comments']['totaltracks'][$key]) = explode('/', $thisfile_id3v2['comments']['track'][$key]);
387  }
388  }
389  }
390 
391  if (!isset($thisfile_id3v2['comments']['year']) && ereg('^([0-9]{4})', trim(@$thisfile_id3v2['comments']['recording_time'][0]), $matches)) {
392  $thisfile_id3v2['comments']['year'] = array($matches[1]);
393  }
394 
395 
396  // Set avdataoffset
397  $ThisFileInfo['avdataoffset'] = $thisfile_id3v2['headerlength'];
398  if (isset($thisfile_id3v2['footer'])) {
399  $ThisFileInfo['avdataoffset'] += 10;
400  }
401 
402  return true;
403  }
ParseID3v2GenreString($genrestring)
ID3v2HeaderLength($majorversion)
ParseID3v2Frame(&$parsedFrame, &$ThisFileInfo)
array_merge_noclobber($array1, $array2)
Definition: getid3.lib.php:376
$header
IsValidID3v2FrameName($framename, $id3v2majorversion)
fread($bytes)
Definition: getid3.php:1685
BigEndian2Int($byteword, $synchsafe=false, $signed=false)
Definition: getid3.lib.php:234
CastAsInt($floatnum)
Definition: getid3.lib.php:60
BigEndian2Bin($byteword)
Definition: getid3.lib.php:271
fseek($bytes, $whence=SEEK_SET)
Definition: getid3.php:1697
+ Here is the call graph for this function:

◆ ID3v2HeaderLength() [1/2]

getid3_id3v2::ID3v2HeaderLength (   $majorversion)

Definition at line 3124 of file module.tag.id3v2.php.

Referenced by Analyze(), getid3_write_id3v2\GenerateID3v2Tag(), and getid3_id3v2().

3124  {
3125  return (($majorversion == 2) ? 6 : 10);
3126  }
+ Here is the caller graph for this function:

◆ ID3v2HeaderLength() [2/2]

static getid3_id3v2::ID3v2HeaderLength (   $majorversion)
static

Definition at line 3633 of file module.tag.id3v2.php.

3633  {
3634  return (($majorversion == 2) ? 6 : 10);
3635  }

◆ IsANumber() [1/2]

getid3_id3v2::IsANumber (   $numberstring,
  $allowdecimal = false,
  $allownegative = false 
)

Definition at line 3081 of file module.tag.id3v2.php.

Referenced by IsValidDateStampString().

3081  {
3082  for ($i = 0; $i < strlen($numberstring); $i++) {
3083  if ((chr($numberstring{$i}) < chr('0')) || (chr($numberstring{$i}) > chr('9'))) {
3084  if (($numberstring{$i} == '.') && $allowdecimal) {
3085  // allowed
3086  } elseif (($numberstring{$i} == '-') && $allownegative && ($i == 0)) {
3087  // allowed
3088  } else {
3089  return false;
3090  }
3091  }
3092  }
3093  return true;
3094  }
+ Here is the caller graph for this function:

◆ IsANumber() [2/2]

static getid3_id3v2::IsANumber (   $numberstring,
  $allowdecimal = false,
  $allownegative = false 
)
static

Definition at line 3590 of file module.tag.id3v2.php.

3590  {
3591  for ($i = 0; $i < strlen($numberstring); $i++) {
3592  if ((chr($numberstring{$i}) < chr('0')) || (chr($numberstring{$i}) > chr('9'))) {
3593  if (($numberstring{$i} == '.') && $allowdecimal) {
3594  // allowed
3595  } elseif (($numberstring{$i} == '-') && $allownegative && ($i == 0)) {
3596  // allowed
3597  } else {
3598  return false;
3599  }
3600  }
3601  }
3602  return true;
3603  }

◆ IsValidDateStampString() [1/2]

getid3_id3v2::IsValidDateStampString (   $datestamp)

Definition at line 3096 of file module.tag.id3v2.php.

References IsANumber().

Referenced by ParseID3v2Frame().

3096  {
3097  if (strlen($datestamp) != 8) {
3098  return false;
3099  }
3100  if (!$this->IsANumber($datestamp, false)) {
3101  return false;
3102  }
3103  $year = substr($datestamp, 0, 4);
3104  $month = substr($datestamp, 4, 2);
3105  $day = substr($datestamp, 6, 2);
3106  if (($year == 0) || ($month == 0) || ($day == 0)) {
3107  return false;
3108  }
3109  if ($month > 12) {
3110  return false;
3111  }
3112  if ($day > 31) {
3113  return false;
3114  }
3115  if (($day > 30) && (($month == 4) || ($month == 6) || ($month == 9) || ($month == 11))) {
3116  return false;
3117  }
3118  if (($day > 29) && ($month == 2)) {
3119  return false;
3120  }
3121  return true;
3122  }
IsANumber($numberstring, $allowdecimal=false, $allownegative=false)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ IsValidDateStampString() [2/2]

static getid3_id3v2::IsValidDateStampString (   $datestamp)
static

Definition at line 3605 of file module.tag.id3v2.php.

3605  {
3606  if (strlen($datestamp) != 8) {
3607  return false;
3608  }
3609  if (!self::IsANumber($datestamp, false)) {
3610  return false;
3611  }
3612  $year = substr($datestamp, 0, 4);
3613  $month = substr($datestamp, 4, 2);
3614  $day = substr($datestamp, 6, 2);
3615  if (($year == 0) || ($month == 0) || ($day == 0)) {
3616  return false;
3617  }
3618  if ($month > 12) {
3619  return false;
3620  }
3621  if ($day > 31) {
3622  return false;
3623  }
3624  if (($day > 30) && (($month == 4) || ($month == 6) || ($month == 9) || ($month == 11))) {
3625  return false;
3626  }
3627  if (($day > 29) && ($month == 2)) {
3628  return false;
3629  }
3630  return true;
3631  }

◆ IsValidID3v2FrameName() [1/2]

getid3_id3v2::IsValidID3v2FrameName (   $framename,
  $id3v2majorversion 
)

Definition at line 3067 of file module.tag.id3v2.php.

Referenced by Analyze(), getid3_write_id3v2\GenerateID3v2FrameData(), getid3_write_id3v2\GenerateID3v2Tag(), and getid3_id3v2().

3067  {
3068  switch ($id3v2majorversion) {
3069  case 2:
3070  return ereg('[A-Z][A-Z0-9]{2}', $framename);
3071  break;
3072 
3073  case 3:
3074  case 4:
3075  return ereg('[A-Z][A-Z0-9]{3}', $framename);
3076  break;
3077  }
3078  return false;
3079  }
+ Here is the caller graph for this function:

◆ IsValidID3v2FrameName() [2/2]

static getid3_id3v2::IsValidID3v2FrameName (   $framename,
  $id3v2majorversion 
)
static

Definition at line 3576 of file module.tag.id3v2.php.

3576  {
3577  switch ($id3v2majorversion) {
3578  case 2:
3579  return preg_match('#[A-Z][A-Z0-9]{2}#', $framename);
3580  break;
3581 
3582  case 3:
3583  case 4:
3584  return preg_match('#[A-Z][A-Z0-9]{3}#', $framename);
3585  break;
3586  }
3587  return false;
3588  }

◆ LanguageLookup() [1/2]

getid3_id3v2::LanguageLookup (   $languagecode,
  $casesensitive = false 
)

This is not a comment!

XXX unknown
xxx unknown
aar Afar
abk Abkhazian
ace Achinese
ach Acoli
ada Adangme
afa Afro-Asiatic (Other)
afh Afrihili
afr Afrikaans
aka Akan
akk Akkadian
alb Albanian
ale Aleut
alg Algonquian Languages
amh Amharic
ang English, Old (ca. 450-1100)
apa Apache Languages
ara Arabic
arc Aramaic
arm Armenian
arn Araucanian
arp Arapaho
art Artificial (Other)
arw Arawak
asm Assamese
ath Athapascan Languages
ava Avaric
ave Avestan
awa Awadhi
aym Aymara
aze Azerbaijani
bad Banda
bai Bamileke Languages
bak Bashkir
bal Baluchi
bam Bambara
ban Balinese
baq Basque
bas Basa
bat Baltic (Other)
bej Beja
bel Byelorussian
bem Bemba
ben Bengali
ber Berber (Other)
bho Bhojpuri
bih Bihari
bik Bikol
bin Bini
bis Bislama
bla Siksika
bnt Bantu (Other)
bod Tibetan
bra Braj
bre Breton
bua Buriat
bug Buginese
bul Bulgarian
bur Burmese
cad Caddo
cai Central American Indian (Other)
car Carib
cat Catalan
cau Caucasian (Other)
ceb Cebuano
cel Celtic (Other)
ces Czech
cha Chamorro
chb Chibcha
che Chechen
chg Chagatai
chi Chinese
chm Mari
chn Chinook jargon
cho Choctaw
chr Cherokee
chu Church Slavic
chv Chuvash
chy Cheyenne
cop Coptic
cor Cornish
cos Corsican
cpe Creoles and Pidgins, English-based (Other)
cpf Creoles and Pidgins, French-based (Other)
cpp Creoles and Pidgins, Portuguese-based (Other)
cre Cree
crp Creoles and Pidgins (Other)
cus Cushitic (Other)
cym Welsh
cze Czech
dak Dakota
dan Danish
del Delaware
deu German
din Dinka
div Divehi
doi Dogri
dra Dravidian (Other)
dua Duala
dum Dutch, Middle (ca. 1050-1350)
dut Dutch
dyu Dyula
dzo Dzongkha
efi Efik
egy Egyptian (Ancient)
eka Ekajuk
ell Greek, Modern (1453-)
elx Elamite
eng English
enm English, Middle (ca. 1100-1500)
epo Esperanto
esk Eskimo (Other)
esl Spanish
est Estonian
eus Basque
ewe Ewe
ewo Ewondo
fan Fang
fao Faroese
fas Persian
fat Fanti
fij Fijian
fin Finnish
fiu Finno-Ugrian (Other)
fon Fon
fra French
fre French
frm French, Middle (ca. 1400-1600)
fro French, Old (842- ca. 1400)
fry Frisian
ful Fulah
gaa Ga
gae Gaelic (Scots)
gai Irish
gay Gayo
gdh Gaelic (Scots)
gem Germanic (Other)
geo Georgian
ger German
gez Geez
gil Gilbertese
glg Gallegan
gmh German, Middle High (ca. 1050-1500)
goh German, Old High (ca. 750-1050)
gon Gondi
got Gothic
grb Grebo
grc Greek, Ancient (to 1453)
gre Greek, Modern (1453-)
grn Guarani
guj Gujarati
hai Haida
hau Hausa
haw Hawaiian
heb Hebrew
her Herero
hil Hiligaynon
him Himachali
hin Hindi
hmo Hiri Motu
hun Hungarian
hup Hupa
hye Armenian
iba Iban
ibo Igbo
ice Icelandic
ijo Ijo
iku Inuktitut
ilo Iloko
ina Interlingua (International Auxiliary language Association)
inc Indic (Other)
ind Indonesian
ine Indo-European (Other)
ine Interlingue
ipk Inupiak
ira Iranian (Other)
iri Irish
iro Iroquoian uages
isl Icelandic
ita Italian
jav Javanese
jaw Javanese
jpn Japanese
jpr Judeo-Persian
jrb Judeo-Arabic
kaa Kara-Kalpak
kab Kabyle
kac Kachin
kal Greenlandic
kam Kamba
kan Kannada
kar Karen
kas Kashmiri
kat Georgian
kau Kanuri
kaw Kawi
kaz Kazakh
kha Khasi
khi Khoisan (Other)
khm Khmer
kho Khotanese
kik Kikuyu
kin Kinyarwanda
kir Kirghiz
kok Konkani
kom Komi
kon Kongo
kor Korean
kpe Kpelle
kro Kru
kru Kurukh
kua Kuanyama
kum Kumyk
kur Kurdish
kus Kusaie
kut Kutenai
lad Ladino
lah Lahnda
lam Lamba
lao Lao
lat Latin
lav Latvian
lez Lezghian
lin Lingala
lit Lithuanian
lol Mongo
loz Lozi
ltz Letzeburgesch
lub Luba-Katanga
lug Ganda
lui Luiseno
lun Lunda
luo Luo (Kenya and Tanzania)
mac Macedonian
mad Madurese
mag Magahi
mah Marshall
mai Maithili
mak Macedonian
mak Makasar
mal Malayalam
man Mandingo
mao Maori
map Austronesian (Other)
mar Marathi
mas Masai
max Manx
may Malay
men Mende
mga Irish, Middle (900 - 1200)
mic Micmac
min Minangkabau
mis Miscellaneous (Other)
mkh Mon-Kmer (Other)
mlg Malagasy
mlt Maltese
mni Manipuri
mno Manobo Languages
moh Mohawk
mol Moldavian
mon Mongolian
mos Mossi
mri Maori
msa Malay
mul Multiple Languages
mun Munda Languages
mus Creek
mwr Marwari
mya Burmese
myn Mayan Languages
nah Aztec
nai North American Indian (Other)
nau Nauru
nav Navajo
nbl Ndebele, South
nde Ndebele, North
ndo Ndongo
nep Nepali
new Newari
nic Niger-Kordofanian (Other)
niu Niuean
nla Dutch
nno Norwegian (Nynorsk)
non Norse, Old
nor Norwegian
nso Sotho, Northern
nub Nubian Languages
nya Nyanja
nym Nyamwezi
nyn Nyankole
nyo Nyoro
nzi Nzima
oci Langue d'Oc (post 1500)
oji Ojibwa
ori Oriya
orm Oromo
osa Osage
oss Ossetic
ota Turkish, Ottoman (1500 - 1928)
oto Otomian Languages
paa Papuan-Australian (Other)
pag Pangasinan
pal Pahlavi
pam Pampanga
pan Panjabi
pap Papiamento
pau Palauan
peo Persian, Old (ca 600 - 400 B.C.)
per Persian
phn Phoenician
pli Pali
pol Polish
pon Ponape
por Portuguese
pra Prakrit uages
pro Provencal, Old (to 1500)
pus Pushto
que Quechua
raj Rajasthani
rar Rarotongan
roa Romance (Other)
roh Rhaeto-Romance
rom Romany
ron Romanian
rum Romanian
run Rundi
rus Russian
sad Sandawe
sag Sango
sah Yakut
sai South American Indian (Other)
sal Salishan Languages
sam Samaritan Aramaic
san Sanskrit
sco Scots
scr Serbo-Croatian
sel Selkup
sem Semitic (Other)
sga Irish, Old (to 900)
shn Shan
sid Sidamo
sin Singhalese
sio Siouan Languages
sit Sino-Tibetan (Other)
sla Slavic (Other)
slk Slovak
slo Slovak
slv Slovenian
smi Sami Languages
smo Samoan
sna Shona
snd Sindhi
sog Sogdian
som Somali
son Songhai
sot Sotho, Southern
spa Spanish
sqi Albanian
srd Sardinian
srr Serer
ssa Nilo-Saharan (Other)
ssw Siswant
ssw Swazi
suk Sukuma
sun Sudanese
sus Susu
sux Sumerian
sve Swedish
swa Swahili
swe Swedish
syr Syriac
tah Tahitian
tam Tamil
tat Tatar
tel Telugu
tem Timne
ter Tereno
tgk Tajik
tgl Tagalog
tha Thai
tib Tibetan
tig Tigre
tir Tigrinya
tiv Tivi
tli Tlingit
tmh Tamashek
tog Tonga (Nyasa)
ton Tonga (Tonga Islands)
tru Truk
tsi Tsimshian
tsn Tswana
tso Tsonga
tuk Turkmen
tum Tumbuka
tur Turkish
tut Altaic (Other)
twi Twi
tyv Tuvinian
uga Ugaritic
uig Uighur
ukr Ukrainian
umb Umbundu
und Undetermined
urd Urdu
uzb Uzbek
vai Vai
ven Venda
vie Vietnamese
vol Volapük
vot    Votic
wak Wakashan Languages
wal Walamo
war Waray
was Washo
wel Welsh
wen Sorbian Languages
wol Wolof
xho Xhosa
yao Yao
yap Yap
yid Yiddish
yor Yoruba
zap Zapotec
zen Zenaga
zha Zhuang
zho Chinese
zul Zulu
zun Zuni

Definition at line 2126 of file module.tag.id3v2.php.

References getid3_lib\EmbeddedLookup().

Referenced by getid3_write_id3v2\GenerateID3v2FrameData(), getid3_write_id3v2\ID3v2IsValidPriceString(), ParseID3v2Frame(), and getid3_quicktime\QuicktimeLanguageLookup().

2126  {
2127 
2128  if (!$casesensitive) {
2129  $languagecode = strtolower($languagecode);
2130  }
2131 
2132  // http://www.id3.org/id3v2.4.0-structure.txt
2133  // [4. ID3v2 frame overview]
2134  // The three byte language field, present in several frames, is used to
2135  // describe the language of the frame's content, according to ISO-639-2
2136  // [ISO-639-2]. The language should be represented in lower case. If the
2137  // language is not known the string "XXX" should be used.
2138 
2139 
2140  // ISO 639-2 - http://www.id3.org/iso639-2.html
2141 
2142  $begin = __LINE__;
2143 
2578  return getid3_lib::EmbeddedLookup($languagecode, $begin, __LINE__, __FILE__, 'id3v2-languagecode');
2579  }
EmbeddedLookup($key, $begin, $end, $file, $name)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ LanguageLookup() [2/2]

static getid3_id3v2::LanguageLookup (   $languagecode,
  $casesensitive = false 
)
static

This is not a comment!

XXX unknown
xxx unknown
aar Afar
abk Abkhazian
ace Achinese
ach Acoli
ada Adangme
afa Afro-Asiatic (Other)
afh Afrihili
afr Afrikaans
aka Akan
akk Akkadian
alb Albanian
ale Aleut
alg Algonquian Languages
amh Amharic
ang English, Old (ca. 450-1100)
apa Apache Languages
ara Arabic
arc Aramaic
arm Armenian
arn Araucanian
arp Arapaho
art Artificial (Other)
arw Arawak
asm Assamese
ath Athapascan Languages
ava Avaric
ave Avestan
awa Awadhi
aym Aymara
aze Azerbaijani
bad Banda
bai Bamileke Languages
bak Bashkir
bal Baluchi
bam Bambara
ban Balinese
baq Basque
bas Basa
bat Baltic (Other)
bej Beja
bel Byelorussian
bem Bemba
ben Bengali
ber Berber (Other)
bho Bhojpuri
bih Bihari
bik Bikol
bin Bini
bis Bislama
bla Siksika
bnt Bantu (Other)
bod Tibetan
bra Braj
bre Breton
bua Buriat
bug Buginese
bul Bulgarian
bur Burmese
cad Caddo
cai Central American Indian (Other)
car Carib
cat Catalan
cau Caucasian (Other)
ceb Cebuano
cel Celtic (Other)
ces Czech
cha Chamorro
chb Chibcha
che Chechen
chg Chagatai
chi Chinese
chm Mari
chn Chinook jargon
cho Choctaw
chr Cherokee
chu Church Slavic
chv Chuvash
chy Cheyenne
cop Coptic
cor Cornish
cos Corsican
cpe Creoles and Pidgins, English-based (Other)
cpf Creoles and Pidgins, French-based (Other)
cpp Creoles and Pidgins, Portuguese-based (Other)
cre Cree
crp Creoles and Pidgins (Other)
cus Cushitic (Other)
cym Welsh
cze Czech
dak Dakota
dan Danish
del Delaware
deu German
din Dinka
div Divehi
doi Dogri
dra Dravidian (Other)
dua Duala
dum Dutch, Middle (ca. 1050-1350)
dut Dutch
dyu Dyula
dzo Dzongkha
efi Efik
egy Egyptian (Ancient)
eka Ekajuk
ell Greek, Modern (1453-)
elx Elamite
eng English
enm English, Middle (ca. 1100-1500)
epo Esperanto
esk Eskimo (Other)
esl Spanish
est Estonian
eus Basque
ewe Ewe
ewo Ewondo
fan Fang
fao Faroese
fas Persian
fat Fanti
fij Fijian
fin Finnish
fiu Finno-Ugrian (Other)
fon Fon
fra French
fre French
frm French, Middle (ca. 1400-1600)
fro French, Old (842- ca. 1400)
fry Frisian
ful Fulah
gaa Ga
gae Gaelic (Scots)
gai Irish
gay Gayo
gdh Gaelic (Scots)
gem Germanic (Other)
geo Georgian
ger German
gez Geez
gil Gilbertese
glg Gallegan
gmh German, Middle High (ca. 1050-1500)
goh German, Old High (ca. 750-1050)
gon Gondi
got Gothic
grb Grebo
grc Greek, Ancient (to 1453)
gre Greek, Modern (1453-)
grn Guarani
guj Gujarati
hai Haida
hau Hausa
haw Hawaiian
heb Hebrew
her Herero
hil Hiligaynon
him Himachali
hin Hindi
hmo Hiri Motu
hun Hungarian
hup Hupa
hye Armenian
iba Iban
ibo Igbo
ice Icelandic
ijo Ijo
iku Inuktitut
ilo Iloko
ina Interlingua (International Auxiliary language Association)
inc Indic (Other)
ind Indonesian
ine Indo-European (Other)
ine Interlingue
ipk Inupiak
ira Iranian (Other)
iri Irish
iro Iroquoian uages
isl Icelandic
ita Italian
jav Javanese
jaw Javanese
jpn Japanese
jpr Judeo-Persian
jrb Judeo-Arabic
kaa Kara-Kalpak
kab Kabyle
kac Kachin
kal Greenlandic
kam Kamba
kan Kannada
kar Karen
kas Kashmiri
kat Georgian
kau Kanuri
kaw Kawi
kaz Kazakh
kha Khasi
khi Khoisan (Other)
khm Khmer
kho Khotanese
kik Kikuyu
kin Kinyarwanda
kir Kirghiz
kok Konkani
kom Komi
kon Kongo
kor Korean
kpe Kpelle
kro Kru
kru Kurukh
kua Kuanyama
kum Kumyk
kur Kurdish
kus Kusaie
kut Kutenai
lad Ladino
lah Lahnda
lam Lamba
lao Lao
lat Latin
lav Latvian
lez Lezghian
lin Lingala
lit Lithuanian
lol Mongo
loz Lozi
ltz Letzeburgesch
lub Luba-Katanga
lug Ganda
lui Luiseno
lun Lunda
luo Luo (Kenya and Tanzania)
mac Macedonian
mad Madurese
mag Magahi
mah Marshall
mai Maithili
mak Macedonian
mak Makasar
mal Malayalam
man Mandingo
mao Maori
map Austronesian (Other)
mar Marathi
mas Masai
max Manx
may Malay
men Mende
mga Irish, Middle (900 - 1200)
mic Micmac
min Minangkabau
mis Miscellaneous (Other)
mkh Mon-Kmer (Other)
mlg Malagasy
mlt Maltese
mni Manipuri
mno Manobo Languages
moh Mohawk
mol Moldavian
mon Mongolian
mos Mossi
mri Maori
msa Malay
mul Multiple Languages
mun Munda Languages
mus Creek
mwr Marwari
mya Burmese
myn Mayan Languages
nah Aztec
nai North American Indian (Other)
nau Nauru
nav Navajo
nbl Ndebele, South
nde Ndebele, North
ndo Ndongo
nep Nepali
new Newari
nic Niger-Kordofanian (Other)
niu Niuean
nla Dutch
nno Norwegian (Nynorsk)
non Norse, Old
nor Norwegian
nso Sotho, Northern
nub Nubian Languages
nya Nyanja
nym Nyamwezi
nyn Nyankole
nyo Nyoro
nzi Nzima
oci Langue d'Oc (post 1500)
oji Ojibwa
ori Oriya
orm Oromo
osa Osage
oss Ossetic
ota Turkish, Ottoman (1500 - 1928)
oto Otomian Languages
paa Papuan-Australian (Other)
pag Pangasinan
pal Pahlavi
pam Pampanga
pan Panjabi
pap Papiamento
pau Palauan
peo Persian, Old (ca 600 - 400 B.C.)
per Persian
phn Phoenician
pli Pali
pol Polish
pon Ponape
por Portuguese
pra Prakrit uages
pro Provencal, Old (to 1500)
pus Pushto
que Quechua
raj Rajasthani
rar Rarotongan
roa Romance (Other)
roh Rhaeto-Romance
rom Romany
ron Romanian
rum Romanian
run Rundi
rus Russian
sad Sandawe
sag Sango
sah Yakut
sai South American Indian (Other)
sal Salishan Languages
sam Samaritan Aramaic
san Sanskrit
sco Scots
scr Serbo-Croatian
sel Selkup
sem Semitic (Other)
sga Irish, Old (to 900)
shn Shan
sid Sidamo
sin Singhalese
sio Siouan Languages
sit Sino-Tibetan (Other)
sla Slavic (Other)
slk Slovak
slo Slovak
slv Slovenian
smi Sami Languages
smo Samoan
sna Shona
snd Sindhi
sog Sogdian
som Somali
son Songhai
sot Sotho, Southern
spa Spanish
sqi Albanian
srd Sardinian
srr Serer
ssa Nilo-Saharan (Other)
ssw Siswant
ssw Swazi
suk Sukuma
sun Sudanese
sus Susu
sux Sumerian
sve Swedish
swa Swahili
swe Swedish
syr Syriac
tah Tahitian
tam Tamil
tat Tatar
tel Telugu
tem Timne
ter Tereno
tgk Tajik
tgl Tagalog
tha Thai
tib Tibetan
tig Tigre
tir Tigrinya
tiv Tivi
tli Tlingit
tmh Tamashek
tog Tonga (Nyasa)
ton Tonga (Tonga Islands)
tru Truk
tsi Tsimshian
tsn Tswana
tso Tsonga
tuk Turkmen
tum Tumbuka
tur Turkish
tut Altaic (Other)
twi Twi
tyv Tuvinian
uga Ugaritic
uig Uighur
ukr Ukrainian
umb Umbundu
und Undetermined
urd Urdu
uzb Uzbek
vai Vai
ven Venda
vie Vietnamese
vol Volapük
vot Votic
wak Wakashan Languages
wal Walamo
war Waray
was Washo
wel Welsh
wen Sorbian Languages
wol Wolof
xho Xhosa
yao Yao
yap Yap
yid Yiddish
yor Yoruba
zap Zapotec
zen Zenaga
zha Zhuang
zho Chinese
zul Zulu
zun Zuni

Definition at line 2610 of file module.tag.id3v2.php.

References getid3_lib\EmbeddedLookup().

2610  {
2611 
2612  if (!$casesensitive) {
2613  $languagecode = strtolower($languagecode);
2614  }
2615 
2616  // http://www.id3.org/id3v2.4.0-structure.txt
2617  // [4. ID3v2 frame overview]
2618  // The three byte language field, present in several frames, is used to
2619  // describe the language of the frame's content, according to ISO-639-2
2620  // [ISO-639-2]. The language should be represented in lower case. If the
2621  // language is not known the string "XXX" should be used.
2622 
2623 
2624  // ISO 639-2 - http://www.id3.org/iso639-2.html
2625 
2626  $begin = __LINE__;
2627 
3062  return getid3_lib::EmbeddedLookup($languagecode, $begin, __LINE__, __FILE__, 'id3v2-languagecode');
3063  }
EmbeddedLookup($key, $begin, $end, $file, $name)
+ Here is the call graph for this function:

◆ LookupCurrencyCountry() [1/2]

getid3_id3v2::LookupCurrencyCountry (   $currencyid)

This is not a comment!

AED United Arab Emirates
AFA Afghanistan
ALL Albania
AMD Armenia
ANG Netherlands Antilles
AOA Angola
ARS Argentina
ATS Austria
AUD Australia
AWG Aruba
AZM Azerbaijan
BAM Bosnia and Herzegovina
BBD Barbados
BDT Bangladesh
BEF Belgium
BGL Bulgaria
BHD Bahrain
BIF Burundi
BMD Bermuda
BND Brunei Darussalam
BOB Bolivia
BRL Brazil
BSD Bahamas
BTN Bhutan
BWP Botswana
BYR Belarus
BZD Belize
CAD Canada
CDF Congo/Kinshasa
CHF Switzerland
CLP Chile
CNY China
COP Colombia
CRC Costa Rica
CUP Cuba
CVE Cape Verde
CYP Cyprus
CZK Czech Republic
DEM Germany
DJF Djibouti
DKK Denmark
DOP Dominican Republic
DZD Algeria
EEK Estonia
EGP Egypt
ERN Eritrea
ESP Spain
ETB Ethiopia
EUR Euro Member Countries
FIM Finland
FJD Fiji
FKP Falkland Islands (Malvinas)
FRF France
GBP United Kingdom
GEL Georgia
GGP Guernsey
GHC Ghana
GIP Gibraltar
GMD Gambia
GNF Guinea
GRD Greece
GTQ Guatemala
GYD Guyana
HKD Hong Kong
HNL Honduras
HRK Croatia
HTG Haiti
HUF Hungary
IDR Indonesia
IEP Ireland (Eire)
ILS Israel
IMP Isle of Man
INR India
IQD Iraq
IRR Iran
ISK Iceland
ITL Italy
JEP Jersey
JMD Jamaica
JOD Jordan
JPY Japan
KES Kenya
KGS Kyrgyzstan
KHR Cambodia
KMF Comoros
KPW Korea
KWD Kuwait
KYD Cayman Islands
KZT Kazakstan
LAK Laos
LBP Lebanon
LKR Sri Lanka
LRD Liberia
LSL Lesotho
LTL Lithuania
LUF Luxembourg
LVL Latvia
LYD Libya
MAD Morocco
MDL Moldova
MGF Madagascar
MKD Macedonia
MMK Myanmar (Burma)
MNT Mongolia
MOP Macau
MRO Mauritania
MTL Malta
MUR Mauritius
MVR Maldives (Maldive Islands)
MWK Malawi
MXN Mexico
MYR Malaysia
MZM Mozambique
NAD Namibia
NGN Nigeria
NIO Nicaragua
NLG Netherlands (Holland)
NOK Norway
NPR Nepal
NZD New Zealand
OMR Oman
PAB Panama
PEN Peru
PGK Papua New Guinea
PHP Philippines
PKR Pakistan
PLN Poland
PTE Portugal
PYG Paraguay
QAR Qatar
ROL Romania
RUR Russia
RWF Rwanda
SAR Saudi Arabia
SBD Solomon Islands
SCR Seychelles
SDD Sudan
SEK Sweden
SGD Singapore
SHP Saint Helena
SIT Slovenia
SKK Slovakia
SLL Sierra Leone
SOS Somalia
SPL Seborga
SRG Suriname
STD São Tome and Principe
SVC El Salvador
SYP Syria
SZL Swaziland
THB Thailand
TJR Tajikistan
TMM Turkmenistan
TND Tunisia
TOP Tonga
TRL Turkey
TTD Trinidad and Tobago
TVD Tuvalu
TWD Taiwan
TZS Tanzania
UAH Ukraine
UGX Uganda
USD United States of America
UYU Uruguay
UZS Uzbekistan
VAL Vatican City
VEB Venezuela
VND Viet Nam
VUV Vanuatu
WST Samoa
XAF Communauté Financière Africaine
XAG Silver
XAU Gold
XCD East Caribbean
XDR International Monetary Fund
XPD Palladium
XPF Comptoirs Français du Pacifique
XPT Platinum
YER Yemen
YUM Yugoslavia
ZAR South Africa
ZMK Zambia
ZWD Zimbabwe

Definition at line 1929 of file module.tag.id3v2.php.

References getid3_lib\EmbeddedLookup().

1929  {
1930 
1931  $begin = __LINE__;
1932 
2121  return getid3_lib::EmbeddedLookup($currencyid, $begin, __LINE__, __FILE__, 'id3v2-currency-country');
2122  }
EmbeddedLookup($key, $begin, $end, $file, $name)
+ Here is the call graph for this function:

◆ LookupCurrencyCountry() [2/2]

getid3_id3v2::LookupCurrencyCountry (   $currencyid)

This is not a comment!

AED United Arab Emirates
AFA Afghanistan
ALL Albania
AMD Armenia
ANG Netherlands Antilles
AOA Angola
ARS Argentina
ATS Austria
AUD Australia
AWG Aruba
AZM Azerbaijan
BAM Bosnia and Herzegovina
BBD Barbados
BDT Bangladesh
BEF Belgium
BGL Bulgaria
BHD Bahrain
BIF Burundi
BMD Bermuda
BND Brunei Darussalam
BOB Bolivia
BRL Brazil
BSD Bahamas
BTN Bhutan
BWP Botswana
BYR Belarus
BZD Belize
CAD Canada
CDF Congo/Kinshasa
CHF Switzerland
CLP Chile
CNY China
COP Colombia
CRC Costa Rica
CUP Cuba
CVE Cape Verde
CYP Cyprus
CZK Czech Republic
DEM Germany
DJF Djibouti
DKK Denmark
DOP Dominican Republic
DZD Algeria
EEK Estonia
EGP Egypt
ERN Eritrea
ESP Spain
ETB Ethiopia
EUR Euro Member Countries
FIM Finland
FJD Fiji
FKP Falkland Islands (Malvinas)
FRF France
GBP United Kingdom
GEL Georgia
GGP Guernsey
GHC Ghana
GIP Gibraltar
GMD Gambia
GNF Guinea
GRD Greece
GTQ Guatemala
GYD Guyana
HKD Hong Kong
HNL Honduras
HRK Croatia
HTG Haiti
HUF Hungary
IDR Indonesia
IEP Ireland (Eire)
ILS Israel
IMP Isle of Man
INR India
IQD Iraq
IRR Iran
ISK Iceland
ITL Italy
JEP Jersey
JMD Jamaica
JOD Jordan
JPY Japan
KES Kenya
KGS Kyrgyzstan
KHR Cambodia
KMF Comoros
KPW Korea
KWD Kuwait
KYD Cayman Islands
KZT Kazakstan
LAK Laos
LBP Lebanon
LKR Sri Lanka
LRD Liberia
LSL Lesotho
LTL Lithuania
LUF Luxembourg
LVL Latvia
LYD Libya
MAD Morocco
MDL Moldova
MGF Madagascar
MKD Macedonia
MMK Myanmar (Burma)
MNT Mongolia
MOP Macau
MRO Mauritania
MTL Malta
MUR Mauritius
MVR Maldives (Maldive Islands)
MWK Malawi
MXN Mexico
MYR Malaysia
MZM Mozambique
NAD Namibia
NGN Nigeria
NIO Nicaragua
NLG Netherlands (Holland)
NOK Norway
NPR Nepal
NZD New Zealand
OMR Oman
PAB Panama
PEN Peru
PGK Papua New Guinea
PHP Philippines
PKR Pakistan
PLN Poland
PTE Portugal
PYG Paraguay
QAR Qatar
ROL Romania
RUR Russia
RWF Rwanda
SAR Saudi Arabia
SBD Solomon Islands
SCR Seychelles
SDD Sudan
SEK Sweden
SGD Singapore
SHP Saint Helena
SIT Slovenia
SKK Slovakia
SLL Sierra Leone
SOS Somalia
SPL Seborga
SRG Suriname
STD São Tome and Principe
SVC El Salvador
SYP Syria
SZL Swaziland
THB Thailand
TJR Tajikistan
TMM Turkmenistan
TND Tunisia
TOP Tonga
TRL Turkey
TTD Trinidad and Tobago
TVD Tuvalu
TWD Taiwan
TZS Tanzania
UAH Ukraine
UGX Uganda
USD United States of America
UYU Uruguay
UZS Uzbekistan
VAL Vatican City
VEB Venezuela
VND Viet Nam
VUV Vanuatu
WST Samoa
XAF Communauté Financière Africaine
XAG Silver
XAU Gold
XCD East Caribbean
XDR International Monetary Fund
XPD Palladium
XPF Comptoirs Français du Pacifique
XPT Platinum
YER Yemen
YUM Yugoslavia
ZAR South Africa
ZMK Zambia
ZWD Zimbabwe

Definition at line 2413 of file module.tag.id3v2.php.

References getid3_lib\EmbeddedLookup().

2413  {
2414 
2415  $begin = __LINE__;
2416 
2605  return getid3_lib::EmbeddedLookup($currencyid, $begin, __LINE__, __FILE__, 'id3v2-currency-country');
2606  }
EmbeddedLookup($key, $begin, $end, $file, $name)
+ Here is the call graph for this function:

◆ LookupCurrencyUnits() [1/2]

getid3_id3v2::LookupCurrencyUnits (   $currencyid)

This is not a comment!

AED Dirhams
AFA Afghanis
ALL Leke
AMD Drams
ANG Guilders
AOA Kwanza
ARS Pesos
ATS Schillings
AUD Dollars
AWG Guilders
AZM Manats
BAM Convertible Marka
BBD Dollars
BDT Taka
BEF Francs
BGL Leva
BHD Dinars
BIF Francs
BMD Dollars
BND Dollars
BOB Bolivianos
BRL Brazil Real
BSD Dollars
BTN Ngultrum
BWP Pulas
BYR Rubles
BZD Dollars
CAD Dollars
CDF Congolese Francs
CHF Francs
CLP Pesos
CNY Yuan Renminbi
COP Pesos
CRC Colones
CUP Pesos
CVE Escudos
CYP Pounds
CZK Koruny
DEM Deutsche Marks
DJF Francs
DKK Kroner
DOP Pesos
DZD Algeria Dinars
EEK Krooni
EGP Pounds
ERN Nakfa
ESP Pesetas
ETB Birr
EUR Euro
FIM Markkaa
FJD Dollars
FKP Pounds
FRF Francs
GBP Pounds
GEL Lari
GGP Pounds
GHC Cedis
GIP Pounds
GMD Dalasi
GNF Francs
GRD Drachmae
GTQ Quetzales
GYD Dollars
HKD Dollars
HNL Lempiras
HRK Kuna
HTG Gourdes
HUF Forints
IDR Rupiahs
IEP Pounds
ILS New Shekels
IMP Pounds
INR Rupees
IQD Dinars
IRR Rials
ISK Kronur
ITL Lire
JEP Pounds
JMD Dollars
JOD Dinars
JPY Yen
KES Shillings
KGS Soms
KHR Riels
KMF Francs
KPW Won
KWD Dinars
KYD Dollars
KZT Tenge
LAK Kips
LBP Pounds
LKR Rupees
LRD Dollars
LSL Maloti
LTL Litai
LUF Francs
LVL Lati
LYD Dinars
MAD Dirhams
MDL Lei
MGF Malagasy Francs
MKD Denars
MMK Kyats
MNT Tugriks
MOP Patacas
MRO Ouguiyas
MTL Liri
MUR Rupees
MVR Rufiyaa
MWK Kwachas
MXN Pesos
MYR Ringgits
MZM Meticais
NAD Dollars
NGN Nairas
NIO Gold Cordobas
NLG Guilders
NOK Krone
NPR Nepal Rupees
NZD Dollars
OMR Rials
PAB Balboa
PEN Nuevos Soles
PGK Kina
PHP Pesos
PKR Rupees
PLN Zlotych
PTE Escudos
PYG Guarani
QAR Rials
ROL Lei
RUR Rubles
RWF Rwanda Francs
SAR Riyals
SBD Dollars
SCR Rupees
SDD Dinars
SEK Kronor
SGD Dollars
SHP Pounds
SIT Tolars
SKK Koruny
SLL Leones
SOS Shillings
SPL Luigini
SRG Guilders
STD Dobras
SVC Colones
SYP Pounds
SZL Emalangeni
THB Baht
TJR Rubles
TMM Manats
TND Dinars
TOP Pa'anga
TRL Liras
TTD Dollars
TVD Tuvalu Dollars
TWD New Dollars
TZS Shillings
UAH Hryvnia
UGX Shillings
USD Dollars
UYU Pesos
UZS Sums
VAL Lire
VEB Bolivares
VND Dong
VUV Vatu
WST Tala
XAF Francs
XAG Ounces
XAU Ounces
XCD Dollars
XDR Special Drawing Rights
XPD Ounces
XPF Francs
XPT Ounces
YER Rials
YUM New Dinars
ZAR Rand
ZMK Kwacha
ZWD Zimbabwe Dollars

Definition at line 1732 of file module.tag.id3v2.php.

References getid3_lib\EmbeddedLookup().

Referenced by ParseID3v2Frame().

1732  {
1733 
1734  $begin = __LINE__;
1735 
1925  return getid3_lib::EmbeddedLookup($currencyid, $begin, __LINE__, __FILE__, 'id3v2-currency-units');
1926  }
EmbeddedLookup($key, $begin, $end, $file, $name)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ LookupCurrencyUnits() [2/2]

getid3_id3v2::LookupCurrencyUnits (   $currencyid)

This is not a comment!

AED Dirhams
AFA Afghanis
ALL Leke
AMD Drams
ANG Guilders
AOA Kwanza
ARS Pesos
ATS Schillings
AUD Dollars
AWG Guilders
AZM Manats
BAM Convertible Marka
BBD Dollars
BDT Taka
BEF Francs
BGL Leva
BHD Dinars
BIF Francs
BMD Dollars
BND Dollars
BOB Bolivianos
BRL Brazil Real
BSD Dollars
BTN Ngultrum
BWP Pulas
BYR Rubles
BZD Dollars
CAD Dollars
CDF Congolese Francs
CHF Francs
CLP Pesos
CNY Yuan Renminbi
COP Pesos
CRC Colones
CUP Pesos
CVE Escudos
CYP Pounds
CZK Koruny
DEM Deutsche Marks
DJF Francs
DKK Kroner
DOP Pesos
DZD Algeria Dinars
EEK Krooni
EGP Pounds
ERN Nakfa
ESP Pesetas
ETB Birr
EUR Euro
FIM Markkaa
FJD Dollars
FKP Pounds
FRF Francs
GBP Pounds
GEL Lari
GGP Pounds
GHC Cedis
GIP Pounds
GMD Dalasi
GNF Francs
GRD Drachmae
GTQ Quetzales
GYD Dollars
HKD Dollars
HNL Lempiras
HRK Kuna
HTG Gourdes
HUF Forints
IDR Rupiahs
IEP Pounds
ILS New Shekels
IMP Pounds
INR Rupees
IQD Dinars
IRR Rials
ISK Kronur
ITL Lire
JEP Pounds
JMD Dollars
JOD Dinars
JPY Yen
KES Shillings
KGS Soms
KHR Riels
KMF Francs
KPW Won
KWD Dinars
KYD Dollars
KZT Tenge
LAK Kips
LBP Pounds
LKR Rupees
LRD Dollars
LSL Maloti
LTL Litai
LUF Francs
LVL Lati
LYD Dinars
MAD Dirhams
MDL Lei
MGF Malagasy Francs
MKD Denars
MMK Kyats
MNT Tugriks
MOP Patacas
MRO Ouguiyas
MTL Liri
MUR Rupees
MVR Rufiyaa
MWK Kwachas
MXN Pesos
MYR Ringgits
MZM Meticais
NAD Dollars
NGN Nairas
NIO Gold Cordobas
NLG Guilders
NOK Krone
NPR Nepal Rupees
NZD Dollars
OMR Rials
PAB Balboa
PEN Nuevos Soles
PGK Kina
PHP Pesos
PKR Rupees
PLN Zlotych
PTE Escudos
PYG Guarani
QAR Rials
ROL Lei
RUR Rubles
RWF Rwanda Francs
SAR Riyals
SBD Dollars
SCR Rupees
SDD Dinars
SEK Kronor
SGD Dollars
SHP Pounds
SIT Tolars
SKK Koruny
SLL Leones
SOS Shillings
SPL Luigini
SRG Guilders
STD Dobras
SVC Colones
SYP Pounds
SZL Emalangeni
THB Baht
TJR Rubles
TMM Manats
TND Dinars
TOP Pa'anga
TRL Liras
TTD Dollars
TVD Tuvalu Dollars
TWD New Dollars
TZS Shillings
UAH Hryvnia
UGX Shillings
USD Dollars
UYU Pesos
UZS Sums
VAL Lire
VEB Bolivares
VND Dong
VUV Vatu
WST Tala
XAF Francs
XAG Ounces
XAU Ounces
XCD Dollars
XDR Special Drawing Rights
XPD Ounces
XPF Francs
XPT Ounces
YER Rials
YUM New Dinars
ZAR Rand
ZMK Kwacha
ZWD Zimbabwe Dollars

Definition at line 2216 of file module.tag.id3v2.php.

References getid3_lib\EmbeddedLookup().

2216  {
2217 
2218  $begin = __LINE__;
2219 
2409  return getid3_lib::EmbeddedLookup($currencyid, $begin, __LINE__, __FILE__, 'id3v2-currency-units');
2410  }
EmbeddedLookup($key, $begin, $end, $file, $name)
+ Here is the call graph for this function:

◆ LookupExtendedHeaderRestrictionsImageEncoding()

getid3_id3v2::LookupExtendedHeaderRestrictionsImageEncoding (   $index)

Definition at line 2198 of file module.tag.id3v2.php.

Referenced by Analyze().

2198  {
2199  static $LookupExtendedHeaderRestrictionsImageEncoding = array(
2200  0x00 => 'No restrictions',
2201  0x01 => 'Images are encoded only with PNG or JPEG',
2202  );
2203  return (isset($LookupExtendedHeaderRestrictionsImageEncoding[$index]) ? $LookupExtendedHeaderRestrictionsImageEncoding[$index] : '');
2204  }
+ Here is the caller graph for this function:

◆ LookupExtendedHeaderRestrictionsImageSizeSize()

getid3_id3v2::LookupExtendedHeaderRestrictionsImageSizeSize (   $index)

Definition at line 2206 of file module.tag.id3v2.php.

Referenced by Analyze().

2206  {
2207  static $LookupExtendedHeaderRestrictionsImageSizeSize = array(
2208  0x00 => 'No restrictions',
2209  0x01 => 'All images are 256x256 pixels or smaller',
2210  0x02 => 'All images are 64x64 pixels or smaller',
2211  0x03 => 'All images are exactly 64x64 pixels, unless required otherwise',
2212  );
2213  return (isset($LookupExtendedHeaderRestrictionsImageSizeSize[$index]) ? $LookupExtendedHeaderRestrictionsImageSizeSize[$index] : '');
2214  }
+ Here is the caller graph for this function:

◆ LookupExtendedHeaderRestrictionsTagSizeLimits()

getid3_id3v2::LookupExtendedHeaderRestrictionsTagSizeLimits (   $index)

Definition at line 2170 of file module.tag.id3v2.php.

Referenced by Analyze().

2170  {
2171  static $LookupExtendedHeaderRestrictionsTagSizeLimits = array(
2172  0x00 => 'No more than 128 frames and 1 MB total tag size',
2173  0x01 => 'No more than 64 frames and 128 KB total tag size',
2174  0x02 => 'No more than 32 frames and 40 KB total tag size',
2175  0x03 => 'No more than 32 frames and 4 KB total tag size',
2176  );
2177  return (isset($LookupExtendedHeaderRestrictionsTagSizeLimits[$index]) ? $LookupExtendedHeaderRestrictionsTagSizeLimits[$index] : '');
2178  }
+ Here is the caller graph for this function:

◆ LookupExtendedHeaderRestrictionsTextEncodings()

getid3_id3v2::LookupExtendedHeaderRestrictionsTextEncodings (   $index)

Definition at line 2180 of file module.tag.id3v2.php.

Referenced by Analyze().

2180  {
2181  static $LookupExtendedHeaderRestrictionsTextEncodings = array(
2182  0x00 => 'No restrictions',
2183  0x01 => 'Strings are only encoded with ISO-8859-1 or UTF-8',
2184  );
2185  return (isset($LookupExtendedHeaderRestrictionsTextEncodings[$index]) ? $LookupExtendedHeaderRestrictionsTextEncodings[$index] : '');
2186  }
+ Here is the caller graph for this function:

◆ LookupExtendedHeaderRestrictionsTextFieldSize()

getid3_id3v2::LookupExtendedHeaderRestrictionsTextFieldSize (   $index)

Definition at line 2188 of file module.tag.id3v2.php.

Referenced by Analyze().

2188  {
2189  static $LookupExtendedHeaderRestrictionsTextFieldSize = array(
2190  0x00 => 'No restrictions',
2191  0x01 => 'No string is longer than 1024 characters',
2192  0x02 => 'No string is longer than 128 characters',
2193  0x03 => 'No string is longer than 30 characters',
2194  );
2195  return (isset($LookupExtendedHeaderRestrictionsTextFieldSize[$index]) ? $LookupExtendedHeaderRestrictionsTextFieldSize[$index] : '');
2196  }
+ Here is the caller graph for this function:

◆ ParseID3v2Frame() [1/2]

getid3_id3v2::ParseID3v2Frame ( $parsedFrame,
$ThisFileInfo 
)

Definition at line 465 of file module.tag.id3v2.php.

References APICPictureTypeLookup(), getid3_lib\BigEndian2Bin(), getid3_lib\BigEndian2Float(), getid3_lib\BigEndian2Int(), getid3_lib\Bin2Dec(), COMRReceivedAsLookup(), getid3_lib\Dec2Bin(), DeUnsynchronise(), ETCOEventLookup(), FrameNameLongLookup(), FrameNameShortLookup(), getid3_lib\GetDataImageSize(), getid3_lib\iconv_fallback(), IsValidDateStampString(), LanguageLookup(), LookupCurrencyUnits(), getid3_lib\RGADadjustmentLookup(), getid3_lib\RGADnameLookup(), getid3_lib\RGADoriginatorLookup(), RVA2ChannelTypeLookup(), SYTLContentTypeLookup(), TextEncodingNameLookup(), and TextEncodingTerminatorLookup().

Referenced by Analyze(), and getid3_id3v2().

465  {
466 
467  // shortcuts
468  $id3v2_majorversion = $ThisFileInfo['id3v2']['majorversion'];
469 
470  $parsedFrame['framenamelong'] = $this->FrameNameLongLookup($parsedFrame['frame_name']);
471  if (empty($parsedFrame['framenamelong'])) {
472  unset($parsedFrame['framenamelong']);
473  }
474  $parsedFrame['framenameshort'] = $this->FrameNameShortLookup($parsedFrame['frame_name']);
475  if (empty($parsedFrame['framenameshort'])) {
476  unset($parsedFrame['framenameshort']);
477  }
478 
479  if ($id3v2_majorversion >= 3) { // frame flags are not part of the ID3v2.2 standard
480  if ($id3v2_majorversion == 3) {
481  // Frame Header Flags
482  // %abc00000 %ijk00000
483  $parsedFrame['flags']['TagAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x8000); // a - Tag alter preservation
484  $parsedFrame['flags']['FileAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x4000); // b - File alter preservation
485  $parsedFrame['flags']['ReadOnly'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x2000); // c - Read only
486  $parsedFrame['flags']['compression'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0080); // i - Compression
487  $parsedFrame['flags']['Encryption'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0040); // j - Encryption
488  $parsedFrame['flags']['GroupingIdentity'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0020); // k - Grouping identity
489 
490  } elseif ($id3v2_majorversion == 4) {
491  // Frame Header Flags
492  // %0abc0000 %0h00kmnp
493  $parsedFrame['flags']['TagAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x4000); // a - Tag alter preservation
494  $parsedFrame['flags']['FileAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x2000); // b - File alter preservation
495  $parsedFrame['flags']['ReadOnly'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x1000); // c - Read only
496  $parsedFrame['flags']['GroupingIdentity'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0040); // h - Grouping identity
497  $parsedFrame['flags']['compression'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0008); // k - Compression
498  $parsedFrame['flags']['Encryption'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0004); // m - Encryption
499  $parsedFrame['flags']['Unsynchronisation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0002); // n - Unsynchronisation
500  $parsedFrame['flags']['DataLengthIndicator'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0001); // p - Data length indicator
501 
502  // Frame-level de-unsynchronisation - ID3v2.4
503  if ($parsedFrame['flags']['Unsynchronisation']) {
504  $parsedFrame['data'] = $this->DeUnsynchronise($parsedFrame['data']);
505  }
506  }
507 
508  // Frame-level de-compression
509  if ($parsedFrame['flags']['compression']) {
510  $parsedFrame['decompressed_size'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 0, 4));
511  if (!function_exists('gzuncompress')) {
512  $ThisFileInfo['warning'][] = 'gzuncompress() support required to decompress ID3v2 frame "'.$parsedFrame['frame_name'].'"';
513  } elseif ($decompresseddata = @gzuncompress(substr($parsedFrame['data'], 4))) {
514  $parsedFrame['data'] = $decompresseddata;
515  } else {
516  $ThisFileInfo['warning'][] = 'gzuncompress() failed on compressed contents of ID3v2 frame "'.$parsedFrame['frame_name'].'"';
517  }
518  }
519  }
520 
521  if (isset($parsedFrame['datalength']) && ($parsedFrame['datalength'] == 0)) {
522 
523  $warning = 'Frame "'.$parsedFrame['frame_name'].'" at offset '.$parsedFrame['dataoffset'].' has no data portion';
524  switch ($parsedFrame['frame_name']) {
525  case 'WCOM':
526  $warning .= ' (this is known to happen with files tagged by RioPort)';
527  break;
528 
529  default:
530  break;
531  }
532  $ThisFileInfo['warning'][] = $warning;
533 
534  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'UFID')) || // 4.1 UFID Unique file identifier
535  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'UFI'))) { // 4.1 UFI Unique file identifier
536  // There may be more than one 'UFID' frame in a tag,
537  // but only one with the same 'Owner identifier'.
538  // <Header for 'Unique file identifier', ID: 'UFID'>
539  // Owner identifier <text string> $00
540  // Identifier <up to 64 bytes binary data>
541 
542  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00");
543  $frame_idstring = substr($parsedFrame['data'], 0, $frame_terminatorpos);
544  $parsedFrame['ownerid'] = $frame_idstring;
545  $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen("\x00"));
546  unset($parsedFrame['data']);
547 
548 
549  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'TXXX')) || // 4.2.2 TXXX User defined text information frame
550  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'TXX'))) { // 4.2.2 TXX User defined text information frame
551  // There may be more than one 'TXXX' frame in each tag,
552  // but only one with the same description.
553  // <Header for 'User defined text information frame', ID: 'TXXX'>
554  // Text encoding $xx
555  // Description <text string according to encoding> $00 (00)
556  // Value <text string according to encoding>
557 
558  $frame_offset = 0;
559  $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
560 
561  if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
562  $ThisFileInfo['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
563  }
564  $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
565  if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
566  $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
567  }
568  $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
569  if (ord($frame_description) === 0) {
570  $frame_description = '';
571  }
572  $parsedFrame['encodingid'] = $frame_textencoding;
573  $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
574 
575  $parsedFrame['description'] = $frame_description;
576  $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
577  if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
578  $ThisFileInfo['id3v2']['comments'][$parsedFrame['framenameshort']][] = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $ThisFileInfo['id3v2']['encoding'], $parsedFrame['data']));
579  }
580  unset($parsedFrame['data']);
581 
582 
583  } elseif ($parsedFrame['frame_name']{0} == 'T') { // 4.2. T??[?] Text information frame
584  // There may only be one text information frame of its kind in an tag.
585  // <Header for 'Text information frame', ID: 'T000' - 'TZZZ',
586  // excluding 'TXXX' described in 4.2.6.>
587  // Text encoding $xx
588  // Information <text string(s) according to encoding>
589 
590  $frame_offset = 0;
591  $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
592  if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
593  $ThisFileInfo['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
594  }
595 
596  $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
597 
598  $parsedFrame['encodingid'] = $frame_textencoding;
599  $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
600 
601  if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
602  $ThisFileInfo['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $ThisFileInfo['id3v2']['encoding'], $parsedFrame['data']);
603  }
604 
605  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'WXXX')) || // 4.3.2 WXXX User defined URL link frame
606  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'WXX'))) { // 4.3.2 WXX User defined URL link frame
607  // There may be more than one 'WXXX' frame in each tag,
608  // but only one with the same description
609  // <Header for 'User defined URL link frame', ID: 'WXXX'>
610  // Text encoding $xx
611  // Description <text string according to encoding> $00 (00)
612  // URL <text string>
613 
614  $frame_offset = 0;
615  $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
616  if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
617  $ThisFileInfo['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
618  }
619  $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
620  if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
621  $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
622  }
623  $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
624 
625  if (ord($frame_description) === 0) {
626  $frame_description = '';
627  }
628  $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
629 
630  $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding));
631  if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
632  $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
633  }
634  if ($frame_terminatorpos) {
635  // there are null bytes after the data - this is not according to spec
636  // only use data up to first null byte
637  $frame_urldata = (string) substr($parsedFrame['data'], 0, $frame_terminatorpos);
638  } else {
639  // no null bytes following data, just use all data
640  $frame_urldata = (string) $parsedFrame['data'];
641  }
642 
643  $parsedFrame['encodingid'] = $frame_textencoding;
644  $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
645 
646  $parsedFrame['url'] = $frame_urldata;
647  $parsedFrame['description'] = $frame_description;
648  if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) {
649  $ThisFileInfo['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $ThisFileInfo['id3v2']['encoding'], $parsedFrame['url']);
650  }
651  unset($parsedFrame['data']);
652 
653 
654  } elseif ($parsedFrame['frame_name']{0} == 'W') { // 4.3. W??? URL link frames
655  // There may only be one URL link frame of its kind in a tag,
656  // except when stated otherwise in the frame description
657  // <Header for 'URL link frame', ID: 'W000' - 'WZZZ', excluding 'WXXX'
658  // described in 4.3.2.>
659  // URL <text string>
660 
661  $parsedFrame['url'] = trim($parsedFrame['data']);
662  if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) {
663  $ThisFileInfo['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['url'];
664  }
665  unset($parsedFrame['data']);
666 
667 
668  } elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'IPLS')) || // 4.4 IPLS Involved people list (ID3v2.3 only)
669  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'IPL'))) { // 4.4 IPL Involved people list (ID3v2.2 only)
670  // There may only be one 'IPL' frame in each tag
671  // <Header for 'User defined URL link frame', ID: 'IPL'>
672  // Text encoding $xx
673  // People list strings <textstrings>
674 
675  $frame_offset = 0;
676  $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
677  if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
678  $ThisFileInfo['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
679  }
680  $parsedFrame['encodingid'] = $frame_textencoding;
681  $parsedFrame['encoding'] = $this->TextEncodingNameLookup($parsedFrame['encodingid']);
682 
683  $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
684  if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
685  $ThisFileInfo['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $ThisFileInfo['id3v2']['encoding'], $parsedFrame['data']);
686  }
687 
688 
689  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'MCDI')) || // 4.4 MCDI Music CD identifier
690  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'MCI'))) { // 4.5 MCI Music CD identifier
691  // There may only be one 'MCDI' frame in each tag
692  // <Header for 'Music CD identifier', ID: 'MCDI'>
693  // CD TOC <binary data>
694 
695  if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
696  $ThisFileInfo['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['data'];
697  }
698 
699 
700  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'ETCO')) || // 4.5 ETCO Event timing codes
701  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'ETC'))) { // 4.6 ETC Event timing codes
702  // There may only be one 'ETCO' frame in each tag
703  // <Header for 'Event timing codes', ID: 'ETCO'>
704  // Time stamp format $xx
705  // Where time stamp format is:
706  // $01 (32-bit value) MPEG frames from beginning of file
707  // $02 (32-bit value) milliseconds from beginning of file
708  // Followed by a list of key events in the following format:
709  // Type of event $xx
710  // Time stamp $xx (xx ...)
711  // The 'Time stamp' is set to zero if directly at the beginning of the sound
712  // or after the previous event. All events MUST be sorted in chronological order.
713 
714  $frame_offset = 0;
715  $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
716 
717  while ($frame_offset < strlen($parsedFrame['data'])) {
718  $parsedFrame['typeid'] = substr($parsedFrame['data'], $frame_offset++, 1);
719  $parsedFrame['type'] = $this->ETCOEventLookup($parsedFrame['typeid']);
720  $parsedFrame['timestamp'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
721  $frame_offset += 4;
722  }
723  unset($parsedFrame['data']);
724 
725 
726  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'MLLT')) || // 4.6 MLLT MPEG location lookup table
727  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'MLL'))) { // 4.7 MLL MPEG location lookup table
728  // There may only be one 'MLLT' frame in each tag
729  // <Header for 'Location lookup table', ID: 'MLLT'>
730  // MPEG frames between reference $xx xx
731  // Bytes between reference $xx xx xx
732  // Milliseconds between reference $xx xx xx
733  // Bits for bytes deviation $xx
734  // Bits for milliseconds dev. $xx
735  // Then for every reference the following data is included;
736  // Deviation in bytes %xxx....
737  // Deviation in milliseconds %xxx....
738 
739  $frame_offset = 0;
740  $parsedFrame['framesbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 0, 2));
741  $parsedFrame['bytesbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 2, 3));
742  $parsedFrame['msbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 5, 3));
743  $parsedFrame['bitsforbytesdeviation'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 8, 1));
744  $parsedFrame['bitsformsdeviation'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 9, 1));
745  $parsedFrame['data'] = substr($parsedFrame['data'], 10);
746  while ($frame_offset < strlen($parsedFrame['data'])) {
747  $deviationbitstream .= getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1));
748  }
749  $reference_counter = 0;
750  while (strlen($deviationbitstream) > 0) {
751  $parsedFrame[$reference_counter]['bytedeviation'] = bindec(substr($deviationbitstream, 0, $parsedFrame['bitsforbytesdeviation']));
752  $parsedFrame[$reference_counter]['msdeviation'] = bindec(substr($deviationbitstream, $parsedFrame['bitsforbytesdeviation'], $parsedFrame['bitsformsdeviation']));
753  $deviationbitstream = substr($deviationbitstream, $parsedFrame['bitsforbytesdeviation'] + $parsedFrame['bitsformsdeviation']);
754  $reference_counter++;
755  }
756  unset($parsedFrame['data']);
757 
758 
759  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'SYTC')) || // 4.7 SYTC Synchronised tempo codes
760  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'STC'))) { // 4.8 STC Synchronised tempo codes
761  // There may only be one 'SYTC' frame in each tag
762  // <Header for 'Synchronised tempo codes', ID: 'SYTC'>
763  // Time stamp format $xx
764  // Tempo data <binary data>
765  // Where time stamp format is:
766  // $01 (32-bit value) MPEG frames from beginning of file
767  // $02 (32-bit value) milliseconds from beginning of file
768 
769  $frame_offset = 0;
770  $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
771  $timestamp_counter = 0;
772  while ($frame_offset < strlen($parsedFrame['data'])) {
773  $parsedFrame[$timestamp_counter]['tempo'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
774  if ($parsedFrame[$timestamp_counter]['tempo'] == 255) {
775  $parsedFrame[$timestamp_counter]['tempo'] += ord(substr($parsedFrame['data'], $frame_offset++, 1));
776  }
777  $parsedFrame[$timestamp_counter]['timestamp'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
778  $frame_offset += 4;
779  $timestamp_counter++;
780  }
781  unset($parsedFrame['data']);
782 
783 
784  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'USLT')) || // 4.8 USLT Unsynchronised lyric/text transcription
785  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'ULT'))) { // 4.9 ULT Unsynchronised lyric/text transcription
786  // There may be more than one 'Unsynchronised lyrics/text transcription' frame
787  // in each tag, but only one with the same language and content descriptor.
788  // <Header for 'Unsynchronised lyrics/text transcription', ID: 'USLT'>
789  // Text encoding $xx
790  // Language $xx xx xx
791  // Content descriptor <text string according to encoding> $00 (00)
792  // Lyrics/text <full text string according to encoding>
793 
794  $frame_offset = 0;
795  $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
796  if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
797  $ThisFileInfo['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
798  }
799  $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
800  $frame_offset += 3;
801  $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
802  if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
803  $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
804  }
805  $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
806  if (ord($frame_description) === 0) {
807  $frame_description = '';
808  }
809  $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
810 
811  $parsedFrame['encodingid'] = $frame_textencoding;
812  $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
813 
814  $parsedFrame['data'] = $parsedFrame['data'];
815  $parsedFrame['language'] = $frame_language;
816  $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
817  $parsedFrame['description'] = $frame_description;
818  if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
819  $ThisFileInfo['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $ThisFileInfo['id3v2']['encoding'], $parsedFrame['data']);
820  }
821  unset($parsedFrame['data']);
822 
823 
824  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'SYLT')) || // 4.9 SYLT Synchronised lyric/text
825  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'SLT'))) { // 4.10 SLT Synchronised lyric/text
826  // There may be more than one 'SYLT' frame in each tag,
827  // but only one with the same language and content descriptor.
828  // <Header for 'Synchronised lyrics/text', ID: 'SYLT'>
829  // Text encoding $xx
830  // Language $xx xx xx
831  // Time stamp format $xx
832  // $01 (32-bit value) MPEG frames from beginning of file
833  // $02 (32-bit value) milliseconds from beginning of file
834  // Content type $xx
835  // Content descriptor <text string according to encoding> $00 (00)
836  // Terminated text to be synced (typically a syllable)
837  // Sync identifier (terminator to above string) $00 (00)
838  // Time stamp $xx (xx ...)
839 
840  $frame_offset = 0;
841  $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
842  if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
843  $ThisFileInfo['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
844  }
845  $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
846  $frame_offset += 3;
847  $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
848  $parsedFrame['contenttypeid'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
849  $parsedFrame['contenttype'] = $this->SYTLContentTypeLookup($parsedFrame['contenttypeid']);
850  $parsedFrame['encodingid'] = $frame_textencoding;
851  $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
852 
853  $parsedFrame['language'] = $frame_language;
854  $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
855 
856  $timestampindex = 0;
857  $frame_remainingdata = substr($parsedFrame['data'], $frame_offset);
858  while (strlen($frame_remainingdata)) {
859  $frame_offset = 0;
860  $frame_terminatorpos = strpos($frame_remainingdata, $this->TextEncodingTerminatorLookup($frame_textencoding));
861  if ($frame_terminatorpos === false) {
862  $frame_remainingdata = '';
863  } else {
864  if (ord(substr($frame_remainingdata, $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
865  $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
866  }
867  $parsedFrame['lyrics'][$timestampindex]['data'] = substr($frame_remainingdata, $frame_offset, $frame_terminatorpos - $frame_offset);
868 
869  $frame_remainingdata = substr($frame_remainingdata, $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
870  if (($timestampindex == 0) && (ord($frame_remainingdata{0}) != 0)) {
871  // timestamp probably omitted for first data item
872  } else {
873  $parsedFrame['lyrics'][$timestampindex]['timestamp'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 0, 4));
874  $frame_remainingdata = substr($frame_remainingdata, 4);
875  }
876  $timestampindex++;
877  }
878  }
879  unset($parsedFrame['data']);
880 
881 
882  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'COMM')) || // 4.10 COMM Comments
883  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'COM'))) { // 4.11 COM Comments
884  // There may be more than one comment frame in each tag,
885  // but only one with the same language and content descriptor.
886  // <Header for 'Comment', ID: 'COMM'>
887  // Text encoding $xx
888  // Language $xx xx xx
889  // Short content descrip. <text string according to encoding> $00 (00)
890  // The actual text <full text string according to encoding>
891 
892  if (strlen($parsedFrame['data']) < 5) {
893 
894  $ThisFileInfo['warning'][] = 'Invalid data (too short) for "'.$parsedFrame['frame_name'].'" frame at offset '.$parsedFrame['dataoffset'];
895 
896  } else {
897 
898  $frame_offset = 0;
899  $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
900  if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
901  $ThisFileInfo['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
902  }
903  $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
904  $frame_offset += 3;
905  $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
906  if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
907  $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
908  }
909  $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
910  if (ord($frame_description) === 0) {
911  $frame_description = '';
912  }
913  $frame_text = (string) substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
914 
915  $parsedFrame['encodingid'] = $frame_textencoding;
916  $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
917 
918  $parsedFrame['language'] = $frame_language;
919  $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
920  $parsedFrame['description'] = $frame_description;
921  $parsedFrame['data'] = $frame_text;
922  if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
923  $ThisFileInfo['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $ThisFileInfo['id3v2']['encoding'], $parsedFrame['data']);
924  }
925 
926  }
927 
928  } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'RVA2')) { // 4.11 RVA2 Relative volume adjustment (2) (ID3v2.4+ only)
929  // There may be more than one 'RVA2' frame in each tag,
930  // but only one with the same identification string
931  // <Header for 'Relative volume adjustment (2)', ID: 'RVA2'>
932  // Identification <text string> $00
933  // The 'identification' string is used to identify the situation and/or
934  // device where this adjustment should apply. The following is then
935  // repeated for every channel:
936  // Type of channel $xx
937  // Volume adjustment $xx xx
938  // Bits representing peak $xx
939  // Peak volume $xx (xx ...)
940 
941  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00");
942  $frame_idstring = substr($parsedFrame['data'], 0, $frame_terminatorpos);
943  if (ord($frame_idstring) === 0) {
944  $frame_idstring = '';
945  }
946  $frame_remainingdata = substr($parsedFrame['data'], $frame_terminatorpos + strlen("\x00"));
947  $parsedFrame['description'] = $frame_idstring;
948  while (strlen($frame_remainingdata)) {
949  $frame_offset = 0;
950  $frame_channeltypeid = ord(substr($frame_remainingdata, $frame_offset++, 1));
951  $parsedFrame[$frame_channeltypeid]['channeltypeid'] = $frame_channeltypeid;
952  $parsedFrame[$frame_channeltypeid]['channeltype'] = $this->RVA2ChannelTypeLookup($frame_channeltypeid);
953  $parsedFrame[$frame_channeltypeid]['volumeadjust'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, $frame_offset, 2), false, true); // 16-bit signed
954  $frame_offset += 2;
955  $parsedFrame[$frame_channeltypeid]['bitspeakvolume'] = ord(substr($frame_remainingdata, $frame_offset++, 1));
956  $frame_bytespeakvolume = ceil($parsedFrame[$frame_channeltypeid]['bitspeakvolume'] / 8);
957  $parsedFrame[$frame_channeltypeid]['peakvolume'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, $frame_offset, $frame_bytespeakvolume));
958  $frame_remainingdata = substr($frame_remainingdata, $frame_offset + $frame_bytespeakvolume);
959  }
960  unset($parsedFrame['data']);
961 
962 
963  } elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'RVAD')) || // 4.12 RVAD Relative volume adjustment (ID3v2.3 only)
964  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'RVA'))) { // 4.12 RVA Relative volume adjustment (ID3v2.2 only)
965  // There may only be one 'RVA' frame in each tag
966  // <Header for 'Relative volume adjustment', ID: 'RVA'>
967  // ID3v2.2 => Increment/decrement %000000ba
968  // ID3v2.3 => Increment/decrement %00fedcba
969  // Bits used for volume descr. $xx
970  // Relative volume change, right $xx xx (xx ...) // a
971  // Relative volume change, left $xx xx (xx ...) // b
972  // Peak volume right $xx xx (xx ...)
973  // Peak volume left $xx xx (xx ...)
974  // ID3v2.3 only, optional (not present in ID3v2.2):
975  // Relative volume change, right back $xx xx (xx ...) // c
976  // Relative volume change, left back $xx xx (xx ...) // d
977  // Peak volume right back $xx xx (xx ...)
978  // Peak volume left back $xx xx (xx ...)
979  // ID3v2.3 only, optional (not present in ID3v2.2):
980  // Relative volume change, center $xx xx (xx ...) // e
981  // Peak volume center $xx xx (xx ...)
982  // ID3v2.3 only, optional (not present in ID3v2.2):
983  // Relative volume change, bass $xx xx (xx ...) // f
984  // Peak volume bass $xx xx (xx ...)
985 
986  $frame_offset = 0;
987  $frame_incrdecrflags = getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1));
988  $parsedFrame['incdec']['right'] = (bool) substr($frame_incrdecrflags, 6, 1);
989  $parsedFrame['incdec']['left'] = (bool) substr($frame_incrdecrflags, 7, 1);
990  $parsedFrame['bitsvolume'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
991  $frame_bytesvolume = ceil($parsedFrame['bitsvolume'] / 8);
992  $parsedFrame['volumechange']['right'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
993  if ($parsedFrame['incdec']['right'] === false) {
994  $parsedFrame['volumechange']['right'] *= -1;
995  }
996  $frame_offset += $frame_bytesvolume;
997  $parsedFrame['volumechange']['left'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
998  if ($parsedFrame['incdec']['left'] === false) {
999  $parsedFrame['volumechange']['left'] *= -1;
1000  }
1001  $frame_offset += $frame_bytesvolume;
1002  $parsedFrame['peakvolume']['right'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1003  $frame_offset += $frame_bytesvolume;
1004  $parsedFrame['peakvolume']['left'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1005  $frame_offset += $frame_bytesvolume;
1006  if ($id3v2_majorversion == 3) {
1007  $parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset);
1008  if (strlen($parsedFrame['data']) > 0) {
1009  $parsedFrame['incdec']['rightrear'] = (bool) substr($frame_incrdecrflags, 4, 1);
1010  $parsedFrame['incdec']['leftrear'] = (bool) substr($frame_incrdecrflags, 5, 1);
1011  $parsedFrame['volumechange']['rightrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1012  if ($parsedFrame['incdec']['rightrear'] === false) {
1013  $parsedFrame['volumechange']['rightrear'] *= -1;
1014  }
1015  $frame_offset += $frame_bytesvolume;
1016  $parsedFrame['volumechange']['leftrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1017  if ($parsedFrame['incdec']['leftrear'] === false) {
1018  $parsedFrame['volumechange']['leftrear'] *= -1;
1019  }
1020  $frame_offset += $frame_bytesvolume;
1021  $parsedFrame['peakvolume']['rightrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1022  $frame_offset += $frame_bytesvolume;
1023  $parsedFrame['peakvolume']['leftrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1024  $frame_offset += $frame_bytesvolume;
1025  }
1026  $parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset);
1027  if (strlen($parsedFrame['data']) > 0) {
1028  $parsedFrame['incdec']['center'] = (bool) substr($frame_incrdecrflags, 3, 1);
1029  $parsedFrame['volumechange']['center'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1030  if ($parsedFrame['incdec']['center'] === false) {
1031  $parsedFrame['volumechange']['center'] *= -1;
1032  }
1033  $frame_offset += $frame_bytesvolume;
1034  $parsedFrame['peakvolume']['center'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1035  $frame_offset += $frame_bytesvolume;
1036  }
1037  $parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset);
1038  if (strlen($parsedFrame['data']) > 0) {
1039  $parsedFrame['incdec']['bass'] = (bool) substr($frame_incrdecrflags, 2, 1);
1040  $parsedFrame['volumechange']['bass'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1041  if ($parsedFrame['incdec']['bass'] === false) {
1042  $parsedFrame['volumechange']['bass'] *= -1;
1043  }
1044  $frame_offset += $frame_bytesvolume;
1045  $parsedFrame['peakvolume']['bass'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1046  $frame_offset += $frame_bytesvolume;
1047  }
1048  }
1049  unset($parsedFrame['data']);
1050 
1051 
1052  } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'EQU2')) { // 4.12 EQU2 Equalisation (2) (ID3v2.4+ only)
1053  // There may be more than one 'EQU2' frame in each tag,
1054  // but only one with the same identification string
1055  // <Header of 'Equalisation (2)', ID: 'EQU2'>
1056  // Interpolation method $xx
1057  // $00 Band
1058  // $01 Linear
1059  // Identification <text string> $00
1060  // The following is then repeated for every adjustment point
1061  // Frequency $xx xx
1062  // Volume adjustment $xx xx
1063 
1064  $frame_offset = 0;
1065  $frame_interpolationmethod = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1066  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1067  $frame_idstring = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1068  if (ord($frame_idstring) === 0) {
1069  $frame_idstring = '';
1070  }
1071  $parsedFrame['description'] = $frame_idstring;
1072  $frame_remainingdata = substr($parsedFrame['data'], $frame_terminatorpos + strlen("\x00"));
1073  while (strlen($frame_remainingdata)) {
1074  $frame_frequency = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 0, 2)) / 2;
1075  $parsedFrame['data'][$frame_frequency] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 2, 2), false, true);
1076  $frame_remainingdata = substr($frame_remainingdata, 4);
1077  }
1078  $parsedFrame['interpolationmethod'] = $frame_interpolationmethod;
1079  unset($parsedFrame['data']);
1080 
1081 
1082  } elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'EQUA')) || // 4.12 EQUA Equalisation (ID3v2.3 only)
1083  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'EQU'))) { // 4.13 EQU Equalisation (ID3v2.2 only)
1084  // There may only be one 'EQUA' frame in each tag
1085  // <Header for 'Relative volume adjustment', ID: 'EQU'>
1086  // Adjustment bits $xx
1087  // This is followed by 2 bytes + ('adjustment bits' rounded up to the
1088  // nearest byte) for every equalisation band in the following format,
1089  // giving a frequency range of 0 - 32767Hz:
1090  // Increment/decrement %x (MSB of the Frequency)
1091  // Frequency (lower 15 bits)
1092  // Adjustment $xx (xx ...)
1093 
1094  $frame_offset = 0;
1095  $parsedFrame['adjustmentbits'] = substr($parsedFrame['data'], $frame_offset++, 1);
1096  $frame_adjustmentbytes = ceil($parsedFrame['adjustmentbits'] / 8);
1097 
1098  $frame_remainingdata = (string) substr($parsedFrame['data'], $frame_offset);
1099  while (strlen($frame_remainingdata) > 0) {
1100  $frame_frequencystr = getid3_lib::BigEndian2Bin(substr($frame_remainingdata, 0, 2));
1101  $frame_incdec = (bool) substr($frame_frequencystr, 0, 1);
1102  $frame_frequency = bindec(substr($frame_frequencystr, 1, 15));
1103  $parsedFrame[$frame_frequency]['incdec'] = $frame_incdec;
1104  $parsedFrame[$frame_frequency]['adjustment'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 2, $frame_adjustmentbytes));
1105  if ($parsedFrame[$frame_frequency]['incdec'] === false) {
1106  $parsedFrame[$frame_frequency]['adjustment'] *= -1;
1107  }
1108  $frame_remainingdata = substr($frame_remainingdata, 2 + $frame_adjustmentbytes);
1109  }
1110  unset($parsedFrame['data']);
1111 
1112 
1113  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RVRB')) || // 4.13 RVRB Reverb
1114  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'REV'))) { // 4.14 REV Reverb
1115  // There may only be one 'RVRB' frame in each tag.
1116  // <Header for 'Reverb', ID: 'RVRB'>
1117  // Reverb left (ms) $xx xx
1118  // Reverb right (ms) $xx xx
1119  // Reverb bounces, left $xx
1120  // Reverb bounces, right $xx
1121  // Reverb feedback, left to left $xx
1122  // Reverb feedback, left to right $xx
1123  // Reverb feedback, right to right $xx
1124  // Reverb feedback, right to left $xx
1125  // Premix left to right $xx
1126  // Premix right to left $xx
1127 
1128  $frame_offset = 0;
1129  $parsedFrame['left'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
1130  $frame_offset += 2;
1131  $parsedFrame['right'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
1132  $frame_offset += 2;
1133  $parsedFrame['bouncesL'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1134  $parsedFrame['bouncesR'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1135  $parsedFrame['feedbackLL'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1136  $parsedFrame['feedbackLR'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1137  $parsedFrame['feedbackRR'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1138  $parsedFrame['feedbackRL'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1139  $parsedFrame['premixLR'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1140  $parsedFrame['premixRL'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1141  unset($parsedFrame['data']);
1142 
1143 
1144  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'APIC')) || // 4.14 APIC Attached picture
1145  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'PIC'))) { // 4.15 PIC Attached picture
1146  // There may be several pictures attached to one file,
1147  // each in their individual 'APIC' frame, but only one
1148  // with the same content descriptor
1149  // <Header for 'Attached picture', ID: 'APIC'>
1150  // Text encoding $xx
1151  // ID3v2.3+ => MIME type <text string> $00
1152  // ID3v2.2 => Image format $xx xx xx
1153  // Picture type $xx
1154  // Description <text string according to encoding> $00 (00)
1155  // Picture data <binary data>
1156 
1157  $frame_offset = 0;
1158  $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1159  if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
1160  $ThisFileInfo['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
1161  }
1162 
1163  if ($id3v2_majorversion == 2) {
1164  $frame_imagetype = substr($parsedFrame['data'], $frame_offset, 3);
1165  if (strtolower($frame_imagetype) == 'ima') {
1166  // complete hack for mp3Rage (www.chaoticsoftware.com) that puts ID3v2.3-formatted
1167  // MIME type instead of 3-char ID3v2.2-format image type (thanks xbhoffØpacbell*net)
1168  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1169  $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1170  if (ord($frame_mimetype) === 0) {
1171  $frame_mimetype = '';
1172  }
1173  $frame_imagetype = strtoupper(str_replace('image/', '', strtolower($frame_mimetype)));
1174  if ($frame_imagetype == 'JPEG') {
1175  $frame_imagetype = 'JPG';
1176  }
1177  $frame_offset = $frame_terminatorpos + strlen("\x00");
1178  } else {
1179  $frame_offset += 3;
1180  }
1181  }
1182  if ($id3v2_majorversion > 2) {
1183  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1184  $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1185  if (ord($frame_mimetype) === 0) {
1186  $frame_mimetype = '';
1187  }
1188  $frame_offset = $frame_terminatorpos + strlen("\x00");
1189  }
1190 
1191  $frame_picturetype = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1192 
1193  $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
1194  if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
1195  $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
1196  }
1197  $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1198  if (ord($frame_description) === 0) {
1199  $frame_description = '';
1200  }
1201  $parsedFrame['encodingid'] = $frame_textencoding;
1202  $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
1203 
1204  if ($id3v2_majorversion == 2) {
1205  $parsedFrame['imagetype'] = $frame_imagetype;
1206  } else {
1207  $parsedFrame['mime'] = $frame_mimetype;
1208  }
1209  $parsedFrame['picturetypeid'] = $frame_picturetype;
1210  $parsedFrame['picturetype'] = $this->APICPictureTypeLookup($frame_picturetype);
1211  $parsedFrame['description'] = $frame_description;
1212  $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
1213 
1214  $imagechunkcheck = getid3_lib::GetDataImageSize($parsedFrame['data']);
1215  if (($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3)) {
1216  $parsedFrame['image_mime'] = 'image/'.getid3_lib::ImageTypesLookup($imagechunkcheck[2]);
1217  if ($imagechunkcheck[0]) {
1218  $parsedFrame['image_width'] = $imagechunkcheck[0];
1219  }
1220  if ($imagechunkcheck[1]) {
1221  $parsedFrame['image_height'] = $imagechunkcheck[1];
1222  }
1223  $parsedFrame['image_bytes'] = strlen($parsedFrame['data']);
1224  }
1225 
1226 
1227  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'GEOB')) || // 4.15 GEOB General encapsulated object
1228  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'GEO'))) { // 4.16 GEO General encapsulated object
1229  // There may be more than one 'GEOB' frame in each tag,
1230  // but only one with the same content descriptor
1231  // <Header for 'General encapsulated object', ID: 'GEOB'>
1232  // Text encoding $xx
1233  // MIME type <text string> $00
1234  // Filename <text string according to encoding> $00 (00)
1235  // Content description <text string according to encoding> $00 (00)
1236  // Encapsulated object <binary data>
1237 
1238  $frame_offset = 0;
1239  $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1240  if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
1241  $ThisFileInfo['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
1242  }
1243  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1244  $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1245  if (ord($frame_mimetype) === 0) {
1246  $frame_mimetype = '';
1247  }
1248  $frame_offset = $frame_terminatorpos + strlen("\x00");
1249 
1250  $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
1251  if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
1252  $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
1253  }
1254  $frame_filename = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1255  if (ord($frame_filename) === 0) {
1256  $frame_filename = '';
1257  }
1258  $frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding));
1259 
1260  $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
1261  if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
1262  $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
1263  }
1264  $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1265  if (ord($frame_description) === 0) {
1266  $frame_description = '';
1267  }
1268  $frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding));
1269 
1270  $parsedFrame['objectdata'] = (string) substr($parsedFrame['data'], $frame_offset);
1271  $parsedFrame['encodingid'] = $frame_textencoding;
1272  $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
1273 
1274  $parsedFrame['mime'] = $frame_mimetype;
1275  $parsedFrame['filename'] = $frame_filename;
1276  $parsedFrame['description'] = $frame_description;
1277  unset($parsedFrame['data']);
1278 
1279 
1280  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'PCNT')) || // 4.16 PCNT Play counter
1281  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CNT'))) { // 4.17 CNT Play counter
1282  // There may only be one 'PCNT' frame in each tag.
1283  // When the counter reaches all one's, one byte is inserted in
1284  // front of the counter thus making the counter eight bits bigger
1285  // <Header for 'Play counter', ID: 'PCNT'>
1286  // Counter $xx xx xx xx (xx ...)
1287 
1288  $parsedFrame['data'] = getid3_lib::BigEndian2Int($parsedFrame['data']);
1289 
1290 
1291  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'POPM')) || // 4.17 POPM Popularimeter
1292  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'POP'))) { // 4.18 POP Popularimeter
1293  // There may be more than one 'POPM' frame in each tag,
1294  // but only one with the same email address
1295  // <Header for 'Popularimeter', ID: 'POPM'>
1296  // Email to user <text string> $00
1297  // Rating $xx
1298  // Counter $xx xx xx xx (xx ...)
1299 
1300  $frame_offset = 0;
1301  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1302  $frame_emailaddress = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1303  if (ord($frame_emailaddress) === 0) {
1304  $frame_emailaddress = '';
1305  }
1306  $frame_offset = $frame_terminatorpos + strlen("\x00");
1307  $frame_rating = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1308  $parsedFrame['data'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset));
1309  $parsedFrame['email'] = $frame_emailaddress;
1310  $parsedFrame['rating'] = $frame_rating;
1311  unset($parsedFrame['data']);
1312 
1313 
1314  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RBUF')) || // 4.18 RBUF Recommended buffer size
1315  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'BUF'))) { // 4.19 BUF Recommended buffer size
1316  // There may only be one 'RBUF' frame in each tag
1317  // <Header for 'Recommended buffer size', ID: 'RBUF'>
1318  // Buffer size $xx xx xx
1319  // Embedded info flag %0000000x
1320  // Offset to next tag $xx xx xx xx
1321 
1322  $frame_offset = 0;
1323  $parsedFrame['buffersize'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 3));
1324  $frame_offset += 3;
1325 
1326  $frame_embeddedinfoflags = getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1));
1327  $parsedFrame['flags']['embededinfo'] = (bool) substr($frame_embeddedinfoflags, 7, 1);
1328  $parsedFrame['nexttagoffset'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
1329  unset($parsedFrame['data']);
1330 
1331 
1332  } elseif (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CRM')) { // 4.20 Encrypted meta frame (ID3v2.2 only)
1333  // There may be more than one 'CRM' frame in a tag,
1334  // but only one with the same 'owner identifier'
1335  // <Header for 'Encrypted meta frame', ID: 'CRM'>
1336  // Owner identifier <textstring> $00 (00)
1337  // Content/explanation <textstring> $00 (00)
1338  // Encrypted datablock <binary data>
1339 
1340  $frame_offset = 0;
1341  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1342  $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1343  $frame_offset = $frame_terminatorpos + strlen("\x00");
1344 
1345  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1346  $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1347  if (ord($frame_description) === 0) {
1348  $frame_description = '';
1349  }
1350  $frame_offset = $frame_terminatorpos + strlen("\x00");
1351 
1352  $parsedFrame['ownerid'] = $frame_ownerid;
1353  $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
1354  $parsedFrame['description'] = $frame_description;
1355  unset($parsedFrame['data']);
1356 
1357 
1358  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'AENC')) || // 4.19 AENC Audio encryption
1359  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CRA'))) { // 4.21 CRA Audio encryption
1360  // There may be more than one 'AENC' frames in a tag,
1361  // but only one with the same 'Owner identifier'
1362  // <Header for 'Audio encryption', ID: 'AENC'>
1363  // Owner identifier <text string> $00
1364  // Preview start $xx xx
1365  // Preview length $xx xx
1366  // Encryption info <binary data>
1367 
1368  $frame_offset = 0;
1369  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1370  $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1371  if (ord($frame_ownerid) === 0) {
1372  $frame_ownerid == '';
1373  }
1374  $frame_offset = $frame_terminatorpos + strlen("\x00");
1375  $parsedFrame['ownerid'] = $frame_ownerid;
1376  $parsedFrame['previewstart'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
1377  $frame_offset += 2;
1378  $parsedFrame['previewlength'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
1379  $frame_offset += 2;
1380  $parsedFrame['encryptioninfo'] = (string) substr($parsedFrame['data'], $frame_offset);
1381  unset($parsedFrame['data']);
1382 
1383 
1384  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'LINK')) || // 4.20 LINK Linked information
1385  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'LNK'))) { // 4.22 LNK Linked information
1386  // There may be more than one 'LINK' frame in a tag,
1387  // but only one with the same contents
1388  // <Header for 'Linked information', ID: 'LINK'>
1389  // ID3v2.3+ => Frame identifier $xx xx xx xx
1390  // ID3v2.2 => Frame identifier $xx xx xx
1391  // URL <text string> $00
1392  // ID and additional data <text string(s)>
1393 
1394  $frame_offset = 0;
1395  if ($id3v2_majorversion == 2) {
1396  $parsedFrame['frameid'] = substr($parsedFrame['data'], $frame_offset, 3);
1397  $frame_offset += 3;
1398  } else {
1399  $parsedFrame['frameid'] = substr($parsedFrame['data'], $frame_offset, 4);
1400  $frame_offset += 4;
1401  }
1402 
1403  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1404  $frame_url = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1405  if (ord($frame_url) === 0) {
1406  $frame_url = '';
1407  }
1408  $frame_offset = $frame_terminatorpos + strlen("\x00");
1409  $parsedFrame['url'] = $frame_url;
1410 
1411  $parsedFrame['additionaldata'] = (string) substr($parsedFrame['data'], $frame_offset);
1412  if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) {
1413  $ThisFileInfo['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $ThisFileInfo['id3v2']['encoding'], $parsedFrame['url']);
1414  }
1415  unset($parsedFrame['data']);
1416 
1417 
1418  } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'POSS')) { // 4.21 POSS Position synchronisation frame (ID3v2.3+ only)
1419  // There may only be one 'POSS' frame in each tag
1420  // <Head for 'Position synchronisation', ID: 'POSS'>
1421  // Time stamp format $xx
1422  // Position $xx (xx ...)
1423 
1424  $frame_offset = 0;
1425  $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1426  $parsedFrame['position'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset));
1427  unset($parsedFrame['data']);
1428 
1429 
1430  } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'USER')) { // 4.22 USER Terms of use (ID3v2.3+ only)
1431  // There may be more than one 'Terms of use' frame in a tag,
1432  // but only one with the same 'Language'
1433  // <Header for 'Terms of use frame', ID: 'USER'>
1434  // Text encoding $xx
1435  // Language $xx xx xx
1436  // The actual text <text string according to encoding>
1437 
1438  $frame_offset = 0;
1439  $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1440  if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
1441  $ThisFileInfo['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
1442  }
1443  $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
1444  $frame_offset += 3;
1445  $parsedFrame['language'] = $frame_language;
1446  $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
1447  $parsedFrame['encodingid'] = $frame_textencoding;
1448  $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
1449 
1450  $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
1451  if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
1452  $ThisFileInfo['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $ThisFileInfo['id3v2']['encoding'], $parsedFrame['data']);
1453  }
1454  unset($parsedFrame['data']);
1455 
1456 
1457  } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'OWNE')) { // 4.23 OWNE Ownership frame (ID3v2.3+ only)
1458  // There may only be one 'OWNE' frame in a tag
1459  // <Header for 'Ownership frame', ID: 'OWNE'>
1460  // Text encoding $xx
1461  // Price paid <text string> $00
1462  // Date of purch. <text string>
1463  // Seller <text string according to encoding>
1464 
1465  $frame_offset = 0;
1466  $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1467  if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
1468  $ThisFileInfo['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
1469  }
1470  $parsedFrame['encodingid'] = $frame_textencoding;
1471  $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
1472 
1473  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1474  $frame_pricepaid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1475  $frame_offset = $frame_terminatorpos + strlen("\x00");
1476 
1477  $parsedFrame['pricepaid']['currencyid'] = substr($frame_pricepaid, 0, 3);
1478  $parsedFrame['pricepaid']['currency'] = $this->LookupCurrencyUnits($parsedFrame['pricepaid']['currencyid']);
1479  $parsedFrame['pricepaid']['value'] = substr($frame_pricepaid, 3);
1480 
1481  $parsedFrame['purchasedate'] = substr($parsedFrame['data'], $frame_offset, 8);
1482  if (!$this->IsValidDateStampString($parsedFrame['purchasedate'])) {
1483  $parsedFrame['purchasedateunix'] = mktime (0, 0, 0, substr($parsedFrame['purchasedate'], 4, 2), substr($parsedFrame['purchasedate'], 6, 2), substr($parsedFrame['purchasedate'], 0, 4));
1484  }
1485  $frame_offset += 8;
1486 
1487  $parsedFrame['seller'] = (string) substr($parsedFrame['data'], $frame_offset);
1488  unset($parsedFrame['data']);
1489 
1490 
1491  } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'COMR')) { // 4.24 COMR Commercial frame (ID3v2.3+ only)
1492  // There may be more than one 'commercial frame' in a tag,
1493  // but no two may be identical
1494  // <Header for 'Commercial frame', ID: 'COMR'>
1495  // Text encoding $xx
1496  // Price string <text string> $00
1497  // Valid until <text string>
1498  // Contact URL <text string> $00
1499  // Received as $xx
1500  // Name of seller <text string according to encoding> $00 (00)
1501  // Description <text string according to encoding> $00 (00)
1502  // Picture MIME type <string> $00
1503  // Seller logo <binary data>
1504 
1505  $frame_offset = 0;
1506  $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1507  if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
1508  $ThisFileInfo['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
1509  }
1510 
1511  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1512  $frame_pricestring = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1513  $frame_offset = $frame_terminatorpos + strlen("\x00");
1514  $frame_rawpricearray = explode('/', $frame_pricestring);
1515  foreach ($frame_rawpricearray as $key => $val) {
1516  $frame_currencyid = substr($val, 0, 3);
1517  $parsedFrame['price'][$frame_currencyid]['currency'] = $this->LookupCurrencyUnits($frame_currencyid);
1518  $parsedFrame['price'][$frame_currencyid]['value'] = substr($val, 3);
1519  }
1520 
1521  $frame_datestring = substr($parsedFrame['data'], $frame_offset, 8);
1522  $frame_offset += 8;
1523 
1524  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1525  $frame_contacturl = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1526  $frame_offset = $frame_terminatorpos + strlen("\x00");
1527 
1528  $frame_receivedasid = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1529 
1530  $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
1531  if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
1532  $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
1533  }
1534  $frame_sellername = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1535  if (ord($frame_sellername) === 0) {
1536  $frame_sellername = '';
1537  }
1538  $frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding));
1539 
1540  $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
1541  if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
1542  $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
1543  }
1544  $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1545  if (ord($frame_description) === 0) {
1546  $frame_description = '';
1547  }
1548  $frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding));
1549 
1550  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1551  $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1552  $frame_offset = $frame_terminatorpos + strlen("\x00");
1553 
1554  $frame_sellerlogo = substr($parsedFrame['data'], $frame_offset);
1555 
1556  $parsedFrame['encodingid'] = $frame_textencoding;
1557  $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
1558 
1559  $parsedFrame['pricevaliduntil'] = $frame_datestring;
1560  $parsedFrame['contacturl'] = $frame_contacturl;
1561  $parsedFrame['receivedasid'] = $frame_receivedasid;
1562  $parsedFrame['receivedas'] = $this->COMRReceivedAsLookup($frame_receivedasid);
1563  $parsedFrame['sellername'] = $frame_sellername;
1564  $parsedFrame['description'] = $frame_description;
1565  $parsedFrame['mime'] = $frame_mimetype;
1566  $parsedFrame['logo'] = $frame_sellerlogo;
1567  unset($parsedFrame['data']);
1568 
1569 
1570  } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'ENCR')) { // 4.25 ENCR Encryption method registration (ID3v2.3+ only)
1571  // There may be several 'ENCR' frames in a tag,
1572  // but only one containing the same symbol
1573  // and only one containing the same owner identifier
1574  // <Header for 'Encryption method registration', ID: 'ENCR'>
1575  // Owner identifier <text string> $00
1576  // Method symbol $xx
1577  // Encryption data <binary data>
1578 
1579  $frame_offset = 0;
1580  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1581  $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1582  if (ord($frame_ownerid) === 0) {
1583  $frame_ownerid = '';
1584  }
1585  $frame_offset = $frame_terminatorpos + strlen("\x00");
1586 
1587  $parsedFrame['ownerid'] = $frame_ownerid;
1588  $parsedFrame['methodsymbol'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1589  $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
1590 
1591 
1592  } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'GRID')) { // 4.26 GRID Group identification registration (ID3v2.3+ only)
1593 
1594  // There may be several 'GRID' frames in a tag,
1595  // but only one containing the same symbol
1596  // and only one containing the same owner identifier
1597  // <Header for 'Group ID registration', ID: 'GRID'>
1598  // Owner identifier <text string> $00
1599  // Group symbol $xx
1600  // Group dependent data <binary data>
1601 
1602  $frame_offset = 0;
1603  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1604  $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1605  if (ord($frame_ownerid) === 0) {
1606  $frame_ownerid = '';
1607  }
1608  $frame_offset = $frame_terminatorpos + strlen("\x00");
1609 
1610  $parsedFrame['ownerid'] = $frame_ownerid;
1611  $parsedFrame['groupsymbol'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1612  $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
1613 
1614 
1615  } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'PRIV')) { // 4.27 PRIV Private frame (ID3v2.3+ only)
1616  // The tag may contain more than one 'PRIV' frame
1617  // but only with different contents
1618  // <Header for 'Private frame', ID: 'PRIV'>
1619  // Owner identifier <text string> $00
1620  // The private data <binary data>
1621 
1622  $frame_offset = 0;
1623  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1624  $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1625  if (ord($frame_ownerid) === 0) {
1626  $frame_ownerid = '';
1627  }
1628  $frame_offset = $frame_terminatorpos + strlen("\x00");
1629 
1630  $parsedFrame['ownerid'] = $frame_ownerid;
1631  $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
1632 
1633 
1634  } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'SIGN')) { // 4.28 SIGN Signature frame (ID3v2.4+ only)
1635  // There may be more than one 'signature frame' in a tag,
1636  // but no two may be identical
1637  // <Header for 'Signature frame', ID: 'SIGN'>
1638  // Group symbol $xx
1639  // Signature <binary data>
1640 
1641  $frame_offset = 0;
1642  $parsedFrame['groupsymbol'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1643  $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
1644 
1645 
1646  } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'SEEK')) { // 4.29 SEEK Seek frame (ID3v2.4+ only)
1647  // There may only be one 'seek frame' in a tag
1648  // <Header for 'Seek frame', ID: 'SEEK'>
1649  // Minimum offset to next tag $xx xx xx xx
1650 
1651  $frame_offset = 0;
1652  $parsedFrame['data'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
1653 
1654 
1655  } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'ASPI')) { // 4.30 ASPI Audio seek point index (ID3v2.4+ only)
1656  // There may only be one 'audio seek point index' frame in a tag
1657  // <Header for 'Seek Point Index', ID: 'ASPI'>
1658  // Indexed data start (S) $xx xx xx xx
1659  // Indexed data length (L) $xx xx xx xx
1660  // Number of index points (N) $xx xx
1661  // Bits per index point (b) $xx
1662  // Then for every index point the following data is included:
1663  // Fraction at index (Fi) $xx (xx)
1664 
1665  $frame_offset = 0;
1666  $parsedFrame['datastart'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
1667  $frame_offset += 4;
1668  $parsedFrame['indexeddatalength'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
1669  $frame_offset += 4;
1670  $parsedFrame['indexpoints'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
1671  $frame_offset += 2;
1672  $parsedFrame['bitsperpoint'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1673  $frame_bytesperpoint = ceil($parsedFrame['bitsperpoint'] / 8);
1674  for ($i = 0; $i < $frame_indexpoints; $i++) {
1675  $parsedFrame['indexes'][$i] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesperpoint));
1676  $frame_offset += $frame_bytesperpoint;
1677  }
1678  unset($parsedFrame['data']);
1679 
1680  } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RGAD')) { // Replay Gain Adjustment
1681  // http://privatewww.essex.ac.uk/~djmrob/replaygain/file_format_id3v2.html
1682  // There may only be one 'RGAD' frame in a tag
1683  // <Header for 'Replay Gain Adjustment', ID: 'RGAD'>
1684  // Peak Amplitude $xx $xx $xx $xx
1685  // Radio Replay Gain Adjustment %aaabbbcd %dddddddd
1686  // Audiophile Replay Gain Adjustment %aaabbbcd %dddddddd
1687  // a - name code
1688  // b - originator code
1689  // c - sign bit
1690  // d - replay gain adjustment
1691 
1692  $frame_offset = 0;
1693  $parsedFrame['peakamplitude'] = getid3_lib::BigEndian2Float(substr($parsedFrame['data'], $frame_offset, 4));
1694  $frame_offset += 4;
1695  $rg_track_adjustment = getid3_lib::Dec2Bin(substr($parsedFrame['data'], $frame_offset, 2));
1696  $frame_offset += 2;
1697  $rg_album_adjustment = getid3_lib::Dec2Bin(substr($parsedFrame['data'], $frame_offset, 2));
1698  $frame_offset += 2;
1699  $parsedFrame['raw']['track']['name'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 0, 3));
1700  $parsedFrame['raw']['track']['originator'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 3, 3));
1701  $parsedFrame['raw']['track']['signbit'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 6, 1));
1702  $parsedFrame['raw']['track']['adjustment'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 7, 9));
1703  $parsedFrame['raw']['album']['name'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 0, 3));
1704  $parsedFrame['raw']['album']['originator'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 3, 3));
1705  $parsedFrame['raw']['album']['signbit'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 6, 1));
1706  $parsedFrame['raw']['album']['adjustment'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 7, 9));
1707  $parsedFrame['track']['name'] = getid3_lib::RGADnameLookup($parsedFrame['raw']['track']['name']);
1708  $parsedFrame['track']['originator'] = getid3_lib::RGADoriginatorLookup($parsedFrame['raw']['track']['originator']);
1709  $parsedFrame['track']['adjustment'] = getid3_lib::RGADadjustmentLookup($parsedFrame['raw']['track']['adjustment'], $parsedFrame['raw']['track']['signbit']);
1710  $parsedFrame['album']['name'] = getid3_lib::RGADnameLookup($parsedFrame['raw']['album']['name']);
1711  $parsedFrame['album']['originator'] = getid3_lib::RGADoriginatorLookup($parsedFrame['raw']['album']['originator']);
1712  $parsedFrame['album']['adjustment'] = getid3_lib::RGADadjustmentLookup($parsedFrame['raw']['album']['adjustment'], $parsedFrame['raw']['album']['signbit']);
1713 
1714  $ThisFileInfo['replay_gain']['track']['peak'] = $parsedFrame['peakamplitude'];
1715  $ThisFileInfo['replay_gain']['track']['originator'] = $parsedFrame['track']['originator'];
1716  $ThisFileInfo['replay_gain']['track']['adjustment'] = $parsedFrame['track']['adjustment'];
1717  $ThisFileInfo['replay_gain']['album']['originator'] = $parsedFrame['album']['originator'];
1718  $ThisFileInfo['replay_gain']['album']['adjustment'] = $parsedFrame['album']['adjustment'];
1719 
1720  unset($parsedFrame['data']);
1721 
1722  }
1723 
1724  return true;
1725  }
LookupCurrencyUnits($currencyid)
LanguageLookup($languagecode, $casesensitive=false)
RGADadjustmentLookup($rawadjustment, $signbit)
Bin2Dec($binstring, $signed=false)
Definition: getid3.lib.php:316
FrameNameShortLookup($framename)
SYTLContentTypeLookup($index)
RGADnameLookup($namecode)
TextEncodingNameLookup($encoding)
GetDataImageSize($imgData)
TextEncodingTerminatorLookup($encoding)
iconv_fallback($in_charset, $out_charset, $string)
Definition: getid3.lib.php:951
RVA2ChannelTypeLookup($index)
FrameNameLongLookup($framename)
Dec2Bin($number)
Definition: getid3.lib.php:302
BigEndian2Int($byteword, $synchsafe=false, $signed=false)
Definition: getid3.lib.php:234
COMRReceivedAsLookup($index)
BigEndian2Float($byteword)
Definition: getid3.lib.php:159
RGADoriginatorLookup($originatorcode)
APICPictureTypeLookup($index, $returnarray=false)
BigEndian2Bin($byteword)
Definition: getid3.lib.php:271
IsValidDateStampString($datestamp)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ ParseID3v2Frame() [2/2]

getid3_id3v2::ParseID3v2Frame ( $parsedFrame)

Definition at line 532 of file module.tag.id3v2.php.

References $info, APICPictureTypeLookup(), getid3_lib\BigEndian2Bin(), getid3_lib\BigEndian2Float(), getid3_lib\BigEndian2Int(), getid3_lib\Bin2Dec(), COMRReceivedAsLookup(), getid3_lib\Dec2Bin(), DeUnsynchronise(), ETCOEventLookup(), FrameNameLongLookup(), FrameNameShortLookup(), getid3_lib\GetDataImageSize(), getid3_lib\iconv_fallback(), getid3_lib\iconv_fallback_iso88591_utf8(), IsValidDateStampString(), LanguageLookup(), LookupCurrencyUnits(), getid3_lib\RGADadjustmentLookup(), getid3_lib\RGADnameLookup(), getid3_lib\RGADoriginatorLookup(), RVA2ChannelTypeLookup(), SYTLContentTypeLookup(), TextEncodingNameLookup(), and TextEncodingTerminatorLookup().

532  {
533 
534  // shortcuts
535  $info = &$this->getid3->info;
536  $id3v2_majorversion = $info['id3v2']['majorversion'];
537 
538  $parsedFrame['framenamelong'] = $this->FrameNameLongLookup($parsedFrame['frame_name']);
539  if (empty($parsedFrame['framenamelong'])) {
540  unset($parsedFrame['framenamelong']);
541  }
542  $parsedFrame['framenameshort'] = $this->FrameNameShortLookup($parsedFrame['frame_name']);
543  if (empty($parsedFrame['framenameshort'])) {
544  unset($parsedFrame['framenameshort']);
545  }
546 
547  if ($id3v2_majorversion >= 3) { // frame flags are not part of the ID3v2.2 standard
548  if ($id3v2_majorversion == 3) {
549  // Frame Header Flags
550  // %abc00000 %ijk00000
551  $parsedFrame['flags']['TagAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x8000); // a - Tag alter preservation
552  $parsedFrame['flags']['FileAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x4000); // b - File alter preservation
553  $parsedFrame['flags']['ReadOnly'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x2000); // c - Read only
554  $parsedFrame['flags']['compression'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0080); // i - Compression
555  $parsedFrame['flags']['Encryption'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0040); // j - Encryption
556  $parsedFrame['flags']['GroupingIdentity'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0020); // k - Grouping identity
557 
558  } elseif ($id3v2_majorversion == 4) {
559  // Frame Header Flags
560  // %0abc0000 %0h00kmnp
561  $parsedFrame['flags']['TagAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x4000); // a - Tag alter preservation
562  $parsedFrame['flags']['FileAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x2000); // b - File alter preservation
563  $parsedFrame['flags']['ReadOnly'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x1000); // c - Read only
564  $parsedFrame['flags']['GroupingIdentity'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0040); // h - Grouping identity
565  $parsedFrame['flags']['compression'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0008); // k - Compression
566  $parsedFrame['flags']['Encryption'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0004); // m - Encryption
567  $parsedFrame['flags']['Unsynchronisation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0002); // n - Unsynchronisation
568  $parsedFrame['flags']['DataLengthIndicator'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0001); // p - Data length indicator
569 
570  // Frame-level de-unsynchronisation - ID3v2.4
571  if ($parsedFrame['flags']['Unsynchronisation']) {
572  $parsedFrame['data'] = $this->DeUnsynchronise($parsedFrame['data']);
573  }
574 
575  if ($parsedFrame['flags']['DataLengthIndicator']) {
576  $parsedFrame['data_length_indicator'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 0, 4), 1);
577  $parsedFrame['data'] = substr($parsedFrame['data'], 4);
578  }
579  }
580 
581  // Frame-level de-compression
582  if ($parsedFrame['flags']['compression']) {
583  $parsedFrame['decompressed_size'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 0, 4));
584  if (!function_exists('gzuncompress')) {
585  $info['warning'][] = 'gzuncompress() support required to decompress ID3v2 frame "'.$parsedFrame['frame_name'].'"';
586  } else {
587  if ($decompresseddata = @gzuncompress(substr($parsedFrame['data'], 4))) {
588  //if ($decompresseddata = @gzuncompress($parsedFrame['data'])) {
589  $parsedFrame['data'] = $decompresseddata;
590  unset($decompresseddata);
591  } else {
592  $info['warning'][] = 'gzuncompress() failed on compressed contents of ID3v2 frame "'.$parsedFrame['frame_name'].'"';
593  }
594  }
595  }
596  }
597 
598  if (!empty($parsedFrame['flags']['DataLengthIndicator'])) {
599  if ($parsedFrame['data_length_indicator'] != strlen($parsedFrame['data'])) {
600  $info['warning'][] = 'ID3v2 frame "'.$parsedFrame['frame_name'].'" should be '.$parsedFrame['data_length_indicator'].' bytes long according to DataLengthIndicator, but found '.strlen($parsedFrame['data']).' bytes of data';
601  }
602  }
603 
604  if (isset($parsedFrame['datalength']) && ($parsedFrame['datalength'] == 0)) {
605 
606  $warning = 'Frame "'.$parsedFrame['frame_name'].'" at offset '.$parsedFrame['dataoffset'].' has no data portion';
607  switch ($parsedFrame['frame_name']) {
608  case 'WCOM':
609  $warning .= ' (this is known to happen with files tagged by RioPort)';
610  break;
611 
612  default:
613  break;
614  }
615  $info['warning'][] = $warning;
616 
617  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'UFID')) || // 4.1 UFID Unique file identifier
618  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'UFI'))) { // 4.1 UFI Unique file identifier
619  // There may be more than one 'UFID' frame in a tag,
620  // but only one with the same 'Owner identifier'.
621  // <Header for 'Unique file identifier', ID: 'UFID'>
622  // Owner identifier <text string> $00
623  // Identifier <up to 64 bytes binary data>
624  $exploded = explode("\x00", $parsedFrame['data'], 2);
625  $parsedFrame['ownerid'] = (isset($exploded[0]) ? $exploded[0] : '');
626  $parsedFrame['data'] = (isset($exploded[1]) ? $exploded[1] : '');
627 
628  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'TXXX')) || // 4.2.2 TXXX User defined text information frame
629  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'TXX'))) { // 4.2.2 TXX User defined text information frame
630  // There may be more than one 'TXXX' frame in each tag,
631  // but only one with the same description.
632  // <Header for 'User defined text information frame', ID: 'TXXX'>
633  // Text encoding $xx
634  // Description <text string according to encoding> $00 (00)
635  // Value <text string according to encoding>
636 
637  $frame_offset = 0;
638  $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
639  $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
640  if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
641  $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
642  $frame_textencoding_terminator = "\x00";
643  }
644  $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
645  if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
646  $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
647  }
648  $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
649  if (ord($frame_description) === 0) {
650  $frame_description = '';
651  }
652  $parsedFrame['encodingid'] = $frame_textencoding;
653  $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
654 
655  $parsedFrame['description'] = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $frame_description));
656  $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
657  if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
658  $commentkey = ($parsedFrame['description'] ? $parsedFrame['description'] : (isset($info['id3v2']['comments'][$parsedFrame['framenameshort']]) ? count($info['id3v2']['comments'][$parsedFrame['framenameshort']]) : 0));
659  if (!isset($info['id3v2']['comments'][$parsedFrame['framenameshort']]) || !array_key_exists($commentkey, $info['id3v2']['comments'][$parsedFrame['framenameshort']])) {
660  $info['id3v2']['comments'][$parsedFrame['framenameshort']][$commentkey] = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']));
661  } else {
662  $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']));
663  }
664  }
665  //unset($parsedFrame['data']); do not unset, may be needed elsewhere, e.g. for replaygain
666 
667 
668  } elseif ($parsedFrame['frame_name']{0} == 'T') { // 4.2. T??[?] Text information frame
669  // There may only be one text information frame of its kind in an tag.
670  // <Header for 'Text information frame', ID: 'T000' - 'TZZZ',
671  // excluding 'TXXX' described in 4.2.6.>
672  // Text encoding $xx
673  // Information <text string(s) according to encoding>
674 
675  $frame_offset = 0;
676  $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
677  if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
678  $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
679  }
680 
681  $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
682 
683  $parsedFrame['encodingid'] = $frame_textencoding;
684  $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
685 
686  if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
687  // ID3v2.3 specs say that TPE1 (and others) can contain multiple artist values separated with /
688  // This of course breaks when an artist name contains slash character, e.g. "AC/DC"
689  // MP3tag (maybe others) implement alternative system where multiple artists are null-separated, which makes more sense
690  // getID3 will split null-separated artists into multiple artists and leave slash-separated ones to the user
691  switch ($parsedFrame['encoding']) {
692  case 'UTF-16':
693  case 'UTF-16BE':
694  case 'UTF-16LE':
695  $wordsize = 2;
696  break;
697  case 'ISO-8859-1':
698  case 'UTF-8':
699  default:
700  $wordsize = 1;
701  break;
702  }
703  $Txxx_elements = array();
704  $Txxx_elements_start_offset = 0;
705  for ($i = 0; $i < strlen($parsedFrame['data']); $i += $wordsize) {
706  if (substr($parsedFrame['data'], $i, $wordsize) == str_repeat("\x00", $wordsize)) {
707  $Txxx_elements[] = substr($parsedFrame['data'], $Txxx_elements_start_offset, $i - $Txxx_elements_start_offset);
708  $Txxx_elements_start_offset = $i + $wordsize;
709  }
710  }
711  $Txxx_elements[] = substr($parsedFrame['data'], $Txxx_elements_start_offset, $i - $Txxx_elements_start_offset);
712  foreach ($Txxx_elements as $Txxx_element) {
713  $string = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $Txxx_element);
714  if (!empty($string)) {
715  $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $string;
716  }
717  }
718  unset($string, $wordsize, $i, $Txxx_elements, $Txxx_element, $Txxx_elements_start_offset);
719  }
720 
721  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'WXXX')) || // 4.3.2 WXXX User defined URL link frame
722  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'WXX'))) { // 4.3.2 WXX User defined URL link frame
723  // There may be more than one 'WXXX' frame in each tag,
724  // but only one with the same description
725  // <Header for 'User defined URL link frame', ID: 'WXXX'>
726  // Text encoding $xx
727  // Description <text string according to encoding> $00 (00)
728  // URL <text string>
729 
730  $frame_offset = 0;
731  $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
732  $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
733  if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
734  $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
735  $frame_textencoding_terminator = "\x00";
736  }
737  $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
738  if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
739  $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
740  }
741  $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
742 
743  if (ord($frame_description) === 0) {
744  $frame_description = '';
745  }
746  $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
747 
748  $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator);
749  if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
750  $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
751  }
752  if ($frame_terminatorpos) {
753  // there are null bytes after the data - this is not according to spec
754  // only use data up to first null byte
755  $frame_urldata = (string) substr($parsedFrame['data'], 0, $frame_terminatorpos);
756  } else {
757  // no null bytes following data, just use all data
758  $frame_urldata = (string) $parsedFrame['data'];
759  }
760 
761  $parsedFrame['encodingid'] = $frame_textencoding;
762  $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
763 
764  $parsedFrame['url'] = $frame_urldata;
765  $parsedFrame['description'] = $frame_description;
766  if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) {
767  $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['url']);
768  }
769  unset($parsedFrame['data']);
770 
771 
772  } elseif ($parsedFrame['frame_name']{0} == 'W') { // 4.3. W??? URL link frames
773  // There may only be one URL link frame of its kind in a tag,
774  // except when stated otherwise in the frame description
775  // <Header for 'URL link frame', ID: 'W000' - 'WZZZ', excluding 'WXXX'
776  // described in 4.3.2.>
777  // URL <text string>
778 
779  $parsedFrame['url'] = trim($parsedFrame['data']);
780  if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) {
781  $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['url'];
782  }
783  unset($parsedFrame['data']);
784 
785 
786  } elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'IPLS')) || // 4.4 IPLS Involved people list (ID3v2.3 only)
787  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'IPL'))) { // 4.4 IPL Involved people list (ID3v2.2 only)
788  // http://id3.org/id3v2.3.0#sec4.4
789  // There may only be one 'IPL' frame in each tag
790  // <Header for 'User defined URL link frame', ID: 'IPL'>
791  // Text encoding $xx
792  // People list strings <textstrings>
793 
794  $frame_offset = 0;
795  $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
796  if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
797  $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
798  }
799  $parsedFrame['encodingid'] = $frame_textencoding;
800  $parsedFrame['encoding'] = $this->TextEncodingNameLookup($parsedFrame['encodingid']);
801  $parsedFrame['data_raw'] = (string) substr($parsedFrame['data'], $frame_offset);
802 
803  // http://www.getid3.org/phpBB3/viewtopic.php?t=1369
804  // "this tag typically contains null terminated strings, which are associated in pairs"
805  // "there are users that use the tag incorrectly"
806  $IPLS_parts = array();
807  if (strpos($parsedFrame['data_raw'], "\x00") !== false) {
808  $IPLS_parts_unsorted = array();
809  if (((strlen($parsedFrame['data_raw']) % 2) == 0) && ((substr($parsedFrame['data_raw'], 0, 2) == "\xFF\xFE") || (substr($parsedFrame['data_raw'], 0, 2) == "\xFE\xFF"))) {
810  // 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
811  $thisILPS = '';
812  for ($i = 0; $i < strlen($parsedFrame['data_raw']); $i += 2) {
813  $twobytes = substr($parsedFrame['data_raw'], $i, 2);
814  if ($twobytes === "\x00\x00") {
815  $IPLS_parts_unsorted[] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $thisILPS);
816  $thisILPS = '';
817  } else {
818  $thisILPS .= $twobytes;
819  }
820  }
821  if (strlen($thisILPS) > 2) { // 2-byte BOM
822  $IPLS_parts_unsorted[] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $thisILPS);
823  }
824  } else {
825  // ISO-8859-1 or UTF-8 or other single-byte-null character set
826  $IPLS_parts_unsorted = explode("\x00", $parsedFrame['data_raw']);
827  }
828  if (count($IPLS_parts_unsorted) == 1) {
829  // just a list of names, e.g. "Dino Baptiste, Jimmy Copley, John Gordon, Bernie Marsden, Sharon Watson"
830  foreach ($IPLS_parts_unsorted as $key => $value) {
831  $IPLS_parts_sorted = preg_split('#[;,\\r\\n\\t]#', $value);
832  $position = '';
833  foreach ($IPLS_parts_sorted as $person) {
834  $IPLS_parts[] = array('position'=>$position, 'person'=>$person);
835  }
836  }
837  } elseif ((count($IPLS_parts_unsorted) % 2) == 0) {
838  $position = '';
839  $person = '';
840  foreach ($IPLS_parts_unsorted as $key => $value) {
841  if (($key % 2) == 0) {
842  $position = $value;
843  } else {
844  $person = $value;
845  $IPLS_parts[] = array('position'=>$position, 'person'=>$person);
846  $position = '';
847  $person = '';
848  }
849  }
850  } else {
851  foreach ($IPLS_parts_unsorted as $key => $value) {
852  $IPLS_parts[] = array($value);
853  }
854  }
855 
856  } else {
857  $IPLS_parts = preg_split('#[;,\\r\\n\\t]#', $parsedFrame['data_raw']);
858  }
859  $parsedFrame['data'] = $IPLS_parts;
860 
861  if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
862  $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['data'];
863  }
864 
865 
866  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'MCDI')) || // 4.4 MCDI Music CD identifier
867  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'MCI'))) { // 4.5 MCI Music CD identifier
868  // There may only be one 'MCDI' frame in each tag
869  // <Header for 'Music CD identifier', ID: 'MCDI'>
870  // CD TOC <binary data>
871 
872  if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
873  $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['data'];
874  }
875 
876 
877  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'ETCO')) || // 4.5 ETCO Event timing codes
878  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'ETC'))) { // 4.6 ETC Event timing codes
879  // There may only be one 'ETCO' frame in each tag
880  // <Header for 'Event timing codes', ID: 'ETCO'>
881  // Time stamp format $xx
882  // Where time stamp format is:
883  // $01 (32-bit value) MPEG frames from beginning of file
884  // $02 (32-bit value) milliseconds from beginning of file
885  // Followed by a list of key events in the following format:
886  // Type of event $xx
887  // Time stamp $xx (xx ...)
888  // The 'Time stamp' is set to zero if directly at the beginning of the sound
889  // or after the previous event. All events MUST be sorted in chronological order.
890 
891  $frame_offset = 0;
892  $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
893 
894  while ($frame_offset < strlen($parsedFrame['data'])) {
895  $parsedFrame['typeid'] = substr($parsedFrame['data'], $frame_offset++, 1);
896  $parsedFrame['type'] = $this->ETCOEventLookup($parsedFrame['typeid']);
897  $parsedFrame['timestamp'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
898  $frame_offset += 4;
899  }
900  unset($parsedFrame['data']);
901 
902 
903  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'MLLT')) || // 4.6 MLLT MPEG location lookup table
904  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'MLL'))) { // 4.7 MLL MPEG location lookup table
905  // There may only be one 'MLLT' frame in each tag
906  // <Header for 'Location lookup table', ID: 'MLLT'>
907  // MPEG frames between reference $xx xx
908  // Bytes between reference $xx xx xx
909  // Milliseconds between reference $xx xx xx
910  // Bits for bytes deviation $xx
911  // Bits for milliseconds dev. $xx
912  // Then for every reference the following data is included;
913  // Deviation in bytes %xxx....
914  // Deviation in milliseconds %xxx....
915 
916  $frame_offset = 0;
917  $parsedFrame['framesbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 0, 2));
918  $parsedFrame['bytesbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 2, 3));
919  $parsedFrame['msbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 5, 3));
920  $parsedFrame['bitsforbytesdeviation'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 8, 1));
921  $parsedFrame['bitsformsdeviation'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 9, 1));
922  $parsedFrame['data'] = substr($parsedFrame['data'], 10);
923  while ($frame_offset < strlen($parsedFrame['data'])) {
924  $deviationbitstream .= getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1));
925  }
926  $reference_counter = 0;
927  while (strlen($deviationbitstream) > 0) {
928  $parsedFrame[$reference_counter]['bytedeviation'] = bindec(substr($deviationbitstream, 0, $parsedFrame['bitsforbytesdeviation']));
929  $parsedFrame[$reference_counter]['msdeviation'] = bindec(substr($deviationbitstream, $parsedFrame['bitsforbytesdeviation'], $parsedFrame['bitsformsdeviation']));
930  $deviationbitstream = substr($deviationbitstream, $parsedFrame['bitsforbytesdeviation'] + $parsedFrame['bitsformsdeviation']);
931  $reference_counter++;
932  }
933  unset($parsedFrame['data']);
934 
935 
936  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'SYTC')) || // 4.7 SYTC Synchronised tempo codes
937  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'STC'))) { // 4.8 STC Synchronised tempo codes
938  // There may only be one 'SYTC' frame in each tag
939  // <Header for 'Synchronised tempo codes', ID: 'SYTC'>
940  // Time stamp format $xx
941  // Tempo data <binary data>
942  // Where time stamp format is:
943  // $01 (32-bit value) MPEG frames from beginning of file
944  // $02 (32-bit value) milliseconds from beginning of file
945 
946  $frame_offset = 0;
947  $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
948  $timestamp_counter = 0;
949  while ($frame_offset < strlen($parsedFrame['data'])) {
950  $parsedFrame[$timestamp_counter]['tempo'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
951  if ($parsedFrame[$timestamp_counter]['tempo'] == 255) {
952  $parsedFrame[$timestamp_counter]['tempo'] += ord(substr($parsedFrame['data'], $frame_offset++, 1));
953  }
954  $parsedFrame[$timestamp_counter]['timestamp'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
955  $frame_offset += 4;
956  $timestamp_counter++;
957  }
958  unset($parsedFrame['data']);
959 
960 
961  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'USLT')) || // 4.8 USLT Unsynchronised lyric/text transcription
962  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'ULT'))) { // 4.9 ULT Unsynchronised lyric/text transcription
963  // There may be more than one 'Unsynchronised lyrics/text transcription' frame
964  // in each tag, but only one with the same language and content descriptor.
965  // <Header for 'Unsynchronised lyrics/text transcription', ID: 'USLT'>
966  // Text encoding $xx
967  // Language $xx xx xx
968  // Content descriptor <text string according to encoding> $00 (00)
969  // Lyrics/text <full text string according to encoding>
970 
971  $frame_offset = 0;
972  $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
973  $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
974  if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
975  $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
976  $frame_textencoding_terminator = "\x00";
977  }
978  $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
979  $frame_offset += 3;
980  $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
981  if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
982  $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
983  }
984  $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
985  if (ord($frame_description) === 0) {
986  $frame_description = '';
987  }
988  $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
989 
990  $parsedFrame['encodingid'] = $frame_textencoding;
991  $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
992 
993  $parsedFrame['language'] = $frame_language;
994  $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
995  $parsedFrame['description'] = $frame_description;
996  if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
997  $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
998  }
999  unset($parsedFrame['data']);
1000 
1001 
1002  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'SYLT')) || // 4.9 SYLT Synchronised lyric/text
1003  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'SLT'))) { // 4.10 SLT Synchronised lyric/text
1004  // There may be more than one 'SYLT' frame in each tag,
1005  // but only one with the same language and content descriptor.
1006  // <Header for 'Synchronised lyrics/text', ID: 'SYLT'>
1007  // Text encoding $xx
1008  // Language $xx xx xx
1009  // Time stamp format $xx
1010  // $01 (32-bit value) MPEG frames from beginning of file
1011  // $02 (32-bit value) milliseconds from beginning of file
1012  // Content type $xx
1013  // Content descriptor <text string according to encoding> $00 (00)
1014  // Terminated text to be synced (typically a syllable)
1015  // Sync identifier (terminator to above string) $00 (00)
1016  // Time stamp $xx (xx ...)
1017 
1018  $frame_offset = 0;
1019  $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1020  $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
1021  if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
1022  $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
1023  $frame_textencoding_terminator = "\x00";
1024  }
1025  $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
1026  $frame_offset += 3;
1027  $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1028  $parsedFrame['contenttypeid'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1029  $parsedFrame['contenttype'] = $this->SYTLContentTypeLookup($parsedFrame['contenttypeid']);
1030  $parsedFrame['encodingid'] = $frame_textencoding;
1031  $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
1032 
1033  $parsedFrame['language'] = $frame_language;
1034  $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
1035 
1036  $timestampindex = 0;
1037  $frame_remainingdata = substr($parsedFrame['data'], $frame_offset);
1038  while (strlen($frame_remainingdata)) {
1039  $frame_offset = 0;
1040  $frame_terminatorpos = strpos($frame_remainingdata, $frame_textencoding_terminator);
1041  if ($frame_terminatorpos === false) {
1042  $frame_remainingdata = '';
1043  } else {
1044  if (ord(substr($frame_remainingdata, $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
1045  $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
1046  }
1047  $parsedFrame['lyrics'][$timestampindex]['data'] = substr($frame_remainingdata, $frame_offset, $frame_terminatorpos - $frame_offset);
1048 
1049  $frame_remainingdata = substr($frame_remainingdata, $frame_terminatorpos + strlen($frame_textencoding_terminator));
1050  if (($timestampindex == 0) && (ord($frame_remainingdata{0}) != 0)) {
1051  // timestamp probably omitted for first data item
1052  } else {
1053  $parsedFrame['lyrics'][$timestampindex]['timestamp'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 0, 4));
1054  $frame_remainingdata = substr($frame_remainingdata, 4);
1055  }
1056  $timestampindex++;
1057  }
1058  }
1059  unset($parsedFrame['data']);
1060 
1061 
1062  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'COMM')) || // 4.10 COMM Comments
1063  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'COM'))) { // 4.11 COM Comments
1064  // There may be more than one comment frame in each tag,
1065  // but only one with the same language and content descriptor.
1066  // <Header for 'Comment', ID: 'COMM'>
1067  // Text encoding $xx
1068  // Language $xx xx xx
1069  // Short content descrip. <text string according to encoding> $00 (00)
1070  // The actual text <full text string according to encoding>
1071 
1072  if (strlen($parsedFrame['data']) < 5) {
1073 
1074  $info['warning'][] = 'Invalid data (too short) for "'.$parsedFrame['frame_name'].'" frame at offset '.$parsedFrame['dataoffset'];
1075 
1076  } else {
1077 
1078  $frame_offset = 0;
1079  $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1080  $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
1081  if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
1082  $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
1083  $frame_textencoding_terminator = "\x00";
1084  }
1085  $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
1086  $frame_offset += 3;
1087  $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
1088  if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
1089  $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
1090  }
1091  $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1092  if (ord($frame_description) === 0) {
1093  $frame_description = '';
1094  }
1095  $frame_text = (string) substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
1096 
1097  $parsedFrame['encodingid'] = $frame_textencoding;
1098  $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
1099 
1100  $parsedFrame['language'] = $frame_language;
1101  $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
1102  $parsedFrame['description'] = $frame_description;
1103  $parsedFrame['data'] = $frame_text;
1104  if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
1105  $commentkey = ($parsedFrame['description'] ? $parsedFrame['description'] : (!empty($info['id3v2']['comments'][$parsedFrame['framenameshort']]) ? count($info['id3v2']['comments'][$parsedFrame['framenameshort']]) : 0));
1106  if (!isset($info['id3v2']['comments'][$parsedFrame['framenameshort']]) || !array_key_exists($commentkey, $info['id3v2']['comments'][$parsedFrame['framenameshort']])) {
1107  $info['id3v2']['comments'][$parsedFrame['framenameshort']][$commentkey] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
1108  } else {
1109  $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
1110  }
1111  }
1112 
1113  }
1114 
1115  } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'RVA2')) { // 4.11 RVA2 Relative volume adjustment (2) (ID3v2.4+ only)
1116  // There may be more than one 'RVA2' frame in each tag,
1117  // but only one with the same identification string
1118  // <Header for 'Relative volume adjustment (2)', ID: 'RVA2'>
1119  // Identification <text string> $00
1120  // The 'identification' string is used to identify the situation and/or
1121  // device where this adjustment should apply. The following is then
1122  // repeated for every channel:
1123  // Type of channel $xx
1124  // Volume adjustment $xx xx
1125  // Bits representing peak $xx
1126  // Peak volume $xx (xx ...)
1127 
1128  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00");
1129  $frame_idstring = substr($parsedFrame['data'], 0, $frame_terminatorpos);
1130  if (ord($frame_idstring) === 0) {
1131  $frame_idstring = '';
1132  }
1133  $frame_remainingdata = substr($parsedFrame['data'], $frame_terminatorpos + strlen("\x00"));
1134  $parsedFrame['description'] = $frame_idstring;
1135  $RVA2channelcounter = 0;
1136  while (strlen($frame_remainingdata) >= 5) {
1137  $frame_offset = 0;
1138  $frame_channeltypeid = ord(substr($frame_remainingdata, $frame_offset++, 1));
1139  $parsedFrame[$RVA2channelcounter]['channeltypeid'] = $frame_channeltypeid;
1140  $parsedFrame[$RVA2channelcounter]['channeltype'] = $this->RVA2ChannelTypeLookup($frame_channeltypeid);
1141  $parsedFrame[$RVA2channelcounter]['volumeadjust'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, $frame_offset, 2), false, true); // 16-bit signed
1142  $frame_offset += 2;
1143  $parsedFrame[$RVA2channelcounter]['bitspeakvolume'] = ord(substr($frame_remainingdata, $frame_offset++, 1));
1144  if (($parsedFrame[$RVA2channelcounter]['bitspeakvolume'] < 1) || ($parsedFrame[$RVA2channelcounter]['bitspeakvolume'] > 4)) {
1145  $info['warning'][] = 'ID3v2::RVA2 frame['.$RVA2channelcounter.'] contains invalid '.$parsedFrame[$RVA2channelcounter]['bitspeakvolume'].'-byte bits-representing-peak value';
1146  break;
1147  }
1148  $frame_bytespeakvolume = ceil($parsedFrame[$RVA2channelcounter]['bitspeakvolume'] / 8);
1149  $parsedFrame[$RVA2channelcounter]['peakvolume'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, $frame_offset, $frame_bytespeakvolume));
1150  $frame_remainingdata = substr($frame_remainingdata, $frame_offset + $frame_bytespeakvolume);
1151  $RVA2channelcounter++;
1152  }
1153  unset($parsedFrame['data']);
1154 
1155 
1156  } elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'RVAD')) || // 4.12 RVAD Relative volume adjustment (ID3v2.3 only)
1157  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'RVA'))) { // 4.12 RVA Relative volume adjustment (ID3v2.2 only)
1158  // There may only be one 'RVA' frame in each tag
1159  // <Header for 'Relative volume adjustment', ID: 'RVA'>
1160  // ID3v2.2 => Increment/decrement %000000ba
1161  // ID3v2.3 => Increment/decrement %00fedcba
1162  // Bits used for volume descr. $xx
1163  // Relative volume change, right $xx xx (xx ...) // a
1164  // Relative volume change, left $xx xx (xx ...) // b
1165  // Peak volume right $xx xx (xx ...)
1166  // Peak volume left $xx xx (xx ...)
1167  // ID3v2.3 only, optional (not present in ID3v2.2):
1168  // Relative volume change, right back $xx xx (xx ...) // c
1169  // Relative volume change, left back $xx xx (xx ...) // d
1170  // Peak volume right back $xx xx (xx ...)
1171  // Peak volume left back $xx xx (xx ...)
1172  // ID3v2.3 only, optional (not present in ID3v2.2):
1173  // Relative volume change, center $xx xx (xx ...) // e
1174  // Peak volume center $xx xx (xx ...)
1175  // ID3v2.3 only, optional (not present in ID3v2.2):
1176  // Relative volume change, bass $xx xx (xx ...) // f
1177  // Peak volume bass $xx xx (xx ...)
1178 
1179  $frame_offset = 0;
1180  $frame_incrdecrflags = getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1));
1181  $parsedFrame['incdec']['right'] = (bool) substr($frame_incrdecrflags, 6, 1);
1182  $parsedFrame['incdec']['left'] = (bool) substr($frame_incrdecrflags, 7, 1);
1183  $parsedFrame['bitsvolume'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1184  $frame_bytesvolume = ceil($parsedFrame['bitsvolume'] / 8);
1185  $parsedFrame['volumechange']['right'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1186  if ($parsedFrame['incdec']['right'] === false) {
1187  $parsedFrame['volumechange']['right'] *= -1;
1188  }
1189  $frame_offset += $frame_bytesvolume;
1190  $parsedFrame['volumechange']['left'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1191  if ($parsedFrame['incdec']['left'] === false) {
1192  $parsedFrame['volumechange']['left'] *= -1;
1193  }
1194  $frame_offset += $frame_bytesvolume;
1195  $parsedFrame['peakvolume']['right'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1196  $frame_offset += $frame_bytesvolume;
1197  $parsedFrame['peakvolume']['left'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1198  $frame_offset += $frame_bytesvolume;
1199  if ($id3v2_majorversion == 3) {
1200  $parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset);
1201  if (strlen($parsedFrame['data']) > 0) {
1202  $parsedFrame['incdec']['rightrear'] = (bool) substr($frame_incrdecrflags, 4, 1);
1203  $parsedFrame['incdec']['leftrear'] = (bool) substr($frame_incrdecrflags, 5, 1);
1204  $parsedFrame['volumechange']['rightrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1205  if ($parsedFrame['incdec']['rightrear'] === false) {
1206  $parsedFrame['volumechange']['rightrear'] *= -1;
1207  }
1208  $frame_offset += $frame_bytesvolume;
1209  $parsedFrame['volumechange']['leftrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1210  if ($parsedFrame['incdec']['leftrear'] === false) {
1211  $parsedFrame['volumechange']['leftrear'] *= -1;
1212  }
1213  $frame_offset += $frame_bytesvolume;
1214  $parsedFrame['peakvolume']['rightrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1215  $frame_offset += $frame_bytesvolume;
1216  $parsedFrame['peakvolume']['leftrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1217  $frame_offset += $frame_bytesvolume;
1218  }
1219  $parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset);
1220  if (strlen($parsedFrame['data']) > 0) {
1221  $parsedFrame['incdec']['center'] = (bool) substr($frame_incrdecrflags, 3, 1);
1222  $parsedFrame['volumechange']['center'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1223  if ($parsedFrame['incdec']['center'] === false) {
1224  $parsedFrame['volumechange']['center'] *= -1;
1225  }
1226  $frame_offset += $frame_bytesvolume;
1227  $parsedFrame['peakvolume']['center'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1228  $frame_offset += $frame_bytesvolume;
1229  }
1230  $parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset);
1231  if (strlen($parsedFrame['data']) > 0) {
1232  $parsedFrame['incdec']['bass'] = (bool) substr($frame_incrdecrflags, 2, 1);
1233  $parsedFrame['volumechange']['bass'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1234  if ($parsedFrame['incdec']['bass'] === false) {
1235  $parsedFrame['volumechange']['bass'] *= -1;
1236  }
1237  $frame_offset += $frame_bytesvolume;
1238  $parsedFrame['peakvolume']['bass'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1239  $frame_offset += $frame_bytesvolume;
1240  }
1241  }
1242  unset($parsedFrame['data']);
1243 
1244 
1245  } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'EQU2')) { // 4.12 EQU2 Equalisation (2) (ID3v2.4+ only)
1246  // There may be more than one 'EQU2' frame in each tag,
1247  // but only one with the same identification string
1248  // <Header of 'Equalisation (2)', ID: 'EQU2'>
1249  // Interpolation method $xx
1250  // $00 Band
1251  // $01 Linear
1252  // Identification <text string> $00
1253  // The following is then repeated for every adjustment point
1254  // Frequency $xx xx
1255  // Volume adjustment $xx xx
1256 
1257  $frame_offset = 0;
1258  $frame_interpolationmethod = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1259  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1260  $frame_idstring = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1261  if (ord($frame_idstring) === 0) {
1262  $frame_idstring = '';
1263  }
1264  $parsedFrame['description'] = $frame_idstring;
1265  $frame_remainingdata = substr($parsedFrame['data'], $frame_terminatorpos + strlen("\x00"));
1266  while (strlen($frame_remainingdata)) {
1267  $frame_frequency = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 0, 2)) / 2;
1268  $parsedFrame['data'][$frame_frequency] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 2, 2), false, true);
1269  $frame_remainingdata = substr($frame_remainingdata, 4);
1270  }
1271  $parsedFrame['interpolationmethod'] = $frame_interpolationmethod;
1272  unset($parsedFrame['data']);
1273 
1274 
1275  } elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'EQUA')) || // 4.12 EQUA Equalisation (ID3v2.3 only)
1276  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'EQU'))) { // 4.13 EQU Equalisation (ID3v2.2 only)
1277  // There may only be one 'EQUA' frame in each tag
1278  // <Header for 'Relative volume adjustment', ID: 'EQU'>
1279  // Adjustment bits $xx
1280  // This is followed by 2 bytes + ('adjustment bits' rounded up to the
1281  // nearest byte) for every equalisation band in the following format,
1282  // giving a frequency range of 0 - 32767Hz:
1283  // Increment/decrement %x (MSB of the Frequency)
1284  // Frequency (lower 15 bits)
1285  // Adjustment $xx (xx ...)
1286 
1287  $frame_offset = 0;
1288  $parsedFrame['adjustmentbits'] = substr($parsedFrame['data'], $frame_offset++, 1);
1289  $frame_adjustmentbytes = ceil($parsedFrame['adjustmentbits'] / 8);
1290 
1291  $frame_remainingdata = (string) substr($parsedFrame['data'], $frame_offset);
1292  while (strlen($frame_remainingdata) > 0) {
1293  $frame_frequencystr = getid3_lib::BigEndian2Bin(substr($frame_remainingdata, 0, 2));
1294  $frame_incdec = (bool) substr($frame_frequencystr, 0, 1);
1295  $frame_frequency = bindec(substr($frame_frequencystr, 1, 15));
1296  $parsedFrame[$frame_frequency]['incdec'] = $frame_incdec;
1297  $parsedFrame[$frame_frequency]['adjustment'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 2, $frame_adjustmentbytes));
1298  if ($parsedFrame[$frame_frequency]['incdec'] === false) {
1299  $parsedFrame[$frame_frequency]['adjustment'] *= -1;
1300  }
1301  $frame_remainingdata = substr($frame_remainingdata, 2 + $frame_adjustmentbytes);
1302  }
1303  unset($parsedFrame['data']);
1304 
1305 
1306  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RVRB')) || // 4.13 RVRB Reverb
1307  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'REV'))) { // 4.14 REV Reverb
1308  // There may only be one 'RVRB' frame in each tag.
1309  // <Header for 'Reverb', ID: 'RVRB'>
1310  // Reverb left (ms) $xx xx
1311  // Reverb right (ms) $xx xx
1312  // Reverb bounces, left $xx
1313  // Reverb bounces, right $xx
1314  // Reverb feedback, left to left $xx
1315  // Reverb feedback, left to right $xx
1316  // Reverb feedback, right to right $xx
1317  // Reverb feedback, right to left $xx
1318  // Premix left to right $xx
1319  // Premix right to left $xx
1320 
1321  $frame_offset = 0;
1322  $parsedFrame['left'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
1323  $frame_offset += 2;
1324  $parsedFrame['right'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
1325  $frame_offset += 2;
1326  $parsedFrame['bouncesL'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1327  $parsedFrame['bouncesR'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1328  $parsedFrame['feedbackLL'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1329  $parsedFrame['feedbackLR'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1330  $parsedFrame['feedbackRR'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1331  $parsedFrame['feedbackRL'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1332  $parsedFrame['premixLR'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1333  $parsedFrame['premixRL'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1334  unset($parsedFrame['data']);
1335 
1336 
1337  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'APIC')) || // 4.14 APIC Attached picture
1338  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'PIC'))) { // 4.15 PIC Attached picture
1339  // There may be several pictures attached to one file,
1340  // each in their individual 'APIC' frame, but only one
1341  // with the same content descriptor
1342  // <Header for 'Attached picture', ID: 'APIC'>
1343  // Text encoding $xx
1344  // ID3v2.3+ => MIME type <text string> $00
1345  // ID3v2.2 => Image format $xx xx xx
1346  // Picture type $xx
1347  // Description <text string according to encoding> $00 (00)
1348  // Picture data <binary data>
1349 
1350  $frame_offset = 0;
1351  $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1352  $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
1353  if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
1354  $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
1355  $frame_textencoding_terminator = "\x00";
1356  }
1357 
1358  if ($id3v2_majorversion == 2 && strlen($parsedFrame['data']) > $frame_offset) {
1359  $frame_imagetype = substr($parsedFrame['data'], $frame_offset, 3);
1360  if (strtolower($frame_imagetype) == 'ima') {
1361  // complete hack for mp3Rage (www.chaoticsoftware.com) that puts ID3v2.3-formatted
1362  // MIME type instead of 3-char ID3v2.2-format image type (thanks xbhoffØpacbell*net)
1363  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1364  $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1365  if (ord($frame_mimetype) === 0) {
1366  $frame_mimetype = '';
1367  }
1368  $frame_imagetype = strtoupper(str_replace('image/', '', strtolower($frame_mimetype)));
1369  if ($frame_imagetype == 'JPEG') {
1370  $frame_imagetype = 'JPG';
1371  }
1372  $frame_offset = $frame_terminatorpos + strlen("\x00");
1373  } else {
1374  $frame_offset += 3;
1375  }
1376  }
1377  if ($id3v2_majorversion > 2 && strlen($parsedFrame['data']) > $frame_offset) {
1378  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1379  $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1380  if (ord($frame_mimetype) === 0) {
1381  $frame_mimetype = '';
1382  }
1383  $frame_offset = $frame_terminatorpos + strlen("\x00");
1384  }
1385 
1386  $frame_picturetype = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1387 
1388  if ($frame_offset >= $parsedFrame['datalength']) {
1389  $info['warning'][] = 'data portion of APIC frame is missing at offset '.($parsedFrame['dataoffset'] + 8 + $frame_offset);
1390  } else {
1391  $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
1392  if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
1393  $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
1394  }
1395  $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1396  if (ord($frame_description) === 0) {
1397  $frame_description = '';
1398  }
1399  $parsedFrame['encodingid'] = $frame_textencoding;
1400  $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
1401 
1402  if ($id3v2_majorversion == 2) {
1403  $parsedFrame['imagetype'] = $frame_imagetype;
1404  } else {
1405  $parsedFrame['mime'] = $frame_mimetype;
1406  }
1407  $parsedFrame['picturetypeid'] = $frame_picturetype;
1408  $parsedFrame['picturetype'] = $this->APICPictureTypeLookup($frame_picturetype);
1409  $parsedFrame['description'] = $frame_description;
1410  $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
1411  $parsedFrame['datalength'] = strlen($parsedFrame['data']);
1412 
1413  $parsedFrame['image_mime'] = '';
1414  $imageinfo = array();
1415  if ($imagechunkcheck = getid3_lib::GetDataImageSize($parsedFrame['data'], $imageinfo)) {
1416  if (($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3)) {
1417  $parsedFrame['image_mime'] = 'image/'.getid3_lib::ImageTypesLookup($imagechunkcheck[2]);
1418  if ($imagechunkcheck[0]) {
1419  $parsedFrame['image_width'] = $imagechunkcheck[0];
1420  }
1421  if ($imagechunkcheck[1]) {
1422  $parsedFrame['image_height'] = $imagechunkcheck[1];
1423  }
1424  }
1425  }
1426 
1427  do {
1428  if ($this->getid3->option_save_attachments === false) {
1429  // skip entirely
1430  unset($parsedFrame['data']);
1431  break;
1432  }
1433  if ($this->getid3->option_save_attachments === true) {
1434  // great
1435 /*
1436  } elseif (is_int($this->getid3->option_save_attachments)) {
1437  if ($this->getid3->option_save_attachments < $parsedFrame['data_length']) {
1438  // too big, skip
1439  $info['warning'][] = 'attachment at '.$frame_offset.' is too large to process inline ('.number_format($parsedFrame['data_length']).' bytes)';
1440  unset($parsedFrame['data']);
1441  break;
1442  }
1443 */
1444  } elseif (is_string($this->getid3->option_save_attachments)) {
1445  $dir = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->getid3->option_save_attachments), DIRECTORY_SEPARATOR);
1446  if (!is_dir($dir) || !is_writable($dir)) {
1447  // cannot write, skip
1448  $info['warning'][] = 'attachment at '.$frame_offset.' cannot be saved to "'.$dir.'" (not writable)';
1449  unset($parsedFrame['data']);
1450  break;
1451  }
1452  }
1453  // if we get this far, must be OK
1454  if (is_string($this->getid3->option_save_attachments)) {
1455  $destination_filename = $dir.DIRECTORY_SEPARATOR.md5($info['filenamepath']).'_'.$frame_offset;
1456  if (!file_exists($destination_filename) || is_writable($destination_filename)) {
1457  file_put_contents($destination_filename, $parsedFrame['data']);
1458  } else {
1459  $info['warning'][] = 'attachment at '.$frame_offset.' cannot be saved to "'.$destination_filename.'" (not writable)';
1460  }
1461  $parsedFrame['data_filename'] = $destination_filename;
1462  unset($parsedFrame['data']);
1463  } else {
1464  if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
1465  if (!isset($info['id3v2']['comments']['picture'])) {
1466  $info['id3v2']['comments']['picture'] = array();
1467  }
1468  $comments_picture_data = array();
1469  foreach (array('data', 'image_mime', 'image_width', 'image_height', 'imagetype', 'picturetype', 'description', 'datalength') as $picture_key) {
1470  if (isset($parsedFrame[$picture_key])) {
1471  $comments_picture_data[$picture_key] = $parsedFrame[$picture_key];
1472  }
1473  }
1474  $info['id3v2']['comments']['picture'][] = $comments_picture_data;
1475  unset($comments_picture_data);
1476  }
1477  }
1478  } while (false);
1479  }
1480 
1481  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'GEOB')) || // 4.15 GEOB General encapsulated object
1482  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'GEO'))) { // 4.16 GEO General encapsulated object
1483  // There may be more than one 'GEOB' frame in each tag,
1484  // but only one with the same content descriptor
1485  // <Header for 'General encapsulated object', ID: 'GEOB'>
1486  // Text encoding $xx
1487  // MIME type <text string> $00
1488  // Filename <text string according to encoding> $00 (00)
1489  // Content description <text string according to encoding> $00 (00)
1490  // Encapsulated object <binary data>
1491 
1492  $frame_offset = 0;
1493  $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1494  $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
1495  if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
1496  $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
1497  $frame_textencoding_terminator = "\x00";
1498  }
1499  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1500  $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1501  if (ord($frame_mimetype) === 0) {
1502  $frame_mimetype = '';
1503  }
1504  $frame_offset = $frame_terminatorpos + strlen("\x00");
1505 
1506  $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
1507  if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
1508  $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
1509  }
1510  $frame_filename = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1511  if (ord($frame_filename) === 0) {
1512  $frame_filename = '';
1513  }
1514  $frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator);
1515 
1516  $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
1517  if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
1518  $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
1519  }
1520  $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1521  if (ord($frame_description) === 0) {
1522  $frame_description = '';
1523  }
1524  $frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator);
1525 
1526  $parsedFrame['objectdata'] = (string) substr($parsedFrame['data'], $frame_offset);
1527  $parsedFrame['encodingid'] = $frame_textencoding;
1528  $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
1529 
1530  $parsedFrame['mime'] = $frame_mimetype;
1531  $parsedFrame['filename'] = $frame_filename;
1532  $parsedFrame['description'] = $frame_description;
1533  unset($parsedFrame['data']);
1534 
1535 
1536  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'PCNT')) || // 4.16 PCNT Play counter
1537  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CNT'))) { // 4.17 CNT Play counter
1538  // There may only be one 'PCNT' frame in each tag.
1539  // When the counter reaches all one's, one byte is inserted in
1540  // front of the counter thus making the counter eight bits bigger
1541  // <Header for 'Play counter', ID: 'PCNT'>
1542  // Counter $xx xx xx xx (xx ...)
1543 
1544  $parsedFrame['data'] = getid3_lib::BigEndian2Int($parsedFrame['data']);
1545 
1546 
1547  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'POPM')) || // 4.17 POPM Popularimeter
1548  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'POP'))) { // 4.18 POP Popularimeter
1549  // There may be more than one 'POPM' frame in each tag,
1550  // but only one with the same email address
1551  // <Header for 'Popularimeter', ID: 'POPM'>
1552  // Email to user <text string> $00
1553  // Rating $xx
1554  // Counter $xx xx xx xx (xx ...)
1555 
1556  $frame_offset = 0;
1557  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1558  $frame_emailaddress = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1559  if (ord($frame_emailaddress) === 0) {
1560  $frame_emailaddress = '';
1561  }
1562  $frame_offset = $frame_terminatorpos + strlen("\x00");
1563  $frame_rating = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1564  $parsedFrame['counter'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset));
1565  $parsedFrame['email'] = $frame_emailaddress;
1566  $parsedFrame['rating'] = $frame_rating;
1567  unset($parsedFrame['data']);
1568 
1569 
1570  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RBUF')) || // 4.18 RBUF Recommended buffer size
1571  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'BUF'))) { // 4.19 BUF Recommended buffer size
1572  // There may only be one 'RBUF' frame in each tag
1573  // <Header for 'Recommended buffer size', ID: 'RBUF'>
1574  // Buffer size $xx xx xx
1575  // Embedded info flag %0000000x
1576  // Offset to next tag $xx xx xx xx
1577 
1578  $frame_offset = 0;
1579  $parsedFrame['buffersize'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 3));
1580  $frame_offset += 3;
1581 
1582  $frame_embeddedinfoflags = getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1));
1583  $parsedFrame['flags']['embededinfo'] = (bool) substr($frame_embeddedinfoflags, 7, 1);
1584  $parsedFrame['nexttagoffset'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
1585  unset($parsedFrame['data']);
1586 
1587 
1588  } elseif (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CRM')) { // 4.20 Encrypted meta frame (ID3v2.2 only)
1589  // There may be more than one 'CRM' frame in a tag,
1590  // but only one with the same 'owner identifier'
1591  // <Header for 'Encrypted meta frame', ID: 'CRM'>
1592  // Owner identifier <textstring> $00 (00)
1593  // Content/explanation <textstring> $00 (00)
1594  // Encrypted datablock <binary data>
1595 
1596  $frame_offset = 0;
1597  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1598  $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1599  $frame_offset = $frame_terminatorpos + strlen("\x00");
1600 
1601  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1602  $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1603  if (ord($frame_description) === 0) {
1604  $frame_description = '';
1605  }
1606  $frame_offset = $frame_terminatorpos + strlen("\x00");
1607 
1608  $parsedFrame['ownerid'] = $frame_ownerid;
1609  $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
1610  $parsedFrame['description'] = $frame_description;
1611  unset($parsedFrame['data']);
1612 
1613 
1614  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'AENC')) || // 4.19 AENC Audio encryption
1615  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CRA'))) { // 4.21 CRA Audio encryption
1616  // There may be more than one 'AENC' frames in a tag,
1617  // but only one with the same 'Owner identifier'
1618  // <Header for 'Audio encryption', ID: 'AENC'>
1619  // Owner identifier <text string> $00
1620  // Preview start $xx xx
1621  // Preview length $xx xx
1622  // Encryption info <binary data>
1623 
1624  $frame_offset = 0;
1625  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1626  $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1627  if (ord($frame_ownerid) === 0) {
1628  $frame_ownerid == '';
1629  }
1630  $frame_offset = $frame_terminatorpos + strlen("\x00");
1631  $parsedFrame['ownerid'] = $frame_ownerid;
1632  $parsedFrame['previewstart'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
1633  $frame_offset += 2;
1634  $parsedFrame['previewlength'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
1635  $frame_offset += 2;
1636  $parsedFrame['encryptioninfo'] = (string) substr($parsedFrame['data'], $frame_offset);
1637  unset($parsedFrame['data']);
1638 
1639 
1640  } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'LINK')) || // 4.20 LINK Linked information
1641  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'LNK'))) { // 4.22 LNK Linked information
1642  // There may be more than one 'LINK' frame in a tag,
1643  // but only one with the same contents
1644  // <Header for 'Linked information', ID: 'LINK'>
1645  // ID3v2.3+ => Frame identifier $xx xx xx xx
1646  // ID3v2.2 => Frame identifier $xx xx xx
1647  // URL <text string> $00
1648  // ID and additional data <text string(s)>
1649 
1650  $frame_offset = 0;
1651  if ($id3v2_majorversion == 2) {
1652  $parsedFrame['frameid'] = substr($parsedFrame['data'], $frame_offset, 3);
1653  $frame_offset += 3;
1654  } else {
1655  $parsedFrame['frameid'] = substr($parsedFrame['data'], $frame_offset, 4);
1656  $frame_offset += 4;
1657  }
1658 
1659  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1660  $frame_url = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1661  if (ord($frame_url) === 0) {
1662  $frame_url = '';
1663  }
1664  $frame_offset = $frame_terminatorpos + strlen("\x00");
1665  $parsedFrame['url'] = $frame_url;
1666 
1667  $parsedFrame['additionaldata'] = (string) substr($parsedFrame['data'], $frame_offset);
1668  if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) {
1669  $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback_iso88591_utf8($parsedFrame['url']);
1670  }
1671  unset($parsedFrame['data']);
1672 
1673 
1674  } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'POSS')) { // 4.21 POSS Position synchronisation frame (ID3v2.3+ only)
1675  // There may only be one 'POSS' frame in each tag
1676  // <Head for 'Position synchronisation', ID: 'POSS'>
1677  // Time stamp format $xx
1678  // Position $xx (xx ...)
1679 
1680  $frame_offset = 0;
1681  $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1682  $parsedFrame['position'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset));
1683  unset($parsedFrame['data']);
1684 
1685 
1686  } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'USER')) { // 4.22 USER Terms of use (ID3v2.3+ only)
1687  // There may be more than one 'Terms of use' frame in a tag,
1688  // but only one with the same 'Language'
1689  // <Header for 'Terms of use frame', ID: 'USER'>
1690  // Text encoding $xx
1691  // Language $xx xx xx
1692  // The actual text <text string according to encoding>
1693 
1694  $frame_offset = 0;
1695  $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1696  if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
1697  $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
1698  }
1699  $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
1700  $frame_offset += 3;
1701  $parsedFrame['language'] = $frame_language;
1702  $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
1703  $parsedFrame['encodingid'] = $frame_textencoding;
1704  $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
1705 
1706  $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
1707  if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
1708  $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
1709  }
1710  unset($parsedFrame['data']);
1711 
1712 
1713  } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'OWNE')) { // 4.23 OWNE Ownership frame (ID3v2.3+ only)
1714  // There may only be one 'OWNE' frame in a tag
1715  // <Header for 'Ownership frame', ID: 'OWNE'>
1716  // Text encoding $xx
1717  // Price paid <text string> $00
1718  // Date of purch. <text string>
1719  // Seller <text string according to encoding>
1720 
1721  $frame_offset = 0;
1722  $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1723  if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
1724  $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
1725  }
1726  $parsedFrame['encodingid'] = $frame_textencoding;
1727  $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
1728 
1729  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1730  $frame_pricepaid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1731  $frame_offset = $frame_terminatorpos + strlen("\x00");
1732 
1733  $parsedFrame['pricepaid']['currencyid'] = substr($frame_pricepaid, 0, 3);
1734  $parsedFrame['pricepaid']['currency'] = $this->LookupCurrencyUnits($parsedFrame['pricepaid']['currencyid']);
1735  $parsedFrame['pricepaid']['value'] = substr($frame_pricepaid, 3);
1736 
1737  $parsedFrame['purchasedate'] = substr($parsedFrame['data'], $frame_offset, 8);
1738  if (!$this->IsValidDateStampString($parsedFrame['purchasedate'])) {
1739  $parsedFrame['purchasedateunix'] = mktime (0, 0, 0, substr($parsedFrame['purchasedate'], 4, 2), substr($parsedFrame['purchasedate'], 6, 2), substr($parsedFrame['purchasedate'], 0, 4));
1740  }
1741  $frame_offset += 8;
1742 
1743  $parsedFrame['seller'] = (string) substr($parsedFrame['data'], $frame_offset);
1744  unset($parsedFrame['data']);
1745 
1746 
1747  } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'COMR')) { // 4.24 COMR Commercial frame (ID3v2.3+ only)
1748  // There may be more than one 'commercial frame' in a tag,
1749  // but no two may be identical
1750  // <Header for 'Commercial frame', ID: 'COMR'>
1751  // Text encoding $xx
1752  // Price string <text string> $00
1753  // Valid until <text string>
1754  // Contact URL <text string> $00
1755  // Received as $xx
1756  // Name of seller <text string according to encoding> $00 (00)
1757  // Description <text string according to encoding> $00 (00)
1758  // Picture MIME type <string> $00
1759  // Seller logo <binary data>
1760 
1761  $frame_offset = 0;
1762  $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1763  $frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
1764  if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
1765  $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
1766  $frame_textencoding_terminator = "\x00";
1767  }
1768 
1769  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1770  $frame_pricestring = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1771  $frame_offset = $frame_terminatorpos + strlen("\x00");
1772  $frame_rawpricearray = explode('/', $frame_pricestring);
1773  foreach ($frame_rawpricearray as $key => $val) {
1774  $frame_currencyid = substr($val, 0, 3);
1775  $parsedFrame['price'][$frame_currencyid]['currency'] = $this->LookupCurrencyUnits($frame_currencyid);
1776  $parsedFrame['price'][$frame_currencyid]['value'] = substr($val, 3);
1777  }
1778 
1779  $frame_datestring = substr($parsedFrame['data'], $frame_offset, 8);
1780  $frame_offset += 8;
1781 
1782  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1783  $frame_contacturl = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1784  $frame_offset = $frame_terminatorpos + strlen("\x00");
1785 
1786  $frame_receivedasid = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1787 
1788  $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
1789  if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
1790  $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
1791  }
1792  $frame_sellername = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1793  if (ord($frame_sellername) === 0) {
1794  $frame_sellername = '';
1795  }
1796  $frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator);
1797 
1798  $frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
1799  if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
1800  $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
1801  }
1802  $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1803  if (ord($frame_description) === 0) {
1804  $frame_description = '';
1805  }
1806  $frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator);
1807 
1808  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1809  $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1810  $frame_offset = $frame_terminatorpos + strlen("\x00");
1811 
1812  $frame_sellerlogo = substr($parsedFrame['data'], $frame_offset);
1813 
1814  $parsedFrame['encodingid'] = $frame_textencoding;
1815  $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
1816 
1817  $parsedFrame['pricevaliduntil'] = $frame_datestring;
1818  $parsedFrame['contacturl'] = $frame_contacturl;
1819  $parsedFrame['receivedasid'] = $frame_receivedasid;
1820  $parsedFrame['receivedas'] = $this->COMRReceivedAsLookup($frame_receivedasid);
1821  $parsedFrame['sellername'] = $frame_sellername;
1822  $parsedFrame['description'] = $frame_description;
1823  $parsedFrame['mime'] = $frame_mimetype;
1824  $parsedFrame['logo'] = $frame_sellerlogo;
1825  unset($parsedFrame['data']);
1826 
1827 
1828  } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'ENCR')) { // 4.25 ENCR Encryption method registration (ID3v2.3+ only)
1829  // There may be several 'ENCR' frames in a tag,
1830  // but only one containing the same symbol
1831  // and only one containing the same owner identifier
1832  // <Header for 'Encryption method registration', ID: 'ENCR'>
1833  // Owner identifier <text string> $00
1834  // Method symbol $xx
1835  // Encryption data <binary data>
1836 
1837  $frame_offset = 0;
1838  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1839  $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1840  if (ord($frame_ownerid) === 0) {
1841  $frame_ownerid = '';
1842  }
1843  $frame_offset = $frame_terminatorpos + strlen("\x00");
1844 
1845  $parsedFrame['ownerid'] = $frame_ownerid;
1846  $parsedFrame['methodsymbol'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1847  $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
1848 
1849 
1850  } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'GRID')) { // 4.26 GRID Group identification registration (ID3v2.3+ only)
1851 
1852  // There may be several 'GRID' frames in a tag,
1853  // but only one containing the same symbol
1854  // and only one containing the same owner identifier
1855  // <Header for 'Group ID registration', ID: 'GRID'>
1856  // Owner identifier <text string> $00
1857  // Group symbol $xx
1858  // Group dependent data <binary data>
1859 
1860  $frame_offset = 0;
1861  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1862  $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1863  if (ord($frame_ownerid) === 0) {
1864  $frame_ownerid = '';
1865  }
1866  $frame_offset = $frame_terminatorpos + strlen("\x00");
1867 
1868  $parsedFrame['ownerid'] = $frame_ownerid;
1869  $parsedFrame['groupsymbol'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1870  $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
1871 
1872 
1873  } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'PRIV')) { // 4.27 PRIV Private frame (ID3v2.3+ only)
1874  // The tag may contain more than one 'PRIV' frame
1875  // but only with different contents
1876  // <Header for 'Private frame', ID: 'PRIV'>
1877  // Owner identifier <text string> $00
1878  // The private data <binary data>
1879 
1880  $frame_offset = 0;
1881  $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1882  $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1883  if (ord($frame_ownerid) === 0) {
1884  $frame_ownerid = '';
1885  }
1886  $frame_offset = $frame_terminatorpos + strlen("\x00");
1887 
1888  $parsedFrame['ownerid'] = $frame_ownerid;
1889  $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
1890 
1891 
1892  } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'SIGN')) { // 4.28 SIGN Signature frame (ID3v2.4+ only)
1893  // There may be more than one 'signature frame' in a tag,
1894  // but no two may be identical
1895  // <Header for 'Signature frame', ID: 'SIGN'>
1896  // Group symbol $xx
1897  // Signature <binary data>
1898 
1899  $frame_offset = 0;
1900  $parsedFrame['groupsymbol'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1901  $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
1902 
1903 
1904  } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'SEEK')) { // 4.29 SEEK Seek frame (ID3v2.4+ only)
1905  // There may only be one 'seek frame' in a tag
1906  // <Header for 'Seek frame', ID: 'SEEK'>
1907  // Minimum offset to next tag $xx xx xx xx
1908 
1909  $frame_offset = 0;
1910  $parsedFrame['data'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
1911 
1912 
1913  } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'ASPI')) { // 4.30 ASPI Audio seek point index (ID3v2.4+ only)
1914  // There may only be one 'audio seek point index' frame in a tag
1915  // <Header for 'Seek Point Index', ID: 'ASPI'>
1916  // Indexed data start (S) $xx xx xx xx
1917  // Indexed data length (L) $xx xx xx xx
1918  // Number of index points (N) $xx xx
1919  // Bits per index point (b) $xx
1920  // Then for every index point the following data is included:
1921  // Fraction at index (Fi) $xx (xx)
1922 
1923  $frame_offset = 0;
1924  $parsedFrame['datastart'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
1925  $frame_offset += 4;
1926  $parsedFrame['indexeddatalength'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
1927  $frame_offset += 4;
1928  $parsedFrame['indexpoints'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
1929  $frame_offset += 2;
1930  $parsedFrame['bitsperpoint'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1931  $frame_bytesperpoint = ceil($parsedFrame['bitsperpoint'] / 8);
1932  for ($i = 0; $i < $parsedFrame['indexpoints']; $i++) {
1933  $parsedFrame['indexes'][$i] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesperpoint));
1934  $frame_offset += $frame_bytesperpoint;
1935  }
1936  unset($parsedFrame['data']);
1937 
1938  } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RGAD')) { // Replay Gain Adjustment
1939  // http://privatewww.essex.ac.uk/~djmrob/replaygain/file_format_id3v2.html
1940  // There may only be one 'RGAD' frame in a tag
1941  // <Header for 'Replay Gain Adjustment', ID: 'RGAD'>
1942  // Peak Amplitude $xx $xx $xx $xx
1943  // Radio Replay Gain Adjustment %aaabbbcd %dddddddd
1944  // Audiophile Replay Gain Adjustment %aaabbbcd %dddddddd
1945  // a - name code
1946  // b - originator code
1947  // c - sign bit
1948  // d - replay gain adjustment
1949 
1950  $frame_offset = 0;
1951  $parsedFrame['peakamplitude'] = getid3_lib::BigEndian2Float(substr($parsedFrame['data'], $frame_offset, 4));
1952  $frame_offset += 4;
1953  $rg_track_adjustment = getid3_lib::Dec2Bin(substr($parsedFrame['data'], $frame_offset, 2));
1954  $frame_offset += 2;
1955  $rg_album_adjustment = getid3_lib::Dec2Bin(substr($parsedFrame['data'], $frame_offset, 2));
1956  $frame_offset += 2;
1957  $parsedFrame['raw']['track']['name'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 0, 3));
1958  $parsedFrame['raw']['track']['originator'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 3, 3));
1959  $parsedFrame['raw']['track']['signbit'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 6, 1));
1960  $parsedFrame['raw']['track']['adjustment'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 7, 9));
1961  $parsedFrame['raw']['album']['name'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 0, 3));
1962  $parsedFrame['raw']['album']['originator'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 3, 3));
1963  $parsedFrame['raw']['album']['signbit'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 6, 1));
1964  $parsedFrame['raw']['album']['adjustment'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 7, 9));
1965  $parsedFrame['track']['name'] = getid3_lib::RGADnameLookup($parsedFrame['raw']['track']['name']);
1966  $parsedFrame['track']['originator'] = getid3_lib::RGADoriginatorLookup($parsedFrame['raw']['track']['originator']);
1967  $parsedFrame['track']['adjustment'] = getid3_lib::RGADadjustmentLookup($parsedFrame['raw']['track']['adjustment'], $parsedFrame['raw']['track']['signbit']);
1968  $parsedFrame['album']['name'] = getid3_lib::RGADnameLookup($parsedFrame['raw']['album']['name']);
1969  $parsedFrame['album']['originator'] = getid3_lib::RGADoriginatorLookup($parsedFrame['raw']['album']['originator']);
1970  $parsedFrame['album']['adjustment'] = getid3_lib::RGADadjustmentLookup($parsedFrame['raw']['album']['adjustment'], $parsedFrame['raw']['album']['signbit']);
1971 
1972  $info['replay_gain']['track']['peak'] = $parsedFrame['peakamplitude'];
1973  $info['replay_gain']['track']['originator'] = $parsedFrame['track']['originator'];
1974  $info['replay_gain']['track']['adjustment'] = $parsedFrame['track']['adjustment'];
1975  $info['replay_gain']['album']['originator'] = $parsedFrame['album']['originator'];
1976  $info['replay_gain']['album']['adjustment'] = $parsedFrame['album']['adjustment'];
1977 
1978  unset($parsedFrame['data']);
1979 
1980  } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'CHAP')) { // CHAP Chapters frame (ID3v2.3+ only)
1981  // http://id3.org/id3v2-chapters-1.0
1982  // <ID3v2.3 or ID3v2.4 frame header, ID: "CHAP"> (10 bytes)
1983  // Element ID <text string> $00
1984  // Start time $xx xx xx xx
1985  // End time $xx xx xx xx
1986  // Start offset $xx xx xx xx
1987  // End offset $xx xx xx xx
1988  // <Optional embedded sub-frames>
1989 
1990  $frame_offset = 0;
1991  @list($parsedFrame['element_id']) = explode("\x00", $parsedFrame['data'], 2);
1992  $frame_offset += strlen($parsedFrame['element_id']."\x00");
1993  $parsedFrame['time_begin'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
1994  $frame_offset += 4;
1995  $parsedFrame['time_end'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
1996  $frame_offset += 4;
1997  if (substr($parsedFrame['data'], $frame_offset, 4) != "\xFF\xFF\xFF\xFF") {
1998  // "If these bytes are all set to 0xFF then the value should be ignored and the start time value should be utilized."
1999  $parsedFrame['offset_begin'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
2000  }
2001  $frame_offset += 4;
2002  if (substr($parsedFrame['data'], $frame_offset, 4) != "\xFF\xFF\xFF\xFF") {
2003  // "If these bytes are all set to 0xFF then the value should be ignored and the start time value should be utilized."
2004  $parsedFrame['offset_end'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
2005  }
2006  $frame_offset += 4;
2007 
2008  if ($frame_offset < strlen($parsedFrame['data'])) {
2009  $parsedFrame['subframes'] = array();
2010  while ($frame_offset < strlen($parsedFrame['data'])) {
2011  // <Optional embedded sub-frames>
2012  $subframe = array();
2013  $subframe['name'] = substr($parsedFrame['data'], $frame_offset, 4);
2014  $frame_offset += 4;
2015  $subframe['size'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
2016  $frame_offset += 4;
2017  $subframe['flags_raw'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
2018  $frame_offset += 2;
2019  if ($subframe['size'] > (strlen($parsedFrame['data']) - $frame_offset)) {
2020  $info['warning'][] = 'CHAP subframe "'.$subframe['name'].'" at frame offset '.$frame_offset.' claims to be "'.$subframe['size'].'" bytes, which is more than the available data ('.(strlen($parsedFrame['data']) - $frame_offset).' bytes)';
2021  break;
2022  }
2023  $subframe_rawdata = substr($parsedFrame['data'], $frame_offset, $subframe['size']);
2024  $frame_offset += $subframe['size'];
2025 
2026  $subframe['encodingid'] = ord(substr($subframe_rawdata, 0, 1));
2027  $subframe['text'] = substr($subframe_rawdata, 1);
2028  $subframe['encoding'] = $this->TextEncodingNameLookup($subframe['encodingid']);
2029  $encoding_converted_text = trim(getid3_lib::iconv_fallback($subframe['encoding'], $info['encoding'], $subframe['text']));;
2030  switch (substr($encoding_converted_text, 0, 2)) {
2031  case "\xFF\xFE":
2032  case "\xFE\xFF":
2033  switch (strtoupper($info['id3v2']['encoding'])) {
2034  case 'ISO-8859-1':
2035  case 'UTF-8':
2036  $encoding_converted_text = substr($encoding_converted_text, 2);
2037  // remove unwanted byte-order-marks
2038  break;
2039  default:
2040  // ignore
2041  break;
2042  }
2043  break;
2044  default:
2045  // do not remove BOM
2046  break;
2047  }
2048 
2049  if (($subframe['name'] == 'TIT2') || ($subframe['name'] == 'TIT3')) {
2050  if ($subframe['name'] == 'TIT2') {
2051  $parsedFrame['chapter_name'] = $encoding_converted_text;
2052  } elseif ($subframe['name'] == 'TIT3') {
2053  $parsedFrame['chapter_description'] = $encoding_converted_text;
2054  }
2055  $parsedFrame['subframes'][] = $subframe;
2056  } else {
2057  $info['warning'][] = 'ID3v2.CHAP subframe "'.$subframe['name'].'" not handled (only TIT2 and TIT3)';
2058  }
2059  }
2060  unset($subframe_rawdata, $subframe, $encoding_converted_text);
2061  }
2062 
2063  $id3v2_chapter_entry = array();
2064  foreach (array('id', 'time_begin', 'time_end', 'offset_begin', 'offset_end', 'chapter_name', 'chapter_description') as $id3v2_chapter_key) {
2065  if (isset($parsedFrame[$id3v2_chapter_key])) {
2066  $id3v2_chapter_entry[$id3v2_chapter_key] = $parsedFrame[$id3v2_chapter_key];
2067  }
2068  }
2069  if (!isset($info['id3v2']['chapters'])) {
2070  $info['id3v2']['chapters'] = array();
2071  }
2072  $info['id3v2']['chapters'][] = $id3v2_chapter_entry;
2073  unset($id3v2_chapter_entry, $id3v2_chapter_key);
2074 
2075 
2076  } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'CTOC')) { // CTOC Chapters Table Of Contents frame (ID3v2.3+ only)
2077  // http://id3.org/id3v2-chapters-1.0
2078  // <ID3v2.3 or ID3v2.4 frame header, ID: "CTOC"> (10 bytes)
2079  // Element ID <text string> $00
2080  // CTOC flags %xx
2081  // Entry count $xx
2082  // Child Element ID <string>$00 /* zero or more child CHAP or CTOC entries */
2083  // <Optional embedded sub-frames>
2084 
2085  $frame_offset = 0;
2086  @list($parsedFrame['element_id']) = explode("\x00", $parsedFrame['data'], 2);
2087  $frame_offset += strlen($parsedFrame['element_id']."\x00");
2088  $ctoc_flags_raw = ord(substr($parsedFrame['data'], $frame_offset, 1));
2089  $frame_offset += 1;
2090  $parsedFrame['entry_count'] = ord(substr($parsedFrame['data'], $frame_offset, 1));
2091  $frame_offset += 1;
2092 
2093  $terminator_position = null;
2094  for ($i = 0; $i < $parsedFrame['entry_count']; $i++) {
2095  $terminator_position = strpos($parsedFrame['data'], "\x00", $frame_offset);
2096  $parsedFrame['child_element_ids'][$i] = substr($parsedFrame['data'], $frame_offset, $terminator_position - $frame_offset);
2097  $frame_offset = $terminator_position + 1;
2098  }
2099 
2100  $parsedFrame['ctoc_flags']['ordered'] = (bool) ($ctoc_flags_raw & 0x01);
2101  $parsedFrame['ctoc_flags']['top_level'] = (bool) ($ctoc_flags_raw & 0x03);
2102 
2103  unset($ctoc_flags_raw, $terminator_position);
2104 
2105  if ($frame_offset < strlen($parsedFrame['data'])) {
2106  $parsedFrame['subframes'] = array();
2107  while ($frame_offset < strlen($parsedFrame['data'])) {
2108  // <Optional embedded sub-frames>
2109  $subframe = array();
2110  $subframe['name'] = substr($parsedFrame['data'], $frame_offset, 4);
2111  $frame_offset += 4;
2112  $subframe['size'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
2113  $frame_offset += 4;
2114  $subframe['flags_raw'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
2115  $frame_offset += 2;
2116  if ($subframe['size'] > (strlen($parsedFrame['data']) - $frame_offset)) {
2117  $info['warning'][] = 'CTOS subframe "'.$subframe['name'].'" at frame offset '.$frame_offset.' claims to be "'.$subframe['size'].'" bytes, which is more than the available data ('.(strlen($parsedFrame['data']) - $frame_offset).' bytes)';
2118  break;
2119  }
2120  $subframe_rawdata = substr($parsedFrame['data'], $frame_offset, $subframe['size']);
2121  $frame_offset += $subframe['size'];
2122 
2123  $subframe['encodingid'] = ord(substr($subframe_rawdata, 0, 1));
2124  $subframe['text'] = substr($subframe_rawdata, 1);
2125  $subframe['encoding'] = $this->TextEncodingNameLookup($subframe['encodingid']);
2126  $encoding_converted_text = trim(getid3_lib::iconv_fallback($subframe['encoding'], $info['encoding'], $subframe['text']));;
2127  switch (substr($encoding_converted_text, 0, 2)) {
2128  case "\xFF\xFE":
2129  case "\xFE\xFF":
2130  switch (strtoupper($info['id3v2']['encoding'])) {
2131  case 'ISO-8859-1':
2132  case 'UTF-8':
2133  $encoding_converted_text = substr($encoding_converted_text, 2);
2134  // remove unwanted byte-order-marks
2135  break;
2136  default:
2137  // ignore
2138  break;
2139  }
2140  break;
2141  default:
2142  // do not remove BOM
2143  break;
2144  }
2145 
2146  if (($subframe['name'] == 'TIT2') || ($subframe['name'] == 'TIT3')) {
2147  if ($subframe['name'] == 'TIT2') {
2148  $parsedFrame['toc_name'] = $encoding_converted_text;
2149  } elseif ($subframe['name'] == 'TIT3') {
2150  $parsedFrame['toc_description'] = $encoding_converted_text;
2151  }
2152  $parsedFrame['subframes'][] = $subframe;
2153  } else {
2154  $info['warning'][] = 'ID3v2.CTOC subframe "'.$subframe['name'].'" not handled (only TIT2 and TIT3)';
2155  }
2156  }
2157  unset($subframe_rawdata, $subframe, $encoding_converted_text);
2158  }
2159 
2160  }
2161 
2162  return true;
2163  }
LookupCurrencyUnits($currencyid)
LanguageLookup($languagecode, $casesensitive=false)
RGADadjustmentLookup($rawadjustment, $signbit)
Bin2Dec($binstring, $signed=false)
Definition: getid3.lib.php:316
FrameNameShortLookup($framename)
SYTLContentTypeLookup($index)
RGADnameLookup($namecode)
TextEncodingNameLookup($encoding)
GetDataImageSize($imgData)
$info
Definition: example_052.php:80
iconv_fallback_iso88591_utf8($string, $bom=false)
Definition: getid3.lib.php:693
TextEncodingTerminatorLookup($encoding)
iconv_fallback($in_charset, $out_charset, $string)
Definition: getid3.lib.php:951
RVA2ChannelTypeLookup($index)
FrameNameLongLookup($framename)
Dec2Bin($number)
Definition: getid3.lib.php:302
BigEndian2Int($byteword, $synchsafe=false, $signed=false)
Definition: getid3.lib.php:234
COMRReceivedAsLookup($index)
BigEndian2Float($byteword)
Definition: getid3.lib.php:159
RGADoriginatorLookup($originatorcode)
APICPictureTypeLookup($index, $returnarray=false)
BigEndian2Bin($byteword)
Definition: getid3.lib.php:271
IsValidDateStampString($datestamp)
+ Here is the call graph for this function:

◆ ParseID3v2GenreString() [1/2]

getid3_id3v2::ParseID3v2GenreString (   $genrestring)

Definition at line 406 of file module.tag.id3v2.php.

References getid3_id3v1\LookupGenreID(), and getid3_id3v1\LookupGenreName().

Referenced by Analyze(), and getid3_id3v2().

406  {
407  // Parse genres into arrays of genreName and genreID
408  // ID3v2.2.x, ID3v2.3.x: '(21)' or '(4)Eurodisco' or '(51)(39)' or '(55)((I think...)'
409  // ID3v2.4.x: '21' $00 'Eurodisco' $00
410 
411  $genrestring = trim($genrestring);
412  $returnarray = array();
413  if (strpos($genrestring, "\x00") !== false) {
414  $unprocessed = trim($genrestring); // trailing nulls will cause an infinite loop.
415  $genrestring = '';
416  while (strpos($unprocessed, "\x00") !== false) {
417  // convert null-seperated v2.4-format into v2.3 ()-seperated format
418  $endpos = strpos($unprocessed, "\x00");
419  $genrestring .= '('.substr($unprocessed, 0, $endpos).')';
420  $unprocessed = substr($unprocessed, $endpos + 1);
421  }
422  unset($unprocessed);
423  }
424  if (getid3_id3v1::LookupGenreID($genrestring)) {
425 
426  $returnarray['genre'][] = $genrestring;
427 
428  } else {
429 
430  while (strpos($genrestring, '(') !== false) {
431 
432  $startpos = strpos($genrestring, '(');
433  $endpos = strpos($genrestring, ')');
434  if (substr($genrestring, $startpos + 1, 1) == '(') {
435  $genrestring = substr($genrestring, 0, $startpos).substr($genrestring, $startpos + 1);
436  $endpos--;
437  }
438  $element = substr($genrestring, $startpos + 1, $endpos - ($startpos + 1));
439  $genrestring = substr($genrestring, 0, $startpos).substr($genrestring, $endpos + 1);
440  if (getid3_id3v1::LookupGenreName($element)) { // $element is a valid genre id/abbreviation
441 
442  if (empty($returnarray['genre']) || !in_array(getid3_id3v1::LookupGenreName($element), $returnarray['genre'])) { // avoid duplicate entires
443  $returnarray['genre'][] = getid3_id3v1::LookupGenreName($element);
444  }
445 
446  } else {
447 
448  if (empty($returnarray['genre']) || !in_array($element, $returnarray['genre'])) { // avoid duplicate entires
449  $returnarray['genre'][] = $element;
450  }
451 
452  }
453  }
454  }
455  if ($genrestring) {
456  if (empty($returnarray['genre']) || !in_array($genrestring, $returnarray['genre'])) { // avoid duplicate entires
457  $returnarray['genre'][] = $genrestring;
458  }
459  }
460 
461  return $returnarray;
462  }
LookupGenreID($genre, $allowSCMPXextended=false)
LookupGenreName($genreid, $allowSCMPXextended=true)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ ParseID3v2GenreString() [2/2]

getid3_id3v2::ParseID3v2GenreString (   $genrestring)

Definition at line 502 of file module.tag.id3v2.php.

References getid3_id3v1\LookupGenreName().

502  {
503  // Parse genres into arrays of genreName and genreID
504  // ID3v2.2.x, ID3v2.3.x: '(21)' or '(4)Eurodisco' or '(51)(39)' or '(55)((I think...)'
505  // ID3v2.4.x: '21' $00 'Eurodisco' $00
506  $clean_genres = array();
507  if (strpos($genrestring, "\x00") === false) {
508  $genrestring = preg_replace('#\(([0-9]{1,3})\)#', '$1'."\x00", $genrestring);
509  }
510 
511  // note: MusicBrainz Picard incorrectly stores plaintext genres separated by "/" when writing in ID3v2.3 mode, hack-fix here:
512  // replace / with NULL, then replace back the two ID3v1 genres that legitimately have "/" as part of the single genre name
513  $genrestring = str_replace('/', "\x00", $genrestring);
514  $genrestring = str_replace('Pop'."\x00".'Funk', 'Pop/Funk', $genrestring);
515  $genrestring = str_replace('Rock'."\x00".'Rock', 'Folk/Rock', $genrestring);
516 
517  $genre_elements = explode("\x00", $genrestring);
518  foreach ($genre_elements as $element) {
519  $element = trim($element);
520  if ($element) {
521  if (preg_match('#^[0-9]{1,3}#', $element)) {
522  $clean_genres[] = getid3_id3v1::LookupGenreName($element);
523  } else {
524  $clean_genres[] = str_replace('((', '(', $element);
525  }
526  }
527  }
528  return $clean_genres;
529  }
LookupGenreName($genreid, $allowSCMPXextended=true)
+ Here is the call graph for this function:

◆ RVA2ChannelTypeLookup() [1/2]

getid3_id3v2::RVA2ChannelTypeLookup (   $index)

Definition at line 2687 of file module.tag.id3v2.php.

Referenced by ParseID3v2Frame().

2687  {
2688  static $RVA2ChannelTypeLookup = array(
2689  0x00 => 'Other',
2690  0x01 => 'Master volume',
2691  0x02 => 'Front right',
2692  0x03 => 'Front left',
2693  0x04 => 'Back right',
2694  0x05 => 'Back left',
2695  0x06 => 'Front centre',
2696  0x07 => 'Back centre',
2697  0x08 => 'Subwoofer'
2698  );
2699 
2700  return (isset($RVA2ChannelTypeLookup[$index]) ? $RVA2ChannelTypeLookup[$index] : '');
2701  }
+ Here is the caller graph for this function:

◆ RVA2ChannelTypeLookup() [2/2]

static getid3_id3v2::RVA2ChannelTypeLookup (   $index)
static

Definition at line 3171 of file module.tag.id3v2.php.

3171  {
3172  static $RVA2ChannelTypeLookup = array(
3173  0x00 => 'Other',
3174  0x01 => 'Master volume',
3175  0x02 => 'Front right',
3176  0x03 => 'Front left',
3177  0x04 => 'Back right',
3178  0x05 => 'Back left',
3179  0x06 => 'Front centre',
3180  0x07 => 'Back centre',
3181  0x08 => 'Subwoofer'
3182  );
3183 
3184  return (isset($RVA2ChannelTypeLookup[$index]) ? $RVA2ChannelTypeLookup[$index] : '');
3185  }

◆ SYTLContentTypeLookup() [1/2]

getid3_id3v2::SYTLContentTypeLookup (   $index)

Definition at line 2625 of file module.tag.id3v2.php.

Referenced by ParseID3v2Frame().

2625  {
2626  static $SYTLContentTypeLookup = array(
2627  0x00 => 'other',
2628  0x01 => 'lyrics',
2629  0x02 => 'text transcription',
2630  0x03 => 'movement/part name', // (e.g. 'Adagio')
2631  0x04 => 'events', // (e.g. 'Don Quijote enters the stage')
2632  0x05 => 'chord', // (e.g. 'Bb F Fsus')
2633  0x06 => 'trivia/\'pop up\' information',
2634  0x07 => 'URLs to webpages',
2635  0x08 => 'URLs to images'
2636  );
2637 
2638  return (isset($SYTLContentTypeLookup[$index]) ? $SYTLContentTypeLookup[$index] : '');
2639  }
+ Here is the caller graph for this function:

◆ SYTLContentTypeLookup() [2/2]

static getid3_id3v2::SYTLContentTypeLookup (   $index)
static

Definition at line 3109 of file module.tag.id3v2.php.

3109  {
3110  static $SYTLContentTypeLookup = array(
3111  0x00 => 'other',
3112  0x01 => 'lyrics',
3113  0x02 => 'text transcription',
3114  0x03 => 'movement/part name', // (e.g. 'Adagio')
3115  0x04 => 'events', // (e.g. 'Don Quijote enters the stage')
3116  0x05 => 'chord', // (e.g. 'Bb F Fsus')
3117  0x06 => 'trivia/\'pop up\' information',
3118  0x07 => 'URLs to webpages',
3119  0x08 => 'URLs to images'
3120  );
3121 
3122  return (isset($SYTLContentTypeLookup[$index]) ? $SYTLContentTypeLookup[$index] : '');
3123  }

◆ TextEncodingNameLookup() [1/2]

getid3_id3v2::TextEncodingNameLookup (   $encoding)

Definition at line 3061 of file module.tag.id3v2.php.

Referenced by ParseID3v2Frame().

3061  {
3062  // http://www.id3.org/id3v2.4.0-structure.txt
3063  static $TextEncodingNameLookup = array(0=>'ISO-8859-1', 1=>'UTF-16', 2=>'UTF-16BE', 3=>'UTF-8', 255=>'UTF-16BE');
3064  return (isset($TextEncodingNameLookup[$encoding]) ? $TextEncodingNameLookup[$encoding] : 'ISO-8859-1');
3065  }
+ Here is the caller graph for this function:

◆ TextEncodingNameLookup() [2/2]

static getid3_id3v2::TextEncodingNameLookup (   $encoding)
static

Definition at line 3563 of file module.tag.id3v2.php.

3563  {
3564  // http://www.id3.org/id3v2.4.0-structure.txt
3565  // Frames that allow different types of text encoding contains a text encoding description byte. Possible encodings:
3566  static $TextEncodingNameLookup = array(
3567  0 => 'ISO-8859-1', // $00 ISO-8859-1. Terminated with $00.
3568  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.
3569  2 => 'UTF-16BE', // $02 UTF-16BE encoded Unicode without BOM. Terminated with $00 00.
3570  3 => 'UTF-8', // $03 UTF-8 encoded Unicode. Terminated with $00.
3571  255 => 'UTF-16BE'
3572  );
3573  return (isset($TextEncodingNameLookup[$encoding]) ? $TextEncodingNameLookup[$encoding] : 'ISO-8859-1');
3574  }

◆ TextEncodingTerminatorLookup() [1/2]

getid3_id3v2::TextEncodingTerminatorLookup (   $encoding)

Definition at line 3048 of file module.tag.id3v2.php.

Referenced by getid3_write_id3v2\GenerateID3v2FrameData(), and ParseID3v2Frame().

3048  {
3049  // http://www.id3.org/id3v2.4.0-structure.txt
3050  // Frames that allow different types of text encoding contains a text encoding description byte. Possible encodings:
3051  // $00 ISO-8859-1. Terminated with $00.
3052  // $01 UTF-16 encoded Unicode with BOM. All strings in the same frame SHALL have the same byteorder. Terminated with $00 00.
3053  // $02 UTF-16BE encoded Unicode without BOM. Terminated with $00 00.
3054  // $03 UTF-8 encoded Unicode. Terminated with $00.
3055 
3056  static $TextEncodingTerminatorLookup = array(0=>"\x00", 1=>"\x00\x00", 2=>"\x00\x00", 3=>"\x00", 255=>"\x00\x00");
3057 
3058  return @$TextEncodingTerminatorLookup[$encoding];
3059  }
+ Here is the caller graph for this function:

◆ TextEncodingTerminatorLookup() [2/2]

static getid3_id3v2::TextEncodingTerminatorLookup (   $encoding)
static

Definition at line 3550 of file module.tag.id3v2.php.

3550  {
3551  // http://www.id3.org/id3v2.4.0-structure.txt
3552  // Frames that allow different types of text encoding contains a text encoding description byte. Possible encodings:
3553  static $TextEncodingTerminatorLookup = array(
3554  0 => "\x00", // $00 ISO-8859-1. Terminated with $00.
3555  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.
3556  2 => "\x00\x00", // $02 UTF-16BE encoded Unicode without BOM. Terminated with $00 00.
3557  3 => "\x00", // $03 UTF-8 encoded Unicode. Terminated with $00.
3558  255 => "\x00\x00"
3559  );
3560  return (isset($TextEncodingTerminatorLookup[$encoding]) ? $TextEncodingTerminatorLookup[$encoding] : "\x00");
3561  }

Field Documentation

◆ $StartingOffset

getid3_id3v2::$StartingOffset = 0

Definition at line 21 of file module.tag.id3v2.php.

Referenced by Analyze(), and getid3_id3v2().


The documentation for this class was generated from the following file: