136 $offset += $value_size; |
136 $offset += $value_size; |
137 |
137 |
138 $thisfile_ape_items_current['flags'] = $this->parseAPEtagFlags($item_flags); |
138 $thisfile_ape_items_current['flags'] = $this->parseAPEtagFlags($item_flags); |
139 switch ($thisfile_ape_items_current['flags']['item_contents_raw']) { |
139 switch ($thisfile_ape_items_current['flags']['item_contents_raw']) { |
140 case 0: // UTF-8 |
140 case 0: // UTF-8 |
141 case 3: // Locator (URL, filename, etc), UTF-8 encoded |
141 case 2: // Locator (URL, filename, etc), UTF-8 encoded |
142 $thisfile_ape_items_current['data'] = explode("\x00", trim($thisfile_ape_items_current['data'])); |
142 $thisfile_ape_items_current['data'] = explode("\x00", $thisfile_ape_items_current['data']); |
143 break; |
143 break; |
144 |
144 |
145 default: // binary data |
145 case 1: // binary data |
|
146 default: |
146 break; |
147 break; |
147 } |
148 } |
148 |
149 |
149 switch (strtolower($item_key)) { |
150 switch (strtolower($item_key)) { |
|
151 // http://wiki.hydrogenaud.io/index.php?title=ReplayGain#MP3Gain |
150 case 'replaygain_track_gain': |
152 case 'replaygain_track_gain': |
151 $thisfile_replaygain['track']['adjustment'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero! |
153 if (preg_match('#^[\\-\\+][0-9\\.,]{8}$#', $thisfile_ape_items_current['data'][0])) { |
152 $thisfile_replaygain['track']['originator'] = 'unspecified'; |
154 $thisfile_replaygain['track']['adjustment'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero! |
|
155 $thisfile_replaygain['track']['originator'] = 'unspecified'; |
|
156 } else { |
|
157 $this->warning('MP3gainTrackGain value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"'); |
|
158 } |
153 break; |
159 break; |
154 |
160 |
155 case 'replaygain_track_peak': |
161 case 'replaygain_track_peak': |
156 $thisfile_replaygain['track']['peak'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero! |
162 if (preg_match('#^[0-9\\.,]{8}$#', $thisfile_ape_items_current['data'][0])) { |
157 $thisfile_replaygain['track']['originator'] = 'unspecified'; |
163 $thisfile_replaygain['track']['peak'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero! |
158 if ($thisfile_replaygain['track']['peak'] <= 0) { |
164 $thisfile_replaygain['track']['originator'] = 'unspecified'; |
159 $info['warning'][] = 'ReplayGain Track peak from APEtag appears invalid: '.$thisfile_replaygain['track']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")'; |
165 if ($thisfile_replaygain['track']['peak'] <= 0) { |
|
166 $this->warning('ReplayGain Track peak from APEtag appears invalid: '.$thisfile_replaygain['track']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")'); |
|
167 } |
|
168 } else { |
|
169 $this->warning('MP3gainTrackPeak value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"'); |
160 } |
170 } |
161 break; |
171 break; |
162 |
172 |
163 case 'replaygain_album_gain': |
173 case 'replaygain_album_gain': |
164 $thisfile_replaygain['album']['adjustment'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero! |
174 if (preg_match('#^[\\-\\+][0-9\\.,]{8}$#', $thisfile_ape_items_current['data'][0])) { |
165 $thisfile_replaygain['album']['originator'] = 'unspecified'; |
175 $thisfile_replaygain['album']['adjustment'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero! |
|
176 $thisfile_replaygain['album']['originator'] = 'unspecified'; |
|
177 } else { |
|
178 $this->warning('MP3gainAlbumGain value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"'); |
|
179 } |
166 break; |
180 break; |
167 |
181 |
168 case 'replaygain_album_peak': |
182 case 'replaygain_album_peak': |
169 $thisfile_replaygain['album']['peak'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero! |
183 if (preg_match('#^[0-9\\.,]{8}$#', $thisfile_ape_items_current['data'][0])) { |
170 $thisfile_replaygain['album']['originator'] = 'unspecified'; |
184 $thisfile_replaygain['album']['peak'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero! |
171 if ($thisfile_replaygain['album']['peak'] <= 0) { |
185 $thisfile_replaygain['album']['originator'] = 'unspecified'; |
172 $info['warning'][] = 'ReplayGain Album peak from APEtag appears invalid: '.$thisfile_replaygain['album']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")'; |
186 if ($thisfile_replaygain['album']['peak'] <= 0) { |
|
187 $this->warning('ReplayGain Album peak from APEtag appears invalid: '.$thisfile_replaygain['album']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")'); |
|
188 } |
|
189 } else { |
|
190 $this->warning('MP3gainAlbumPeak value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"'); |
173 } |
191 } |
174 break; |
192 break; |
175 |
193 |
176 case 'mp3gain_undo': |
194 case 'mp3gain_undo': |
177 list($mp3gain_undo_left, $mp3gain_undo_right, $mp3gain_undo_wrap) = explode(',', $thisfile_ape_items_current['data'][0]); |
195 if (preg_match('#^[\\-\\+][0-9]{3},[\\-\\+][0-9]{3},[NW]$#', $thisfile_ape_items_current['data'][0])) { |
178 $thisfile_replaygain['mp3gain']['undo_left'] = intval($mp3gain_undo_left); |
196 list($mp3gain_undo_left, $mp3gain_undo_right, $mp3gain_undo_wrap) = explode(',', $thisfile_ape_items_current['data'][0]); |
179 $thisfile_replaygain['mp3gain']['undo_right'] = intval($mp3gain_undo_right); |
197 $thisfile_replaygain['mp3gain']['undo_left'] = intval($mp3gain_undo_left); |
180 $thisfile_replaygain['mp3gain']['undo_wrap'] = (($mp3gain_undo_wrap == 'Y') ? true : false); |
198 $thisfile_replaygain['mp3gain']['undo_right'] = intval($mp3gain_undo_right); |
|
199 $thisfile_replaygain['mp3gain']['undo_wrap'] = (($mp3gain_undo_wrap == 'Y') ? true : false); |
|
200 } else { |
|
201 $this->warning('MP3gainUndo value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"'); |
|
202 } |
181 break; |
203 break; |
182 |
204 |
183 case 'mp3gain_minmax': |
205 case 'mp3gain_minmax': |
184 list($mp3gain_globalgain_min, $mp3gain_globalgain_max) = explode(',', $thisfile_ape_items_current['data'][0]); |
206 if (preg_match('#^[0-9]{3},[0-9]{3}$#', $thisfile_ape_items_current['data'][0])) { |
185 $thisfile_replaygain['mp3gain']['globalgain_track_min'] = intval($mp3gain_globalgain_min); |
207 list($mp3gain_globalgain_min, $mp3gain_globalgain_max) = explode(',', $thisfile_ape_items_current['data'][0]); |
186 $thisfile_replaygain['mp3gain']['globalgain_track_max'] = intval($mp3gain_globalgain_max); |
208 $thisfile_replaygain['mp3gain']['globalgain_track_min'] = intval($mp3gain_globalgain_min); |
|
209 $thisfile_replaygain['mp3gain']['globalgain_track_max'] = intval($mp3gain_globalgain_max); |
|
210 } else { |
|
211 $this->warning('MP3gainMinMax value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"'); |
|
212 } |
187 break; |
213 break; |
188 |
214 |
189 case 'mp3gain_album_minmax': |
215 case 'mp3gain_album_minmax': |
190 list($mp3gain_globalgain_album_min, $mp3gain_globalgain_album_max) = explode(',', $thisfile_ape_items_current['data'][0]); |
216 if (preg_match('#^[0-9]{3},[0-9]{3}$#', $thisfile_ape_items_current['data'][0])) { |
191 $thisfile_replaygain['mp3gain']['globalgain_album_min'] = intval($mp3gain_globalgain_album_min); |
217 list($mp3gain_globalgain_album_min, $mp3gain_globalgain_album_max) = explode(',', $thisfile_ape_items_current['data'][0]); |
192 $thisfile_replaygain['mp3gain']['globalgain_album_max'] = intval($mp3gain_globalgain_album_max); |
218 $thisfile_replaygain['mp3gain']['globalgain_album_min'] = intval($mp3gain_globalgain_album_min); |
|
219 $thisfile_replaygain['mp3gain']['globalgain_album_max'] = intval($mp3gain_globalgain_album_max); |
|
220 } else { |
|
221 $this->warning('MP3gainAlbumMinMax value in APEtag appears invalid: "'.$thisfile_ape_items_current['data'][0].'"'); |
|
222 } |
193 break; |
223 break; |
194 |
224 |
195 case 'tracknumber': |
225 case 'tracknumber': |
196 if (is_array($thisfile_ape_items_current['data'])) { |
226 if (is_array($thisfile_ape_items_current['data'])) { |
197 foreach ($thisfile_ape_items_current['data'] as $comment) { |
227 foreach ($thisfile_ape_items_current['data'] as $comment) { |
220 case 'cover art (performance)': |
250 case 'cover art (performance)': |
221 case 'cover art (publisher logo)': |
251 case 'cover art (publisher logo)': |
222 case 'cover art (recording)': |
252 case 'cover art (recording)': |
223 case 'cover art (studio)': |
253 case 'cover art (studio)': |
224 // list of possible cover arts from http://taglib-sharp.sourcearchive.com/documentation/2.0.3.0-2/Ape_2Tag_8cs-source.html |
254 // list of possible cover arts from http://taglib-sharp.sourcearchive.com/documentation/2.0.3.0-2/Ape_2Tag_8cs-source.html |
|
255 if (is_array($thisfile_ape_items_current['data'])) { |
|
256 $this->warning('APEtag "'.$item_key.'" should be flagged as Binary data, but was incorrectly flagged as UTF-8'); |
|
257 $thisfile_ape_items_current['data'] = implode("\x00", $thisfile_ape_items_current['data']); |
|
258 } |
225 list($thisfile_ape_items_current['filename'], $thisfile_ape_items_current['data']) = explode("\x00", $thisfile_ape_items_current['data'], 2); |
259 list($thisfile_ape_items_current['filename'], $thisfile_ape_items_current['data']) = explode("\x00", $thisfile_ape_items_current['data'], 2); |
226 $thisfile_ape_items_current['data_offset'] = $thisfile_ape_items_current['offset'] + strlen($thisfile_ape_items_current['filename']."\x00"); |
260 $thisfile_ape_items_current['data_offset'] = $thisfile_ape_items_current['offset'] + strlen($thisfile_ape_items_current['filename']."\x00"); |
227 $thisfile_ape_items_current['data_length'] = strlen($thisfile_ape_items_current['data']); |
261 $thisfile_ape_items_current['data_length'] = strlen($thisfile_ape_items_current['data']); |
228 |
262 |
229 $thisfile_ape_items_current['image_mime'] = ''; |
|
230 $imageinfo = array(); |
|
231 $imagechunkcheck = getid3_lib::GetDataImageSize($thisfile_ape_items_current['data'], $imageinfo); |
|
232 $thisfile_ape_items_current['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]); |
|
233 |
|
234 do { |
263 do { |
|
264 $thisfile_ape_items_current['image_mime'] = ''; |
|
265 $imageinfo = array(); |
|
266 $imagechunkcheck = getid3_lib::GetDataImageSize($thisfile_ape_items_current['data'], $imageinfo); |
|
267 if (($imagechunkcheck === false) || !isset($imagechunkcheck[2])) { |
|
268 $this->warning('APEtag "'.$item_key.'" contains invalid image data'); |
|
269 break; |
|
270 } |
|
271 $thisfile_ape_items_current['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]); |
|
272 |
235 if ($this->inline_attachments === false) { |
273 if ($this->inline_attachments === false) { |
236 // skip entirely |
274 // skip entirely |
237 unset($thisfile_ape_items_current['data']); |
275 unset($thisfile_ape_items_current['data']); |
238 break; |
276 break; |
239 } |
277 } |
240 if ($this->inline_attachments === true) { |
278 if ($this->inline_attachments === true) { |
241 // great |
279 // great |
242 } elseif (is_int($this->inline_attachments)) { |
280 } elseif (is_int($this->inline_attachments)) { |
243 if ($this->inline_attachments < $thisfile_ape_items_current['data_length']) { |
281 if ($this->inline_attachments < $thisfile_ape_items_current['data_length']) { |
244 // too big, skip |
282 // too big, skip |
245 $info['warning'][] = 'attachment at '.$thisfile_ape_items_current['offset'].' is too large to process inline ('.number_format($thisfile_ape_items_current['data_length']).' bytes)'; |
283 $this->warning('attachment at '.$thisfile_ape_items_current['offset'].' is too large to process inline ('.number_format($thisfile_ape_items_current['data_length']).' bytes)'); |
246 unset($thisfile_ape_items_current['data']); |
284 unset($thisfile_ape_items_current['data']); |
247 break; |
285 break; |
248 } |
286 } |
249 } elseif (is_string($this->inline_attachments)) { |
287 } elseif (is_string($this->inline_attachments)) { |
250 $this->inline_attachments = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->inline_attachments), DIRECTORY_SEPARATOR); |
288 $this->inline_attachments = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->inline_attachments), DIRECTORY_SEPARATOR); |
251 if (!is_dir($this->inline_attachments) || !is_writable($this->inline_attachments)) { |
289 if (!is_dir($this->inline_attachments) || !getID3::is_writable($this->inline_attachments)) { |
252 // cannot write, skip |
290 // cannot write, skip |
253 $info['warning'][] = 'attachment at '.$thisfile_ape_items_current['offset'].' cannot be saved to "'.$this->inline_attachments.'" (not writable)'; |
291 $this->warning('attachment at '.$thisfile_ape_items_current['offset'].' cannot be saved to "'.$this->inline_attachments.'" (not writable)'); |
254 unset($thisfile_ape_items_current['data']); |
292 unset($thisfile_ape_items_current['data']); |
255 break; |
293 break; |
256 } |
294 } |
257 } |
295 } |
258 // if we get this far, must be OK |
296 // if we get this far, must be OK |
259 if (is_string($this->inline_attachments)) { |
297 if (is_string($this->inline_attachments)) { |
260 $destination_filename = $this->inline_attachments.DIRECTORY_SEPARATOR.md5($info['filenamepath']).'_'.$thisfile_ape_items_current['data_offset']; |
298 $destination_filename = $this->inline_attachments.DIRECTORY_SEPARATOR.md5($info['filenamepath']).'_'.$thisfile_ape_items_current['data_offset']; |
261 if (!file_exists($destination_filename) || is_writable($destination_filename)) { |
299 if (!file_exists($destination_filename) || getID3::is_writable($destination_filename)) { |
262 file_put_contents($destination_filename, $thisfile_ape_items_current['data']); |
300 file_put_contents($destination_filename, $thisfile_ape_items_current['data']); |
263 } else { |
301 } else { |
264 $info['warning'][] = 'attachment at '.$thisfile_ape_items_current['offset'].' cannot be saved to "'.$destination_filename.'" (not writable)'; |
302 $this->warning('attachment at '.$thisfile_ape_items_current['offset'].' cannot be saved to "'.$destination_filename.'" (not writable)'); |
265 } |
303 } |
266 $thisfile_ape_items_current['data_filename'] = $destination_filename; |
304 $thisfile_ape_items_current['data_filename'] = $destination_filename; |
267 unset($thisfile_ape_items_current['data']); |
305 unset($thisfile_ape_items_current['data']); |
268 } else { |
306 } else { |
269 if (!isset($info['ape']['comments']['picture'])) { |
307 if (!isset($info['ape']['comments']['picture'])) { |
270 $info['ape']['comments']['picture'] = array(); |
308 $info['ape']['comments']['picture'] = array(); |
271 } |
309 } |
272 $info['ape']['comments']['picture'][] = array('data'=>$thisfile_ape_items_current['data'], 'image_mime'=>$thisfile_ape_items_current['image_mime']); |
310 $comments_picture_data = array(); |
|
311 foreach (array('data', 'image_mime', 'image_width', 'image_height', 'imagetype', 'picturetype', 'description', 'datalength') as $picture_key) { |
|
312 if (isset($thisfile_ape_items_current[$picture_key])) { |
|
313 $comments_picture_data[$picture_key] = $thisfile_ape_items_current[$picture_key]; |
|
314 } |
|
315 } |
|
316 $info['ape']['comments']['picture'][] = $comments_picture_data; |
|
317 unset($comments_picture_data); |
273 } |
318 } |
274 } while (false); |
319 } while (false); |
275 break; |
320 break; |
276 |
321 |
277 default: |
322 default: |