[pLog-svn] r7238 - plog/branches/lifetype-1.2/class/gallery/getid3

jondaley at devel.lifetype.net jondaley at devel.lifetype.net
Wed Jul 15 03:59:27 EDT 2020


Author: jondaley
Date: 2020-07-15 03:59:26 -0400 (Wed, 15 Jul 2020)
New Revision: 7238

Added:
   plog/branches/lifetype-1.2/class/gallery/getid3/extension.cache.mysqli.php
   plog/branches/lifetype-1.2/class/gallery/getid3/extension.cache.sqlite3.php
   plog/branches/lifetype-1.2/class/gallery/getid3/module.archive.hpk.php
   plog/branches/lifetype-1.2/class/gallery/getid3/module.archive.xz.php
   plog/branches/lifetype-1.2/class/gallery/getid3/module.audio-video.ivf.php
   plog/branches/lifetype-1.2/class/gallery/getid3/module.audio-video.ts.php
   plog/branches/lifetype-1.2/class/gallery/getid3/module.audio-video.wtv.php
   plog/branches/lifetype-1.2/class/gallery/getid3/module.audio.aa.php
   plog/branches/lifetype-1.2/class/gallery/getid3/module.audio.amr.php
   plog/branches/lifetype-1.2/class/gallery/getid3/module.audio.dsdiff.php
   plog/branches/lifetype-1.2/class/gallery/getid3/module.audio.dsf.php
   plog/branches/lifetype-1.2/class/gallery/getid3/module.audio.dss.php
   plog/branches/lifetype-1.2/class/gallery/getid3/module.audio.dts.php
   plog/branches/lifetype-1.2/class/gallery/getid3/module.audio.tak.php
   plog/branches/lifetype-1.2/class/gallery/getid3/module.graphic.efax.php
   plog/branches/lifetype-1.2/class/gallery/getid3/module.misc.cue.php
   plog/branches/lifetype-1.2/class/gallery/getid3/module.misc.msoffice.php
   plog/branches/lifetype-1.2/class/gallery/getid3/module.misc.par2.php
   plog/branches/lifetype-1.2/class/gallery/getid3/module.misc.pdf.php
   plog/branches/lifetype-1.2/class/gallery/getid3/module.tag.xmp.php
Log:
forgot to check in the new files in the new version of getid3

Added: plog/branches/lifetype-1.2/class/gallery/getid3/extension.cache.mysqli.php
===================================================================
--- plog/branches/lifetype-1.2/class/gallery/getid3/extension.cache.mysqli.php	                        (rev 0)
+++ plog/branches/lifetype-1.2/class/gallery/getid3/extension.cache.mysqli.php	2020-07-15 07:59:26 UTC (rev 7238)
@@ -0,0 +1,263 @@
+<?php
+
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org>               //
+//  available at https://github.com/JamesHeinrich/getID3       //
+//            or https://www.getid3.org                        //
+//            or http://getid3.sourceforge.net                 //
+//                                                             //
+// extension.cache.mysqli.php - part of getID3()               //
+// Please see readme.txt for more information                  //
+//                                                             //
+/////////////////////////////////////////////////////////////////
+//                                                             //
+// This extension written by Allan Hansen <ahØartemis*dk>      //
+// Table name mod by Carlo Capocasa <calroØcarlocapocasa*com>  //
+//                                                            ///
+/////////////////////////////////////////////////////////////////
+
+
+/**
+* This is a caching extension for getID3(). It works the exact same
+* way as the getID3 class, but return cached information very fast
+*
+* Example:  (see also demo.cache.mysql.php in /demo/)
+*
+*    Normal getID3 usage (example):
+*
+*       require_once 'getid3/getid3.php';
+*       $getID3 = new getID3;
+*       $getID3->encoding = 'UTF-8';
+*       $info1 = $getID3->analyze('file1.flac');
+*       $info2 = $getID3->analyze('file2.wv');
+*
+*    getID3_cached usage:
+*
+*       require_once 'getid3/getid3.php';
+*       require_once 'getid3/getid3/extension.cache.mysqli.php';
+*       // 5th parameter (tablename) is optional, default is 'getid3_cache'
+*       $getID3 = new getID3_cached_mysqli('localhost', 'database', 'username', 'password', 'tablename');
+*       $getID3->encoding = 'UTF-8';
+*       $info1 = $getID3->analyze('file1.flac');
+*       $info2 = $getID3->analyze('file2.wv');
+*
+*
+* Supported Cache Types    (this extension)
+*
+*   SQL Databases:
+*
+*   cache_type          cache_options
+*   -------------------------------------------------------------------
+*   mysqli              host, database, username, password
+*
+*
+*   DBM-Style Databases:    (use extension.cache.dbm)
+*
+*   cache_type          cache_options
+*   -------------------------------------------------------------------
+*   gdbm                dbm_filename, lock_filename
+*   ndbm                dbm_filename, lock_filename
+*   db2                 dbm_filename, lock_filename
+*   db3                 dbm_filename, lock_filename
+*   db4                 dbm_filename, lock_filename  (PHP5 required)
+*
+*   PHP must have write access to both dbm_filename and lock_filename.
+*
+*
+* Recommended Cache Types
+*
+*   Infrequent updates, many reads      any DBM
+*   Frequent updates                    mysqli
+*/
+
+class getID3_cached_mysqli extends getID3
+{
+	/**
+	 * @var mysqli
+	 */
+	private $mysqli;
+
+	/**
+	 * @var mysqli_result
+	 */
+	private $cursor;
+
+	/**
+	 * @var string
+	 */
+	private $table;
+
+	/**
+	 * @var bool
+	 */
+	private $db_structure_check;
+
+
+	/**
+	 * constructor - see top of this file for cache type and cache_options
+	 *
+	 * @param string $host
+	 * @param string $database
+	 * @param string $username
+	 * @param string $password
+	 * @param string $table
+	 *
+	 * @throws Exception
+	 * @throws getid3_exception
+	 */
+	public function __construct($host, $database, $username, $password, $table='getid3_cache') {
+
+		// Check for mysqli support
+		if (!function_exists('mysqli_connect')) {
+			throw new Exception('PHP not compiled with mysqli support.');
+		}
+
+		// Connect to database
+		$this->mysqli = new mysqli($host, $username, $password);
+		if ($this->mysqli->connect_error) {
+			throw new Exception('Connect Error (' . $this->mysqli->connect_errno . ') ' . $this->mysqli->connect_error);
+		}
+
+		// Select database
+		if (!$this->mysqli->select_db($database)) {
+			throw new Exception('Cannot use database '.$database);
+		}
+
+		// Set table
+		$this->table = $table;
+
+		// Create cache table if not exists
+		$this->create_table();
+
+		$this->db_structure_check = true; // set to false if you know your table structure has already been migrated to use `hash` as the primary key to avoid
+		$this->migrate_db_structure();
+
+		// Check version number and clear cache if changed
+		$version = '';
+		$SQLquery  = 'SELECT `value`';
+		$SQLquery .= ' FROM `'.$this->mysqli->real_escape_string($this->table).'`';
+		$SQLquery .= ' WHERE (`filename` = \''.$this->mysqli->real_escape_string(getID3::VERSION).'\')';
+		$SQLquery .= ' AND (`hash` = \'getID3::VERSION\')';
+		if ($this->cursor = $this->mysqli->query($SQLquery)) {
+			list($version) = $this->cursor->fetch_array();
+		}
+		if ($version != getID3::VERSION) {
+			$this->clear_cache();
+		}
+
+		parent::__construct();
+	}
+
+
+	/**
+	 * clear cache
+	 */
+	public function clear_cache() {
+		$this->mysqli->query('TRUNCATE TABLE `'.$this->mysqli->real_escape_string($this->table).'`');
+		$this->mysqli->query('INSERT INTO `'.$this->mysqli->real_escape_string($this->table).'` (`hash`, `filename`, `filesize`, `filetime`, `analyzetime`, `value`) VALUES (\'getID3::VERSION\', \''.getID3::VERSION.'\', -1, -1, -1, \''.getID3::VERSION.'\')');
+	}
+
+
+	/**
+	 * migrate database structure if needed
+	 */
+	public function migrate_db_structure() {
+		// Check for table structure
+		if ($this->db_structure_check) {
+			$SQLquery  = 'SHOW COLUMNS';
+			$SQLquery .= ' FROM `'.$this->mysqli->real_escape_string($this->table).'`';
+			$SQLquery .= ' LIKE \'hash\'';
+			$this->cursor = $this->mysqli->query($SQLquery);
+			if ($this->cursor->num_rows == 0) {
+				// table has not been migrated, add column, add hashes, change index
+				$SQLquery  = 'ALTER TABLE `getid3_cache` DROP PRIMARY KEY, ADD `hash` CHAR(32) NOT NULL DEFAULT \'\' FIRST, ADD PRIMARY KEY(`hash`)';
+				$this->mysqli->query($SQLquery);
+
+				$SQLquery  = 'UPDATE `getid3_cache` SET';
+				$SQLquery .= ' `hash` = MD5(`filename`, `filesize`, `filetime`)';
+				$SQLquery .= ' WHERE (`filesize` > -1)';
+				$this->mysqli->query($SQLquery);
+
+				$SQLquery  = 'UPDATE `getid3_cache` SET';
+				$SQLquery .= ' `hash` = \'getID3::VERSION\'';
+				$SQLquery .= ' WHERE (`filesize` = -1)';
+				$SQLquery .= '   AND (`filetime` = -1)';
+				$SQLquery .= '   AND (`filetime` = -1)';
+				$this->mysqli->query($SQLquery);
+			}
+		}
+	}
+
+
+	/**
+	 * analyze file
+	 *
+	 * @param string   $filename
+	 * @param int      $filesize
+	 * @param string   $original_filename
+	 * @param resource $fp
+	 *
+	 * @return mixed
+	 */
+	public function analyze($filename, $filesize=null, $original_filename='', $fp=null) {
+
+		$filetime = 0;
+		if (file_exists($filename)) {
+
+			// Short-hands
+			$filetime = filemtime($filename);
+			$filesize =  filesize($filename);
+
+			// Lookup file
+			$SQLquery  = 'SELECT `value`';
+			$SQLquery .= ' FROM `'.$this->mysqli->real_escape_string($this->table).'`';
+			$SQLquery .= ' WHERE (`hash` = \''.$this->mysqli->real_escape_string(md5($filename.$filesize.$filetime)).'\')';
+			$this->cursor = $this->mysqli->query($SQLquery);
+			if ($this->cursor->num_rows > 0) {
+				// Hit
+				list($result) = $this->cursor->fetch_array();
+				return unserialize(base64_decode($result));
+			}
+		}
+
+		// Miss
+		$analysis = parent::analyze($filename, $filesize, $original_filename, $fp);
+
+		// Save result
+		if (file_exists($filename)) {
+			$SQLquery  = 'INSERT INTO `'.$this->mysqli->real_escape_string($this->table).'` (`hash`, `filename`, `filesize`, `filetime`, `analyzetime`, `value`) VALUES (';
+			$SQLquery .=   '\''.$this->mysqli->real_escape_string(md5($filename.$filesize.$filetime)).'\'';
+			$SQLquery .= ', \''.$this->mysqli->real_escape_string($filename).'\'';
+			$SQLquery .= ', \''.$this->mysqli->real_escape_string($filesize).'\'';
+			$SQLquery .= ', \''.$this->mysqli->real_escape_string($filetime).'\'';
+			$SQLquery .= ', UNIX_TIMESTAMP()';
+			$SQLquery .= ', \''.$this->mysqli->real_escape_string(base64_encode(serialize($analysis))).'\'';
+			$SQLquery .= ')';
+			$this->cursor = $this->mysqli->query($SQLquery);
+		}
+		return $analysis;
+	}
+
+
+	/**
+	 * (re)create mysqli table
+	 *
+	 * @param bool $drop
+	 */
+	private function create_table($drop=false) {
+		if ($drop) {
+			$SQLquery  = 'DROP TABLE IF EXISTS `'.$this->mysqli->real_escape_string($this->table).'`';
+			$this->mysqli->query($SQLquery);
+		}
+		$SQLquery  = 'CREATE TABLE IF NOT EXISTS `'.$this->mysqli->real_escape_string($this->table).'` (';
+		$SQLquery .=   '`hash` CHAR(32) NOT NULL DEFAULT \'\'';
+		$SQLquery .= ', `filename` VARCHAR(1000) NOT NULL DEFAULT \'\'';
+		$SQLquery .= ', `filesize` INT(11) NOT NULL DEFAULT \'0\'';
+		$SQLquery .= ', `filetime` INT(11) NOT NULL DEFAULT \'0\'';
+		$SQLquery .= ', `analyzetime` INT(11) NOT NULL DEFAULT \'0\'';
+		$SQLquery .= ', `value` LONGTEXT NOT NULL';
+		$SQLquery .= ', PRIMARY KEY (`hash`))';
+		$this->cursor = $this->mysqli->query($SQLquery);
+		echo $this->mysqli->error;
+	}
+}

Added: plog/branches/lifetype-1.2/class/gallery/getid3/extension.cache.sqlite3.php
===================================================================
--- plog/branches/lifetype-1.2/class/gallery/getid3/extension.cache.sqlite3.php	                        (rev 0)
+++ plog/branches/lifetype-1.2/class/gallery/getid3/extension.cache.sqlite3.php	2020-07-15 07:59:26 UTC (rev 7238)
@@ -0,0 +1,297 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org>               //
+//  available at https://github.com/JamesHeinrich/getID3       //
+//            or https://www.getid3.org                        //
+//            or http://getid3.sourceforge.net                 //
+//                                                             //
+// extension.cache.mysqli.php - part of getID3()               //
+// Please see readme.txt for more information                  //
+//                                                             //
+/////////////////////////////////////////////////////////////////
+//                                                             //
+// extension.cache.sqlite3.php - part of getID3()              //
+// Please see readme.txt for more information                  //
+//                                                             //
+/////////////////////////////////////////////////////////////////
+///                                                            //
+// MySQL extension written by Allan Hansen <ahØartemis*dk>     //
+// Table name mod by Carlo Capocasa <calroØcarlocapocasa*com>  //
+// MySQL extension was reworked for SQLite3 by                 //
+//   Karl G. Holz <newaeonØmac*com>                            //
+//                                                            ///
+/////////////////////////////////////////////////////////////////
+
+/**
+* This is a caching extension for getID3(). It works the exact same
+* way as the getID3 class, but return cached information much faster
+*
+*    Normal getID3 usage (example):
+*
+*       require_once 'getid3/getid3.php';
+*       $getID3 = new getID3;
+*       $getID3->encoding = 'UTF-8';
+*       $info1 = $getID3->analyze('file1.flac');
+*       $info2 = $getID3->analyze('file2.wv');
+*
+*    getID3_cached usage:
+*
+*       require_once 'getid3/getid3.php';
+*       require_once 'getid3/extension.cache.sqlite3.php';
+*       // all parameters are optional, defaults are:
+*       $getID3 = new getID3_cached_sqlite3($table='getid3_cache', $hide=FALSE);
+*       $getID3->encoding = 'UTF-8';
+*       $info1 = $getID3->analyze('file1.flac');
+*       $info2 = $getID3->analyze('file2.wv');
+*
+*
+* Supported Cache Types    (this extension)
+*
+*   SQL Databases:
+*
+*   cache_type          cache_options
+*   -------------------------------------------------------------------
+*   mysql               host, database, username, password
+*
+*   sqlite3             table='getid3_cache', hide=false        (PHP5)
+*
+*
+* ***  database file will be stored in the same directory as this script,
+* ***  webserver must have write access to that directory!
+* ***  set $hide to TRUE to prefix db file with .ht to pervent access from web client
+* ***  this is a default setting in the Apache configuration:
+*
+* The following lines prevent .htaccess and .htpasswd files from being viewed by Web clients.
+*
+* <Files ~ "^\.ht">
+*     Order allow,deny
+*     Deny from all
+*     Satisfy all
+* </Files>
+*
+********************************************************************************
+*
+*   -------------------------------------------------------------------
+*   DBM-Style Databases:    (use extension.cache.dbm)
+*
+*   cache_type          cache_options
+*   -------------------------------------------------------------------
+*   gdbm                dbm_filename, lock_filename
+*   ndbm                dbm_filename, lock_filename
+*   db2                 dbm_filename, lock_filename
+*   db3                 dbm_filename, lock_filename
+*   db4                 dbm_filename, lock_filename  (PHP5 required)
+*
+*   PHP must have write access to both dbm_filename and lock_filename.
+*
+* Recommended Cache Types
+*
+*   Infrequent updates, many reads      any DBM
+*   Frequent updates                    mysql
+********************************************************************************
+*
+* IMHO this is still a bit slow, I'm using this with MP4/MOV/ M4v files
+* there is a plan to add directory scanning and analyzing to make things work much faster
+*
+*
+*/
+class getID3_cached_sqlite3 extends getID3
+{
+	/**
+	 * hold the sqlite db
+	 *
+	 * @var SQLite3 Resource
+	 */
+	private $db;
+
+	/**
+	 * table to use for caching
+	 *
+	 * @var string $table
+	 */
+	private $table;
+
+	/**
+	 * @param string  $table holds name of sqlite table
+	 * @param boolean $hide
+	 *
+	 * @throws getid3_exception
+	 * @throws Exception
+	 */
+	public function __construct($table='getid3_cache', $hide=false) {
+		// Check for SQLite3 support
+		if (!function_exists('sqlite_open')) {
+			throw new Exception('PHP not compiled with SQLite3 support.');
+		}
+
+		$this->table = $table; // Set table
+		$file = dirname(__FILE__).'/'.basename(__FILE__, 'php').'sqlite';
+		if ($hide) {
+			$file = dirname(__FILE__).'/.ht.'.basename(__FILE__, 'php').'sqlite';
+		}
+		$this->db = new SQLite3($file);
+		$db = $this->db;
+		$this->create_table();   // Create cache table if not exists
+		$version = '';
+		$sql = $this->getQuery('version_check');
+		$stmt = $db->prepare($sql);
+		$stmt->bindValue(':filename', getID3::VERSION, SQLITE3_TEXT);
+		$result = $stmt->execute();
+		list($version) = $result->fetchArray();
+		if ($version != getID3::VERSION) { // Check version number and clear cache if changed
+			$this->clear_cache();
+		}
+		parent::__construct();
+	}
+
+	/**
+	 * close the database connection
+	 */
+	public function __destruct() {
+		$db=$this->db;
+		$db->close();
+	}
+
+	/**
+	 * clear the cache
+	 *
+	 * @return SQLite3Result
+	 */
+	private function clear_cache() {
+		$db = $this->db;
+		$sql = $this->getQuery('delete_cache');
+		$db->exec($sql);
+		$sql = $this->getQuery('set_version');
+		$stmt = $db->prepare($sql);
+		$stmt->bindValue(':filename', getID3::VERSION, SQLITE3_TEXT);
+		$stmt->bindValue(':dirname', getID3::VERSION, SQLITE3_TEXT);
+		$stmt->bindValue(':val', getID3::VERSION, SQLITE3_TEXT);
+		return $stmt->execute();
+	}
+
+	/**
+	 * analyze file and cache them, if cached pull from the db
+	 *
+	 * @param string   $filename
+	 * @param integer  $filesize
+	 * @param string   $original_filename
+	 * @param resource $fp
+	 *
+	 * @return mixed|false
+	 */
+	public function analyze($filename, $filesize=null, $original_filename='', $fp=null) {
+		if (!file_exists($filename)) {
+			return false;
+		}
+		// items to track for caching
+		$filetime = filemtime($filename);
+		$filesize_real = filesize($filename);
+		// this will be saved for a quick directory lookup of analized files
+		// ... why do 50 seperate sql quries when you can do 1 for the same result
+		$dirname  = dirname($filename);
+		// Lookup file
+		$db = $this->db;
+		$sql = $this->getQuery('get_id3_data');
+		$stmt = $db->prepare($sql);
+		$stmt->bindValue(':filename', $filename,      SQLITE3_TEXT);
+		$stmt->bindValue(':filesize', $filesize_real, SQLITE3_INTEGER);
+		$stmt->bindValue(':filetime', $filetime,      SQLITE3_INTEGER);
+		$res = $stmt->execute();
+		list($result) = $res->fetchArray();
+		if (count($result) > 0 ) {
+			return unserialize(base64_decode($result));
+		}
+		// if it hasn't been analyzed before, then do it now
+		$analysis = parent::analyze($filename, $filesize, $original_filename, $fp);
+		// Save result
+		$sql = $this->getQuery('cache_file');
+		$stmt = $db->prepare($sql);
+		$stmt->bindValue(':filename', $filename,                           SQLITE3_TEXT);
+		$stmt->bindValue(':dirname',  $dirname,                            SQLITE3_TEXT);
+		$stmt->bindValue(':filesize', $filesize_real,                      SQLITE3_INTEGER);
+		$stmt->bindValue(':filetime', $filetime,                           SQLITE3_INTEGER);
+		$stmt->bindValue(':atime',    time(),                              SQLITE3_INTEGER);
+		$stmt->bindValue(':val',      base64_encode(serialize($analysis)), SQLITE3_TEXT);
+		$res = $stmt->execute();
+		return $analysis;
+	}
+
+	/**
+	 * create data base table
+	 * this is almost the same as MySQL, with the exception of the dirname being added
+	 *
+	 * @return bool
+	 */
+	private function create_table() {
+		$db = $this->db;
+		$sql = $this->getQuery('make_table');
+		return $db->exec($sql);
+	}
+
+	/**
+	 * get cached directory
+	 *
+	 * This function is not in the MySQL extention, it's ment to speed up requesting multiple files
+	 * which is ideal for podcasting, playlists, etc.
+	 *
+	 * @param string $dir directory to search the cache database for
+	 *
+	 * @return array return an array of matching id3 data
+	 */
+	public function get_cached_dir($dir) {
+		$db = $this->db;
+		$rows = array();
+		$sql = $this->getQuery('get_cached_dir');
+		$stmt = $db->prepare($sql);
+		$stmt->bindValue(':dirname', $dir, SQLITE3_TEXT);
+		$res = $stmt->execute();
+		while ($row=$res->fetchArray()) {
+			$rows[] = unserialize(base64_decode($row));
+		}
+		return $rows;
+	}
+
+	/**
+	 * returns NULL if query is not found
+	 *
+	 * @param string $name
+	 *
+	 * @return null|string
+	 */
+	public function getQuery($name)
+	{
+		switch ($name) {
+			case 'version_check':
+				return "SELECT val FROM $this->table WHERE filename = :filename AND filesize = '-1' AND filetime = '-1' AND analyzetime = '-1'";
+			case 'delete_cache':
+				return "DELETE FROM $this->table";
+			case 'set_version':
+				return "INSERT INTO $this->table (filename, dirname, filesize, filetime, analyzetime, val) VALUES (:filename, :dirname, -1, -1, -1, :val)";
+			case 'get_id3_data':
+				return "SELECT val FROM $this->table WHERE filename = :filename AND filesize = :filesize AND filetime = :filetime";
+			case 'cache_file':
+				return "INSERT INTO $this->table (filename, dirname, filesize, filetime, analyzetime, val) VALUES (:filename, :dirname, :filesize, :filetime, :atime, :val)";
+			case 'make_table':
+				return "CREATE TABLE IF NOT EXISTS $this->table (filename VARCHAR(255) DEFAULT '', dirname VARCHAR(255) DEFAULT '', filesize INT(11) DEFAULT '0', filetime INT(11) DEFAULT '0', analyzetime INT(11) DEFAULT '0', val text, PRIMARY KEY (filename, filesize, filetime))";
+			case 'get_cached_dir':
+				return "SELECT val FROM $this->table WHERE dirname = :dirname";
+			default:
+				return null;
+		}
+	}
+
+	/**
+	* use the magical __get() for sql queries
+	*
+	* access as easy as $this->{case name}, returns NULL if query is not found
+	*
+	* @param string $name
+	*
+	* @return string
+	* @deprecated use getQuery() instead
+	*/
+	public function __get($name) {
+		return $this->getQuery($name);
+	}
+
+}

Added: plog/branches/lifetype-1.2/class/gallery/getid3/module.archive.hpk.php
===================================================================
--- plog/branches/lifetype-1.2/class/gallery/getid3/module.archive.hpk.php	                        (rev 0)
+++ plog/branches/lifetype-1.2/class/gallery/getid3/module.archive.hpk.php	2020-07-15 07:59:26 UTC (rev 7238)
@@ -0,0 +1,92 @@
+<?php
+
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org>               //
+//  available at https://github.com/JamesHeinrich/getID3       //
+//            or https://www.getid3.org                        //
+//            or http://getid3.sourceforge.net                 //
+//  see readme.txt for more details                            //
+/////////////////////////////////////////////////////////////////
+//                                                             //
+// module.archive.hpk.php                                      //
+// module for analyzing HPK files                              //
+// dependencies: NONE                                          //
+//                                                            ///
+/////////////////////////////////////////////////////////////////
+
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+	exit;
+}
+
+class getid3_hpk extends getid3_handler
+{
+	/**
+	 * @return bool
+	 */
+	public function Analyze() {
+		$info = &$this->getid3->info;
+
+		$info['fileformat'] = 'hpk';
+
+		$this->fseek($info['avdataoffset']);
+		$HPKheader = $this->fread(36);
+
+		if (substr($HPKheader, 0, 4) == 'BPUL') {
+
+			$info['hpk']['header']['signature']                    =                              substr($HPKheader,  0, 4);
+			$info['hpk']['header']['data_offset']                  = getid3_lib::LittleEndian2Int(substr($HPKheader,  4, 4));
+			$info['hpk']['header']['fragments_per_file']           = getid3_lib::LittleEndian2Int(substr($HPKheader,  8, 4));
+			//$info['hpk']['header']['unknown1']                     = getid3_lib::LittleEndian2Int(substr($HPKheader, 12, 4));
+			$info['hpk']['header']['fragments_residual_offset']    = getid3_lib::LittleEndian2Int(substr($HPKheader, 16, 4));
+			$info['hpk']['header']['fragments_residual_count']     = getid3_lib::LittleEndian2Int(substr($HPKheader, 20, 4));
+			//$info['hpk']['header']['unknown2']                     = getid3_lib::LittleEndian2Int(substr($HPKheader, 24, 4));
+			$info['hpk']['header']['fragmented_filesystem_offset'] = getid3_lib::LittleEndian2Int(substr($HPKheader, 28, 4));
+			$info['hpk']['header']['fragmented_filesystem_length'] = getid3_lib::LittleEndian2Int(substr($HPKheader, 32, 4));
+
+			$info['hpk']['header']['filesystem_entries'] = $info['hpk']['header']['fragmented_filesystem_length'] / ($info['hpk']['header']['fragments_per_file'] * 8);
+			$this->fseek($info['hpk']['header']['fragmented_filesystem_offset']);
+			for ($i = 0; $i < $info['hpk']['header']['filesystem_entries']; $i++) {
+				$offset = getid3_lib::LittleEndian2Int($this->fread(4));
+				$length = getid3_lib::LittleEndian2Int($this->fread(4));
+				$info['hpk']['filesystem'][$i] = array('offset' => $offset, 'length' => $length);
+			}
+
+$this->error('HPK parsing incomplete (and mostly broken) in this version of getID3() ['.$this->getid3->version().']');
+
+/*
+			$filename = '';
+			$dirs = array();
+			foreach ($info['hpk']['filesystem'] as $key => $filesystemdata) {
+				$this->fseek($filesystemdata['offset']);
+				$first4 = $this->fread(4);
+				if (($first4 == 'LZ4 ') || ($first4 == 'ZLIB')) {
+					// actual data, ignore
+					$info['hpk']['toc'][$key] = array(
+						'filename' => ltrim(implode('/', $dirs).'/'.$filename, '/'),
+						'offset'   => $filesystemdata['offset'],
+						'length'   => $filesystemdata['length'],
+					);
+					$filename = '';
+					$dirs = array();
+				} else {
+					$fragment_index = getid3_lib::LittleEndian2Int($first4);
+					$fragment_type  = getid3_lib::LittleEndian2Int($this->fread(4)); // file = 0, directory = 1
+					$name_length    = getid3_lib::LittleEndian2Int($this->fread(2));
+					if ($fragment_type == 1) {
+						$dirs[]   = $this->fread($name_length);
+					} else {
+						$filename = $this->fread($name_length);
+					}
+				}
+			}
+*/
+
+		} else {
+			$this->error('Expecting "BPUL" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($HPKheader, 0, 4)).'"');
+			return false;
+		}
+
+		return true;
+	}
+
+}

Added: plog/branches/lifetype-1.2/class/gallery/getid3/module.archive.xz.php
===================================================================
--- plog/branches/lifetype-1.2/class/gallery/getid3/module.archive.xz.php	                        (rev 0)
+++ plog/branches/lifetype-1.2/class/gallery/getid3/module.archive.xz.php	2020-07-15 07:59:26 UTC (rev 7238)
@@ -0,0 +1,45 @@
+<?php
+
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org>               //
+//  available at https://github.com/JamesHeinrich/getID3       //
+//            or https://www.getid3.org                        //
+//            or http://getid3.sourceforge.net                 //
+//  see readme.txt for more details                            //
+/////////////////////////////////////////////////////////////////
+//                                                             //
+// module.archive.xz.php                                       //
+// module for analyzing XZ files                               //
+// dependencies: NONE                                          //
+//                                                            ///
+/////////////////////////////////////////////////////////////////
+
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+	exit;
+}
+
+class getid3_xz extends getid3_handler
+{
+
+	/**
+	 * @return bool
+	 */
+	public function Analyze() {
+		$info = &$this->getid3->info;
+
+		$this->fseek($info['avdataoffset']);
+		$xzheader = $this->fread(6);
+
+		// https://tukaani.org/xz/xz-file-format-1.0.4.txt
+		$info['xz']['stream_header']['magic'] = substr($xzheader, 0, 6);
+		if ($info['xz']['stream_header']['magic'] != "\xFD".'7zXZ'."\x00") {
+			$this->error('Invalid XZ stream header magic (expecting FD 37 7A 58 5A 00, found '.getid3_lib::PrintHexBytes($info['xz']['stream_header']['magic']).') at offset '.$info['avdataoffset']);
+			return false;
+		}
+		$info['fileformat'] = 'xz';
+		$this->error('XZ parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
+		return false;
+
+	}
+
+}

Added: plog/branches/lifetype-1.2/class/gallery/getid3/module.audio-video.ivf.php
===================================================================
--- plog/branches/lifetype-1.2/class/gallery/getid3/module.audio-video.ivf.php	                        (rev 0)
+++ plog/branches/lifetype-1.2/class/gallery/getid3/module.audio-video.ivf.php	2020-07-15 07:59:26 UTC (rev 7238)
@@ -0,0 +1,81 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org>               //
+//  available at https://github.com/JamesHeinrich/getID3       //
+//            or https://www.getid3.org                        //
+//            or http://getid3.sourceforge.net                 //
+//  see readme.txt for more details                            //
+/////////////////////////////////////////////////////////////////
+//                                                             //
+// module.audio.ivf.php                                        //
+// module for analyzing IVF audio-video files                  //
+// dependencies: NONE                                          //
+//                                                            ///
+/////////////////////////////////////////////////////////////////
+
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+	exit;
+}
+
+class getid3_ivf extends getid3_handler
+{
+	/**
+	 * @return bool
+	 */
+	public function Analyze() {
+		$info = &$this->getid3->info;
+
+		$info['fileformat']          = 'ivf';
+		$info['video']['dataformat'] = 'ivf';
+
+		$this->fseek($info['avdataoffset']);
+		$IVFheader = $this->fread(32);
+
+		if (substr($IVFheader, 0, 4) == 'DKIF') {
+
+			// https://wiki.multimedia.cx/index.php/IVF
+			$info['ivf']['header']['signature']            =                              substr($IVFheader,  0, 4);
+			$info['ivf']['header']['version']              = getid3_lib::LittleEndian2Int(substr($IVFheader,  4, 2)); // should be 0
+			$info['ivf']['header']['headersize']           = getid3_lib::LittleEndian2Int(substr($IVFheader,  6, 2));
+			$info['ivf']['header']['fourcc']               =                              substr($IVFheader,  8, 4);
+			$info['ivf']['header']['resolution_x']         = getid3_lib::LittleEndian2Int(substr($IVFheader, 12, 2));
+			$info['ivf']['header']['resolution_y']         = getid3_lib::LittleEndian2Int(substr($IVFheader, 14, 2));
+			$info['ivf']['header']['timebase_numerator']   = getid3_lib::LittleEndian2Int(substr($IVFheader, 16, 4));
+			$info['ivf']['header']['timebase_denominator'] = getid3_lib::LittleEndian2Int(substr($IVFheader, 20, 4));
+			$info['ivf']['header']['frame_count']          = getid3_lib::LittleEndian2Int(substr($IVFheader, 24, 4));
+			//$info['ivf']['header']['reserved']             =                              substr($IVFheader, 28, 4);
+
+			$info['ivf']['header']['frame_rate'] = (float) $info['ivf']['header']['timebase_numerator'] / $info['ivf']['header']['timebase_denominator'];
+
+			if ($info['ivf']['header']['version'] > 0) {
+				$this->warning('Expecting IVF header version 0, found version '.$info['ivf']['header']['version'].', results may not be accurate');
+			}
+
+			$info['video']['resolution_x']    =         $info['ivf']['header']['resolution_x'];
+			$info['video']['resolution_y']    =         $info['ivf']['header']['resolution_y'];
+			$info['video']['codec']           =         $info['ivf']['header']['fourcc'];
+
+			$info['ivf']['frame_count'] = 0;
+			$timestamp                  = 0;
+			while (!$this->feof()) {
+				if ($frameheader = $this->fread(12)) {
+					$framesize = getid3_lib::LittleEndian2Int(substr($frameheader, 0, 4)); // size of frame in bytes (not including the 12-byte header)
+					$timestamp = getid3_lib::LittleEndian2Int(substr($frameheader, 4, 8)); // 64-bit presentation timestamp
+					$this->fseek($framesize, SEEK_CUR);
+					$info['ivf']['frame_count']++;
+				}
+			}
+			if ($info['ivf']['frame_count']) {
+				$info['playtime_seconds']    = $timestamp / 100000;
+				$info['video']['frame_rate'] = (float) $info['ivf']['frame_count'] / $info['playtime_seconds'];
+			}
+
+		} else {
+			$this->error('Expecting "DKIF" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($IVFheader, 0, 4)).'"');
+			return false;
+		}
+
+		return true;
+	}
+
+}

Added: plog/branches/lifetype-1.2/class/gallery/getid3/module.audio-video.ts.php
===================================================================
--- plog/branches/lifetype-1.2/class/gallery/getid3/module.audio-video.ts.php	                        (rev 0)
+++ plog/branches/lifetype-1.2/class/gallery/getid3/module.audio-video.ts.php	2020-07-15 07:59:26 UTC (rev 7238)
@@ -0,0 +1,88 @@
+<?php
+
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org>               //
+//  available at https://github.com/JamesHeinrich/getID3       //
+//            or https://www.getid3.org                        //
+//            or http://getid3.sourceforge.net                 //
+//  see readme.txt for more details                            //
+/////////////////////////////////////////////////////////////////
+//                                                             //
+// module.audio-video.ts.php                                   //
+// module for analyzing MPEG Transport Stream (.ts) files      //
+// dependencies: NONE                                          //
+//                                                            ///
+/////////////////////////////////////////////////////////////////
+
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+	exit;
+}
+
+class getid3_ts extends getid3_handler
+{
+	/**
+	 * @return bool
+	 */
+	public function Analyze() {
+		$info = &$this->getid3->info;
+
+		$this->fseek($info['avdataoffset']);
+		$TSheader = $this->fread(19);
+		$magic = "\x47";
+		if (substr($TSheader, 0, 1) != $magic) {
+			$this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at '.$info['avdataoffset'].', found '.getid3_lib::PrintHexBytes(substr($TSheader, 0, 1)).' instead.');
+			return false;
+		}
+		$info['fileformat'] = 'ts';
+
+		// http://en.wikipedia.org/wiki/.ts
+
+		$offset = 0;
+		$info['ts']['packet']['sync'] = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 1)); $offset += 1;
+		$pid_flags_raw                = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 2)); $offset += 2;
+		$SAC_raw                      = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 1)); $offset += 1;
+		$info['ts']['packet']['flags']['transport_error_indicator']    =      (bool) ($pid_flags_raw & 0x8000);      // Set by demodulator if can't correct errors in the stream, to tell the demultiplexer that the packet has an uncorrectable error
+		$info['ts']['packet']['flags']['payload_unit_start_indicator'] =      (bool) ($pid_flags_raw & 0x4000);      // 1 means start of PES data or PSI otherwise zero only.
+		$info['ts']['packet']['flags']['transport_high_priority']      =      (bool) ($pid_flags_raw & 0x2000);      // 1 means higher priority than other packets with the same PID.
+		$info['ts']['packet']['packet_id']                             =             ($pid_flags_raw & 0x1FFF) >> 0;
+
+		$info['ts']['packet']['raw']['scrambling_control']             =                   ($SAC_raw &   0xC0) >> 6;
+		$info['ts']['packet']['flags']['adaption_field_exists']        =      (bool)       ($SAC_raw &   0x20);
+		$info['ts']['packet']['flags']['payload_exists']               =      (bool)       ($SAC_raw &   0x10);
+		$info['ts']['packet']['continuity_counter']                    =                   ($SAC_raw &   0x0F) >> 0; // Incremented only when a payload is present
+		$info['ts']['packet']['scrambling_control']                    = $this->TSscramblingControlLookup($info['ts']['packet']['raw']['scrambling_control']);
+
+		if ($info['ts']['packet']['flags']['adaption_field_exists']) {
+			$AdaptionField_raw        = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 2)); $offset += 2;
+			$info['ts']['packet']['adaption']['field_length']           =        ($AdaptionField_raw & 0xFF00) >> 8;  // Number of bytes in the adaptation field immediately following this byte
+			$info['ts']['packet']['adaption']['flags']['discontinuity'] = (bool) ($AdaptionField_raw & 0x0080);       // Set to 1 if current TS packet is in a discontinuity state with respect to either the continuity counter or the program clock reference
+			$info['ts']['packet']['adaption']['flags']['random_access'] = (bool) ($AdaptionField_raw & 0x0040);       // Set to 1 if the PES packet in this TS packet starts a video/audio sequence
+			$info['ts']['packet']['adaption']['flags']['high_priority'] = (bool) ($AdaptionField_raw & 0x0020);       // 1 = higher priority
+			$info['ts']['packet']['adaption']['flags']['pcr']           = (bool) ($AdaptionField_raw & 0x0010);       // 1 means adaptation field does contain a PCR field
+			$info['ts']['packet']['adaption']['flags']['opcr']          = (bool) ($AdaptionField_raw & 0x0008);       // 1 means adaptation field does contain an OPCR field
+			$info['ts']['packet']['adaption']['flags']['splice_point']  = (bool) ($AdaptionField_raw & 0x0004);       // 1 means presence of splice countdown field in adaptation field
+			$info['ts']['packet']['adaption']['flags']['private_data']  = (bool) ($AdaptionField_raw & 0x0002);       // 1 means presence of private data bytes in adaptation field
+			$info['ts']['packet']['adaption']['flags']['extension']     = (bool) ($AdaptionField_raw & 0x0001);       // 1 means presence of adaptation field extension
+			if ($info['ts']['packet']['adaption']['flags']['pcr']) {
+				$info['ts']['packet']['adaption']['raw']['pcr'] = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 6)); $offset += 6;
+			}
+			if ($info['ts']['packet']['adaption']['flags']['opcr']) {
+				$info['ts']['packet']['adaption']['raw']['opcr'] = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 6)); $offset += 6;
+			}
+		}
+
+		$this->error('MPEG Transport Stream (.ts) parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
+		return false;
+
+	}
+
+	/**
+	 * @param int $raw
+	 *
+	 * @return string
+	 */
+	public function TSscramblingControlLookup($raw) {
+		$TSscramblingControlLookup = array(0x00=>'not scrambled', 0x01=>'reserved', 0x02=>'scrambled, even key', 0x03=>'scrambled, odd key');
+		return (isset($TSscramblingControlLookup[$raw]) ? $TSscramblingControlLookup[$raw] : 'invalid');
+	}
+}

Added: plog/branches/lifetype-1.2/class/gallery/getid3/module.audio-video.wtv.php
===================================================================
--- plog/branches/lifetype-1.2/class/gallery/getid3/module.audio-video.wtv.php	                        (rev 0)
+++ plog/branches/lifetype-1.2/class/gallery/getid3/module.audio-video.wtv.php	2020-07-15 07:59:26 UTC (rev 7238)
@@ -0,0 +1,37 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org>               //
+//  available at https://github.com/JamesHeinrich/getID3       //
+//            or https://www.getid3.org                        //
+//            or http://getid3.sourceforge.net                 //
+//  see readme.txt for more details                            //
+/////////////////////////////////////////////////////////////////
+//                                                             //
+// module.audio.wtv.php                                        //
+// module for analyzing WTV (Windows Recorded TV Show)         //
+//   audio-video files                                         //
+// dependencies: NONE                                          //
+//                                                            ///
+/////////////////////////////////////////////////////////////////
+
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+	exit;
+}
+
+class getid3_wtv extends getid3_handler
+{
+	/**
+	 * @return bool
+	 */
+	public function Analyze() {
+		$info = &$this->getid3->info;
+
+		$info['fileformat']          = 'wtv';
+		$info['video']['dataformat'] = 'wtv';
+
+		$this->error('WTV (Windows Recorded TV Show) files not properly processed by this version of getID3() ['.$this->getid3->version().']');
+
+		return true;
+	}
+
+}

Added: plog/branches/lifetype-1.2/class/gallery/getid3/module.audio.aa.php
===================================================================
--- plog/branches/lifetype-1.2/class/gallery/getid3/module.audio.aa.php	                        (rev 0)
+++ plog/branches/lifetype-1.2/class/gallery/getid3/module.audio.aa.php	2020-07-15 07:59:26 UTC (rev 7238)
@@ -0,0 +1,64 @@
+<?php
+
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org>               //
+//  available at https://github.com/JamesHeinrich/getID3       //
+//            or https://www.getid3.org                        //
+//            or http://getid3.sourceforge.net                 //
+//  see readme.txt for more details                            //
+/////////////////////////////////////////////////////////////////
+//                                                             //
+// module.audio.aa.php                                         //
+// module for analyzing Audible Audiobook files                //
+// dependencies: NONE                                          //
+//                                                            ///
+/////////////////////////////////////////////////////////////////
+
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+	exit;
+}
+
+class getid3_aa extends getid3_handler
+{
+	/**
+	 * @return bool
+	 */
+	public function Analyze() {
+		$info = &$this->getid3->info;
+
+		$this->fseek($info['avdataoffset']);
+		$AAheader  = $this->fread(8);
+
+		$magic = "\x57\x90\x75\x36";
+		if (substr($AAheader, 4, 4) != $magic) {
+			$this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($AAheader, 4, 4)).'"');
+			return false;
+		}
+
+		// shortcut
+		$info['aa'] = array();
+		$thisfile_aa = &$info['aa'];
+
+		$info['fileformat']            = 'aa';
+		$info['audio']['dataformat']   = 'aa';
+		$this->error('Audible Audiobook (.aa) parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
+		return false;
+		$info['audio']['bitrate_mode'] = 'cbr'; // is it?
+		$thisfile_aa['encoding']       = 'ISO-8859-1';
+
+		$thisfile_aa['filesize'] = getid3_lib::BigEndian2Int(substr($AAheader,  0, 4));
+		if ($thisfile_aa['filesize'] > ($info['avdataend'] - $info['avdataoffset'])) {
+			$this->warning('Possible truncated file - expecting "'.$thisfile_aa['filesize'].'" bytes of data, only found '.($info['avdataend'] - $info['avdataoffset']).' bytes"');
+		}
+
+		$info['audio']['bits_per_sample'] = 16; // is it?
+		$info['audio']['sample_rate'] = $thisfile_aa['sample_rate'];
+		$info['audio']['channels']    = $thisfile_aa['channels'];
+
+		//$info['playtime_seconds'] = 0;
+		//$info['audio']['bitrate'] = 0;
+
+		return true;
+	}
+
+}

Added: plog/branches/lifetype-1.2/class/gallery/getid3/module.audio.amr.php
===================================================================
--- plog/branches/lifetype-1.2/class/gallery/getid3/module.audio.amr.php	                        (rev 0)
+++ plog/branches/lifetype-1.2/class/gallery/getid3/module.audio.amr.php	2020-07-15 07:59:26 UTC (rev 7238)
@@ -0,0 +1,110 @@
+<?php
+
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org>               //
+//  available at https://github.com/JamesHeinrich/getID3       //
+//            or https://www.getid3.org                        //
+//            or http://getid3.sourceforge.net                 //
+//  see readme.txt for more details                            //
+/////////////////////////////////////////////////////////////////
+//                                                             //
+// module.audio.aa.php                                         //
+// module for analyzing Audible Audiobook files                //
+// dependencies: NONE                                          //
+//                                                            ///
+/////////////////////////////////////////////////////////////////
+
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+	exit;
+}
+
+class getid3_amr extends getid3_handler
+{
+	/**
+	 * @return bool
+	 */
+	public function Analyze() {
+		$info = &$this->getid3->info;
+
+		$this->fseek($info['avdataoffset']);
+		$AMRheader = $this->fread(6);
+
+		$magic = '#!AMR'."\x0A";
+		if (substr($AMRheader, 0, 6) != $magic) {
+			$this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($AMRheader, 0, 6)).'"');
+			return false;
+		}
+
+		// shortcut
+		$info['amr'] = array();
+		$thisfile_amr = &$info['amr'];
+
+		$info['fileformat']               = 'amr';
+		$info['audio']['dataformat']      = 'amr';
+		$info['audio']['bitrate_mode']    = 'vbr';   // within a small predefined range: 4.75kbps to 12.2kbps
+		$info['audio']['bits_per_sample'] =    13;   // http://en.wikipedia.org/wiki/Adaptive_Multi-Rate_audio_codec: "Sampling frequency 8 kHz/13-bit (160 samples for 20 ms frames), filtered to 200–3400 Hz"
+		$info['audio']['sample_rate']     =  8000;   // http://en.wikipedia.org/wiki/Adaptive_Multi-Rate_audio_codec: "Sampling frequency 8 kHz/13-bit (160 samples for 20 ms frames), filtered to 200–3400 Hz"
+		$info['audio']['channels']        =     1;
+		$thisfile_amr['frame_mode_count'] = array(0=>0, 1=>0, 2=>0, 3=>0, 4=>0, 5=>0, 6=>0, 7=>0);
+
+		$buffer = '';
+		do {
+			if ((strlen($buffer) < $this->getid3->fread_buffer_size()) && !feof($this->getid3->fp)) {
+				$buffer .= $this->fread($this->getid3->fread_buffer_size() * 2);
+			}
+			$AMR_frame_header = ord(substr($buffer, 0, 1));
+			$codec_mode_request = ($AMR_frame_header & 0x78) >> 3; // The 2nd bit through 5th bit (counting the most significant bit as the first bit) comprise the CMR (Codec Mode Request), values 0-7 being valid for AMR. The top bit of the CMR can actually be ignored, though it is used when AMR forms RTP payloads. The lower 3-bits of the header are reserved and are not used. Viewing the header from most significant bit to least significant bit, the encoding is XCCCCXXX, where Xs are reserved (typically 0) and the Cs are the CMR.
+			if ($codec_mode_request > 7) {
+				break;
+			}
+			$thisfile_amr['frame_mode_count'][$codec_mode_request]++;
+			$buffer = substr($buffer, $this->amr_mode_bytes_per_frame($codec_mode_request));
+		} while (strlen($buffer) > 0);
+
+		$info['playtime_seconds'] = array_sum($thisfile_amr['frame_mode_count']) * 0.020; // each frame contain 160 samples and is 20 milliseconds long
+		$info['audio']['bitrate'] = (8 * ($info['avdataend'] - $info['avdataoffset'])) / $info['playtime_seconds']; // bitrate could be calculated from average bitrate by distributation of frame types. That would give effective audio bitrate, this gives overall file bitrate which will be a little bit higher since every frame will waste 8 bits for header, plus a few bits for octet padding
+		$info['bitrate'] = $info['audio']['bitrate'];
+
+		return true;
+	}
+
+	/**
+	 * @param int $key
+	 *
+	 * @return int|false
+	 */
+	public function amr_mode_bitrate($key) {
+		static $amr_mode_bitrate = array(
+			0 =>  4750,
+			1 =>  5150,
+			2 =>  5900,
+			3 =>  6700,
+			4 =>  7400,
+			5 =>  7950,
+			6 => 10200,
+			7 => 12200,
+		);
+		return (isset($amr_mode_bitrate[$key]) ? $amr_mode_bitrate[$key] : false);
+	}
+
+	/**
+	 * @param int $key
+	 *
+	 * @return int|false
+	 */
+	public function amr_mode_bytes_per_frame($key) {
+		static $amr_mode_bitrate = array(
+			0 =>  13, // 1-byte frame header +  95 bits [padded to: 12 bytes] audio data
+			1 =>  14, // 1-byte frame header + 103 bits [padded to: 13 bytes] audio data
+			2 =>  16, // 1-byte frame header + 118 bits [padded to: 15 bytes] audio data
+			3 =>  18, // 1-byte frame header + 134 bits [padded to: 17 bytes] audio data
+			4 =>  20, // 1-byte frame header + 148 bits [padded to: 19 bytes] audio data
+			5 =>  21, // 1-byte frame header + 159 bits [padded to: 20 bytes] audio data
+			6 =>  27, // 1-byte frame header + 204 bits [padded to: 26 bytes] audio data
+			7 =>  32, // 1-byte frame header + 244 bits [padded to: 31 bytes] audio data
+		);
+		return (isset($amr_mode_bitrate[$key]) ? $amr_mode_bitrate[$key] : false);
+	}
+
+
+}

Added: plog/branches/lifetype-1.2/class/gallery/getid3/module.audio.dsdiff.php
===================================================================
--- plog/branches/lifetype-1.2/class/gallery/getid3/module.audio.dsdiff.php	                        (rev 0)
+++ plog/branches/lifetype-1.2/class/gallery/getid3/module.audio.dsdiff.php	2020-07-15 07:59:26 UTC (rev 7238)
@@ -0,0 +1,310 @@
+<?php
+
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org>               //
+//  available at https://github.com/JamesHeinrich/getID3       //
+//            or https://www.getid3.org                        //
+//            or http://getid3.sourceforge.net                 //
+//  see readme.txt for more details                            //
+/////////////////////////////////////////////////////////////////
+//                                                             //
+// module.audio.dsdiff.php                                     //
+// module for analyzing Direct Stream Digital Interchange      //
+// File Format (DSDIFF) files                                  //
+// dependencies: NONE                                          //
+//                                                            ///
+/////////////////////////////////////////////////////////////////
+
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+	exit;
+}
+
+class getid3_dsdiff extends getid3_handler
+{
+	/**
+	 * @return bool
+	 */
+	public function Analyze() {
+		$info = &$this->getid3->info;
+
+		$this->fseek($info['avdataoffset']);
+		$DSDIFFheader = $this->fread(4);
+
+		// https://dsd-guide.com/sites/default/files/white-papers/DSDIFF_1.5_Spec.pdf
+		if (substr($DSDIFFheader, 0, 4) != 'FRM8') {
+			$this->error('Expecting "FRM8" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($DSDIFFheader, 0, 4)).'"');
+			return false;
+		}
+		unset($DSDIFFheader);
+		$this->fseek($info['avdataoffset']);
+
+		$info['encoding']                 = 'ISO-8859-1'; // not certain, but assumed
+		$info['fileformat']               = 'dsdiff';
+		$info['mime_type']                = 'audio/dsd';
+		$info['audio']['dataformat']      = 'dsdiff';
+		$info['audio']['bitrate_mode']    = 'cbr';
+		$info['audio']['bits_per_sample'] = 1;
+
+		$info['dsdiff'] = array();
+		while (!$this->feof() && ($ChunkHeader = $this->fread(12))) {
+			if (strlen($ChunkHeader) < 12) {
+				$this->error('Expecting chunk header at offset '.(isset($thisChunk['offset']) ? $thisChunk['offset'] : 'N/A').', found insufficient data in file, aborting parsing');
+				break;
+			}
+			$thisChunk = array();
+			$thisChunk['offset'] = $this->ftell() - 12;
+			$thisChunk['name'] = substr($ChunkHeader, 0, 4);
+			if (!preg_match('#^[\\x21-\\x7E]+ *$#', $thisChunk['name'])) {
+				// "a concatenation of four printable ASCII characters in the range ' ' (space, 0x20) through '~'(0x7E). Space (0x20) cannot precede printing characters; trailing spaces are allowed."
+				$this->error('Invalid chunk name "'.$thisChunk['name'].'" ('.getid3_lib::PrintHexBytes($thisChunk['name']).') at offset '.$thisChunk['offset'].', aborting parsing');
+			}
+			$thisChunk['size'] = getid3_lib::BigEndian2Int(substr($ChunkHeader, 4, 8));
+			$datasize = $thisChunk['size'] + ($thisChunk['size'] % 2); // "If the data is an odd number of bytes in length, a pad byte must be added at the end. The pad byte is not included in ckDataSize."
+
+			switch ($thisChunk['name']) {
+				case 'FRM8':
+					$thisChunk['form_type'] = $this->fread(4);
+					if ($thisChunk['form_type'] != 'DSD ') {
+						$this->error('Expecting "DSD " at offset '.($this->ftell() - 4).', found "'.getid3_lib::PrintHexBytes($thisChunk['form_type']).'", aborting parsing');
+						break 2;
+					}
+					// do nothing further, prevent skipping subchunks
+					break;
+				case 'PROP': // PROPerty chunk
+					$thisChunk['prop_type'] = $this->fread(4);
+					if ($thisChunk['prop_type'] != 'SND ') {
+						$this->error('Expecting "SND " at offset '.($this->ftell() - 4).', found "'.getid3_lib::PrintHexBytes($thisChunk['prop_type']).'", aborting parsing');
+						break 2;
+					}
+					// do nothing further, prevent skipping subchunks
+					break;
+				case 'DIIN': // eDIted master INformation chunk
+					// do nothing, just prevent skipping subchunks
+					break;
+
+				case 'FVER': // Format VERsion chunk
+					if ($thisChunk['size'] == 4) {
+						$FVER = $this->fread(4);
+						$info['dsdiff']['format_version'] = ord($FVER[0]).'.'.ord($FVER[1]).'.'.ord($FVER[2]).'.'.ord($FVER[3]);
+						unset($FVER);
+					} else {
+						$this->warning('Expecting "FVER" chunk to be 4 bytes, found '.$thisChunk['size'].' bytes, skipping chunk');
+						$this->fseek($datasize, SEEK_CUR);
+					}
+					break;
+				case 'FS  ': // sample rate chunk
+					if ($thisChunk['size'] == 4) {
+						$info['dsdiff']['sample_rate'] = getid3_lib::BigEndian2Int($this->fread(4));
+						$info['audio']['sample_rate'] = $info['dsdiff']['sample_rate'];
+					} else {
+						$this->warning('Expecting "FVER" chunk to be 4 bytes, found '.$thisChunk['size'].' bytes, skipping chunk');
+						$this->fseek($datasize, SEEK_CUR);
+					}
+					break;
+				case 'CHNL': // CHaNneLs chunk
+					$thisChunk['num_channels'] = getid3_lib::BigEndian2Int($this->fread(2));
+					if ($thisChunk['num_channels'] == 0) {
+						$this->warning('channel count should be greater than zero, skipping chunk');
+						$this->fseek($datasize - 2, SEEK_CUR);
+					}
+					for ($i = 0; $i < $thisChunk['num_channels']; $i++) {
+						$thisChunk['channels'][$i] = $this->fread(4);
+					}
+					$info['audio']['channels'] = $thisChunk['num_channels'];
+					break;
+				case 'CMPR': // CoMPRession type chunk
+					$thisChunk['compression_type'] = $this->fread(4);
+					$info['audio']['dataformat'] = trim($thisChunk['compression_type']);
+					$humanReadableByteLength = getid3_lib::BigEndian2Int($this->fread(1));
+					$thisChunk['compression_name'] = $this->fread($humanReadableByteLength);
+					if (($humanReadableByteLength % 2) == 0) {
+						// need to seek to multiple of 2 bytes, human-readable string length is only one byte long so if the string is an even number of bytes we need to seek past a padding byte after the string
+						$this->fseek(1, SEEK_CUR);
+					}
+					unset($humanReadableByteLength);
+					break;
+				case 'ABSS': // ABSolute Start time chunk
+					$ABSS = $this->fread(8);
+					$info['dsdiff']['absolute_start_time']['hours']   = getid3_lib::BigEndian2Int(substr($ABSS, 0, 2));
+					$info['dsdiff']['absolute_start_time']['minutes'] = getid3_lib::BigEndian2Int(substr($ABSS, 2, 1));
+					$info['dsdiff']['absolute_start_time']['seconds'] = getid3_lib::BigEndian2Int(substr($ABSS, 3, 1));
+					$info['dsdiff']['absolute_start_time']['samples'] = getid3_lib::BigEndian2Int(substr($ABSS, 4, 4));
+					unset($ABSS);
+					break;
+				case 'LSCO': // LoudSpeaker COnfiguration chunk
+					// 0 = 2-channel stereo set-up
+					// 3 = 5-channel set-up according to ITU-R BS.775-1 [ITU]
+					// 4 = 6-channel set-up, 5-channel set-up according to ITU-R BS.775-1 [ITU], plus additional Low Frequency Enhancement (LFE) loudspeaker. Also known as "5.1 configuration"
+					// 65535 = Undefined channel set-up
+					$thisChunk['loundspeaker_config_id'] = getid3_lib::BigEndian2Int($this->fread(2));
+					break;
+				case 'COMT': // COMmenTs chunk
+					$thisChunk['num_comments'] = getid3_lib::BigEndian2Int($this->fread(2));
+					for ($i = 0; $i < $thisChunk['num_comments']; $i++) {
+						$thisComment = array();
+						$COMT = $this->fread(14);
+						$thisComment['creation_year']   = getid3_lib::BigEndian2Int(substr($COMT,  0, 2));
+						$thisComment['creation_month']  = getid3_lib::BigEndian2Int(substr($COMT,  2, 1));
+						$thisComment['creation_day']    = getid3_lib::BigEndian2Int(substr($COMT,  3, 1));
+						$thisComment['creation_hour']   = getid3_lib::BigEndian2Int(substr($COMT,  4, 1));
+						$thisComment['creation_minute'] = getid3_lib::BigEndian2Int(substr($COMT,  5, 1));
+						$thisComment['comment_type_id'] = getid3_lib::BigEndian2Int(substr($COMT,  6, 2));
+						$thisComment['comment_ref_id']  = getid3_lib::BigEndian2Int(substr($COMT,  8, 2));
+						$thisComment['string_length']   = getid3_lib::BigEndian2Int(substr($COMT, 10, 4));
+						$thisComment['comment_text'] = $this->fread($thisComment['string_length']);
+						if ($thisComment['string_length'] % 2) {
+							// commentText[] is the description of the Comment. This text must be padded with a byte at the end, if needed, to make it an even number of bytes long. This pad byte, if present, is not included in count.
+							$this->fseek(1, SEEK_CUR);
+						}
+						$thisComment['comment_type']      = $this->DSDIFFcmtType($thisComment['comment_type_id']);
+						$thisComment['comment_reference'] = $this->DSDIFFcmtRef($thisComment['comment_type_id'], $thisComment['comment_ref_id']);
+						$thisComment['creation_unix'] = mktime($thisComment['creation_hour'], $thisComment['creation_minute'], 0, $thisComment['creation_month'], $thisComment['creation_day'], $thisComment['creation_year']);
+						$thisChunk['comments'][$i] = $thisComment;
+
+						$commentkey = ($thisComment['comment_reference'] ?: 'comment');
+						$info['dsdiff']['comments'][$commentkey][] = $thisComment['comment_text'];
+						unset($thisComment);
+					}
+					break;
+				case 'MARK': // MARKer chunk
+					$MARK = $this->fread(22);
+					$thisChunk['marker_hours']   = getid3_lib::BigEndian2Int(substr($MARK,  0, 2));
+					$thisChunk['marker_minutes'] = getid3_lib::BigEndian2Int(substr($MARK,  2, 1));
+					$thisChunk['marker_seconds'] = getid3_lib::BigEndian2Int(substr($MARK,  3, 1));
+					$thisChunk['marker_samples'] = getid3_lib::BigEndian2Int(substr($MARK,  4, 4));
+					$thisChunk['marker_offset']  = getid3_lib::BigEndian2Int(substr($MARK,  8, 4));
+					$thisChunk['marker_type_id'] = getid3_lib::BigEndian2Int(substr($MARK, 12, 2));
+					$thisChunk['marker_channel'] = getid3_lib::BigEndian2Int(substr($MARK, 14, 2));
+					$thisChunk['marker_flagraw'] = getid3_lib::BigEndian2Int(substr($MARK, 16, 2));
+					$thisChunk['string_length']  = getid3_lib::BigEndian2Int(substr($MARK, 18, 4));
+					$thisChunk['description'] = ($thisChunk['string_length'] ? $this->fread($thisChunk['string_length']) : '');
+					if ($thisChunk['string_length'] % 2) {
+						// markerText[] is the description of the marker. This text must be padded with a byte at the end, if needed, to make it an even number of bytes long. This pad byte, if present, is not included in count.
+						$this->fseek(1, SEEK_CUR);
+					}
+					$thisChunk['marker_type'] = $this->DSDIFFmarkType($thisChunk['marker_type_id']);
+					unset($MARK);
+					break;
+				case 'DIAR': // artist chunk
+				case 'DITI': // title chunk
+					$thisChunk['string_length']  = getid3_lib::BigEndian2Int($this->fread(4));
+					$thisChunk['description'] = ($thisChunk['string_length'] ? $this->fread($thisChunk['string_length']) : '');
+					if ($thisChunk['string_length'] % 2) {
+						// This text must be padded with a byte at the end, if needed, to make it an even number of bytes long. This pad byte, if present, is not included in count.
+						$this->fseek(1, SEEK_CUR);
+					}
+
+					if ($commentkey = (($thisChunk['name'] == 'DIAR') ? 'artist' : (($thisChunk['name'] == 'DITI') ? 'title' : ''))) {
+						@$info['dsdiff']['comments'][$commentkey][] = $thisChunk['description'];
+					}
+					break;
+				case 'EMID': // Edited Master ID chunk
+					if ($thisChunk['size']) {
+						$thisChunk['identifier'] = $this->fread($thisChunk['size']);
+					}
+					break;
+
+				case 'ID3 ':
+					$endOfID3v2 = $this->ftell() + $datasize; // we will need to reset the filepointer after parsing ID3v2
+
+					getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
+					$getid3_temp = new getID3();
+					$getid3_temp->openfile($this->getid3->filename, null, $this->getid3->fp);
+					$getid3_id3v2 = new getid3_id3v2($getid3_temp);
+					$getid3_id3v2->StartingOffset = $this->ftell();
+					if ($thisChunk['valid'] = $getid3_id3v2->Analyze()) {
+						$info['id3v2'] = $getid3_temp->info['id3v2'];
+					}
+					unset($getid3_temp, $getid3_id3v2);
+
+					$this->fseek($endOfID3v2);
+					break;
+
+				case 'DSD ': // DSD sound data chunk
+				case 'DST ': // DST sound data chunk
+					// actual audio data, we're not interested, skip
+					$this->fseek($datasize, SEEK_CUR);
+					break;
+				default:
+					$this->warning('Unhandled chunk "'.$thisChunk['name'].'"');
+					$this->fseek($datasize, SEEK_CUR);
+					break;
+			}
+
+			@$info['dsdiff']['chunks'][] = $thisChunk;
+			//break;
+		}
+		if (empty($info['audio']['bitrate']) && !empty($info['audio']['channels']) && !empty($info['audio']['sample_rate']) && !empty($info['audio']['bits_per_sample'])) {
+			$info['audio']['bitrate'] = $info['audio']['bits_per_sample'] * $info['audio']['sample_rate'] * $info['audio']['channels'];
+		}
+
+		return true;
+	}
+
+	/**
+	 * @param int $cmtType
+	 *
+	 * @return string
+	 */
+	public static function DSDIFFcmtType($cmtType) {
+		static $DSDIFFcmtType = array(
+			0 => 'General (album) Comment',
+			1 => 'Channel Comment',
+			2 => 'Sound Source',
+			3 => 'File History',
+		);
+		return (isset($DSDIFFcmtType[$cmtType]) ? $DSDIFFcmtType[$cmtType] : 'reserved');
+	}
+
+	/**
+	 * @param int $cmtType
+	 * @param int $cmtRef
+	 *
+	 * @return string
+	 */
+	public static function DSDIFFcmtRef($cmtType, $cmtRef) {
+		static $DSDIFFcmtRef = array(
+			2 => array(  // Sound Source
+				0 => 'DSD recording',
+				1 => 'Analogue recording',
+				2 => 'PCM recording',
+			),
+			3 => array( // File History
+				0 => 'comment',   // General Remark
+				1 => 'encodeby',  // Name of the operator
+				2 => 'encoder',   // Name or type of the creating machine
+				3 => 'timezone',  // Time zone information
+				4 => 'revision',  // Revision of the file
+			),
+		);
+		switch ($cmtType) {
+			case 0:
+				// If the comment type is General Comment the comment reference must be 0
+				return '';
+			case 1:
+				// If the comment type is Channel Comment, the comment reference defines the channel number to which the comment belongs
+				return ($cmtRef ? 'channel '.$cmtRef : 'all channels');
+			case 2:
+			case 3:
+				return (isset($DSDIFFcmtRef[$cmtType][$cmtRef]) ? $DSDIFFcmtRef[$cmtType][$cmtRef] : 'reserved');
+		}
+		return 'unsupported $cmtType='.$cmtType;
+	}
+
+	/**
+	 * @param int $markType
+	 *
+	 * @return string
+	 */
+	public static function DSDIFFmarkType($markType) {
+		static $DSDIFFmarkType = array(
+			0 => 'TrackStart',   // Entry point for a Track start
+			1 => 'TrackStop',    // Entry point for ending a Track
+			2 => 'ProgramStart', // Start point of 2-channel or multi-channel area
+			3 => 'Obsolete',     //
+			4 => 'Index',        // Entry point of an Index
+		);
+		return (isset($DSDIFFmarkType[$markType]) ? $DSDIFFmarkType[$markType] : 'reserved');
+	}
+
+}

Added: plog/branches/lifetype-1.2/class/gallery/getid3/module.audio.dsf.php
===================================================================
--- plog/branches/lifetype-1.2/class/gallery/getid3/module.audio.dsf.php	                        (rev 0)
+++ plog/branches/lifetype-1.2/class/gallery/getid3/module.audio.dsf.php	2020-07-15 07:59:26 UTC (rev 7238)
@@ -0,0 +1,142 @@
+<?php
+
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org>               //
+//  available at https://github.com/JamesHeinrich/getID3       //
+//            or https://www.getid3.org                        //
+//            or http://getid3.sourceforge.net                 //
+//  see readme.txt for more details                            //
+/////////////////////////////////////////////////////////////////
+//                                                             //
+// module.audio.dsf.php                                        //
+// module for analyzing dsf/DSF Audio files                    //
+// dependencies: module.tag.id3v2.php                          //
+//                                                            ///
+/////////////////////////////////////////////////////////////////
+
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+	exit;
+}
+getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
+
+class getid3_dsf extends getid3_handler
+{
+	/**
+	 * @return bool
+	 */
+	public function Analyze() {
+		$info = &$this->getid3->info;
+
+		$info['fileformat']            = 'dsf';
+		$info['audio']['dataformat']   = 'dsf';
+		$info['audio']['lossless']     = true;
+		$info['audio']['bitrate_mode'] = 'cbr';
+
+		$this->fseek($info['avdataoffset']);
+		$dsfheader = $this->fread(28 + 12);
+
+		$headeroffset = 0;
+		$info['dsf']['dsd']['magic'] = substr($dsfheader, $headeroffset, 4);
+		$headeroffset += 4;
+		$magic = 'DSD ';
+		if ($info['dsf']['dsd']['magic'] != $magic) {
+			$this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['dsf']['dsd']['magic']).'"');
+			unset($info['fileformat']);
+			unset($info['audio']);
+			unset($info['dsf']);
+			return false;
+		}
+		$info['dsf']['dsd']['dsd_chunk_size']     = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8)); // should be 28
+		$headeroffset += 8;
+		$info['dsf']['dsd']['dsf_file_size']      = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8));
+		$headeroffset += 8;
+		$info['dsf']['dsd']['meta_chunk_offset']  = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8));
+		$headeroffset += 8;
+
+
+		$info['dsf']['fmt']['magic'] = substr($dsfheader, $headeroffset, 4);
+		$headeroffset += 4;
+		$magic = 'fmt ';
+		if ($info['dsf']['fmt']['magic'] != $magic) {
+			$this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$headeroffset.', found "'.getid3_lib::PrintHexBytes($info['dsf']['fmt']['magic']).'"');
+			return false;
+		}
+		$info['dsf']['fmt']['fmt_chunk_size']     = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8));  // usually 52 bytes
+		$headeroffset += 8;
+		$dsfheader .= $this->fread($info['dsf']['fmt']['fmt_chunk_size'] - 12 + 12);  // we have already read the entire DSD chunk, plus 12 bytes of FMT. We now want to read the size of FMT, plus 12 bytes into the next chunk to get magic and size.
+		if (strlen($dsfheader) != ($info['dsf']['dsd']['dsd_chunk_size'] + $info['dsf']['fmt']['fmt_chunk_size'] + 12)) {
+			$this->error('Expecting '.($info['dsf']['dsd']['dsd_chunk_size'] + $info['dsf']['fmt']['fmt_chunk_size']).' bytes header, found '.strlen($dsfheader).' bytes');
+			return false;
+		}
+		$info['dsf']['fmt']['format_version']     = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));  // usually "1"
+		$headeroffset += 4;
+		$info['dsf']['fmt']['format_id']          = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));  // usually "0" = "DSD Raw"
+		$headeroffset += 4;
+		$info['dsf']['fmt']['channel_type_id']    = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));
+		$headeroffset += 4;
+		$info['dsf']['fmt']['channels']           = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));
+		$headeroffset += 4;
+		$info['dsf']['fmt']['sample_rate']        = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));
+		$headeroffset += 4;
+		$info['dsf']['fmt']['bits_per_sample']    = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));
+		$headeroffset += 4;
+		$info['dsf']['fmt']['sample_count']       = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8));
+		$headeroffset += 8;
+		$info['dsf']['fmt']['channel_block_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));
+		$headeroffset += 4;
+		$info['dsf']['fmt']['reserved']           = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4)); // zero-filled
+		$headeroffset += 4;
+
+
+		$info['dsf']['data']['magic'] = substr($dsfheader, $headeroffset, 4);
+		$headeroffset += 4;
+		$magic = 'data';
+		if ($info['dsf']['data']['magic'] != $magic) {
+			$this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$headeroffset.', found "'.getid3_lib::PrintHexBytes($info['dsf']['data']['magic']).'"');
+			return false;
+		}
+		$info['dsf']['data']['data_chunk_size']    = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8));
+		$headeroffset += 8;
+		$info['avdataoffset'] = $headeroffset;
+		$info['avdataend']    = $info['avdataoffset'] + $info['dsf']['data']['data_chunk_size'];
+
+
+		if ($info['dsf']['dsd']['meta_chunk_offset'] > 0) {
+			$getid3_id3v2 = new getid3_id3v2($this->getid3);
+			$getid3_id3v2->StartingOffset = $info['dsf']['dsd']['meta_chunk_offset'];
+			$getid3_id3v2->Analyze();
+			unset($getid3_id3v2);
+		}
+
+
+		$info['dsf']['fmt']['channel_type'] = $this->DSFchannelTypeLookup($info['dsf']['fmt']['channel_type_id']);
+		$info['audio']['channelmode']       = $info['dsf']['fmt']['channel_type'];
+		$info['audio']['bits_per_sample']   = $info['dsf']['fmt']['bits_per_sample'];
+		$info['audio']['sample_rate']       = $info['dsf']['fmt']['sample_rate'];
+		$info['audio']['channels']          = $info['dsf']['fmt']['channels'];
+		$info['audio']['bitrate']           = $info['audio']['bits_per_sample'] * $info['audio']['sample_rate'] * $info['audio']['channels'];
+		$info['playtime_seconds']           = ($info['dsf']['data']['data_chunk_size'] * 8) / $info['audio']['bitrate'];
+
+		return true;
+	}
+
+	/**
+	 * @param int $channel_type_id
+	 *
+	 * @return string
+	 */
+	public static function DSFchannelTypeLookup($channel_type_id) {
+		static $DSFchannelTypeLookup = array(
+			                  // interleaving order:
+			1 => 'mono',      // 1: Mono
+			2 => 'stereo',    // 1: Front-Left; 2: Front-Right
+			3 => '3-channel', // 1: Front-Left; 2: Front-Right; 3: Center
+			4 => 'quad',      // 1: Front-Left; 2: Front-Right; 3: Back-Left; 4: Back-Right
+			5 => '4-channel', // 1: Front-Left; 2: Front-Right; 3: Center;    4: Low-Frequency
+			6 => '5-channel', // 1: Front-Left; 2: Front-Right; 3: Center;    4: Back-Left      5: Back-Right
+			7 => '5.1',       // 1: Front-Left; 2: Front-Right; 3: Center;    4: Low-Frequency; 5: Back-Left;  6: Back-Right
+		);
+		return (isset($DSFchannelTypeLookup[$channel_type_id]) ? $DSFchannelTypeLookup[$channel_type_id] : '');
+	}
+
+}

Added: plog/branches/lifetype-1.2/class/gallery/getid3/module.audio.dss.php
===================================================================
--- plog/branches/lifetype-1.2/class/gallery/getid3/module.audio.dss.php	                        (rev 0)
+++ plog/branches/lifetype-1.2/class/gallery/getid3/module.audio.dss.php	2020-07-15 07:59:26 UTC (rev 7238)
@@ -0,0 +1,114 @@
+<?php
+
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org>               //
+//  available at https://github.com/JamesHeinrich/getID3       //
+//            or https://www.getid3.org                        //
+//            or http://getid3.sourceforge.net                 //
+//  see readme.txt for more details                            //
+/////////////////////////////////////////////////////////////////
+//                                                             //
+// module.audio.dss.php                                        //
+// module for analyzing Digital Speech Standard (DSS) files    //
+// dependencies: NONE                                          //
+//                                                            ///
+/////////////////////////////////////////////////////////////////
+
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+	exit;
+}
+
+class getid3_dss extends getid3_handler
+{
+	/**
+	 * @return bool
+	 */
+	public function Analyze() {
+		$info = &$this->getid3->info;
+
+		$this->fseek($info['avdataoffset']);
+		$DSSheader  = $this->fread(1540);
+
+		if (!preg_match('#^[\\x02-\\x08]ds[s2]#', $DSSheader)) {
+			$this->error('Expecting "[02-08] 64 73 [73|32]" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($DSSheader, 0, 4)).'"');
+			return false;
+		}
+
+		// some structure information taken from http://cpansearch.perl.org/src/RGIBSON/Audio-DSS-0.02/lib/Audio/DSS.pm
+		$info['encoding']              = 'ISO-8859-1'; // not certain, but assumed
+		$info['dss'] = array();
+
+		$info['fileformat']            = 'dss';
+		$info['mime_type']             = 'audio/x-'.substr($DSSheader, 1, 3); // "audio/x-dss" or "audio/x-ds2"
+		$info['audio']['dataformat']   =            substr($DSSheader, 1, 3); //         "dss" or         "ds2"
+		$info['audio']['bitrate_mode'] = 'cbr';
+
+		$info['dss']['version']            =                            ord(substr($DSSheader,    0,   1));
+		$info['dss']['hardware']           =                           trim(substr($DSSheader,   12,  16)); // identification string for hardware used to create the file, e.g. "DPM 9600", "DS2400"
+		$info['dss']['unknown1']           =   getid3_lib::LittleEndian2Int(substr($DSSheader,   28,   4));
+		// 32-37 = "FE FF FE FF F7 FF" in all the sample files I've seen
+		$info['dss']['date_create_unix']   = $this->DSSdateStringToUnixDate(substr($DSSheader,   38,  12));
+		$info['dss']['date_complete_unix'] = $this->DSSdateStringToUnixDate(substr($DSSheader,   50,  12));
+		$info['dss']['playtime_sec']       = ((int) substr($DSSheader, 62, 2) * 3600) + ((int) substr($DSSheader, 64, 2) * 60) + (int) substr($DSSheader, 66, 2); // approximate file playtime in HHMMSS
+		if ($info['dss']['version'] <= 3) {
+			$info['dss']['playtime_ms']        =   getid3_lib::LittleEndian2Int(substr($DSSheader,  512,   4)); // exact file playtime in milliseconds. Has also been observed at offset 530 in one sample file, with something else (unknown) at offset 512
+			$info['dss']['priority']           =                            ord(substr($DSSheader,  793,   1));
+			$info['dss']['comments']           =                           trim(substr($DSSheader,  798, 100));
+			$info['dss']['sample_rate_index']  =                            ord(substr($DSSheader, 1538,   1));  // this isn't certain, this may or may not be where the sample rate info is stored, but it seems consistent on my small selection of sample files
+			$info['audio']['sample_rate']      = $this->DSSsampleRateLookup($info['dss']['sample_rate_index']);
+		} else {
+			$this->getid3->warning('DSS above version 3 not fully supported in this version of getID3. Any additional documentation or format specifications would be welcome. This file is version '.$info['dss']['version']);
+		}
+
+		$info['audio']['bits_per_sample']  = 16; // maybe, maybe not -- most compressed audio formats don't have a fixed bits-per-sample value, but this is a reasonable approximation
+		$info['audio']['channels']         = 1;
+
+		if (!empty($info['dss']['playtime_ms']) && (floor($info['dss']['playtime_ms'] / 1000) == $info['dss']['playtime_sec'])) { // *should* just be playtime_ms / 1000 but at least one sample file has playtime_ms at offset 530 instead of offset 512, so safety check
+			$info['playtime_seconds'] = $info['dss']['playtime_ms'] / 1000;
+		} else {
+			$info['playtime_seconds'] = $info['dss']['playtime_sec'];
+			if (!empty($info['dss']['playtime_ms'])) {
+				$this->getid3->warning('playtime_ms ('.number_format($info['dss']['playtime_ms'] / 1000, 3).') does not match playtime_sec ('.number_format($info['dss']['playtime_sec']).') - using playtime_sec value');
+			}
+		}
+		$info['audio']['bitrate'] = ($info['filesize'] * 8) / $info['playtime_seconds'];
+
+		return true;
+	}
+
+	/**
+	 * @param string $datestring
+	 *
+	 * @return int|false
+	 */
+	public function DSSdateStringToUnixDate($datestring) {
+		$y = (int) substr($datestring,  0, 2);
+		$m = substr($datestring,  2, 2);
+		$d = substr($datestring,  4, 2);
+		$h = substr($datestring,  6, 2);
+		$i = substr($datestring,  8, 2);
+		$s = substr($datestring, 10, 2);
+		$y += (($y < 95) ? 2000 : 1900);
+		return mktime($h, $i, $s, $m, $d, $y);
+	}
+
+	/**
+	 * @param int $sample_rate_index
+	 *
+	 * @return int|false
+	 */
+	public function DSSsampleRateLookup($sample_rate_index) {
+		static $dssSampleRateLookup = array(
+			0x0A => 16000,
+			0x0C => 11025,
+			0x0D => 12000,
+			0x15 =>  8000,
+		);
+		if (!array_key_exists($sample_rate_index, $dssSampleRateLookup)) {
+			$this->getid3->warning('unknown sample_rate_index: 0x'.strtoupper(dechex($sample_rate_index)));
+			return false;
+		}
+		return $dssSampleRateLookup[$sample_rate_index];
+	}
+
+}

Added: plog/branches/lifetype-1.2/class/gallery/getid3/module.audio.dts.php
===================================================================
--- plog/branches/lifetype-1.2/class/gallery/getid3/module.audio.dts.php	                        (rev 0)
+++ plog/branches/lifetype-1.2/class/gallery/getid3/module.audio.dts.php	2020-07-15 07:59:26 UTC (rev 7238)
@@ -0,0 +1,327 @@
+<?php
+
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org>               //
+//  available at https://github.com/JamesHeinrich/getID3       //
+//            or https://www.getid3.org                        //
+//            or http://getid3.sourceforge.net                 //
+//  see readme.txt for more details                            //
+/////////////////////////////////////////////////////////////////
+//                                                             //
+// module.audio.dts.php                                        //
+// module for analyzing DTS Audio files                        //
+// dependencies: NONE                                          //
+//                                                             //
+/////////////////////////////////////////////////////////////////
+
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+	exit;
+}
+
+/**
+* @tutorial http://wiki.multimedia.cx/index.php?title=DTS
+*/
+class getid3_dts extends getid3_handler
+{
+	/**
+	 * Default DTS syncword used in native .cpt or .dts formats.
+	 */
+	const syncword = "\x7F\xFE\x80\x01";
+
+	/**
+	 * @var int
+	 */
+	private $readBinDataOffset = 0;
+
+	/**
+	 * Possible syncwords indicating bitstream encoding.
+	 */
+	public static $syncwords = array(
+		0 => "\x7F\xFE\x80\x01",  // raw big-endian
+		1 => "\xFE\x7F\x01\x80",  // raw little-endian
+		2 => "\x1F\xFF\xE8\x00",  // 14-bit big-endian
+		3 => "\xFF\x1F\x00\xE8"); // 14-bit little-endian
+
+	/**
+	 * @return bool
+	 */
+	public function Analyze() {
+		$info = &$this->getid3->info;
+		$info['fileformat'] = 'dts';
+
+		$this->fseek($info['avdataoffset']);
+		$DTSheader = $this->fread(20); // we only need 2 words magic + 6 words frame header, but these words may be normal 16-bit words OR 14-bit words with 2 highest bits set to zero, so 8 words can be either 8*16/8 = 16 bytes OR 8*16*(16/14)/8 = 18.3 bytes
+
+		// check syncword
+		$sync = substr($DTSheader, 0, 4);
+		if (($encoding = array_search($sync, self::$syncwords)) !== false) {
+
+			$info['dts']['raw']['magic'] = $sync;
+			$this->readBinDataOffset = 32;
+
+		} elseif ($this->isDependencyFor('matroska')) {
+
+			// Matroska contains DTS without syncword encoded as raw big-endian format
+			$encoding = 0;
+			$this->readBinDataOffset = 0;
+
+		} else {
+
+			unset($info['fileformat']);
+			return $this->error('Expecting "'.implode('| ', array_map('getid3_lib::PrintHexBytes', self::$syncwords)).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($sync).'"');
+
+		}
+
+		// decode header
+		$fhBS = '';
+		for ($word_offset = 0; $word_offset <= strlen($DTSheader); $word_offset += 2) {
+			switch ($encoding) {
+				case 0: // raw big-endian
+					$fhBS .=        getid3_lib::BigEndian2Bin(       substr($DTSheader, $word_offset, 2) );
+					break;
+				case 1: // raw little-endian
+					$fhBS .=        getid3_lib::BigEndian2Bin(strrev(substr($DTSheader, $word_offset, 2)));
+					break;
+				case 2: // 14-bit big-endian
+					$fhBS .= substr(getid3_lib::BigEndian2Bin(       substr($DTSheader, $word_offset, 2) ), 2, 14);
+					break;
+				case 3: // 14-bit little-endian
+					$fhBS .= substr(getid3_lib::BigEndian2Bin(strrev(substr($DTSheader, $word_offset, 2))), 2, 14);
+					break;
+			}
+		}
+
+		$info['dts']['raw']['frame_type']             =        $this->readBinData($fhBS,  1);
+		$info['dts']['raw']['deficit_samples']        =        $this->readBinData($fhBS,  5);
+		$info['dts']['flags']['crc_present']          = (bool) $this->readBinData($fhBS,  1);
+		$info['dts']['raw']['pcm_sample_blocks']      =        $this->readBinData($fhBS,  7);
+		$info['dts']['raw']['frame_byte_size']        =        $this->readBinData($fhBS, 14);
+		$info['dts']['raw']['channel_arrangement']    =        $this->readBinData($fhBS,  6);
+		$info['dts']['raw']['sample_frequency']       =        $this->readBinData($fhBS,  4);
+		$info['dts']['raw']['bitrate']                =        $this->readBinData($fhBS,  5);
+		$info['dts']['flags']['embedded_downmix']     = (bool) $this->readBinData($fhBS,  1);
+		$info['dts']['flags']['dynamicrange']         = (bool) $this->readBinData($fhBS,  1);
+		$info['dts']['flags']['timestamp']            = (bool) $this->readBinData($fhBS,  1);
+		$info['dts']['flags']['auxdata']              = (bool) $this->readBinData($fhBS,  1);
+		$info['dts']['flags']['hdcd']                 = (bool) $this->readBinData($fhBS,  1);
+		$info['dts']['raw']['extension_audio']        =        $this->readBinData($fhBS,  3);
+		$info['dts']['flags']['extended_coding']      = (bool) $this->readBinData($fhBS,  1);
+		$info['dts']['flags']['audio_sync_insertion'] = (bool) $this->readBinData($fhBS,  1);
+		$info['dts']['raw']['lfe_effects']            =        $this->readBinData($fhBS,  2);
+		$info['dts']['flags']['predictor_history']    = (bool) $this->readBinData($fhBS,  1);
+		if ($info['dts']['flags']['crc_present']) {
+			$info['dts']['raw']['crc16']              =        $this->readBinData($fhBS, 16);
+		}
+		$info['dts']['flags']['mri_perfect_reconst']  = (bool) $this->readBinData($fhBS,  1);
+		$info['dts']['raw']['encoder_soft_version']   =        $this->readBinData($fhBS,  4);
+		$info['dts']['raw']['copy_history']           =        $this->readBinData($fhBS,  2);
+		$info['dts']['raw']['bits_per_sample']        =        $this->readBinData($fhBS,  2);
+		$info['dts']['flags']['surround_es']          = (bool) $this->readBinData($fhBS,  1);
+		$info['dts']['flags']['front_sum_diff']       = (bool) $this->readBinData($fhBS,  1);
+		$info['dts']['flags']['surround_sum_diff']    = (bool) $this->readBinData($fhBS,  1);
+		$info['dts']['raw']['dialog_normalization']   =        $this->readBinData($fhBS,  4);
+
+
+		$info['dts']['bitrate']              = self::bitrateLookup($info['dts']['raw']['bitrate']);
+		$info['dts']['bits_per_sample']      = self::bitPerSampleLookup($info['dts']['raw']['bits_per_sample']);
+		$info['dts']['sample_rate']          = self::sampleRateLookup($info['dts']['raw']['sample_frequency']);
+		$info['dts']['dialog_normalization'] = self::dialogNormalization($info['dts']['raw']['dialog_normalization'], $info['dts']['raw']['encoder_soft_version']);
+		$info['dts']['flags']['lossless']    = (($info['dts']['raw']['bitrate'] == 31) ? true  : false);
+		$info['dts']['bitrate_mode']         = (($info['dts']['raw']['bitrate'] == 30) ? 'vbr' : 'cbr');
+		$info['dts']['channels']             = self::numChannelsLookup($info['dts']['raw']['channel_arrangement']);
+		$info['dts']['channel_arrangement']  = self::channelArrangementLookup($info['dts']['raw']['channel_arrangement']);
+
+		$info['audio']['dataformat']          = 'dts';
+		$info['audio']['lossless']            = $info['dts']['flags']['lossless'];
+		$info['audio']['bitrate_mode']        = $info['dts']['bitrate_mode'];
+		$info['audio']['bits_per_sample']     = $info['dts']['bits_per_sample'];
+		$info['audio']['sample_rate']         = $info['dts']['sample_rate'];
+		$info['audio']['channels']            = $info['dts']['channels'];
+		$info['audio']['bitrate']             = $info['dts']['bitrate'];
+		if (isset($info['avdataend']) && !empty($info['dts']['bitrate']) && is_numeric($info['dts']['bitrate'])) {
+			$info['playtime_seconds']         = ($info['avdataend'] - $info['avdataoffset']) / ($info['dts']['bitrate'] / 8);
+			if (($encoding == 2) || ($encoding == 3)) {
+				// 14-bit data packed into 16-bit words, so the playtime is wrong because only (14/16) of the bytes in the data portion of the file are used at the specified bitrate
+				$info['playtime_seconds'] *= (14 / 16);
+			}
+		}
+		return true;
+	}
+
+	/**
+	 * @param string $bin
+	 * @param int $length
+	 *
+	 * @return int
+	 */
+	private function readBinData($bin, $length) {
+		$data = substr($bin, $this->readBinDataOffset, $length);
+		$this->readBinDataOffset += $length;
+
+		return bindec($data);
+	}
+
+	/**
+	 * @param int $index
+	 *
+	 * @return int|string|false
+	 */
+	public static function bitrateLookup($index) {
+		static $lookup = array(
+			0  => 32000,
+			1  => 56000,
+			2  => 64000,
+			3  => 96000,
+			4  => 112000,
+			5  => 128000,
+			6  => 192000,
+			7  => 224000,
+			8  => 256000,
+			9  => 320000,
+			10 => 384000,
+			11 => 448000,
+			12 => 512000,
+			13 => 576000,
+			14 => 640000,
+			15 => 768000,
+			16 => 960000,
+			17 => 1024000,
+			18 => 1152000,
+			19 => 1280000,
+			20 => 1344000,
+			21 => 1408000,
+			22 => 1411200,
+			23 => 1472000,
+			24 => 1536000,
+			25 => 1920000,
+			26 => 2048000,
+			27 => 3072000,
+			28 => 3840000,
+			29 => 'open',
+			30 => 'variable',
+			31 => 'lossless',
+		);
+		return (isset($lookup[$index]) ? $lookup[$index] : false);
+	}
+
+	/**
+	 * @param int $index
+	 *
+	 * @return int|string|false
+	 */
+	public static function sampleRateLookup($index) {
+		static $lookup = array(
+			0  => 'invalid',
+			1  => 8000,
+			2  => 16000,
+			3  => 32000,
+			4  => 'invalid',
+			5  => 'invalid',
+			6  => 11025,
+			7  => 22050,
+			8  => 44100,
+			9  => 'invalid',
+			10 => 'invalid',
+			11 => 12000,
+			12 => 24000,
+			13 => 48000,
+			14 => 'invalid',
+			15 => 'invalid',
+		);
+		return (isset($lookup[$index]) ? $lookup[$index] : false);
+	}
+
+	/**
+	 * @param int $index
+	 *
+	 * @return int|false
+	 */
+	public static function bitPerSampleLookup($index) {
+		static $lookup = array(
+			0  => 16,
+			1  => 20,
+			2  => 24,
+			3  => 24,
+		);
+		return (isset($lookup[$index]) ? $lookup[$index] : false);
+	}
+
+	/**
+	 * @param int $index
+	 *
+	 * @return int|false
+	 */
+	public static function numChannelsLookup($index) {
+		switch ($index) {
+			case 0:
+				return 1;
+			case 1:
+			case 2:
+			case 3:
+			case 4:
+				return 2;
+			case 5:
+			case 6:
+				return 3;
+			case 7:
+			case 8:
+				return 4;
+			case 9:
+				return 5;
+			case 10:
+			case 11:
+			case 12:
+				return 6;
+			case 13:
+				return 7;
+			case 14:
+			case 15:
+				return 8;
+		}
+		return false;
+	}
+
+	/**
+	 * @param int $index
+	 *
+	 * @return string
+	 */
+	public static function channelArrangementLookup($index) {
+		static $lookup = array(
+			0  => 'A',
+			1  => 'A + B (dual mono)',
+			2  => 'L + R (stereo)',
+			3  => '(L+R) + (L-R) (sum-difference)',
+			4  => 'LT + RT (left and right total)',
+			5  => 'C + L + R',
+			6  => 'L + R + S',
+			7  => 'C + L + R + S',
+			8  => 'L + R + SL + SR',
+			9  => 'C + L + R + SL + SR',
+			10 => 'CL + CR + L + R + SL + SR',
+			11 => 'C + L + R+ LR + RR + OV',
+			12 => 'CF + CR + LF + RF + LR + RR',
+			13 => 'CL + C + CR + L + R + SL + SR',
+			14 => 'CL + CR + L + R + SL1 + SL2 + SR1 + SR2',
+			15 => 'CL + C+ CR + L + R + SL + S + SR',
+		);
+		return (isset($lookup[$index]) ? $lookup[$index] : 'user-defined');
+	}
+
+	/**
+	 * @param int $index
+	 * @param int $version
+	 *
+	 * @return int|false
+	 */
+	public static function dialogNormalization($index, $version) {
+		switch ($version) {
+			case 7:
+				return 0 - $index;
+			case 6:
+				return 0 - 16 - $index;
+		}
+		return false;
+	}
+
+}

Added: plog/branches/lifetype-1.2/class/gallery/getid3/module.audio.tak.php
===================================================================
--- plog/branches/lifetype-1.2/class/gallery/getid3/module.audio.tak.php	                        (rev 0)
+++ plog/branches/lifetype-1.2/class/gallery/getid3/module.audio.tak.php	2020-07-15 07:59:26 UTC (rev 7238)
@@ -0,0 +1,214 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org>               //
+//  available at http://getid3.sourceforge.net                 //
+//            or https://www.getid3.org                         //
+//          also https://github.com/JamesHeinrich/getID3       //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details                             //
+/////////////////////////////////////////////////////////////////
+//                                                             //
+// module.audio.tak.php                                        //
+// module for analyzing Tom's lossless Audio Kompressor        //
+// dependencies: NONE                                          //
+//                                                            ///
+/////////////////////////////////////////////////////////////////
+
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+	exit;
+}
+
+class getid3_tak extends getid3_handler
+{
+
+	public function Analyze() {
+		$info = &$this->getid3->info;
+
+		$info['fileformat']            = 'tak';
+		$info['audio']['dataformat']   = 'tak';
+		$info['audio']['bitrate_mode'] = 'vbr';
+		$info['audio']['lossless']     = true;
+
+		$info['tak_audio']['raw'] = array();
+		$thisfile_takaudio                = &$info['tak_audio'];
+		$thisfile_takaudio_raw            = &$thisfile_takaudio['raw'];
+
+		$this->fseek($info['avdataoffset']);
+		$TAKMetaData = $this->fread(4);
+
+		$thisfile_takaudio_raw['magic'] = $TAKMetaData;
+		$magic = 'tBaK';
+		if ($thisfile_takaudio_raw['magic'] != $magic) {
+			$this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($thisfile_takaudio_raw['magic']).'"');
+			unset($info['fileformat']);
+			return false;
+		}
+		$offset = 4; //skip magic
+		$this->fseek($offset);
+		$TAKMetaData = $this->fread(4); //read Metadata Block Header
+		$objtype = getid3_lib::BigEndian2Int(substr($TAKMetaData, 0, 1)); //Metadata Block Object Type
+		$objlength = getid3_lib::LittleEndian2Int(substr($TAKMetaData, 1, 3)); //Metadata Block Object Lenght excluding header
+		if ($objtype == 1) { //The First Metadata Block Object must be of Type 1 (STREAMINFO)
+			$offset += 4; //skip to Metadata Block contents
+			$this->fseek($offset);
+		        $TAKMetaData = $this->fread($objlength); // Get the raw Metadata Block Data
+			$thisfile_takaudio_raw['STREAMINFO'] = getid3_lib::LittleEndian2Bin(substr($TAKMetaData, 0, $objlength - 3));
+			$offset += $objlength; // Move to the next Metadata Block Object
+			$thisfile_takaudio['channels'] = getid3_lib::Bin2Dec(substr($thisfile_takaudio_raw['STREAMINFO'], 1, 4)) + 1;
+			$thisfile_takaudio['bits_per_sample'] = getid3_lib::Bin2Dec(substr($thisfile_takaudio_raw['STREAMINFO'], 5, 5)) + 8;
+			$thisfile_takaudio['sample_rate'] = getid3_lib::Bin2Dec(substr($thisfile_takaudio_raw['STREAMINFO'], 10, 18)) + 6000;
+			$thisfile_takaudio['samples'] = getid3_lib::Bin2Dec(substr($thisfile_takaudio_raw['STREAMINFO'], 31, 35));
+			$thisfile_takaudio['framesize'] = self::TAKFramesizeLookup(getid3_lib::Bin2Dec(substr($thisfile_takaudio_raw['STREAMINFO'], 66, 4)));
+			$thisfile_takaudio['codectype'] = self::TAKCodecTypeLookup(getid3_lib::Bin2Dec(substr($thisfile_takaudio_raw['STREAMINFO'], 74, 6)));
+		} else {
+			$this->error('Expecting Type 1 (STREAMINFO) Metadata Object header, but found Type "'.$objtype.'" Object instead');
+			unset($info['fileformat']);
+			return false;
+		}
+		$this->fseek($offset);
+		$TAKMetaData = $this->fread(4);
+		$objtype = getid3_lib::BigEndian2Int(substr($TAKMetaData, 0, 1));
+		$objlength = getid3_lib::LittleEndian2Int(substr($TAKMetaData, 1, 3));
+		while ($objtype != 0) {
+			switch ($objtype) {
+			case 4 :
+				// ENCODERINFO Metadata Block
+				$offset += 4;
+				$this->fseek($offset);
+		                $TAKMetaData = $this->fread($objlength);
+				$ver = getid3_lib::LittleEndian2Int(substr($TAKMetaData, 0, 3));
+				$major = ($ver & 0xff0000) >> 16;
+				$minor = ($ver & 0x00ff00) >> 8;
+				$revision= $ver & 0x0000ff;
+				$thisfile_takaudio['version'] = 'TAK V '.$major.'.'.$minor.'.'.$revision;
+				$thisfile_takaudio['profile'] = self::TAKProfileLookup(getid3_lib::BigEndian2Int(substr($TAKMetaData, 3, 1)));
+				$offset += $objlength;
+				break;
+			case 6 :
+				// MD5 Checksum Metadata Block
+				$offset += 4;
+				$this->fseek($offset);
+		                $TAKMetaData = $this->fread($objlength);
+				$thisfile_takaudio_raw['MD5Data'] = substr($TAKMetaData, 0, 16);
+				$offset += $objlength;
+				break;
+			case 7 :
+				// LASTFRAME Metadata Block
+				$offset += 4;
+				$this->fseek($offset);
+		                $TAKMetaData = $this->fread($objlength);
+				$thisfile_takaudio['lastframe_pos'] = getid3_lib::LittleEndian2Int(substr($TAKMetaData, 0, 5));
+				$thisfile_takaudio['last_frame_size'] = getid3_lib::LittleEndian2Int(substr($TAKMetaData, 5, 3));
+				$offset += $objlength;
+				break;
+			case 3 :
+				// ORIGINALFILEDATA Metadata Block
+				$offset += 4;
+				$this->fseek($offset);
+		                $TAKMetaData = $this->fread($objlength);
+				$headersize = getid3_lib::LittleEndian2Int(substr($TAKMetaData, 0, 3));
+				$footersize = getid3_lib::LittleEndian2Int(substr($TAKMetaData, 3, 3));
+				if ($headersize) $thisfile_takaudio_raw['header_data'] = substr($TAKMetaData, 6, $headersize);
+				if ($footersize) $thisfile_takaudio_raw['footer_data'] = substr($TAKMetaData, $headersize, $footersize);
+				$offset += $objlength;
+				break;
+			default :
+				// PADDING or SEEKTABLE Metadata Block. Just skip it
+				$offset += 4;
+				$this->fseek($offset);
+		                $TAKMetaData = $this->fread($objlength);
+				$offset += $objlength;
+				break;
+			}
+			$this->fseek($offset);
+			$TAKMetaData = $this->fread(4);
+			$objtype = getid3_lib::BigEndian2Int(substr($TAKMetaData, 0, 1));
+			$objlength = getid3_lib::LittleEndian2Int(substr($TAKMetaData, 1, 3));
+		}
+		// Finished all Metadata Blocks. So update $info['avdataoffset'] because next block is the first Audio data block
+		$info['avdataoffset'] = $offset;
+
+		$info['audio']['channels'] = $thisfile_takaudio['channels'];
+		if ($thisfile_takaudio['sample_rate'] == 0) {
+			$this->error('Corrupt TAK file: samplerate == zero');
+			return false;
+		}
+		$info['audio']['sample_rate'] = $thisfile_takaudio['sample_rate'];
+		$thisfile_takaudio['playtime'] = $thisfile_takaudio['samples'] / $thisfile_takaudio['sample_rate'];
+		if ($thisfile_takaudio['playtime'] == 0) {
+			$this->error('Corrupt TAK file: playtime == zero');
+			return false;
+		}
+		$info['playtime_seconds'] = $thisfile_takaudio['playtime'];
+		$thisfile_takaudio['compressed_size'] = $info['avdataend'] - $info['avdataoffset'];
+		$thisfile_takaudio['uncompressed_size'] = $thisfile_takaudio['samples'] * $thisfile_takaudio['channels'] * ($thisfile_takaudio['bits_per_sample'] / 8);
+		if ($thisfile_takaudio['uncompressed_size'] == 0) {
+			$this->error('Corrupt TAK file: uncompressed_size == zero');
+			return false;
+		}
+		$thisfile_takaudio['compression_ratio'] = $thisfile_takaudio['compressed_size'] / ($thisfile_takaudio['uncompressed_size'] + $offset);
+		$thisfile_takaudio['bitrate'] = (($thisfile_takaudio['samples'] * $thisfile_takaudio['channels'] * $thisfile_takaudio['bits_per_sample']) / $thisfile_takaudio['playtime']) * $thisfile_takaudio['compression_ratio'];
+		$info['audio']['bitrate'] = $thisfile_takaudio['bitrate'];
+
+		if (empty($thisfile_takaudio_raw['MD5Data'])) {
+			//$this->warning('MD5Data is not set');
+		} elseif ($thisfile_takaudio_raw['MD5Data'] === str_repeat("\x00", 16)) {
+			//$this->warning('MD5Data is null');
+		} else {
+			$info['md5_data_source'] = '';
+			$md5 = $thisfile_takaudio_raw['MD5Data'];
+			for ($i = 0; $i < strlen($md5); $i++) {
+				$info['md5_data_source'] .= str_pad(dechex(ord($md5[$i])), 2, '00', STR_PAD_LEFT);
+			}
+			if (!preg_match('/^[0-9a-f]{32}$/', $info['md5_data_source'])) {
+				unset($info['md5_data_source']);
+			}
+		}
+
+		foreach (array('bits_per_sample', 'version', 'profile') as $key) {
+			if (!empty($thisfile_takaudio[$key])) {
+				$info['audio'][$key] = $thisfile_takaudio[$key];
+			}
+		}
+
+		return true;
+	}
+
+	public function TAKFramesizeLookup($framesize) {
+		static $TAKFramesizeLookup = array(
+			0     => '94 ms',
+			1     => '125 ms',
+			2     => '188 ms',
+			3     => '250 ms',
+			4     => '4096 samples',
+			5     => '8192 samples',
+			6     => '16384 samples',
+			7     => '512 samples',
+			8     => '1024 samples',
+			9     => '2048 samples'
+		);
+		return (isset($TAKFramesizeLookup[$framesize]) ? $TAKFramesizeLookup[$framesize] : 'invalid');
+	}
+	public function TAKCodecTypeLookup($code) {
+		static $TAKCodecTypeLookup = array(
+			0     => 'Integer 24 bit (TAK 1.0)',
+			1     => 'Experimental!',
+			2     => 'Integer 24 bit (TAK 2.0)',
+			3     => 'LossyWav (TAK 2.1)',
+			4     => 'Integer 24 bit MC (TAK 2.2)'
+		);
+		return (isset($TAKCodecTypeLookup[$code]) ? $TAKCodecTypeLookup[$code] : 'invalid');
+	}
+	public function TAKProfileLookup($code) {
+		$out ='-p';
+		$evaluation = ($code & 0xf0) >> 4;
+		$compresion = $code & 0x0f;
+		static $TAKEvaluationLookup = array(
+			0     => '',
+			1     => 'e',
+			2     => 'm'
+		);
+		return (isset($TAKEvaluationLookup[$evaluation]) ? $out .= $compresion . $TAKEvaluationLookup[$evaluation] : 'invalid');
+	}
+
+}

Added: plog/branches/lifetype-1.2/class/gallery/getid3/module.graphic.efax.php
===================================================================
--- plog/branches/lifetype-1.2/class/gallery/getid3/module.graphic.efax.php	                        (rev 0)
+++ plog/branches/lifetype-1.2/class/gallery/getid3/module.graphic.efax.php	2020-07-15 07:59:26 UTC (rev 7238)
@@ -0,0 +1,54 @@
+<?php
+
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org>               //
+//  available at https://github.com/JamesHeinrich/getID3       //
+//            or https://www.getid3.org                        //
+//            or http://getid3.sourceforge.net                 //
+//  see readme.txt for more details                            //
+/////////////////////////////////////////////////////////////////
+//                                                             //
+// module.archive.efax.php                                     //
+// module for analyzing eFax files                             //
+// dependencies: NONE                                          //
+//                                                            ///
+/////////////////////////////////////////////////////////////////
+
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+	exit;
+}
+
+class getid3_efax extends getid3_handler
+{
+	/**
+	 * @return bool
+	 */
+	public function Analyze() {
+		$info = &$this->getid3->info;
+
+		$this->fseek($info['avdataoffset']);
+		$efaxheader = $this->fread(1024);
+
+		$info['efax']['header']['magic'] = substr($efaxheader, 0, 2);
+		if ($info['efax']['header']['magic'] != "\xDC\xFE") {
+			$this->error('Invalid eFax byte order identifier (expecting DC FE, found '.getid3_lib::PrintHexBytes($info['efax']['header']['magic']).') at offset '.$info['avdataoffset']);
+			return false;
+		}
+		$info['fileformat'] = 'efax';
+
+		$info['efax']['header']['filesize'] = getid3_lib::LittleEndian2Int(substr($efaxheader, 2, 4));
+		if ($info['efax']['header']['filesize'] != $info['filesize']) {
+			$this->error('Probable '.(($info['efax']['header']['filesize'] > $info['filesize']) ? 'truncated' : 'corrupt').' file, expecting '.$info['efax']['header']['filesize'].' bytes, found '.$info['filesize'].' bytes');
+		}
+		$info['efax']['header']['software1'] =                        rtrim(substr($efaxheader,  26, 32), "\x00");
+		$info['efax']['header']['software2'] =                        rtrim(substr($efaxheader,  58, 32), "\x00");
+		$info['efax']['header']['software3'] =                        rtrim(substr($efaxheader,  90, 32), "\x00");
+
+		$info['efax']['header']['pages']      = getid3_lib::LittleEndian2Int(substr($efaxheader, 198, 2));
+		$info['efax']['header']['data_bytes'] = getid3_lib::LittleEndian2Int(substr($efaxheader, 202, 4));
+
+		$this->error('eFax parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
+		return false;
+	}
+
+}

Added: plog/branches/lifetype-1.2/class/gallery/getid3/module.misc.cue.php
===================================================================
--- plog/branches/lifetype-1.2/class/gallery/getid3/module.misc.cue.php	                        (rev 0)
+++ plog/branches/lifetype-1.2/class/gallery/getid3/module.misc.cue.php	2020-07-15 07:59:26 UTC (rev 7238)
@@ -0,0 +1,332 @@
+<?php
+
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org>               //
+//  available at https://github.com/JamesHeinrich/getID3       //
+//            or https://www.getid3.org                        //
+//            or http://getid3.sourceforge.net                 //
+//  see readme.txt for more details                            //
+/////////////////////////////////////////////////////////////////
+//                                                             //
+// module.misc.cue.php                                         //
+// module for analyzing CUEsheet files                         //
+// dependencies: NONE                                          //
+//                                                             //
+/////////////////////////////////////////////////////////////////
+//                                                             //
+// Module originally written [2009-Mar-25] by                  //
+//      Nigel Barnes <ngbarnesØhotmail*com>                    //
+// Minor reformatting and similar small changes to integrate   //
+//   into getID3 by James Heinrich <info at getid3.org>           //
+//                                                            ///
+/////////////////////////////////////////////////////////////////
+
+/*
+ * CueSheet parser by Nigel Barnes.
+ *
+ * This is a PHP conversion of CueSharp 0.5 by Wyatt O'Day (wyday.com/cuesharp)
+ */
+
+/**
+ * A CueSheet class used to open and parse cuesheets.
+ *
+ */
+
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+	exit;
+}
+
+class getid3_cue extends getid3_handler
+{
+	public $cuesheet = array();
+
+	/**
+	 * @return bool
+	 */
+	public function Analyze() {
+		$info = &$this->getid3->info;
+
+		$info['fileformat'] = 'cue';
+		$this->readCueSheetFilename($info['filenamepath']);
+		$info['cue'] = $this->cuesheet;
+		return true;
+	}
+
+	/**
+	 * @param string $filename
+	 *
+	 * @return array
+	 */
+	public function readCueSheetFilename($filename)
+	{
+		$filedata = file_get_contents($filename);
+		return $this->readCueSheet($filedata);
+	}
+
+	/**
+	 * Parses a cue sheet file.
+	 *
+	 * @param string $filedata
+	 *
+	 * @return array
+	 */
+	public function readCueSheet(&$filedata)
+	{
+		$cue_lines = array();
+		foreach (explode("\n", str_replace("\r", null, $filedata)) as $line)
+		{
+			if ( (strlen($line) > 0) && ($line[0] != '#'))
+			{
+				$cue_lines[] = trim($line);
+			}
+		}
+		$this->parseCueSheet($cue_lines);
+
+		return $this->cuesheet;
+	}
+
+	/**
+	 * Parses the cue sheet array.
+	 *
+	 * @param array $file - The cuesheet as an array of each line.
+	 */
+	public function parseCueSheet($file)
+	{
+		//-1 means still global, all others are track specific
+		$track_on = -1;
+
+		for ($i=0; $i < count($file); $i++)
+		{
+			list($key) = explode(' ', strtolower($file[$i]), 2);
+			switch ($key)
+			{
+				case 'catalog':
+				case 'cdtextfile':
+				case 'isrc':
+				case 'performer':
+				case 'songwriter':
+				case 'title':
+					$this->parseString($file[$i], $track_on);
+					break;
+				case 'file':
+					$currentFile = $this->parseFile($file[$i]);
+					break;
+				case 'flags':
+					$this->parseFlags($file[$i], $track_on);
+					break;
+				case 'index':
+				case 'postgap':
+				case 'pregap':
+					$this->parseIndex($file[$i], $track_on);
+					break;
+				case 'rem':
+					$this->parseComment($file[$i], $track_on);
+					break;
+				case 'track':
+					$track_on++;
+					$this->parseTrack($file[$i], $track_on);
+					if (isset($currentFile)) // if there's a file
+					{
+						$this->cuesheet['tracks'][$track_on]['datafile'] = $currentFile;
+					}
+					break;
+				default:
+					//save discarded junk and place string[] with track it was found in
+					$this->parseGarbage($file[$i], $track_on);
+					break;
+			}
+		}
+	}
+
+	/**
+	 * Parses the REM command.
+	 *
+	 * @param string  $line - The line in the cue file that contains the TRACK command.
+	 * @param integer $track_on - The track currently processing.
+	 */
+	public function parseComment($line, $track_on)
+	{
+		$explodedline = explode(' ', $line, 3);
+		$comment_REM  = (isset($explodedline[0]) ? $explodedline[0] : '');
+		$comment_type = (isset($explodedline[1]) ? $explodedline[1] : '');
+		$comment_data = (isset($explodedline[2]) ? $explodedline[2] : '');
+		if (($comment_REM == 'REM') && $comment_type) {
+			$comment_type  = strtolower($comment_type);
+			$commment_data = trim($comment_data, ' "');
+			if ($track_on != -1) {
+				$this->cuesheet['tracks'][$track_on]['comments'][$comment_type][] = $comment_data;
+			} else {
+				$this->cuesheet['comments'][$comment_type][] = $comment_data;
+			}
+		}
+	}
+
+	/**
+	 * Parses the FILE command.
+	 *
+	 * @param string $line - The line in the cue file that contains the FILE command.
+	 *
+	 * @return array - Array of FILENAME and TYPE of file..
+	 */
+	public function parseFile($line)
+	{
+		$line =            substr($line, strpos($line, ' ') + 1);
+		$type = strtolower(substr($line, strrpos($line, ' ')));
+
+		//remove type
+		$line = substr($line, 0, strrpos($line, ' ') - 1);
+
+		//if quotes around it, remove them.
+		$line = trim($line, '"');
+
+		return array('filename'=>$line, 'type'=>$type);
+	}
+
+	/**
+	 * Parses the FLAG command.
+	 *
+	 * @param string  $line - The line in the cue file that contains the TRACK command.
+	 * @param integer $track_on - The track currently processing.
+	 */
+	public function parseFlags($line, $track_on)
+	{
+		if ($track_on != -1)
+		{
+			foreach (explode(' ', strtolower($line)) as $type)
+			{
+				switch ($type)
+				{
+					case 'flags':
+						// first entry in this line
+						$this->cuesheet['tracks'][$track_on]['flags'] = array(
+							'4ch'  => false,
+							'data' => false,
+							'dcp'  => false,
+							'pre'  => false,
+							'scms' => false,
+						);
+						break;
+					case 'data':
+					case 'dcp':
+					case '4ch':
+					case 'pre':
+					case 'scms':
+						$this->cuesheet['tracks'][$track_on]['flags'][$type] = true;
+						break;
+					default:
+						break;
+				}
+			}
+		}
+	}
+
+	/**
+	 * Collect any unidentified data.
+	 *
+	 * @param string  $line - The line in the cue file that contains the TRACK command.
+	 * @param integer $track_on - The track currently processing.
+	 */
+	public function parseGarbage($line, $track_on)
+	{
+		if ( strlen($line) > 0 )
+		{
+			if ($track_on == -1)
+			{
+				$this->cuesheet['garbage'][] = $line;
+			}
+			else
+			{
+				$this->cuesheet['tracks'][$track_on]['garbage'][] = $line;
+			}
+		}
+	}
+
+	/**
+	 * Parses the INDEX command of a TRACK.
+	 *
+	 * @param string  $line - The line in the cue file that contains the TRACK command.
+	 * @param integer $track_on - The track currently processing.
+	 */
+	public function parseIndex($line, $track_on)
+	{
+		$type = strtolower(substr($line, 0, strpos($line, ' ')));
+		$line =            substr($line, strpos($line, ' ') + 1);
+		$number = 0;
+
+		if ($type == 'index')
+		{
+			//read the index number
+			$number = intval(substr($line, 0, strpos($line, ' ')));
+			$line   =        substr($line, strpos($line, ' ') + 1);
+		}
+
+		//extract the minutes, seconds, and frames
+		$explodedline = explode(':', $line);
+		$minutes = (isset($explodedline[0]) ? $explodedline[0] : '');
+		$seconds = (isset($explodedline[1]) ? $explodedline[1] : '');
+		$frames  = (isset($explodedline[2]) ? $explodedline[2] : '');
+
+		switch ($type) {
+			case 'index':
+				$this->cuesheet['tracks'][$track_on][$type][$number] = array('minutes'=>intval($minutes), 'seconds'=>intval($seconds), 'frames'=>intval($frames));
+				break;
+			case 'pregap':
+			case 'postgap':
+				$this->cuesheet['tracks'][$track_on][$type]          = array('minutes'=>intval($minutes), 'seconds'=>intval($seconds), 'frames'=>intval($frames));
+				break;
+		}
+	}
+
+	/**
+	 * @param string $line
+	 * @param int    $track_on
+	 */
+	public function parseString($line, $track_on)
+	{
+		$category = strtolower(substr($line, 0, strpos($line, ' ')));
+		$line     =            substr($line, strpos($line, ' ') + 1);
+
+		//get rid of the quotes
+		$line = trim($line, '"');
+
+		switch ($category)
+		{
+			case 'catalog':
+			case 'cdtextfile':
+			case 'isrc':
+			case 'performer':
+			case 'songwriter':
+			case 'title':
+				if ($track_on == -1)
+				{
+					$this->cuesheet[$category] = $line;
+				}
+				else
+				{
+					$this->cuesheet['tracks'][$track_on][$category] = $line;
+				}
+				break;
+			default:
+				break;
+		}
+	}
+
+	/**
+	 * Parses the TRACK command.
+	 *
+	 * @param string  $line - The line in the cue file that contains the TRACK command.
+	 * @param integer $track_on - The track currently processing.
+	 */
+	public function parseTrack($line, $track_on)
+	{
+		$line = substr($line, strpos($line, ' ') + 1);
+		$track = ltrim(substr($line, 0, strpos($line, ' ')), '0');
+
+		//find the data type.
+		$datatype = strtolower(substr($line, strpos($line, ' ') + 1));
+
+		$this->cuesheet['tracks'][$track_on] = array('track_number'=>$track, 'datatype'=>$datatype);
+	}
+
+}
+

Added: plog/branches/lifetype-1.2/class/gallery/getid3/module.misc.msoffice.php
===================================================================
--- plog/branches/lifetype-1.2/class/gallery/getid3/module.misc.msoffice.php	                        (rev 0)
+++ plog/branches/lifetype-1.2/class/gallery/getid3/module.misc.msoffice.php	2020-07-15 07:59:26 UTC (rev 7238)
@@ -0,0 +1,43 @@
+<?php
+
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org>               //
+//  available at https://github.com/JamesHeinrich/getID3       //
+//            or https://www.getid3.org                        //
+//            or http://getid3.sourceforge.net                 //
+//  see readme.txt for more details                            //
+/////////////////////////////////////////////////////////////////
+//                                                             //
+// module.misc.msoffice.php                                    //
+// module for analyzing MS Office (.doc, .xls, etc) files      //
+// dependencies: NONE                                          //
+//                                                            ///
+/////////////////////////////////////////////////////////////////
+
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+	exit;
+}
+
+class getid3_msoffice extends getid3_handler
+{
+	/**
+	 * @return bool
+	 */
+	public function Analyze() {
+		$info = &$this->getid3->info;
+
+		$this->fseek($info['avdataoffset']);
+		$DOCFILEheader = $this->fread(8);
+		$magic = "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1";
+		if (substr($DOCFILEheader, 0, 8) != $magic) {
+			$this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at '.$info['avdataoffset'].', found '.getid3_lib::PrintHexBytes(substr($DOCFILEheader, 0, 8)).' instead.');
+			return false;
+		}
+		$info['fileformat'] = 'msoffice';
+
+		$this->error('MS Office (.doc, .xls, etc) parsing not enabled in this version of getID3() ['.$this->getid3->version().']');
+		return false;
+
+	}
+
+}

Added: plog/branches/lifetype-1.2/class/gallery/getid3/module.misc.par2.php
===================================================================
--- plog/branches/lifetype-1.2/class/gallery/getid3/module.misc.par2.php	                        (rev 0)
+++ plog/branches/lifetype-1.2/class/gallery/getid3/module.misc.par2.php	2020-07-15 07:59:26 UTC (rev 7238)
@@ -0,0 +1,36 @@
+<?php
+
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org>               //
+//  available at https://github.com/JamesHeinrich/getID3       //
+//            or https://www.getid3.org                        //
+//            or http://getid3.sourceforge.net                 //
+//  see readme.txt for more details                            //
+/////////////////////////////////////////////////////////////////
+//                                                             //
+// module.misc.par2.php                                        //
+// module for analyzing PAR2 files                             //
+// dependencies: NONE                                          //
+//                                                            ///
+/////////////////////////////////////////////////////////////////
+
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+	exit;
+}
+
+class getid3_par2 extends getid3_handler
+{
+	/**
+	 * @return bool
+	 */
+	public function Analyze() {
+		$info = &$this->getid3->info;
+
+		$info['fileformat'] = 'par2';
+
+		$this->error('PAR2 parsing not enabled in this version of getID3()');
+		return false;
+
+	}
+
+}

Added: plog/branches/lifetype-1.2/class/gallery/getid3/module.misc.pdf.php
===================================================================
--- plog/branches/lifetype-1.2/class/gallery/getid3/module.misc.pdf.php	                        (rev 0)
+++ plog/branches/lifetype-1.2/class/gallery/getid3/module.misc.pdf.php	2020-07-15 07:59:26 UTC (rev 7238)
@@ -0,0 +1,148 @@
+<?php
+
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org>               //
+//  available at https://github.com/JamesHeinrich/getID3       //
+//            or https://www.getid3.org                        //
+//            or http://getid3.sourceforge.net                 //
+//  see readme.txt for more details                            //
+/////////////////////////////////////////////////////////////////
+//                                                             //
+// module.misc.pdf.php                                         //
+// module for analyzing PDF files                              //
+// dependencies: NONE                                          //
+//                                                            ///
+/////////////////////////////////////////////////////////////////
+
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+	exit;
+}
+
+class getid3_pdf extends getid3_handler
+{
+	public $returnXREF = false; // return full details of PDF Cross-Reference Table (XREF)
+
+	/**
+	 * @return bool
+	 */
+	public function Analyze() {
+		$info = &$this->getid3->info;
+
+		$this->fseek(0);
+		if (preg_match('#^%PDF-([0-9\\.]+)$#', rtrim($this->fgets()), $matches)) {
+			$info['pdf']['header']['version'] = floatval($matches[1]);
+			$info['fileformat'] = 'pdf';
+
+			// the PDF Cross-Reference Table (XREF) is located near the end of the file
+			// the starting offset is specified in the penultimate section, on the two lines just before "%%EOF"
+			// the first line is "startxref", the second line is the byte offset of the XREF.
+			// We know the length of "%%EOF" and "startxref", but the offset could be 2-10 bytes,
+			// and we're not sure if the line ends are one or two bytes, so we might find "startxref" as little as 18(?) bytes
+			// from EOF, but it could 30 bytes, so we start 40 bytes back just to be safe and do a search for the data we want.
+			$this->fseek(-40, SEEK_END);
+			if (preg_match('#[\r\n]startxref[ \r\n]+([0-9]+)[ \r\n]+#', $this->fread(40), $matches)) {
+				$info['pdf']['trailer']['startxref'] = intval($matches[1]);
+				$this->parseXREF($info['pdf']['trailer']['startxref']);
+				if (!empty($info['pdf']['xref']['offset'])) {
+					while (!$this->feof() && (max(array_keys($info['pdf']['xref']['offset'])) > $info['pdf']['xref']['count'])) {
+						// suspect that there may be another XREF entry somewhere in the file, brute-force scan for it
+						/*
+						// starting at last known entry of main XREF table
+						$this->fseek(max($info['pdf']['xref']['offset']));
+						*/
+						// starting at the beginning of the file
+						$this->fseek(0);
+						while (!$this->feof()) {
+							$XREFoffset = $this->ftell();
+							if (rtrim($this->fgets()) == 'xref') {
+								if (empty($info['pdf']['xref']['xref_offsets']) || !in_array($XREFoffset, $info['pdf']['xref']['xref_offsets'])) {
+									$this->parseXREF($XREFoffset);
+									break;
+								}
+							}
+						}
+					}
+					foreach ($info['pdf']['xref']['offset'] as $objectNumber => $offset) {
+						if ($info['pdf']['xref']['entry'][$objectNumber] == 'f') {
+							// "free" object means "deleted", ignore
+							continue;
+						}
+						$this->fseek($offset);
+						$line = rtrim($this->fgets());
+						if (preg_match('#^'.$objectNumber.' ([0-9]+) obj#', $line, $matches)) {
+							if (strlen($line) > strlen($matches[0])) {
+								// object header line not actually on its own line, rewind file pointer to start reading data
+								$this->fseek($offset + strlen($matches[0]));
+							}
+							$objectData  = '';
+							while (true) {
+								$line = $this->fgets();
+								if (rtrim($line) == 'endobj') {
+									break;
+								}
+								$objectData .= $line;
+							}
+							if (preg_match('#^<<[\r\n\s]*(/Type|/Pages|/Parent [0-9]+ [0-9]+ [A-Z]|/Count [0-9]+|/Kids *\\[[0-9A-Z ]+\\]|[\r\n\s])+[\r\n\s]*>>#', $objectData, $matches)) {
+								if (preg_match('#/Count ([0-9]+)#', $objectData, $matches)) {
+									$info['pdf']['pages'] = (int) $matches[1];
+									break; // for now this is the only data we're looking for in the PDF not need to loop through every object in the file (and a large PDF may contain MANY objects). And it MAY be possible that there are other objects elsewhere in the file that define additional (or removed?) pages
+								}
+							}
+						} else {
+							$this->error('Unexpected structure "'.$line.'" at offset '.$offset);
+							break;
+						}
+					}
+					if (!$this->returnXREF) {
+						unset($info['pdf']['xref']['offset'], $info['pdf']['xref']['generation'], $info['pdf']['xref']['entry']);
+					}
+
+				} else {
+					$this->error('Did not find "xref" at offset '.$info['pdf']['trailer']['startxref']);
+				}
+			} else {
+				$this->error('Did not find "startxref" in the last 40 bytes of the PDF');
+			}
+
+			$this->warning('PDF parsing incomplete in this version of getID3() ['.$this->getid3->version().']');
+			return true;
+		}
+		$this->error('Did not find "%PDF" at the beginning of the PDF');
+		return false;
+
+	}
+
+	/**
+	 * @return bool
+	 */
+	private function parseXREF($XREFoffset) {
+		$info = &$this->getid3->info;
+
+		$this->fseek($XREFoffset);
+		if (rtrim($this->fgets()) == 'xref') {
+
+			$info['pdf']['xref']['xref_offsets'][$XREFoffset] = $XREFoffset;
+			list($firstObjectNumber, $XREFcount) = explode(' ', rtrim($this->fgets()));
+			$firstObjectNumber = (int) $firstObjectNumber;
+			$XREFcount = (int) $XREFcount;
+			$info['pdf']['xref']['count'] = $XREFcount + (!empty($info['pdf']['xref']['count']) ? $info['pdf']['xref']['count'] : 0);
+			for ($i = 0; $i < $XREFcount; $i++) {
+				$line = rtrim($this->fgets());
+				if (preg_match('#^([0-9]+) ([0-9]+) ([nf])$#', $line, $matches)) {
+					$info['pdf']['xref']['offset'][($firstObjectNumber + $i)]     = (int) $matches[1];
+					$info['pdf']['xref']['generation'][($firstObjectNumber + $i)] = (int) $matches[2];
+					$info['pdf']['xref']['entry'][($firstObjectNumber + $i)]      =       $matches[3];
+				} else {
+					$this->error('failed to parse XREF entry #'.$i.' in XREF table at offset '.$XREFoffset);
+					return false;
+				}
+			}
+			sort($info['pdf']['xref']['xref_offsets']);
+			return true;
+
+		}
+		$this->warning('failed to find expected XREF structure at offset '.$XREFoffset);
+		return false;
+	}
+
+}

Added: plog/branches/lifetype-1.2/class/gallery/getid3/module.tag.xmp.php
===================================================================
--- plog/branches/lifetype-1.2/class/gallery/getid3/module.tag.xmp.php	                        (rev 0)
+++ plog/branches/lifetype-1.2/class/gallery/getid3/module.tag.xmp.php	2020-07-15 07:59:26 UTC (rev 7238)
@@ -0,0 +1,774 @@
+<?php
+
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info at getid3.org>               //
+//  available at https://github.com/JamesHeinrich/getID3       //
+//            or https://www.getid3.org                        //
+//            or http://getid3.sourceforge.net                 //
+//  see readme.txt for more details                            //
+/////////////////////////////////////////////////////////////////
+//                                                             //
+// module.tag.xmp.php                                          //
+// module for analyzing XMP metadata (e.g. in JPEG files)      //
+// dependencies: NONE                                          //
+//                                                             //
+/////////////////////////////////////////////////////////////////
+//                                                             //
+// Module originally written [2009-Mar-26] by                  //
+//      Nigel Barnes <ngbarnesØhotmail*com>                    //
+// Bundled into getID3 with permission                         //
+//   called by getID3 in module.graphic.jpg.php                //
+//                                                            ///
+/////////////////////////////////////////////////////////////////
+
+/**************************************************************************************************
+ * SWISScenter Source                                                              Nigel Barnes
+ *
+ * 	Provides functions for reading information from the 'APP1' Extensible Metadata
+ *	Platform (XMP) segment of JPEG format files.
+ *	This XMP segment is XML based and contains the Resource Description Framework (RDF)
+ *	data, which itself can contain the Dublin Core Metadata Initiative (DCMI) information.
+ *
+ * 	This code uses segments from the JPEG Metadata Toolkit project by Evan Hunter.
+ *************************************************************************************************/
+class Image_XMP
+{
+	/**
+	* @var string
+	* The name of the image file that contains the XMP fields to extract and modify.
+	* @see Image_XMP()
+	*/
+	public $_sFilename = null;
+
+	/**
+	* @var array
+	* The XMP fields that were extracted from the image or updated by this class.
+	* @see getAllTags()
+	*/
+	public $_aXMP = array();
+
+	/**
+	* @var boolean
+	* True if an APP1 segment was found to contain XMP metadata.
+	* @see isValid()
+	*/
+	public $_bXMPParse = false;
+
+	/**
+	* Returns the status of XMP parsing during instantiation
+	*
+	* You'll normally want to call this method before trying to get XMP fields.
+	*
+	* @return boolean
+	* Returns true if an APP1 segment was found to contain XMP metadata.
+	*/
+	public function isValid()
+	{
+		return $this->_bXMPParse;
+	}
+
+	/**
+	* Get a copy of all XMP tags extracted from the image
+	*
+	* @return array - An array of XMP fields as it extracted by the XMPparse() function
+	*/
+	public function getAllTags()
+	{
+		return $this->_aXMP;
+	}
+
+	/**
+	* Reads all the JPEG header segments from an JPEG image file into an array
+	*
+	* @param string $filename - the filename of the JPEG file to read
+	* @return array|boolean  $headerdata - Array of JPEG header segments,
+	*                        FALSE - if headers could not be read
+	*/
+	public function _get_jpeg_header_data($filename)
+	{
+		// prevent refresh from aborting file operations and hosing file
+		ignore_user_abort(true);
+
+		// Attempt to open the jpeg file - the at symbol supresses the error message about
+		// not being able to open files. The file_exists would have been used, but it
+		// does not work with files fetched over http or ftp.
+		if (is_readable($filename) && is_file($filename) && ($filehnd = fopen($filename, 'rb'))) {
+			// great
+		} else {
+			return false;
+		}
+
+		// Read the first two characters
+		$data = fread($filehnd, 2);
+
+		// Check that the first two characters are 0xFF 0xD8  (SOI - Start of image)
+		if ($data != "\xFF\xD8")
+		{
+			// No SOI (FF D8) at start of file - This probably isn't a JPEG file - close file and return;
+			echo '<p>This probably is not a JPEG file</p>'."\n";
+			fclose($filehnd);
+			return false;
+		}
+
+		// Read the third character
+		$data = fread($filehnd, 2);
+
+		// Check that the third character is 0xFF (Start of first segment header)
+		if ($data[0] != "\xFF")
+		{
+			// NO FF found - close file and return - JPEG is probably corrupted
+			fclose($filehnd);
+			return false;
+		}
+
+		// Flag that we havent yet hit the compressed image data
+		$hit_compressed_image_data = false;
+
+		$headerdata = array();
+		// Cycle through the file until, one of: 1) an EOI (End of image) marker is hit,
+		//                                       2) we have hit the compressed image data (no more headers are allowed after data)
+		//                                       3) or end of file is hit
+
+		while (($data[1] != "\xD9") && (!$hit_compressed_image_data) && (!feof($filehnd)))
+		{
+			// Found a segment to look at.
+			// Check that the segment marker is not a Restart marker - restart markers don't have size or data after them
+			if ((ord($data[1]) < 0xD0) || (ord($data[1]) > 0xD7))
+			{
+				// Segment isn't a Restart marker
+				// Read the next two bytes (size)
+				$sizestr = fread($filehnd, 2);
+
+				// convert the size bytes to an integer
+				$decodedsize = unpack('nsize', $sizestr);
+
+				// Save the start position of the data
+				$segdatastart = ftell($filehnd);
+
+				// Read the segment data with length indicated by the previously read size
+				$segdata = fread($filehnd, $decodedsize['size'] - 2);
+
+				// Store the segment information in the output array
+				$headerdata[] = array(
+					'SegType'      => ord($data[1]),
+					'SegName'      => $GLOBALS['JPEG_Segment_Names'][ord($data[1])],
+					'SegDataStart' => $segdatastart,
+					'SegData'      => $segdata,
+				);
+			}
+
+			// If this is a SOS (Start Of Scan) segment, then there is no more header data - the compressed image data follows
+			if ($data[1] == "\xDA")
+			{
+				// Flag that we have hit the compressed image data - exit loop as no more headers available.
+				$hit_compressed_image_data = true;
+			}
+			else
+			{
+				// Not an SOS - Read the next two bytes - should be the segment marker for the next segment
+				$data = fread($filehnd, 2);
+
+				// Check that the first byte of the two is 0xFF as it should be for a marker
+				if ($data[0] != "\xFF")
+				{
+					// NO FF found - close file and return - JPEG is probably corrupted
+					fclose($filehnd);
+					return false;
+				}
+			}
+		}
+
+		// Close File
+		fclose($filehnd);
+		// Alow the user to abort from now on
+		ignore_user_abort(false);
+
+		// Return the header data retrieved
+		return $headerdata;
+	}
+
+
+	/**
+	* Retrieves XMP information from an APP1 JPEG segment and returns the raw XML text as a string.
+	*
+	* @param string $filename - the filename of the JPEG file to read
+	* @return string|boolean $xmp_data - the string of raw XML text,
+	*                        FALSE - if an APP 1 XMP segment could not be found, or if an error occured
+	*/
+	public function _get_XMP_text($filename)
+	{
+		//Get JPEG header data
+		$jpeg_header_data = $this->_get_jpeg_header_data($filename);
+
+		//Cycle through the header segments
+		for ($i = 0; $i < count($jpeg_header_data); $i++)
+		{
+			// If we find an APP1 header,
+			if (strcmp($jpeg_header_data[$i]['SegName'], 'APP1') == 0)
+			{
+				// And if it has the Adobe XMP/RDF label (http://ns.adobe.com/xap/1.0/\x00) ,
+				if (strncmp($jpeg_header_data[$i]['SegData'], 'http://ns.adobe.com/xap/1.0/'."\x00", 29) == 0)
+				{
+					// Found a XMP/RDF block
+					// Return the XMP text
+					$xmp_data = substr($jpeg_header_data[$i]['SegData'], 29);
+
+					return trim($xmp_data); // trim() should not be neccesary, but some files found in the wild with null-terminated block (known samples from Apple Aperture) causes problems elsewhere (see https://www.getid3.org/phpBB3/viewtopic.php?f=4&t=1153)
+				}
+			}
+		}
+		return false;
+	}
+
+	/**
+	* Parses a string containing XMP data (XML), and returns an array
+	* which contains all the XMP (XML) information.
+	*
+	* @param string $xmltext - a string containing the XMP data (XML) to be parsed
+	* @return array|boolean $xmp_array - an array containing all xmp details retrieved,
+	*                       FALSE - couldn't parse the XMP data.
+	*/
+	public function read_XMP_array_from_text($xmltext)
+	{
+		// Check if there actually is any text to parse
+		if (trim($xmltext) == '')
+		{
+			return false;
+		}
+
+		// Create an instance of a xml parser to parse the XML text
+		$xml_parser = xml_parser_create('UTF-8');
+
+		// Change: Fixed problem that caused the whitespace (especially newlines) to be destroyed when converting xml text to an xml array, as of revision 1.10
+
+		// We would like to remove unneccessary white space, but this will also
+		// remove things like newlines (&#xA;) in the XML values, so white space
+		// will have to be removed later
+		if (xml_parser_set_option($xml_parser, XML_OPTION_SKIP_WHITE, 0) == false)
+		{
+			// Error setting case folding - destroy the parser and return
+			xml_parser_free($xml_parser);
+			return false;
+		}
+
+		// to use XML code correctly we have to turn case folding
+		// (uppercasing) off. XML is case sensitive and upper
+		// casing is in reality XML standards violation
+		if (xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, 0) == false)
+		{
+			// Error setting case folding - destroy the parser and return
+			xml_parser_free($xml_parser);
+			return false;
+		}
+
+		// Parse the XML text into a array structure
+		if (xml_parse_into_struct($xml_parser, $xmltext, $values, $tags) == 0)
+		{
+			// Error Parsing XML - destroy the parser and return
+			xml_parser_free($xml_parser);
+			return false;
+		}
+
+		// Destroy the xml parser
+		xml_parser_free($xml_parser);
+
+		// Clear the output array
+		$xmp_array = array();
+
+		// The XMP data has now been parsed into an array ...
+
+		// Cycle through each of the array elements
+		$current_property = ''; // current property being processed
+		$container_index = -1; // -1 = no container open, otherwise index of container content
+		foreach ($values as $xml_elem)
+		{
+			// Syntax and Class names
+			switch ($xml_elem['tag'])
+			{
+				case 'x:xmpmeta':
+					// only defined attribute is x:xmptk written by Adobe XMP Toolkit; value is the version of the toolkit
+					break;
+
+				case 'rdf:RDF':
+					// required element immediately within x:xmpmeta; no data here
+					break;
+
+				case 'rdf:Description':
+					switch ($xml_elem['type'])
+					{
+						case 'open':
+						case 'complete':
+							if (array_key_exists('attributes', $xml_elem))
+							{
+								// rdf:Description may contain wanted attributes
+								foreach (array_keys($xml_elem['attributes']) as $key)
+								{
+									// Check whether we want this details from this attribute
+//									if (in_array($key, $GLOBALS['XMP_tag_captions']))
+//									if (true)
+//									{
+										// Attribute wanted
+										$xmp_array[$key] = $xml_elem['attributes'][$key];
+//									}
+								}
+							}
+							break;
+						case 'cdata':
+						case 'close':
+							break;
+					}
+					break;
+
+				case 'rdf:ID':
+				case 'rdf:nodeID':
+					// Attributes are ignored
+					break;
+
+				case 'rdf:li':
+					// Property member
+					if ($xml_elem['type'] == 'complete')
+					{
+						if (array_key_exists('attributes', $xml_elem))
+						{
+							// If Lang Alt (language alternatives) then ensure we take the default language
+							if (isset($xml_elem['attributes']['xml:lang']) && ($xml_elem['attributes']['xml:lang'] != 'x-default'))
+							{
+								break;
+							}
+						}
+						if ($current_property != '')
+						{
+							$xmp_array[$current_property][$container_index] = (isset($xml_elem['value']) ? $xml_elem['value'] : '');
+							$container_index += 1;
+						}
+					//else unidentified attribute!!
+					}
+					break;
+
+				case 'rdf:Seq':
+				case 'rdf:Bag':
+				case 'rdf:Alt':
+					// Container found
+					switch ($xml_elem['type'])
+					{
+						case 'open':
+ 							$container_index = 0;
+ 							break;
+						case 'close':
+							$container_index = -1;
+							break;
+						case 'cdata':
+							break;
+					}
+					break;
+
+				default:
+					// Check whether we want the details from this attribute
+//					if (in_array($xml_elem['tag'], $GLOBALS['XMP_tag_captions']))
+//					if (true)
+//					{
+						switch ($xml_elem['type'])
+						{
+							case 'open':
+								// open current element
+								$current_property = $xml_elem['tag'];
+								break;
+
+							case 'close':
+								// close current element
+								$current_property = '';
+								break;
+
+							case 'complete':
+								// store attribute value
+								$xmp_array[$xml_elem['tag']] = (isset($xml_elem['attributes']) ? $xml_elem['attributes'] : (isset($xml_elem['value']) ? $xml_elem['value'] : ''));
+								break;
+
+							case 'cdata':
+								// ignore
+								break;
+						}
+//					}
+					break;
+			}
+
+		}
+		return $xmp_array;
+	}
+
+
+	/**
+	* Constructor
+	*
+	* @param string $sFilename - Name of the image file to access and extract XMP information from.
+	*/
+	public function __construct($sFilename)
+	{
+		$this->_sFilename = $sFilename;
+
+		if (is_file($this->_sFilename))
+		{
+			// Get XMP data
+			$xmp_data = $this->_get_XMP_text($sFilename);
+			if ($xmp_data)
+			{
+				$aXMP = $this->read_XMP_array_from_text($xmp_data);
+				if ($aXMP !== false) {
+					$this->_aXMP = (array) $aXMP;
+					$this->_bXMPParse = true;
+				}
+			}
+		}
+	}
+
+}
+
+/**
+* Global Variable: XMP_tag_captions
+*
+* The Property names of all known XMP fields.
+* Note: this is a full list with unrequired properties commented out.
+*/
+/*
+$GLOBALS['XMP_tag_captions'] = array(
+// IPTC Core
+	'Iptc4xmpCore:CiAdrCity',
+	'Iptc4xmpCore:CiAdrCtry',
+	'Iptc4xmpCore:CiAdrExtadr',
+	'Iptc4xmpCore:CiAdrPcode',
+	'Iptc4xmpCore:CiAdrRegion',
+	'Iptc4xmpCore:CiEmailWork',
+	'Iptc4xmpCore:CiTelWork',
+	'Iptc4xmpCore:CiUrlWork',
+	'Iptc4xmpCore:CountryCode',
+	'Iptc4xmpCore:CreatorContactInfo',
+	'Iptc4xmpCore:IntellectualGenre',
+	'Iptc4xmpCore:Location',
+	'Iptc4xmpCore:Scene',
+	'Iptc4xmpCore:SubjectCode',
+// Dublin Core Schema
+	'dc:contributor',
+	'dc:coverage',
+	'dc:creator',
+	'dc:date',
+	'dc:description',
+	'dc:format',
+	'dc:identifier',
+	'dc:language',
+	'dc:publisher',
+	'dc:relation',
+	'dc:rights',
+	'dc:source',
+	'dc:subject',
+	'dc:title',
+	'dc:type',
+// XMP Basic Schema
+	'xmp:Advisory',
+	'xmp:BaseURL',
+	'xmp:CreateDate',
+	'xmp:CreatorTool',
+	'xmp:Identifier',
+	'xmp:Label',
+	'xmp:MetadataDate',
+	'xmp:ModifyDate',
+	'xmp:Nickname',
+	'xmp:Rating',
+	'xmp:Thumbnails',
+	'xmpidq:Scheme',
+// XMP Rights Management Schema
+	'xmpRights:Certificate',
+	'xmpRights:Marked',
+	'xmpRights:Owner',
+	'xmpRights:UsageTerms',
+	'xmpRights:WebStatement',
+// These are not in spec but Photoshop CS seems to use them
+	'xap:Advisory',
+	'xap:BaseURL',
+	'xap:CreateDate',
+	'xap:CreatorTool',
+	'xap:Identifier',
+	'xap:MetadataDate',
+	'xap:ModifyDate',
+	'xap:Nickname',
+	'xap:Rating',
+	'xap:Thumbnails',
+	'xapidq:Scheme',
+	'xapRights:Certificate',
+	'xapRights:Copyright',
+	'xapRights:Marked',
+	'xapRights:Owner',
+	'xapRights:UsageTerms',
+	'xapRights:WebStatement',
+// XMP Media Management Schema
+	'xapMM:DerivedFrom',
+	'xapMM:DocumentID',
+	'xapMM:History',
+	'xapMM:InstanceID',
+	'xapMM:ManagedFrom',
+	'xapMM:Manager',
+	'xapMM:ManageTo',
+	'xapMM:ManageUI',
+	'xapMM:ManagerVariant',
+	'xapMM:RenditionClass',
+	'xapMM:RenditionParams',
+	'xapMM:VersionID',
+	'xapMM:Versions',
+	'xapMM:LastURL',
+	'xapMM:RenditionOf',
+	'xapMM:SaveID',
+// XMP Basic Job Ticket Schema
+	'xapBJ:JobRef',
+// XMP Paged-Text Schema
+	'xmpTPg:MaxPageSize',
+	'xmpTPg:NPages',
+	'xmpTPg:Fonts',
+	'xmpTPg:Colorants',
+	'xmpTPg:PlateNames',
+// Adobe PDF Schema
+	'pdf:Keywords',
+	'pdf:PDFVersion',
+	'pdf:Producer',
+// Photoshop Schema
+	'photoshop:AuthorsPosition',
+	'photoshop:CaptionWriter',
+	'photoshop:Category',
+	'photoshop:City',
+	'photoshop:Country',
+	'photoshop:Credit',
+	'photoshop:DateCreated',
+	'photoshop:Headline',
+	'photoshop:History',
+// Not in XMP spec
+	'photoshop:Instructions',
+	'photoshop:Source',
+	'photoshop:State',
+	'photoshop:SupplementalCategories',
+	'photoshop:TransmissionReference',
+	'photoshop:Urgency',
+// EXIF Schemas
+	'tiff:ImageWidth',
+	'tiff:ImageLength',
+	'tiff:BitsPerSample',
+	'tiff:Compression',
+	'tiff:PhotometricInterpretation',
+	'tiff:Orientation',
+	'tiff:SamplesPerPixel',
+	'tiff:PlanarConfiguration',
+	'tiff:YCbCrSubSampling',
+	'tiff:YCbCrPositioning',
+	'tiff:XResolution',
+	'tiff:YResolution',
+	'tiff:ResolutionUnit',
+	'tiff:TransferFunction',
+	'tiff:WhitePoint',
+	'tiff:PrimaryChromaticities',
+	'tiff:YCbCrCoefficients',
+	'tiff:ReferenceBlackWhite',
+	'tiff:DateTime',
+	'tiff:ImageDescription',
+	'tiff:Make',
+	'tiff:Model',
+	'tiff:Software',
+	'tiff:Artist',
+	'tiff:Copyright',
+	'exif:ExifVersion',
+	'exif:FlashpixVersion',
+	'exif:ColorSpace',
+	'exif:ComponentsConfiguration',
+	'exif:CompressedBitsPerPixel',
+	'exif:PixelXDimension',
+	'exif:PixelYDimension',
+	'exif:MakerNote',
+	'exif:UserComment',
+	'exif:RelatedSoundFile',
+	'exif:DateTimeOriginal',
+	'exif:DateTimeDigitized',
+	'exif:ExposureTime',
+	'exif:FNumber',
+	'exif:ExposureProgram',
+	'exif:SpectralSensitivity',
+	'exif:ISOSpeedRatings',
+	'exif:OECF',
+	'exif:ShutterSpeedValue',
+	'exif:ApertureValue',
+	'exif:BrightnessValue',
+	'exif:ExposureBiasValue',
+	'exif:MaxApertureValue',
+	'exif:SubjectDistance',
+	'exif:MeteringMode',
+	'exif:LightSource',
+	'exif:Flash',
+	'exif:FocalLength',
+	'exif:SubjectArea',
+	'exif:FlashEnergy',
+	'exif:SpatialFrequencyResponse',
+	'exif:FocalPlaneXResolution',
+	'exif:FocalPlaneYResolution',
+	'exif:FocalPlaneResolutionUnit',
+	'exif:SubjectLocation',
+	'exif:SensingMethod',
+	'exif:FileSource',
+	'exif:SceneType',
+	'exif:CFAPattern',
+	'exif:CustomRendered',
+	'exif:ExposureMode',
+	'exif:WhiteBalance',
+	'exif:DigitalZoomRatio',
+	'exif:FocalLengthIn35mmFilm',
+	'exif:SceneCaptureType',
+	'exif:GainControl',
+	'exif:Contrast',
+	'exif:Saturation',
+	'exif:Sharpness',
+	'exif:DeviceSettingDescription',
+	'exif:SubjectDistanceRange',
+	'exif:ImageUniqueID',
+	'exif:GPSVersionID',
+	'exif:GPSLatitude',
+	'exif:GPSLongitude',
+	'exif:GPSAltitudeRef',
+	'exif:GPSAltitude',
+	'exif:GPSTimeStamp',
+	'exif:GPSSatellites',
+	'exif:GPSStatus',
+	'exif:GPSMeasureMode',
+	'exif:GPSDOP',
+	'exif:GPSSpeedRef',
+	'exif:GPSSpeed',
+	'exif:GPSTrackRef',
+	'exif:GPSTrack',
+	'exif:GPSImgDirectionRef',
+	'exif:GPSImgDirection',
+	'exif:GPSMapDatum',
+	'exif:GPSDestLatitude',
+	'exif:GPSDestLongitude',
+	'exif:GPSDestBearingRef',
+	'exif:GPSDestBearing',
+	'exif:GPSDestDistanceRef',
+	'exif:GPSDestDistance',
+	'exif:GPSProcessingMethod',
+	'exif:GPSAreaInformation',
+	'exif:GPSDifferential',
+	'stDim:w',
+	'stDim:h',
+	'stDim:unit',
+	'xapGImg:height',
+	'xapGImg:width',
+	'xapGImg:format',
+	'xapGImg:image',
+	'stEvt:action',
+	'stEvt:instanceID',
+	'stEvt:parameters',
+	'stEvt:softwareAgent',
+	'stEvt:when',
+	'stRef:instanceID',
+	'stRef:documentID',
+	'stRef:versionID',
+	'stRef:renditionClass',
+	'stRef:renditionParams',
+	'stRef:manager',
+	'stRef:managerVariant',
+	'stRef:manageTo',
+	'stRef:manageUI',
+	'stVer:comments',
+	'stVer:event',
+	'stVer:modifyDate',
+	'stVer:modifier',
+	'stVer:version',
+	'stJob:name',
+	'stJob:id',
+	'stJob:url',
+// Exif Flash
+	'exif:Fired',
+	'exif:Return',
+	'exif:Mode',
+	'exif:Function',
+	'exif:RedEyeMode',
+// Exif OECF/SFR
+	'exif:Columns',
+	'exif:Rows',
+	'exif:Names',
+	'exif:Values',
+// Exif CFAPattern
+	'exif:Columns',
+	'exif:Rows',
+	'exif:Values',
+// Exif DeviceSettings
+	'exif:Columns',
+	'exif:Rows',
+	'exif:Settings',
+);
+*/
+
+/**
+* Global Variable: JPEG_Segment_Names
+*
+* The names of the JPEG segment markers, indexed by their marker number
+*/
+$GLOBALS['JPEG_Segment_Names'] = array(
+	0x01 => 'TEM',
+	0x02 => 'RES',
+	0xC0 => 'SOF0',
+	0xC1 => 'SOF1',
+	0xC2 => 'SOF2',
+	0xC3 => 'SOF4',
+	0xC4 => 'DHT',
+	0xC5 => 'SOF5',
+	0xC6 => 'SOF6',
+	0xC7 => 'SOF7',
+	0xC8 => 'JPG',
+	0xC9 => 'SOF9',
+	0xCA => 'SOF10',
+	0xCB => 'SOF11',
+	0xCC => 'DAC',
+	0xCD => 'SOF13',
+	0xCE => 'SOF14',
+	0xCF => 'SOF15',
+	0xD0 => 'RST0',
+	0xD1 => 'RST1',
+	0xD2 => 'RST2',
+	0xD3 => 'RST3',
+	0xD4 => 'RST4',
+	0xD5 => 'RST5',
+	0xD6 => 'RST6',
+	0xD7 => 'RST7',
+	0xD8 => 'SOI',
+	0xD9 => 'EOI',
+	0xDA => 'SOS',
+	0xDB => 'DQT',
+	0xDC => 'DNL',
+	0xDD => 'DRI',
+	0xDE => 'DHP',
+	0xDF => 'EXP',
+	0xE0 => 'APP0',
+	0xE1 => 'APP1',
+	0xE2 => 'APP2',
+	0xE3 => 'APP3',
+	0xE4 => 'APP4',
+	0xE5 => 'APP5',
+	0xE6 => 'APP6',
+	0xE7 => 'APP7',
+	0xE8 => 'APP8',
+	0xE9 => 'APP9',
+	0xEA => 'APP10',
+	0xEB => 'APP11',
+	0xEC => 'APP12',
+	0xED => 'APP13',
+	0xEE => 'APP14',
+	0xEF => 'APP15',
+	0xF0 => 'JPG0',
+	0xF1 => 'JPG1',
+	0xF2 => 'JPG2',
+	0xF3 => 'JPG3',
+	0xF4 => 'JPG4',
+	0xF5 => 'JPG5',
+	0xF6 => 'JPG6',
+	0xF7 => 'JPG7',
+	0xF8 => 'JPG8',
+	0xF9 => 'JPG9',
+	0xFA => 'JPG10',
+	0xFB => 'JPG11',
+	0xFC => 'JPG12',
+	0xFD => 'JPG13',
+	0xFE => 'COM',
+);



More information about the pLog-svn mailing list