ILIAS  release_5-0 Revision 5.0.0-1144-gc4397b1f870
getid3_apetag Class Reference

getID3() by James Heinrich info@.nosp@m.geti.nosp@m.d3.or.nosp@m.g // More...

+ Collaboration diagram for getid3_apetag:

Public Member Functions

 getid3_apetag (&$fd, &$ThisFileInfo, $overrideendoffset=0)
 
 parseAPEheaderFooter ($APEheaderFooterData)
 
 parseAPEtagFlags ($rawflagint)
 
 APEcontentTypeFlagLookup ($contenttypeid)
 
 APEtagItemIsUTF8Lookup ($itemkey)
 

Detailed Description

getID3() by James Heinrich info@.nosp@m.geti.nosp@m.d3.or.nosp@m.g //

Definition at line 16 of file module.tag.apetag.php.

Member Function Documentation

◆ APEcontentTypeFlagLookup()

getid3_apetag::APEcontentTypeFlagLookup (   $contenttypeid)

Definition at line 243 of file module.tag.apetag.php.

Referenced by parseAPEtagFlags().

243  {
244  static $APEcontentTypeFlagLookup = array(
245  0 => 'utf-8',
246  1 => 'binary',
247  2 => 'external',
248  3 => 'reserved'
249  );
250  return (isset($APEcontentTypeFlagLookup[$contenttypeid]) ? $APEcontentTypeFlagLookup[$contenttypeid] : 'invalid');
251  }
+ Here is the caller graph for this function:

◆ APEtagItemIsUTF8Lookup()

getid3_apetag::APEtagItemIsUTF8Lookup (   $itemkey)

Definition at line 253 of file module.tag.apetag.php.

253  {
254  static $APEtagItemIsUTF8Lookup = array(
255  'title',
256  'subtitle',
257  'artist',
258  'album',
259  'debut album',
260  'publisher',
261  'conductor',
262  'track',
263  'composer',
264  'comment',
265  'copyright',
266  'publicationright',
267  'file',
268  'year',
269  'record date',
270  'record location',
271  'genre',
272  'media',
273  'related',
274  'isrc',
275  'abstract',
276  'language',
277  'bibliography'
278  );
279  return in_array(strtolower($itemkey), $APEtagItemIsUTF8Lookup);
280  }

◆ getid3_apetag()

getid3_apetag::getid3_apetag ( $fd,
$ThisFileInfo,
  $overrideendoffset = 0 
)

Definition at line 19 of file module.tag.apetag.php.

References $comment, getid3_lib\LittleEndian2Int(), parseAPEheaderFooter(), and parseAPEtagFlags().

19  {
20  $id3v1tagsize = 128;
21  $apetagheadersize = 32;
22  $lyrics3tagsize = 10;
23 
24  if ($overrideendoffset == 0) {
25 
26  fseek($fd, 0 - $id3v1tagsize - $apetagheadersize - $lyrics3tagsize, SEEK_END);
27  $APEfooterID3v1 = fread($fd, $id3v1tagsize + $apetagheadersize + $lyrics3tagsize);
28 
29  //if (preg_match('/APETAGEX.{24}TAG.{125}$/i', $APEfooterID3v1)) {
30  if (substr($APEfooterID3v1, strlen($APEfooterID3v1) - $id3v1tagsize - $apetagheadersize, 8) == 'APETAGEX') {
31 
32  // APE tag found before ID3v1
33  $ThisFileInfo['ape']['tag_offset_end'] = $ThisFileInfo['filesize'] - $id3v1tagsize;
34 
35  //} elseif (preg_match('/APETAGEX.{24}$/i', $APEfooterID3v1)) {
36  } elseif (substr($APEfooterID3v1, strlen($APEfooterID3v1) - $apetagheadersize, 8) == 'APETAGEX') {
37 
38  // APE tag found, no ID3v1
39  $ThisFileInfo['ape']['tag_offset_end'] = $ThisFileInfo['filesize'];
40 
41  }
42 
43  } else {
44 
45  fseek($fd, $overrideendoffset - $apetagheadersize, SEEK_SET);
46  if (fread($fd, 8) == 'APETAGEX') {
47  $ThisFileInfo['ape']['tag_offset_end'] = $overrideendoffset;
48  }
49 
50  }
51  if (!isset($ThisFileInfo['ape']['tag_offset_end'])) {
52 
53  // APE tag not found
54  unset($ThisFileInfo['ape']);
55  return false;
56 
57  }
58 
59  // shortcut
60  $thisfile_ape = &$ThisFileInfo['ape'];
61 
62  fseek($fd, $thisfile_ape['tag_offset_end'] - $apetagheadersize, SEEK_SET);
63  $APEfooterData = fread($fd, 32);
64  if (!($thisfile_ape['footer'] = $this->parseAPEheaderFooter($APEfooterData))) {
65  $ThisFileInfo['error'][] = 'Error parsing APE footer at offset '.$thisfile_ape['tag_offset_end'];
66  return false;
67  }
68 
69  if (isset($thisfile_ape['footer']['flags']['header']) && $thisfile_ape['footer']['flags']['header']) {
70  fseek($fd, $thisfile_ape['tag_offset_end'] - $thisfile_ape['footer']['raw']['tagsize'] - $apetagheadersize, SEEK_SET);
71  $thisfile_ape['tag_offset_start'] = ftell($fd);
72  $APEtagData = fread($fd, $thisfile_ape['footer']['raw']['tagsize'] + $apetagheadersize);
73  } else {
74  $thisfile_ape['tag_offset_start'] = $thisfile_ape['tag_offset_end'] - $thisfile_ape['footer']['raw']['tagsize'];
75  fseek($fd, $thisfile_ape['tag_offset_start'], SEEK_SET);
76  $APEtagData = fread($fd, $thisfile_ape['footer']['raw']['tagsize']);
77  }
78  $ThisFileInfo['avdataend'] = $thisfile_ape['tag_offset_start'];
79 
80  if (isset($ThisFileInfo['id3v1']['tag_offset_start']) && ($ThisFileInfo['id3v1']['tag_offset_start'] < $thisfile_ape['tag_offset_end'])) {
81  $ThisFileInfo['warning'][] = 'ID3v1 tag information ignored since it appears to be a false synch in APEtag data';
82  unset($ThisFileInfo['id3v1']);
83  foreach ($ThisFileInfo['warning'] as $key => $value) {
84  if ($value == 'Some ID3v1 fields do not use NULL characters for padding') {
85  unset($ThisFileInfo['warning'][$key]);
86  sort($ThisFileInfo['warning']);
87  break;
88  }
89  }
90  }
91 
92  $offset = 0;
93  if (isset($thisfile_ape['footer']['flags']['header']) && $thisfile_ape['footer']['flags']['header']) {
94  if ($thisfile_ape['header'] = $this->parseAPEheaderFooter(substr($APEtagData, 0, $apetagheadersize))) {
95  $offset += $apetagheadersize;
96  } else {
97  $ThisFileInfo['error'][] = 'Error parsing APE header at offset '.$thisfile_ape['tag_offset_start'];
98  return false;
99  }
100  }
101 
102  // shortcut
103  $ThisFileInfo['replay_gain'] = array();
104  $thisfile_replaygain = &$ThisFileInfo['replay_gain'];
105 
106  for ($i = 0; $i < $thisfile_ape['footer']['raw']['tag_items']; $i++) {
107  $value_size = getid3_lib::LittleEndian2Int(substr($APEtagData, $offset, 4));
108  $offset += 4;
109  $item_flags = getid3_lib::LittleEndian2Int(substr($APEtagData, $offset, 4));
110  $offset += 4;
111  if (strstr(substr($APEtagData, $offset), "\x00") === false) {
112  $ThisFileInfo['error'][] = 'Cannot find null-byte (0x00) seperator between ItemKey #'.$i.' and value. ItemKey starts '.$offset.' bytes into the APE tag, at file offset '.($thisfile_ape['tag_offset_start'] + $offset);
113  return false;
114  }
115  $ItemKeyLength = strpos($APEtagData, "\x00", $offset) - $offset;
116  $item_key = strtolower(substr($APEtagData, $offset, $ItemKeyLength));
117 
118  // shortcut
119  $thisfile_ape['items'][$item_key] = array();
120  $thisfile_ape_items_current = &$thisfile_ape['items'][$item_key];
121 
122  $offset += ($ItemKeyLength + 1); // skip 0x00 terminator
123  $thisfile_ape_items_current['data'] = substr($APEtagData, $offset, $value_size);
124  $offset += $value_size;
125 
126  $thisfile_ape_items_current['flags'] = $this->parseAPEtagFlags($item_flags);
127  switch ($thisfile_ape_items_current['flags']['item_contents_raw']) {
128  case 0: // UTF-8
129  case 3: // Locator (URL, filename, etc), UTF-8 encoded
130  $thisfile_ape_items_current['data'] = explode("\x00", trim($thisfile_ape_items_current['data']));
131  break;
132 
133  default: // binary data
134  break;
135  }
136 
137  switch (strtolower($item_key)) {
138  case 'replaygain_track_gain':
139  $thisfile_replaygain['track']['adjustment'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
140  $thisfile_replaygain['track']['originator'] = 'unspecified';
141  break;
142 
143  case 'replaygain_track_peak':
144  $thisfile_replaygain['track']['peak'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
145  $thisfile_replaygain['track']['originator'] = 'unspecified';
146  if ($thisfile_replaygain['track']['peak'] <= 0) {
147  $ThisFileInfo['warning'][] = 'ReplayGain Track peak from APEtag appears invalid: '.$thisfile_replaygain['track']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")';
148  }
149  break;
150 
151  case 'replaygain_album_gain':
152  $thisfile_replaygain['album']['adjustment'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
153  $thisfile_replaygain['album']['originator'] = 'unspecified';
154  break;
155 
156  case 'replaygain_album_peak':
157  $thisfile_replaygain['album']['peak'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
158  $thisfile_replaygain['album']['originator'] = 'unspecified';
159  if ($thisfile_replaygain['album']['peak'] <= 0) {
160  $ThisFileInfo['warning'][] = 'ReplayGain Album peak from APEtag appears invalid: '.$thisfile_replaygain['album']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")';
161  }
162  break;
163 
164  case 'mp3gain_undo':
165  list($mp3gain_undo_left, $mp3gain_undo_right, $mp3gain_undo_wrap) = explode(',', $thisfile_ape_items_current['data'][0]);
166  $thisfile_replaygain['mp3gain']['undo_left'] = intval($mp3gain_undo_left);
167  $thisfile_replaygain['mp3gain']['undo_right'] = intval($mp3gain_undo_right);
168  $thisfile_replaygain['mp3gain']['undo_wrap'] = (($mp3gain_undo_wrap == 'Y') ? true : false);
169  break;
170 
171  case 'mp3gain_minmax':
172  list($mp3gain_globalgain_min, $mp3gain_globalgain_max) = explode(',', $thisfile_ape_items_current['data'][0]);
173  $thisfile_replaygain['mp3gain']['globalgain_track_min'] = intval($mp3gain_globalgain_min);
174  $thisfile_replaygain['mp3gain']['globalgain_track_max'] = intval($mp3gain_globalgain_max);
175  break;
176 
177  case 'mp3gain_album_minmax':
178  list($mp3gain_globalgain_album_min, $mp3gain_globalgain_album_max) = explode(',', $thisfile_ape_items_current['data'][0]);
179  $thisfile_replaygain['mp3gain']['globalgain_album_min'] = intval($mp3gain_globalgain_album_min);
180  $thisfile_replaygain['mp3gain']['globalgain_album_max'] = intval($mp3gain_globalgain_album_max);
181  break;
182 
183  case 'tracknumber':
184  foreach ($thisfile_ape_items_current['data'] as $comment) {
185  $thisfile_ape['comments']['track'][] = $comment;
186  }
187  break;
188 
189  default:
190  foreach ($thisfile_ape_items_current['data'] as $comment) {
191  $thisfile_ape['comments'][strtolower($item_key)][] = $comment;
192  }
193  break;
194  }
195 
196  }
197  if (empty($thisfile_replaygain)) {
198  unset($ThisFileInfo['replay_gain']);
199  }
200 
201  return true;
202  }
LittleEndian2Int($byteword, $signed=false)
Definition: getid3.lib.php:266
$comment
Definition: buildRTE.php:83
parseAPEtagFlags($rawflagint)
parseAPEheaderFooter($APEheaderFooterData)
+ Here is the call graph for this function:

◆ parseAPEheaderFooter()

getid3_apetag::parseAPEheaderFooter (   $APEheaderFooterData)

Definition at line 204 of file module.tag.apetag.php.

References getid3_lib\LittleEndian2Int(), and parseAPEtagFlags().

Referenced by getid3_apetag().

204  {
205  // http://www.uni-jena.de/~pfk/mpp/sv8/apeheader.html
206 
207  // shortcut
208  $headerfooterinfo['raw'] = array();
209  $headerfooterinfo_raw = &$headerfooterinfo['raw'];
210 
211  $headerfooterinfo_raw['footer_tag'] = substr($APEheaderFooterData, 0, 8);
212  if ($headerfooterinfo_raw['footer_tag'] != 'APETAGEX') {
213  return false;
214  }
215  $headerfooterinfo_raw['version'] = getid3_lib::LittleEndian2Int(substr($APEheaderFooterData, 8, 4));
216  $headerfooterinfo_raw['tagsize'] = getid3_lib::LittleEndian2Int(substr($APEheaderFooterData, 12, 4));
217  $headerfooterinfo_raw['tag_items'] = getid3_lib::LittleEndian2Int(substr($APEheaderFooterData, 16, 4));
218  $headerfooterinfo_raw['global_flags'] = getid3_lib::LittleEndian2Int(substr($APEheaderFooterData, 20, 4));
219  $headerfooterinfo_raw['reserved'] = substr($APEheaderFooterData, 24, 8);
220 
221  $headerfooterinfo['tag_version'] = $headerfooterinfo_raw['version'] / 1000;
222  if ($headerfooterinfo['tag_version'] >= 2) {
223  $headerfooterinfo['flags'] = $this->parseAPEtagFlags($headerfooterinfo_raw['global_flags']);
224  }
225  return $headerfooterinfo;
226  }
LittleEndian2Int($byteword, $signed=false)
Definition: getid3.lib.php:266
parseAPEtagFlags($rawflagint)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parseAPEtagFlags()

getid3_apetag::parseAPEtagFlags (   $rawflagint)

Definition at line 228 of file module.tag.apetag.php.

References APEcontentTypeFlagLookup().

Referenced by getid3_apetag(), and parseAPEheaderFooter().

228  {
229  // "Note: APE Tags 1.0 do not use any of the APE Tag flags.
230  // All are set to zero on creation and ignored on reading."
231  // http://www.uni-jena.de/~pfk/mpp/sv8/apetagflags.html
232  $flags['header'] = (bool) ($rawflagint & 0x80000000);
233  $flags['footer'] = (bool) ($rawflagint & 0x40000000);
234  $flags['this_is_header'] = (bool) ($rawflagint & 0x20000000);
235  $flags['item_contents_raw'] = ($rawflagint & 0x00000006) >> 1;
236  $flags['read_only'] = (bool) ($rawflagint & 0x00000001);
237 
238  $flags['item_contents'] = $this->APEcontentTypeFlagLookup($flags['item_contents_raw']);
239 
240  return $flags;
241  }
APEcontentTypeFlagLookup($contenttypeid)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

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