diff e2gallerypro/e2upload/Backend/Assets/getid3/getid3.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 diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/e2gallerypro/e2upload/Backend/Assets/getid3/getid3.php	Mon Feb 22 08:02:39 2010 -0500
     1.3 @@ -0,0 +1,1598 @@
     1.4 +<?php
     1.5 +// +----------------------------------------------------------------------+
     1.6 +// | PHP version 5                                                        |
     1.7 +// +----------------------------------------------------------------------+
     1.8 +// | Copyright (c) 2002-2006 James Heinrich, Allan Hansen                 |
     1.9 +// +----------------------------------------------------------------------+
    1.10 +// | This source file is subject to version 2 of the GPL license,         |
    1.11 +// | that is bundled with this package in the file license.txt and is     |
    1.12 +// | available through the world-wide-web at the following url:           |
    1.13 +// | http://www.gnu.org/copyleft/gpl.html                                 |
    1.14 +// +----------------------------------------------------------------------+
    1.15 +// | getID3() - http://getid3.sourceforge.net or http://www.getid3.org    |
    1.16 +// +----------------------------------------------------------------------+
    1.17 +// | Authors: James Heinrich <infogetid3*org>                            |
    1.18 +// |          Allan Hansen <ahartemis*dk>                                |
    1.19 +// +----------------------------------------------------------------------+
    1.20 +// | getid3.php                                                           |
    1.21 +// | Main getID3() file.                                                  |
    1.22 +// | dependencies: modules.                                               |
    1.23 +// +----------------------------------------------------------------------+
    1.24 +//
    1.25 +// $Id: getid3.php,v 1.26 2006/12/25 23:44:23 ah Exp $
    1.26 +
    1.27 +
    1.28 +class getid3
    1.29 +{
    1.30 +    //// Settings Section - do NOT modify this file - change setting after newing getid3!
    1.31 +
    1.32 +    // Encoding
    1.33 +    public $encoding                 = 'ISO-8859-1';      // CASE SENSITIVE! - i.e. (must be supported by iconv() - see http://www.gnu.org/software/libiconv/).  Examples:  ISO-8859-1  UTF-8  UTF-16  UTF-16BE.
    1.34 +    public $encoding_id3v1           = 'ISO-8859-1';      // Override SPECIFICATION encoding for broken ID3v1 tags caused by bad tag programs. Examples: 'EUC-CN' for "Chinese MP3s" and 'CP1251' for "Cyrillic".
    1.35 +    public $encoding_id3v2           = 'ISO-8859-1';      // Override ISO-8859-1 encoding for broken ID3v2 tags caused by BRAINDEAD tag programs that writes system codepage as 'ISO-8859-1' instead of UTF-8.
    1.36 +
    1.37 +    // Tags - disable for speed
    1.38 +    public $option_tag_id3v1         = true;              // Read and process ID3v1 tags.
    1.39 +    public $option_tag_id3v2         = true;              // Read and process ID3v2 tags.
    1.40 +    public $option_tag_lyrics3       = true;              // Read and process Lyrics3 tags.
    1.41 +    public $option_tag_apetag        = true;              // Read and process APE tags.
    1.42 +
    1.43 +    // Misc calucations - disable for speed
    1.44 +    public $option_analyze           = true;              // Analyze file - disable if you only need to detect file format.
    1.45 +    public $option_accurate_results  = true;              // Disable to greatly speed up parsing of some file formats at the cost of accuracy.
    1.46 +    public $option_tags_process      = true;              // Copy tags to root key 'tags' and 'comments' and encode to $this->encoding.
    1.47 +    public $option_tags_images       = false;             // Scan tags for binary image data - ID3v2 and vorbiscomments only.
    1.48 +    public $option_extra_info        = true;              // Calculate/return additional info such as bitrate, channelmode etc.
    1.49 +    public $option_max_2gb_check     = false;             // Check whether file is larger than 2 Gb and thus not supported by PHP.
    1.50 +
    1.51 +    // Misc data hashes - slow - require hash module
    1.52 +    public $option_md5_data          = false;             // Get MD5 sum of data part - slow.
    1.53 +    public $option_md5_data_source   = false;             // Use MD5 of source file if available - only FLAC, MAC, OptimFROG and Wavpack4.
    1.54 +    public $option_sha1_data         = false;             // Get SHA1 sum of data part - slow.
    1.55 +
    1.56 +    // Public variables
    1.57 +    public $filename;                                     // Filename of file being analysed.
    1.58 +    public $fp;                                           // Filepointer to file being analysed.
    1.59 +    public $info;                                         // Result array.
    1.60 +
    1.61 +    // Protected variables
    1.62 +    protected $include_path;                              // getid3 include path.
    1.63 +    protected $warnings = array ();
    1.64 +    protected $iconv_present;
    1.65 +
    1.66 +    // Class constants
    1.67 +    const VERSION           = '2.0.0b4';
    1.68 +    const FREAD_BUFFER_SIZE = 16384;                      // Read buffer size in bytes.
    1.69 +    const ICONV_TEST_STRING = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ';
    1.70 +
    1.71 +
    1.72 +
    1.73 +    // Constructor - check PHP enviroment and load library.
    1.74 +    public function __construct() {
    1.75 +
    1.76 +        // Static varibles - no need to recalc every time we new getid3.
    1.77 +        static $include_path;
    1.78 +        static $iconv_present;
    1.79 +
    1.80 +
    1.81 +        static $initialized;
    1.82 +        if ($initialized) {
    1.83 +
    1.84 +            // Import static variables
    1.85 +            $this->include_path  = $include_path;
    1.86 +            $this->iconv_present = $iconv_present;
    1.87 +
    1.88 +            // Run init checks only on first instance.
    1.89 +            return;
    1.90 +        }
    1.91 +
    1.92 +        // Get include_path
    1.93 +        $this->include_path = $include_path = dirname(__FILE__) . '/';
    1.94 +
    1.95 +        // Check for presence of iconv() and make sure it works (simpel test only).
    1.96 +        if (function_exists('iconv') && @iconv('UTF-16LE', 'ISO-8859-1', @iconv('ISO-8859-1', 'UTF-16LE', getid3::ICONV_TEST_STRING)) == getid3::ICONV_TEST_STRING) {
    1.97 +            $this->iconv_present = $iconv_present = true;
    1.98 +        }
    1.99 +
   1.100 +        // iconv() not present - load replacement module.
   1.101 +        else {
   1.102 +            $this->include_module('lib.iconv_replacement');
   1.103 +            $this->iconv_present = $iconv_present = false;
   1.104 +        }
   1.105 +
   1.106 +
   1.107 +        // Require magic_quotes_runtime off
   1.108 +        if (get_magic_quotes_runtime()) {
   1.109 +            throw new getid3_exception('magic_quotes_runtime must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_runtime(0) and set_magic_quotes_runtime(1).');
   1.110 +        }
   1.111 +
   1.112 +
   1.113 +        // Check memory limit.
   1.114 +        $memory_limit = ini_get('memory_limit');
   1.115 +        if (eregi('([0-9]+)M', $memory_limit, $matches)) {
   1.116 +            // could be stored as "16M" rather than 16777216 for example
   1.117 +            $memory_limit = $matches[1] * 1048576;
   1.118 +        }
   1.119 +        if ($memory_limit <= 0) {
   1.120 +            // Should not happen.
   1.121 +        } elseif ($memory_limit <= 4194304) {
   1.122 +            $this->warning('[SERIOUS] PHP has less than 4 Mb available memory and will very likely run out. Increase memory_limit in php.ini.');
   1.123 +        } elseif ($memory_limit <= 12582912) {
   1.124 +            $this->warning('PHP has less than 12 Mb available memory and might run out if all modules are loaded. Increase memory_limit in php.ini if needed.');
   1.125 +        }
   1.126 +
   1.127 +
   1.128 +        // Check safe_mode off
   1.129 +        if ((bool)ini_get('safe_mode')) {
   1.130 +            $this->warning('Safe mode is on, shorten support disabled, md5data/sha1data for ogg vorbis disabled, ogg vorbis/flac tag writing disabled.');
   1.131 +        }
   1.132 +
   1.133 +        $initialized = true;
   1.134 +    }
   1.135 +
   1.136 +
   1.137 +
   1.138 +    // Analyze file by name
   1.139 +    public function Analyze($filename) {
   1.140 +
   1.141 +        // Init and save values
   1.142 +        $this->filename = $filename;
   1.143 +        $this->warnings = array ();
   1.144 +
   1.145 +        // Init result array and set parameters
   1.146 +        $this->info = array ();
   1.147 +        $this->info['GETID3_VERSION'] = getid3::VERSION;
   1.148 +
   1.149 +        // Remote files not supported
   1.150 +        if (preg_match('/^(ht|f)tp:\/\//', $filename)) {
   1.151 +            throw new getid3_exception('Remote files are not supported - please copy the file locally first.');
   1.152 +        }
   1.153 +
   1.154 +        // Open local file
   1.155 +        if (!$this->fp = @fopen($filename, 'rb')) {
   1.156 +            throw new getid3_exception('Could not open file "'.$filename.'"');
   1.157 +        }
   1.158 +
   1.159 +        // Set filesize related parameters
   1.160 +        $this->info['filesize']     = filesize($filename);
   1.161 +        $this->info['avdataoffset'] = 0;
   1.162 +        $this->info['avdataend']    = $this->info['filesize'];
   1.163 +
   1.164 +        // Option_max_2gb_check
   1.165 +        if ($this->option_max_2gb_check) {
   1.166 +            // PHP doesn't support integers larger than 31-bit (~2GB)
   1.167 +            // filesize() simply returns (filesize % (pow(2, 32)), no matter the actual filesize
   1.168 +            // ftell() returns 0 if seeking to the end is beyond the range of unsigned integer
   1.169 +            fseek($this->fp, 0, SEEK_END);
   1.170 +            if ((($this->info['filesize'] != 0) && (ftell($this->fp) == 0)) ||
   1.171 +                ($this->info['filesize'] < 0) ||
   1.172 +                (ftell($this->fp) < 0)) {
   1.173 +                    unset($this->info['filesize']);
   1.174 +                    fclose($this->fp);
   1.175 +                    throw new getid3_exception('File is most likely larger than 2GB and is not supported by PHP.');
   1.176 +            }
   1.177 +        }
   1.178 +
   1.179 +
   1.180 +        // ID3v2 detection (NOT parsing) done to make fileformat easier.
   1.181 +        if (!$this->option_tag_id3v2) {
   1.182 +
   1.183 +            fseek($this->fp, 0, SEEK_SET);
   1.184 +            $header = fread($this->fp, 10);
   1.185 +            if (substr($header, 0, 3) == 'ID3'  &&  strlen($header) == 10) {
   1.186 +                $this->info['id3v2']['header']        = true;
   1.187 +                $this->info['id3v2']['majorversion']  = ord($header{3});
   1.188 +                $this->info['id3v2']['minorversion']  = ord($header{4});
   1.189 +                $this->info['avdataoffset']          += getid3_lib::BigEndian2Int(substr($header, 6, 4), 1) + 10; // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length
   1.190 +            }
   1.191 +        }
   1.192 +
   1.193 +
   1.194 +        // Handle tags
   1.195 +        foreach (array ("id3v2", "id3v1", "apetag", "lyrics3") as $tag_name) {
   1.196 +
   1.197 +            $option_tag = 'option_tag_' . $tag_name;
   1.198 +            if ($this->$option_tag) {
   1.199 +                $this->include_module('tag.'.$tag_name);
   1.200 +                try {
   1.201 +                    $tag_class = 'getid3_' . $tag_name;
   1.202 +                    $tag = new $tag_class($this);
   1.203 +                    $tag->Analyze();
   1.204 +                }
   1.205 +                catch (getid3_exception $e) {
   1.206 +                    throw $e;
   1.207 +                }
   1.208 +            }
   1.209 +        }
   1.210 +
   1.211 +
   1.212 +
   1.213 +        //// Determine file format by magic bytes in file header.
   1.214 +
   1.215 +        // Read 32 kb file data
   1.216 +        fseek($this->fp, $this->info['avdataoffset'], SEEK_SET);
   1.217 +        $filedata = fread($this->fp, 32774);
   1.218 +
   1.219 +        // Get huge FileFormatArray
   1.220 +        $file_format_array = getid3::GetFileFormatArray();
   1.221 +
   1.222 +        // Identify file format - loop through $format_info and detect with reg expr
   1.223 +        foreach ($file_format_array as $name => $info) {
   1.224 +
   1.225 +            if (preg_match('/'.$info['pattern'].'/s', $filedata)) {                         // The /s switch on preg_match() forces preg_match() NOT to treat newline (0x0A) characters as special chars but do a binary match
   1.226 +
   1.227 +                // Format detected but not supported
   1.228 +                if (!@$info['module'] || !@$info['group']) {
   1.229 +                    fclose($this->fp);
   1.230 +                    $this->info['fileformat'] = $name;
   1.231 +                    $this->info['mime_type']  = $info['mime_type'];
   1.232 +                    $this->warning('Format only detected. Parsing not available yet.');
   1.233 +                    $this->info['warning'] = $this->warnings;
   1.234 +                    return $this->info;
   1.235 +                }
   1.236 +
   1.237 +                $determined_format = $info;  // copy $info deleted by foreach()
   1.238 +                continue;
   1.239 +            }
   1.240 +        }
   1.241 +
   1.242 +        // Unable to determine file format
   1.243 +        if (!@$determined_format) {
   1.244 +
   1.245 +            // Too many mp3 encoders on the market put gabage in front of mpeg files
   1.246 +            // use assume format on these if format detection failed
   1.247 +            if (preg_match('/\.mp[123a]$/i', $filename)) {
   1.248 +                $determined_format = $file_format_array['mp3'];
   1.249 +            }
   1.250 +
   1.251 +            else {
   1.252 +                fclose($this->fp);
   1.253 +                throw new getid3_exception('Unable to determine file format');
   1.254 +            }
   1.255 +        }
   1.256 +
   1.257 +        // Free memory
   1.258 +        unset($file_format_array);
   1.259 +
   1.260 +        // Check for illegal ID3 tags
   1.261 +        if (@$determined_format['fail_id3'] && (@$this->info['id3v1'] || @$this->info['id3v2'])) {
   1.262 +            if ($determined_format['fail_id3'] === 'ERROR') {
   1.263 +                fclose($this->fp);
   1.264 +                throw new getid3_exception('ID3 tags not allowed on this file type.');
   1.265 +            }
   1.266 +            elseif ($determined_format['fail_id3'] === 'WARNING') {
   1.267 +                @$this->info['id3v1'] and $this->warning('ID3v1 tags not allowed on this file type.');
   1.268 +                @$this->info['id3v2'] and $this->warning('ID3v2 tags not allowed on this file type.');
   1.269 +            }
   1.270 +        }
   1.271 +
   1.272 +        // Check for illegal APE tags
   1.273 +        if (@$determined_format['fail_ape'] && @$this->info['tags']['ape']) {
   1.274 +            if ($determined_format['fail_ape'] === 'ERROR') {
   1.275 +                fclose($this->fp);
   1.276 +                throw new getid3_exception('APE tags not allowed on this file type.');
   1.277 +            } elseif ($determined_format['fail_ape'] === 'WARNING') {
   1.278 +                $this->warning('APE tags not allowed on this file type.');
   1.279 +            }
   1.280 +        }
   1.281 +
   1.282 +
   1.283 +        // Set mime type
   1.284 +        $this->info['mime_type'] = $determined_format['mime_type'];
   1.285 +
   1.286 +        // Calc module file name
   1.287 +        $determined_format['include'] = 'module.'.$determined_format['group'].'.'.$determined_format['module'].'.php';
   1.288 +
   1.289 +        // Supported format signature pattern detected, but module deleted.
   1.290 +        if (!file_exists($this->include_path.$determined_format['include'])) {
   1.291 +            fclose($this->fp);
   1.292 +            throw new getid3_exception('Format not supported, module, '.$determined_format['include'].', was removed.');
   1.293 +        }
   1.294 +
   1.295 +        // Include module
   1.296 +        $this->include_module($determined_format['group'].'.'.$determined_format['module']);
   1.297 +
   1.298 +        // Instantiate module class and analyze
   1.299 +        $class_name = 'getid3_'.$determined_format['module'];
   1.300 +        if (!class_exists($class_name)) {
   1.301 +            throw new getid3_exception('Format not supported, module, '.$determined_format['include'].', is corrupt.');
   1.302 +        }
   1.303 +        $class = new $class_name($this);
   1.304 +
   1.305 +        try {
   1.306 +             $this->option_analyze and $class->Analyze();
   1.307 +            }
   1.308 +        catch (getid3_exception $e) {
   1.309 +            throw $e;
   1.310 +        }
   1.311 +        catch (Exception $e) {
   1.312 +            throw new getid3_exception('Corrupt file.');
   1.313 +        }
   1.314 +
   1.315 +        // Close file
   1.316 +        fclose($this->fp);
   1.317 +
   1.318 +        // Optional - Process all tags - copy to 'tags' and convert charsets
   1.319 +        if ($this->option_tags_process) {
   1.320 +            $this->HandleAllTags();
   1.321 +        }
   1.322 +
   1.323 +
   1.324 +        //// Optional - perform more calculations
   1.325 +        if ($this->option_extra_info) {
   1.326 +
   1.327 +            // Set channelmode on audio
   1.328 +            if (@$this->info['audio']['channels'] == '1') {
   1.329 +                $this->info['audio']['channelmode'] = 'mono';
   1.330 +            } elseif (@$this->info['audio']['channels'] == '2') {
   1.331 +                $this->info['audio']['channelmode'] = 'stereo';
   1.332 +            }
   1.333 +
   1.334 +            // Calculate combined bitrate - audio + video
   1.335 +            $combined_bitrate  = 0;
   1.336 +            $combined_bitrate += (isset($this->info['audio']['bitrate']) ? $this->info['audio']['bitrate'] : 0);
   1.337 +            $combined_bitrate += (isset($this->info['video']['bitrate']) ? $this->info['video']['bitrate'] : 0);
   1.338 +            if (($combined_bitrate > 0) && empty($this->info['bitrate'])) {
   1.339 +                $this->info['bitrate'] = $combined_bitrate;
   1.340 +            }
   1.341 +            if (!isset($this->info['playtime_seconds']) && !empty($this->info['bitrate'])) {
   1.342 +                $this->info['playtime_seconds'] = (($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['bitrate'];
   1.343 +            }
   1.344 +
   1.345 +            // Set playtime string
   1.346 +            if (!empty($this->info['playtime_seconds']) && empty($this->info['playtime_string'])) {
   1.347 +                $this->info['playtime_string'] =  floor(round($this->info['playtime_seconds']) / 60) . ':' . str_pad(floor(round($this->info['playtime_seconds']) % 60), 2, 0, STR_PAD_LEFT);;
   1.348 +            }
   1.349 +
   1.350 +
   1.351 +            // CalculateCompressionRatioVideo() {
   1.352 +            if (@$this->info['video'] && @$this->info['video']['resolution_x'] && @$this->info['video']['resolution_y'] && @$this->info['video']['bits_per_sample']) {
   1.353 +
   1.354 +                // From static image formats
   1.355 +                if (in_array($this->info['video']['dataformat'], array ('bmp', 'gif', 'jpeg', 'jpg', 'png', 'tiff'))) {
   1.356 +                    $frame_rate         = 1;
   1.357 +                    $bitrate_compressed = $this->info['filesize'] * 8;
   1.358 +                }
   1.359 +
   1.360 +                // From video formats
   1.361 +                else {
   1.362 +                    $frame_rate         = @$this->info['video']['frame_rate'];
   1.363 +                    $bitrate_compressed = @$this->info['video']['bitrate'];
   1.364 +                }
   1.365 +
   1.366 +                if ($frame_rate && $bitrate_compressed) {
   1.367 +                    $this->info['video']['compression_ratio'] = $bitrate_compressed / ($this->info['video']['resolution_x'] * $this->info['video']['resolution_y'] * $this->info['video']['bits_per_sample'] * $frame_rate);
   1.368 +                }
   1.369 +            }
   1.370 +
   1.371 +
   1.372 +            // CalculateCompressionRatioAudio() {
   1.373 +            if (@$this->info['audio']['bitrate'] && @$this->info['audio']['channels'] && @$this->info['audio']['sample_rate']) {
   1.374 +                $this->info['audio']['compression_ratio'] = $this->info['audio']['bitrate'] / ($this->info['audio']['channels'] * $this->info['audio']['sample_rate'] * (@$this->info['audio']['bits_per_sample'] ? $this->info['audio']['bits_per_sample'] : 16));
   1.375 +            }
   1.376 +
   1.377 +            if (@$this->info['audio']['streams']) {
   1.378 +                foreach ($this->info['audio']['streams'] as $stream_number => $stream_data) {
   1.379 +                    if (@$stream_data['bitrate'] && @$stream_data['channels'] && @$stream_data['sample_rate']) {
   1.380 +                        $this->info['audio']['streams'][$stream_number]['compression_ratio'] = $stream_data['bitrate'] / ($stream_data['channels'] * $stream_data['sample_rate'] * (@$stream_data['bits_per_sample'] ? $stream_data['bits_per_sample'] : 16));
   1.381 +                    }
   1.382 +                }
   1.383 +            }
   1.384 +
   1.385 +
   1.386 +            // CalculateReplayGain() {
   1.387 +            if (@$this->info['replay_gain']) {
   1.388 +                if (!@$this->info['replay_gain']['reference_volume']) {
   1.389 +                     $this->info['replay_gain']['reference_volume'] = 89;
   1.390 +                }
   1.391 +                if (isset($this->info['replay_gain']['track']['adjustment'])) {
   1.392 +                    $this->info['replay_gain']['track']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['track']['adjustment'];
   1.393 +                }
   1.394 +                if (isset($this->info['replay_gain']['album']['adjustment'])) {
   1.395 +                    $this->info['replay_gain']['album']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['album']['adjustment'];
   1.396 +                }
   1.397 +
   1.398 +                if (isset($this->info['replay_gain']['track']['peak'])) {
   1.399 +                    $this->info['replay_gain']['track']['max_noclip_gain'] = 0 - 20 * log10($this->info['replay_gain']['track']['peak']);
   1.400 +                }
   1.401 +                if (isset($this->info['replay_gain']['album']['peak'])) {
   1.402 +                    $this->info['replay_gain']['album']['max_noclip_gain'] = 0 - 20 * log10($this->info['replay_gain']['album']['peak']);
   1.403 +                }
   1.404 +            }
   1.405 +
   1.406 +
   1.407 +            // ProcessAudioStreams() {
   1.408 +            if (@!$this->info['audio']['streams'] && (@$this->info['audio']['bitrate'] || @$this->info['audio']['channels'] || @$this->info['audio']['sample_rate'])) {
   1.409 +                  foreach ($this->info['audio'] as $key => $value) {
   1.410 +                    if ($key != 'streams') {
   1.411 +                        $this->info['audio']['streams'][0][$key] = $value;
   1.412 +                    }
   1.413 +                }
   1.414 +            }
   1.415 +        }
   1.416 +
   1.417 +
   1.418 +        // Get the md5/sha1sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags.
   1.419 +        if ($this->option_md5_data || $this->option_sha1_data) {
   1.420 +
   1.421 +            // Load data-hash library if needed
   1.422 +            $this->include_module('lib.data_hash');
   1.423 +
   1.424 +            if ($this->option_sha1_data) {
   1.425 +                new getid3_lib_data_hash($this, 'sha1');
   1.426 +            }
   1.427 +
   1.428 +            if ($this->option_md5_data) {
   1.429 +
   1.430 +                // no md5_data_source or option disabled -- md5_data_source supported by FLAC, MAC, OptimFROG, Wavpack4
   1.431 +                if (!$this->option_md5_data_source || !@$this->info['md5_data_source']) {
   1.432 +                    new getid3_lib_data_hash($this, 'md5');
   1.433 +                }
   1.434 +
   1.435 +                // copy md5_data_source to md5_data if option set to true
   1.436 +                elseif ($this->option_md5_data_source && @$this->info['md5_data_source']) {
   1.437 +                    $this->info['md5_data'] = $this->info['md5_data_source'];
   1.438 +                }
   1.439 +            }
   1.440 +        }
   1.441 +
   1.442 +        // Set warnings
   1.443 +        if ($this->warnings) {
   1.444 +            $this->info['warning'] = $this->warnings;
   1.445 +        }
   1.446 +
   1.447 +        // Return result
   1.448 +        return $this->info;
   1.449 +    }
   1.450 +
   1.451 +
   1.452 +
   1.453 +    // Return array of warnings
   1.454 +    public function warnings() {
   1.455 +
   1.456 +        return $this->warnings;
   1.457 +    }
   1.458 +
   1.459 +
   1.460 +
   1.461 +    // Add warning(s) to $this->warnings[]
   1.462 +    public function warning($message) {
   1.463 +
   1.464 +        if (is_array($message)) {
   1.465 +            $this->warnings = array_merge($this->warnings, $message);
   1.466 +        }
   1.467 +        else {
   1.468 +            $this->warnings[] = $message;
   1.469 +        }
   1.470 +    }
   1.471 +
   1.472 +
   1.473 +
   1.474 +    //  Clear all warnings when cloning
   1.475 +    public function __clone() {
   1.476 +
   1.477 +        $this->warnings = array ();
   1.478 +
   1.479 +        // Copy info array, otherwise it will be a reference.
   1.480 +        $temp = $this->info;
   1.481 +        unset($this->info);
   1.482 +        $this->info = $temp;
   1.483 +    }
   1.484 +
   1.485 +
   1.486 +
   1.487 +    // Convert string between charsets -- iconv() wrapper
   1.488 +    public function iconv($in_charset, $out_charset, $string, $drop01 = false) {
   1.489 +
   1.490 +        if ($drop01 && ($string === "\x00" || $string === "\x01")) {
   1.491 +            return '';
   1.492 +        }
   1.493 +
   1.494 +
   1.495 +        if (!$this->iconv_present) {
   1.496 +            return getid3_iconv_replacement::iconv($in_charset, $out_charset, $string);
   1.497 +        }
   1.498 +
   1.499 +
   1.500 +        // iconv() present
   1.501 +        if ($result = @iconv($in_charset, $out_charset.'//TRANSLIT', $string)) {
   1.502 +
   1.503 +            if ($out_charset == 'ISO-8859-1') {
   1.504 +                return rtrim($result, "\x00");
   1.505 +            }
   1.506 +            return $result;
   1.507 +        }
   1.508 +
   1.509 +        $this->warning('iconv() was unable to convert the string: "' . $string . '" from ' . $in_charset . ' to ' . $out_charset);
   1.510 +        return $string;
   1.511 +    }
   1.512 +
   1.513 +
   1.514 +
   1.515 +    public function include_module($name) {
   1.516 +
   1.517 +        if (!file_exists($this->include_path.'module.'.$name.'.php')) {
   1.518 +            throw new getid3_exception('Required module.'.$name.'.php is missing.');
   1.519 +        }
   1.520 +
   1.521 +        include_once($this->include_path.'module.'.$name.'.php');
   1.522 +    }
   1.523 +
   1.524 +
   1.525 +
   1.526 +    public function include_module_optional($name) {
   1.527 +
   1.528 +        if (!file_exists($this->include_path.'module.'.$name.'.php')) {
   1.529 +            return;
   1.530 +        }
   1.531 +
   1.532 +        include_once($this->include_path.'module.'.$name.'.php');
   1.533 +        return true;
   1.534 +    }
   1.535 +
   1.536 +
   1.537 +    // Return array containing information about all supported formats
   1.538 +    public static function GetFileFormatArray() {
   1.539 +
   1.540 +        static $format_info = array (
   1.541 +
   1.542 +                // Audio formats
   1.543 +
   1.544 +                // AC-3   - audio      - Dolby AC-3 / Dolby Digital
   1.545 +                'ac3'  => array (
   1.546 +                            'pattern'   => '^\x0B\x77',
   1.547 +                            'group'     => 'audio',
   1.548 +                            'module'    => 'ac3',
   1.549 +                            'mime_type' => 'audio/ac3',
   1.550 +                          ),
   1.551 +
   1.552 +                // AAC  - audio       - Advanced Audio Coding (AAC) - ADIF format
   1.553 +                'adif' => array (
   1.554 +                            'pattern'   => '^ADIF',
   1.555 +                            'group'     => 'audio',
   1.556 +                            'module'    => 'aac_adif',
   1.557 +                            'mime_type' => 'application/octet-stream',
   1.558 +                            'fail_ape'  => 'WARNING',
   1.559 +                          ),
   1.560 +
   1.561 +
   1.562 +                // AAC  - audio       - Advanced Audio Coding (AAC) - ADTS format (very similar to MP3)
   1.563 +                'adts' => array (
   1.564 +                            'pattern'   => '^\xFF[\xF0-\xF1\xF8-\xF9]',
   1.565 +                            'group'     => 'audio',
   1.566 +                            'module'    => 'aac_adts',
   1.567 +                            'mime_type' => 'application/octet-stream',
   1.568 +                            'fail_ape'  => 'WARNING',
   1.569 +                          ),
   1.570 +
   1.571 +
   1.572 +                // AU   - audio       - NeXT/Sun AUdio (AU)
   1.573 +                'au'   => array (
   1.574 +                            'pattern'   => '^\.snd',
   1.575 +                            'group'     => 'audio',
   1.576 +                            'module'    => 'au',
   1.577 +                            'mime_type' => 'audio/basic',
   1.578 +                          ),
   1.579 +
   1.580 +                // AVR  - audio       - Audio Visual Research
   1.581 +                'avr'  => array (
   1.582 +                            'pattern'   => '^2BIT',
   1.583 +                            'group'     => 'audio',
   1.584 +                            'module'    => 'avr',
   1.585 +                            'mime_type' => 'application/octet-stream',
   1.586 +                          ),
   1.587 +
   1.588 +                // BONK - audio       - Bonk v0.9+
   1.589 +                'bonk' => array (
   1.590 +                            'pattern'   => '^\x00(BONK|INFO|META| ID3)',
   1.591 +                            'group'     => 'audio',
   1.592 +                            'module'    => 'bonk',
   1.593 +                            'mime_type' => 'audio/xmms-bonk',
   1.594 +                          ),
   1.595 +
   1.596 +                // DTS  - audio       - Dolby Theatre System
   1.597 +				'dts'  => array(
   1.598 +							'pattern'   => '^\x7F\xFE\x80\x01',
   1.599 +							'group'     => 'audio',
   1.600 +							'module'    => 'dts',
   1.601 +							'mime_type' => 'audio/dts',
   1.602 +						),
   1.603 +
   1.604 +                // FLAC - audio       - Free Lossless Audio Codec
   1.605 +                'flac' => array (
   1.606 +                            'pattern'   => '^fLaC',
   1.607 +                            'group'     => 'audio',
   1.608 +                            'module'    => 'xiph',
   1.609 +                            'mime_type' => 'audio/x-flac',
   1.610 +                          ),
   1.611 +
   1.612 +                // LA   - audio       - Lossless Audio (LA)
   1.613 +                'la'   => array (
   1.614 +                            'pattern'   => '^LA0[2-4]',
   1.615 +                            'group'     => 'audio',
   1.616 +                            'module'    => 'la',
   1.617 +                            'mime_type' => 'application/octet-stream',
   1.618 +                          ),
   1.619 +
   1.620 +                // LPAC - audio       - Lossless Predictive Audio Compression (LPAC)
   1.621 +                'lpac' => array (
   1.622 +                            'pattern'   => '^LPAC',
   1.623 +                            'group'     => 'audio',
   1.624 +                            'module'    => 'lpac',
   1.625 +                            'mime_type' => 'application/octet-stream',
   1.626 +                          ),
   1.627 +
   1.628 +                // MIDI - audio       - MIDI (Musical Instrument Digital Interface)
   1.629 +                'midi' => array (
   1.630 +                            'pattern'   => '^MThd',
   1.631 +                            'group'     => 'audio',
   1.632 +                            'module'    => 'midi',
   1.633 +                            'mime_type' => 'audio/midi',
   1.634 +                          ),
   1.635 +
   1.636 +                // MAC  - audio       - Monkey's Audio Compressor
   1.637 +                'mac'  => array (
   1.638 +                            'pattern'   => '^MAC ',
   1.639 +                            'group'     => 'audio',
   1.640 +                            'module'    => 'monkey',
   1.641 +                            'mime_type' => 'application/octet-stream',
   1.642 +                          ),
   1.643 +
   1.644 +                // MOD  - audio       - MODule (assorted sub-formats)
   1.645 +                'mod'  => array (
   1.646 +                            'pattern'   => '^.{1080}(M.K.|[5-9]CHN|[1-3][0-9]CH)',
   1.647 +                            'mime_type' => 'audio/mod',
   1.648 +                          ),
   1.649 +
   1.650 +                // MOD  - audio       - MODule (Impulse Tracker)
   1.651 +                'it'   => array (
   1.652 +                            'pattern'   => '^IMPM',
   1.653 +                            'mime_type' => 'audio/it',
   1.654 +                          ),
   1.655 +
   1.656 +                // MOD  - audio       - MODule (eXtended Module, various sub-formats)
   1.657 +                'xm'   => array (
   1.658 +                            'pattern'   => '^Extended Module',
   1.659 +                            'mime_type' => 'audio/xm',
   1.660 +                          ),
   1.661 +
   1.662 +                // MOD  - audio       - MODule (ScreamTracker)
   1.663 +                's3m'  => array (
   1.664 +                            'pattern'   => '^.{44}SCRM',
   1.665 +                            'mime_type' => 'audio/s3m',
   1.666 +                          ),
   1.667 +
   1.668 +                // MPC  - audio       - Musepack / MPEGplus SV7+
   1.669 +                'mpc'  => array (
   1.670 +                            'pattern'   => '^(MP\+)',
   1.671 +                            'group'     => 'audio',
   1.672 +                            'module'    => 'mpc',
   1.673 +                            'mime_type' => 'audio/x-musepack',
   1.674 +                          ),
   1.675 +
   1.676 +                // MPC  - audio       - Musepack / MPEGplus SV4-6
   1.677 +                'mpc_old' => array (
   1.678 +                            'pattern'   => '^([\x00\x01\x10\x11\x40\x41\x50\x51\x80\x81\x90\x91\xC0\xC1\xD0\xD1][\x20-37][\x00\x20\x40\x60\x80\xA0\xC0\xE0])',
   1.679 +                            'group'     => 'audio',
   1.680 +                            'module'    => 'mpc_old',
   1.681 +                            'mime_type' => 'application/octet-stream',
   1.682 +                          ),
   1.683 +
   1.684 +
   1.685 +                // MP3  - audio       - MPEG-audio Layer 3 (very similar to AAC-ADTS)
   1.686 +                'mp3'  => array (
   1.687 +                            'pattern'   => '^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]',
   1.688 +                            'group'     => 'audio',
   1.689 +                            'module'    => 'mp3',
   1.690 +                            'mime_type' => 'audio/mpeg',
   1.691 +                          ),
   1.692 +
   1.693 +                // OFR  - audio       - OptimFROG
   1.694 +                'ofr'  => array (
   1.695 +                            'pattern'   => '^(\*RIFF|OFR)',
   1.696 +                            'group'     => 'audio',
   1.697 +                            'module'    => 'optimfrog',
   1.698 +                            'mime_type' => 'application/octet-stream',
   1.699 +                          ),
   1.700 +
   1.701 +                // RKAU - audio       - RKive AUdio compressor
   1.702 +                'rkau' => array (
   1.703 +                            'pattern'   => '^RKA',
   1.704 +                            'group'     => 'audio',
   1.705 +                            'module'    => 'rkau',
   1.706 +                            'mime_type' => 'application/octet-stream',
   1.707 +                          ),
   1.708 +
   1.709 +                // SHN  - audio       - Shorten
   1.710 +                'shn'  => array (
   1.711 +                            'pattern'   => '^ajkg',
   1.712 +                            'group'     => 'audio',
   1.713 +                            'module'    => 'shorten',
   1.714 +                            'mime_type' => 'audio/xmms-shn',
   1.715 +                            'fail_id3'  => 'ERROR',
   1.716 +                            'fail_ape'  => 'ERROR',
   1.717 +                          ),
   1.718 +
   1.719 +                // TTA  - audio       - TTA Lossless Audio Compressor (http://tta.corecodec.org)
   1.720 +                'tta'  => array (
   1.721 +                            'pattern'   => '^TTA',  // could also be '^TTA(\x01|\x02|\x03|2|1)'
   1.722 +                            'group'     => 'audio',
   1.723 +                            'module'    => 'tta',
   1.724 +                            'mime_type' => 'application/octet-stream',
   1.725 +                          ),
   1.726 +
   1.727 +                // VOC  - audio       - Creative Voice (VOC)
   1.728 +                'voc'  => array (
   1.729 +                            'pattern'   => '^Creative Voice File',
   1.730 +                            'group'     => 'audio',
   1.731 +                            'module'    => 'voc',
   1.732 +                            'mime_type' => 'audio/voc',
   1.733 +                          ),
   1.734 +
   1.735 +                // VQF  - audio       - transform-domain weighted interleave Vector Quantization Format (VQF)
   1.736 +                'vqf'  => array (
   1.737 +                            'pattern'   => '^TWIN',
   1.738 +                            'group'     => 'audio',
   1.739 +                            'module'    => 'vqf',
   1.740 +                            'mime_type' => 'application/octet-stream',
   1.741 +                          ),
   1.742 +
   1.743 +                // WV  - audio        - WavPack (v4.0+)
   1.744 +                'vw'  => array(
   1.745 +                            'pattern'   => '^wvpk',
   1.746 +                            'group'     => 'audio',
   1.747 +                            'module'    => 'wavpack',
   1.748 +                            'mime_type' => 'application/octet-stream',
   1.749 +                          ),
   1.750 +
   1.751 +
   1.752 +                // Audio-Video formats
   1.753 +
   1.754 +                // ASF  - audio/video - Advanced Streaming Format, Windows Media Video, Windows Media Audio
   1.755 +                'asf'  => array (
   1.756 +                            'pattern'   => '^\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C',
   1.757 +                            'group'     => 'audio-video',
   1.758 +                            'module'    => 'asf',
   1.759 +                            'mime_type' => 'video/x-ms-asf',
   1.760 +                          ),
   1.761 +
   1.762 +                // BINK  - audio/video - Bink / Smacker
   1.763 +                'bink' => array(
   1.764 +                            'pattern'   => '^(BIK|SMK)',
   1.765 +                            'mime_type' => 'application/octet-stream',
   1.766 +                          ),
   1.767 +
   1.768 +                // FLV  - audio/video - FLash Video
   1.769 +                'flv' => array(
   1.770 +                            'pattern'   => '^FLV\x01',
   1.771 +                            'group'     => 'audio-video',
   1.772 +                            'module'    => 'flv',
   1.773 +                            'mime_type' => 'video/x-flv',
   1.774 +                          ),
   1.775 +
   1.776 +                // MKAV - audio/video - Mastroka
   1.777 +                'matroska' => array (
   1.778 +                            'pattern'   => '^\x1A\x45\xDF\xA3',
   1.779 +                            'mime_type' => 'application/octet-stream',
   1.780 +                          ),
   1.781 +
   1.782 +                // MPEG - audio/video - MPEG (Moving Pictures Experts Group)
   1.783 +                'mpeg' => array (
   1.784 +                            'pattern'   => '^\x00\x00\x01(\xBA|\xB3)',
   1.785 +                            'group'     => 'audio-video',
   1.786 +                            'module'    => 'mpeg',
   1.787 +                            'mime_type' => 'video/mpeg',
   1.788 +                          ),
   1.789 +
   1.790 +                // NSV  - audio/video - Nullsoft Streaming Video (NSV)
   1.791 +                'nsv'  => array (
   1.792 +                            'pattern'   => '^NSV[sf]',
   1.793 +                            'group'     => 'audio-video',
   1.794 +                            'module'    => 'nsv',
   1.795 +                            'mime_type' => 'application/octet-stream',
   1.796 +                          ),
   1.797 +
   1.798 +                // Ogg  - audio/video - Ogg (Ogg Vorbis, OggFLAC, Speex, Ogg Theora(*), Ogg Tarkin(*))
   1.799 +                'ogg'  => array (
   1.800 +                            'pattern'   => '^OggS',
   1.801 +                            'group'     => 'audio',
   1.802 +                            'module'    => 'xiph',
   1.803 +                            'mime_type' => 'application/ogg',
   1.804 +                            'fail_id3'  => 'WARNING',
   1.805 +                            'fail_ape'  => 'WARNING',
   1.806 +                          ),
   1.807 +
   1.808 +                // QT   - audio/video - Quicktime
   1.809 +                'quicktime' => array (
   1.810 +                            'pattern'   => '^.{4}(cmov|free|ftyp|mdat|moov|pnot|skip|wide)',
   1.811 +                            'group'     => 'audio-video',
   1.812 +                            'module'    => 'quicktime',
   1.813 +                            'mime_type' => 'video/quicktime',
   1.814 +                          ),
   1.815 +
   1.816 +                // RIFF - audio/video - Resource Interchange File Format (RIFF) / WAV / AVI / CD-audio / SDSS = renamed variant used by SmartSound QuickTracks (www.smartsound.com) / FORM = Audio Interchange File Format (AIFF)
   1.817 +                'riff' => array (
   1.818 +                            'pattern'   => '^(RIFF|SDSS|FORM)',
   1.819 +                            'group'     => 'audio-video',
   1.820 +                            'module'    => 'riff',
   1.821 +                            'mime_type' => 'audio/x-wave',
   1.822 +                            'fail_ape'  => 'WARNING',
   1.823 +                          ),
   1.824 +
   1.825 +                // Real - audio/video - RealAudio, RealVideo
   1.826 +                'real' => array (
   1.827 +                            'pattern'   => '^(\.RMF|.ra)',
   1.828 +                            'group'     => 'audio-video',
   1.829 +                            'module'    => 'real',
   1.830 +                            'mime_type' => 'audio/x-realaudio',
   1.831 +                          ),
   1.832 +
   1.833 +                // SWF - audio/video - ShockWave Flash
   1.834 +                'swf' => array (
   1.835 +                            'pattern'   => '^(F|C)WS',
   1.836 +                            'group'     => 'audio-video',
   1.837 +                            'module'    => 'swf',
   1.838 +                            'mime_type' => 'application/x-shockwave-flash',
   1.839 +                          ),
   1.840 +
   1.841 +
   1.842 +                // Still-Image formats
   1.843 +
   1.844 +                // BMP  - still image - Bitmap (Windows, OS/2; uncompressed, RLE8, RLE4)
   1.845 +                'bmp'  => array (
   1.846 +                            'pattern'   => '^BM',
   1.847 +                            'group'     => 'graphic',
   1.848 +                            'module'    => 'bmp',
   1.849 +                            'mime_type' => 'image/bmp',
   1.850 +                            'fail_id3'  => 'ERROR',
   1.851 +                            'fail_ape'  => 'ERROR',
   1.852 +                          ),
   1.853 +
   1.854 +                // GIF  - still image - Graphics Interchange Format
   1.855 +                'gif'  => array (
   1.856 +                            'pattern'   => '^GIF',
   1.857 +                            'group'     => 'graphic',
   1.858 +                            'module'    => 'gif',
   1.859 +                            'mime_type' => 'image/gif',
   1.860 +                            'fail_id3'  => 'ERROR',
   1.861 +                            'fail_ape'  => 'ERROR',
   1.862 +                          ),
   1.863 +
   1.864 +                // JPEG - still image - Joint Photographic Experts Group (JPEG)
   1.865 +                'jpeg'  => array (
   1.866 +                            'pattern'   => '^\xFF\xD8\xFF',
   1.867 +                            'group'     => 'graphic',
   1.868 +                            'module'    => 'jpeg',
   1.869 +                            'mime_type' => 'image/jpeg',
   1.870 +                            'fail_id3'  => 'ERROR',
   1.871 +                            'fail_ape'  => 'ERROR',
   1.872 +                          ),
   1.873 +
   1.874 +                // PCD  - still image - Kodak Photo CD
   1.875 +                'pcd'  => array (
   1.876 +                            'pattern'   => '^.{2048}PCD_IPI\x00',
   1.877 +                            'group'     => 'graphic',
   1.878 +                            'module'    => 'pcd',
   1.879 +                            'mime_type' => 'image/x-photo-cd',
   1.880 +                            'fail_id3'  => 'ERROR',
   1.881 +                            'fail_ape'  => 'ERROR',
   1.882 +                          ),
   1.883 +
   1.884 +
   1.885 +                // PNG  - still image - Portable Network Graphics (PNG)
   1.886 +                'png'  => array (
   1.887 +                            'pattern'   => '^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A',
   1.888 +                            'group'     => 'graphic',
   1.889 +                            'module'    => 'png',
   1.890 +                            'mime_type' => 'image/png',
   1.891 +                            'fail_id3'  => 'ERROR',
   1.892 +                            'fail_ape'  => 'ERROR',
   1.893 +                          ),
   1.894 +
   1.895 +
   1.896 +                // SVG  - still image - Scalable Vector Graphics (SVG)
   1.897 +				'svg'  => array(
   1.898 +							'pattern'   => '<!DOCTYPE svg PUBLIC ',
   1.899 +							'mime_type' => 'image/svg+xml',
   1.900 +							'fail_id3'  => 'ERROR',
   1.901 +							'fail_ape'  => 'ERROR',
   1.902 +						),
   1.903 +
   1.904 +
   1.905 +                // TIFF  - still image - Tagged Information File Format (TIFF)
   1.906 +                'tiff' => array (
   1.907 +                            'pattern'   => '^(II\x2A\x00|MM\x00\x2A)',
   1.908 +                            'group'     => 'graphic',
   1.909 +                            'module'    => 'tiff',
   1.910 +                            'mime_type' => 'image/tiff',
   1.911 +                            'fail_id3'  => 'ERROR',
   1.912 +                            'fail_ape'  => 'ERROR',
   1.913 +                          ),
   1.914 +
   1.915 +
   1.916 +                // Data formats
   1.917 +
   1.918 +                'exe'  => array(
   1.919 +                            'pattern'   => '^MZ',
   1.920 +                            'mime_type' => 'application/octet-stream',
   1.921 +                            'fail_id3'  => 'ERROR',
   1.922 +                            'fail_ape'  => 'ERROR',
   1.923 +                          ),
   1.924 +
   1.925 +                // ISO  - data        - International Standards Organization (ISO) CD-ROM Image
   1.926 +                'iso'  => array (
   1.927 +                            'pattern'   => '^.{32769}CD001',
   1.928 +                            'group'     => 'misc',
   1.929 +                            'module'    => 'iso',
   1.930 +                            'mime_type' => 'application/octet-stream',
   1.931 +                            'fail_id3'  => 'ERROR',
   1.932 +                            'fail_ape'  => 'ERROR',
   1.933 +                          ),
   1.934 +
   1.935 +                // RAR  - data        - RAR compressed data
   1.936 +                'rar'  => array(
   1.937 +                            'pattern'   => '^Rar\!',
   1.938 +                            'mime_type' => 'application/octet-stream',
   1.939 +                            'fail_id3'  => 'ERROR',
   1.940 +                            'fail_ape'  => 'ERROR',
   1.941 +                          ),
   1.942 +
   1.943 +                // SZIP - audio       - SZIP compressed data
   1.944 +                'szip' => array (
   1.945 +                            'pattern'   => '^SZ\x0A\x04',
   1.946 +                            'group'     => 'archive',
   1.947 +                            'module'    => 'szip',
   1.948 +                            'mime_type' => 'application/octet-stream',
   1.949 +                            'fail_id3'  => 'ERROR',
   1.950 +                            'fail_ape'  => 'ERROR',
   1.951 +                          ),
   1.952 +
   1.953 +                // TAR  - data        - TAR compressed data
   1.954 +                'tar'  => array(
   1.955 +                            'pattern'   => '^.{100}[0-9\x20]{7}\x00[0-9\x20]{7}\x00[0-9\x20]{7}\x00[0-9\x20\x00]{12}[0-9\x20\x00]{12}',
   1.956 +                            'group'     => 'archive',
   1.957 +                            'module'    => 'tar',
   1.958 +                            'mime_type' => 'application/x-tar',
   1.959 +                            'fail_id3'  => 'ERROR',
   1.960 +                            'fail_ape'  => 'ERROR',
   1.961 +                          ),
   1.962 +
   1.963 +                // GZIP  - data        - GZIP compressed data
   1.964 +                'gz'  => array(
   1.965 +                            'pattern'   => '^\x1F\x8B\x08',
   1.966 +                            'group'     => 'archive',
   1.967 +                            'module'    => 'gzip',
   1.968 +                            'mime_type' => 'application/x-gzip',
   1.969 +                            'fail_id3'  => 'ERROR',
   1.970 +                            'fail_ape'  => 'ERROR',
   1.971 +                          ),
   1.972 +
   1.973 +
   1.974 +                // ZIP  - data        - ZIP compressed data
   1.975 +                'zip'  => array (
   1.976 +                            'pattern'   => '^PK\x03\x04',
   1.977 +                            'group'     => 'archive',
   1.978 +                            'module'    => 'zip',
   1.979 +                            'mime_type' => 'application/zip',
   1.980 +                            'fail_id3'  => 'ERROR',
   1.981 +                            'fail_ape'  => 'ERROR',
   1.982 +                          ),
   1.983 +
   1.984 +
   1.985 +                // PAR2 - data        - Parity Volume Set Specification 2.0
   1.986 +                'par2' => array (
   1.987 +                			'pattern'   => '^PAR2\x00PKT',
   1.988 +							'mime_type' => 'application/octet-stream',
   1.989 +							'fail_id3'  => 'ERROR',
   1.990 +							'fail_ape'  => 'ERROR',
   1.991 +						),
   1.992 +
   1.993 +
   1.994 +                 // PDF  - data       - Portable Document Format
   1.995 +                 'pdf' => array(
   1.996 +                            'pattern'   => '^\x25PDF',
   1.997 +                            'mime_type' => 'application/pdf',
   1.998 +                            'fail_id3'  => 'ERROR',
   1.999 +                            'fail_ape'  => 'ERROR',
  1.1000 +                           ),
  1.1001 +
  1.1002 +                 // DOC  - data       - Microsoft Word
  1.1003 +                 'msoffice' => array(
  1.1004 +                            'pattern'   => '^\xD0\xCF\x11\xE0', // D0CF11E == DOCFILE == Microsoft Office Document
  1.1005 +                            'mime_type' => 'application/octet-stream',
  1.1006 +                            'fail_id3'  => 'ERROR',
  1.1007 +                            'fail_ape'  => 'ERROR',
  1.1008 +                          ),
  1.1009 +            );
  1.1010 +
  1.1011 +        return $format_info;
  1.1012 +    }
  1.1013 +
  1.1014 +
  1.1015 +
  1.1016 +    // Recursive over array - converts array to $encoding charset from $this->encoding
  1.1017 +    function CharConvert(&$array, $encoding) {
  1.1018 +
  1.1019 +        // Identical encoding - end here
  1.1020 +        if ($encoding == $this->encoding) {
  1.1021 +            return;
  1.1022 +        }
  1.1023 +
  1.1024 +        // Loop thru array
  1.1025 +        foreach ($array as $key => $value) {
  1.1026 +
  1.1027 +            // Go recursive
  1.1028 +            if (is_array($value)) {
  1.1029 +                $this->CharConvert($array[$key], $encoding);
  1.1030 +            }
  1.1031 +
  1.1032 +            // Convert string
  1.1033 +            elseif (is_string($value)) {
  1.1034 +                $array[$key] = $this->iconv($encoding, $this->encoding, $value);
  1.1035 +            }
  1.1036 +        }
  1.1037 +    }
  1.1038 +
  1.1039 +
  1.1040 +
  1.1041 +    // Convert and copy tags
  1.1042 +    protected function HandleAllTags() {
  1.1043 +
  1.1044 +        // Key name => array (tag name, character encoding)
  1.1045 +        static $tags = array (
  1.1046 +            'asf'       => array ('asf',           'UTF-16LE'),
  1.1047 +            'midi'      => array ('midi',          'ISO-8859-1'),
  1.1048 +            'nsv'       => array ('nsv',           'ISO-8859-1'),
  1.1049 +            'ogg'       => array ('vorbiscomment', 'UTF-8'),
  1.1050 +            'png'       => array ('png',           'UTF-8'),
  1.1051 +            'tiff'      => array ('tiff',          'ISO-8859-1'),
  1.1052 +            'quicktime' => array ('quicktime',     'ISO-8859-1'),
  1.1053 +            'real'      => array ('real',          'ISO-8859-1'),
  1.1054 +            'vqf'       => array ('vqf',           'ISO-8859-1'),
  1.1055 +            'zip'       => array ('zip',           'ISO-8859-1'),
  1.1056 +            'riff'      => array ('riff',          'ISO-8859-1'),
  1.1057 +            'lyrics3'   => array ('lyrics3',       'ISO-8859-1'),
  1.1058 +            'id3v1'     => array ('id3v1',         ''),            // change below - cannot assign variable to static array
  1.1059 +            'id3v2'     => array ('id3v2',         'UTF-8'),       // module converts all frames to UTF-8
  1.1060 +            'ape'       => array ('ape',           'UTF-8')
  1.1061 +        );
  1.1062 +        $tags['id3v1'][1] = $this->encoding_id3v1;
  1.1063 +
  1.1064 +        // Loop thru tags array
  1.1065 +        foreach ($tags as $comment_name => $tag_name_encoding_array) {
  1.1066 +            list($tag_name, $encoding) = $tag_name_encoding_array;
  1.1067 +
  1.1068 +            // Fill in default encoding type if not already present
  1.1069 +            @$this->info[$comment_name]  and  $this->info[$comment_name]['encoding'] = $encoding;
  1.1070 +
  1.1071 +            // Copy comments if key name set
  1.1072 +            if (@$this->info[$comment_name]['comments']) {
  1.1073 +
  1.1074 +                foreach ($this->info[$comment_name]['comments'] as $tag_key => $value_array) {
  1.1075 +                    foreach ($value_array as $key => $value) {
  1.1076 +                        if (strlen(trim($value)) > 0) {
  1.1077 +                            $this->info['tags'][$tag_name][trim($tag_key)][] = $value; // do not trim!! Unicode characters will get mangled if trailing nulls are removed!
  1.1078 +                        }
  1.1079 +                    }
  1.1080 +
  1.1081 +                }
  1.1082 +
  1.1083 +                if (!@$this->info['tags'][$tag_name]) {
  1.1084 +                    // comments are set but contain nothing but empty strings, so skip
  1.1085 +                    continue;
  1.1086 +                }
  1.1087 +
  1.1088 +                $this->CharConvert($this->info['tags'][$tag_name], $encoding);
  1.1089 +            }
  1.1090 +        }
  1.1091 +
  1.1092 +
  1.1093 +        // Merge comments from ['tags'] into common ['comments']
  1.1094 +        if (@$this->info['tags']) {
  1.1095 +
  1.1096 +            foreach ($this->info['tags'] as $tag_type => $tag_array) {
  1.1097 +
  1.1098 +                foreach ($tag_array as $tag_name => $tagdata) {
  1.1099 +
  1.1100 +                    foreach ($tagdata as $key => $value) {
  1.1101 +
  1.1102 +                        if (!empty($value)) {
  1.1103 +
  1.1104 +                            if (empty($this->info['comments'][$tag_name])) {
  1.1105 +
  1.1106 +                                // fall through and append value
  1.1107 +                            }
  1.1108 +                            elseif ($tag_type == 'id3v1') {
  1.1109 +
  1.1110 +                                $new_value_length = strlen(trim($value));
  1.1111 +                                foreach ($this->info['comments'][$tag_name] as $existing_key => $existing_value) {
  1.1112 +                                    $old_value_length = strlen(trim($existing_value));
  1.1113 +                                    if (($new_value_length <= $old_value_length) && (substr($existing_value, 0, $new_value_length) == trim($value))) {
  1.1114 +                                        // new value is identical but shorter-than (or equal-length to) one already in comments - skip
  1.1115 +                                        break 2;
  1.1116 +                                    }
  1.1117 +                                }
  1.1118 +                            }
  1.1119 +                            else {
  1.1120 +
  1.1121 +                                $new_value_length = strlen(trim($value));
  1.1122 +                                foreach ($this->info['comments'][$tag_name] as $existing_key => $existing_value) {
  1.1123 +                                    $old_value_length = strlen(trim($existing_value));
  1.1124 +                                    if (($new_value_length > $old_value_length) && (substr(trim($value), 0, strlen($existing_value)) == $existing_value)) {
  1.1125 +                                        $this->info['comments'][$tag_name][$existing_key] = trim($value);
  1.1126 +                                        break 2;
  1.1127 +                                    }
  1.1128 +                                }
  1.1129 +                            }
  1.1130 +
  1.1131 +                            if (empty($this->info['comments'][$tag_name]) || !in_array(trim($value), $this->info['comments'][$tag_name])) {
  1.1132 +                                $this->info['comments'][$tag_name][] = trim($value);
  1.1133 +                            }
  1.1134 +                        }
  1.1135 +                    }
  1.1136 +                }
  1.1137 +            }
  1.1138 +        }
  1.1139 +
  1.1140 +        return true;
  1.1141 +    }
  1.1142 +}
  1.1143 +
  1.1144 +
  1.1145 +abstract class getid3_handler
  1.1146 +{
  1.1147 +
  1.1148 +    protected $getid3;                          // pointer
  1.1149 +
  1.1150 +    protected $data_string_flag = false;        // analyzing filepointer or string
  1.1151 +    protected $data_string;                     // string to analyze
  1.1152 +    protected $data_string_position = 0;        // seek position in string
  1.1153 +
  1.1154 +
  1.1155 +    public function __construct(getID3 $getid3) {
  1.1156 +
  1.1157 +        $this->getid3 = $getid3;
  1.1158 +    }
  1.1159 +
  1.1160 +
  1.1161 +    // Analyze from file pointer
  1.1162 +    abstract public function Analyze();
  1.1163 +
  1.1164 +
  1.1165 +
  1.1166 +    // Analyze from string instead
  1.1167 +    public function AnalyzeString(&$string) {
  1.1168 +
  1.1169 +        // Enter string mode
  1.1170 +        $this->data_string_flag = true;
  1.1171 +        $this->data_string      = $string;
  1.1172 +
  1.1173 +        // Save info
  1.1174 +        $saved_avdataoffset = $this->getid3->info['avdataoffset'];
  1.1175 +        $saved_avdataend    = $this->getid3->info['avdataend'];
  1.1176 +        $saved_filesize     = $this->getid3->info['filesize'];
  1.1177 +
  1.1178 +        // Reset some info
  1.1179 +        $this->getid3->info['avdataoffset'] = 0;
  1.1180 +        $this->getid3->info['avdataend']    = $this->getid3->info['filesize'] = strlen($string);
  1.1181 +
  1.1182 +        // Analyze
  1.1183 +        $this->Analyze();
  1.1184 +
  1.1185 +        // Restore some info
  1.1186 +        $this->getid3->info['avdataoffset'] = $saved_avdataoffset;
  1.1187 +        $this->getid3->info['avdataend']    = $saved_avdataend;
  1.1188 +        $this->getid3->info['filesize']     = $saved_filesize;
  1.1189 +
  1.1190 +        // Exit string mode
  1.1191 +        $this->data_string_flag = false;
  1.1192 +    }
  1.1193 +
  1.1194 +
  1.1195 +    protected function ftell() {
  1.1196 +
  1.1197 +        if ($this->data_string_flag) {
  1.1198 +            return $this->data_string_position;
  1.1199 +        }
  1.1200 +        return ftell($this->getid3->fp);
  1.1201 +    }
  1.1202 +
  1.1203 +
  1.1204 +    protected function fread($bytes) {
  1.1205 +
  1.1206 +        if ($this->data_string_flag) {
  1.1207 +            $this->data_string_position += $bytes;
  1.1208 +            return substr($this->data_string, $this->data_string_position - $bytes, $bytes);
  1.1209 +        }
  1.1210 +        return fread($this->getid3->fp, $bytes);
  1.1211 +    }
  1.1212 +
  1.1213 +
  1.1214 +    protected function fseek($bytes, $whence = SEEK_SET) {
  1.1215 +
  1.1216 +        if ($this->data_string_flag) {
  1.1217 +            switch ($whence) {
  1.1218 +                case SEEK_SET:
  1.1219 +                    $this->data_string_position = $bytes;
  1.1220 +                    return;
  1.1221 +
  1.1222 +                case SEEK_CUR:
  1.1223 +                    $this->data_string_position += $bytes;
  1.1224 +                    return;
  1.1225 +
  1.1226 +                case SEEK_END:
  1.1227 +                    $this->data_string_position = strlen($this->data_string) + $bytes;
  1.1228 +                    return;
  1.1229 +            }
  1.1230 +        }
  1.1231 +        return fseek($this->getid3->fp, $bytes, $whence);
  1.1232 +    }
  1.1233 +
  1.1234 +}
  1.1235 +
  1.1236 +
  1.1237 +
  1.1238 +
  1.1239 +abstract class getid3_handler_write
  1.1240 +{
  1.1241 +    protected $filename;
  1.1242 +    protected $user_abort;
  1.1243 +
  1.1244 +    private $fp_lock;
  1.1245 +    private $owner;
  1.1246 +    private $group;
  1.1247 +    private $perms;
  1.1248 +
  1.1249 +
  1.1250 +    public function __construct($filename) {
  1.1251 +
  1.1252 +        if (!file_exists($filename)) {
  1.1253 +            throw new getid3_exception('File does not exist: "' . $filename . '"');
  1.1254 +        }
  1.1255 +
  1.1256 +        if (!is_writeable($filename)) {
  1.1257 +            throw new getid3_exception('File is not writeable: "' . $filename . '"');
  1.1258 +        }
  1.1259 +
  1.1260 +        if (!is_writeable(dirname($filename))) {
  1.1261 +            throw new getid3_exception('Directory is not writeable: ' . dirname($filename) . ' (need to write lock file).');
  1.1262 +        }
  1.1263 +
  1.1264 +        $this->user_abort = ignore_user_abort(true);
  1.1265 +
  1.1266 +        $this->fp_lock = fopen($filename . '.getid3.lock', 'w');
  1.1267 +        flock($this->fp_lock, LOCK_EX);
  1.1268 +
  1.1269 +        $this->filename = $filename;
  1.1270 +    }
  1.1271 +
  1.1272 +
  1.1273 +    public function __destruct() {
  1.1274 +
  1.1275 +        flock($this->fp_lock, LOCK_UN);
  1.1276 +        fclose($this->fp_lock);
  1.1277 +        unlink($this->filename . '.getid3.lock');
  1.1278 +
  1.1279 +        ignore_user_abort($this->user_abort);
  1.1280 +    }
  1.1281 +    
  1.1282 +    
  1.1283 +    protected function save_permissions() {
  1.1284 +        
  1.1285 +        $this->owner = fileowner($this->filename);
  1.1286 +        $this->group = filegroup($this->filename);
  1.1287 +        $this->perms = fileperms($this->filename);
  1.1288 +    }
  1.1289 +    
  1.1290 +    
  1.1291 +    protected function restore_permissions() {
  1.1292 +        
  1.1293 +        @chown($this->filename, $this->owner);
  1.1294 +        @chgrp($this->filename, $this->group);
  1.1295 +        @chmod($this->filename, $this->perms);
  1.1296 +    }
  1.1297 +
  1.1298 +
  1.1299 +    abstract public function read();
  1.1300 +
  1.1301 +    abstract public function write();
  1.1302 +
  1.1303 +    abstract public function remove();
  1.1304 +
  1.1305 +}
  1.1306 +
  1.1307 +
  1.1308 +
  1.1309 +
  1.1310 +class getid3_exception extends Exception
  1.1311 +{
  1.1312 +    public $message;
  1.1313 +
  1.1314 +}
  1.1315 +
  1.1316 +
  1.1317 +
  1.1318 +
  1.1319 +class getid3_lib
  1.1320 +{
  1.1321 +
  1.1322 +    // Convert Little Endian byte string to int - max 32 bits
  1.1323 +    public static function LittleEndian2Int($byte_word, $signed = false) {
  1.1324 +
  1.1325 +        return getid3_lib::BigEndian2Int(strrev($byte_word), $signed);
  1.1326 +    }
  1.1327 +
  1.1328 +
  1.1329 +
  1.1330 +    // Convert number to Little Endian byte string
  1.1331 +    public static function LittleEndian2String($number, $minbytes=1, $synchsafe=false) {
  1.1332 +        $intstring = '';
  1.1333 +        while ($number > 0) {
  1.1334 +            if ($synchsafe) {
  1.1335 +                $intstring = $intstring.chr($number & 127);
  1.1336 +                $number >>= 7;
  1.1337 +            } else {
  1.1338 +                $intstring = $intstring.chr($number & 255);
  1.1339 +                $number >>= 8;
  1.1340 +            }
  1.1341 +        }
  1.1342 +        return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT);
  1.1343 +    }
  1.1344 +
  1.1345 +
  1.1346 +
  1.1347 +    // Convert Big Endian byte string to int - max 32 bits
  1.1348 +    public static function BigEndian2Int($byte_word, $signed = false) {
  1.1349 +
  1.1350 +        $int_value = 0;
  1.1351 +        $byte_wordlen = strlen($byte_word);
  1.1352 +
  1.1353 +        for ($i = 0; $i < $byte_wordlen; $i++) {
  1.1354 +            $int_value += ord($byte_word{$i}) * pow(256, ($byte_wordlen - 1 - $i));
  1.1355 +        }
  1.1356 +
  1.1357 +        if ($signed) {
  1.1358 +            $sign_mask_bit = 0x80 << (8 * ($byte_wordlen - 1));
  1.1359 +            if ($int_value & $sign_mask_bit) {
  1.1360 +                $int_value = 0 - ($int_value & ($sign_mask_bit - 1));
  1.1361 +            }
  1.1362 +        }
  1.1363 +
  1.1364 +        return $int_value;
  1.1365 +    }
  1.1366 +
  1.1367 +
  1.1368 +
  1.1369 +    // Convert Big Endian byte sybc safe string to int - max 32 bits
  1.1370 +    public static function BigEndianSyncSafe2Int($byte_word) {
  1.1371 +
  1.1372 +        $int_value = 0;
  1.1373 +        $byte_wordlen = strlen($byte_word);
  1.1374 +
  1.1375 +        // disregard MSB, effectively 7-bit bytes
  1.1376 +        for ($i = 0; $i < $byte_wordlen; $i++) {
  1.1377 +            $int_value = $int_value | (ord($byte_word{$i}) & 0x7F) << (($byte_wordlen - 1 - $i) * 7);
  1.1378 +        }
  1.1379 +        return $int_value;
  1.1380 +    }
  1.1381 +
  1.1382 +
  1.1383 +
  1.1384 +    // Convert Big Endian byte string to bit string
  1.1385 +    public static function BigEndian2Bin($byte_word) {
  1.1386 +
  1.1387 +        $bin_value = '';
  1.1388 +        $byte_wordlen = strlen($byte_word);
  1.1389 +        for ($i = 0; $i < $byte_wordlen; $i++) {
  1.1390 +            $bin_value .= str_pad(decbin(ord($byte_word{$i})), 8, '0', STR_PAD_LEFT);
  1.1391 +        }
  1.1392 +        return $bin_value;
  1.1393 +    }
  1.1394 +
  1.1395 +
  1.1396 +
  1.1397 +    public static function BigEndian2Float($byte_word) {
  1.1398 +
  1.1399 +		// ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic
  1.1400 +		// http://www.psc.edu/general/software/packages/ieee/ieee.html
  1.1401 +		// http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html
  1.1402 +
  1.1403 +		$bit_word = getid3_lib::BigEndian2Bin($byte_word);
  1.1404 +		if (!$bit_word) {
  1.1405 +            return 0;
  1.1406 +        }
  1.1407 +		$sign_bit = $bit_word{0};
  1.1408 +
  1.1409 +		switch (strlen($byte_word) * 8) {
  1.1410 +			case 32:
  1.1411 +				$exponent_bits = 8;
  1.1412 +				$fraction_bits = 23;
  1.1413 +				break;
  1.1414 +
  1.1415 +			case 64:
  1.1416 +				$exponent_bits = 11;
  1.1417 +				$fraction_bits = 52;
  1.1418 +				break;
  1.1419 +
  1.1420 +			case 80:
  1.1421 +				// 80-bit Apple SANE format
  1.1422 +				// http://www.mactech.com/articles/mactech/Vol.06/06.01/SANENormalized/
  1.1423 +				$exponent_string = substr($bit_word, 1, 15);
  1.1424 +				$is_normalized = intval($bit_word{16});
  1.1425 +				$fraction_string = substr($bit_word, 17, 63);
  1.1426 +				$exponent = pow(2, getid3_lib::Bin2Dec($exponent_string) - 16383);
  1.1427 +				$fraction = $is_normalized + getid3_lib::DecimalBinary2Float($fraction_string);
  1.1428 +				$float_value = $exponent * $fraction;
  1.1429 +				if ($sign_bit == '1') {
  1.1430 +					$float_value *= -1;
  1.1431 +				}
  1.1432 +				return $float_value;
  1.1433 +				break;
  1.1434 +
  1.1435 +			default:
  1.1436 +				return false;
  1.1437 +				break;
  1.1438 +		}
  1.1439 +		$exponent_string = substr($bit_word, 1, $exponent_bits);
  1.1440 +		$fraction_string = substr($bit_word, $exponent_bits + 1, $fraction_bits);
  1.1441 +		$exponent = bindec($exponent_string);
  1.1442 +		$fraction = bindec($fraction_string);
  1.1443 +
  1.1444 +		if (($exponent == (pow(2, $exponent_bits) - 1)) && ($fraction != 0)) {
  1.1445 +			// Not a Number
  1.1446 +			$float_value = false;
  1.1447 +		} elseif (($exponent == (pow(2, $exponent_bits) - 1)) && ($fraction == 0)) {
  1.1448 +			if ($sign_bit == '1') {
  1.1449 +				$float_value = '-infinity';
  1.1450 +			} else {
  1.1451 +				$float_value = '+infinity';
  1.1452 +			}
  1.1453 +		} elseif (($exponent == 0) && ($fraction == 0)) {
  1.1454 +			if ($sign_bit == '1') {
  1.1455 +				$float_value = -0;
  1.1456 +			} else {
  1.1457 +				$float_value = 0;
  1.1458 +			}
  1.1459 +			$float_value = ($sign_bit ? 0 : -0);
  1.1460 +		} elseif (($exponent == 0) && ($fraction != 0)) {
  1.1461 +			// These are 'unnormalized' values
  1.1462 +			$float_value = pow(2, (-1 * (pow(2, $exponent_bits - 1) - 2))) * getid3_lib::DecimalBinary2Float($fraction_string);
  1.1463 +			if ($sign_bit == '1') {
  1.1464 +				$float_value *= -1;
  1.1465 +			}
  1.1466 +		} elseif ($exponent != 0) {
  1.1467 +			$float_value = pow(2, ($exponent - (pow(2, $exponent_bits - 1) - 1))) * (1 + getid3_lib::DecimalBinary2Float($fraction_string));
  1.1468 +			if ($sign_bit == '1') {
  1.1469 +				$float_value *= -1;
  1.1470 +			}
  1.1471 +		}
  1.1472 +		return (float) $float_value;
  1.1473 +	}
  1.1474 +
  1.1475 +
  1.1476 +
  1.1477 +	public static function LittleEndian2Float($byte_word) {
  1.1478 +
  1.1479 +		return getid3_lib::BigEndian2Float(strrev($byte_word));
  1.1480 +	}
  1.1481 +
  1.1482 +
  1.1483 +
  1.1484 +	public static function DecimalBinary2Float($binary_numerator) {
  1.1485 +		$numerator   = bindec($binary_numerator);
  1.1486 +		$denominator = bindec('1'.str_repeat('0', strlen($binary_numerator)));
  1.1487 +		return ($numerator / $denominator);
  1.1488 +	}
  1.1489 +
  1.1490 +
  1.1491 +	public static function PrintHexBytes($string, $hex=true, $spaces=true, $html_safe=true) {
  1.1492 +
  1.1493 +        $return_string = '';
  1.1494 +        for ($i = 0; $i < strlen($string); $i++) {
  1.1495 +            if ($hex) {
  1.1496 +                $return_string .= str_pad(dechex(ord($string{$i})), 2, '0', STR_PAD_LEFT);
  1.1497 +            } else {
  1.1498 +                $return_string .= ' '.(ereg("[\x20-\x7E]", $string{$i}) ? $string{$i} : '');
  1.1499 +            }
  1.1500 +            if ($spaces) {
  1.1501 +                $return_string .= ' ';
  1.1502 +            }
  1.1503 +        }
  1.1504 +        if ($html_safe) {
  1.1505 +            $return_string = htmlentities($return_string);
  1.1506 +        }
  1.1507 +        return $return_string;
  1.1508 +    }
  1.1509 +
  1.1510 +
  1.1511 +
  1.1512 +    // Process header data string - read several values with algorithm and add to target
  1.1513 +    //   algorithm is one one the getid3_lib::Something2Something() function names
  1.1514 +    //   parts_array is  index => length    -  $target[index] = algorithm(substring(data))
  1.1515 +    //   - OR just substring(data) if length is negative!
  1.1516 +    //  indexes == 'IGNORE**' are ignored
  1.1517 +
  1.1518 +    public static function ReadSequence($algorithm, &$target, &$data, $offset, $parts_array) {
  1.1519 +
  1.1520 +        // Loop thru $parts_array
  1.1521 +        foreach ($parts_array as $target_string => $length) {
  1.1522 +
  1.1523 +            // Add to target
  1.1524 +            if (!strstr($target_string, 'IGNORE')) {
  1.1525 +
  1.1526 +                // substr(....length)
  1.1527 +                if ($length < 0) {
  1.1528 +                    $target[$target_string] = substr($data, $offset, -$length);
  1.1529 +                }
  1.1530 +
  1.1531 +                // algorithm(substr(...length))
  1.1532 +                else {
  1.1533 +                    $target[$target_string] = getid3_lib::$algorithm(substr($data, $offset, $length));
  1.1534 +                }
  1.1535 +            }
  1.1536 +
  1.1537 +            // Move pointer
  1.1538 +            $offset += abs($length);
  1.1539 +        }
  1.1540 +    }
  1.1541 +
  1.1542 +}
  1.1543 +
  1.1544 +
  1.1545 +
  1.1546 +class getid3_lib_replaygain
  1.1547 +{
  1.1548 +
  1.1549 +    public static function NameLookup($name_code) {
  1.1550 +
  1.1551 +        static $lookup = array (
  1.1552 +            0 => 'not set',
  1.1553 +            1 => 'Track Gain Adjustment',
  1.1554 +            2 => 'Album Gain Adjustment'
  1.1555 +        );
  1.1556 +
  1.1557 +        return @$lookup[$name_code];
  1.1558 +    }
  1.1559 +
  1.1560 +
  1.1561 +
  1.1562 +    public static function OriginatorLookup($originator_code) {
  1.1563 +
  1.1564 +        static $lookup = array (
  1.1565 +            0 => 'unspecified',
  1.1566 +            1 => 'pre-set by artist/producer/mastering engineer',
  1.1567 +            2 => 'set by user',
  1.1568 +            3 => 'determined automatically'
  1.1569 +        );
  1.1570 +
  1.1571 +        return @$lookup[$originator_code];
  1.1572 +    }
  1.1573 +
  1.1574 +
  1.1575 +
  1.1576 +    public static function AdjustmentLookup($raw_adjustment, $sign_bit) {
  1.1577 +
  1.1578 +        return (float)$raw_adjustment / 10 * ($sign_bit == 1 ? -1 : 1);
  1.1579 +    }
  1.1580 +
  1.1581 +
  1.1582 +
  1.1583 +    public static function GainString($name_code, $originator_code, $replaygain) {
  1.1584 +
  1.1585 +        $sign_bit = $replaygain < 0 ? 1 : 0;
  1.1586 +
  1.1587 +        $stored_replaygain = intval(round($replaygain * 10));
  1.1588 +        $gain_string  = str_pad(decbin($name_code), 3, '0', STR_PAD_LEFT);
  1.1589 +        $gain_string .= str_pad(decbin($originator_code), 3, '0', STR_PAD_LEFT);
  1.1590 +        $gain_string .= $sign_bit;
  1.1591 +        $gain_string .= str_pad(decbin($stored_replaygain), 9, '0', STR_PAD_LEFT);
  1.1592 +
  1.1593 +        return $gain_string;
  1.1594 +    }
  1.1595 +
  1.1596 +}
  1.1597 +
  1.1598 +
  1.1599 +
  1.1600 +
  1.1601 +?>
  1.1602 \ No newline at end of file