Ignore:
Timestamp:
Jul 7, 2009, 10:27:37 PM (15 years ago)
Author:
vdigital
Message:

Change: getid3 upgraded to -> 1.7.9

File:
1 edited

Legend:

Unmodified
Added
Removed
  • extensions/charlies_content/getid3/getid3/module.tag.apetag.php

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