view e2gallerypro/e2upload/Backend/Assets/getid3/module.tag.apetag.php @ 3:3f6b44aa6b35 judyates

[svn r4] added ability to buy stuff, from a Prints page, but it doesn't work well with the css, and it also has not been fitted into the perl make system.
author rlm
date Mon, 22 Feb 2010 08:02:39 -0500
parents
children
line wrap: on
line source
1 <?php
2 // +----------------------------------------------------------------------+
3 // | PHP version 5 |
4 // +----------------------------------------------------------------------+
5 // | Copyright (c) 2002-2006 James Heinrich, Allan Hansen |
6 // +----------------------------------------------------------------------+
7 // | This source file is subject to version 2 of the GPL license, |
8 // | that is bundled with this package in the file license.txt and is |
9 // | available through the world-wide-web at the following url: |
10 // | http://www.gnu.org/copyleft/gpl.html |
11 // +----------------------------------------------------------------------+
12 // | getID3() - http://getid3.sourceforge.net or http://www.getid3.org |
13 // +----------------------------------------------------------------------+
14 // | Authors: James Heinrich <infoØgetid3*org> |
15 // | Allan Hansen <ahØartemis*dk> |
16 // +----------------------------------------------------------------------+
17 // | module.tag.apetag.php |
18 // | module for analyzing APE tags |
19 // | dependencies: NONE |
20 // +----------------------------------------------------------------------+
21 //
22 // $Id: module.tag.apetag.php,v 1.5 2006/11/16 14:05:21 ah Exp $
26 class getid3_apetag extends getid3_handler
27 {
28 /*
29 ID3v1_TAG_SIZE = 128;
30 APETAG_HEADER_SIZE = 32;
31 LYRICS3_TAG_SIZE = 10;
32 */
34 public $option_override_end_offset = 0;
38 public function Analyze() {
40 $getid3 = $this->getid3;
42 if ($this->option_override_end_offset == 0) {
44 fseek($getid3->fp, 0 - 170, SEEK_END); // 170 = ID3v1_TAG_SIZE + APETAG_HEADER_SIZE + LYRICS3_TAG_SIZE
45 $apetag_footer_id3v1 = fread($getid3->fp, 170); // 170 = ID3v1_TAG_SIZE + APETAG_HEADER_SIZE + LYRICS3_TAG_SIZE
47 // APE tag found before ID3v1
48 if (substr($apetag_footer_id3v1, strlen($apetag_footer_id3v1) - 160, 8) == 'APETAGEX') { // 160 = ID3v1_TAG_SIZE + APETAG_HEADER_SIZE
49 $getid3->info['ape']['tag_offset_end'] = filesize($getid3->filename) - 128; // 128 = ID3v1_TAG_SIZE
50 }
52 // APE tag found, no ID3v1
53 elseif (substr($apetag_footer_id3v1, strlen($apetag_footer_id3v1) - 32, 8) == 'APETAGEX') { // 32 = APETAG_HEADER_SIZE
54 $getid3->info['ape']['tag_offset_end'] = filesize($getid3->filename);
55 }
57 }
58 else {
60 fseek($getid3->fp, $this->option_override_end_offset - 32, SEEK_SET); // 32 = APETAG_HEADER_SIZE
61 if (fread($getid3->fp, 8) == 'APETAGEX') {
62 $getid3->info['ape']['tag_offset_end'] = $this->option_override_end_offset;
63 }
65 }
67 // APE tag not found
68 if (!@$getid3->info['ape']['tag_offset_end']) {
69 return false;
70 }
72 // Shortcut
73 $info_ape = &$getid3->info['ape'];
75 // Read and parse footer
76 fseek($getid3->fp, $info_ape['tag_offset_end'] - 32, SEEK_SET); // 32 = APETAG_HEADER_SIZE
77 $apetag_footer_data = fread($getid3->fp, 32);
78 if (!($this->ParseAPEHeaderFooter($apetag_footer_data, $info_ape['footer']))) {
79 throw new getid3_exception('Error parsing APE footer at offset '.$info_ape['tag_offset_end']);
80 }
82 if (isset($info_ape['footer']['flags']['header']) && $info_ape['footer']['flags']['header']) {
83 fseek($getid3->fp, $info_ape['tag_offset_end'] - $info_ape['footer']['raw']['tagsize'] - 32, SEEK_SET);
84 $info_ape['tag_offset_start'] = ftell($getid3->fp);
85 $apetag_data = fread($getid3->fp, $info_ape['footer']['raw']['tagsize'] + 32);
86 }
87 else {
88 $info_ape['tag_offset_start'] = $info_ape['tag_offset_end'] - $info_ape['footer']['raw']['tagsize'];
89 fseek($getid3->fp, $info_ape['tag_offset_start'], SEEK_SET);
90 $apetag_data = fread($getid3->fp, $info_ape['footer']['raw']['tagsize']);
91 }
92 $getid3->info['avdataend'] = $info_ape['tag_offset_start'];
94 if (isset($getid3->info['id3v1']['tag_offset_start']) && ($getid3->info['id3v1']['tag_offset_start'] < $info_ape['tag_offset_end'])) {
95 $getid3->warning('ID3v1 tag information ignored since it appears to be a false synch in APEtag data');
96 unset($getid3->info['id3v1']);
97 }
99 $offset = 0;
100 if (isset($info_ape['footer']['flags']['header']) && $info_ape['footer']['flags']['header']) {
101 if (!$this->ParseAPEHeaderFooter(substr($apetag_data, 0, 32), $info_ape['header'])) {
102 throw new getid3_exception('Error parsing APE header at offset '.$info_ape['tag_offset_start']);
103 }
104 $offset = 32;
105 }
107 // Shortcut
108 $getid3->info['replay_gain'] = array ();
109 $info_replaygain = &$getid3->info['replay_gain'];
111 for ($i = 0; $i < $info_ape['footer']['raw']['tag_items']; $i++) {
112 $value_size = getid3_lib::LittleEndian2Int(substr($apetag_data, $offset, 4));
113 $item_flags = getid3_lib::LittleEndian2Int(substr($apetag_data, $offset + 4, 4));
114 $offset += 8;
116 if (strstr(substr($apetag_data, $offset), "\x00") === false) {
117 throw new getid3_exception('Cannot find null-byte (0x00) seperator between ItemKey #'.$i.' and value. ItemKey starts ' . $offset . ' bytes into the APE tag, at file offset '.($info_ape['tag_offset_start'] + $offset));
118 }
120 $item_key_length = strpos($apetag_data, "\x00", $offset) - $offset;
121 $item_key = strtolower(substr($apetag_data, $offset, $item_key_length));
123 // Shortcut
124 $info_ape['items'][$item_key] = array ();
125 $info_ape_items_current = &$info_ape['items'][$item_key];
127 $offset += $item_key_length + 1; // skip 0x00 terminator
128 $info_ape_items_current['data'] = substr($apetag_data, $offset, $value_size);
129 $offset += $value_size;
132 $info_ape_items_current['flags'] = $this->ParseAPEtagFlags($item_flags);
134 switch ($info_ape_items_current['flags']['item_contents_raw']) {
135 case 0: // UTF-8
136 case 3: // Locator (URL, filename, etc), UTF-8 encoded
137 $info_ape_items_current['data'] = explode("\x00", trim($info_ape_items_current['data']));
138 break;
140 default: // binary data
141 break;
142 }
144 switch (strtolower($item_key)) {
145 case 'replaygain_track_gain':
146 $info_replaygain['track']['adjustment'] = (float)str_replace(',', '.', $info_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
147 $info_replaygain['track']['originator'] = 'unspecified';
148 break;
150 case 'replaygain_track_peak':
151 $info_replaygain['track']['peak'] = (float)str_replace(',', '.', $info_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
152 $info_replaygain['track']['originator'] = 'unspecified';
153 if ($info_replaygain['track']['peak'] <= 0) {
154 $getid3->warning('ReplayGain Track peak from APEtag appears invalid: '.$info_replaygain['track']['peak'].' (original value = "'.$info_ape_items_current['data'][0].'")');
155 }
156 break;
158 case 'replaygain_album_gain':
159 $info_replaygain['album']['adjustment'] = (float)str_replace(',', '.', $info_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
160 $info_replaygain['album']['originator'] = 'unspecified';
161 break;
163 case 'replaygain_album_peak':
164 $info_replaygain['album']['peak'] = (float)str_replace(',', '.', $info_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
165 $info_replaygain['album']['originator'] = 'unspecified';
166 if ($info_replaygain['album']['peak'] <= 0) {
167 $getid3->warning('ReplayGain Album peak from APEtag appears invalid: '.$info_replaygain['album']['peak'].' (original value = "'.$info_ape_items_current['data'][0].'")');
168 }
169 break;
171 case 'mp3gain_undo':
172 list($mp3gain_undo_left, $mp3gain_undo_right, $mp3gain_undo_wrap) = explode(',', $info_ape_items_current['data'][0]);
173 $info_replaygain['mp3gain']['undo_left'] = intval($mp3gain_undo_left);
174 $info_replaygain['mp3gain']['undo_right'] = intval($mp3gain_undo_right);
175 $info_replaygain['mp3gain']['undo_wrap'] = (($mp3gain_undo_wrap == 'Y') ? true : false);
176 break;
178 case 'mp3gain_minmax':
179 list($mp3gain_globalgain_min, $mp3gain_globalgain_max) = explode(',', $info_ape_items_current['data'][0]);
180 $info_replaygain['mp3gain']['globalgain_track_min'] = intval($mp3gain_globalgain_min);
181 $info_replaygain['mp3gain']['globalgain_track_max'] = intval($mp3gain_globalgain_max);
182 break;
184 case 'mp3gain_album_minmax':
185 list($mp3gain_globalgain_album_min, $mp3gain_globalgain_album_max) = explode(',', $info_ape_items_current['data'][0]);
186 $info_replaygain['mp3gain']['globalgain_album_min'] = intval($mp3gain_globalgain_album_min);
187 $info_replaygain['mp3gain']['globalgain_album_max'] = intval($mp3gain_globalgain_album_max);
188 break;
190 case 'tracknumber':
191 foreach ($info_ape_items_current['data'] as $comment) {
192 $info_ape['comments']['track'][] = $comment;
193 }
194 break;
196 default:
197 foreach ($info_ape_items_current['data'] as $comment) {
198 $info_ape['comments'][strtolower($item_key)][] = $comment;
199 }
200 break;
201 }
203 }
204 if (empty($info_replaygain)) {
205 unset($getid3->info['replay_gain']);
206 }
208 return true;
209 }
213 protected function ParseAPEheaderFooter($data, &$target) {
215 // http://www.uni-jena.de/~pfk/mpp/sv8/apeheader.html
217 if (substr($data, 0, 8) != 'APETAGEX') {
218 return false;
219 }
221 // shortcut
222 $target['raw'] = array ();
223 $target_raw = &$target['raw'];
225 $target_raw['footer_tag'] = 'APETAGEX';
227 getid3_lib::ReadSequence("LittleEndian2Int", $target_raw, $data, 8,
228 array (
229 'version' => 4,
230 'tagsize' => 4,
231 'tag_items' => 4,
232 'global_flags' => 4
233 )
234 );
235 $target_raw['reserved'] = substr($data, 24, 8);
237 $target['tag_version'] = $target_raw['version'] / 1000;
238 if ($target['tag_version'] >= 2) {
240 $target['flags'] = $this->ParseAPEtagFlags($target_raw['global_flags']);
241 }
243 return true;
244 }
248 protected function ParseAPEtagFlags($raw_flag_int) {
250 // "Note: APE Tags 1.0 do not use any of the APE Tag flags.
251 // All are set to zero on creation and ignored on reading."
252 // http://www.uni-jena.de/~pfk/mpp/sv8/apetagflags.html
254 $target['header'] = (bool) ($raw_flag_int & 0x80000000);
255 $target['footer'] = (bool) ($raw_flag_int & 0x40000000);
256 $target['this_is_header'] = (bool) ($raw_flag_int & 0x20000000);
257 $target['item_contents_raw'] = ($raw_flag_int & 0x00000006) >> 1;
258 $target['read_only'] = (bool) ($raw_flag_int & 0x00000001);
260 $target['item_contents'] = getid3_apetag::APEcontentTypeFlagLookup($target['item_contents_raw']);
262 return $target;
263 }
267 public static function APEcontentTypeFlagLookup($content_type_id) {
269 static $lookup = array (
270 0 => 'utf-8',
271 1 => 'binary',
272 2 => 'external',
273 3 => 'reserved'
274 );
275 return (isset($lookup[$content_type_id]) ? $lookup[$content_type_id] : 'invalid');
276 }
280 public static function APEtagItemIsUTF8Lookup($item_key) {
282 static $lookup = array (
283 'title',
284 'subtitle',
285 'artist',
286 'album',
287 'debut album',
288 'publisher',
289 'conductor',
290 'track',
291 'composer',
292 'comment',
293 'copyright',
294 'publicationright',
295 'file',
296 'year',
297 'record date',
298 'record location',
299 'genre',
300 'media',
301 'related',
302 'isrc',
303 'abstract',
304 'language',
305 'bibliography'
306 );
307 return in_array(strtolower($item_key), $lookup);
308 }
310 }
312 ?>