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