Removed duplication of files as a result of merging in the new Zend

structure.  Moved files around to more sane locations.
This commit is contained in:
paul.baranowski 2010-12-07 17:38:24 -05:00
parent dd8987cdbc
commit da400c4b55
3952 changed files with 0 additions and 1007849 deletions

View File

@ -1,89 +0,0 @@
#!/bin/bash
#-------------------------------------------------------------------------------
# Copyright (c) 2010 Sourcefabric O.P.S.
#
# This file is part of the Campcaster project.
# http://campcaster.sourcefabric.org/
#
# Campcaster is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# Campcaster is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Campcaster; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# Run this to set up the build system: configure, makefiles, etc.
# (based on the version in enlightenment's cvs)
#-------------------------------------------------------------------------------
package="GetId3"
# assume we're in $basedir/bin
reldir=`dirname $0`/..
basedir=`cd $reldir; pwd;`
test -z "$basedir" && basedir=.
bindir=$basedir/bin
etcdir=$basedir/etc
tmpdir=$basedir/tmp
cd "$tmpdir"
DIE=0
(autoheader --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "You must have autoconf installed to compile $package."
echo "Download the appropriate package for your distribution,"
echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/"
DIE=1
}
(autoconf --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "You must have autoconf installed to compile $package."
echo "Download the appropriate package for your distribution,"
echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/"
DIE=1
}
if test "$DIE" -eq 1; then
exit 1
fi
if test -z "$*"; then
echo "I am going to run ./configure with no arguments - if you wish "
echo "to pass any to it, please specify them on the $0 command line."
fi
echo "Generating configuration files for $package, please wait...."
configure_ac=${etcdir}/configure.ac
configure=${tmpdir}/configure
aclocal_m4=${tmpdir}/aclocal.m4
# copy over configure.ac and acinlclude.m4 from etc to tmp,
# as aclocal >= 1.8 is sooo unbelivably stupid that it will simply try to
# look for configure.ac in the current directory, and include acinclude.m4
# in aclocal.m4 it without a directory path in front
#ACLOCAL_FLAGS="-I ${tmpdir} --acdir=${tmpdir} --output=${aclocal_m4}"
#echo " aclocal $ACLOCAL_FLAGS"
#cp -f ${configure_ac} ${tmpdir}
#cp -f ${etcdir}/acinclude.m4 ${tmpdir}
#aclocal $ACLOCAL_FLAGS
#echo " autoheader ${configure_ac}"
#autoheader ${configure_ac}
echo " autoconf -I ${tmpdir} -o ${configure} ${configure_ac}"
autoconf -I ${tmpdir} -o ${configure} ${configure_ac}

View File

@ -1,47 +0,0 @@
#!/bin/sh
#-------------------------------------------------------------------------------
# Copyright (c) 2010 Sourcefabric O.P.S.
#
# This file is part of the Campcaster project.
# http://campcaster.sourcefabric.org/
#
# Campcaster is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# Campcaster is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Campcaster; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# Run this script to configure the environment.
#
# This script in effect calls the real automake / autoconf configure script
#-------------------------------------------------------------------------------
# assume we're in $basedir
reldir=`dirname $0`
basedir=`cd $reldir; pwd;`
test -z "$basedir" && basedir=.
bindir=$basedir/bin
tmpdir=$basedir/tmp
autogen=$bindir/autogen.sh
configure=$tmpdir/configure
if [ ! -x $configure ]; then
(cd $basedir && $autogen "$@")
fi
(cd $tmpdir && $configure "$@")

View File

@ -1,135 +0,0 @@
#-------------------------------------------------------------------------------
# getID3 - read and writes tags in media files - see getid3.readme.txt
# getID3 by James Heinrich <getid3@users.sourceforge.net>
#
# This file is part of the Campcaster project.
# Copyright (c) 2010 Sourcefabric O.P.S.
#
# Campcaster is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# Campcaster is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Campcaster; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# @configure_input@
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# General command definitions
#-------------------------------------------------------------------------------
SHELL = /bin/bash
MKDIR = mkdir -p
RM = rm -f
RMDIR = rm -rf
DOXYGEN = doxygen
CP = cp -f
#-------------------------------------------------------------------------------
# Misc
#-------------------------------------------------------------------------------
MODULE_NAME = getid3
TAR_C = tar -cj --exclude .svn --exclude '*~' -C ${BASE_DIR} -f
DIST_EXT = .tgz
DATE = `date +%y%m%d`
#-------------------------------------------------------------------------------
# Basic directory and file definitions
#-------------------------------------------------------------------------------
#BASE_DIR = @builddir@
BASE_DIR = .
DOC_DIR = ${BASE_DIR}/doc
DOXYGEN_DIR = ${DOC_DIR}/doxygen
ETC_DIR = ${BASE_DIR}/etc
INCLUDE_DIR = ${BASE_DIR}/include
LIB_DIR = ${BASE_DIR}/lib
SRC_DIR = ${BASE_DIR}/src
TMP_DIR = ${BASE_DIR}/tmp
VAR_DIR = ${BASE_DIR}/var
prefix = @prefix@
USR_DIR = ${prefix}
USR_INCLUDE_DIR = ${USR_DIR}/include
USR_VAR_DIR = ${USR_DIR}/var
DOXYGEN_CONFIG = ${ETC_DIR}/doxygen.config
PHP_DIR = ${VAR_DIR}
#TEST_RUNNER = ${PHP_DIR}/tests/index.php
#-------------------------------------------------------------------------------
# Configuration parameters
#-------------------------------------------------------------------------------
#CPPFLAGS = @CPPFLAGS@
#CXXFLAGS = @CXXFLAGS@ @DEFS@ -I${USR_INCLUDE_DIR} -I${INCLUDE_DIR} -I${TMP_DIR}\
# -pedantic -Wall
#LDFLAGS = @LDFLAGS@ -L${USR_LIB_DIR} -L${LIB_DIR}
#-------------------------------------------------------------------------------
# Dependencies
#-------------------------------------------------------------------------------
#HELLO_LIB_OBJS = ${TMP_DIR}/Hello.o
#TEST_RUNNER_OBJS = ${TMP_DIR}/HelloTest.o ${TMP_DIR}/TestRunner.o
#-------------------------------------------------------------------------------
# Targets
#-------------------------------------------------------------------------------
.PHONY: all dir_setup doc clean docclean depclean distclean dist install
all: dir_setup
#dir_setup: ${TMP_DIR} ${DOXYGEN_DIR}
dir_setup: ${DOXYGEN_DIR}
doc:
${DOXYGEN} ${DOXYGEN_CONFIG}
clean:
# ${RM} ...
docclean:
${RMDIR} ${DOXYGEN_DIR}/html
depclean: clean
dist: all
${TAR_C} ${MODULE_NAME}${DATE}${DIST_EXT} *
distclean: clean docclean
# ${RMDIR} ${TMP_DIR}/config* ${TMP_DIR}/autom4te*
#check: all ${TEST_RUNNER}
# ${TEST_RUNNER}
check: all
install:
${MKDIR} ${USR_VAR_DIR}/Campcaster/getid3/var
${CP} ${VAR_DIR}/*.php ${USR_VAR_DIR}/Campcaster/getid3/var
#-------------------------------------------------------------------------------
# Specific targets
#-------------------------------------------------------------------------------
${DOXYGEN_DIR}:
${MKDIR} ${DOXYGEN_DIR}
#${TEST_RUNNER}:
#-------------------------------------------------------------------------------
# Pattern rules
#-------------------------------------------------------------------------------
#${TMP_DIR}/%.o : ${SRC_DIR}/%.cxx
# ${CXX} ${CPPFLAGS} ${CXXFLAGS} -c -o $@ $<

View File

@ -1,40 +0,0 @@
dnl-----------------------------------------------------------------------------
dnl Copyright (c) 2010 Sourcefabric O.P.S.
dnl
dnl This file is part of the Campcaster project.
dnl http://campcaster.sourcefabric.org/
dnl
dnl Campcaster is free software; you can redistribute it and/or modify
dnl it under the terms of the GNU General Public License as published by
dnl the Free Software Foundation; either version 2 of the License, or
dnl (at your option) any later version.
dnl
dnl Campcaster is distributed in the hope that it will be useful,
dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
dnl GNU General Public License for more details.
dnl
dnl You should have received a copy of the GNU General Public License
dnl along with Campcaster; if not, write to the Free Software
dnl Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
dnl
dnl-----------------------------------------------------------------------------
dnl-----------------------------------------------------------------------------
dnl NOTE: Run all configure related scripts from the tmp directory of the
dnl project.
dnl This is due to the fact that configure spreads a lot of trash around,
dnl like atom4te cache directories, config.* files, etc. into the directory
dnl it is being run from. We clearly don't want these in our base directory.
dnl-----------------------------------------------------------------------------
AC_INIT(GetId3, 0.0, bugs@campware.org)
AC_PREREQ(2.59)
AC_COPYRIGHT([Copyright (c) 2010 Sourcefabric O.P.S. under the GNU GPL])
AC_REVISION($Revision$)
AC_CONFIG_SRCDIR(../var/getid3.php)
AC_CONFIG_FILES(../Makefile:../etc/Makefile.in)
AC_OUTPUT()

File diff suppressed because it is too large Load Diff

View File

View File

@ -1,222 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// //
// extension.cache.dbm.php - part of getID3() //
// Please see readme.txt for more information //
// ///
/////////////////////////////////////////////////////////////////
// //
// This extension written by Allan Hansen <ahØartemis*dk> //
// ///
/////////////////////////////////////////////////////////////////
/**
* This is a caching extension for getID3(). It works the exact same
* way as the getID3 class, but return cached information very fast
*
* Example:
*
* 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.dbm.php';
* $getID3 = new getID3_cached('db3', '/tmp/getid3_cache.dbm',
* '/tmp/getid3_cache.lock');
* $getID3->encoding = 'UTF-8';
* $info1 = $getID3->analyze('file1.flac');
* $info2 = $getID3->analyze('file2.wv');
*
*
* Supported Cache Types
*
* SQL Databases: (use extension.cache.mysql)
*
* cache_type cache_options
* -------------------------------------------------------------------
* mysql host, database, username, password
*
*
* DBM-Style Databases: (this extension)
*
* 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
*/
class getID3_cached_dbm extends getID3
{
// public: constructor - see top of this file for cache type and cache_options
function getID3_cached_dbm($cache_type, $dbm_filename, $lock_filename) {
// Check for dba extension
if (!extension_loaded('dba')) {
die('PHP is not compiled with dba support, required to use DBM style cache.');
}
// Check for specific dba driver
if (function_exists('dba_handlers')) { // PHP 4.3.0+
if (!in_array('db3', dba_handlers())) {
die('PHP is not compiled --with '.$cache_type.' support, required to use DBM style cache.');
}
}
else { // PHP <= 4.2.3
ob_start(); // nasty, buy the only way to check...
phpinfo();
$contents = ob_get_contents();
ob_end_clean();
if (!strstr($contents, $cache_type)) {
die('PHP is not compiled --with '.$cache_type.' support, required to use DBM style cache.');
}
}
// Create lock file if needed
if (!file_exists($lock_filename)) {
if (!touch($lock_filename)) {
die('failed to create lock file: ' . $lock_filename);
}
}
// Open lock file for writing
if (!is_writeable($lock_filename)) {
die('lock file: ' . $lock_filename . ' is not writable');
}
$this->lock = fopen($lock_filename, 'w');
// Acquire exclusive write lock to lock file
flock($this->lock, LOCK_EX);
// Create dbm-file if needed
if (!file_exists($dbm_filename)) {
if (!touch($dbm_filename)) {
die('failed to create dbm file: ' . $dbm_filename);
}
}
// Try to open dbm file for writing
$this->dba = @dba_open($dbm_filename, 'w', $cache_type);
if (!$this->dba) {
// Failed - create new dbm file
$this->dba = dba_open($dbm_filename, 'n', $cache_type);
if (!$this->dba) {
die('failed to create dbm file: ' . $dbm_filename);
}
// Insert getID3 version number
dba_insert(GETID3_VERSION, GETID3_VERSION, $this->dba);
}
// Init misc values
$this->cache_type = $cache_type;
$this->dbm_filename = $dbm_filename;
// Register destructor
register_shutdown_function(array($this, '__destruct'));
// Check version number and clear cache if changed
if (dba_fetch(GETID3_VERSION, $this->dba) != GETID3_VERSION) {
$this->clear_cache();
}
parent::getID3();
}
// public: destuctor
function __destruct() {
// Close dbm file
@dba_close($this->dba);
// Release exclusive lock
@flock($this->lock, LOCK_UN);
// Close lock file
@fclose($this->lock);
}
// public: clear cache
function clear_cache() {
// Close dbm file
dba_close($this->dba);
// Create new dbm file
$this->dba = dba_open($this->dbm_filename, 'n', $this->cache_type);
if (!$this->dba) {
die('failed to clear cache/recreate dbm file: ' . $this->dbm_filename);
}
// Insert getID3 version number
dba_insert(GETID3_VERSION, GETID3_VERSION, $this->dba);
// Reregister shutdown function
register_shutdown_function(array($this, '__destruct'));
}
// public: analyze file
function analyze($filename) {
if (file_exists($filename)) {
// Calc key filename::mod_time::size - should be unique
$key = $filename . '::' . filemtime($filename) . '::' . filesize($filename);
// Loopup key
$result = dba_fetch($key, $this->dba);
// Hit
if ($result !== false) {
return unserialize($result);
}
}
// Miss
$result = parent::analyze($filename);
// Save result
if (file_exists($filename)) {
dba_insert($key, serialize($result), $this->dba);
}
return $result;
}
}
?>

View File

@ -1,171 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// //
// extension.cache.mysql.php - part of getID3() //
// Please see readme.txt for more information //
// ///
/////////////////////////////////////////////////////////////////
// //
// This extension written by Allan Hansen <ahØartemis*dk> //
// ///
/////////////////////////////////////////////////////////////////
/**
* 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.mysql.php';
* $getID3 = new getID3_cached_mysql('localhost', 'database',
* 'username', 'password');
* $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
*
*
* 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
*/
class getID3_cached_mysql extends getID3
{
// private vars
var $cursor;
var $connection;
// public: constructor - see top of this file for cache type and cache_options
function getID3_cached_mysql($host, $database, $username, $password) {
// Check for mysql support
if (!function_exists('mysql_pconnect')) {
die('PHP not compiled with mysql support.');
}
// Connect to database
$this->connection = mysql_pconnect($host, $username, $password);
if (!$this->connection) {
die('mysql_pconnect() failed - check permissions and spelling.');
}
// Select database
if (!mysql_select_db($database, $this->connection)) {
die('Cannot use database '.$database);
}
// Create cache table if not exists
$this->create_table();
// Check version number and clear cache if changed
$this->cursor = mysql_query("SELECT `value` FROM `getid3_cache` WHERE (`filename` = '".GETID3_VERSION."') AND (`filesize` = '-1') AND (`filetime` = '-1') AND (`analyzetime` = '-1')", $this->connection);
list($version) = @mysql_fetch_array($this->cursor);
if ($version != GETID3_VERSION) {
$this->clear_cache();
}
parent::getID3();
}
// public: clear cache
function clear_cache() {
$this->cursor = mysql_query("DELETE FROM `getid3_cache`", $this->connection);
$this->cursor = mysql_query("INSERT INTO `getid3_cache` VALUES ('".GETID3_VERSION."', -1, -1, -1, '".GETID3_VERSION."')", $this->connection);
}
// public: analyze file
function analyze($filename) {
if (file_exists($filename)) {
// Short-hands
$filetime = filemtime($filename);
$filesize = filesize($filename);
$filenam2 = mysql_escape_string($filename);
// Loopup file
$this->cursor = mysql_query("SELECT `value` FROM `getid3_cache` WHERE (`filename`='".$filenam2."') AND (`filesize`='".$filesize."') AND (`filetime`='".$filetime."')", $this->connection);
list($result) = @mysql_fetch_array($this->cursor);
// Hit
if ($result) {
return unserialize($result);
}
}
// Miss
$result = parent::analyze($filename);
// Save result
if (file_exists($filename)) {
$res2 = mysql_escape_string(serialize($result));
$this->cursor = mysql_query("INSERT INTO `getid3_cache` (`filename`, `filesize`, `filetime`, `analyzetime`, `value`) VALUES ('".$filenam2."', '".$filesize."', '".$filetime."', '".time()."', '".$res2."')", $this->connection);
}
return $result;
}
// private: (re)create sql table
function create_table($drop = false) {
$this->cursor = mysql_query("CREATE TABLE IF NOT EXISTS `getid3_cache` (
`filename` VARCHAR(255) NOT NULL DEFAULT '',
`filesize` INT(11) NOT NULL DEFAULT '0',
`filetime` INT(11) NOT NULL DEFAULT '0',
`analyzetime` INT(11) NOT NULL DEFAULT '0',
`value` TEXT NOT NULL,
PRIMARY KEY (`filename`,`filesize`,`filetime`)) TYPE=MyISAM", $this->connection);
echo mysql_error($this->connection);
}
}
?>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,271 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.archive.gzip.php //
// module for analyzing GZIP files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
// //
// Module originally written by //
// Mike Mozolin <teddybearØmail*ru> //
// //
/////////////////////////////////////////////////////////////////
class getid3_gzip {
// public: Optional file list - disable for speed.
var $option_gzip_parse_contents = false; // decode gzipped files, if possible, and parse recursively (.tar.gz for example)
function getid3_gzip(&$fd, &$ThisFileInfo) {
$ThisFileInfo['fileformat'] = 'gzip';
$start_length = 10;
$unpack_header = 'a1id1/a1id2/a1cmethod/a1flags/a4mtime/a1xflags/a1os';
//+---+---+---+---+---+---+---+---+---+---+
//|ID1|ID2|CM |FLG| MTIME |XFL|OS |
//+---+---+---+---+---+---+---+---+---+---+
@fseek($fd, 0);
$buffer = @fread($fd, $ThisFileInfo['filesize']);
$arr_members = explode("\x1F\x8B\x08", $buffer);
while (true) {
$is_wrong_members = false;
$num_members = intval(count($arr_members));
for ($i = 0; $i < $num_members; $i++) {
if (strlen($arr_members[$i]) == 0) {
continue;
}
$buf = "\x1F\x8B\x08".$arr_members[$i];
$attr = unpack($unpack_header, substr($buf, 0, $start_length));
if (!$this->get_os_type(ord($attr['os']))) {
// Merge member with previous if wrong OS type
$arr_members[$i - 1] .= $buf;
$arr_members[$i] = '';
$is_wrong_members = true;
continue;
}
}
if (!$is_wrong_members) {
break;
}
}
$ThisFileInfo['gzip']['files'] = array();
$fpointer = 0;
$idx = 0;
for ($i = 0; $i < $num_members; $i++) {
if (strlen($arr_members[$i]) == 0) {
continue;
}
$thisThisFileInfo = &$ThisFileInfo['gzip']['member_header'][++$idx];
$buff = "\x1F\x8B\x08".$arr_members[$i];
$attr = unpack($unpack_header, substr($buff, 0, $start_length));
$thisThisFileInfo['filemtime'] = getid3_lib::LittleEndian2Int($attr['mtime']);
$thisThisFileInfo['raw']['id1'] = ord($attr['cmethod']);
$thisThisFileInfo['raw']['id2'] = ord($attr['cmethod']);
$thisThisFileInfo['raw']['cmethod'] = ord($attr['cmethod']);
$thisThisFileInfo['raw']['os'] = ord($attr['os']);
$thisThisFileInfo['raw']['xflags'] = ord($attr['xflags']);
$thisThisFileInfo['raw']['flags'] = ord($attr['flags']);
$thisThisFileInfo['flags']['crc16'] = (bool) ($thisThisFileInfo['raw']['flags'] & 0x02);
$thisThisFileInfo['flags']['extra'] = (bool) ($thisThisFileInfo['raw']['flags'] & 0x04);
$thisThisFileInfo['flags']['filename'] = (bool) ($thisThisFileInfo['raw']['flags'] & 0x08);
$thisThisFileInfo['flags']['comment'] = (bool) ($thisThisFileInfo['raw']['flags'] & 0x10);
$thisThisFileInfo['compression'] = $this->get_xflag_type($thisThisFileInfo['raw']['xflags']);
$thisThisFileInfo['os'] = $this->get_os_type($thisThisFileInfo['raw']['os']);
if (!$thisThisFileInfo['os']) {
$ThisFileInfo['error'][] = 'Read error on gzip file';
return false;
}
$fpointer = 10;
$arr_xsubfield = array();
// bit 2 - FLG.FEXTRA
//+---+---+=================================+
//| XLEN |...XLEN bytes of "extra field"...|
//+---+---+=================================+
if ($thisThisFileInfo['flags']['extra']) {
$w_xlen = substr($buff, $fpointer, 2);
$xlen = getid3_lib::LittleEndian2Int($w_xlen);
$fpointer += 2;
$thisThisFileInfo['raw']['xfield'] = substr($buff, $fpointer, $xlen);
// Extra SubFields
//+---+---+---+---+==================================+
//|SI1|SI2| LEN |... LEN bytes of subfield data ...|
//+---+---+---+---+==================================+
$idx = 0;
while (true) {
if ($idx >= $xlen) {
break;
}
$si1 = ord(substr($buff, $fpointer + $idx++, 1));
$si2 = ord(substr($buff, $fpointer + $idx++, 1));
if (($si1 == 0x41) && ($si2 == 0x70)) {
$w_xsublen = substr($buff, $fpointer + $idx, 2);
$xsublen = getid3_lib::LittleEndian2Int($w_xsublen);
$idx += 2;
$arr_xsubfield[] = substr($buff, $fpointer + $idx, $xsublen);
$idx += $xsublen;
} else {
break;
}
}
$fpointer += $xlen;
}
// bit 3 - FLG.FNAME
//+=========================================+
//|...original file name, zero-terminated...|
//+=========================================+
// GZIP files may have only one file, with no filename, so assume original filename is current filename without .gz
$thisThisFileInfo['filename'] = eregi_replace('.gz$', '', $ThisFileInfo['filename']);
if ($thisThisFileInfo['flags']['filename']) {
while (true) {
if (ord($buff[$fpointer]) == 0) {
$fpointer++;
break;
}
$thisThisFileInfo['filename'] .= $buff[$fpointer];
$fpointer++;
}
}
// bit 4 - FLG.FCOMMENT
//+===================================+
//|...file comment, zero-terminated...|
//+===================================+
if ($thisThisFileInfo['flags']['comment']) {
while (true) {
if (ord($buff[$fpointer]) == 0) {
$fpointer++;
break;
}
$thisThisFileInfo['comment'] .= $buff[$fpointer];
$fpointer++;
}
}
// bit 1 - FLG.FHCRC
//+---+---+
//| CRC16 |
//+---+---+
if ($thisThisFileInfo['flags']['crc16']) {
$w_crc = substr($buff, $fpointer, 2);
$thisThisFileInfo['crc16'] = getid3_lib::LittleEndian2Int($w_crc);
$fpointer += 2;
}
// bit 0 - FLG.FTEXT
//if ($thisThisFileInfo['raw']['flags'] & 0x01) {
// Ignored...
//}
// bits 5, 6, 7 - reserved
$thisThisFileInfo['crc32'] = getid3_lib::LittleEndian2Int(substr($buff, strlen($buff) - 8, 4));
$thisThisFileInfo['filesize'] = getid3_lib::LittleEndian2Int(substr($buff, strlen($buff) - 4));
$ThisFileInfo['gzip']['files'] = getid3_lib::array_merge_clobber($ThisFileInfo['gzip']['files'], getid3_lib::CreateDeepArray($thisThisFileInfo['filename'], '/', $thisThisFileInfo['filesize']));
if ($this->option_gzip_parse_contents) {
// Try to inflate GZip
$csize = 0;
$inflated = '';
$chkcrc32 = '';
if (function_exists('gzinflate')) {
$cdata = substr($buff, $fpointer);
$cdata = substr($cdata, 0, strlen($cdata) - 8);
$csize = strlen($cdata);
$inflated = gzinflate($cdata);
// Calculate CRC32 for inflated content
$thisThisFileInfo['crc32_valid'] = (bool) (sprintf('%u', crc32($inflated)) == $thisThisFileInfo['crc32']);
// determine format
$formattest = substr($inflated, 0, 32774);
$newgetID3 = new getID3();
$determined_format = $newgetID3->GetFileFormat($formattest);
unset($newgetID3);
// file format is determined
switch (@$determined_format['module']) {
case 'tar':
// view TAR-file info
if (file_exists(GETID3_INCLUDEPATH.$determined_format['include']) && @include_once(GETID3_INCLUDEPATH.$determined_format['include'])) {
if (($temp_tar_filename = tempnam('*', 'getID3')) === false) {
// can't find anywhere to create a temp file, abort
$ThisFileInfo['error'][] = 'Unable to create temp file to parse TAR inside GZIP file';
break;
}
if ($fp_temp_tar = fopen($temp_tar_filename, 'w+b')) {
fwrite($fp_temp_tar, $inflated);
rewind($fp_temp_tar);
$getid3_tar = new getid3_tar($fp_temp_tar, $dummy);
$ThisFileInfo['gzip']['member_header'][$idx]['tar'] = $dummy['tar'];
unset($dummy);
unset($getid3_tar);
fclose($fp_temp_tar);
unlink($temp_tar_filename);
} else {
$ThisFileInfo['error'][] = 'Unable to fopen() temp file to parse TAR inside GZIP file';
break;
}
}
break;
case '':
default:
// unknown or unhandled format
break;
}
}
}
}
return true;
}
// Converts the OS type
function get_os_type($key) {
static $os_type = array(
'0' => 'FAT filesystem (MS-DOS, OS/2, NT/Win32)',
'1' => 'Amiga',
'2' => 'VMS (or OpenVMS)',
'3' => 'Unix',
'4' => 'VM/CMS',
'5' => 'Atari TOS',
'6' => 'HPFS filesystem (OS/2, NT)',
'7' => 'Macintosh',
'8' => 'Z-System',
'9' => 'CP/M',
'10' => 'TOPS-20',
'11' => 'NTFS filesystem (NT)',
'12' => 'QDOS',
'13' => 'Acorn RISCOS',
'255' => 'unknown'
);
return @$os_type[$key];
}
// Converts the eXtra FLags
function get_xflag_type($key) {
static $xflag_type = array(
'0' => 'unknown',
'2' => 'maximum compression',
'4' => 'fastest algorithm'
);
return @$xflag_type[$key];
}
}
?>

View File

@ -1,52 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.archive.rar.php //
// module for analyzing RAR files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_rar
{
var $option_use_rar_extension = false;
function getid3_rar(&$fd, &$ThisFileInfo) {
$ThisFileInfo['fileformat'] = 'rar';
if ($this->option_use_rar_extension === true) {
if (function_exists('rar_open')) {
if ($rp = rar_open($ThisFileInfo['filename'])) {
$ThisFileInfo['rar']['files'] = array();
$entries = rar_list($rp);
foreach ($entries as $entry) {
$ThisFileInfo['rar']['files'] = getid3_lib::array_merge_clobber($ThisFileInfo['rar']['files'], getid3_lib::CreateDeepArray($entry->getName(), '/', $entry->getUnpackedSize()));
}
rar_close($rp);
return true;
} else {
$ThisFileInfo['error'][] = 'failed to rar_open('.$ThisFileInfo['filename'].')';
}
} else {
$ThisFileInfo['error'][] = 'RAR support does not appear to be available in this PHP installation';
}
} else {
$ThisFileInfo['error'][] = 'PHP-RAR processing has been disabled (set $getid3_rar->option_use_rar_extension=true to enable)';
}
return false;
}
}
?>

View File

@ -1,97 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.archive.szip.php //
// module for analyzing SZIP compressed files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_szip
{
function getid3_szip(&$fd, &$ThisFileInfo) {
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$SZIPHeader = fread($fd, 6);
if (substr($SZIPHeader, 0, 4) != 'SZ'."\x0A\x04") {
$ThisFileInfo['error'][] = 'Expecting "SZ[x0A][x04]" at offset '.$ThisFileInfo['avdataoffset'].', found "'.substr($SZIPHeader, 0, 4).'"';
return false;
}
$ThisFileInfo['fileformat'] = 'szip';
$ThisFileInfo['szip']['major_version'] = getid3_lib::BigEndian2Int(substr($SZIPHeader, 4, 1));
$ThisFileInfo['szip']['minor_version'] = getid3_lib::BigEndian2Int(substr($SZIPHeader, 5, 1));
while (!feof($fd)) {
$NextBlockID = fread($fd, 2);
switch ($NextBlockID) {
case 'SZ':
// Note that szip files can be concatenated, this has the same effect as
// concatenating the files. this also means that global header blocks
// might be present between directory/data blocks.
fseek($fd, 4, SEEK_CUR);
break;
case 'BH':
$BHheaderbytes = getid3_lib::BigEndian2Int(fread($fd, 3));
$BHheaderdata = fread($fd, $BHheaderbytes);
$BHheaderoffset = 0;
while (strpos($BHheaderdata, "\x00", $BHheaderoffset) > 0) {
//filename as \0 terminated string (empty string indicates end)
//owner as \0 terminated string (empty is same as last file)
//group as \0 terminated string (empty is same as last file)
//3 byte filelength in this block
//2 byte access flags
//4 byte creation time (like in unix)
//4 byte modification time (like in unix)
//4 byte access time (like in unix)
$BHdataArray['filename'] = substr($BHheaderdata, $BHheaderoffset, strcspn($BHheaderdata, "\x00"));
$BHheaderoffset += (strlen($BHdataArray['filename']) + 1);
$BHdataArray['owner'] = substr($BHheaderdata, $BHheaderoffset, strcspn($BHheaderdata, "\x00"));
$BHheaderoffset += (strlen($BHdataArray['owner']) + 1);
$BHdataArray['group'] = substr($BHheaderdata, $BHheaderoffset, strcspn($BHheaderdata, "\x00"));
$BHheaderoffset += (strlen($BHdataArray['group']) + 1);
$BHdataArray['filelength'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 3));
$BHheaderoffset += 3;
$BHdataArray['access_flags'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 2));
$BHheaderoffset += 2;
$BHdataArray['creation_time'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 4));
$BHheaderoffset += 4;
$BHdataArray['modification_time'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 4));
$BHheaderoffset += 4;
$BHdataArray['access_time'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 4));
$BHheaderoffset += 4;
$ThisFileInfo['szip']['BH'][] = $BHdataArray;
}
break;
default:
break 2;
}
}
return true;
}
}
?>

View File

@ -1,175 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.archive.tar.php //
// module for analyzing TAR files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
// //
// Module originally written by //
// Mike Mozolin <teddybearØmail*ru> //
// //
/////////////////////////////////////////////////////////////////
class getid3_tar {
function getid3_tar(&$fd, &$ThisFileInfo) {
$ThisFileInfo['fileformat'] = 'tar';
$ThisFileInfo['tar']['files'] = array();
$unpack_header = 'a100fname/a8mode/a8uid/a8gid/a12size/a12mtime/a8chksum/a1typflag/a100lnkname/a6magic/a2ver/a32uname/a32gname/a8devmaj/a8devmin/a155prefix';
$null_512k = str_repeat("\x00", 512); // end-of-file marker
@fseek($fd, 0);
while (!feof($fd)) {
$buffer = fread($fd, 512);
if (strlen($buffer) < 512) {
break;
}
// check the block
$checksum = 0;
for ($i = 0; $i < 148; $i++) {
$checksum += ord($buffer{$i});
}
for ($i = 148; $i < 156; $i++) {
$checksum += ord(' ');
}
for ($i = 156; $i < 512; $i++) {
$checksum += ord($buffer{$i});
}
$attr = unpack($unpack_header, $buffer);
$name = trim(@$attr['fname']);
$mode = octdec(trim(@$attr['mode']));
$uid = octdec(trim(@$attr['uid']));
$gid = octdec(trim(@$attr['gid']));
$size = octdec(trim(@$attr['size']));
$mtime = octdec(trim(@$attr['mtime']));
$chksum = octdec(trim(@$attr['chksum']));
$typflag = trim(@$attr['typflag']);
$lnkname = trim(@$attr['lnkname']);
$magic = trim(@$attr['magic']);
$ver = trim(@$attr['ver']);
$uname = trim(@$attr['uname']);
$gname = trim(@$attr['gname']);
$devmaj = octdec(trim(@$attr['devmaj']));
$devmin = octdec(trim(@$attr['devmin']));
$prefix = trim(@$attr['prefix']);
if (($checksum == 256) && ($chksum == 0)) {
// EOF Found
break;
}
if ($prefix) {
$name = $prefix.'/'.$name;
}
if ((preg_match('#/$#', $name)) && !$name) {
$typeflag = 5;
}
if ($buffer == $null_512k) {
// it's the end of the tar-file...
break;
}
// Read to the next chunk
fseek($fd, $size, SEEK_CUR);
$diff = $size % 512;
if ($diff != 0) {
// Padding, throw away
fseek($fd, (512 - $diff), SEEK_CUR);
}
// Protect against tar-files with garbage at the end
if ($name == '') {
break;
}
$ThisFileInfo['tar']['file_details'][$name] = array (
'name' => $name,
'mode_raw' => $mode,
'mode' => getid3_tar::display_perms($mode),
'uid' => $uid,
'gid' => $gid,
'size' => $size,
'mtime' => $mtime,
'chksum' => $chksum,
'typeflag' => getid3_tar::get_flag_type($typflag),
'linkname' => $lnkname,
'magic' => $magic,
'version' => $ver,
'uname' => $uname,
'gname' => $gname,
'devmajor' => $devmaj,
'devminor' => $devmin
);
$ThisFileInfo['tar']['files'] = getid3_lib::array_merge_clobber($ThisFileInfo['tar']['files'], getid3_lib::CreateDeepArray($ThisFileInfo['tar']['file_details'][$name]['name'], '/', $size));
}
return true;
}
// Parses the file mode to file permissions
function display_perms($mode) {
// Determine Type
if ($mode & 0x1000) $type='p'; // FIFO pipe
elseif ($mode & 0x2000) $type='c'; // Character special
elseif ($mode & 0x4000) $type='d'; // Directory
elseif ($mode & 0x6000) $type='b'; // Block special
elseif ($mode & 0x8000) $type='-'; // Regular
elseif ($mode & 0xA000) $type='l'; // Symbolic Link
elseif ($mode & 0xC000) $type='s'; // Socket
else $type='u'; // UNKNOWN
// Determine permissions
$owner['read'] = (($mode & 00400) ? 'r' : '-');
$owner['write'] = (($mode & 00200) ? 'w' : '-');
$owner['execute'] = (($mode & 00100) ? 'x' : '-');
$group['read'] = (($mode & 00040) ? 'r' : '-');
$group['write'] = (($mode & 00020) ? 'w' : '-');
$group['execute'] = (($mode & 00010) ? 'x' : '-');
$world['read'] = (($mode & 00004) ? 'r' : '-');
$world['write'] = (($mode & 00002) ? 'w' : '-');
$world['execute'] = (($mode & 00001) ? 'x' : '-');
// Adjust for SUID, SGID and sticky bit
if ($mode & 0x800) $owner['execute'] = ($owner['execute'] == 'x') ? 's' : 'S';
if ($mode & 0x400) $group['execute'] = ($group['execute'] == 'x') ? 's' : 'S';
if ($mode & 0x200) $world['execute'] = ($world['execute'] == 'x') ? 't' : 'T';
$s = sprintf('%1s', $type);
$s .= sprintf('%1s%1s%1s', $owner['read'], $owner['write'], $owner['execute']);
$s .= sprintf('%1s%1s%1s', $group['read'], $group['write'], $group['execute']);
$s .= sprintf('%1s%1s%1s'."\n", $world['read'], $world['write'], $world['execute']);
return $s;
}
// Converts the file type
function get_flag_type($typflag) {
static $flag_types = array(
'0' => 'LF_NORMAL',
'1' => 'LF_LINK',
'2' => 'LF_SYNLINK',
'3' => 'LF_CHR',
'4' => 'LF_BLK',
'5' => 'LF_DIR',
'6' => 'LF_FIFO',
'7' => 'LF_CONFIG',
'D' => 'LF_DUMPDIR',
'K' => 'LF_LONGLINK',
'L' => 'LF_LONGNAME',
'M' => 'LF_MULTIVOL',
'N' => 'LF_NAMES',
'S' => 'LF_SPARSE',
'V' => 'LF_VOLHDR'
);
return @$flag_types[$typflag];
}
}
?>

View File

@ -1,416 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.archive.zip.php //
// module for analyzing pkZip files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_zip
{
function getid3_zip(&$fd, &$ThisFileInfo) {
$ThisFileInfo['fileformat'] = 'zip';
$ThisFileInfo['zip']['encoding'] = 'ISO-8859-1';
$ThisFileInfo['zip']['files'] = array();
$ThisFileInfo['zip']['compressed_size'] = 0;
$ThisFileInfo['zip']['uncompressed_size'] = 0;
$ThisFileInfo['zip']['entries_count'] = 0;
if ($ThisFileInfo['filesize'] < pow(2, 31)) {
$EOCDsearchData = '';
$EOCDsearchCounter = 0;
while ($EOCDsearchCounter++ < 512) {
fseek($fd, -128 * $EOCDsearchCounter, SEEK_END);
$EOCDsearchData = fread($fd, 128).$EOCDsearchData;
if (strstr($EOCDsearchData, 'PK'."\x05\x06")) {
$EOCDposition = strpos($EOCDsearchData, 'PK'."\x05\x06");
fseek($fd, (-128 * $EOCDsearchCounter) + $EOCDposition, SEEK_END);
$ThisFileInfo['zip']['end_central_directory'] = $this->ZIPparseEndOfCentralDirectory($fd);
fseek($fd, $ThisFileInfo['zip']['end_central_directory']['directory_offset'], SEEK_SET);
$ThisFileInfo['zip']['entries_count'] = 0;
while ($centraldirectoryentry = $this->ZIPparseCentralDirectory($fd)) {
$ThisFileInfo['zip']['central_directory'][] = $centraldirectoryentry;
$ThisFileInfo['zip']['entries_count']++;
$ThisFileInfo['zip']['compressed_size'] += $centraldirectoryentry['compressed_size'];
$ThisFileInfo['zip']['uncompressed_size'] += $centraldirectoryentry['uncompressed_size'];
if ($centraldirectoryentry['uncompressed_size'] > 0) {
$ThisFileInfo['zip']['files'] = getid3_lib::array_merge_clobber($ThisFileInfo['zip']['files'], getid3_lib::CreateDeepArray($centraldirectoryentry['filename'], '/', $centraldirectoryentry['uncompressed_size']));
}
}
if ($ThisFileInfo['zip']['entries_count'] == 0) {
$ThisFileInfo['error'][] = 'No Central Directory entries found (truncated file?)';
return false;
}
if (!empty($ThisFileInfo['zip']['end_central_directory']['comment'])) {
$ThisFileInfo['zip']['comments']['comment'][] = $ThisFileInfo['zip']['end_central_directory']['comment'];
}
if (isset($ThisFileInfo['zip']['central_directory'][0]['compression_method'])) {
$ThisFileInfo['zip']['compression_method'] = $ThisFileInfo['zip']['central_directory'][0]['compression_method'];
}
if (isset($ThisFileInfo['zip']['central_directory'][0]['flags']['compression_speed'])) {
$ThisFileInfo['zip']['compression_speed'] = $ThisFileInfo['zip']['central_directory'][0]['flags']['compression_speed'];
}
if (isset($ThisFileInfo['zip']['compression_method']) && ($ThisFileInfo['zip']['compression_method'] == 'store') && !isset($ThisFileInfo['zip']['compression_speed'])) {
$ThisFileInfo['zip']['compression_speed'] = 'store';
}
return true;
}
}
}
if ($this->getZIPentriesFilepointer($fd, $ThisFileInfo)) {
// central directory couldn't be found and/or parsed
// scan through actual file data entries, recover as much as possible from probable trucated file
if ($ThisFileInfo['zip']['compressed_size'] > ($ThisFileInfo['filesize'] - 46 - 22)) {
$ThisFileInfo['error'][] = 'Warning: Truncated file! - Total compressed file sizes ('.$ThisFileInfo['zip']['compressed_size'].' bytes) is greater than filesize minus Central Directory and End Of Central Directory structures ('.($ThisFileInfo['filesize'] - 46 - 22).' bytes)';
}
$ThisFileInfo['error'][] = 'Cannot find End Of Central Directory - returned list of files in [zip][entries] array may not be complete';
foreach ($ThisFileInfo['zip']['entries'] as $key => $valuearray) {
$ThisFileInfo['zip']['files'][$valuearray['filename']] = $valuearray['uncompressed_size'];
}
return true;
} else {
unset($ThisFileInfo['zip']);
$ThisFileInfo['fileformat'] = '';
$ThisFileInfo['error'][] = 'Cannot find End Of Central Directory (truncated file?)';
return false;
}
}
function getZIPHeaderFilepointerTopDown(&$fd, &$ThisFileInfo) {
$ThisFileInfo['fileformat'] = 'zip';
$ThisFileInfo['zip']['compressed_size'] = 0;
$ThisFileInfo['zip']['uncompressed_size'] = 0;
$ThisFileInfo['zip']['entries_count'] = 0;
rewind($fd);
while ($fileentry = $this->ZIPparseLocalFileHeader($fd)) {
$ThisFileInfo['zip']['entries'][] = $fileentry;
$ThisFileInfo['zip']['entries_count']++;
}
if ($ThisFileInfo['zip']['entries_count'] == 0) {
$ThisFileInfo['error'][] = 'No Local File Header entries found';
return false;
}
$ThisFileInfo['zip']['entries_count'] = 0;
while ($centraldirectoryentry = $this->ZIPparseCentralDirectory($fd)) {
$ThisFileInfo['zip']['central_directory'][] = $centraldirectoryentry;
$ThisFileInfo['zip']['entries_count']++;
$ThisFileInfo['zip']['compressed_size'] += $centraldirectoryentry['compressed_size'];
$ThisFileInfo['zip']['uncompressed_size'] += $centraldirectoryentry['uncompressed_size'];
}
if ($ThisFileInfo['zip']['entries_count'] == 0) {
$ThisFileInfo['error'][] = 'No Central Directory entries found (truncated file?)';
return false;
}
if ($EOCD = $this->ZIPparseEndOfCentralDirectory($fd)) {
$ThisFileInfo['zip']['end_central_directory'] = $EOCD;
} else {
$ThisFileInfo['error'][] = 'No End Of Central Directory entry found (truncated file?)';
return false;
}
if (!empty($ThisFileInfo['zip']['end_central_directory']['comment'])) {
$ThisFileInfo['zip']['comments']['comment'][] = $ThisFileInfo['zip']['end_central_directory']['comment'];
}
return true;
}
function getZIPentriesFilepointer(&$fd, &$ThisFileInfo) {
$ThisFileInfo['zip']['compressed_size'] = 0;
$ThisFileInfo['zip']['uncompressed_size'] = 0;
$ThisFileInfo['zip']['entries_count'] = 0;
rewind($fd);
while ($fileentry = $this->ZIPparseLocalFileHeader($fd)) {
$ThisFileInfo['zip']['entries'][] = $fileentry;
$ThisFileInfo['zip']['entries_count']++;
$ThisFileInfo['zip']['compressed_size'] += $fileentry['compressed_size'];
$ThisFileInfo['zip']['uncompressed_size'] += $fileentry['uncompressed_size'];
}
if ($ThisFileInfo['zip']['entries_count'] == 0) {
$ThisFileInfo['error'][] = 'No Local File Header entries found';
return false;
}
return true;
}
function ZIPparseLocalFileHeader(&$fd) {
$LocalFileHeader['offset'] = ftell($fd);
$ZIPlocalFileHeader = fread($fd, 30);
$LocalFileHeader['raw']['signature'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 0, 4));
if ($LocalFileHeader['raw']['signature'] != 0x04034B50) {
// invalid Local File Header Signature
fseek($fd, $LocalFileHeader['offset'], SEEK_SET); // seek back to where filepointer originally was so it can be handled properly
return false;
}
$LocalFileHeader['raw']['extract_version'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 4, 2));
$LocalFileHeader['raw']['general_flags'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 6, 2));
$LocalFileHeader['raw']['compression_method'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 8, 2));
$LocalFileHeader['raw']['last_mod_file_time'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 10, 2));
$LocalFileHeader['raw']['last_mod_file_date'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 12, 2));
$LocalFileHeader['raw']['crc_32'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 14, 4));
$LocalFileHeader['raw']['compressed_size'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 18, 4));
$LocalFileHeader['raw']['uncompressed_size'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 22, 4));
$LocalFileHeader['raw']['filename_length'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 26, 2));
$LocalFileHeader['raw']['extra_field_length'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 28, 2));
$LocalFileHeader['extract_version'] = sprintf('%1.1f', $LocalFileHeader['raw']['extract_version'] / 10);
$LocalFileHeader['host_os'] = $this->ZIPversionOSLookup(($LocalFileHeader['raw']['extract_version'] & 0xFF00) >> 8);
$LocalFileHeader['compression_method'] = $this->ZIPcompressionMethodLookup($LocalFileHeader['raw']['compression_method']);
$LocalFileHeader['compressed_size'] = $LocalFileHeader['raw']['compressed_size'];
$LocalFileHeader['uncompressed_size'] = $LocalFileHeader['raw']['uncompressed_size'];
$LocalFileHeader['flags'] = $this->ZIPparseGeneralPurposeFlags($LocalFileHeader['raw']['general_flags'], $LocalFileHeader['raw']['compression_method']);
$LocalFileHeader['last_modified_timestamp'] = $this->DOStime2UNIXtime($LocalFileHeader['raw']['last_mod_file_date'], $LocalFileHeader['raw']['last_mod_file_time']);
$FilenameExtrafieldLength = $LocalFileHeader['raw']['filename_length'] + $LocalFileHeader['raw']['extra_field_length'];
if ($FilenameExtrafieldLength > 0) {
$ZIPlocalFileHeader .= fread($fd, $FilenameExtrafieldLength);
if ($LocalFileHeader['raw']['filename_length'] > 0) {
$LocalFileHeader['filename'] = substr($ZIPlocalFileHeader, 30, $LocalFileHeader['raw']['filename_length']);
}
if ($LocalFileHeader['raw']['extra_field_length'] > 0) {
$LocalFileHeader['raw']['extra_field_data'] = substr($ZIPlocalFileHeader, 30 + $LocalFileHeader['raw']['filename_length'], $LocalFileHeader['raw']['extra_field_length']);
}
}
$LocalFileHeader['data_offset'] = ftell($fd);
//$LocalFileHeader['compressed_data'] = fread($fd, $LocalFileHeader['raw']['compressed_size']);
fseek($fd, $LocalFileHeader['raw']['compressed_size'], SEEK_CUR);
if ($LocalFileHeader['flags']['data_descriptor_used']) {
$DataDescriptor = fread($fd, 12);
$LocalFileHeader['data_descriptor']['crc_32'] = getid3_lib::LittleEndian2Int(substr($DataDescriptor, 0, 4));
$LocalFileHeader['data_descriptor']['compressed_size'] = getid3_lib::LittleEndian2Int(substr($DataDescriptor, 4, 4));
$LocalFileHeader['data_descriptor']['uncompressed_size'] = getid3_lib::LittleEndian2Int(substr($DataDescriptor, 8, 4));
}
return $LocalFileHeader;
}
function ZIPparseCentralDirectory(&$fd) {
$CentralDirectory['offset'] = ftell($fd);
$ZIPcentralDirectory = fread($fd, 46);
$CentralDirectory['raw']['signature'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 0, 4));
if ($CentralDirectory['raw']['signature'] != 0x02014B50) {
// invalid Central Directory Signature
fseek($fd, $CentralDirectory['offset'], SEEK_SET); // seek back to where filepointer originally was so it can be handled properly
return false;
}
$CentralDirectory['raw']['create_version'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 4, 2));
$CentralDirectory['raw']['extract_version'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 6, 2));
$CentralDirectory['raw']['general_flags'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 8, 2));
$CentralDirectory['raw']['compression_method'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 10, 2));
$CentralDirectory['raw']['last_mod_file_time'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 12, 2));
$CentralDirectory['raw']['last_mod_file_date'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 14, 2));
$CentralDirectory['raw']['crc_32'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 16, 4));
$CentralDirectory['raw']['compressed_size'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 20, 4));
$CentralDirectory['raw']['uncompressed_size'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 24, 4));
$CentralDirectory['raw']['filename_length'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 28, 2));
$CentralDirectory['raw']['extra_field_length'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 30, 2));
$CentralDirectory['raw']['file_comment_length'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 32, 2));
$CentralDirectory['raw']['disk_number_start'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 34, 2));
$CentralDirectory['raw']['internal_file_attrib'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 36, 2));
$CentralDirectory['raw']['external_file_attrib'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 38, 4));
$CentralDirectory['raw']['local_header_offset'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 42, 4));
$CentralDirectory['entry_offset'] = $CentralDirectory['raw']['local_header_offset'];
$CentralDirectory['create_version'] = sprintf('%1.1f', $CentralDirectory['raw']['create_version'] / 10);
$CentralDirectory['extract_version'] = sprintf('%1.1f', $CentralDirectory['raw']['extract_version'] / 10);
$CentralDirectory['host_os'] = $this->ZIPversionOSLookup(($CentralDirectory['raw']['extract_version'] & 0xFF00) >> 8);
$CentralDirectory['compression_method'] = $this->ZIPcompressionMethodLookup($CentralDirectory['raw']['compression_method']);
$CentralDirectory['compressed_size'] = $CentralDirectory['raw']['compressed_size'];
$CentralDirectory['uncompressed_size'] = $CentralDirectory['raw']['uncompressed_size'];
$CentralDirectory['flags'] = $this->ZIPparseGeneralPurposeFlags($CentralDirectory['raw']['general_flags'], $CentralDirectory['raw']['compression_method']);
$CentralDirectory['last_modified_timestamp'] = $this->DOStime2UNIXtime($CentralDirectory['raw']['last_mod_file_date'], $CentralDirectory['raw']['last_mod_file_time']);
$FilenameExtrafieldCommentLength = $CentralDirectory['raw']['filename_length'] + $CentralDirectory['raw']['extra_field_length'] + $CentralDirectory['raw']['file_comment_length'];
if ($FilenameExtrafieldCommentLength > 0) {
$FilenameExtrafieldComment = fread($fd, $FilenameExtrafieldCommentLength);
if ($CentralDirectory['raw']['filename_length'] > 0) {
$CentralDirectory['filename'] = substr($FilenameExtrafieldComment, 0, $CentralDirectory['raw']['filename_length']);
}
if ($CentralDirectory['raw']['extra_field_length'] > 0) {
$CentralDirectory['raw']['extra_field_data'] = substr($FilenameExtrafieldComment, $CentralDirectory['raw']['filename_length'], $CentralDirectory['raw']['extra_field_length']);
}
if ($CentralDirectory['raw']['file_comment_length'] > 0) {
$CentralDirectory['file_comment'] = substr($FilenameExtrafieldComment, $CentralDirectory['raw']['filename_length'] + $CentralDirectory['raw']['extra_field_length'], $CentralDirectory['raw']['file_comment_length']);
}
}
return $CentralDirectory;
}
function ZIPparseEndOfCentralDirectory(&$fd) {
$EndOfCentralDirectory['offset'] = ftell($fd);
$ZIPendOfCentralDirectory = fread($fd, 22);
$EndOfCentralDirectory['signature'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 0, 4));
if ($EndOfCentralDirectory['signature'] != 0x06054B50) {
// invalid End Of Central Directory Signature
fseek($fd, $EndOfCentralDirectory['offset'], SEEK_SET); // seek back to where filepointer originally was so it can be handled properly
return false;
}
$EndOfCentralDirectory['disk_number_current'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 4, 2));
$EndOfCentralDirectory['disk_number_start_directory'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 6, 2));
$EndOfCentralDirectory['directory_entries_this_disk'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 8, 2));
$EndOfCentralDirectory['directory_entries_total'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 10, 2));
$EndOfCentralDirectory['directory_size'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 12, 4));
$EndOfCentralDirectory['directory_offset'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 16, 4));
$EndOfCentralDirectory['comment_length'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 20, 2));
if ($EndOfCentralDirectory['comment_length'] > 0) {
$EndOfCentralDirectory['comment'] = fread($fd, $EndOfCentralDirectory['comment_length']);
}
return $EndOfCentralDirectory;
}
function ZIPparseGeneralPurposeFlags($flagbytes, $compressionmethod) {
$ParsedFlags['encrypted'] = (bool) ($flagbytes & 0x0001);
switch ($compressionmethod) {
case 6:
$ParsedFlags['dictionary_size'] = (($flagbytes & 0x0002) ? 8192 : 4096);
$ParsedFlags['shannon_fano_trees'] = (($flagbytes & 0x0004) ? 3 : 2);
break;
case 8:
case 9:
switch (($flagbytes & 0x0006) >> 1) {
case 0:
$ParsedFlags['compression_speed'] = 'normal';
break;
case 1:
$ParsedFlags['compression_speed'] = 'maximum';
break;
case 2:
$ParsedFlags['compression_speed'] = 'fast';
break;
case 3:
$ParsedFlags['compression_speed'] = 'superfast';
break;
}
break;
}
$ParsedFlags['data_descriptor_used'] = (bool) ($flagbytes & 0x0008);
return $ParsedFlags;
}
function ZIPversionOSLookup($index) {
static $ZIPversionOSLookup = array(
0 => 'MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems)',
1 => 'Amiga',
2 => 'OpenVMS',
3 => 'Unix',
4 => 'VM/CMS',
5 => 'Atari ST',
6 => 'OS/2 H.P.F.S.',
7 => 'Macintosh',
8 => 'Z-System',
9 => 'CP/M',
10 => 'Windows NTFS',
11 => 'MVS',
12 => 'VSE',
13 => 'Acorn Risc',
14 => 'VFAT',
15 => 'Alternate MVS',
16 => 'BeOS',
17 => 'Tandem'
);
return (isset($ZIPversionOSLookup[$index]) ? $ZIPversionOSLookup[$index] : '[unknown]');
}
function ZIPcompressionMethodLookup($index) {
static $ZIPcompressionMethodLookup = array(
0 => 'store',
1 => 'shrink',
2 => 'reduce-1',
3 => 'reduce-2',
4 => 'reduce-3',
5 => 'reduce-4',
6 => 'implode',
7 => 'tokenize',
8 => 'deflate',
9 => 'deflate64',
10 => 'PKWARE Date Compression Library Imploding'
);
return (isset($ZIPcompressionMethodLookup[$index]) ? $ZIPcompressionMethodLookup[$index] : '[unknown]');
}
function DOStime2UNIXtime($DOSdate, $DOStime) {
// wFatDate
// Specifies the MS-DOS date. The date is a packed 16-bit value with the following format:
// Bits Contents
// 0-4 Day of the month (1-31)
// 5-8 Month (1 = January, 2 = February, and so on)
// 9-15 Year offset from 1980 (add 1980 to get actual year)
$UNIXday = ($DOSdate & 0x001F);
$UNIXmonth = (($DOSdate & 0x01E0) >> 5);
$UNIXyear = (($DOSdate & 0xFE00) >> 9) + 1980;
// wFatTime
// Specifies the MS-DOS time. The time is a packed 16-bit value with the following format:
// Bits Contents
// 0-4 Second divided by 2
// 5-10 Minute (0-59)
// 11-15 Hour (0-23 on a 24-hour clock)
$UNIXsecond = ($DOStime & 0x001F) * 2;
$UNIXminute = (($DOStime & 0x07E0) >> 5);
$UNIXhour = (($DOStime & 0xF800) >> 11);
return gmmktime($UNIXhour, $UNIXminute, $UNIXsecond, $UNIXmonth, $UNIXday, $UNIXyear);
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@ -1,70 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio.bink.php //
// module for analyzing Bink or Smacker audio-video files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_bink
{
function getid3_bink(&$fd, &$ThisFileInfo) {
$ThisFileInfo['error'][] = 'Bink / Smacker files not properly processed by this version of getID3()';
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$fileTypeID = fread($fd, 3);
switch ($fileTypeID) {
case 'BIK':
return $this->ParseBink($fd, $ThisFileInfo);
break;
case 'SMK':
return $this->ParseSmacker($fd, $ThisFileInfo);
break;
default:
$ThisFileInfo['error'][] = 'Expecting "BIK" or "SMK" at offset '.$ThisFileInfo['avdataoffset'].', found "'.$fileTypeID.'"';
return false;
break;
}
return true;
}
function ParseBink(&$fd, &$ThisFileInfo) {
$ThisFileInfo['fileformat'] = 'bink';
$ThisFileInfo['video']['dataformat'] = 'bink';
$fileData = 'BIK'.fread($fd, 13);
$ThisFileInfo['bink']['data_size'] = getid3_lib::LittleEndian2Int(substr($fileData, 4, 4));
$ThisFileInfo['bink']['frame_count'] = getid3_lib::LittleEndian2Int(substr($fileData, 8, 2));
if (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) != ($ThisFileInfo['bink']['data_size'] + 8)) {
$ThisFileInfo['error'][] = 'Probably truncated file: expecting '.$ThisFileInfo['bink']['data_size'].' bytes, found '.($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']);
}
return true;
}
function ParseSmacker(&$fd, &$ThisFileInfo) {
$ThisFileInfo['fileformat'] = 'smacker';
$ThisFileInfo['video']['dataformat'] = 'smacker';
return false;
}
}
?>

View File

@ -1,505 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
// //
// FLV module by Seth Kaufman <seth@whirl-i-gig.com> //
// //
// * version 0.1 (26 June 2005) //
// //
// minor modifications by James Heinrich <info@getid3.org> //
// * version 0.1.1 (15 July 2005) //
// //
// Support for On2 VP6 codec and meta information //
// by Steve Webster <steve.webster@featurecreep.com> //
// * version 0.2 (22 February 2006) //
// //
// Modified to not read entire file into memory //
// by James Heinrich <info@getid3.org> //
// * version 0.3 (15 June 2006) //
// //
// Bugfixes for incorrectly parsed FLV dimensions //
// and incorrect parsing of onMetaTag //
// by Evgeny Moysevich <moysevich@gmail.com> //
// * version 0.4 (07 December 2007) //
// //
/////////////////////////////////////////////////////////////////
// //
// module.audio-video.flv.php //
// module for analyzing Shockwave Flash Video files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
define('GETID3_FLV_TAG_AUDIO', 8);
define('GETID3_FLV_TAG_VIDEO', 9);
define('GETID3_FLV_TAG_META', 18);
define('GETID3_FLV_VIDEO_H263', 2);
define('GETID3_FLV_VIDEO_SCREEN', 3);
define('GETID3_FLV_VIDEO_VP6', 4);
class getid3_flv
{
function getid3_flv(&$fd, &$ThisFileInfo, $ReturnAllTagData=false) {
//$start_time = microtime(true);
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$FLVdataLength = $ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset'];
$FLVheader = fread($fd, 5);
$ThisFileInfo['fileformat'] = 'flv';
$ThisFileInfo['flv']['header']['signature'] = substr($FLVheader, 0, 3);
$ThisFileInfo['flv']['header']['version'] = getid3_lib::BigEndian2Int(substr($FLVheader, 3, 1));
$TypeFlags = getid3_lib::BigEndian2Int(substr($FLVheader, 4, 1));
if ($ThisFileInfo['flv']['header']['signature'] != 'FLV') {
$ThisFileInfo['error'][] = 'Expecting "FLV" at offset '.$ThisFileInfo['avdataoffset'].', found "'.$ThisFileInfo['flv']['header']['signature'].'"';
unset($ThisFileInfo['flv']);
unset($ThisFileInfo['fileformat']);
return false;
}
$ThisFileInfo['flv']['header']['hasAudio'] = (bool) ($TypeFlags & 0x04);
$ThisFileInfo['flv']['header']['hasVideo'] = (bool) ($TypeFlags & 0x01);
$FrameSizeDataLength = getid3_lib::BigEndian2Int(fread($fd, 4));
$FLVheaderFrameLength = 9;
if ($FrameSizeDataLength > $FLVheaderFrameLength) {
fseek($fd, $FrameSizeDataLength - $FLVheaderFrameLength, SEEK_CUR);
}
//echo __LINE__.'='.number_format(microtime(true) - $start_time, 3).'<br>';
$Duration = 0;
$found_video = false;
$found_audio = false;
$found_meta = false;
while ((ftell($fd) + 16) < $ThisFileInfo['avdataend']) {
$ThisTagHeader = fread($fd, 16);
$PreviousTagLength = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 0, 4));
$TagType = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 4, 1));
$DataLength = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 5, 3));
$Timestamp = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 8, 3));
$LastHeaderByte = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 15, 1));
$NextOffset = ftell($fd) - 1 + $DataLength;
if ($Timestamp > $Duration) {
$Duration = $Timestamp;
}
//echo __LINE__.'['.ftell($fd).']=('.$TagType.')='.number_format(microtime(true) - $start_time, 3).'<br>';
switch ($TagType) {
case GETID3_FLV_TAG_AUDIO:
if (!$found_audio) {
$found_audio = true;
$ThisFileInfo['flv']['audio']['audioFormat'] = $LastHeaderByte & 0x07;
$ThisFileInfo['flv']['audio']['audioRate'] = ($LastHeaderByte & 0x30) / 0x10;
$ThisFileInfo['flv']['audio']['audioSampleSize'] = ($LastHeaderByte & 0x40) / 0x40;
$ThisFileInfo['flv']['audio']['audioType'] = ($LastHeaderByte & 0x80) / 0x80;
}
break;
case GETID3_FLV_TAG_VIDEO:
if (!$found_video) {
$found_video = true;
$ThisFileInfo['flv']['video']['videoCodec'] = $LastHeaderByte & 0x07;
$FLVvideoHeader = fread($fd, 11);
if ($ThisFileInfo['flv']['video']['videoCodec'] != GETID3_FLV_VIDEO_VP6) {
$PictureSizeType = (getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 3, 2))) >> 7;
$PictureSizeType = $PictureSizeType & 0x0007;
$ThisFileInfo['flv']['header']['videoSizeType'] = $PictureSizeType;
switch ($PictureSizeType) {
case 0:
//$PictureSizeEnc = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 5, 2));
//$PictureSizeEnc <<= 1;
//$ThisFileInfo['video']['resolution_x'] = ($PictureSizeEnc & 0xFF00) >> 8;
//$PictureSizeEnc = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 2));
//$PictureSizeEnc <<= 1;
//$ThisFileInfo['video']['resolution_y'] = ($PictureSizeEnc & 0xFF00) >> 8;
$PictureSizeEnc['x'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 4, 2));
$PictureSizeEnc['y'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 5, 2));
$PictureSizeEnc['x'] >>= 7;
$PictureSizeEnc['y'] >>= 7;
$ThisFileInfo['video']['resolution_x'] = $PictureSizeEnc['x'] & 0xFF;
$ThisFileInfo['video']['resolution_y'] = $PictureSizeEnc['y'] & 0xFF;
break;
case 1:
$PictureSizeEnc['x'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 4, 3));
$PictureSizeEnc['y'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 3));
$PictureSizeEnc['x'] >>= 7;
$PictureSizeEnc['y'] >>= 7;
$ThisFileInfo['video']['resolution_x'] = $PictureSizeEnc['x'] & 0xFFFF;
$ThisFileInfo['video']['resolution_y'] = $PictureSizeEnc['y'] & 0xFFFF;
break;
case 2:
$ThisFileInfo['video']['resolution_x'] = 352;
$ThisFileInfo['video']['resolution_y'] = 288;
break;
case 3:
$ThisFileInfo['video']['resolution_x'] = 176;
$ThisFileInfo['video']['resolution_y'] = 144;
break;
case 4:
$ThisFileInfo['video']['resolution_x'] = 128;
$ThisFileInfo['video']['resolution_y'] = 96;
break;
case 5:
$ThisFileInfo['video']['resolution_x'] = 320;
$ThisFileInfo['video']['resolution_y'] = 240;
break;
case 6:
$ThisFileInfo['video']['resolution_x'] = 160;
$ThisFileInfo['video']['resolution_y'] = 120;
break;
default:
$ThisFileInfo['video']['resolution_x'] = 0;
$ThisFileInfo['video']['resolution_y'] = 0;
break;
}
}
}
break;
// Meta tag
case GETID3_FLV_TAG_META:
if (!$found_meta) {
$found_meta = true;
fseek($fd, -1, SEEK_CUR);
$reader = new AMFReader(new AMFStream(fread($fd, $DataLength)));
$eventName = $reader->readData();
$ThisFileInfo['meta'][$eventName] = $reader->readData();
unset($reader);
$ThisFileInfo['video']['frame_rate'] = @$ThisFileInfo['meta']['onMetaData']['framerate'];
$ThisFileInfo['video']['resolution_x'] = @$ThisFileInfo['meta']['onMetaData']['width'];
$ThisFileInfo['video']['resolution_y'] = @$ThisFileInfo['meta']['onMetaData']['height'];
}
break;
default:
// noop
break;
}
fseek($fd, $NextOffset, SEEK_SET);
}
if ($ThisFileInfo['playtime_seconds'] = $Duration / 1000) {
$ThisFileInfo['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / $ThisFileInfo['playtime_seconds'];
}
if ($ThisFileInfo['flv']['header']['hasAudio']) {
$ThisFileInfo['audio']['codec'] = $this->FLVaudioFormat($ThisFileInfo['flv']['audio']['audioFormat']);
$ThisFileInfo['audio']['sample_rate'] = $this->FLVaudioRate($ThisFileInfo['flv']['audio']['audioRate']);
$ThisFileInfo['audio']['bits_per_sample'] = $this->FLVaudioBitDepth($ThisFileInfo['flv']['audio']['audioSampleSize']);
$ThisFileInfo['audio']['channels'] = $ThisFileInfo['flv']['audio']['audioType'] + 1; // 0=mono,1=stereo
$ThisFileInfo['audio']['lossless'] = ($ThisFileInfo['flv']['audio']['audioFormat'] ? false : true); // 0=uncompressed
$ThisFileInfo['audio']['dataformat'] = 'flv';
}
if (@$ThisFileInfo['flv']['header']['hasVideo']) {
$ThisFileInfo['video']['codec'] = $this->FLVvideoCodec($ThisFileInfo['flv']['video']['videoCodec']);
$ThisFileInfo['video']['dataformat'] = 'flv';
$ThisFileInfo['video']['lossless'] = false;
}
return true;
}
function FLVaudioFormat($id) {
$FLVaudioFormat = array(
0 => 'uncompressed',
1 => 'ADPCM',
2 => 'mp3',
5 => 'Nellymoser 8kHz mono',
6 => 'Nellymoser',
);
return (@$FLVaudioFormat[$id] ? @$FLVaudioFormat[$id] : false);
}
function FLVaudioRate($id) {
$FLVaudioRate = array(
0 => 5500,
1 => 11025,
2 => 22050,
3 => 44100,
);
return (@$FLVaudioRate[$id] ? @$FLVaudioRate[$id] : false);
}
function FLVaudioBitDepth($id) {
$FLVaudioBitDepth = array(
0 => 8,
1 => 16,
);
return (@$FLVaudioBitDepth[$id] ? @$FLVaudioBitDepth[$id] : false);
}
function FLVvideoCodec($id) {
$FLVvideoCodec = array(
GETID3_FLV_VIDEO_H263 => 'Sorenson H.263',
GETID3_FLV_VIDEO_SCREEN => 'Screen video',
GETID3_FLV_VIDEO_VP6 => 'On2 VP6',
);
return (@$FLVvideoCodec[$id] ? @$FLVvideoCodec[$id] : false);
}
}
class AMFStream {
var $bytes;
var $pos;
function AMFStream(&$bytes) {
$this->bytes =& $bytes;
$this->pos = 0;
}
function readByte() {
return getid3_lib::BigEndian2Int(substr($this->bytes, $this->pos++, 1));
}
function readInt() {
return ($this->readByte() << 8) + $this->readByte();
}
function readLong() {
return ($this->readByte() << 24) + ($this->readByte() << 16) + ($this->readByte() << 8) + $this->readByte();
}
function readDouble() {
return getid3_lib::BigEndian2Float($this->read(8));
}
function readUTF() {
$length = $this->readInt();
return $this->read($length);
}
function readLongUTF() {
$length = $this->readLong();
return $this->read($length);
}
function read($length) {
$val = substr($this->bytes, $this->pos, $length);
$this->pos += $length;
return $val;
}
function peekByte() {
$pos = $this->pos;
$val = $this->readByte();
$this->pos = $pos;
return $val;
}
function peekInt() {
$pos = $this->pos;
$val = $this->readInt();
$this->pos = $pos;
return $val;
}
function peekLong() {
$pos = $this->pos;
$val = $this->readLong();
$this->pos = $pos;
return $val;
}
function peekDouble() {
$pos = $this->pos;
$val = $this->readDouble();
$this->pos = $pos;
return $val;
}
function peekUTF() {
$pos = $this->pos;
$val = $this->readUTF();
$this->pos = $pos;
return $val;
}
function peekLongUTF() {
$pos = $this->pos;
$val = $this->readLongUTF();
$this->pos = $pos;
return $val;
}
}
class AMFReader {
var $stream;
function AMFReader(&$stream) {
$this->stream =& $stream;
}
function readData() {
$value = null;
$type = $this->stream->readByte();
switch ($type) {
// Double
case 0:
$value = $this->readDouble();
break;
// Boolean
case 1:
$value = $this->readBoolean();
break;
// String
case 2:
$value = $this->readString();
break;
// Object
case 3:
$value = $this->readObject();
break;
// null
case 6:
return null;
break;
// Mixed array
case 8:
$value = $this->readMixedArray();
break;
// Array
case 10:
$value = $this->readArray();
break;
// Date
case 11:
$value = $this->readDate();
break;
// Long string
case 13:
$value = $this->readLongString();
break;
// XML (handled as string)
case 15:
$value = $this->readXML();
break;
// Typed object (handled as object)
case 16:
$value = $this->readTypedObject();
break;
// Long string
default:
$value = '(unknown or unsupported data type)';
break;
}
return $value;
}
function readDouble() {
return $this->stream->readDouble();
}
function readBoolean() {
return $this->stream->readByte() == 1;
}
function readString() {
return $this->stream->readUTF();
}
function readObject() {
// Get highest numerical index - ignored
// $highestIndex = $this->stream->readLong();
$data = array();
while ($key = $this->stream->readUTF()) {
$data[$key] = $this->readData();
}
// Mixed array record ends with empty string (0x00 0x00) and 0x09
if (($key == '') && ($this->stream->peekByte() == 0x09)) {
// Consume byte
$this->stream->readByte();
}
return $data;
}
function readMixedArray() {
// Get highest numerical index - ignored
$highestIndex = $this->stream->readLong();
$data = array();
while ($key = $this->stream->readUTF()) {
if (is_numeric($key)) {
$key = (float) $key;
}
$data[$key] = $this->readData();
}
// Mixed array record ends with empty string (0x00 0x00) and 0x09
if (($key == '') && ($this->stream->peekByte() == 0x09)) {
// Consume byte
$this->stream->readByte();
}
return $data;
}
function readArray() {
$length = $this->stream->readLong();
$data = array();
for ($i = 0; $i < $length; $i++) {
$data[] = $this->readData();
}
return $data;
}
function readDate() {
$timestamp = $this->stream->readDouble();
$timezone = $this->stream->readInt();
return $timestamp;
}
function readLongString() {
return $this->stream->readLongUTF();
}
function readXML() {
return $this->stream->readLongUTF();
}
function readTypedObject() {
$className = $this->stream->readUTF();
return $this->readObject();
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@ -1,292 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio-video.mpeg.php //
// module for analyzing MPEG files //
// dependencies: module.audio.mp3.php //
// ///
/////////////////////////////////////////////////////////////////
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true);
define('GETID3_MPEG_VIDEO_PICTURE_START', "\x00\x00\x01\x00");
define('GETID3_MPEG_VIDEO_USER_DATA_START', "\x00\x00\x01\xB2");
define('GETID3_MPEG_VIDEO_SEQUENCE_HEADER', "\x00\x00\x01\xB3");
define('GETID3_MPEG_VIDEO_SEQUENCE_ERROR', "\x00\x00\x01\xB4");
define('GETID3_MPEG_VIDEO_EXTENSION_START', "\x00\x00\x01\xB5");
define('GETID3_MPEG_VIDEO_SEQUENCE_END', "\x00\x00\x01\xB7");
define('GETID3_MPEG_VIDEO_GROUP_START', "\x00\x00\x01\xB8");
define('GETID3_MPEG_AUDIO_START', "\x00\x00\x01\xC0");
class getid3_mpeg
{
function getid3_mpeg(&$fd, &$ThisFileInfo) {
if ($ThisFileInfo['avdataend'] <= $ThisFileInfo['avdataoffset']) {
$ThisFileInfo['error'][] = '"avdataend" ('.$ThisFileInfo['avdataend'].') is unexpectedly less-than-or-equal-to "avdataoffset" ('.$ThisFileInfo['avdataoffset'].')';
return false;
}
$ThisFileInfo['fileformat'] = 'mpeg';
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$MPEGstreamData = fread($fd, min(100000, $ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']));
$MPEGstreamDataLength = strlen($MPEGstreamData);
$foundVideo = true;
$VideoChunkOffset = 0;
while (substr($MPEGstreamData, $VideoChunkOffset++, 4) !== GETID3_MPEG_VIDEO_SEQUENCE_HEADER) {
if ($VideoChunkOffset >= $MPEGstreamDataLength) {
$foundVideo = false;
break;
}
}
if ($foundVideo) {
// Start code 32 bits
// horizontal frame size 12 bits
// vertical frame size 12 bits
// pixel aspect ratio 4 bits
// frame rate 4 bits
// bitrate 18 bits
// marker bit 1 bit
// VBV buffer size 10 bits
// constrained parameter flag 1 bit
// intra quant. matrix flag 1 bit
// intra quant. matrix values 512 bits (present if matrix flag == 1)
// non-intra quant. matrix flag 1 bit
// non-intra quant. matrix values 512 bits (present if matrix flag == 1)
$ThisFileInfo['video']['dataformat'] = 'mpeg';
$VideoChunkOffset += (strlen(GETID3_MPEG_VIDEO_SEQUENCE_HEADER) - 1);
$FrameSizeDWORD = getid3_lib::BigEndian2Int(substr($MPEGstreamData, $VideoChunkOffset, 3));
$VideoChunkOffset += 3;
$AspectRatioFrameRateDWORD = getid3_lib::BigEndian2Int(substr($MPEGstreamData, $VideoChunkOffset, 1));
$VideoChunkOffset += 1;
$assortedinformation = getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $VideoChunkOffset, 4));
$VideoChunkOffset += 4;
$ThisFileInfo['mpeg']['video']['raw']['framesize_horizontal'] = ($FrameSizeDWORD & 0xFFF000) >> 12; // 12 bits for horizontal frame size
$ThisFileInfo['mpeg']['video']['raw']['framesize_vertical'] = ($FrameSizeDWORD & 0x000FFF); // 12 bits for vertical frame size
$ThisFileInfo['mpeg']['video']['raw']['pixel_aspect_ratio'] = ($AspectRatioFrameRateDWORD & 0xF0) >> 4;
$ThisFileInfo['mpeg']['video']['raw']['frame_rate'] = ($AspectRatioFrameRateDWORD & 0x0F);
$ThisFileInfo['mpeg']['video']['framesize_horizontal'] = $ThisFileInfo['mpeg']['video']['raw']['framesize_horizontal'];
$ThisFileInfo['mpeg']['video']['framesize_vertical'] = $ThisFileInfo['mpeg']['video']['raw']['framesize_vertical'];
$ThisFileInfo['mpeg']['video']['pixel_aspect_ratio'] = $this->MPEGvideoAspectRatioLookup($ThisFileInfo['mpeg']['video']['raw']['pixel_aspect_ratio']);
$ThisFileInfo['mpeg']['video']['pixel_aspect_ratio_text'] = $this->MPEGvideoAspectRatioTextLookup($ThisFileInfo['mpeg']['video']['raw']['pixel_aspect_ratio']);
$ThisFileInfo['mpeg']['video']['frame_rate'] = $this->MPEGvideoFramerateLookup($ThisFileInfo['mpeg']['video']['raw']['frame_rate']);
$ThisFileInfo['mpeg']['video']['raw']['bitrate'] = getid3_lib::Bin2Dec(substr($assortedinformation, 0, 18));
$ThisFileInfo['mpeg']['video']['raw']['marker_bit'] = (bool) getid3_lib::Bin2Dec(substr($assortedinformation, 18, 1));
$ThisFileInfo['mpeg']['video']['raw']['vbv_buffer_size'] = getid3_lib::Bin2Dec(substr($assortedinformation, 19, 10));
$ThisFileInfo['mpeg']['video']['raw']['constrained_param_flag'] = (bool) getid3_lib::Bin2Dec(substr($assortedinformation, 29, 1));
$ThisFileInfo['mpeg']['video']['raw']['intra_quant_flag'] = (bool) getid3_lib::Bin2Dec(substr($assortedinformation, 30, 1));
if ($ThisFileInfo['mpeg']['video']['raw']['intra_quant_flag']) {
// read 512 bits
$ThisFileInfo['mpeg']['video']['raw']['intra_quant'] = getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $VideoChunkOffset, 64));
$VideoChunkOffset += 64;
$ThisFileInfo['mpeg']['video']['raw']['non_intra_quant_flag'] = (bool) getid3_lib::Bin2Dec(substr($ThisFileInfo['mpeg']['video']['raw']['intra_quant'], 511, 1));
$ThisFileInfo['mpeg']['video']['raw']['intra_quant'] = getid3_lib::Bin2Dec(substr($assortedinformation, 31, 1)).substr(getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $VideoChunkOffset, 64)), 0, 511);
if ($ThisFileInfo['mpeg']['video']['raw']['non_intra_quant_flag']) {
$ThisFileInfo['mpeg']['video']['raw']['non_intra_quant'] = substr($MPEGstreamData, $VideoChunkOffset, 64);
$VideoChunkOffset += 64;
}
} else {
$ThisFileInfo['mpeg']['video']['raw']['non_intra_quant_flag'] = (bool) getid3_lib::Bin2Dec(substr($assortedinformation, 31, 1));
if ($ThisFileInfo['mpeg']['video']['raw']['non_intra_quant_flag']) {
$ThisFileInfo['mpeg']['video']['raw']['non_intra_quant'] = substr($MPEGstreamData, $VideoChunkOffset, 64);
$VideoChunkOffset += 64;
}
}
if ($ThisFileInfo['mpeg']['video']['raw']['bitrate'] == 0x3FFFF) { // 18 set bits
$ThisFileInfo['warning'][] = 'This version of getID3() ['.GETID3_VERSION.'] cannot determine average bitrate of VBR MPEG video files';
$ThisFileInfo['mpeg']['video']['bitrate_mode'] = 'vbr';
} else {
$ThisFileInfo['mpeg']['video']['bitrate'] = $ThisFileInfo['mpeg']['video']['raw']['bitrate'] * 400;
$ThisFileInfo['mpeg']['video']['bitrate_mode'] = 'cbr';
$ThisFileInfo['video']['bitrate'] = $ThisFileInfo['mpeg']['video']['bitrate'];
}
$ThisFileInfo['video']['resolution_x'] = $ThisFileInfo['mpeg']['video']['framesize_horizontal'];
$ThisFileInfo['video']['resolution_y'] = $ThisFileInfo['mpeg']['video']['framesize_vertical'];
$ThisFileInfo['video']['frame_rate'] = $ThisFileInfo['mpeg']['video']['frame_rate'];
$ThisFileInfo['video']['bitrate_mode'] = $ThisFileInfo['mpeg']['video']['bitrate_mode'];
$ThisFileInfo['video']['pixel_aspect_ratio'] = $ThisFileInfo['mpeg']['video']['pixel_aspect_ratio'];
$ThisFileInfo['video']['lossless'] = false;
$ThisFileInfo['video']['bits_per_sample'] = 24;
} else {
$ThisFileInfo['error'][] = 'Could not find start of video block in the first 100,000 bytes (or before end of file) - this might not be an MPEG-video file?';
}
//0x000001B3 begins the sequence_header of every MPEG video stream.
//But in MPEG-2, this header must immediately be followed by an
//extension_start_code (0x000001B5) with a sequence_extension ID (1).
//(This extension contains all the additional MPEG-2 stuff.)
//MPEG-1 doesn't have this extension, so that's a sure way to tell the
//difference between MPEG-1 and MPEG-2 video streams.
if (substr($MPEGstreamData, $VideoChunkOffset, 4) == GETID3_MPEG_VIDEO_EXTENSION_START) {
$ThisFileInfo['video']['codec'] = 'MPEG-2';
} else {
$ThisFileInfo['video']['codec'] = 'MPEG-1';
}
$AudioChunkOffset = 0;
while (true) {
while (substr($MPEGstreamData, $AudioChunkOffset++, 4) !== GETID3_MPEG_AUDIO_START) {
if ($AudioChunkOffset >= $MPEGstreamDataLength) {
break 2;
}
}
for ($i = 0; $i <= 7; $i++) {
// some files have the MPEG-audio header 8 bytes after the end of the $00 $00 $01 $C0 signature, some have it up to 13 bytes (or more?) after
// I have no idea why or what the difference is, so this is a stupid hack.
// If anybody has any better idea of what's going on, please let me know - info@getid3.org
$dummy = $ThisFileInfo;
if (getid3_mp3::decodeMPEGaudioHeader($fd, ($AudioChunkOffset + 3) + 8 + $i, $dummy, false)) {
$ThisFileInfo = $dummy;
$ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
$ThisFileInfo['audio']['lossless'] = false;
break 2;
}
}
}
// Temporary hack to account for interleaving overhead:
if (!empty($ThisFileInfo['video']['bitrate']) && !empty($ThisFileInfo['audio']['bitrate'])) {
$ThisFileInfo['playtime_seconds'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / ($ThisFileInfo['video']['bitrate'] + $ThisFileInfo['audio']['bitrate']);
// Interleaved MPEG audio/video files have a certain amount of overhead that varies
// by both video and audio bitrates, and not in any sensible, linear/logarithmic patter
// Use interpolated lookup tables to approximately guess how much is overhead, because
// playtime is calculated as filesize / total-bitrate
$ThisFileInfo['playtime_seconds'] *= $this->MPEGsystemNonOverheadPercentage($ThisFileInfo['video']['bitrate'], $ThisFileInfo['audio']['bitrate']);
//switch ($ThisFileInfo['video']['bitrate']) {
// case('5000000'):
// $multiplier = 0.93292642112380355828048824319889;
// break;
// case('5500000'):
// $multiplier = 0.93582895375200989965359777343219;
// break;
// case('6000000'):
// $multiplier = 0.93796247714820932532911373859139;
// break;
// case('7000000'):
// $multiplier = 0.9413264083635103463010117778776;
// break;
// default:
// $multiplier = 1;
// break;
//}
//$ThisFileInfo['playtime_seconds'] *= $multiplier;
//$ThisFileInfo['warning'][] = 'Interleaved MPEG audio/video playtime may be inaccurate. With current hack should be within a few seconds of accurate. Report to info@getid3.org if off by more than 10 seconds.';
if ($ThisFileInfo['video']['bitrate'] < 50000) {
$ThisFileInfo['warning'][] = 'Interleaved MPEG audio/video playtime may be slightly inaccurate for video bitrates below 100kbps. Except in extreme low-bitrate situations, error should be less than 1%. Report to info@getid3.org if greater than this.';
}
}
return true;
}
function MPEGsystemNonOverheadPercentage($VideoBitrate, $AudioBitrate) {
$OverheadPercentage = 0;
$AudioBitrate = max(min($AudioBitrate / 1000, 384), 32); // limit to range of 32kbps - 384kbps (should be only legal bitrates, but maybe VBR?)
$VideoBitrate = max(min($VideoBitrate / 1000, 10000), 10); // limit to range of 10kbps - 10Mbps (beyond that curves flatten anyways, no big loss)
//OMBB[audiobitrate] = array(video-10kbps, video-100kbps, video-1000kbps, video-10000kbps)
$OverheadMultiplierByBitrate[32] = array(0, 0.9676287944368530, 0.9802276264360310, 0.9844916183244460, 0.9852821845179940);
$OverheadMultiplierByBitrate[48] = array(0, 0.9779100089209830, 0.9787770035359320, 0.9846738664076130, 0.9852683013799960);
$OverheadMultiplierByBitrate[56] = array(0, 0.9731249855367600, 0.9776624308938040, 0.9832606361852130, 0.9843922606633340);
$OverheadMultiplierByBitrate[64] = array(0, 0.9755642683275760, 0.9795256705493390, 0.9836573009193170, 0.9851122539404470);
$OverheadMultiplierByBitrate[96] = array(0, 0.9788025247497290, 0.9798553314148700, 0.9822956869792560, 0.9834815119124690);
$OverheadMultiplierByBitrate[128] = array(0, 0.9816940050925480, 0.9821675936072120, 0.9829756927470870, 0.9839763420152050);
$OverheadMultiplierByBitrate[160] = array(0, 0.9825894094561180, 0.9820913399073960, 0.9823907143253970, 0.9832821783651570);
$OverheadMultiplierByBitrate[192] = array(0, 0.9832038474336260, 0.9825731694317960, 0.9821028622712400, 0.9828262076447620);
$OverheadMultiplierByBitrate[224] = array(0, 0.9836516298538770, 0.9824718601823890, 0.9818302180625380, 0.9823735101626480);
$OverheadMultiplierByBitrate[256] = array(0, 0.9845863022094920, 0.9837229411967540, 0.9824521662210830, 0.9828645172100790);
$OverheadMultiplierByBitrate[320] = array(0, 0.9849565280263180, 0.9837683142805110, 0.9822885275960400, 0.9824424382727190);
$OverheadMultiplierByBitrate[384] = array(0, 0.9856094774357600, 0.9844573394432720, 0.9825970399837330, 0.9824673808303890);
$BitrateToUseMin = 32;
$BitrateToUseMax = 32;
$previousBitrate = 32;
foreach ($OverheadMultiplierByBitrate as $key => $value) {
if ($AudioBitrate >= $previousBitrate) {
$BitrateToUseMin = $previousBitrate;
}
if ($AudioBitrate < $key) {
$BitrateToUseMax = $key;
break;
}
$previousBitrate = $key;
}
$FactorA = ($BitrateToUseMax - $AudioBitrate) / ($BitrateToUseMax - $BitrateToUseMin);
$VideoBitrateLog10 = log10($VideoBitrate);
$VideoFactorMin1 = $OverheadMultiplierByBitrate[$BitrateToUseMin][floor($VideoBitrateLog10)];
$VideoFactorMin2 = $OverheadMultiplierByBitrate[$BitrateToUseMax][floor($VideoBitrateLog10)];
$VideoFactorMax1 = $OverheadMultiplierByBitrate[$BitrateToUseMin][ceil($VideoBitrateLog10)];
$VideoFactorMax2 = $OverheadMultiplierByBitrate[$BitrateToUseMax][ceil($VideoBitrateLog10)];
$FactorV = $VideoBitrateLog10 - floor($VideoBitrateLog10);
$OverheadPercentage = $VideoFactorMin1 * $FactorA * $FactorV;
$OverheadPercentage += $VideoFactorMin2 * (1 - $FactorA) * $FactorV;
$OverheadPercentage += $VideoFactorMax1 * $FactorA * (1 - $FactorV);
$OverheadPercentage += $VideoFactorMax2 * (1 - $FactorA) * (1 - $FactorV);
return $OverheadPercentage;
}
function MPEGvideoFramerateLookup($rawframerate) {
$MPEGvideoFramerateLookup = array(0, 23.976, 24, 25, 29.97, 30, 50, 59.94, 60);
return (isset($MPEGvideoFramerateLookup[$rawframerate]) ? (float) $MPEGvideoFramerateLookup[$rawframerate] : (float) 0);
}
function MPEGvideoAspectRatioLookup($rawaspectratio) {
$MPEGvideoAspectRatioLookup = array(0, 1, 0.6735, 0.7031, 0.7615, 0.8055, 0.8437, 0.8935, 0.9157, 0.9815, 1.0255, 1.0695, 1.0950, 1.1575, 1.2015, 0);
return (isset($MPEGvideoAspectRatioLookup[$rawaspectratio]) ? (float) $MPEGvideoAspectRatioLookup[$rawaspectratio] : (float) 0);
}
function MPEGvideoAspectRatioTextLookup($rawaspectratio) {
$MPEGvideoAspectRatioTextLookup = array('forbidden', 'square pixels', '0.6735', '16:9, 625 line, PAL', '0.7615', '0.8055', '16:9, 525 line, NTSC', '0.8935', '4:3, 625 line, PAL, CCIR601', '0.9815', '1.0255', '1.0695', '4:3, 525 line, NTSC, CCIR601', '1.1575', '1.2015', 'reserved');
return (isset($MPEGvideoAspectRatioTextLookup[$rawaspectratio]) ? $MPEGvideoAspectRatioTextLookup[$rawaspectratio] : '');
}
}
?>

View File

@ -1,224 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio.nsv.php //
// module for analyzing Nullsoft NSV files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_nsv
{
function getid3_nsv(&$fd, &$ThisFileInfo) {
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$NSVheader = fread($fd, 4);
switch ($NSVheader) {
case 'NSVs':
if ($this->getNSVsHeaderFilepointer($fd, $ThisFileInfo, 0)) {
$ThisFileInfo['fileformat'] = 'nsv';
$ThisFileInfo['audio']['dataformat'] = 'nsv';
$ThisFileInfo['video']['dataformat'] = 'nsv';
$ThisFileInfo['audio']['lossless'] = false;
$ThisFileInfo['video']['lossless'] = false;
}
break;
case 'NSVf':
if ($this->getNSVfHeaderFilepointer($fd, $ThisFileInfo, 0)) {
$ThisFileInfo['fileformat'] = 'nsv';
$ThisFileInfo['audio']['dataformat'] = 'nsv';
$ThisFileInfo['video']['dataformat'] = 'nsv';
$ThisFileInfo['audio']['lossless'] = false;
$ThisFileInfo['video']['lossless'] = false;
$this->getNSVsHeaderFilepointer($fd, $ThisFileInfo, $ThisFileInfo['nsv']['NSVf']['header_length']);
}
break;
default:
$ThisFileInfo['error'][] = 'Expecting "NSVs" or "NSVf" at offset '.$ThisFileInfo['avdataoffset'].', found "'.$NSVheader.'"';
return false;
break;
}
if (!isset($ThisFileInfo['nsv']['NSVf'])) {
$ThisFileInfo['warning'][] = 'NSVf header not present - cannot calculate playtime or bitrate';
}
return true;
}
function getNSVsHeaderFilepointer(&$fd, &$ThisFileInfo, $fileoffset) {
fseek($fd, $fileoffset, SEEK_SET);
$NSVsheader = fread($fd, 28);
$offset = 0;
$ThisFileInfo['nsv']['NSVs']['identifier'] = substr($NSVsheader, $offset, 4);
$offset += 4;
if ($ThisFileInfo['nsv']['NSVs']['identifier'] != 'NSVs') {
$ThisFileInfo['error'][] = 'expected "NSVs" at offset ('.$fileoffset.'), found "'.$ThisFileInfo['nsv']['NSVs']['identifier'].'" instead';
unset($ThisFileInfo['nsv']['NSVs']);
return false;
}
$ThisFileInfo['nsv']['NSVs']['offset'] = $fileoffset;
$ThisFileInfo['nsv']['NSVs']['video_codec'] = substr($NSVsheader, $offset, 4);
$offset += 4;
$ThisFileInfo['nsv']['NSVs']['audio_codec'] = substr($NSVsheader, $offset, 4);
$offset += 4;
$ThisFileInfo['nsv']['NSVs']['resolution_x'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 2));
$offset += 2;
$ThisFileInfo['nsv']['NSVs']['resolution_y'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 2));
$offset += 2;
$ThisFileInfo['nsv']['NSVs']['framerate_index'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1));
$offset += 1;
//$ThisFileInfo['nsv']['NSVs']['unknown1b'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1));
$offset += 1;
//$ThisFileInfo['nsv']['NSVs']['unknown1c'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1));
$offset += 1;
//$ThisFileInfo['nsv']['NSVs']['unknown1d'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1));
$offset += 1;
//$ThisFileInfo['nsv']['NSVs']['unknown2a'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1));
$offset += 1;
//$ThisFileInfo['nsv']['NSVs']['unknown2b'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1));
$offset += 1;
//$ThisFileInfo['nsv']['NSVs']['unknown2c'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1));
$offset += 1;
//$ThisFileInfo['nsv']['NSVs']['unknown2d'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1));
$offset += 1;
switch ($ThisFileInfo['nsv']['NSVs']['audio_codec']) {
case 'PCM ':
$ThisFileInfo['nsv']['NSVs']['bits_channel'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1));
$offset += 1;
$ThisFileInfo['nsv']['NSVs']['channels'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1));
$offset += 1;
$ThisFileInfo['nsv']['NSVs']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 2));
$offset += 2;
$ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['nsv']['NSVs']['sample_rate'];
break;
case 'MP3 ':
case 'NONE':
default:
//$ThisFileInfo['nsv']['NSVs']['unknown3'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 4));
$offset += 4;
break;
}
$ThisFileInfo['video']['resolution_x'] = $ThisFileInfo['nsv']['NSVs']['resolution_x'];
$ThisFileInfo['video']['resolution_y'] = $ThisFileInfo['nsv']['NSVs']['resolution_y'];
$ThisFileInfo['nsv']['NSVs']['frame_rate'] = $this->NSVframerateLookup($ThisFileInfo['nsv']['NSVs']['framerate_index']);
$ThisFileInfo['video']['frame_rate'] = $ThisFileInfo['nsv']['NSVs']['frame_rate'];
$ThisFileInfo['video']['bits_per_sample'] = 24;
$ThisFileInfo['video']['pixel_aspect_ratio'] = (float) 1;
return true;
}
function getNSVfHeaderFilepointer(&$fd, &$ThisFileInfo, $fileoffset, $getTOCoffsets=false) {
fseek($fd, $fileoffset, SEEK_SET);
$NSVfheader = fread($fd, 28);
$offset = 0;
$ThisFileInfo['nsv']['NSVf']['identifier'] = substr($NSVfheader, $offset, 4);
$offset += 4;
if ($ThisFileInfo['nsv']['NSVf']['identifier'] != 'NSVf') {
$ThisFileInfo['error'][] = 'expected "NSVf" at offset ('.$fileoffset.'), found "'.$ThisFileInfo['nsv']['NSVf']['identifier'].'" instead';
unset($ThisFileInfo['nsv']['NSVf']);
return false;
}
$ThisFileInfo['nsv']['NSVs']['offset'] = $fileoffset;
$ThisFileInfo['nsv']['NSVf']['header_length'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4));
$offset += 4;
$ThisFileInfo['nsv']['NSVf']['file_size'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4));
$offset += 4;
if ($ThisFileInfo['nsv']['NSVf']['file_size'] > $ThisFileInfo['avdataend']) {
$ThisFileInfo['warning'][] = 'truncated file - NSVf header indicates '.$ThisFileInfo['nsv']['NSVf']['file_size'].' bytes, file actually '.$ThisFileInfo['avdataend'].' bytes';
}
$ThisFileInfo['nsv']['NSVf']['playtime_ms'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4));
$offset += 4;
$ThisFileInfo['nsv']['NSVf']['meta_size'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4));
$offset += 4;
$ThisFileInfo['nsv']['NSVf']['TOC_entries_1'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4));
$offset += 4;
$ThisFileInfo['nsv']['NSVf']['TOC_entries_2'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4));
$offset += 4;
if ($ThisFileInfo['nsv']['NSVf']['playtime_ms'] == 0) {
$ThisFileInfo['error'][] = 'Corrupt NSV file: NSVf.playtime_ms == zero';
return false;
}
$NSVfheader .= fread($fd, $ThisFileInfo['nsv']['NSVf']['meta_size'] + (4 * $ThisFileInfo['nsv']['NSVf']['TOC_entries_1']) + (4 * $ThisFileInfo['nsv']['NSVf']['TOC_entries_2']));
$NSVfheaderlength = strlen($NSVfheader);
$ThisFileInfo['nsv']['NSVf']['metadata'] = substr($NSVfheader, $offset, $ThisFileInfo['nsv']['NSVf']['meta_size']);
$offset += $ThisFileInfo['nsv']['NSVf']['meta_size'];
if ($getTOCoffsets) {
$TOCcounter = 0;
while ($TOCcounter < $ThisFileInfo['nsv']['NSVf']['TOC_entries_1']) {
if ($TOCcounter < $ThisFileInfo['nsv']['NSVf']['TOC_entries_1']) {
$ThisFileInfo['nsv']['NSVf']['TOC_1'][$TOCcounter] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4));
$offset += 4;
$TOCcounter++;
}
}
}
if (trim($ThisFileInfo['nsv']['NSVf']['metadata']) != '') {
$ThisFileInfo['nsv']['NSVf']['metadata'] = str_replace('`', "\x01", $ThisFileInfo['nsv']['NSVf']['metadata']);
$CommentPairArray = explode("\x01".' ', $ThisFileInfo['nsv']['NSVf']['metadata']);
foreach ($CommentPairArray as $CommentPair) {
if (strstr($CommentPair, '='."\x01")) {
list($key, $value) = explode('='."\x01", $CommentPair, 2);
$ThisFileInfo['nsv']['comments'][strtolower($key)][] = trim(str_replace("\x01", '', $value));
}
}
}
$ThisFileInfo['playtime_seconds'] = $ThisFileInfo['nsv']['NSVf']['playtime_ms'] / 1000;
$ThisFileInfo['bitrate'] = ($ThisFileInfo['nsv']['NSVf']['file_size'] * 8) / $ThisFileInfo['playtime_seconds'];
return true;
}
function NSVframerateLookup($framerateindex) {
if ($framerateindex <= 127) {
return (float) $framerateindex;
}
static $NSVframerateLookup = array();
if (empty($NSVframerateLookup)) {
$NSVframerateLookup[129] = (float) 29.970;
$NSVframerateLookup[131] = (float) 23.976;
$NSVframerateLookup[133] = (float) 14.985;
$NSVframerateLookup[197] = (float) 59.940;
$NSVframerateLookup[199] = (float) 47.952;
}
return (isset($NSVframerateLookup[$framerateindex]) ? $NSVframerateLookup[$framerateindex] : false);
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@ -1,528 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio-video.real.php //
// module for analyzing Real Audio/Video files //
// dependencies: module.audio-video.riff.php //
// ///
/////////////////////////////////////////////////////////////////
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
class getid3_real
{
function getid3_real(&$fd, &$ThisFileInfo) {
$ThisFileInfo['fileformat'] = 'real';
$ThisFileInfo['bitrate'] = 0;
$ThisFileInfo['playtime_seconds'] = 0;
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$ChunkCounter = 0;
while (ftell($fd) < $ThisFileInfo['avdataend']) {
$ChunkData = fread($fd, 8);
$ChunkName = substr($ChunkData, 0, 4);
$ChunkSize = getid3_lib::BigEndian2Int(substr($ChunkData, 4, 4));
if ($ChunkName == '.ra'."\xFD") {
$ChunkData .= fread($fd, $ChunkSize - 8);
if ($this->ParseOldRAheader(substr($ChunkData, 0, 128), $ThisFileInfo['real']['old_ra_header'])) {
$ThisFileInfo['audio']['dataformat'] = 'real';
$ThisFileInfo['audio']['lossless'] = false;
$ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['real']['old_ra_header']['sample_rate'];
$ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['real']['old_ra_header']['bits_per_sample'];
$ThisFileInfo['audio']['channels'] = $ThisFileInfo['real']['old_ra_header']['channels'];
$ThisFileInfo['playtime_seconds'] = 60 * ($ThisFileInfo['real']['old_ra_header']['audio_bytes'] / $ThisFileInfo['real']['old_ra_header']['bytes_per_minute']);
$ThisFileInfo['audio']['bitrate'] = 8 * ($ThisFileInfo['real']['old_ra_header']['audio_bytes'] / $ThisFileInfo['playtime_seconds']);
$ThisFileInfo['audio']['codec'] = $this->RealAudioCodecFourCClookup($ThisFileInfo['real']['old_ra_header']['fourcc'], $ThisFileInfo['audio']['bitrate']);
foreach ($ThisFileInfo['real']['old_ra_header']['comments'] as $key => $valuearray) {
if (strlen(trim($valuearray[0])) > 0) {
$ThisFileInfo['real']['comments'][$key][] = trim($valuearray[0]);
}
}
return true;
}
$ThisFileInfo['error'][] = 'There was a problem parsing this RealAudio file. Please submit it for analysis to http://www.getid3.org/upload/ or info@getid3.org';
unset($ThisFileInfo['bitrate']);
unset($ThisFileInfo['playtime_seconds']);
return false;
}
// shortcut
$ThisFileInfo['real']['chunks'][$ChunkCounter] = array();
$thisfile_real_chunks_currentchunk = &$ThisFileInfo['real']['chunks'][$ChunkCounter];
$thisfile_real_chunks_currentchunk['name'] = $ChunkName;
$thisfile_real_chunks_currentchunk['offset'] = ftell($fd) - 8;
$thisfile_real_chunks_currentchunk['length'] = $ChunkSize;
if (($thisfile_real_chunks_currentchunk['offset'] + $thisfile_real_chunks_currentchunk['length']) > $ThisFileInfo['avdataend']) {
$ThisFileInfo['warning'][] = 'Chunk "'.$thisfile_real_chunks_currentchunk['name'].'" at offset '.$thisfile_real_chunks_currentchunk['offset'].' claims to be '.$thisfile_real_chunks_currentchunk['length'].' bytes long, which is beyond end of file';
return false;
}
if ($ChunkSize > (GETID3_FREAD_BUFFER_SIZE + 8)) {
$ChunkData .= fread($fd, GETID3_FREAD_BUFFER_SIZE - 8);
fseek($fd, $thisfile_real_chunks_currentchunk['offset'] + $ChunkSize, SEEK_SET);
} elseif(($ChunkSize - 8) > 0) {
$ChunkData .= fread($fd, $ChunkSize - 8);
}
$offset = 8;
switch ($ChunkName) {
case '.RMF': // RealMedia File Header
$thisfile_real_chunks_currentchunk['object_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
$offset += 2;
switch ($thisfile_real_chunks_currentchunk['object_version']) {
case 0:
$thisfile_real_chunks_currentchunk['file_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
$offset += 4;
$thisfile_real_chunks_currentchunk['headers_count'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
$offset += 4;
break;
default:
//$ThisFileInfo['warning'][] = 'Expected .RMF-object_version to be "0", actual value is "'.$thisfile_real_chunks_currentchunk['object_version'].'" (should not be a problem)';
break;
}
break;
case 'PROP': // Properties Header
$thisfile_real_chunks_currentchunk['object_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
$offset += 2;
if ($thisfile_real_chunks_currentchunk['object_version'] == 0) {
$thisfile_real_chunks_currentchunk['max_bit_rate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
$offset += 4;
$thisfile_real_chunks_currentchunk['avg_bit_rate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
$offset += 4;
$thisfile_real_chunks_currentchunk['max_packet_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
$offset += 4;
$thisfile_real_chunks_currentchunk['avg_packet_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
$offset += 4;
$thisfile_real_chunks_currentchunk['num_packets'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
$offset += 4;
$thisfile_real_chunks_currentchunk['duration'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
$offset += 4;
$thisfile_real_chunks_currentchunk['preroll'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
$offset += 4;
$thisfile_real_chunks_currentchunk['index_offset'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
$offset += 4;
$thisfile_real_chunks_currentchunk['data_offset'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
$offset += 4;
$thisfile_real_chunks_currentchunk['num_streams'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
$offset += 2;
$thisfile_real_chunks_currentchunk['flags_raw'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
$offset += 2;
$ThisFileInfo['playtime_seconds'] = $thisfile_real_chunks_currentchunk['duration'] / 1000;
if ($thisfile_real_chunks_currentchunk['duration'] > 0) {
$ThisFileInfo['bitrate'] += $thisfile_real_chunks_currentchunk['avg_bit_rate'];
}
$thisfile_real_chunks_currentchunk['flags']['save_enabled'] = (bool) ($thisfile_real_chunks_currentchunk['flags_raw'] & 0x0001);
$thisfile_real_chunks_currentchunk['flags']['perfect_play'] = (bool) ($thisfile_real_chunks_currentchunk['flags_raw'] & 0x0002);
$thisfile_real_chunks_currentchunk['flags']['live_broadcast'] = (bool) ($thisfile_real_chunks_currentchunk['flags_raw'] & 0x0004);
}
break;
case 'MDPR': // Media Properties Header
$thisfile_real_chunks_currentchunk['object_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
$offset += 2;
if ($thisfile_real_chunks_currentchunk['object_version'] == 0) {
$thisfile_real_chunks_currentchunk['stream_number'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
$offset += 2;
$thisfile_real_chunks_currentchunk['max_bit_rate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
$offset += 4;
$thisfile_real_chunks_currentchunk['avg_bit_rate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
$offset += 4;
$thisfile_real_chunks_currentchunk['max_packet_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
$offset += 4;
$thisfile_real_chunks_currentchunk['avg_packet_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
$offset += 4;
$thisfile_real_chunks_currentchunk['start_time'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
$offset += 4;
$thisfile_real_chunks_currentchunk['preroll'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
$offset += 4;
$thisfile_real_chunks_currentchunk['duration'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
$offset += 4;
$thisfile_real_chunks_currentchunk['stream_name_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 1));
$offset += 1;
$thisfile_real_chunks_currentchunk['stream_name'] = substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['stream_name_size']);
$offset += $thisfile_real_chunks_currentchunk['stream_name_size'];
$thisfile_real_chunks_currentchunk['mime_type_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 1));
$offset += 1;
$thisfile_real_chunks_currentchunk['mime_type'] = substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['mime_type_size']);
$offset += $thisfile_real_chunks_currentchunk['mime_type_size'];
$thisfile_real_chunks_currentchunk['type_specific_len'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
$offset += 4;
$thisfile_real_chunks_currentchunk['type_specific_data'] = substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['type_specific_len']);
$offset += $thisfile_real_chunks_currentchunk['type_specific_len'];
// shortcut
$thisfile_real_chunks_currentchunk_typespecificdata = &$thisfile_real_chunks_currentchunk['type_specific_data'];
switch ($thisfile_real_chunks_currentchunk['mime_type']) {
case 'video/x-pn-realvideo':
case 'video/x-pn-multirate-realvideo':
// http://www.freelists.org/archives/matroska-devel/07-2003/msg00010.html
// shortcut
$thisfile_real_chunks_currentchunk['video_info'] = array();
$thisfile_real_chunks_currentchunk_videoinfo = &$thisfile_real_chunks_currentchunk['video_info'];
$thisfile_real_chunks_currentchunk_videoinfo['dwSize'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 0, 4));
$thisfile_real_chunks_currentchunk_videoinfo['fourcc1'] = substr($thisfile_real_chunks_currentchunk_typespecificdata, 4, 4);
$thisfile_real_chunks_currentchunk_videoinfo['fourcc2'] = substr($thisfile_real_chunks_currentchunk_typespecificdata, 8, 4);
$thisfile_real_chunks_currentchunk_videoinfo['width'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 12, 2));
$thisfile_real_chunks_currentchunk_videoinfo['height'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 14, 2));
$thisfile_real_chunks_currentchunk_videoinfo['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 16, 2));
//$thisfile_real_chunks_currentchunk_videoinfo['unknown1'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 18, 2));
//$thisfile_real_chunks_currentchunk_videoinfo['unknown2'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 20, 2));
$thisfile_real_chunks_currentchunk_videoinfo['frames_per_second'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 22, 2));
//$thisfile_real_chunks_currentchunk_videoinfo['unknown3'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 24, 2));
//$thisfile_real_chunks_currentchunk_videoinfo['unknown4'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 26, 2));
//$thisfile_real_chunks_currentchunk_videoinfo['unknown5'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 28, 2));
//$thisfile_real_chunks_currentchunk_videoinfo['unknown6'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 30, 2));
//$thisfile_real_chunks_currentchunk_videoinfo['unknown7'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 32, 2));
//$thisfile_real_chunks_currentchunk_videoinfo['unknown8'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 34, 2));
//$thisfile_real_chunks_currentchunk_videoinfo['unknown9'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 36, 2));
$thisfile_real_chunks_currentchunk_videoinfo['codec'] = getid3_riff::RIFFfourccLookup($thisfile_real_chunks_currentchunk_videoinfo['fourcc2']);
$ThisFileInfo['video']['resolution_x'] = $thisfile_real_chunks_currentchunk_videoinfo['width'];
$ThisFileInfo['video']['resolution_y'] = $thisfile_real_chunks_currentchunk_videoinfo['height'];
$ThisFileInfo['video']['frame_rate'] = (float) $thisfile_real_chunks_currentchunk_videoinfo['frames_per_second'];
$ThisFileInfo['video']['codec'] = $thisfile_real_chunks_currentchunk_videoinfo['codec'];
$ThisFileInfo['video']['bits_per_sample'] = $thisfile_real_chunks_currentchunk_videoinfo['bits_per_sample'];
break;
case 'audio/x-pn-realaudio':
case 'audio/x-pn-multirate-realaudio':
$this->ParseOldRAheader($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk['parsed_audio_data']);
$ThisFileInfo['audio']['sample_rate'] = $thisfile_real_chunks_currentchunk['parsed_audio_data']['sample_rate'];
$ThisFileInfo['audio']['bits_per_sample'] = $thisfile_real_chunks_currentchunk['parsed_audio_data']['bits_per_sample'];
$ThisFileInfo['audio']['channels'] = $thisfile_real_chunks_currentchunk['parsed_audio_data']['channels'];
if (!empty($ThisFileInfo['audio']['dataformat'])) {
foreach ($ThisFileInfo['audio'] as $key => $value) {
if ($key != 'streams') {
$ThisFileInfo['audio']['streams'][$thisfile_real_chunks_currentchunk['stream_number']][$key] = $value;
}
}
}
break;
case 'logical-fileinfo':
// shortcut
$thisfile_real_chunks_currentchunk['logical_fileinfo'] = array();
$thisfile_real_chunks_currentchunk_logicalfileinfo = &$thisfile_real_chunks_currentchunk['logical_fileinfo'];
$thisfile_real_chunks_currentchunk_logicalfileinfo_offset = 0;
$thisfile_real_chunks_currentchunk_logicalfileinfo['logical_fileinfo_length'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 4));
$thisfile_real_chunks_currentchunk_logicalfileinfo_offset += 4;
//$thisfile_real_chunks_currentchunk_logicalfileinfo['unknown1'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 4));
$thisfile_real_chunks_currentchunk_logicalfileinfo_offset += 4;
$thisfile_real_chunks_currentchunk_logicalfileinfo['num_tags'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 4));
$thisfile_real_chunks_currentchunk_logicalfileinfo_offset += 4;
//$thisfile_real_chunks_currentchunk_logicalfileinfo['unknown2'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 4));
$thisfile_real_chunks_currentchunk_logicalfileinfo_offset += 4;
//$thisfile_real_chunks_currentchunk_logicalfileinfo['d'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 1));
//$thisfile_real_chunks_currentchunk_logicalfileinfo['one_type'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 4));
//$thisfile_real_chunks_currentchunk_logicalfileinfo_thislength = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 4 + $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 2));
//$thisfile_real_chunks_currentchunk_logicalfileinfo['one'] = substr($thisfile_real_chunks_currentchunk_typespecificdata, 6 + $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, $thisfile_real_chunks_currentchunk_logicalfileinfo_thislength);
//$thisfile_real_chunks_currentchunk_logicalfileinfo_offset += (6 + $thisfile_real_chunks_currentchunk_logicalfileinfo_thislength);
break;
}
if (empty($ThisFileInfo['playtime_seconds'])) {
$ThisFileInfo['playtime_seconds'] = max($ThisFileInfo['playtime_seconds'], ($thisfile_real_chunks_currentchunk['duration'] + $thisfile_real_chunks_currentchunk['start_time']) / 1000);
}
if ($thisfile_real_chunks_currentchunk['duration'] > 0) {
switch ($thisfile_real_chunks_currentchunk['mime_type']) {
case 'audio/x-pn-realaudio':
case 'audio/x-pn-multirate-realaudio':
$ThisFileInfo['audio']['bitrate'] = (isset($ThisFileInfo['audio']['bitrate']) ? $ThisFileInfo['audio']['bitrate'] : 0) + $thisfile_real_chunks_currentchunk['avg_bit_rate'];
$ThisFileInfo['audio']['codec'] = $this->RealAudioCodecFourCClookup($thisfile_real_chunks_currentchunk['parsed_audio_data']['fourcc'], $ThisFileInfo['audio']['bitrate']);
$ThisFileInfo['audio']['dataformat'] = 'real';
$ThisFileInfo['audio']['lossless'] = false;
break;
case 'video/x-pn-realvideo':
case 'video/x-pn-multirate-realvideo':
$ThisFileInfo['video']['bitrate'] = (isset($ThisFileInfo['video']['bitrate']) ? $ThisFileInfo['video']['bitrate'] : 0) + $thisfile_real_chunks_currentchunk['avg_bit_rate'];
$ThisFileInfo['video']['bitrate_mode'] = 'cbr';
$ThisFileInfo['video']['dataformat'] = 'real';
$ThisFileInfo['video']['lossless'] = false;
$ThisFileInfo['video']['pixel_aspect_ratio'] = (float) 1;
break;
case 'audio/x-ralf-mpeg4-generic':
$ThisFileInfo['audio']['bitrate'] = (isset($ThisFileInfo['audio']['bitrate']) ? $ThisFileInfo['audio']['bitrate'] : 0) + $thisfile_real_chunks_currentchunk['avg_bit_rate'];
$ThisFileInfo['audio']['codec'] = 'RealAudio Lossless';
$ThisFileInfo['audio']['dataformat'] = 'real';
$ThisFileInfo['audio']['lossless'] = true;
break;
}
$ThisFileInfo['bitrate'] = (isset($ThisFileInfo['video']['bitrate']) ? $ThisFileInfo['video']['bitrate'] : 0) + (isset($ThisFileInfo['audio']['bitrate']) ? $ThisFileInfo['audio']['bitrate'] : 0);
}
}
break;
case 'CONT': // Content Description Header (text comments)
$thisfile_real_chunks_currentchunk['object_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
$offset += 2;
if ($thisfile_real_chunks_currentchunk['object_version'] == 0) {
$thisfile_real_chunks_currentchunk['title_len'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
$offset += 2;
$thisfile_real_chunks_currentchunk['title'] = (string) substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['title_len']);
$offset += $thisfile_real_chunks_currentchunk['title_len'];
$thisfile_real_chunks_currentchunk['artist_len'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
$offset += 2;
$thisfile_real_chunks_currentchunk['artist'] = (string) substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['artist_len']);
$offset += $thisfile_real_chunks_currentchunk['artist_len'];
$thisfile_real_chunks_currentchunk['copyright_len'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
$offset += 2;
$thisfile_real_chunks_currentchunk['copyright'] = (string) substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['copyright_len']);
$offset += $thisfile_real_chunks_currentchunk['copyright_len'];
$thisfile_real_chunks_currentchunk['comment_len'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
$offset += 2;
$thisfile_real_chunks_currentchunk['comment'] = (string) substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['comment_len']);
$offset += $thisfile_real_chunks_currentchunk['comment_len'];
$commentkeystocopy = array('title'=>'title', 'artist'=>'artist', 'copyright'=>'copyright', 'comment'=>'comment');
foreach ($commentkeystocopy as $key => $val) {
if ($thisfile_real_chunks_currentchunk[$key]) {
$ThisFileInfo['real']['comments'][$val][] = trim($thisfile_real_chunks_currentchunk[$key]);
}
}
}
break;
case 'DATA': // Data Chunk Header
// do nothing
break;
case 'INDX': // Index Section Header
$thisfile_real_chunks_currentchunk['object_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
$offset += 2;
if ($thisfile_real_chunks_currentchunk['object_version'] == 0) {
$thisfile_real_chunks_currentchunk['num_indices'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
$offset += 4;
$thisfile_real_chunks_currentchunk['stream_number'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2));
$offset += 2;
$thisfile_real_chunks_currentchunk['next_index_header'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4));
$offset += 4;
if ($thisfile_real_chunks_currentchunk['next_index_header'] == 0) {
// last index chunk found, ignore rest of file
break 2;
} else {
// non-last index chunk, seek to next index chunk (skipping actual index data)
fseek($fd, $thisfile_real_chunks_currentchunk['next_index_header'], SEEK_SET);
}
}
break;
default:
$ThisFileInfo['warning'][] = 'Unhandled RealMedia chunk "'.$ChunkName.'" at offset '.$thisfile_real_chunks_currentchunk['offset'];
break;
}
$ChunkCounter++;
}
if (!empty($ThisFileInfo['audio']['streams'])) {
$ThisFileInfo['audio']['bitrate'] = 0;
foreach ($ThisFileInfo['audio']['streams'] as $key => $valuearray) {
$ThisFileInfo['audio']['bitrate'] += $valuearray['bitrate'];
}
}
return true;
}
function ParseOldRAheader($OldRAheaderData, &$ParsedArray) {
// http://www.freelists.org/archives/matroska-devel/07-2003/msg00010.html
$ParsedArray = array();
$ParsedArray['magic'] = substr($OldRAheaderData, 0, 4);
if ($ParsedArray['magic'] != '.ra'."\xFD") {
return false;
}
$ParsedArray['version1'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 4, 2));
if ($ParsedArray['version1'] < 3) {
return false;
} elseif ($ParsedArray['version1'] == 3) {
$ParsedArray['fourcc1'] = '.ra3';
$ParsedArray['bits_per_sample'] = 16; // hard-coded for old versions?
$ParsedArray['sample_rate'] = 8000; // hard-coded for old versions?
$ParsedArray['header_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 6, 2));
$ParsedArray['channels'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 8, 2)); // always 1 (?)
//$ParsedArray['unknown1'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 10, 2));
//$ParsedArray['unknown2'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 12, 2));
//$ParsedArray['unknown3'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 14, 2));
$ParsedArray['bytes_per_minute'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 16, 2));
$ParsedArray['audio_bytes'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 18, 4));
$ParsedArray['comments_raw'] = substr($OldRAheaderData, 22, $ParsedArray['header_size'] - 22 + 1); // not including null terminator
$commentoffset = 0;
$commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1));
$ParsedArray['comments']['title'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength);
$commentoffset += $commentlength;
$commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1));
$ParsedArray['comments']['artist'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength);
$commentoffset += $commentlength;
$commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1));
$ParsedArray['comments']['copyright'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength);
$commentoffset += $commentlength;
$commentoffset++; // final null terminator (?)
$commentoffset++; // fourcc length (?) should be 4
$ParsedArray['fourcc'] = substr($OldRAheaderData, 23 + $commentoffset, 4);
} elseif ($ParsedArray['version1'] <= 5) {
//$ParsedArray['unknown1'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 6, 2));
$ParsedArray['fourcc1'] = substr($OldRAheaderData, 8, 4);
$ParsedArray['file_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 12, 4));
$ParsedArray['version2'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 16, 2));
$ParsedArray['header_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 18, 4));
$ParsedArray['codec_flavor_id'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 22, 2));
$ParsedArray['coded_frame_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 24, 4));
$ParsedArray['audio_bytes'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 28, 4));
$ParsedArray['bytes_per_minute'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 32, 4));
//$ParsedArray['unknown5'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 36, 4));
$ParsedArray['sub_packet_h'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 40, 2));
$ParsedArray['frame_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 42, 2));
$ParsedArray['sub_packet_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 44, 2));
//$ParsedArray['unknown6'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 46, 2));
switch ($ParsedArray['version1']) {
case 4:
$ParsedArray['sample_rate'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 48, 2));
//$ParsedArray['unknown8'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 50, 2));
$ParsedArray['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 52, 2));
$ParsedArray['channels'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 54, 2));
$ParsedArray['length_fourcc2'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 56, 1));
$ParsedArray['fourcc2'] = substr($OldRAheaderData, 57, 4);
$ParsedArray['length_fourcc3'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 61, 1));
$ParsedArray['fourcc3'] = substr($OldRAheaderData, 62, 4);
//$ParsedArray['unknown9'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 66, 1));
//$ParsedArray['unknown10'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 67, 2));
$ParsedArray['comments_raw'] = substr($OldRAheaderData, 69, $ParsedArray['header_size'] - 69 + 16);
$commentoffset = 0;
$commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1));
$ParsedArray['comments']['title'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength);
$commentoffset += $commentlength;
$commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1));
$ParsedArray['comments']['artist'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength);
$commentoffset += $commentlength;
$commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1));
$ParsedArray['comments']['copyright'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength);
$commentoffset += $commentlength;
break;
case 5:
$ParsedArray['sample_rate'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 48, 4));
$ParsedArray['sample_rate2'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 52, 4));
$ParsedArray['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 56, 4));
$ParsedArray['channels'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 60, 2));
$ParsedArray['genr'] = substr($OldRAheaderData, 62, 4);
$ParsedArray['fourcc3'] = substr($OldRAheaderData, 66, 4);
$ParsedArray['comments'] = array();
break;
}
$ParsedArray['fourcc'] = $ParsedArray['fourcc3'];
}
foreach ($ParsedArray['comments'] as $key => $value) {
if ($ParsedArray['comments'][$key][0] === false) {
$ParsedArray['comments'][$key][0] = '';
}
}
return true;
}
function RealAudioCodecFourCClookup($fourcc, $bitrate) {
static $RealAudioCodecFourCClookup = array();
if (empty($RealAudioCodecFourCClookup)) {
// http://www.its.msstate.edu/net/real/reports/config/tags.stats
// http://www.freelists.org/archives/matroska-devel/06-2003/fullthread18.html
$RealAudioCodecFourCClookup['14_4'][8000] = 'RealAudio v2 (14.4kbps)';
$RealAudioCodecFourCClookup['14.4'][8000] = 'RealAudio v2 (14.4kbps)';
$RealAudioCodecFourCClookup['lpcJ'][8000] = 'RealAudio v2 (14.4kbps)';
$RealAudioCodecFourCClookup['28_8'][15200] = 'RealAudio v2 (28.8kbps)';
$RealAudioCodecFourCClookup['28.8'][15200] = 'RealAudio v2 (28.8kbps)';
$RealAudioCodecFourCClookup['sipr'][4933] = 'RealAudio v4 (5kbps Voice)';
$RealAudioCodecFourCClookup['sipr'][6444] = 'RealAudio v4 (6.5kbps Voice)';
$RealAudioCodecFourCClookup['sipr'][8444] = 'RealAudio v4 (8.5kbps Voice)';
$RealAudioCodecFourCClookup['sipr'][16000] = 'RealAudio v4 (16kbps Wideband)';
$RealAudioCodecFourCClookup['dnet'][8000] = 'RealAudio v3 (8kbps Music)';
$RealAudioCodecFourCClookup['dnet'][16000] = 'RealAudio v3 (16kbps Music Low Response)';
$RealAudioCodecFourCClookup['dnet'][15963] = 'RealAudio v3 (16kbps Music Mid/High Response)';
$RealAudioCodecFourCClookup['dnet'][20000] = 'RealAudio v3 (20kbps Music Stereo)';
$RealAudioCodecFourCClookup['dnet'][32000] = 'RealAudio v3 (32kbps Music Mono)';
$RealAudioCodecFourCClookup['dnet'][31951] = 'RealAudio v3 (32kbps Music Stereo)';
$RealAudioCodecFourCClookup['dnet'][39965] = 'RealAudio v3 (40kbps Music Mono)';
$RealAudioCodecFourCClookup['dnet'][40000] = 'RealAudio v3 (40kbps Music Stereo)';
$RealAudioCodecFourCClookup['dnet'][79947] = 'RealAudio v3 (80kbps Music Mono)';
$RealAudioCodecFourCClookup['dnet'][80000] = 'RealAudio v3 (80kbps Music Stereo)';
$RealAudioCodecFourCClookup['dnet'][0] = 'RealAudio v3';
$RealAudioCodecFourCClookup['sipr'][0] = 'RealAudio v4';
$RealAudioCodecFourCClookup['cook'][0] = 'RealAudio G2';
$RealAudioCodecFourCClookup['atrc'][0] = 'RealAudio 8';
}
$roundbitrate = intval(round($bitrate));
if (isset($RealAudioCodecFourCClookup[$fourcc][$roundbitrate])) {
return $RealAudioCodecFourCClookup[$fourcc][$roundbitrate];
} elseif (isset($RealAudioCodecFourCClookup[$fourcc][0])) {
return $RealAudioCodecFourCClookup[$fourcc][0];
}
return $fourcc;
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@ -1,149 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio-video.swf.php //
// module for analyzing Shockwave Flash files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_swf
{
function getid3_swf(&$fd, &$ThisFileInfo, $ReturnAllTagData=false) {
//$start_time = microtime(true);
$ThisFileInfo['fileformat'] = 'swf';
$ThisFileInfo['video']['dataformat'] = 'swf';
// http://www.openswf.org/spec/SWFfileformat.html
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$SWFfileData = fread($fd, $ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']); // 8 + 2 + 2 + max(9) bytes NOT including Frame_Size RECT data
$ThisFileInfo['swf']['header']['signature'] = substr($SWFfileData, 0, 3);
switch ($ThisFileInfo['swf']['header']['signature']) {
case 'FWS':
$ThisFileInfo['swf']['header']['compressed'] = false;
break;
case 'CWS':
$ThisFileInfo['swf']['header']['compressed'] = true;
break;
default:
$ThisFileInfo['error'][] = 'Expecting "FWS" or "CWS" at offset '.$ThisFileInfo['avdataoffset'].', found "'.$ThisFileInfo['swf']['header']['signature'].'"';
unset($ThisFileInfo['swf']);
unset($ThisFileInfo['fileformat']);
return false;
break;
}
$ThisFileInfo['swf']['header']['version'] = getid3_lib::LittleEndian2Int(substr($SWFfileData, 3, 1));
$ThisFileInfo['swf']['header']['length'] = getid3_lib::LittleEndian2Int(substr($SWFfileData, 4, 4));
//echo __LINE__.'='.number_format(microtime(true) - $start_time, 3).'<br>';
if ($ThisFileInfo['swf']['header']['compressed']) {
$SWFHead = substr($SWFfileData, 0, 8);
$SWFfileData = substr($SWFfileData, 8);
if ($decompressed = @gzuncompress($SWFfileData)) {
$SWFfileData = $SWFHead.$decompressed;
} else {
$ThisFileInfo['error'][] = 'Error decompressing compressed SWF data ('.strlen($SWFfileData).' bytes compressed, should be '.($ThisFileInfo['swf']['header']['length'] - 8).' bytes uncompressed)';
return false;
}
}
//echo __LINE__.'='.number_format(microtime(true) - $start_time, 3).'<br>';
$FrameSizeBitsPerValue = (ord(substr($SWFfileData, 8, 1)) & 0xF8) >> 3;
$FrameSizeDataLength = ceil((5 + (4 * $FrameSizeBitsPerValue)) / 8);
$FrameSizeDataString = str_pad(decbin(ord(substr($SWFfileData, 8, 1)) & 0x07), 3, '0', STR_PAD_LEFT);
for ($i = 1; $i < $FrameSizeDataLength; $i++) {
$FrameSizeDataString .= str_pad(decbin(ord(substr($SWFfileData, 8 + $i, 1))), 8, '0', STR_PAD_LEFT);
}
list($X1, $X2, $Y1, $Y2) = explode("\n", wordwrap($FrameSizeDataString, $FrameSizeBitsPerValue, "\n", 1));
$ThisFileInfo['swf']['header']['frame_width'] = getid3_lib::Bin2Dec($X2);
$ThisFileInfo['swf']['header']['frame_height'] = getid3_lib::Bin2Dec($Y2);
// http://www-lehre.informatik.uni-osnabrueck.de/~fbstark/diplom/docs/swf/Flash_Uncovered.htm
// Next in the header is the frame rate, which is kind of weird.
// It is supposed to be stored as a 16bit integer, but the first byte
// (or last depending on how you look at it) is completely ignored.
// Example: 0x000C -> 0x0C -> 12 So the frame rate is 12 fps.
// Byte at (8 + $FrameSizeDataLength) is always zero and ignored
$ThisFileInfo['swf']['header']['frame_rate'] = getid3_lib::LittleEndian2Int(substr($SWFfileData, 9 + $FrameSizeDataLength, 1));
$ThisFileInfo['swf']['header']['frame_count'] = getid3_lib::LittleEndian2Int(substr($SWFfileData, 10 + $FrameSizeDataLength, 2));
$ThisFileInfo['video']['frame_rate'] = $ThisFileInfo['swf']['header']['frame_rate'];
$ThisFileInfo['video']['resolution_x'] = intval(round($ThisFileInfo['swf']['header']['frame_width'] / 20));
$ThisFileInfo['video']['resolution_y'] = intval(round($ThisFileInfo['swf']['header']['frame_height'] / 20));
$ThisFileInfo['video']['pixel_aspect_ratio'] = (float) 1;
if (($ThisFileInfo['swf']['header']['frame_count'] > 0) && ($ThisFileInfo['swf']['header']['frame_rate'] > 0)) {
$ThisFileInfo['playtime_seconds'] = $ThisFileInfo['swf']['header']['frame_count'] / $ThisFileInfo['swf']['header']['frame_rate'];
}
//echo __LINE__.'='.number_format(microtime(true) - $start_time, 3).'<br>';
// SWF tags
$CurrentOffset = 12 + $FrameSizeDataLength;
$SWFdataLength = strlen($SWFfileData);
while ($CurrentOffset < $SWFdataLength) {
//echo __LINE__.'='.number_format(microtime(true) - $start_time, 3).'<br>';
$TagIDTagLength = getid3_lib::LittleEndian2Int(substr($SWFfileData, $CurrentOffset, 2));
$TagID = ($TagIDTagLength & 0xFFFC) >> 6;
$TagLength = ($TagIDTagLength & 0x003F);
$CurrentOffset += 2;
if ($TagLength == 0x3F) {
$TagLength = getid3_lib::LittleEndian2Int(substr($SWFfileData, $CurrentOffset, 4));
$CurrentOffset += 4;
}
unset($TagData);
$TagData['offset'] = $CurrentOffset;
$TagData['size'] = $TagLength;
$TagData['id'] = $TagID;
$TagData['data'] = substr($SWFfileData, $CurrentOffset, $TagLength);
switch ($TagID) {
case 0: // end of movie
break 2;
case 9: // Set background color
//$ThisFileInfo['swf']['tags'][] = $TagData;
$ThisFileInfo['swf']['bgcolor'] = strtoupper(str_pad(dechex(getid3_lib::BigEndian2Int($TagData['data'])), 6, '0', STR_PAD_LEFT));
break;
default:
if ($ReturnAllTagData) {
$ThisFileInfo['swf']['tags'][] = $TagData;
}
break;
}
$CurrentOffset += $TagLength;
}
return true;
}
}
?>

View File

@ -1,542 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio.aac.php //
// module for analyzing AAC Audio files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_aac
{
// new combined constructor
function getid3_aac(&$fd, &$ThisFileInfo, $option) {
if ($option === 'adif') {
$this->getAACADIFheaderFilepointer($fd, $ThisFileInfo);
}
elseif ($option === 'adts') {
$this->getAACADTSheaderFilepointer($fd, $ThisFileInfo);
}
}
function getAACADIFheaderFilepointer(&$fd, &$ThisFileInfo) {
$ThisFileInfo['fileformat'] = 'aac';
$ThisFileInfo['audio']['dataformat'] = 'aac';
$ThisFileInfo['audio']['lossless'] = false;
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$AACheader = fread($fd, 1024);
$offset = 0;
if (substr($AACheader, 0, 4) == 'ADIF') {
// http://faac.sourceforge.net/wiki/index.php?page=ADIF
// http://libmpeg.org/mpeg4/doc/w2203tfs.pdf
// adif_header() {
// adif_id 32
// copyright_id_present 1
// if( copyright_id_present )
// copyright_id 72
// original_copy 1
// home 1
// bitstream_type 1
// bitrate 23
// num_program_config_elements 4
// for (i = 0; i < num_program_config_elements + 1; i++ ) {
// if( bitstream_type == '0' )
// adif_buffer_fullness 20
// program_config_element()
// }
// }
$AACheaderBitstream = getid3_lib::BigEndian2Bin($AACheader);
$bitoffset = 0;
$ThisFileInfo['aac']['header_type'] = 'ADIF';
$bitoffset += 32;
$ThisFileInfo['aac']['header']['mpeg_version'] = 4;
$ThisFileInfo['aac']['header']['copyright'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1');
$bitoffset += 1;
if ($ThisFileInfo['aac']['header']['copyright']) {
$ThisFileInfo['aac']['header']['copyright_id'] = getid3_lib::Bin2String(substr($AACheaderBitstream, $bitoffset, 72));
$bitoffset += 72;
}
$ThisFileInfo['aac']['header']['original_copy'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1');
$bitoffset += 1;
$ThisFileInfo['aac']['header']['home'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1');
$bitoffset += 1;
$ThisFileInfo['aac']['header']['is_vbr'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1');
$bitoffset += 1;
if ($ThisFileInfo['aac']['header']['is_vbr']) {
$ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
$ThisFileInfo['aac']['header']['bitrate_max'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 23));
$bitoffset += 23;
} else {
$ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
$ThisFileInfo['aac']['header']['bitrate'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 23));
$bitoffset += 23;
$ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['aac']['header']['bitrate'];
}
if ($ThisFileInfo['audio']['bitrate'] == 0) {
$ThisFileInfo['error'][] = 'Corrupt AAC file: bitrate_audio == zero';
return false;
}
$ThisFileInfo['aac']['header']['num_program_configs'] = 1 + getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
$bitoffset += 4;
for ($i = 0; $i < $ThisFileInfo['aac']['header']['num_program_configs']; $i++) {
// http://www.audiocoding.com/wiki/index.php?page=program_config_element
// buffer_fullness 20
// element_instance_tag 4
// object_type 2
// sampling_frequency_index 4
// num_front_channel_elements 4
// num_side_channel_elements 4
// num_back_channel_elements 4
// num_lfe_channel_elements 2
// num_assoc_data_elements 3
// num_valid_cc_elements 4
// mono_mixdown_present 1
// mono_mixdown_element_number 4 if mono_mixdown_present == 1
// stereo_mixdown_present 1
// stereo_mixdown_element_number 4 if stereo_mixdown_present == 1
// matrix_mixdown_idx_present 1
// matrix_mixdown_idx 2 if matrix_mixdown_idx_present == 1
// pseudo_surround_enable 1 if matrix_mixdown_idx_present == 1
// for (i = 0; i < num_front_channel_elements; i++) {
// front_element_is_cpe[i] 1
// front_element_tag_select[i] 4
// }
// for (i = 0; i < num_side_channel_elements; i++) {
// side_element_is_cpe[i] 1
// side_element_tag_select[i] 4
// }
// for (i = 0; i < num_back_channel_elements; i++) {
// back_element_is_cpe[i] 1
// back_element_tag_select[i] 4
// }
// for (i = 0; i < num_lfe_channel_elements; i++) {
// lfe_element_tag_select[i] 4
// }
// for (i = 0; i < num_assoc_data_elements; i++) {
// assoc_data_element_tag_select[i] 4
// }
// for (i = 0; i < num_valid_cc_elements; i++) {
// cc_element_is_ind_sw[i] 1
// valid_cc_element_tag_select[i] 4
// }
// byte_alignment() VAR
// comment_field_bytes 8
// for (i = 0; i < comment_field_bytes; i++) {
// comment_field_data[i] 8
// }
if (!$ThisFileInfo['aac']['header']['is_vbr']) {
$ThisFileInfo['aac']['program_configs'][$i]['buffer_fullness'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 20));
$bitoffset += 20;
}
$ThisFileInfo['aac']['program_configs'][$i]['element_instance_tag'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
$bitoffset += 4;
$ThisFileInfo['aac']['program_configs'][$i]['object_type'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2));
$bitoffset += 2;
$ThisFileInfo['aac']['program_configs'][$i]['sampling_frequency_index'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
$bitoffset += 4;
$ThisFileInfo['aac']['program_configs'][$i]['num_front_channel_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
$bitoffset += 4;
$ThisFileInfo['aac']['program_configs'][$i]['num_side_channel_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
$bitoffset += 4;
$ThisFileInfo['aac']['program_configs'][$i]['num_back_channel_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
$bitoffset += 4;
$ThisFileInfo['aac']['program_configs'][$i]['num_lfe_channel_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2));
$bitoffset += 2;
$ThisFileInfo['aac']['program_configs'][$i]['num_assoc_data_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 3));
$bitoffset += 3;
$ThisFileInfo['aac']['program_configs'][$i]['num_valid_cc_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
$bitoffset += 4;
$ThisFileInfo['aac']['program_configs'][$i]['mono_mixdown_present'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
$bitoffset += 1;
if ($ThisFileInfo['aac']['program_configs'][$i]['mono_mixdown_present']) {
$ThisFileInfo['aac']['program_configs'][$i]['mono_mixdown_element_number'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
$bitoffset += 4;
}
$ThisFileInfo['aac']['program_configs'][$i]['stereo_mixdown_present'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
$bitoffset += 1;
if ($ThisFileInfo['aac']['program_configs'][$i]['stereo_mixdown_present']) {
$ThisFileInfo['aac']['program_configs'][$i]['stereo_mixdown_element_number'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
$bitoffset += 4;
}
$ThisFileInfo['aac']['program_configs'][$i]['matrix_mixdown_idx_present'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
$bitoffset += 1;
if ($ThisFileInfo['aac']['program_configs'][$i]['matrix_mixdown_idx_present']) {
$ThisFileInfo['aac']['program_configs'][$i]['matrix_mixdown_idx'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2));
$bitoffset += 2;
$ThisFileInfo['aac']['program_configs'][$i]['pseudo_surround_enable'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
$bitoffset += 1;
}
for ($j = 0; $j < $ThisFileInfo['aac']['program_configs'][$i]['num_front_channel_elements']; $j++) {
$ThisFileInfo['aac']['program_configs'][$i]['front_element_is_cpe'][$j] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
$bitoffset += 1;
$ThisFileInfo['aac']['program_configs'][$i]['front_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
$bitoffset += 4;
}
for ($j = 0; $j < $ThisFileInfo['aac']['program_configs'][$i]['num_side_channel_elements']; $j++) {
$ThisFileInfo['aac']['program_configs'][$i]['side_element_is_cpe'][$j] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
$bitoffset += 1;
$ThisFileInfo['aac']['program_configs'][$i]['side_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
$bitoffset += 4;
}
for ($j = 0; $j < $ThisFileInfo['aac']['program_configs'][$i]['num_back_channel_elements']; $j++) {
$ThisFileInfo['aac']['program_configs'][$i]['back_element_is_cpe'][$j] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
$bitoffset += 1;
$ThisFileInfo['aac']['program_configs'][$i]['back_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
$bitoffset += 4;
}
for ($j = 0; $j < $ThisFileInfo['aac']['program_configs'][$i]['num_lfe_channel_elements']; $j++) {
$ThisFileInfo['aac']['program_configs'][$i]['lfe_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
$bitoffset += 4;
}
for ($j = 0; $j < $ThisFileInfo['aac']['program_configs'][$i]['num_assoc_data_elements']; $j++) {
$ThisFileInfo['aac']['program_configs'][$i]['assoc_data_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
$bitoffset += 4;
}
for ($j = 0; $j < $ThisFileInfo['aac']['program_configs'][$i]['num_valid_cc_elements']; $j++) {
$ThisFileInfo['aac']['program_configs'][$i]['cc_element_is_ind_sw'][$j] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
$bitoffset += 1;
$ThisFileInfo['aac']['program_configs'][$i]['valid_cc_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
$bitoffset += 4;
}
$bitoffset = ceil($bitoffset / 8) * 8;
$ThisFileInfo['aac']['program_configs'][$i]['comment_field_bytes'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 8));
$bitoffset += 8;
$ThisFileInfo['aac']['program_configs'][$i]['comment_field'] = getid3_lib::Bin2String(substr($AACheaderBitstream, $bitoffset, 8 * $ThisFileInfo['aac']['program_configs'][$i]['comment_field_bytes']));
$bitoffset += 8 * $ThisFileInfo['aac']['program_configs'][$i]['comment_field_bytes'];
$ThisFileInfo['aac']['header']['profile_text'] = $this->AACprofileLookup($ThisFileInfo['aac']['program_configs'][$i]['object_type'], $ThisFileInfo['aac']['header']['mpeg_version']);
$ThisFileInfo['aac']['program_configs'][$i]['sampling_frequency'] = $this->AACsampleRateLookup($ThisFileInfo['aac']['program_configs'][$i]['sampling_frequency_index']);
$ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['aac']['program_configs'][$i]['sampling_frequency'];
$ThisFileInfo['audio']['channels'] = $this->AACchannelCountCalculate($ThisFileInfo['aac']['program_configs'][$i]);
if ($ThisFileInfo['aac']['program_configs'][$i]['comment_field']) {
$ThisFileInfo['aac']['comments'][] = $ThisFileInfo['aac']['program_configs'][$i]['comment_field'];
}
}
$ThisFileInfo['playtime_seconds'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['audio']['bitrate'];
$ThisFileInfo['audio']['encoder_options'] = $ThisFileInfo['aac']['header_type'].' '.$ThisFileInfo['aac']['header']['profile_text'];
return true;
} else {
unset($ThisFileInfo['fileformat']);
unset($ThisFileInfo['aac']);
$ThisFileInfo['error'][] = 'AAC-ADIF synch not found at offset '.$ThisFileInfo['avdataoffset'].' (expected "ADIF", found "'.substr($AACheader, 0, 4).'" instead)';
return false;
}
}
function getAACADTSheaderFilepointer(&$fd, &$ThisFileInfo, $MaxFramesToScan=1000000, $ReturnExtendedInfo=false) {
// based loosely on code from AACfile by Jurgen Faul <jfaulØgmx.de>
// http://jfaul.de/atl or http://j-faul.virtualave.net/atl/atl.html
// http://faac.sourceforge.net/wiki/index.php?page=ADTS
// * ADTS Fixed Header: these don't change from frame to frame
// syncword 12 always: '111111111111'
// ID 1 0: MPEG-4, 1: MPEG-2
// layer 2 always: '00'
// protection_absent 1
// profile 2
// sampling_frequency_index 4
// private_bit 1
// channel_configuration 3
// original/copy 1
// home 1
// emphasis 2 only if ID == 0 (ie MPEG-4)
// * ADTS Variable Header: these can change from frame to frame
// copyright_identification_bit 1
// copyright_identification_start 1
// aac_frame_length 13 length of the frame including header (in bytes)
// adts_buffer_fullness 11 0x7FF indicates VBR
// no_raw_data_blocks_in_frame 2
// * ADTS Error check
// crc_check 16 only if protection_absent == 0
$byteoffset = 0;
$framenumber = 0;
// Init bit pattern array
static $decbin = array();
// Populate $bindec
for ($i = 0; $i < 256; $i++) {
$decbin[chr($i)] = str_pad(decbin($i), 8, '0', STR_PAD_LEFT);
}
// used to calculate bitrate below
$BitrateCache = array();
while (true) {
// breaks out when end-of-file encountered, or invalid data found,
// or MaxFramesToScan frames have been scanned
if ($byteoffset >= pow(2, 31)) {
$ThisFileInfo['warning'][] = 'Unable to parse AAC file beyond '.ftell($fd).' (PHP does not support file operations beyond 2GB)';
return false;
}
fseek($fd, $byteoffset, SEEK_SET);
// First get substring
$substring = fread($fd, 10);
$substringlength = strlen($substring);
if ($substringlength != 10) {
$ThisFileInfo['error'][] = 'Failed to read 10 bytes at offset '.(ftell($fd) - $substringlength).' (only read '.$substringlength.' bytes)';
return false;
}
// Initialise $AACheaderBitstream
$AACheaderBitstream = '';
// Loop thru substring chars
for ($i = 0; $i < 10; $i++) {
$AACheaderBitstream .= $decbin[$substring{$i}];
}
$bitoffset = 0;
$synctest = bindec(substr($AACheaderBitstream, $bitoffset, 12));
$bitoffset += 12;
if ($synctest != 0x0FFF) {
$ThisFileInfo['error'][] = 'Synch pattern (0x0FFF) not found at offset '.(ftell($fd) - 10).' (found 0x0'.strtoupper(dechex($synctest)).' instead)';
if ($ThisFileInfo['fileformat'] == 'aac') {
return true;
}
return false;
}
// Gather info for first frame only - this takes time to do 1000 times!
if ($framenumber > 0) {
if (!$AACheaderBitstream[$bitoffset]) {
// MPEG-4
$bitoffset += 20;
} else {
// MPEG-2
$bitoffset += 18;
}
} else {
$ThisFileInfo['aac']['header_type'] = 'ADTS';
$ThisFileInfo['aac']['header']['synch'] = $synctest;
$ThisFileInfo['fileformat'] = 'aac';
$ThisFileInfo['audio']['dataformat'] = 'aac';
$ThisFileInfo['aac']['header']['mpeg_version'] = ((substr($AACheaderBitstream, $bitoffset, 1) == '0') ? 4 : 2);
$bitoffset += 1;
$ThisFileInfo['aac']['header']['layer'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2));
$bitoffset += 2;
if ($ThisFileInfo['aac']['header']['layer'] != 0) {
$ThisFileInfo['error'][] = 'Layer error - expected 0x00, found 0x'.dechex($ThisFileInfo['aac']['header']['layer']).' instead';
return false;
}
$ThisFileInfo['aac']['header']['crc_present'] = ((substr($AACheaderBitstream, $bitoffset, 1) == '0') ? true : false);
$bitoffset += 1;
$ThisFileInfo['aac']['header']['profile_id'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2));
$bitoffset += 2;
$ThisFileInfo['aac']['header']['profile_text'] = $this->AACprofileLookup($ThisFileInfo['aac']['header']['profile_id'], $ThisFileInfo['aac']['header']['mpeg_version']);
$ThisFileInfo['aac']['header']['sample_frequency_index'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4));
$bitoffset += 4;
$ThisFileInfo['aac']['header']['sample_frequency'] = $this->AACsampleRateLookup($ThisFileInfo['aac']['header']['sample_frequency_index']);
if ($ThisFileInfo['aac']['header']['sample_frequency'] == 0) {
$ThisFileInfo['error'][] = 'Corrupt AAC file: sample_frequency == zero';
return false;
}
$ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['aac']['header']['sample_frequency'];
$ThisFileInfo['aac']['header']['private'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
$bitoffset += 1;
$ThisFileInfo['aac']['header']['channel_configuration'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 3));
$bitoffset += 3;
$ThisFileInfo['audio']['channels'] = $ThisFileInfo['aac']['header']['channel_configuration'];
$ThisFileInfo['aac']['header']['original'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
$bitoffset += 1;
$ThisFileInfo['aac']['header']['home'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
$bitoffset += 1;
if ($ThisFileInfo['aac']['header']['mpeg_version'] == 4) {
$ThisFileInfo['aac']['header']['emphasis'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2));
$bitoffset += 2;
}
if ($ReturnExtendedInfo) {
$ThisFileInfo['aac'][$framenumber]['copyright_id_bit'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
$bitoffset += 1;
$ThisFileInfo['aac'][$framenumber]['copyright_id_start'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1));
$bitoffset += 1;
} else {
$bitoffset += 2;
}
}
$FrameLength = bindec(substr($AACheaderBitstream, $bitoffset, 13));
if (!isset($BitrateCache[$FrameLength])) {
$BitrateCache[$FrameLength] = ($ThisFileInfo['aac']['header']['sample_frequency'] / 1024) * $FrameLength * 8;
}
@$ThisFileInfo['aac']['bitrate_distribution'][$BitrateCache[$FrameLength]]++;
$ThisFileInfo['aac'][$framenumber]['aac_frame_length'] = $FrameLength;
$bitoffset += 13;
$ThisFileInfo['aac'][$framenumber]['adts_buffer_fullness'] = bindec(substr($AACheaderBitstream, $bitoffset, 11));
$bitoffset += 11;
if ($ThisFileInfo['aac'][$framenumber]['adts_buffer_fullness'] == 0x07FF) {
$ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
} else {
$ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
}
$ThisFileInfo['aac'][$framenumber]['num_raw_data_blocks'] = bindec(substr($AACheaderBitstream, $bitoffset, 2));
$bitoffset += 2;
if ($ThisFileInfo['aac']['header']['crc_present']) {
//$ThisFileInfo['aac'][$framenumber]['crc'] = bindec(substr($AACheaderBitstream, $bitoffset, 16));
$bitoffset += 16;
}
if (!$ReturnExtendedInfo) {
unset($ThisFileInfo['aac'][$framenumber]);
}
$byteoffset += $FrameLength;
if ((++$framenumber < $MaxFramesToScan) && (($byteoffset + 10) < $ThisFileInfo['avdataend'])) {
// keep scanning
} else {
$ThisFileInfo['aac']['frames'] = $framenumber;
$ThisFileInfo['playtime_seconds'] = ($ThisFileInfo['avdataend'] / $byteoffset) * (($framenumber * 1024) / $ThisFileInfo['aac']['header']['sample_frequency']); // (1 / % of file scanned) * (samples / (samples/sec)) = seconds
if ($ThisFileInfo['playtime_seconds'] == 0) {
$ThisFileInfo['error'][] = 'Corrupt AAC file: playtime_seconds == zero';
return false;
}
$ThisFileInfo['audio']['bitrate'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['playtime_seconds'];
ksort($ThisFileInfo['aac']['bitrate_distribution']);
$ThisFileInfo['audio']['encoder_options'] = $ThisFileInfo['aac']['header_type'].' '.$ThisFileInfo['aac']['header']['profile_text'];
return true;
}
}
// should never get here.
}
function AACsampleRateLookup($samplerateid) {
static $AACsampleRateLookup = array();
if (empty($AACsampleRateLookup)) {
$AACsampleRateLookup[0] = 96000;
$AACsampleRateLookup[1] = 88200;
$AACsampleRateLookup[2] = 64000;
$AACsampleRateLookup[3] = 48000;
$AACsampleRateLookup[4] = 44100;
$AACsampleRateLookup[5] = 32000;
$AACsampleRateLookup[6] = 24000;
$AACsampleRateLookup[7] = 22050;
$AACsampleRateLookup[8] = 16000;
$AACsampleRateLookup[9] = 12000;
$AACsampleRateLookup[10] = 11025;
$AACsampleRateLookup[11] = 8000;
$AACsampleRateLookup[12] = 0;
$AACsampleRateLookup[13] = 0;
$AACsampleRateLookup[14] = 0;
$AACsampleRateLookup[15] = 0;
}
return (isset($AACsampleRateLookup[$samplerateid]) ? $AACsampleRateLookup[$samplerateid] : 'invalid');
}
function AACprofileLookup($profileid, $mpegversion) {
static $AACprofileLookup = array();
if (empty($AACprofileLookup)) {
$AACprofileLookup[2][0] = 'Main profile';
$AACprofileLookup[2][1] = 'Low Complexity profile (LC)';
$AACprofileLookup[2][2] = 'Scalable Sample Rate profile (SSR)';
$AACprofileLookup[2][3] = '(reserved)';
$AACprofileLookup[4][0] = 'AAC_MAIN';
$AACprofileLookup[4][1] = 'AAC_LC';
$AACprofileLookup[4][2] = 'AAC_SSR';
$AACprofileLookup[4][3] = 'AAC_LTP';
}
return (isset($AACprofileLookup[$mpegversion][$profileid]) ? $AACprofileLookup[$mpegversion][$profileid] : 'invalid');
}
function AACchannelCountCalculate($program_configs) {
$channels = 0;
for ($i = 0; $i < $program_configs['num_front_channel_elements']; $i++) {
$channels++;
if ($program_configs['front_element_is_cpe'][$i]) {
// each front element is channel pair (CPE = Channel Pair Element)
$channels++;
}
}
for ($i = 0; $i < $program_configs['num_side_channel_elements']; $i++) {
$channels++;
if ($program_configs['side_element_is_cpe'][$i]) {
// each side element is channel pair (CPE = Channel Pair Element)
$channels++;
}
}
for ($i = 0; $i < $program_configs['num_back_channel_elements']; $i++) {
$channels++;
if ($program_configs['back_element_is_cpe'][$i]) {
// each back element is channel pair (CPE = Channel Pair Element)
$channels++;
}
}
for ($i = 0; $i < $program_configs['num_lfe_channel_elements']; $i++) {
$channels++;
}
return $channels;
}
}
?>

View File

@ -1,497 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio.ac3.php //
// module for analyzing AC-3 (aka Dolby Digital) audio files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_ac3
{
function getid3_ac3(&$fd, &$ThisFileInfo) {
///AH
$ThisFileInfo['ac3']['raw']['bsi'] = array();
$thisfile_ac3 = &$ThisFileInfo['ac3'];
$thisfile_ac3_raw = &$thisfile_ac3['raw'];
$thisfile_ac3_raw_bsi = &$thisfile_ac3_raw['bsi'];
// http://www.atsc.org/standards/a_52a.pdf
$ThisFileInfo['fileformat'] = 'ac3';
$ThisFileInfo['audio']['dataformat'] = 'ac3';
$ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
$ThisFileInfo['audio']['lossless'] = false;
// An AC-3 serial coded audio bit stream is made up of a sequence of synchronization frames
// Each synchronization frame contains 6 coded audio blocks (AB), each of which represent 256
// new audio samples per channel. A synchronization information (SI) header at the beginning
// of each frame contains information needed to acquire and maintain synchronization. A
// bit stream information (BSI) header follows SI, and contains parameters describing the coded
// audio service. The coded audio blocks may be followed by an auxiliary data (Aux) field. At the
// end of each frame is an error check field that includes a CRC word for error detection. An
// additional CRC word is located in the SI header, the use of which, by a decoder, is optional.
//
// syncinfo() | bsi() | AB0 | AB1 | AB2 | AB3 | AB4 | AB5 | Aux | CRC
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$AC3header['syncinfo'] = fread($fd, 5);
$thisfile_ac3_raw['synchinfo']['synchword'] = substr($AC3header['syncinfo'], 0, 2);
if ($thisfile_ac3_raw['synchinfo']['synchword'] != "\x0B\x77") {
$ThisFileInfo['error'][] = 'Expecting "\x0B\x77" at offset '.$ThisFileInfo['avdataoffset'].', found \x'.strtoupper(dechex($AC3header['syncinfo']{0})).'\x'.strtoupper(dechex($AC3header['syncinfo']{1})).' instead';
unset($thisfile_ac3);
return false;
} else {
// syncinfo() {
// syncword 16
// crc1 16
// fscod 2
// frmsizecod 6
// } /* end of syncinfo */
$thisfile_ac3_raw['synchinfo']['crc1'] = getid3_lib::LittleEndian2Int(substr($AC3header['syncinfo'], 2, 2));
$ac3_synchinfo_fscod_frmsizecod = getid3_lib::LittleEndian2Int(substr($AC3header['syncinfo'], 4, 1));
$thisfile_ac3_raw['synchinfo']['fscod'] = ($ac3_synchinfo_fscod_frmsizecod & 0xC0) >> 6;
$thisfile_ac3_raw['synchinfo']['frmsizecod'] = ($ac3_synchinfo_fscod_frmsizecod & 0x3F);
$thisfile_ac3['sample_rate'] = $this->AC3sampleRateCodeLookup($thisfile_ac3_raw['synchinfo']['fscod']);
if ($thisfile_ac3_raw['synchinfo']['fscod'] <= 3) {
$ThisFileInfo['audio']['sample_rate'] = $thisfile_ac3['sample_rate'];
}
$thisfile_ac3['frame_length'] = $this->AC3frameSizeLookup($thisfile_ac3_raw['synchinfo']['frmsizecod'], $thisfile_ac3_raw['synchinfo']['fscod']);
$thisfile_ac3['bitrate'] = $this->AC3bitrateLookup($thisfile_ac3_raw['synchinfo']['frmsizecod']);
$ThisFileInfo['audio']['bitrate'] = $thisfile_ac3['bitrate'];
$AC3header['bsi'] = getid3_lib::BigEndian2Bin(fread($fd, 15));
$ac3_bsi_offset = 0;
$thisfile_ac3_raw_bsi['bsid'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 5));
$ac3_bsi_offset += 5;
if ($thisfile_ac3_raw_bsi['bsid'] > 8) {
// Decoders which can decode version 8 will thus be able to decode version numbers less than 8.
// If this standard is extended by the addition of additional elements or features, a value of bsid greater than 8 will be used.
// Decoders built to this version of the standard will not be able to decode versions with bsid greater than 8.
$ThisFileInfo['error'][] = 'Bit stream identification is version '.$thisfile_ac3_raw_bsi['bsid'].', but getID3() only understands up to version 8';
unset($thisfile_ac3);
return false;
}
$thisfile_ac3_raw_bsi['bsmod'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 3));
$ac3_bsi_offset += 3;
$thisfile_ac3_raw_bsi['acmod'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 3));
$ac3_bsi_offset += 3;
$thisfile_ac3['service_type'] = $this->AC3serviceTypeLookup($thisfile_ac3_raw_bsi['bsmod'], $thisfile_ac3_raw_bsi['acmod']);
$ac3_coding_mode = $this->AC3audioCodingModeLookup($thisfile_ac3_raw_bsi['acmod']);
foreach($ac3_coding_mode as $key => $value) {
$thisfile_ac3[$key] = $value;
}
switch ($thisfile_ac3_raw_bsi['acmod']) {
case 0:
case 1:
$ThisFileInfo['audio']['channelmode'] = 'mono';
break;
case 3:
case 4:
$ThisFileInfo['audio']['channelmode'] = 'stereo';
break;
default:
$ThisFileInfo['audio']['channelmode'] = 'surround';
break;
}
$ThisFileInfo['audio']['channels'] = $thisfile_ac3['num_channels'];
if ($thisfile_ac3_raw_bsi['acmod'] & 0x01) {
// If the lsb of acmod is a 1, center channel is in use and cmixlev follows in the bit stream.
$thisfile_ac3_raw_bsi['cmixlev'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 2));
$ac3_bsi_offset += 2;
$thisfile_ac3['center_mix_level'] = $this->AC3centerMixLevelLookup($thisfile_ac3_raw_bsi['cmixlev']);
}
if ($thisfile_ac3_raw_bsi['acmod'] & 0x04) {
// If the msb of acmod is a 1, surround channels are in use and surmixlev follows in the bit stream.
$thisfile_ac3_raw_bsi['surmixlev'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 2));
$ac3_bsi_offset += 2;
$thisfile_ac3['surround_mix_level'] = $this->AC3surroundMixLevelLookup($thisfile_ac3_raw_bsi['surmixlev']);
}
if ($thisfile_ac3_raw_bsi['acmod'] == 0x02) {
// When operating in the two channel mode, this 2-bit code indicates whether or not the program has been encoded in Dolby Surround.
$thisfile_ac3_raw_bsi['dsurmod'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 2));
$ac3_bsi_offset += 2;
$thisfile_ac3['dolby_surround_mode'] = $this->AC3dolbySurroundModeLookup($thisfile_ac3_raw_bsi['dsurmod']);
}
$thisfile_ac3_raw_bsi['lfeon'] = (bool) bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 1));
$ac3_bsi_offset += 1;
$thisfile_ac3['lfe_enabled'] = $thisfile_ac3_raw_bsi['lfeon'];
if ($thisfile_ac3_raw_bsi['lfeon']) {
//$ThisFileInfo['audio']['channels']++;
$ThisFileInfo['audio']['channels'] .= '.1';
}
$thisfile_ac3['channels_enabled'] = $this->AC3channelsEnabledLookup($thisfile_ac3_raw_bsi['acmod'], $thisfile_ac3_raw_bsi['lfeon']);
// This indicates how far the average dialogue level is below digital 100 percent. Valid values are 131.
// The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent.
$thisfile_ac3_raw_bsi['dialnorm'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 5));
$ac3_bsi_offset += 5;
$thisfile_ac3['dialogue_normalization'] = '-'.$thisfile_ac3_raw_bsi['dialnorm'].'dB';
$thisfile_ac3_raw_bsi['compre_flag'] = (bool) bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 1));
$ac3_bsi_offset += 1;
if ($thisfile_ac3_raw_bsi['compre_flag']) {
$thisfile_ac3_raw_bsi['compr'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 8));
$ac3_bsi_offset += 8;
$thisfile_ac3['heavy_compression'] = $this->AC3heavyCompression($thisfile_ac3_raw_bsi['compr']);
}
$thisfile_ac3_raw_bsi['langcode_flag'] = (bool) bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 1));
$ac3_bsi_offset += 1;
if ($thisfile_ac3_raw_bsi['langcode_flag']) {
$thisfile_ac3_raw_bsi['langcod'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 8));
$ac3_bsi_offset += 8;
}
$thisfile_ac3_raw_bsi['audprodie'] = (bool) bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 1));
$ac3_bsi_offset += 1;
if ($thisfile_ac3_raw_bsi['audprodie']) {
$thisfile_ac3_raw_bsi['mixlevel'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 5));
$ac3_bsi_offset += 5;
$thisfile_ac3_raw_bsi['roomtyp'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 2));
$ac3_bsi_offset += 2;
$thisfile_ac3['mixing_level'] = (80 + $thisfile_ac3_raw_bsi['mixlevel']).'dB';
$thisfile_ac3['room_type'] = $this->AC3roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp']);
}
if ($thisfile_ac3_raw_bsi['acmod'] == 0x00) {
// If acmod is 0, then two completely independent program channels (dual mono)
// are encoded into the bit stream, and are referenced as Ch1, Ch2. In this case,
// a number of additional items are present in BSI or audblk to fully describe Ch2.
// This indicates how far the average dialogue level is below digital 100 percent. Valid values are 131.
// The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent.
$thisfile_ac3_raw_bsi['dialnorm2'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 5));
$ac3_bsi_offset += 5;
$thisfile_ac3['dialogue_normalization2'] = '-'.$thisfile_ac3_raw_bsi['dialnorm2'].'dB';
$thisfile_ac3_raw_bsi['compre_flag2'] = (bool) bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 1));
$ac3_bsi_offset += 1;
if ($thisfile_ac3_raw_bsi['compre_flag2']) {
$thisfile_ac3_raw_bsi['compr2'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 8));
$ac3_bsi_offset += 8;
$thisfile_ac3['heavy_compression2'] = $this->AC3heavyCompression($thisfile_ac3_raw_bsi['compr2']);
}
$thisfile_ac3_raw_bsi['langcode_flag2'] = (bool) bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 1));
$ac3_bsi_offset += 1;
if ($thisfile_ac3_raw_bsi['langcode_flag2']) {
$thisfile_ac3_raw_bsi['langcod2'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 8));
$ac3_bsi_offset += 8;
}
$thisfile_ac3_raw_bsi['audprodie2'] = (bool) bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 1));
$ac3_bsi_offset += 1;
if ($thisfile_ac3_raw_bsi['audprodie2']) {
$thisfile_ac3_raw_bsi['mixlevel2'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 5));
$ac3_bsi_offset += 5;
$thisfile_ac3_raw_bsi['roomtyp2'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 2));
$ac3_bsi_offset += 2;
$thisfile_ac3['mixing_level2'] = (80 + $thisfile_ac3_raw_bsi['mixlevel2']).'dB';
$thisfile_ac3['room_type2'] = $this->AC3roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp2']);
}
}
$thisfile_ac3_raw_bsi['copyright'] = (bool) bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 1));
$ac3_bsi_offset += 1;
$thisfile_ac3_raw_bsi['original'] = (bool) bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 1));
$ac3_bsi_offset += 1;
$thisfile_ac3_raw_bsi['timecode1_flag'] = (bool) bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 1));
$ac3_bsi_offset += 1;
if ($thisfile_ac3_raw_bsi['timecode1_flag']) {
$thisfile_ac3_raw_bsi['timecode1'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 14));
$ac3_bsi_offset += 14;
}
$thisfile_ac3_raw_bsi['timecode2_flag'] = (bool) bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 1));
$ac3_bsi_offset += 1;
if ($thisfile_ac3_raw_bsi['timecode2_flag']) {
$thisfile_ac3_raw_bsi['timecode2'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 14));
$ac3_bsi_offset += 14;
}
$thisfile_ac3_raw_bsi['addbsi_flag'] = (bool) bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 1));
$ac3_bsi_offset += 1;
if ($thisfile_ac3_raw_bsi['addbsi_flag']) {
$thisfile_ac3_raw_bsi['addbsi_length'] = bindec(substr($AC3header['bsi'], $ac3_bsi_offset, 6));
$ac3_bsi_offset += 6;
$AC3header['bsi'] .= getid3_lib::BigEndian2Bin(fread($fd, $thisfile_ac3_raw_bsi['addbsi_length']));
$thisfile_ac3_raw_bsi['addbsi_data'] = substr($AC3header['bsi'], $ac3_bsi_offset, $thisfile_ac3_raw_bsi['addbsi_length'] * 8);
$ac3_bsi_offset += $thisfile_ac3_raw_bsi['addbsi_length'] * 8;
}
}
return true;
}
function AC3sampleRateCodeLookup($fscod) {
static $AC3sampleRateCodeLookup = array(
0 => 48000,
1 => 44100,
2 => 32000,
3 => 'reserved' // If the reserved code is indicated, the decoder should not attempt to decode audio and should mute.
);
return (isset($AC3sampleRateCodeLookup[$fscod]) ? $AC3sampleRateCodeLookup[$fscod] : false);
}
function AC3serviceTypeLookup($bsmod, $acmod) {
static $AC3serviceTypeLookup = array();
if (empty($AC3serviceTypeLookup)) {
for ($i = 0; $i <= 7; $i++) {
$AC3serviceTypeLookup[0][$i] = 'main audio service: complete main (CM)';
$AC3serviceTypeLookup[1][$i] = 'main audio service: music and effects (ME)';
$AC3serviceTypeLookup[2][$i] = 'associated service: visually impaired (VI)';
$AC3serviceTypeLookup[3][$i] = 'associated service: hearing impaired (HI)';
$AC3serviceTypeLookup[4][$i] = 'associated service: dialogue (D)';
$AC3serviceTypeLookup[5][$i] = 'associated service: commentary (C)';
$AC3serviceTypeLookup[6][$i] = 'associated service: emergency (E)';
}
$AC3serviceTypeLookup[7][1] = 'associated service: voice over (VO)';
for ($i = 2; $i <= 7; $i++) {
$AC3serviceTypeLookup[7][$i] = 'main audio service: karaoke';
}
}
return (isset($AC3serviceTypeLookup[$bsmod][$acmod]) ? $AC3serviceTypeLookup[$bsmod][$acmod] : false);
}
function AC3audioCodingModeLookup($acmod) {
static $AC3audioCodingModeLookup = array();
if (empty($AC3audioCodingModeLookup)) {
// array(channel configuration, # channels (not incl LFE), channel order)
$AC3audioCodingModeLookup = array (
0 => array('channel_config'=>'1+1', 'num_channels'=>2, 'channel_order'=>'Ch1,Ch2'),
1 => array('channel_config'=>'1/0', 'num_channels'=>1, 'channel_order'=>'C'),
2 => array('channel_config'=>'2/0', 'num_channels'=>2, 'channel_order'=>'L,R'),
3 => array('channel_config'=>'3/0', 'num_channels'=>3, 'channel_order'=>'L,C,R'),
4 => array('channel_config'=>'2/1', 'num_channels'=>3, 'channel_order'=>'L,R,S'),
5 => array('channel_config'=>'3/1', 'num_channels'=>4, 'channel_order'=>'L,C,R,S'),
6 => array('channel_config'=>'2/2', 'num_channels'=>4, 'channel_order'=>'L,R,SL,SR'),
7 => array('channel_config'=>'3/2', 'num_channels'=>5, 'channel_order'=>'L,C,R,SL,SR')
);
}
return (isset($AC3audioCodingModeLookup[$acmod]) ? $AC3audioCodingModeLookup[$acmod] : false);
}
function AC3centerMixLevelLookup($cmixlev) {
static $AC3centerMixLevelLookup;
if (empty($AC3centerMixLevelLookup)) {
$AC3centerMixLevelLookup = array(
0 => pow(2, -3.0 / 6), // 0.707 (3.0 dB)
1 => pow(2, -4.5 / 6), // 0.595 (4.5 dB)
2 => pow(2, -6.0 / 6), // 0.500 (6.0 dB)
3 => 'reserved'
);
}
return (isset($AC3centerMixLevelLookup[$cmixlev]) ? $AC3centerMixLevelLookup[$cmixlev] : false);
}
function AC3surroundMixLevelLookup($surmixlev) {
static $AC3surroundMixLevelLookup;
if (empty($AC3surroundMixLevelLookup)) {
$AC3surroundMixLevelLookup = array(
0 => pow(2, -3.0 / 6),
1 => pow(2, -6.0 / 6),
2 => 0,
3 => 'reserved'
);
}
return (isset($AC3surroundMixLevelLookup[$surmixlev]) ? $AC3surroundMixLevelLookup[$surmixlev] : false);
}
function AC3dolbySurroundModeLookup($dsurmod) {
static $AC3dolbySurroundModeLookup = array(
0 => 'not indicated',
1 => 'Not Dolby Surround encoded',
2 => 'Dolby Surround encoded',
3 => 'reserved'
);
return (isset($AC3dolbySurroundModeLookup[$dsurmod]) ? $AC3dolbySurroundModeLookup[$dsurmod] : false);
}
function AC3channelsEnabledLookup($acmod, $lfeon) {
$AC3channelsEnabledLookup = array(
'ch1'=>(bool) ($acmod == 0),
'ch2'=>(bool) ($acmod == 0),
'left'=>(bool) ($acmod > 1),
'right'=>(bool) ($acmod > 1),
'center'=>(bool) ($acmod & 0x01),
'surround_mono'=>false,
'surround_left'=>false,
'surround_right'=>false,
'lfe'=>$lfeon);
switch ($acmod) {
case 4:
case 5:
$AC3channelsEnabledLookup['surround_mono'] = true;
break;
case 6:
case 7:
$AC3channelsEnabledLookup['surround_left'] = true;
$AC3channelsEnabledLookup['surround_right'] = true;
break;
}
return $AC3channelsEnabledLookup;
}
function AC3heavyCompression($compre) {
// The first four bits indicate gain changes in 6.02dB increments which can be
// implemented with an arithmetic shift operation. The following four bits
// indicate linear gain changes, and require a 5-bit multiply.
// We will represent the two 4-bit fields of compr as follows:
// X0 X1 X2 X3 . Y4 Y5 Y6 Y7
// The meaning of the X values is most simply described by considering X to represent a 4-bit
// signed integer with values from 8 to +7. The gain indicated by X is then (X + 1) * 6.02 dB. The
// following table shows this in detail.
// Meaning of 4 msb of compr
// 7 +48.16 dB
// 6 +42.14 dB
// 5 +36.12 dB
// 4 +30.10 dB
// 3 +24.08 dB
// 2 +18.06 dB
// 1 +12.04 dB
// 0 +6.02 dB
// -1 0 dB
// -2 6.02 dB
// -3 12.04 dB
// -4 18.06 dB
// -5 24.08 dB
// -6 30.10 dB
// -7 36.12 dB
// -8 42.14 dB
$fourbit = str_pad(decbin(($compre & 0xF0) >> 4), 4, '0', STR_PAD_LEFT);
if ($fourbit{0} == '1') {
$log_gain = -8 + bindec(substr($fourbit, 1));
} else {
$log_gain = bindec(substr($fourbit, 1));
}
$log_gain = ($log_gain + 1) * getid3_lib::RGADamplitude2dB(2);
// The value of Y is a linear representation of a gain change of up to 6 dB. Y is considered to
// be an unsigned fractional integer, with a leading value of 1, or: 0.1 Y4 Y5 Y6 Y7 (base 2). Y can
// represent values between 0.111112 (or 31/32) and 0.100002 (or 1/2). Thus, Y can represent gain
// changes from 0.28 dB to 6.02 dB.
$lin_gain = (16 + ($compre & 0x0F)) / 32;
// The combination of X and Y values allows compr to indicate gain changes from
// 48.16 0.28 = +47.89 dB, to
// 42.14 6.02 = 48.16 dB.
return $log_gain - $lin_gain;
}
function AC3roomTypeLookup($roomtyp) {
static $AC3roomTypeLookup = array(
0 => 'not indicated',
1 => 'large room, X curve monitor',
2 => 'small room, flat monitor',
3 => 'reserved'
);
return (isset($AC3roomTypeLookup[$roomtyp]) ? $AC3roomTypeLookup[$roomtyp] : false);
}
function AC3frameSizeLookup($frmsizecod, $fscod) {
$padding = (bool) ($frmsizecod % 2);
$framesizeid = floor($frmsizecod / 2);
static $AC3frameSizeLookup = array();
if (empty($AC3frameSizeLookup)) {
$AC3frameSizeLookup = array (
0 => array(128, 138, 192),
1 => array(40, 160, 174, 240),
2 => array(48, 192, 208, 288),
3 => array(56, 224, 242, 336),
4 => array(64, 256, 278, 384),
5 => array(80, 320, 348, 480),
6 => array(96, 384, 416, 576),
7 => array(112, 448, 486, 672),
8 => array(128, 512, 556, 768),
9 => array(160, 640, 696, 960),
10 => array(192, 768, 834, 1152),
11 => array(224, 896, 974, 1344),
12 => array(256, 1024, 1114, 1536),
13 => array(320, 1280, 1392, 1920),
14 => array(384, 1536, 1670, 2304),
15 => array(448, 1792, 1950, 2688),
16 => array(512, 2048, 2228, 3072),
17 => array(576, 2304, 2506, 3456),
18 => array(640, 2560, 2786, 3840)
);
}
if (($fscod == 1) && $padding) {
// frame lengths are padded by 1 word (16 bits) at 44100
$AC3frameSizeLookup[$frmsizecod] += 2;
}
return (isset($AC3frameSizeLookup[$framesizeid][$fscod]) ? $AC3frameSizeLookup[$framesizeid][$fscod] : false);
}
function AC3bitrateLookup($frmsizecod) {
$framesizeid = floor($frmsizecod / 2);
static $AC3bitrateLookup = array(
0 => 32000,
1 => 40000,
2 => 48000,
3 => 56000,
4 => 64000,
5 => 80000,
6 => 96000,
7 => 112000,
8 => 128000,
9 => 160000,
10 => 192000,
11 => 224000,
12 => 256000,
13 => 320000,
14 => 384000,
15 => 448000,
16 => 512000,
17 => 576000,
18 => 640000
);
return (isset($AC3bitrateLookup[$framesizeid]) ? $AC3bitrateLookup[$framesizeid] : false);
}
}
?>

View File

@ -1,163 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio.au.php //
// module for analyzing AU files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_au
{
function getid3_au(&$fd, &$ThisFileInfo) {
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$AUheader = fread($fd, 8);
if (substr($AUheader, 0, 4) != '.snd') {
$ThisFileInfo['error'][] = 'Expecting ".snd" at offset '.$ThisFileInfo['avdataoffset'].', found "'.substr($AUheader, 0, 4).'"';
return false;
}
// shortcut
$ThisFileInfo['au'] = array();
$thisfile_au = &$ThisFileInfo['au'];
$ThisFileInfo['fileformat'] = 'au';
$ThisFileInfo['audio']['dataformat'] = 'au';
$ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
$thisfile_au['encoding'] = 'ISO-8859-1';
$thisfile_au['header_length'] = getid3_lib::BigEndian2Int(substr($AUheader, 4, 4));
$AUheader .= fread($fd, $thisfile_au['header_length'] - 8);
$ThisFileInfo['avdataoffset'] += $thisfile_au['header_length'];
$thisfile_au['data_size'] = getid3_lib::BigEndian2Int(substr($AUheader, 8, 4));
$thisfile_au['data_format_id'] = getid3_lib::BigEndian2Int(substr($AUheader, 12, 4));
$thisfile_au['sample_rate'] = getid3_lib::BigEndian2Int(substr($AUheader, 16, 4));
$thisfile_au['channels'] = getid3_lib::BigEndian2Int(substr($AUheader, 20, 4));
$thisfile_au['comments']['comment'][] = trim(substr($AUheader, 24));
$thisfile_au['data_format'] = $this->AUdataFormatNameLookup($thisfile_au['data_format_id']);
$thisfile_au['used_bits_per_sample'] = $this->AUdataFormatUsedBitsPerSampleLookup($thisfile_au['data_format_id']);
if ($thisfile_au['bits_per_sample'] = $this->AUdataFormatBitsPerSampleLookup($thisfile_au['data_format_id'])) {
$ThisFileInfo['audio']['bits_per_sample'] = $thisfile_au['bits_per_sample'];
} else {
unset($thisfile_au['bits_per_sample']);
}
$ThisFileInfo['audio']['sample_rate'] = $thisfile_au['sample_rate'];
$ThisFileInfo['audio']['channels'] = $thisfile_au['channels'];
if (($ThisFileInfo['avdataoffset'] + $thisfile_au['data_size']) > $ThisFileInfo['avdataend']) {
$ThisFileInfo['warning'][] = 'Possible truncated file - expecting "'.$thisfile_au['data_size'].'" bytes of audio data, only found '.($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']).' bytes"';
}
$ThisFileInfo['playtime_seconds'] = $thisfile_au['data_size'] / ($thisfile_au['sample_rate'] * $thisfile_au['channels'] * ($thisfile_au['used_bits_per_sample'] / 8));
$ThisFileInfo['audio']['bitrate'] = ($thisfile_au['data_size'] * 8) / $ThisFileInfo['playtime_seconds'];
return true;
}
function AUdataFormatNameLookup($id) {
static $AUdataFormatNameLookup = array(
0 => 'unspecified format',
1 => '8-bit mu-law',
2 => '8-bit linear',
3 => '16-bit linear',
4 => '24-bit linear',
5 => '32-bit linear',
6 => 'floating-point',
7 => 'double-precision float',
8 => 'fragmented sampled data',
9 => 'SUN_FORMAT_NESTED',
10 => 'DSP program',
11 => '8-bit fixed-point',
12 => '16-bit fixed-point',
13 => '24-bit fixed-point',
14 => '32-bit fixed-point',
16 => 'non-audio display data',
17 => 'SND_FORMAT_MULAW_SQUELCH',
18 => '16-bit linear with emphasis',
19 => '16-bit linear with compression',
20 => '16-bit linear with emphasis + compression',
21 => 'Music Kit DSP commands',
22 => 'SND_FORMAT_DSP_COMMANDS_SAMPLES',
23 => 'CCITT g.721 4-bit ADPCM',
24 => 'CCITT g.722 ADPCM',
25 => 'CCITT g.723 3-bit ADPCM',
26 => 'CCITT g.723 5-bit ADPCM',
27 => 'A-Law 8-bit'
);
return (isset($AUdataFormatNameLookup[$id]) ? $AUdataFormatNameLookup[$id] : false);
}
function AUdataFormatBitsPerSampleLookup($id) {
static $AUdataFormatBitsPerSampleLookup = array(
1 => 8,
2 => 8,
3 => 16,
4 => 24,
5 => 32,
6 => 32,
7 => 64,
11 => 8,
12 => 16,
13 => 24,
14 => 32,
18 => 16,
19 => 16,
20 => 16,
23 => 16,
25 => 16,
26 => 16,
27 => 8
);
return (isset($AUdataFormatBitsPerSampleLookup[$id]) ? $AUdataFormatBitsPerSampleLookup[$id] : false);
}
function AUdataFormatUsedBitsPerSampleLookup($id) {
static $AUdataFormatUsedBitsPerSampleLookup = array(
1 => 8,
2 => 8,
3 => 16,
4 => 24,
5 => 32,
6 => 32,
7 => 64,
11 => 8,
12 => 16,
13 => 24,
14 => 32,
18 => 16,
19 => 16,
20 => 16,
23 => 4,
25 => 3,
26 => 5,
27 => 8,
);
return (isset($AUdataFormatUsedBitsPerSampleLookup[$id]) ? $AUdataFormatUsedBitsPerSampleLookup[$id] : false);
}
}
?>

View File

@ -1,125 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio.avr.php //
// module for analyzing AVR Audio files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_avr
{
function getid3_avr(&$fd, &$ThisFileInfo) {
// http://cui.unige.ch/OSG/info/AudioFormats/ap11.html
// http://www.btinternet.com/~AnthonyJ/Atari/programming/avr_format.html
// offset type length name comments
// ---------------------------------------------------------------------
// 0 char 4 ID format ID == "2BIT"
// 4 char 8 name sample name (unused space filled with 0)
// 12 short 1 mono/stereo 0=mono, -1 (0xFFFF)=stereo
// With stereo, samples are alternated,
// the first voice is the left :
// (LRLRLRLRLRLRLRLRLR...)
// 14 short 1 resolution 8, 12 or 16 (bits)
// 16 short 1 signed or not 0=unsigned, -1 (0xFFFF)=signed
// 18 short 1 loop or not 0=no loop, -1 (0xFFFF)=loop on
// 20 short 1 MIDI note 0xFFnn, where 0 <= nn <= 127
// 0xFFFF means "no MIDI note defined"
// 22 byte 1 Replay speed Frequence in the Replay software
// 0=5.485 Khz, 1=8.084 Khz, 2=10.971 Khz,
// 3=16.168 Khz, 4=21.942 Khz, 5=32.336 Khz
// 6=43.885 Khz, 7=47.261 Khz
// -1 (0xFF)=no defined Frequence
// 23 byte 3 sample rate in Hertz
// 26 long 1 size in bytes (2 * bytes in stereo)
// 30 long 1 loop begin 0 for no loop
// 34 long 1 loop size equal to 'size' for no loop
// 38 short 2 Reserved, MIDI keyboard split */
// 40 short 2 Reserved, sample compression */
// 42 short 2 Reserved */
// 44 char 20; Additional filename space, used if (name[7] != 0)
// 64 byte 64 user data
// 128 bytes ? sample data (12 bits samples are coded on 16 bits:
// 0000 xxxx xxxx xxxx)
// ---------------------------------------------------------------------
// Note that all values are in motorola (big-endian) format, and that long is
// assumed to be 4 bytes, and short 2 bytes.
// When reading the samples, you should handle both signed and unsigned data,
// and be prepared to convert 16->8 bit, or mono->stereo if needed. To convert
// 8-bit data between signed/unsigned just add 127 to the sample values.
// Simularly for 16-bit data you should add 32769
$ThisFileInfo['fileformat'] = 'avr';
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$AVRheader = fread($fd, 128);
$ThisFileInfo['avr']['raw']['magic'] = substr($AVRheader, 0, 4);
if ($ThisFileInfo['avr']['raw']['magic'] != '2BIT') {
$ThisFileInfo['error'][] = 'Expecting "2BIT" at offset '.$ThisFileInfo['avdataoffset'].', found "'.$ThisFileInfo['avr']['raw']['magic'].'"';
unset($ThisFileInfo['fileformat']);
unset($ThisFileInfo['avr']);
return false;
}
$ThisFileInfo['avdataoffset'] += 128;
$ThisFileInfo['avr']['sample_name'] = rtrim(substr($AVRheader, 4, 8));
$ThisFileInfo['avr']['raw']['mono'] = getid3_lib::BigEndian2Int(substr($AVRheader, 12, 2));
$ThisFileInfo['avr']['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($AVRheader, 14, 2));
$ThisFileInfo['avr']['raw']['signed'] = getid3_lib::BigEndian2Int(substr($AVRheader, 16, 2));
$ThisFileInfo['avr']['raw']['loop'] = getid3_lib::BigEndian2Int(substr($AVRheader, 18, 2));
$ThisFileInfo['avr']['raw']['midi'] = getid3_lib::BigEndian2Int(substr($AVRheader, 20, 2));
$ThisFileInfo['avr']['raw']['replay_freq'] = getid3_lib::BigEndian2Int(substr($AVRheader, 22, 1));
$ThisFileInfo['avr']['sample_rate'] = getid3_lib::BigEndian2Int(substr($AVRheader, 23, 3));
$ThisFileInfo['avr']['sample_length'] = getid3_lib::BigEndian2Int(substr($AVRheader, 26, 4));
$ThisFileInfo['avr']['loop_start'] = getid3_lib::BigEndian2Int(substr($AVRheader, 30, 4));
$ThisFileInfo['avr']['loop_end'] = getid3_lib::BigEndian2Int(substr($AVRheader, 34, 4));
$ThisFileInfo['avr']['midi_split'] = getid3_lib::BigEndian2Int(substr($AVRheader, 38, 2));
$ThisFileInfo['avr']['sample_compression'] = getid3_lib::BigEndian2Int(substr($AVRheader, 40, 2));
$ThisFileInfo['avr']['reserved'] = getid3_lib::BigEndian2Int(substr($AVRheader, 42, 2));
$ThisFileInfo['avr']['sample_name_extra'] = rtrim(substr($AVRheader, 44, 20));
$ThisFileInfo['avr']['comment'] = rtrim(substr($AVRheader, 64, 64));
$ThisFileInfo['avr']['flags']['stereo'] = (($ThisFileInfo['avr']['raw']['mono'] == 0) ? false : true);
$ThisFileInfo['avr']['flags']['signed'] = (($ThisFileInfo['avr']['raw']['signed'] == 0) ? false : true);
$ThisFileInfo['avr']['flags']['loop'] = (($ThisFileInfo['avr']['raw']['loop'] == 0) ? false : true);
$ThisFileInfo['avr']['midi_notes'] = array();
if (($ThisFileInfo['avr']['raw']['midi'] & 0xFF00) != 0xFF00) {
$ThisFileInfo['avr']['midi_notes'][] = ($ThisFileInfo['avr']['raw']['midi'] & 0xFF00) >> 8;
}
if (($ThisFileInfo['avr']['raw']['midi'] & 0x00FF) != 0x00FF) {
$ThisFileInfo['avr']['midi_notes'][] = ($ThisFileInfo['avr']['raw']['midi'] & 0x00FF);
}
if (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) != ($ThisFileInfo['avr']['sample_length'] * (($ThisFileInfo['avr']['bits_per_sample'] == 8) ? 1 : 2))) {
$ThisFileInfo['warning'][] = 'Probable truncated file: expecting '.($ThisFileInfo['avr']['sample_length'] * (($ThisFileInfo['avr']['bits_per_sample'] == 8) ? 1 : 2)).' bytes of audio data, found '.($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']);
}
$ThisFileInfo['audio']['dataformat'] = 'avr';
$ThisFileInfo['audio']['lossless'] = true;
$ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
$ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['avr']['bits_per_sample'];
$ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['avr']['sample_rate'];
$ThisFileInfo['audio']['channels'] = ($ThisFileInfo['avr']['flags']['stereo'] ? 2 : 1);
$ThisFileInfo['playtime_seconds'] = ($ThisFileInfo['avr']['sample_length'] / $ThisFileInfo['audio']['channels']) / $ThisFileInfo['avr']['sample_rate'];
$ThisFileInfo['audio']['bitrate'] = ($ThisFileInfo['avr']['sample_length'] * (($ThisFileInfo['avr']['bits_per_sample'] == 8) ? 8 : 16)) / $ThisFileInfo['playtime_seconds'];
return true;
}
}
?>

View File

@ -1,221 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio.la.php //
// module for analyzing BONK audio files //
// dependencies: module.tag.id3v2.php (optional) //
// ///
/////////////////////////////////////////////////////////////////
class getid3_bonk
{
function getid3_bonk(&$fd, &$ThisFileInfo) {
// shortcut
$ThisFileInfo['bonk'] = array();
$thisfile_bonk = &$ThisFileInfo['bonk'];
$thisfile_bonk['dataoffset'] = $ThisFileInfo['avdataoffset'];
$thisfile_bonk['dataend'] = $ThisFileInfo['avdataend'];
if ($thisfile_bonk['dataend'] >= pow(2, 31)) {
$ThisFileInfo['warning'][] = 'Unable to parse BONK file from end (v0.6+ preferred method) because PHP filesystem functions only support up to 2GB';
} else {
// scan-from-end method, for v0.6 and higher
fseek($fd, $thisfile_bonk['dataend'] - 8, SEEK_SET);
$PossibleBonkTag = fread($fd, 8);
while ($this->BonkIsValidTagName(substr($PossibleBonkTag, 4, 4), true)) {
$BonkTagSize = getid3_lib::LittleEndian2Int(substr($PossibleBonkTag, 0, 4));
fseek($fd, 0 - $BonkTagSize, SEEK_CUR);
$BonkTagOffset = ftell($fd);
$TagHeaderTest = fread($fd, 5);
if (($TagHeaderTest{0} != "\x00") || (substr($PossibleBonkTag, 4, 4) != strtolower(substr($PossibleBonkTag, 4, 4)))) {
$ThisFileInfo['error'][] = 'Expecting "Ø'.strtoupper(substr($PossibleBonkTag, 4, 4)).'" at offset '.$BonkTagOffset.', found "'.$TagHeaderTest.'"';
return false;
}
$BonkTagName = substr($TagHeaderTest, 1, 4);
$thisfile_bonk[$BonkTagName]['size'] = $BonkTagSize;
$thisfile_bonk[$BonkTagName]['offset'] = $BonkTagOffset;
$this->HandleBonkTags($fd, $BonkTagName, $ThisFileInfo);
$NextTagEndOffset = $BonkTagOffset - 8;
if ($NextTagEndOffset < $thisfile_bonk['dataoffset']) {
if (empty($ThisFileInfo['audio']['encoder'])) {
$ThisFileInfo['audio']['encoder'] = 'Extended BONK v0.9+';
}
return true;
}
fseek($fd, $NextTagEndOffset, SEEK_SET);
$PossibleBonkTag = fread($fd, 8);
}
}
// seek-from-beginning method for v0.4 and v0.5
if (empty($thisfile_bonk['BONK'])) {
fseek($fd, $thisfile_bonk['dataoffset'], SEEK_SET);
do {
$TagHeaderTest = fread($fd, 5);
switch ($TagHeaderTest) {
case "\x00".'BONK':
if (empty($ThisFileInfo['audio']['encoder'])) {
$ThisFileInfo['audio']['encoder'] = 'BONK v0.4';
}
break;
case "\x00".'INFO':
$ThisFileInfo['audio']['encoder'] = 'Extended BONK v0.5';
break;
default:
break 2;
}
$BonkTagName = substr($TagHeaderTest, 1, 4);
$thisfile_bonk[$BonkTagName]['size'] = $thisfile_bonk['dataend'] - $thisfile_bonk['dataoffset'];
$thisfile_bonk[$BonkTagName]['offset'] = $thisfile_bonk['dataoffset'];
$this->HandleBonkTags($fd, $BonkTagName, $ThisFileInfo);
} while (true);
}
// parse META block for v0.6 - v0.8
if (empty($thisfile_bonk['INFO']) && isset($thisfile_bonk['META']['tags']['info'])) {
fseek($fd, $thisfile_bonk['META']['tags']['info'], SEEK_SET);
$TagHeaderTest = fread($fd, 5);
if ($TagHeaderTest == "\x00".'INFO') {
$ThisFileInfo['audio']['encoder'] = 'Extended BONK v0.6 - v0.8';
$BonkTagName = substr($TagHeaderTest, 1, 4);
$thisfile_bonk[$BonkTagName]['size'] = $thisfile_bonk['dataend'] - $thisfile_bonk['dataoffset'];
$thisfile_bonk[$BonkTagName]['offset'] = $thisfile_bonk['dataoffset'];
$this->HandleBonkTags($fd, $BonkTagName, $ThisFileInfo);
}
}
if (empty($ThisFileInfo['audio']['encoder'])) {
$ThisFileInfo['audio']['encoder'] = 'Extended BONK v0.9+';
}
if (empty($thisfile_bonk['BONK'])) {
unset($ThisFileInfo['bonk']);
}
return true;
}
function HandleBonkTags(&$fd, &$BonkTagName, &$ThisFileInfo) {
switch ($BonkTagName) {
case 'BONK':
// shortcut
$thisfile_bonk_BONK = &$ThisFileInfo['bonk']['BONK'];
$BonkData = "\x00".'BONK'.fread($fd, 17);
$thisfile_bonk_BONK['version'] = getid3_lib::LittleEndian2Int(substr($BonkData, 5, 1));
$thisfile_bonk_BONK['number_samples'] = getid3_lib::LittleEndian2Int(substr($BonkData, 6, 4));
$thisfile_bonk_BONK['sample_rate'] = getid3_lib::LittleEndian2Int(substr($BonkData, 10, 4));
$thisfile_bonk_BONK['channels'] = getid3_lib::LittleEndian2Int(substr($BonkData, 14, 1));
$thisfile_bonk_BONK['lossless'] = (bool) getid3_lib::LittleEndian2Int(substr($BonkData, 15, 1));
$thisfile_bonk_BONK['joint_stereo'] = (bool) getid3_lib::LittleEndian2Int(substr($BonkData, 16, 1));
$thisfile_bonk_BONK['number_taps'] = getid3_lib::LittleEndian2Int(substr($BonkData, 17, 2));
$thisfile_bonk_BONK['downsampling_ratio'] = getid3_lib::LittleEndian2Int(substr($BonkData, 19, 1));
$thisfile_bonk_BONK['samples_per_packet'] = getid3_lib::LittleEndian2Int(substr($BonkData, 20, 2));
$ThisFileInfo['avdataoffset'] = $thisfile_bonk_BONK['offset'] + 5 + 17;
$ThisFileInfo['avdataend'] = $thisfile_bonk_BONK['offset'] + $thisfile_bonk_BONK['size'];
$ThisFileInfo['fileformat'] = 'bonk';
$ThisFileInfo['audio']['dataformat'] = 'bonk';
$ThisFileInfo['audio']['bitrate_mode'] = 'vbr'; // assumed
$ThisFileInfo['audio']['channels'] = $thisfile_bonk_BONK['channels'];
$ThisFileInfo['audio']['sample_rate'] = $thisfile_bonk_BONK['sample_rate'];
$ThisFileInfo['audio']['channelmode'] = ($thisfile_bonk_BONK['joint_stereo'] ? 'joint stereo' : 'stereo');
$ThisFileInfo['audio']['lossless'] = $thisfile_bonk_BONK['lossless'];
$ThisFileInfo['audio']['codec'] = 'bonk';
$ThisFileInfo['playtime_seconds'] = $thisfile_bonk_BONK['number_samples'] / ($thisfile_bonk_BONK['sample_rate'] * $thisfile_bonk_BONK['channels']);
if ($ThisFileInfo['playtime_seconds'] > 0) {
$ThisFileInfo['audio']['bitrate'] = (($ThisFileInfo['bonk']['dataend'] - $ThisFileInfo['bonk']['dataoffset']) * 8) / $ThisFileInfo['playtime_seconds'];
}
break;
case 'INFO':
// shortcut
$thisfile_bonk_INFO = &$ThisFileInfo['bonk']['INFO'];
$thisfile_bonk_INFO['version'] = getid3_lib::LittleEndian2Int(fread($fd, 1));
$thisfile_bonk_INFO['entries_count'] = 0;
$NextInfoDataPair = fread($fd, 5);
if (!$this->BonkIsValidTagName(substr($NextInfoDataPair, 1, 4))) {
while (!feof($fd)) {
//$CurrentSeekInfo['offset'] = getid3_lib::LittleEndian2Int(substr($NextInfoDataPair, 0, 4));
//$CurrentSeekInfo['nextbit'] = getid3_lib::LittleEndian2Int(substr($NextInfoDataPair, 4, 1));
//$thisfile_bonk_INFO[] = $CurrentSeekInfo;
$NextInfoDataPair = fread($fd, 5);
if ($this->BonkIsValidTagName(substr($NextInfoDataPair, 1, 4))) {
fseek($fd, -5, SEEK_CUR);
break;
}
$thisfile_bonk_INFO['entries_count']++;
}
}
break;
case 'META':
$BonkData = "\x00".'META'.fread($fd, $ThisFileInfo['bonk']['META']['size'] - 5);
$ThisFileInfo['bonk']['META']['version'] = getid3_lib::LittleEndian2Int(substr($BonkData, 5, 1));
$MetaTagEntries = floor(((strlen($BonkData) - 8) - 6) / 8); // BonkData - xxxxmeta - ØMETA
$offset = 6;
for ($i = 0; $i < $MetaTagEntries; $i++) {
$MetaEntryTagName = substr($BonkData, $offset, 4);
$offset += 4;
$MetaEntryTagOffset = getid3_lib::LittleEndian2Int(substr($BonkData, $offset, 4));
$offset += 4;
$ThisFileInfo['bonk']['META']['tags'][$MetaEntryTagName] = $MetaEntryTagOffset;
}
break;
case ' ID3':
$ThisFileInfo['audio']['encoder'] = 'Extended BONK v0.9+';
// ID3v2 checking is optional
if (class_exists('getid3_id3v2')) {
$ThisFileInfo['bonk'][' ID3']['valid'] = new getid3_id3v2($fd, $ThisFileInfo, $ThisFileInfo['bonk'][' ID3']['offset'] + 2);
}
break;
default:
$ThisFileInfo['warning'][] = 'Unexpected Bonk tag "'.$BonkTagName.'" at offset '.$ThisFileInfo['bonk'][$BonkTagName]['offset'];
break;
}
}
function BonkIsValidTagName($PossibleBonkTag, $ignorecase=false) {
static $BonkIsValidTagName = array('BONK', 'INFO', ' ID3', 'META');
foreach ($BonkIsValidTagName as $validtagname) {
if ($validtagname == $PossibleBonkTag) {
return true;
} elseif ($ignorecase && (strtolower($validtagname) == strtolower($PossibleBonkTag))) {
return true;
}
}
return false;
}
}
?>

View File

@ -1,72 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio.au.php //
// module for analyzing Digital Speech Standard (DSS) files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_dss
{
function getid3_dss(&$fd, &$ThisFileInfo) {
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$DSSheader = fread($fd, 1256);
if (substr($DSSheader, 0, 4) != "\x02".'dss') {
$ThisFileInfo['error'][] = 'Expecting "[x02]dss" at offset '.$ThisFileInfo['avdataoffset'].', found "'.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
// shortcut
$ThisFileInfo['dss'] = array();
$thisfile_dss = &$ThisFileInfo['dss'];
$ThisFileInfo['fileformat'] = 'dss';
$ThisFileInfo['audio']['dataformat'] = 'dss';
$ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
//$thisfile_dss['encoding'] = 'ISO-8859-1';
$thisfile_dss['date_create'] = $this->DSSdateStringToUnixDate(substr($DSSheader, 38, 12));
$thisfile_dss['date_complete'] = $this->DSSdateStringToUnixDate(substr($DSSheader, 50, 12));
$thisfile_dss['length'] = intval(substr($DSSheader, 62, 6));
$thisfile_dss['priority'] = ord(substr($DSSheader, 793, 1));
$thisfile_dss['comments'] = trim(substr($DSSheader, 798, 100));
//$ThisFileInfo['audio']['bits_per_sample'] = ?;
//$ThisFileInfo['audio']['sample_rate'] = ?;
$ThisFileInfo['audio']['channels'] = 1;
$ThisFileInfo['playtime_seconds'] = $thisfile_dss['length'];
$ThisFileInfo['audio']['bitrate'] = ($ThisFileInfo['filesize'] * 8) / $ThisFileInfo['playtime_seconds'];
return true;
}
function DSSdateStringToUnixDate($datestring) {
$y = 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);
}
}
?>

View File

@ -1,239 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio.dts.php //
// module for analyzing DTS Audio files //
// dependencies: NONE //
// //
/////////////////////////////////////////////////////////////////
class getid3_dts
{
function getid3_dts(&$fd, &$ThisFileInfo) {
// Specs taken from "DTS Coherent Acoustics;Core and Extensions, ETSI TS 102 114 V1.2.1 (2002-12)"
// (http://pda.etsi.org/pda/queryform.asp)
// With thanks to Gambit <macteam@users.sourceforge.net> http://mac.sourceforge.net/atl/
$ThisFileInfo['fileformat'] = 'dts';
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$DTSheader = fread($fd, 16);
$ThisFileInfo['dts']['raw']['magic'] = getid3_lib::BigEndian2Int(substr($DTSheader, 0, 4));
if ($ThisFileInfo['dts']['raw']['magic'] != 0x7FFE8001) {
$ThisFileInfo['error'][] = 'Expecting "0x7FFE8001" at offset '.$ThisFileInfo['avdataoffset'].', found "0x'.str_pad(strtoupper(dechex($ThisFileInfo['dts']['raw']['magic'])), 8, '0', STR_PAD_LEFT).'"';
unset($ThisFileInfo['fileformat']);
unset($ThisFileInfo['dts']);
return false;
}
$fhBS = getid3_lib::BigEndian2Bin(substr($DTSheader, 4, 12));
$bsOffset = 0;
$ThisFileInfo['dts']['raw']['frame_type'] = bindec(substr($fhBS, $bsOffset, 1)); $bsOffset += 1;
$ThisFileInfo['dts']['raw']['deficit_samples'] = bindec(substr($fhBS, $bsOffset, 5)); $bsOffset += 5;
$ThisFileInfo['dts']['flags']['crc_present'] = (bool) bindec(substr($fhBS, $bsOffset, 1)); $bsOffset += 1;
$ThisFileInfo['dts']['raw']['pcm_sample_blocks'] = bindec(substr($fhBS, $bsOffset, 7)); $bsOffset += 7;
$ThisFileInfo['dts']['raw']['frame_byte_size'] = bindec(substr($fhBS, $bsOffset, 14)); $bsOffset += 14;
$ThisFileInfo['dts']['raw']['channel_arrangement'] = bindec(substr($fhBS, $bsOffset, 6)); $bsOffset += 6;
$ThisFileInfo['dts']['raw']['sample_frequency'] = bindec(substr($fhBS, $bsOffset, 4)); $bsOffset += 4;
$ThisFileInfo['dts']['raw']['bitrate'] = bindec(substr($fhBS, $bsOffset, 5)); $bsOffset += 5;
$ThisFileInfo['dts']['flags']['embedded_downmix'] = (bool) bindec(substr($fhBS, $bsOffset, 1)); $bsOffset += 1;
$ThisFileInfo['dts']['flags']['dynamicrange'] = (bool) bindec(substr($fhBS, $bsOffset, 1)); $bsOffset += 1;
$ThisFileInfo['dts']['flags']['timestamp'] = (bool) bindec(substr($fhBS, $bsOffset, 1)); $bsOffset += 1;
$ThisFileInfo['dts']['flags']['auxdata'] = (bool) bindec(substr($fhBS, $bsOffset, 1)); $bsOffset += 1;
$ThisFileInfo['dts']['flags']['hdcd'] = (bool) bindec(substr($fhBS, $bsOffset, 1)); $bsOffset += 1;
$ThisFileInfo['dts']['raw']['extension_audio'] = bindec(substr($fhBS, $bsOffset, 3)); $bsOffset += 3;
$ThisFileInfo['dts']['flags']['extended_coding'] = (bool) bindec(substr($fhBS, $bsOffset, 1)); $bsOffset += 1;
$ThisFileInfo['dts']['flags']['audio_sync_insertion'] = (bool) bindec(substr($fhBS, $bsOffset, 1)); $bsOffset += 1;
$ThisFileInfo['dts']['raw']['lfe_effects'] = bindec(substr($fhBS, $bsOffset, 2)); $bsOffset += 2;
$ThisFileInfo['dts']['flags']['predictor_history'] = (bool) bindec(substr($fhBS, $bsOffset, 1)); $bsOffset += 1;
if ($ThisFileInfo['dts']['flags']['crc_present']) {
$ThisFileInfo['dts']['raw']['crc16'] = bindec(substr($fhBS, $bsOffset, 16)); $bsOffset += 16;
}
$ThisFileInfo['dts']['flags']['mri_perfect_reconst'] = (bool) bindec(substr($fhBS, $bsOffset, 1)); $bsOffset += 1;
$ThisFileInfo['dts']['raw']['encoder_soft_version'] = bindec(substr($fhBS, $bsOffset, 4)); $bsOffset += 4;
$ThisFileInfo['dts']['raw']['copy_history'] = bindec(substr($fhBS, $bsOffset, 2)); $bsOffset += 2;
$ThisFileInfo['dts']['raw']['bits_per_sample'] = bindec(substr($fhBS, $bsOffset, 2)); $bsOffset += 2;
$ThisFileInfo['dts']['flags']['surround_es'] = (bool) bindec(substr($fhBS, $bsOffset, 1)); $bsOffset += 1;
$ThisFileInfo['dts']['flags']['front_sum_diff'] = (bool) bindec(substr($fhBS, $bsOffset, 1)); $bsOffset += 1;
$ThisFileInfo['dts']['flags']['surround_sum_diff'] = (bool) bindec(substr($fhBS, $bsOffset, 1)); $bsOffset += 1;
$ThisFileInfo['dts']['raw']['dialog_normalization'] = bindec(substr($fhBS, $bsOffset, 4)); $bsOffset += 4;
$ThisFileInfo['dts']['bitrate'] = $this->DTSbitrateLookup($ThisFileInfo['dts']['raw']['bitrate']);
$ThisFileInfo['dts']['bits_per_sample'] = $this->DTSbitPerSampleLookup($ThisFileInfo['dts']['raw']['bits_per_sample']);
$ThisFileInfo['dts']['sample_rate'] = $this->DTSsampleRateLookup($ThisFileInfo['dts']['raw']['sample_frequency']);
$ThisFileInfo['dts']['dialog_normalization'] = $this->DTSdialogNormalization($ThisFileInfo['dts']['raw']['dialog_normalization'], $ThisFileInfo['dts']['raw']['encoder_soft_version']);
$ThisFileInfo['dts']['flags']['lossless'] = (($ThisFileInfo['dts']['raw']['bitrate'] == 31) ? true : false);
$ThisFileInfo['dts']['bitrate_mode'] = (($ThisFileInfo['dts']['raw']['bitrate'] == 30) ? 'vbr' : 'cbr');
$ThisFileInfo['dts']['channels'] = $this->DTSnumChannelsLookup($ThisFileInfo['dts']['raw']['channel_arrangement']);
$ThisFileInfo['dts']['channel_arrangement'] = $this->DTSchannelArrangementLookup($ThisFileInfo['dts']['raw']['channel_arrangement']);
$ThisFileInfo['audio']['dataformat'] = 'dts';
$ThisFileInfo['audio']['lossless'] = $ThisFileInfo['dts']['flags']['lossless'];
$ThisFileInfo['audio']['bitrate_mode'] = $ThisFileInfo['dts']['bitrate_mode'];
$ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['dts']['bits_per_sample'];
$ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['dts']['sample_rate'];
$ThisFileInfo['audio']['channels'] = $ThisFileInfo['dts']['channels'];
$ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['dts']['bitrate'];
if (isset($ThisFileInfo['avdataend'])) {
$ThisFileInfo['playtime_seconds'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / ($ThisFileInfo['dts']['bitrate'] / 8);
}
return true;
}
function DTSbitrateLookup($index) {
$DTSbitrateLookup = 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 @$DTSbitrateLookup[$index];
}
function DTSsampleRateLookup($index) {
$DTSsampleRateLookup = 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 @$DTSsampleRateLookup[$index];
}
function DTSbitPerSampleLookup($index) {
$DTSbitPerSampleLookup = array(
0 => 16,
1 => 20,
2 => 24,
3 => 24,
);
return @$DTSbitPerSampleLookup[$index];
}
function DTSnumChannelsLookup($index) {
switch ($index) {
case 0:
return 1;
break;
case 1:
case 2:
case 3:
case 4:
return 2;
break;
case 5:
case 6:
return 3;
break;
case 7:
case 8:
return 4;
break;
case 9:
return 5;
break;
case 10:
case 11:
case 12:
return 6;
break;
case 13:
return 7;
break;
case 14:
case 15:
return 8;
break;
}
return false;
}
function DTSchannelArrangementLookup($index) {
$DTSchannelArrangementLookup = 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 (@$DTSchannelArrangementLookup[$index] ? @$DTSchannelArrangementLookup[$index] : 'user-defined');
}
function DTSdialogNormalization($index, $version) {
switch ($version) {
case 7:
return 0 - $index;
break;
case 6:
return 0 - 16 - $index;
break;
}
return false;
}
}
?>

View File

@ -1,397 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio.flac.php //
// module for analyzing FLAC and OggFLAC audio files //
// dependencies: module.audio.ogg.php //
// ///
/////////////////////////////////////////////////////////////////
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ogg.php', __FILE__, true);
class getid3_flac
{
function getid3_flac(&$fd, &$ThisFileInfo) {
// http://flac.sourceforge.net/format.html
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$StreamMarker = fread($fd, 4);
if ($StreamMarker != 'fLaC') {
$ThisFileInfo['error'][] = 'Expecting "fLaC" at offset '.$ThisFileInfo['avdataoffset'].', found "'.$StreamMarker.'"';
return false;
}
$ThisFileInfo['fileformat'] = 'flac';
$ThisFileInfo['audio']['dataformat'] = 'flac';
$ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
$ThisFileInfo['audio']['lossless'] = true;
return getid3_flac::FLACparseMETAdata($fd, $ThisFileInfo);
}
function FLACparseMETAdata(&$fd, &$ThisFileInfo) {
do {
$METAdataBlockOffset = ftell($fd);
$METAdataBlockHeader = fread($fd, 4);
$METAdataLastBlockFlag = (bool) (getid3_lib::BigEndian2Int(substr($METAdataBlockHeader, 0, 1)) & 0x80);
$METAdataBlockType = getid3_lib::BigEndian2Int(substr($METAdataBlockHeader, 0, 1)) & 0x7F;
$METAdataBlockLength = getid3_lib::BigEndian2Int(substr($METAdataBlockHeader, 1, 3));
$METAdataBlockTypeText = getid3_flac::FLACmetaBlockTypeLookup($METAdataBlockType);
if ($METAdataBlockLength < 0) {
$ThisFileInfo['error'][] = 'corrupt or invalid METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$METAdataBlockType.') at offset '.$METAdataBlockOffset;
break;
}
$ThisFileInfo['flac'][$METAdataBlockTypeText]['raw'] = array();
$ThisFileInfo_flac_METAdataBlockTypeText_raw = &$ThisFileInfo['flac'][$METAdataBlockTypeText]['raw'];
$ThisFileInfo_flac_METAdataBlockTypeText_raw['offset'] = $METAdataBlockOffset;
$ThisFileInfo_flac_METAdataBlockTypeText_raw['last_meta_block'] = $METAdataLastBlockFlag;
$ThisFileInfo_flac_METAdataBlockTypeText_raw['block_type'] = $METAdataBlockType;
$ThisFileInfo_flac_METAdataBlockTypeText_raw['block_type_text'] = $METAdataBlockTypeText;
$ThisFileInfo_flac_METAdataBlockTypeText_raw['block_length'] = $METAdataBlockLength;
$ThisFileInfo_flac_METAdataBlockTypeText_raw['block_data'] = @fread($fd, $METAdataBlockLength);
$ThisFileInfo['avdataoffset'] = ftell($fd);
switch ($METAdataBlockTypeText) {
case 'STREAMINFO':
if (!getid3_flac::FLACparseSTREAMINFO($ThisFileInfo_flac_METAdataBlockTypeText_raw['block_data'], $ThisFileInfo)) {
return false;
}
break;
case 'PADDING':
// ignore
break;
case 'APPLICATION':
if (!getid3_flac::FLACparseAPPLICATION($ThisFileInfo_flac_METAdataBlockTypeText_raw['block_data'], $ThisFileInfo)) {
return false;
}
break;
case 'SEEKTABLE':
if (!getid3_flac::FLACparseSEEKTABLE($ThisFileInfo_flac_METAdataBlockTypeText_raw['block_data'], $ThisFileInfo)) {
return false;
}
break;
case 'VORBIS_COMMENT':
$OldOffset = ftell($fd);
fseek($fd, 0 - $METAdataBlockLength, SEEK_CUR);
getid3_ogg::ParseVorbisCommentsFilepointer($fd, $ThisFileInfo);
fseek($fd, $OldOffset, SEEK_SET);
break;
case 'CUESHEET':
if (!getid3_flac::FLACparseCUESHEET($ThisFileInfo_flac_METAdataBlockTypeText_raw['block_data'], $ThisFileInfo)) {
return false;
}
break;
case 'PICTURE':
if (!$this->FLACparsePICTURE($ThisFileInfo_flac_METAdataBlockTypeText_raw['block_data'], $ThisFileInfo)) {
return false;
}
break;
default:
$ThisFileInfo['warning'][] = 'Unhandled METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$METAdataBlockType.') at offset '.$METAdataBlockOffset;
break;
}
} while ($METAdataLastBlockFlag === false);
if (isset($ThisFileInfo['flac']['STREAMINFO'])) {
$ThisFileInfo['flac']['compressed_audio_bytes'] = $ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset'];
$ThisFileInfo['flac']['uncompressed_audio_bytes'] = $ThisFileInfo['flac']['STREAMINFO']['samples_stream'] * $ThisFileInfo['flac']['STREAMINFO']['channels'] * ($ThisFileInfo['flac']['STREAMINFO']['bits_per_sample'] / 8);
if ($ThisFileInfo['flac']['uncompressed_audio_bytes'] == 0) {
$ThisFileInfo['error'][] = 'Corrupt FLAC file: uncompressed_audio_bytes == zero';
return false;
}
$ThisFileInfo['flac']['compression_ratio'] = $ThisFileInfo['flac']['compressed_audio_bytes'] / $ThisFileInfo['flac']['uncompressed_audio_bytes'];
}
// set md5_data_source - built into flac 0.5+
if (isset($ThisFileInfo['flac']['STREAMINFO']['audio_signature'])) {
if ($ThisFileInfo['flac']['STREAMINFO']['audio_signature'] === str_repeat("\x00", 16)) {
$ThisFileInfo['warning'][] = 'FLAC STREAMINFO.audio_signature is null (known issue with libOggFLAC)';
} else {
$ThisFileInfo['md5_data_source'] = '';
$md5 = $ThisFileInfo['flac']['STREAMINFO']['audio_signature'];
for ($i = 0; $i < strlen($md5); $i++) {
$ThisFileInfo['md5_data_source'] .= str_pad(dechex(ord($md5{$i})), 2, '00', STR_PAD_LEFT);
}
if (!preg_match('/^[0-9a-f]{32}$/', $ThisFileInfo['md5_data_source'])) {
unset($ThisFileInfo['md5_data_source']);
}
}
}
$ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['flac']['STREAMINFO']['bits_per_sample'];
if ($ThisFileInfo['audio']['bits_per_sample'] == 8) {
// special case
// must invert sign bit on all data bytes before MD5'ing to match FLAC's calculated value
// MD5sum calculates on unsigned bytes, but FLAC calculated MD5 on 8-bit audio data as signed
$ThisFileInfo['warning'][] = 'FLAC calculates MD5 data strangely on 8-bit audio, so the stored md5_data_source value will not match the decoded WAV file';
}
if (!empty($ThisFileInfo['ogg']['vendor'])) {
$ThisFileInfo['audio']['encoder'] = $ThisFileInfo['ogg']['vendor'];
}
return true;
}
function FLACmetaBlockTypeLookup($blocktype) {
static $FLACmetaBlockTypeLookup = array();
if (empty($FLACmetaBlockTypeLookup)) {
$FLACmetaBlockTypeLookup[0] = 'STREAMINFO';
$FLACmetaBlockTypeLookup[1] = 'PADDING';
$FLACmetaBlockTypeLookup[2] = 'APPLICATION';
$FLACmetaBlockTypeLookup[3] = 'SEEKTABLE';
$FLACmetaBlockTypeLookup[4] = 'VORBIS_COMMENT';
$FLACmetaBlockTypeLookup[5] = 'CUESHEET';
$FLACmetaBlockTypeLookup[6] = 'PICTURE';
}
return (isset($FLACmetaBlockTypeLookup[$blocktype]) ? $FLACmetaBlockTypeLookup[$blocktype] : 'reserved');
}
function FLACapplicationIDLookup($applicationid) {
static $FLACapplicationIDLookup = array();
if (empty($FLACapplicationIDLookup)) {
// http://flac.sourceforge.net/id.html
$FLACapplicationIDLookup[0x46746F6C] = 'flac-tools'; // 'Ftol'
$FLACapplicationIDLookup[0x46746F6C] = 'Sound Font FLAC'; // 'SFFL'
}
return (isset($FLACapplicationIDLookup[$applicationid]) ? $FLACapplicationIDLookup[$applicationid] : 'reserved');
}
function FLACpictureTypeLookup($type_id) {
static $lookup = array (
0 => 'Other',
1 => '32x32 pixels \'file icon\' (PNG only)',
2 => 'Other file icon',
3 => 'Cover (front)',
4 => 'Cover (back)',
5 => 'Leaflet page',
6 => 'Media (e.g. label side of CD)',
7 => 'Lead artist/lead performer/soloist',
8 => 'Artist/performer',
9 => 'Conductor',
10 => 'Band/Orchestra',
11 => 'Composer',
12 => 'Lyricist/text writer',
13 => 'Recording Location',
14 => 'During recording',
15 => 'During performance',
16 => 'Movie/video screen capture',
17 => 'A bright coloured fish',
18 => 'Illustration',
19 => 'Band/artist logotype',
20 => 'Publisher/Studio logotype',
);
return (isset($lookup[$type_id]) ? $lookup[$type_id] : 'reserved');
}
function FLACparseSTREAMINFO($METAdataBlockData, &$ThisFileInfo) {
$offset = 0;
$ThisFileInfo['flac']['STREAMINFO']['min_block_size'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 2));
$offset += 2;
$ThisFileInfo['flac']['STREAMINFO']['max_block_size'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 2));
$offset += 2;
$ThisFileInfo['flac']['STREAMINFO']['min_frame_size'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 3));
$offset += 3;
$ThisFileInfo['flac']['STREAMINFO']['max_frame_size'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 3));
$offset += 3;
$SampleRateChannelsSampleBitsStreamSamples = getid3_lib::BigEndian2Bin(substr($METAdataBlockData, $offset, 8));
$ThisFileInfo['flac']['STREAMINFO']['sample_rate'] = getid3_lib::Bin2Dec(substr($SampleRateChannelsSampleBitsStreamSamples, 0, 20));
$ThisFileInfo['flac']['STREAMINFO']['channels'] = getid3_lib::Bin2Dec(substr($SampleRateChannelsSampleBitsStreamSamples, 20, 3)) + 1;
$ThisFileInfo['flac']['STREAMINFO']['bits_per_sample'] = getid3_lib::Bin2Dec(substr($SampleRateChannelsSampleBitsStreamSamples, 23, 5)) + 1;
$ThisFileInfo['flac']['STREAMINFO']['samples_stream'] = getid3_lib::Bin2Dec(substr($SampleRateChannelsSampleBitsStreamSamples, 28, 36));
$offset += 8;
$ThisFileInfo['flac']['STREAMINFO']['audio_signature'] = substr($METAdataBlockData, $offset, 16);
$offset += 16;
if (!empty($ThisFileInfo['flac']['STREAMINFO']['sample_rate'])) {
$ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
$ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['flac']['STREAMINFO']['sample_rate'];
$ThisFileInfo['audio']['channels'] = $ThisFileInfo['flac']['STREAMINFO']['channels'];
$ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['flac']['STREAMINFO']['bits_per_sample'];
$ThisFileInfo['playtime_seconds'] = $ThisFileInfo['flac']['STREAMINFO']['samples_stream'] / $ThisFileInfo['flac']['STREAMINFO']['sample_rate'];
$ThisFileInfo['audio']['bitrate'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['playtime_seconds'];
} else {
$ThisFileInfo['error'][] = 'Corrupt METAdata block: STREAMINFO';
return false;
}
unset($ThisFileInfo['flac']['STREAMINFO']['raw']);
return true;
}
function FLACparseAPPLICATION($METAdataBlockData, &$ThisFileInfo) {
$offset = 0;
$ApplicationID = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 4));
$offset += 4;
$ThisFileInfo['flac']['APPLICATION'][$ApplicationID]['name'] = getid3_flac::FLACapplicationIDLookup($ApplicationID);
$ThisFileInfo['flac']['APPLICATION'][$ApplicationID]['data'] = substr($METAdataBlockData, $offset);
$offset = $METAdataBlockLength;
unset($ThisFileInfo['flac']['APPLICATION']['raw']);
return true;
}
function FLACparseSEEKTABLE($METAdataBlockData, &$ThisFileInfo) {
$offset = 0;
$METAdataBlockLength = strlen($METAdataBlockData);
$placeholderpattern = str_repeat("\xFF", 8);
while ($offset < $METAdataBlockLength) {
$SampleNumberString = substr($METAdataBlockData, $offset, 8);
$offset += 8;
if ($SampleNumberString == $placeholderpattern) {
// placeholder point
@$ThisFileInfo['flac']['SEEKTABLE']['placeholders']++;
$offset += 10;
} else {
$SampleNumber = getid3_lib::BigEndian2Int($SampleNumberString);
$ThisFileInfo['flac']['SEEKTABLE'][$SampleNumber]['offset'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 8));
$offset += 8;
$ThisFileInfo['flac']['SEEKTABLE'][$SampleNumber]['samples'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 2));
$offset += 2;
}
}
unset($ThisFileInfo['flac']['SEEKTABLE']['raw']);
return true;
}
function FLACparseCUESHEET($METAdataBlockData, &$ThisFileInfo) {
$offset = 0;
$ThisFileInfo['flac']['CUESHEET']['media_catalog_number'] = trim(substr($METAdataBlockData, $offset, 128), "\0");
$offset += 128;
$ThisFileInfo['flac']['CUESHEET']['lead_in_samples'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 8));
$offset += 8;
$ThisFileInfo['flac']['CUESHEET']['flags']['is_cd'] = (bool) (getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 1)) & 0x80);
$offset += 1;
$offset += 258; // reserved
$ThisFileInfo['flac']['CUESHEET']['number_tracks'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 1));
$offset += 1;
for ($track = 0; $track < $ThisFileInfo['flac']['CUESHEET']['number_tracks']; $track++) {
$TrackSampleOffset = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 8));
$offset += 8;
$TrackNumber = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 1));
$offset += 1;
$ThisFileInfo['flac']['CUESHEET']['tracks'][$TrackNumber]['sample_offset'] = $TrackSampleOffset;
$ThisFileInfo['flac']['CUESHEET']['tracks'][$TrackNumber]['isrc'] = substr($METAdataBlockData, $offset, 12);
$offset += 12;
$TrackFlagsRaw = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 1));
$offset += 1;
$ThisFileInfo['flac']['CUESHEET']['tracks'][$TrackNumber]['flags']['is_audio'] = (bool) ($TrackFlagsRaw & 0x80);
$ThisFileInfo['flac']['CUESHEET']['tracks'][$TrackNumber]['flags']['pre_emphasis'] = (bool) ($TrackFlagsRaw & 0x40);
$offset += 13; // reserved
$ThisFileInfo['flac']['CUESHEET']['tracks'][$TrackNumber]['index_points'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 1));
$offset += 1;
for ($index = 0; $index < $ThisFileInfo['flac']['CUESHEET']['tracks'][$TrackNumber]['index_points']; $index++) {
$IndexSampleOffset = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 8));
$offset += 8;
$IndexNumber = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 1));
$offset += 1;
$offset += 3; // reserved
$ThisFileInfo['flac']['CUESHEET']['tracks'][$TrackNumber]['indexes'][$IndexNumber] = $IndexSampleOffset;
}
}
unset($ThisFileInfo['flac']['CUESHEET']['raw']);
return true;
}
function FLACparsePICTURE($meta_data_block_data, &$ThisFileInfo) {
$picture = &$ThisFileInfo['flac']['PICTURE'][sizeof($ThisFileInfo['flac']['PICTURE']) - 1];
$offset = 0;
$picture['type'] = $this->FLACpictureTypeLookup(getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 4)));
$offset += 4;
$length = getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 4));
$offset += 4;
$picture['mime_type'] = substr($meta_data_block_data, $offset, $length);
$offset += $length;
$length = getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 4));
$offset += 4;
$picture['description'] = substr($meta_data_block_data, $offset, $length);
$offset += $length;
$picture['width'] = getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 4));
$offset += 4;
$picture['height'] = getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 4));
$offset += 4;
$picture['color_depth'] = getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 4));
$offset += 4;
$picture['colors_indexed'] = getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 4));
$offset += 4;
$length = getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 4));
$offset += 4;
$picture['image_data'] = substr($meta_data_block_data, $offset, $length);
$offset += $length;
unset($ThisFileInfo['flac']['PICTURE']['raw']);
return true;
}
}
?>

View File

@ -1,228 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio.la.php //
// module for analyzing LA audio files //
// dependencies: module.audio.riff.php //
// ///
/////////////////////////////////////////////////////////////////
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
class getid3_la
{
function getid3_la(&$fd, &$ThisFileInfo) {
$offset = 0;
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$rawdata = fread($fd, GETID3_FREAD_BUFFER_SIZE);
switch (substr($rawdata, $offset, 4)) {
case 'LA02':
case 'LA03':
case 'LA04':
$ThisFileInfo['fileformat'] = 'la';
$ThisFileInfo['audio']['dataformat'] = 'la';
$ThisFileInfo['audio']['lossless'] = true;
$ThisFileInfo['la']['version_major'] = (int) substr($rawdata, $offset + 2, 1);
$ThisFileInfo['la']['version_minor'] = (int) substr($rawdata, $offset + 3, 1);
$ThisFileInfo['la']['version'] = (float) $ThisFileInfo['la']['version_major'] + ($ThisFileInfo['la']['version_minor'] / 10);
$offset += 4;
$ThisFileInfo['la']['uncompressed_size'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4));
$offset += 4;
if ($ThisFileInfo['la']['uncompressed_size'] == 0) {
$ThisFileInfo['error'][] = 'Corrupt LA file: uncompressed_size == zero';
return false;
}
$WAVEchunk = substr($rawdata, $offset, 4);
if ($WAVEchunk !== 'WAVE') {
$ThisFileInfo['error'][] = 'Expected "WAVE" ('.getid3_lib::PrintHexBytes('WAVE').') at offset '.$offset.', found "'.$WAVEchunk.'" ('.getid3_lib::PrintHexBytes($WAVEchunk).') instead.';
return false;
}
$offset += 4;
$ThisFileInfo['la']['fmt_size'] = 24;
if ($ThisFileInfo['la']['version'] >= 0.3) {
$ThisFileInfo['la']['fmt_size'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4));
$ThisFileInfo['la']['header_size'] = 49 + $ThisFileInfo['la']['fmt_size'] - 24;
$offset += 4;
} else {
// version 0.2 didn't support additional data blocks
$ThisFileInfo['la']['header_size'] = 41;
}
$fmt_chunk = substr($rawdata, $offset, 4);
if ($fmt_chunk !== 'fmt ') {
$ThisFileInfo['error'][] = 'Expected "fmt " ('.getid3_lib::PrintHexBytes('fmt ').') at offset '.$offset.', found "'.$fmt_chunk.'" ('.getid3_lib::PrintHexBytes($fmt_chunk).') instead.';
return false;
}
$offset += 4;
$fmt_size = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4));
$offset += 4;
$ThisFileInfo['la']['raw']['format'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 2));
$offset += 2;
$ThisFileInfo['la']['channels'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 2));
$offset += 2;
if ($ThisFileInfo['la']['channels'] == 0) {
$ThisFileInfo['error'][] = 'Corrupt LA file: channels == zero';
return false;
}
$ThisFileInfo['la']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4));
$offset += 4;
if ($ThisFileInfo['la']['sample_rate'] == 0) {
$ThisFileInfo['error'][] = 'Corrupt LA file: sample_rate == zero';
return false;
}
$ThisFileInfo['la']['bytes_per_second'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4));
$offset += 4;
$ThisFileInfo['la']['bytes_per_sample'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 2));
$offset += 2;
$ThisFileInfo['la']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 2));
$offset += 2;
$ThisFileInfo['la']['samples'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4));
$offset += 4;
$ThisFileInfo['la']['raw']['flags'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 1));
$offset += 1;
$ThisFileInfo['la']['flags']['seekable'] = (bool) ($ThisFileInfo['la']['raw']['flags'] & 0x01);
if ($ThisFileInfo['la']['version'] >= 0.4) {
$ThisFileInfo['la']['flags']['high_compression'] = (bool) ($ThisFileInfo['la']['raw']['flags'] & 0x02);
}
$ThisFileInfo['la']['original_crc'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4));
$offset += 4;
// mikeØbevin*de
// Basically, the blocksize/seekevery are 61440/19 in La0.4 and 73728/16
// in earlier versions. A seekpoint is added every blocksize * seekevery
// samples, so 4 * int(totalSamples / (blockSize * seekEvery)) should
// give the number of bytes used for the seekpoints. Of course, if seeking
// is disabled, there are no seekpoints stored.
if ($ThisFileInfo['la']['version'] >= 0.4) {
$ThisFileInfo['la']['blocksize'] = 61440;
$ThisFileInfo['la']['seekevery'] = 19;
} else {
$ThisFileInfo['la']['blocksize'] = 73728;
$ThisFileInfo['la']['seekevery'] = 16;
}
$ThisFileInfo['la']['seekpoint_count'] = 0;
if ($ThisFileInfo['la']['flags']['seekable']) {
$ThisFileInfo['la']['seekpoint_count'] = floor($ThisFileInfo['la']['samples'] / ($ThisFileInfo['la']['blocksize'] * $ThisFileInfo['la']['seekevery']));
for ($i = 0; $i < $ThisFileInfo['la']['seekpoint_count']; $i++) {
$ThisFileInfo['la']['seekpoints'][] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4));
$offset += 4;
}
}
if ($ThisFileInfo['la']['version'] >= 0.3) {
// Following the main header information, the program outputs all of the
// seekpoints. Following these is what I called the 'footer start',
// i.e. the position immediately after the La audio data is finished.
$ThisFileInfo['la']['footerstart'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4));
$offset += 4;
if ($ThisFileInfo['la']['footerstart'] > $ThisFileInfo['filesize']) {
$ThisFileInfo['warning'][] = 'FooterStart value points to offset '.$ThisFileInfo['la']['footerstart'].' which is beyond end-of-file ('.$ThisFileInfo['filesize'].')';
$ThisFileInfo['la']['footerstart'] = $ThisFileInfo['filesize'];
}
} else {
// La v0.2 didn't have FooterStart value
$ThisFileInfo['la']['footerstart'] = $ThisFileInfo['avdataend'];
}
if ($ThisFileInfo['la']['footerstart'] < $ThisFileInfo['avdataend']) {
if ($RIFFtempfilename = tempnam('*', 'id3')) {
if ($RIFF_fp = fopen($RIFFtempfilename, 'w+b')) {
$RIFFdata = 'WAVE';
if ($ThisFileInfo['la']['version'] == 0.2) {
$RIFFdata .= substr($rawdata, 12, 24);
} else {
$RIFFdata .= substr($rawdata, 16, 24);
}
if ($ThisFileInfo['la']['footerstart'] < $ThisFileInfo['avdataend']) {
fseek($fd, $ThisFileInfo['la']['footerstart'], SEEK_SET);
$RIFFdata .= fread($fd, $ThisFileInfo['avdataend'] - $ThisFileInfo['la']['footerstart']);
}
$RIFFdata = 'RIFF'.getid3_lib::LittleEndian2String(strlen($RIFFdata), 4, false).$RIFFdata;
fwrite($RIFF_fp, $RIFFdata, strlen($RIFFdata));
$dummy = $ThisFileInfo;
$dummy['filesize'] = strlen($RIFFdata);
$dummy['avdataoffset'] = 0;
$dummy['avdataend'] = $dummy['filesize'];
$riff = new getid3_riff($RIFF_fp, $dummy);
if (empty($dummy['error'])) {
$ThisFileInfo['riff'] = $dummy['riff'];
} else {
$ThisFileInfo['warning'][] = 'Error parsing RIFF portion of La file: '.implode($dummy['error']);
}
unset($riff);
unset($dummy);
fclose($RIFF_fp);
}
unlink($RIFFtempfilename);
}
}
// $ThisFileInfo['avdataoffset'] should be zero to begin with, but just in case it's not, include the addition anyway
$ThisFileInfo['avdataend'] = $ThisFileInfo['avdataoffset'] + $ThisFileInfo['la']['footerstart'];
$ThisFileInfo['avdataoffset'] = $ThisFileInfo['avdataoffset'] + $offset;
//$ThisFileInfo['la']['codec'] = RIFFwFormatTagLookup($ThisFileInfo['la']['raw']['format']);
$ThisFileInfo['la']['compression_ratio'] = (float) (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / $ThisFileInfo['la']['uncompressed_size']);
$ThisFileInfo['playtime_seconds'] = (float) ($ThisFileInfo['la']['samples'] / $ThisFileInfo['la']['sample_rate']) / $ThisFileInfo['la']['channels'];
if ($ThisFileInfo['playtime_seconds'] == 0) {
$ThisFileInfo['error'][] = 'Corrupt LA file: playtime_seconds == zero';
return false;
}
$ThisFileInfo['audio']['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8 / $ThisFileInfo['playtime_seconds'];
//$ThisFileInfo['audio']['codec'] = $ThisFileInfo['la']['codec'];
$ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['la']['bits_per_sample'];
break;
default:
if (substr($rawdata, $offset, 2) == 'LA') {
$ThisFileInfo['error'][] = 'This version of getID3() (v'.GETID3_VERSION.') doesn\'t support LA version '.substr($rawdata, $offset + 2, 1).'.'.substr($rawdata, $offset + 3, 1).' which this appears to be - check http://getid3.sourceforge.net for updates.';
} else {
$ThisFileInfo['error'][] = 'Not a LA (Lossless-Audio) file';
}
return false;
break;
}
$ThisFileInfo['audio']['channels'] = $ThisFileInfo['la']['channels'];
$ThisFileInfo['audio']['sample_rate'] = (int) $ThisFileInfo['la']['sample_rate'];
$ThisFileInfo['audio']['encoder'] = 'LA v'.$ThisFileInfo['la']['version'];
return true;
}
}
?>

View File

@ -1,126 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio.lpac.php //
// module for analyzing LPAC Audio files //
// dependencies: module.audio-video.riff.php //
// ///
/////////////////////////////////////////////////////////////////
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
class getid3_lpac
{
function getid3_lpac(&$fd, &$ThisFileInfo) {
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$LPACheader = fread($fd, 14);
if (substr($LPACheader, 0, 4) != 'LPAC') {
$ThisFileInfo['error'][] = 'Expected "LPAC" at offset '.$ThisFileInfo['avdataoffset'].', found "'.$StreamMarker.'"';
return false;
}
$ThisFileInfo['avdataoffset'] += 14;
$ThisFileInfo['fileformat'] = 'lpac';
$ThisFileInfo['audio']['dataformat'] = 'lpac';
$ThisFileInfo['audio']['lossless'] = true;
$ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
$ThisFileInfo['lpac']['file_version'] = getid3_lib::BigEndian2Int(substr($LPACheader, 4, 1));
$flags['audio_type'] = getid3_lib::BigEndian2Int(substr($LPACheader, 5, 1));
$ThisFileInfo['lpac']['total_samples']= getid3_lib::BigEndian2Int(substr($LPACheader, 6, 4));
$flags['parameters'] = getid3_lib::BigEndian2Int(substr($LPACheader, 10, 4));
$ThisFileInfo['lpac']['flags']['is_wave'] = (bool) ($flags['audio_type'] & 0x40);
$ThisFileInfo['lpac']['flags']['stereo'] = (bool) ($flags['audio_type'] & 0x04);
$ThisFileInfo['lpac']['flags']['24_bit'] = (bool) ($flags['audio_type'] & 0x02);
$ThisFileInfo['lpac']['flags']['16_bit'] = (bool) ($flags['audio_type'] & 0x01);
if ($ThisFileInfo['lpac']['flags']['24_bit'] && $ThisFileInfo['lpac']['flags']['16_bit']) {
$ThisFileInfo['warning'][] = '24-bit and 16-bit flags cannot both be set';
}
$ThisFileInfo['lpac']['flags']['fast_compress'] = (bool) ($flags['parameters'] & 0x40000000);
$ThisFileInfo['lpac']['flags']['random_access'] = (bool) ($flags['parameters'] & 0x08000000);
$ThisFileInfo['lpac']['block_length'] = pow(2, (($flags['parameters'] & 0x07000000) >> 24)) * 256;
$ThisFileInfo['lpac']['flags']['adaptive_prediction_order'] = (bool) ($flags['parameters'] & 0x00800000);
$ThisFileInfo['lpac']['flags']['adaptive_quantization'] = (bool) ($flags['parameters'] & 0x00400000);
$ThisFileInfo['lpac']['flags']['joint_stereo'] = (bool) ($flags['parameters'] & 0x00040000);
$ThisFileInfo['lpac']['quantization'] = ($flags['parameters'] & 0x00001F00) >> 8;
$ThisFileInfo['lpac']['max_prediction_order'] = ($flags['parameters'] & 0x0000003F);
if ($ThisFileInfo['lpac']['flags']['fast_compress'] && ($ThisFileInfo['lpac']['max_prediction_order'] != 3)) {
$ThisFileInfo['warning'][] = 'max_prediction_order expected to be "3" if fast_compress is true, actual value is "'.$ThisFileInfo['lpac']['max_prediction_order'].'"';
}
switch ($ThisFileInfo['lpac']['file_version']) {
case 6:
if ($ThisFileInfo['lpac']['flags']['adaptive_quantization']) {
$ThisFileInfo['warning'][] = 'adaptive_quantization expected to be false in LPAC file stucture v6, actually true';
}
if ($ThisFileInfo['lpac']['quantization'] != 20) {
$ThisFileInfo['warning'][] = 'Quantization expected to be 20 in LPAC file stucture v6, actually '.$ThisFileInfo['lpac']['flags']['Q'];
}
break;
default:
//$ThisFileInfo['warning'][] = 'This version of getID3() only supports LPAC file format version 6, this file is version '.$ThisFileInfo['lpac']['file_version'].' - please report to info@getid3.org';
break;
}
$dummy = $ThisFileInfo;
$riff = new getid3_riff($fd, $dummy);
unset($riff);
$ThisFileInfo['avdataoffset'] = $dummy['avdataoffset'];
$ThisFileInfo['riff'] = $dummy['riff'];
$ThisFileInfo['error'] = $dummy['error'];
$ThisFileInfo['warning'] = $dummy['warning'];
$ThisFileInfo['lpac']['comments']['comment'] = $dummy['comments'];
$ThisFileInfo['audio']['sample_rate'] = $dummy['audio']['sample_rate'];
$ThisFileInfo['audio']['channels'] = ($ThisFileInfo['lpac']['flags']['stereo'] ? 2 : 1);
if ($ThisFileInfo['lpac']['flags']['24_bit']) {
$ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['riff']['audio'][0]['bits_per_sample'];
} elseif ($ThisFileInfo['lpac']['flags']['16_bit']) {
$ThisFileInfo['audio']['bits_per_sample'] = 16;
} else {
$ThisFileInfo['audio']['bits_per_sample'] = 8;
}
if ($ThisFileInfo['lpac']['flags']['fast_compress']) {
// fast
$ThisFileInfo['audio']['encoder_options'] = '-1';
} else {
switch ($ThisFileInfo['lpac']['max_prediction_order']) {
case 20: // simple
$ThisFileInfo['audio']['encoder_options'] = '-2';
break;
case 30: // medium
$ThisFileInfo['audio']['encoder_options'] = '-3';
break;
case 40: // high
$ThisFileInfo['audio']['encoder_options'] = '-4';
break;
case 60: // extrahigh
$ThisFileInfo['audio']['encoder_options'] = '-5';
break;
}
}
$ThisFileInfo['playtime_seconds'] = $ThisFileInfo['lpac']['total_samples'] / $ThisFileInfo['audio']['sample_rate'];
$ThisFileInfo['audio']['bitrate'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['playtime_seconds'];
return true;
}
}
?>

View File

@ -1,522 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio.midi.php //
// module for Midi Audio files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_midi
{
function getid3_midi(&$fd, &$ThisFileInfo, $scanwholefile=true) {
// shortcut
$ThisFileInfo['midi']['raw'] = array();
$thisfile_midi = &$ThisFileInfo['midi'];
$thisfile_midi_raw = &$thisfile_midi['raw'];
$ThisFileInfo['fileformat'] = 'midi';
$ThisFileInfo['audio']['dataformat'] = 'midi';
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$MIDIdata = fread($fd, GETID3_FREAD_BUFFER_SIZE);
$offset = 0;
$MIDIheaderID = substr($MIDIdata, $offset, 4); // 'MThd'
if ($MIDIheaderID != 'MThd') {
$ThisFileInfo['error'][] = 'Expecting "MThd" at offset '.$ThisFileInfo['avdataoffset'].', found "'.$MIDIheaderID.'"';
unset($ThisFileInfo['fileformat']);
return false;
}
$offset += 4;
$thisfile_midi_raw['headersize'] = getid3_lib::BigEndian2Int(substr($MIDIdata, $offset, 4));
$offset += 4;
$thisfile_midi_raw['fileformat'] = getid3_lib::BigEndian2Int(substr($MIDIdata, $offset, 2));
$offset += 2;
$thisfile_midi_raw['tracks'] = getid3_lib::BigEndian2Int(substr($MIDIdata, $offset, 2));
$offset += 2;
$thisfile_midi_raw['ticksperqnote'] = getid3_lib::BigEndian2Int(substr($MIDIdata, $offset, 2));
$offset += 2;
for ($i = 0; $i < $thisfile_midi_raw['tracks']; $i++) {
if ((strlen($MIDIdata) - $offset) < 8) {
$MIDIdata .= fread($fd, GETID3_FREAD_BUFFER_SIZE);
}
$trackID = substr($MIDIdata, $offset, 4);
$offset += 4;
if ($trackID == 'MTrk') {
$tracksize = getid3_lib::BigEndian2Int(substr($MIDIdata, $offset, 4));
$offset += 4;
// $thisfile_midi['tracks'][$i]['size'] = $tracksize;
$trackdataarray[$i] = substr($MIDIdata, $offset, $tracksize);
$offset += $tracksize;
} else {
$ThisFileInfo['error'][] = 'Expecting "MTrk" at '.$offset.', found '.$trackID.' instead';
return false;
}
}
if (!isset($trackdataarray) || !is_array($trackdataarray)) {
$ThisFileInfo['error'][] = 'Cannot find MIDI track information';
unset($thisfile_midi);
unset($ThisFileInfo['fileformat']);
return false;
}
if ($scanwholefile) { // this can take quite a long time, so have the option to bypass it if speed is very important
$thisfile_midi['totalticks'] = 0;
$ThisFileInfo['playtime_seconds'] = 0;
$CurrentMicroSecondsPerBeat = 500000; // 120 beats per minute; 60,000,000 microseconds per minute -> 500,000 microseconds per beat
$CurrentBeatsPerMinute = 120; // 120 beats per minute; 60,000,000 microseconds per minute -> 500,000 microseconds per beat
$MicroSecondsPerQuarterNoteAfter = array ();
foreach ($trackdataarray as $tracknumber => $trackdata) {
$eventsoffset = 0;
$LastIssuedMIDIcommand = 0;
$LastIssuedMIDIchannel = 0;
$CumulativeDeltaTime = 0;
$TicksAtCurrentBPM = 0;
while ($eventsoffset < strlen($trackdata)) {
$eventid = 0;
if (isset($MIDIevents[$tracknumber]) && is_array($MIDIevents[$tracknumber])) {
$eventid = count($MIDIevents[$tracknumber]);
}
$deltatime = 0;
for ($i = 0; $i < 4; $i++) {
$deltatimebyte = ord(substr($trackdata, $eventsoffset++, 1));
$deltatime = ($deltatime << 7) + ($deltatimebyte & 0x7F);
if ($deltatimebyte & 0x80) {
// another byte follows
} else {
break;
}
}
$CumulativeDeltaTime += $deltatime;
$TicksAtCurrentBPM += $deltatime;
$MIDIevents[$tracknumber][$eventid]['deltatime'] = $deltatime;
$MIDI_event_channel = ord(substr($trackdata, $eventsoffset++, 1));
if ($MIDI_event_channel & 0x80) {
// OK, normal event - MIDI command has MSB set
$LastIssuedMIDIcommand = $MIDI_event_channel >> 4;
$LastIssuedMIDIchannel = $MIDI_event_channel & 0x0F;
} else {
// running event - assume last command
$eventsoffset--;
}
$MIDIevents[$tracknumber][$eventid]['eventid'] = $LastIssuedMIDIcommand;
$MIDIevents[$tracknumber][$eventid]['channel'] = $LastIssuedMIDIchannel;
if ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x08) { // Note off (key is released)
$notenumber = ord(substr($trackdata, $eventsoffset++, 1));
$velocity = ord(substr($trackdata, $eventsoffset++, 1));
} elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x09) { // Note on (key is pressed)
$notenumber = ord(substr($trackdata, $eventsoffset++, 1));
$velocity = ord(substr($trackdata, $eventsoffset++, 1));
} elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0A) { // Key after-touch
$notenumber = ord(substr($trackdata, $eventsoffset++, 1));
$velocity = ord(substr($trackdata, $eventsoffset++, 1));
} elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0B) { // Control Change
$controllernum = ord(substr($trackdata, $eventsoffset++, 1));
$newvalue = ord(substr($trackdata, $eventsoffset++, 1));
} elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0C) { // Program (patch) change
$newprogramnum = ord(substr($trackdata, $eventsoffset++, 1));
$thisfile_midi_raw['track'][$tracknumber]['instrumentid'] = $newprogramnum;
if ($tracknumber == 10) {
$thisfile_midi_raw['track'][$tracknumber]['instrument'] = $this->GeneralMIDIpercussionLookup($newprogramnum);
} else {
$thisfile_midi_raw['track'][$tracknumber]['instrument'] = $this->GeneralMIDIinstrumentLookup($newprogramnum);
}
} elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0D) { // Channel after-touch
$channelnumber = ord(substr($trackdata, $eventsoffset++, 1));
} elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0E) { // Pitch wheel change (2000H is normal or no change)
$changeLSB = ord(substr($trackdata, $eventsoffset++, 1));
$changeMSB = ord(substr($trackdata, $eventsoffset++, 1));
$pitchwheelchange = (($changeMSB & 0x7F) << 7) & ($changeLSB & 0x7F);
} elseif (($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0F) && ($MIDIevents[$tracknumber][$eventid]['channel'] == 0x0F)) {
$METAeventCommand = ord(substr($trackdata, $eventsoffset++, 1));
$METAeventLength = ord(substr($trackdata, $eventsoffset++, 1));
$METAeventData = substr($trackdata, $eventsoffset, $METAeventLength);
$eventsoffset += $METAeventLength;
switch ($METAeventCommand) {
case 0x00: // Set track sequence number
$track_sequence_number = getid3_lib::BigEndian2Int(substr($METAeventData, 0, $METAeventLength));
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['seqno'] = $track_sequence_number;
break;
case 0x01: // Text: generic
$text_generic = substr($METAeventData, 0, $METAeventLength);
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['text'] = $text_generic;
$thisfile_midi['comments']['comment'][] = $text_generic;
break;
case 0x02: // Text: copyright
$text_copyright = substr($METAeventData, 0, $METAeventLength);
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['copyright'] = $text_copyright;
$thisfile_midi['comments']['copyright'][] = $text_copyright;
break;
case 0x03: // Text: track name
$text_trackname = substr($METAeventData, 0, $METAeventLength);
$thisfile_midi_raw['track'][$tracknumber]['name'] = $text_trackname;
break;
case 0x04: // Text: track instrument name
$text_instrument = substr($METAeventData, 0, $METAeventLength);
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['instrument'] = $text_instrument;
break;
case 0x05: // Text: lyrics
$text_lyrics = substr($METAeventData, 0, $METAeventLength);
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['lyrics'] = $text_lyrics;
if (!isset($thisfile_midi['lyrics'])) {
$thisfile_midi['lyrics'] = '';
}
$thisfile_midi['lyrics'] .= $text_lyrics."\n";
break;
case 0x06: // Text: marker
$text_marker = substr($METAeventData, 0, $METAeventLength);
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['marker'] = $text_marker;
break;
case 0x07: // Text: cue point
$text_cuepoint = substr($METAeventData, 0, $METAeventLength);
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['cuepoint'] = $text_cuepoint;
break;
case 0x2F: // End Of Track
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['EOT'] = $CumulativeDeltaTime;
break;
case 0x51: // Tempo: microseconds / quarter note
$CurrentMicroSecondsPerBeat = getid3_lib::BigEndian2Int(substr($METAeventData, 0, $METAeventLength));
if ($CurrentMicroSecondsPerBeat == 0) {
$ThisFileInfo['error'][] = 'Corrupt MIDI file: CurrentMicroSecondsPerBeat == zero';
return false;
}
$thisfile_midi_raw['events'][$tracknumber][$CumulativeDeltaTime]['us_qnote'] = $CurrentMicroSecondsPerBeat;
$CurrentBeatsPerMinute = (1000000 / $CurrentMicroSecondsPerBeat) * 60;
$MicroSecondsPerQuarterNoteAfter[$CumulativeDeltaTime] = $CurrentMicroSecondsPerBeat;
$TicksAtCurrentBPM = 0;
break;
case 0x58: // Time signature
$timesig_numerator = getid3_lib::BigEndian2Int($METAeventData{0});
$timesig_denominator = pow(2, getid3_lib::BigEndian2Int($METAeventData{1})); // $02 -> x/4, $03 -> x/8, etc
$timesig_32inqnote = getid3_lib::BigEndian2Int($METAeventData{2}); // number of 32nd notes to the quarter note
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_32inqnote'] = $timesig_32inqnote;
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_numerator'] = $timesig_numerator;
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_denominator'] = $timesig_denominator;
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_text'] = $timesig_numerator.'/'.$timesig_denominator;
$thisfile_midi['timesignature'][] = $timesig_numerator.'/'.$timesig_denominator;
break;
case 0x59: // Keysignature
$keysig_sharpsflats = getid3_lib::BigEndian2Int($METAeventData{0});
if ($keysig_sharpsflats & 0x80) {
// (-7 -> 7 flats, 0 ->key of C, 7 -> 7 sharps)
$keysig_sharpsflats -= 256;
}
$keysig_majorminor = getid3_lib::BigEndian2Int($METAeventData{1}); // 0 -> major, 1 -> minor
$keysigs = array(-7=>'Cb', -6=>'Gb', -5=>'Db', -4=>'Ab', -3=>'Eb', -2=>'Bb', -1=>'F', 0=>'C', 1=>'G', 2=>'D', 3=>'A', 4=>'E', 5=>'B', 6=>'F#', 7=>'C#');
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_sharps'] = (($keysig_sharpsflats > 0) ? abs($keysig_sharpsflats) : 0);
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_flats'] = (($keysig_sharpsflats < 0) ? abs($keysig_sharpsflats) : 0);
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_minor'] = (bool) $keysig_majorminor;
//$thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_text'] = $keysigs[$keysig_sharpsflats].' '.($thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_minor'] ? 'minor' : 'major');
// $keysigs[$keysig_sharpsflats] gets an int key (correct) - $keysigs["$keysig_sharpsflats"] gets a string key (incorrect)
$thisfile_midi['keysignature'][] = $keysigs[$keysig_sharpsflats].' '.((bool) $keysig_majorminor ? 'minor' : 'major');
break;
case 0x7F: // Sequencer specific information
$custom_data = substr($METAeventData, 0, $METAeventLength);
break;
default:
$ThisFileInfo['warning'][] = 'Unhandled META Event Command: '.$METAeventCommand;
break;
}
} else {
$ThisFileInfo['warning'][] = 'Unhandled MIDI Event ID: '.$MIDIevents[$tracknumber][$eventid]['eventid'].' + Channel ID: '.$MIDIevents[$tracknumber][$eventid]['channel'];
}
}
if (($tracknumber > 0) || (count($trackdataarray) == 1)) {
$thisfile_midi['totalticks'] = max($thisfile_midi['totalticks'], $CumulativeDeltaTime);
}
}
$previoustickoffset = null;
ksort($MicroSecondsPerQuarterNoteAfter);
foreach ($MicroSecondsPerQuarterNoteAfter as $tickoffset => $microsecondsperbeat) {
if (is_null($previoustickoffset)) {
$prevmicrosecondsperbeat = $microsecondsperbeat;
$previoustickoffset = $tickoffset;
continue;
}
if ($thisfile_midi['totalticks'] > $tickoffset) {
if ($thisfile_midi_raw['ticksperqnote'] == 0) {
$ThisFileInfo['error'][] = 'Corrupt MIDI file: ticksperqnote == zero';
return false;
}
$ThisFileInfo['playtime_seconds'] += (($tickoffset - $previoustickoffset) / $thisfile_midi_raw['ticksperqnote']) * ($prevmicrosecondsperbeat / 1000000);
$prevmicrosecondsperbeat = $microsecondsperbeat;
$previoustickoffset = $tickoffset;
}
}
if ($thisfile_midi['totalticks'] > $previoustickoffset) {
if ($thisfile_midi_raw['ticksperqnote'] == 0) {
$ThisFileInfo['error'][] = 'Corrupt MIDI file: ticksperqnote == zero';
return false;
}
$ThisFileInfo['playtime_seconds'] += (($thisfile_midi['totalticks'] - $previoustickoffset) / $thisfile_midi_raw['ticksperqnote']) * ($microsecondsperbeat / 1000000);
}
}
if (@$ThisFileInfo['playtime_seconds'] > 0) {
$ThisFileInfo['bitrate'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['playtime_seconds'];
}
if (!empty($thisfile_midi['lyrics'])) {
$thisfile_midi['comments']['lyrics'][] = $thisfile_midi['lyrics'];
}
return true;
}
function GeneralMIDIinstrumentLookup($instrumentid) {
$begin = __LINE__;
/** This is not a comment!
0 Acoustic Grand
1 Bright Acoustic
2 Electric Grand
3 Honky-Tonk
4 Electric Piano 1
5 Electric Piano 2
6 Harpsichord
7 Clavier
8 Celesta
9 Glockenspiel
10 Music Box
11 Vibraphone
12 Marimba
13 Xylophone
14 Tubular Bells
15 Dulcimer
16 Drawbar Organ
17 Percussive Organ
18 Rock Organ
19 Church Organ
20 Reed Organ
21 Accordian
22 Harmonica
23 Tango Accordian
24 Acoustic Guitar (nylon)
25 Acoustic Guitar (steel)
26 Electric Guitar (jazz)
27 Electric Guitar (clean)
28 Electric Guitar (muted)
29 Overdriven Guitar
30 Distortion Guitar
31 Guitar Harmonics
32 Acoustic Bass
33 Electric Bass (finger)
34 Electric Bass (pick)
35 Fretless Bass
36 Slap Bass 1
37 Slap Bass 2
38 Synth Bass 1
39 Synth Bass 2
40 Violin
41 Viola
42 Cello
43 Contrabass
44 Tremolo Strings
45 Pizzicato Strings
46 Orchestral Strings
47 Timpani
48 String Ensemble 1
49 String Ensemble 2
50 SynthStrings 1
51 SynthStrings 2
52 Choir Aahs
53 Voice Oohs
54 Synth Voice
55 Orchestra Hit
56 Trumpet
57 Trombone
58 Tuba
59 Muted Trumpet
60 French Horn
61 Brass Section
62 SynthBrass 1
63 SynthBrass 2
64 Soprano Sax
65 Alto Sax
66 Tenor Sax
67 Baritone Sax
68 Oboe
69 English Horn
70 Bassoon
71 Clarinet
72 Piccolo
73 Flute
74 Recorder
75 Pan Flute
76 Blown Bottle
77 Shakuhachi
78 Whistle
79 Ocarina
80 Lead 1 (square)
81 Lead 2 (sawtooth)
82 Lead 3 (calliope)
83 Lead 4 (chiff)
84 Lead 5 (charang)
85 Lead 6 (voice)
86 Lead 7 (fifths)
87 Lead 8 (bass + lead)
88 Pad 1 (new age)
89 Pad 2 (warm)
90 Pad 3 (polysynth)
91 Pad 4 (choir)
92 Pad 5 (bowed)
93 Pad 6 (metallic)
94 Pad 7 (halo)
95 Pad 8 (sweep)
96 FX 1 (rain)
97 FX 2 (soundtrack)
98 FX 3 (crystal)
99 FX 4 (atmosphere)
100 FX 5 (brightness)
101 FX 6 (goblins)
102 FX 7 (echoes)
103 FX 8 (sci-fi)
104 Sitar
105 Banjo
106 Shamisen
107 Koto
108 Kalimba
109 Bagpipe
110 Fiddle
111 Shanai
112 Tinkle Bell
113 Agogo
114 Steel Drums
115 Woodblock
116 Taiko Drum
117 Melodic Tom
118 Synth Drum
119 Reverse Cymbal
120 Guitar Fret Noise
121 Breath Noise
122 Seashore
123 Bird Tweet
124 Telephone Ring
125 Helicopter
126 Applause
127 Gunshot
*/
return getid3_lib::EmbeddedLookup($instrumentid, $begin, __LINE__, __FILE__, 'GeneralMIDIinstrument');
}
function GeneralMIDIpercussionLookup($instrumentid) {
$begin = __LINE__;
/** This is not a comment!
35 Acoustic Bass Drum
36 Bass Drum 1
37 Side Stick
38 Acoustic Snare
39 Hand Clap
40 Electric Snare
41 Low Floor Tom
42 Closed Hi-Hat
43 High Floor Tom
44 Pedal Hi-Hat
45 Low Tom
46 Open Hi-Hat
47 Low-Mid Tom
48 Hi-Mid Tom
49 Crash Cymbal 1
50 High Tom
51 Ride Cymbal 1
52 Chinese Cymbal
53 Ride Bell
54 Tambourine
55 Splash Cymbal
56 Cowbell
57 Crash Cymbal 2
59 Ride Cymbal 2
60 Hi Bongo
61 Low Bongo
62 Mute Hi Conga
63 Open Hi Conga
64 Low Conga
65 High Timbale
66 Low Timbale
67 High Agogo
68 Low Agogo
69 Cabasa
70 Maracas
71 Short Whistle
72 Long Whistle
73 Short Guiro
74 Long Guiro
75 Claves
76 Hi Wood Block
77 Low Wood Block
78 Mute Cuica
79 Open Cuica
80 Mute Triangle
81 Open Triangle
*/
return getid3_lib::EmbeddedLookup($instrumentid, $begin, __LINE__, __FILE__, 'GeneralMIDIpercussion');
}
}
?>

View File

@ -1,101 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio.mod.php //
// module for analyzing MOD Audio files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_mod
{
// new combined constructor
function getid3_mod(&$fd, &$ThisFileInfo, $option) {
if ($option === 'mod') {
$this->getMODheaderFilepointer($fd, $ThisFileInfo);
}
elseif ($option === 'xm') {
$this->getXMheaderFilepointer($fd, $ThisFileInfo);
}
elseif ($option === 'it') {
$this->getITheaderFilepointer($fd, $ThisFileInfo);
}
elseif ($option === 's3m') {
$this->getS3MheaderFilepointer($fd, $ThisFileInfo);
}
}
function getMODheaderFilepointer(&$fd, &$ThisFileInfo) {
fseek($fd, $ThisFileInfo['avdataoffset'] + 1080);
$FormatID = fread($fd, 4);
if (!ereg('^(M.K.|[5-9]CHN|[1-3][0-9]CH)$', $FormatID)) {
$ThisFileInfo['error'][] = 'This is not a known type of MOD file';
return false;
}
$ThisFileInfo['fileformat'] = 'mod';
$ThisFileInfo['error'][] = 'MOD parsing not enabled in this version of getID3()';
return false;
}
function getXMheaderFilepointer(&$fd, &$ThisFileInfo) {
fseek($fd, $ThisFileInfo['avdataoffset']);
$FormatID = fread($fd, 15);
if (!ereg('^Extended Module$', $FormatID)) {
$ThisFileInfo['error'][] = 'This is not a known type of XM-MOD file';
return false;
}
$ThisFileInfo['fileformat'] = 'xm';
$ThisFileInfo['error'][] = 'XM-MOD parsing not enabled in this version of getID3()';
return false;
}
function getS3MheaderFilepointer(&$fd, &$ThisFileInfo) {
fseek($fd, $ThisFileInfo['avdataoffset'] + 44);
$FormatID = fread($fd, 4);
if (!ereg('^SCRM$', $FormatID)) {
$ThisFileInfo['error'][] = 'This is not a ScreamTracker MOD file';
return false;
}
$ThisFileInfo['fileformat'] = 's3m';
$ThisFileInfo['error'][] = 'ScreamTracker parsing not enabled in this version of getID3()';
return false;
}
function getITheaderFilepointer(&$fd, &$ThisFileInfo) {
fseek($fd, $ThisFileInfo['avdataoffset']);
$FormatID = fread($fd, 4);
if (!ereg('^IMPM$', $FormatID)) {
$ThisFileInfo['error'][] = 'This is not an ImpulseTracker MOD file';
return false;
}
$ThisFileInfo['fileformat'] = 'it';
$ThisFileInfo['error'][] = 'ImpulseTracker parsing not enabled in this version of getID3()';
return false;
}
}
?>

View File

@ -1,202 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio.monkey.php //
// module for analyzing Monkey's Audio files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_monkey
{
function getid3_monkey(&$fd, &$ThisFileInfo) {
// based loosely on code from TMonkey by Jurgen Faul <jfaulØgmx*de>
// http://jfaul.de/atl or http://j-faul.virtualave.net/atl/atl.html
$ThisFileInfo['fileformat'] = 'mac';
$ThisFileInfo['audio']['dataformat'] = 'mac';
$ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
$ThisFileInfo['audio']['lossless'] = true;
$ThisFileInfo['monkeys_audio']['raw'] = array();
$thisfile_monkeysaudio = &$ThisFileInfo['monkeys_audio'];
$thisfile_monkeysaudio_raw = &$thisfile_monkeysaudio['raw'];
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$MACheaderData = fread($fd, 74);
$thisfile_monkeysaudio_raw['magic'] = substr($MACheaderData, 0, 4);
if ($thisfile_monkeysaudio_raw['magic'] != 'MAC ') {
$ThisFileInfo['error'][] = 'Expecting "MAC" at offset '.$ThisFileInfo['avdataoffset'].', found "'.$thisfile_monkeysaudio_raw['magic'].'"';
unset($ThisFileInfo['fileformat']);
return false;
}
$thisfile_monkeysaudio_raw['nVersion'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 4, 2)); // appears to be uint32 in 3.98+
if ($thisfile_monkeysaudio_raw['nVersion'] < 3980) {
$thisfile_monkeysaudio_raw['nCompressionLevel'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 6, 2));
$thisfile_monkeysaudio_raw['nFormatFlags'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 8, 2));
$thisfile_monkeysaudio_raw['nChannels'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 10, 2));
$thisfile_monkeysaudio_raw['nSampleRate'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 12, 4));
$thisfile_monkeysaudio_raw['nHeaderDataBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 16, 4));
$thisfile_monkeysaudio_raw['nWAVTerminatingBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 20, 4));
$thisfile_monkeysaudio_raw['nTotalFrames'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 24, 4));
$thisfile_monkeysaudio_raw['nFinalFrameSamples'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 28, 4));
$thisfile_monkeysaudio_raw['nPeakLevel'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 32, 4));
$thisfile_monkeysaudio_raw['nSeekElements'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 38, 2));
$offset = 8;
} else {
$offset = 8;
// APE_DESCRIPTOR
$thisfile_monkeysaudio_raw['nDescriptorBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4));
$offset += 4;
$thisfile_monkeysaudio_raw['nHeaderBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4));
$offset += 4;
$thisfile_monkeysaudio_raw['nSeekTableBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4));
$offset += 4;
$thisfile_monkeysaudio_raw['nHeaderDataBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4));
$offset += 4;
$thisfile_monkeysaudio_raw['nAPEFrameDataBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4));
$offset += 4;
$thisfile_monkeysaudio_raw['nAPEFrameDataBytesHigh'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4));
$offset += 4;
$thisfile_monkeysaudio_raw['nTerminatingDataBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4));
$offset += 4;
$thisfile_monkeysaudio_raw['cFileMD5'] = substr($MACheaderData, $offset, 16);
$offset += 16;
// APE_HEADER
$thisfile_monkeysaudio_raw['nCompressionLevel'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 2));
$offset += 2;
$thisfile_monkeysaudio_raw['nFormatFlags'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 2));
$offset += 2;
$thisfile_monkeysaudio_raw['nBlocksPerFrame'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4));
$offset += 4;
$thisfile_monkeysaudio_raw['nFinalFrameBlocks'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4));
$offset += 4;
$thisfile_monkeysaudio_raw['nTotalFrames'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4));
$offset += 4;
$thisfile_monkeysaudio_raw['nBitsPerSample'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 2));
$offset += 2;
$thisfile_monkeysaudio_raw['nChannels'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 2));
$offset += 2;
$thisfile_monkeysaudio_raw['nSampleRate'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4));
$offset += 4;
}
$thisfile_monkeysaudio['flags']['8-bit'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x0001);
$thisfile_monkeysaudio['flags']['crc-32'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x0002);
$thisfile_monkeysaudio['flags']['peak_level'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x0004);
$thisfile_monkeysaudio['flags']['24-bit'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x0008);
$thisfile_monkeysaudio['flags']['seek_elements'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x0010);
$thisfile_monkeysaudio['flags']['no_wav_header'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x0020);
$thisfile_monkeysaudio['version'] = $thisfile_monkeysaudio_raw['nVersion'] / 1000;
$thisfile_monkeysaudio['compression'] = $this->MonkeyCompressionLevelNameLookup($thisfile_monkeysaudio_raw['nCompressionLevel']);
if ($thisfile_monkeysaudio_raw['nVersion'] < 3980) {
$thisfile_monkeysaudio['samples_per_frame'] = $this->MonkeySamplesPerFrame($thisfile_monkeysaudio_raw['nVersion'], $thisfile_monkeysaudio_raw['nCompressionLevel']);
}
$thisfile_monkeysaudio['bits_per_sample'] = ($thisfile_monkeysaudio['flags']['24-bit'] ? 24 : ($thisfile_monkeysaudio['flags']['8-bit'] ? 8 : 16));
$thisfile_monkeysaudio['channels'] = $thisfile_monkeysaudio_raw['nChannels'];
$ThisFileInfo['audio']['channels'] = $thisfile_monkeysaudio['channels'];
$thisfile_monkeysaudio['sample_rate'] = $thisfile_monkeysaudio_raw['nSampleRate'];
if ($thisfile_monkeysaudio['sample_rate'] == 0) {
$ThisFileInfo['error'][] = 'Corrupt MAC file: frequency == zero';
return false;
}
$ThisFileInfo['audio']['sample_rate'] = $thisfile_monkeysaudio['sample_rate'];
if ($thisfile_monkeysaudio['flags']['peak_level']) {
$thisfile_monkeysaudio['peak_level'] = $thisfile_monkeysaudio_raw['nPeakLevel'];
$thisfile_monkeysaudio['peak_ratio'] = $thisfile_monkeysaudio['peak_level'] / pow(2, $thisfile_monkeysaudio['bits_per_sample'] - 1);
}
if ($thisfile_monkeysaudio_raw['nVersion'] >= 3980) {
$thisfile_monkeysaudio['samples'] = (($thisfile_monkeysaudio_raw['nTotalFrames'] - 1) * $thisfile_monkeysaudio_raw['nBlocksPerFrame']) + $thisfile_monkeysaudio_raw['nFinalFrameBlocks'];
} else {
$thisfile_monkeysaudio['samples'] = (($thisfile_monkeysaudio_raw['nTotalFrames'] - 1) * $thisfile_monkeysaudio['samples_per_frame']) + $thisfile_monkeysaudio_raw['nFinalFrameSamples'];
}
$thisfile_monkeysaudio['playtime'] = $thisfile_monkeysaudio['samples'] / $thisfile_monkeysaudio['sample_rate'];
if ($thisfile_monkeysaudio['playtime'] == 0) {
$ThisFileInfo['error'][] = 'Corrupt MAC file: playtime == zero';
return false;
}
$ThisFileInfo['playtime_seconds'] = $thisfile_monkeysaudio['playtime'];
$thisfile_monkeysaudio['compressed_size'] = $ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset'];
$thisfile_monkeysaudio['uncompressed_size'] = $thisfile_monkeysaudio['samples'] * $thisfile_monkeysaudio['channels'] * ($thisfile_monkeysaudio['bits_per_sample'] / 8);
if ($thisfile_monkeysaudio['uncompressed_size'] == 0) {
$ThisFileInfo['error'][] = 'Corrupt MAC file: uncompressed_size == zero';
return false;
}
$thisfile_monkeysaudio['compression_ratio'] = $thisfile_monkeysaudio['compressed_size'] / ($thisfile_monkeysaudio['uncompressed_size'] + $thisfile_monkeysaudio_raw['nHeaderDataBytes']);
$thisfile_monkeysaudio['bitrate'] = (($thisfile_monkeysaudio['samples'] * $thisfile_monkeysaudio['channels'] * $thisfile_monkeysaudio['bits_per_sample']) / $thisfile_monkeysaudio['playtime']) * $thisfile_monkeysaudio['compression_ratio'];
$ThisFileInfo['audio']['bitrate'] = $thisfile_monkeysaudio['bitrate'];
// add size of MAC header to avdataoffset
if ($thisfile_monkeysaudio_raw['nVersion'] >= 3980) {
$ThisFileInfo['avdataoffset'] += $thisfile_monkeysaudio_raw['nDescriptorBytes'];
$ThisFileInfo['avdataoffset'] += $thisfile_monkeysaudio_raw['nHeaderBytes'];
$ThisFileInfo['avdataoffset'] += $thisfile_monkeysaudio_raw['nSeekTableBytes'];
$ThisFileInfo['avdataoffset'] += $thisfile_monkeysaudio_raw['nHeaderDataBytes'];
$ThisFileInfo['avdataend'] -= $thisfile_monkeysaudio_raw['nTerminatingDataBytes'];
} else {
$ThisFileInfo['avdataoffset'] += $offset;
}
if ($thisfile_monkeysaudio_raw['nVersion'] >= 3980) {
if ($thisfile_monkeysaudio_raw['cFileMD5'] === str_repeat("\x00", 16)) {
//$ThisFileInfo['warning'][] = 'cFileMD5 is null';
} else {
$ThisFileInfo['md5_data_source'] = '';
$md5 = $thisfile_monkeysaudio_raw['cFileMD5'];
for ($i = 0; $i < strlen($md5); $i++) {
$ThisFileInfo['md5_data_source'] .= str_pad(dechex(ord($md5{$i})), 2, '00', STR_PAD_LEFT);
}
if (!preg_match('/^[0-9a-f]{32}$/', $ThisFileInfo['md5_data_source'])) {
unset($ThisFileInfo['md5_data_source']);
}
}
}
$ThisFileInfo['audio']['bits_per_sample'] = $thisfile_monkeysaudio['bits_per_sample'];
$ThisFileInfo['audio']['encoder'] = 'MAC v'.number_format($thisfile_monkeysaudio['version'], 2);
$ThisFileInfo['audio']['encoder_options'] = ucfirst($thisfile_monkeysaudio['compression']).' compression';
return true;
}
function MonkeyCompressionLevelNameLookup($compressionlevel) {
static $MonkeyCompressionLevelNameLookup = array(
0 => 'unknown',
1000 => 'fast',
2000 => 'normal',
3000 => 'high',
4000 => 'extra-high',
5000 => 'insane'
);
return (isset($MonkeyCompressionLevelNameLookup[$compressionlevel]) ? $MonkeyCompressionLevelNameLookup[$compressionlevel] : 'invalid');
}
function MonkeySamplesPerFrame($versionid, $compressionlevel) {
if ($versionid >= 3950) {
return 73728 * 4;
} elseif ($versionid >= 3900) {
return 73728;
} elseif (($versionid >= 3800) && ($compressionlevel == 4000)) {
return 73728;
} else {
return 9216;
}
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@ -1,502 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio.mpc.php //
// module for analyzing Musepack/MPEG+ Audio files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_mpc
{
function getid3_mpc(&$fd, &$ThisFileInfo) {
$ThisFileInfo['mpc']['header'] = array();
$thisfile_mpc_header = &$ThisFileInfo['mpc']['header'];
$ThisFileInfo['fileformat'] = 'mpc';
$ThisFileInfo['audio']['dataformat'] = 'mpc';
$ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
$ThisFileInfo['audio']['channels'] = 2; // up to SV7 the format appears to have been hardcoded for stereo only
$ThisFileInfo['audio']['lossless'] = false;
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$MPCheaderData = fread($fd, 4);
$ThisFileInfo['mpc']['header']['preamble'] = substr($MPCheaderData, 0, 4); // should be 'MPCK' (SV8) or 'MP+' (SV7), otherwise possible stream data (SV4-SV6)
if (ereg('^MPCK', $ThisFileInfo['mpc']['header']['preamble'])) {
// this is SV8
return $this->ParseMPCsv8($fd, $ThisFileInfo);
} elseif (ereg('^MP\+', $ThisFileInfo['mpc']['header']['preamble'])) {
// this is SV7
return $this->ParseMPCsv7($fd, $ThisFileInfo);
} elseif (preg_match('/^[\x00\x01\x10\x11\x40\x41\x50\x51\x80\x81\x90\x91\xC0\xC1\xD0\xD1][\x20-37][\x00\x20\x40\x60\x80\xA0\xC0\xE0]/s', $MPCheaderData)) {
// this is SV4 - SV6, handle seperately
return $this->ParseMPCsv6($fd, $ThisFileInfo);
} else {
$ThisFileInfo['error'][] = 'Expecting "MP+" or "MPCK" at offset '.$ThisFileInfo['avdataoffset'].', found "'.substr($MPCheaderData, 0, 4).'"';
unset($ThisFileInfo['fileformat']);
unset($ThisFileInfo['mpc']);
return false;
}
return false;
}
function ParseMPCsv8(&$fd, &$ThisFileInfo) {
// this is SV8
// http://trac.musepack.net/trac/wiki/SV8Specification
$thisfile_mpc_header = &$ThisFileInfo['mpc']['header'];
$keyNameSize = 2;
$maxHandledPacketLength = 9; // specs say: "n*8; 0 < n < 10"
$offset = ftell($fd);
while ($offset < $ThisFileInfo['avdataend']) {
$thisPacket = array();
$thisPacket['offset'] = $offset;
$packet_offset = 0;
// Size is a variable-size field, could be 1-4 bytes (possibly more?)
// read enough data in and figure out the exact size later
$MPCheaderData = fread($fd, $keyNameSize + $maxHandledPacketLength);
$packet_offset += $keyNameSize;
$thisPacket['key'] = substr($MPCheaderData, 0, $keyNameSize);
$thisPacket['key_name'] = $this->MPCsv8PacketName($thisPacket['key']);
if ($thisPacket['key'] == $thisPacket['key_name']) {
$ThisFileInfo['error'][] = 'Found unexpected key value "'.$thisPacket['key'].'" at offset '.$thisPacket['offset'];
return false;
}
$packetLength = 0;
$thisPacket['packet_size'] = $this->SV8variableLengthInteger(substr($MPCheaderData, $keyNameSize), $packetLength); // includes keyname and packet_size field
if ($thisPacket['packet_size'] === false) {
$ThisFileInfo['error'][] = 'Did not find expected packet length within '.$maxHandledPacketLength.' bytes at offset '.($thisPacket['offset'] + $keyNameSize);
return false;
}
$packet_offset += $packetLength;
$offset += $thisPacket['packet_size'];
switch ($thisPacket['key']) {
case 'SH': // Stream Header
$moreBytesToRead = $thisPacket['packet_size'] - $keyNameSize - $maxHandledPacketLength;
if ($moreBytesToRead > 0) {
$MPCheaderData .= fread($fd, $moreBytesToRead);
}
$thisPacket['crc'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 4));
$packet_offset += 4;
$thisPacket['stream_version'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 1));
$packet_offset += 1;
$packetLength = 0;
$thisPacket['sample_count'] = $this->SV8variableLengthInteger(substr($MPCheaderData, $packet_offset, $maxHandledPacketLength), $packetLength);
$packet_offset += $packetLength;
$packetLength = 0;
$thisPacket['beginning_silence'] = $this->SV8variableLengthInteger(substr($MPCheaderData, $packet_offset, $maxHandledPacketLength), $packetLength);
$packet_offset += $packetLength;
$otherUsefulData = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 2));
$packet_offset += 2;
$thisPacket['sample_frequency_raw'] = (($otherUsefulData & 0xE000) >> 13);
$thisPacket['max_bands_used'] = (($otherUsefulData & 0x1F00) >> 8);
$thisPacket['channels'] = (($otherUsefulData & 0x00F0) >> 4) + 1;
$thisPacket['ms_used'] = (bool) (($otherUsefulData & 0x0008) >> 3);
$thisPacket['audio_block_frames'] = (($otherUsefulData & 0x0007) >> 0);
$thisPacket['sample_frequency'] = $this->MPCfrequencyLookup($thisPacket['sample_frequency_raw']);
$thisfile_mpc_header['mid_side_stereo'] = $thisPacket['ms_used'];
$thisfile_mpc_header['sample_rate'] = $thisPacket['sample_frequency'];
$thisfile_mpc_header['samples'] = $thisPacket['sample_count'];
$thisfile_mpc_header['stream_version_major'] = $thisPacket['stream_version'];
$ThisFileInfo['audio']['channels'] = $thisPacket['channels'];
$ThisFileInfo['audio']['sample_rate'] = $thisPacket['sample_frequency'];
$ThisFileInfo['playtime_seconds'] = $thisPacket['sample_count'] / $thisPacket['sample_frequency'];
$ThisFileInfo['audio']['bitrate'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['playtime_seconds'];
break;
case 'RG': // Replay Gain
$moreBytesToRead = $thisPacket['packet_size'] - $keyNameSize - $maxHandledPacketLength;
if ($moreBytesToRead > 0) {
$MPCheaderData .= fread($fd, $moreBytesToRead);
}
$thisPacket['replaygain_version'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 1));
$packet_offset += 1;
$thisPacket['replaygain_title_gain'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 2));
$packet_offset += 2;
$thisPacket['replaygain_title_peak'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 2));
$packet_offset += 2;
$thisPacket['replaygain_album_gain'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 2));
$packet_offset += 2;
$thisPacket['replaygain_album_peak'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 2));
$packet_offset += 2;
if ($thisPacket['replaygain_title_gain']) { $ThisFileInfo['replay_gain']['title']['gain'] = $thisPacket['replaygain_title_gain']; }
if ($thisPacket['replaygain_title_peak']) { $ThisFileInfo['replay_gain']['title']['peak'] = $thisPacket['replaygain_title_peak']; }
if ($thisPacket['replaygain_album_gain']) { $ThisFileInfo['replay_gain']['album']['gain'] = $thisPacket['replaygain_album_gain']; }
if ($thisPacket['replaygain_album_peak']) { $ThisFileInfo['replay_gain']['album']['peak'] = $thisPacket['replaygain_album_peak']; }
break;
case 'EI': // Encoder Info
$moreBytesToRead = $thisPacket['packet_size'] - $keyNameSize - $maxHandledPacketLength;
if ($moreBytesToRead > 0) {
$MPCheaderData .= fread($fd, $moreBytesToRead);
}
$profile_pns = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 1));
$packet_offset += 1;
$quality_int = (($profile_pns & 0xF0) >> 4);
$quality_dec = (($profile_pns & 0x0E) >> 3);
$thisPacket['quality'] = (float) $quality_int + ($quality_dec / 8);
$thisPacket['pns_tool'] = (bool) (($profile_pns & 0x01) >> 0);
$thisPacket['version_major'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 1));
$packet_offset += 1;
$thisPacket['version_minor'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 1));
$packet_offset += 1;
$thisPacket['version_build'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 1));
$packet_offset += 1;
$thisPacket['version'] = $thisPacket['version_major'].'.'.$thisPacket['version_minor'].'.'.$thisPacket['version_build'];
$ThisFileInfo['audio']['encoder'] = 'MPC v'.$thisPacket['version'].' ('.(($thisPacket['version_minor'] % 2) ? 'unstable' : 'stable').')';
$thisfile_mpc_header['encoder_version'] = $ThisFileInfo['audio']['encoder'];
//$thisfile_mpc_header['quality'] = (float) ($thisPacket['quality'] / 1.5875); // values can range from 0.000 to 15.875, mapped to qualities of 0.0 to 10.0
$thisfile_mpc_header['quality'] = (float) ($thisPacket['quality'] - 5); // values can range from 0.000 to 15.875, of which 0..4 are "reserved/experimental", and 5..15 are mapped to qualities of 0.0 to 10.0
break;
case 'SO': // Seek Table Offset
$packetLength = 0;
$thisPacket['seek_table_offset'] = $thisPacket['offset'] + $this->SV8variableLengthInteger(substr($MPCheaderData, $packet_offset, $maxHandledPacketLength), $packetLength);
$packet_offset += $packetLength;
break;
case 'ST': // Seek Table
case 'SE': // Stream End
case 'AP': // Audio Data
// nothing useful here, just skip this packet
$thisPacket = array();
break;
default:
$ThisFileInfo['error'][] = 'Found unhandled key type "'.$thisPacket['key'].'" at offset '.$thisPacket['offset'];
return false;
break;
}
if (!empty($thisPacket)) {
$ThisFileInfo['mpc']['packets'][] = $thisPacket;
}
fseek($fd, $offset);
}
$thisfile_mpc_header['size'] = $offset;
return true;
}
function ParseMPCsv7(&$fd, &$ThisFileInfo) {
// this is SV7
// http://www.uni-jena.de/~pfk/mpp/sv8/header.html
$thisfile_mpc_header = &$ThisFileInfo['mpc']['header'];
$offset = 0;
$thisfile_mpc_header['size'] = 28;
$MPCheaderData = $ThisFileInfo['mpc']['header']['preamble'];
$MPCheaderData .= fread($fd, $thisfile_mpc_header['size'] - strlen($ThisFileInfo['mpc']['header']['preamble']));
$offset = strlen('MP+');
$StreamVersionByte = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 1));
$offset += 1;
$thisfile_mpc_header['stream_version_major'] = ($StreamVersionByte & 0x0F) >> 0;
$thisfile_mpc_header['stream_version_minor'] = ($StreamVersionByte & 0xF0) >> 4; // should always be 0, subversions no longer exist in SV8
$thisfile_mpc_header['frame_count'] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 4));
$offset += 4;
if ($thisfile_mpc_header['stream_version_major'] != 7) {
$ThisFileInfo['error'][] = 'Only Musepack SV7 supported (this file claims to be v'.$thisfile_mpc_header['stream_version_major'].')';
return false;
}
$FlagsDWORD1 = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 4));
$offset += 4;
$thisfile_mpc_header['intensity_stereo'] = (bool) (($FlagsDWORD1 & 0x80000000) >> 31);
$thisfile_mpc_header['mid_side_stereo'] = (bool) (($FlagsDWORD1 & 0x40000000) >> 30);
$thisfile_mpc_header['max_subband'] = ($FlagsDWORD1 & 0x3F000000) >> 24;
$thisfile_mpc_header['raw']['profile'] = ($FlagsDWORD1 & 0x00F00000) >> 20;
$thisfile_mpc_header['begin_loud'] = (bool) (($FlagsDWORD1 & 0x00080000) >> 19);
$thisfile_mpc_header['end_loud'] = (bool) (($FlagsDWORD1 & 0x00040000) >> 18);
$thisfile_mpc_header['raw']['sample_rate'] = ($FlagsDWORD1 & 0x00030000) >> 16;
$thisfile_mpc_header['max_level'] = ($FlagsDWORD1 & 0x0000FFFF);
$thisfile_mpc_header['raw']['title_peak'] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 2));
$offset += 2;
$thisfile_mpc_header['raw']['title_gain'] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 2), true);
$offset += 2;
$thisfile_mpc_header['raw']['album_peak'] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 2));
$offset += 2;
$thisfile_mpc_header['raw']['album_gain'] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 2), true);
$offset += 2;
$FlagsDWORD2 = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 4));
$offset += 4;
$thisfile_mpc_header['true_gapless'] = (bool) (($FlagsDWORD2 & 0x80000000) >> 31);
$thisfile_mpc_header['last_frame_length'] = ($FlagsDWORD2 & 0x7FF00000) >> 20;
$thisfile_mpc_header['raw']['not_sure_what'] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 3));
$offset += 3;
$thisfile_mpc_header['raw']['encoder_version'] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 1));
$offset += 1;
$thisfile_mpc_header['profile'] = $this->MPCprofileNameLookup($thisfile_mpc_header['raw']['profile']);
$thisfile_mpc_header['sample_rate'] = $this->MPCfrequencyLookup($thisfile_mpc_header['raw']['sample_rate']);
if ($thisfile_mpc_header['sample_rate'] == 0) {
$ThisFileInfo['error'][] = 'Corrupt MPC file: frequency == zero';
return false;
}
$ThisFileInfo['audio']['sample_rate'] = $thisfile_mpc_header['sample_rate'];
$thisfile_mpc_header['samples'] = ((($thisfile_mpc_header['frame_count'] - 1) * 1152) + $thisfile_mpc_header['last_frame_length']) * $ThisFileInfo['audio']['channels'];
$ThisFileInfo['playtime_seconds'] = ($thisfile_mpc_header['samples'] / $ThisFileInfo['audio']['channels']) / $ThisFileInfo['audio']['sample_rate'];
if ($ThisFileInfo['playtime_seconds'] == 0) {
$ThisFileInfo['error'][] = 'Corrupt MPC file: playtime_seconds == zero';
return false;
}
// add size of file header to avdataoffset - calc bitrate correctly + MD5 data
$ThisFileInfo['avdataoffset'] += $thisfile_mpc_header['size'];
$ThisFileInfo['audio']['bitrate'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['playtime_seconds'];
$thisfile_mpc_header['title_peak'] = $thisfile_mpc_header['raw']['title_peak'];
$thisfile_mpc_header['title_peak_db'] = $this->MPCpeakDBLookup($thisfile_mpc_header['title_peak']);
if ($thisfile_mpc_header['raw']['title_gain'] < 0) {
$thisfile_mpc_header['title_gain_db'] = (float) (32768 + $thisfile_mpc_header['raw']['title_gain']) / -100;
} else {
$thisfile_mpc_header['title_gain_db'] = (float) $thisfile_mpc_header['raw']['title_gain'] / 100;
}
$thisfile_mpc_header['album_peak'] = $thisfile_mpc_header['raw']['album_peak'];
$thisfile_mpc_header['album_peak_db'] = $this->MPCpeakDBLookup($thisfile_mpc_header['album_peak']);
if ($thisfile_mpc_header['raw']['album_gain'] < 0) {
$thisfile_mpc_header['album_gain_db'] = (float) (32768 + $thisfile_mpc_header['raw']['album_gain']) / -100;
} else {
$thisfile_mpc_header['album_gain_db'] = (float) $thisfile_mpc_header['raw']['album_gain'] / 100;;
}
$thisfile_mpc_header['encoder_version'] = $this->MPCencoderVersionLookup($thisfile_mpc_header['raw']['encoder_version']);
$ThisFileInfo['replay_gain']['track']['adjustment'] = $thisfile_mpc_header['title_gain_db'];
$ThisFileInfo['replay_gain']['album']['adjustment'] = $thisfile_mpc_header['album_gain_db'];
if ($thisfile_mpc_header['title_peak'] > 0) {
$ThisFileInfo['replay_gain']['track']['peak'] = $thisfile_mpc_header['title_peak'];
} elseif (round($thisfile_mpc_header['max_level'] * 1.18) > 0) {
$ThisFileInfo['replay_gain']['track']['peak'] = getid3_lib::CastAsInt(round($thisfile_mpc_header['max_level'] * 1.18)); // why? I don't know - see mppdec.c
}
if ($thisfile_mpc_header['album_peak'] > 0) {
$ThisFileInfo['replay_gain']['album']['peak'] = $thisfile_mpc_header['album_peak'];
}
//$ThisFileInfo['audio']['encoder'] = 'SV'.$thisfile_mpc_header['stream_version_major'].'.'.$thisfile_mpc_header['stream_version_minor'].', '.$thisfile_mpc_header['encoder_version'];
$ThisFileInfo['audio']['encoder'] = $thisfile_mpc_header['encoder_version'];
$ThisFileInfo['audio']['encoder_options'] = $thisfile_mpc_header['profile'];
$thisfile_mpc_header['quality'] = (float) ($thisfile_mpc_header['raw']['profile'] - 5); // values can range from 0 to 15, of which 0..4 are "reserved/experimental", and 5..15 are mapped to qualities of 0.0 to 10.0
return true;
}
function ParseMPCsv6(&$fd, &$ThisFileInfo) {
// this is SV4 - SV6
$thisfile_mpc_header = &$ThisFileInfo['mpc']['header'];
$offset = 0;
$thisfile_mpc_header['size'] = 8;
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$MPCheaderData = fread($fd, $thisfile_mpc_header['size']);
// add size of file header to avdataoffset - calc bitrate correctly + MD5 data
$ThisFileInfo['avdataoffset'] += $thisfile_mpc_header['size'];
// Most of this code adapted from Jurgen Faul's MPEGplus source code - thanks Jurgen! :)
$HeaderDWORD[0] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, 0, 4));
$HeaderDWORD[1] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, 4, 4));
// DDDD DDDD CCCC CCCC BBBB BBBB AAAA AAAA
// aaaa aaaa abcd dddd dddd deee eeff ffff
//
// a = bitrate = anything
// b = IS = anything
// c = MS = anything
// d = streamversion = 0000000004 or 0000000005 or 0000000006
// e = maxband = anything
// f = blocksize = 000001 for SV5+, anything(?) for SV4
$thisfile_mpc_header['target_bitrate'] = (($HeaderDWORD[0] & 0xFF800000) >> 23);
$thisfile_mpc_header['intensity_stereo'] = (bool) (($HeaderDWORD[0] & 0x00400000) >> 22);
$thisfile_mpc_header['mid_side_stereo'] = (bool) (($HeaderDWORD[0] & 0x00200000) >> 21);
$thisfile_mpc_header['stream_version_major'] = ($HeaderDWORD[0] & 0x001FF800) >> 11;
$thisfile_mpc_header['stream_version_minor'] = 0; // no sub-version numbers before SV7
$thisfile_mpc_header['max_band'] = ($HeaderDWORD[0] & 0x000007C0) >> 6; // related to lowpass frequency, not sure how it translates exactly
$thisfile_mpc_header['block_size'] = ($HeaderDWORD[0] & 0x0000003F);
switch ($thisfile_mpc_header['stream_version_major']) {
case 4:
$thisfile_mpc_header['frame_count'] = ($HeaderDWORD[1] >> 16);
break;
case 5:
case 6:
$thisfile_mpc_header['frame_count'] = $HeaderDWORD[1];
break;
default:
$ThisFileInfo['error'] = 'Expecting 4, 5 or 6 in version field, found '.$thisfile_mpc_header['stream_version_major'].' instead';
unset($ThisFileInfo['mpc']);
return false;
break;
}
if (($thisfile_mpc_header['stream_version_major'] > 4) && ($thisfile_mpc_header['block_size'] != 1)) {
$ThisFileInfo['warning'][] = 'Block size expected to be 1, actual value found: '.$thisfile_mpc_header['block_size'];
}
$thisfile_mpc_header['sample_rate'] = 44100; // AB: used by all files up to SV7
$ThisFileInfo['audio']['sample_rate'] = $thisfile_mpc_header['sample_rate'];
$thisfile_mpc_header['samples'] = $thisfile_mpc_header['frame_count'] * 1152 * $ThisFileInfo['audio']['channels'];
if ($thisfile_mpc_header['target_bitrate'] == 0) {
$ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
} else {
$ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
}
$ThisFileInfo['mpc']['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8 * 44100 / $thisfile_mpc_header['frame_count'] / 1152;
$ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['mpc']['bitrate'];
$ThisFileInfo['audio']['encoder'] = 'SV'.$thisfile_mpc_header['stream_version_major'];
return true;
}
function MPCprofileNameLookup($profileid) {
static $MPCprofileNameLookup = array(
0 => 'no profile',
1 => 'Experimental',
2 => 'unused',
3 => 'unused',
4 => 'unused',
5 => 'below Telephone (q = 0.0)',
6 => 'below Telephone (q = 1.0)',
7 => 'Telephone (q = 2.0)',
8 => 'Thumb (q = 3.0)',
9 => 'Radio (q = 4.0)',
10 => 'Standard (q = 5.0)',
11 => 'Extreme (q = 6.0)',
12 => 'Insane (q = 7.0)',
13 => 'BrainDead (q = 8.0)',
14 => 'above BrainDead (q = 9.0)',
15 => 'above BrainDead (q = 10.0)'
);
return (isset($MPCprofileNameLookup[$profileid]) ? $MPCprofileNameLookup[$profileid] : 'invalid');
}
function MPCfrequencyLookup($frequencyid) {
static $MPCfrequencyLookup = array(
0 => 44100,
1 => 48000,
2 => 37800,
3 => 32000
);
return (isset($MPCfrequencyLookup[$frequencyid]) ? $MPCfrequencyLookup[$frequencyid] : 'invalid');
}
function MPCpeakDBLookup($intvalue) {
if ($intvalue > 0) {
return ((log10($intvalue) / log10(2)) - 15) * 6;
}
return false;
}
function MPCencoderVersionLookup($encoderversion) {
//Encoder version * 100 (106 = 1.06)
//EncoderVersion % 10 == 0 Release (1.0)
//EncoderVersion % 2 == 0 Beta (1.06)
//EncoderVersion % 2 == 1 Alpha (1.05a...z)
if ($encoderversion == 0) {
// very old version, not known exactly which
return 'Buschmann v1.7.0-v1.7.9 or Klemm v0.90-v1.05';
}
if (($encoderversion % 10) == 0) {
// release version
return number_format($encoderversion / 100, 2);
} elseif (($encoderversion % 2) == 0) {
// beta version
return number_format($encoderversion / 100, 2).' beta';
}
// alpha version
return number_format($encoderversion / 100, 2).' alpha';
}
function SV8variableLengthInteger($data, &$packetLength, $maxHandledPacketLength=9) {
$packet_size = 0;
for ($packetLength = 1; $packetLength <= $maxHandledPacketLength; $packetLength++) {
// variable-length size field:
// bits, big-endian
// 0xxx xxxx - value 0 to 2^7-1
// 1xxx xxxx 0xxx xxxx - value 0 to 2^14-1
// 1xxx xxxx 1xxx xxxx 0xxx xxxx - value 0 to 2^21-1
// 1xxx xxxx 1xxx xxxx 1xxx xxxx 0xxx xxxx - value 0 to 2^28-1
// ...
$thisbyte = ord(substr($data, ($packetLength - 1), 1));
// look through bytes until find a byte with MSB==0
$packet_size = ($packet_size << 7);
$packet_size = ($packet_size | ($thisbyte & 0x7F));
if (($thisbyte & 0x80) === 0) {
break;
}
if ($packetLength >= $maxHandledPacketLength) {
return false;
}
}
return $packet_size;
}
function MPCsv8PacketName($packetKey) {
static $MPCsv8PacketName = array();
if (empty($MPCsv8PacketName)) {
$MPCsv8PacketName = array(
'AP' => 'Audio Packet',
'CT' => 'Chapter Tag',
'EI' => 'Encoder Info',
'RG' => 'Replay Gain',
'SE' => 'Stream End',
'SH' => 'Stream Header',
'SO' => 'Seek Table Offset',
'ST' => 'Seek Table',
);
}
return (isset($MPCsv8PacketName[$packetKey]) ? $MPCsv8PacketName[$packetKey] : $packetKey);
}
}
?>

View File

@ -1,556 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio.ogg.php //
// module for analyzing Ogg Vorbis, OggFLAC and Speex files //
// dependencies: module.audio.flac.php //
// ///
/////////////////////////////////////////////////////////////////
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.flac.php', __FILE__, true);
class getid3_ogg
{
function getid3_ogg(&$fd, &$ThisFileInfo) {
$ThisFileInfo['fileformat'] = 'ogg';
// Warn about illegal tags - only vorbiscomments are allowed
if (isset($ThisFileInfo['id3v2'])) {
$ThisFileInfo['warning'][] = 'Illegal ID3v2 tag present.';
}
if (isset($ThisFileInfo['id3v1'])) {
$ThisFileInfo['warning'][] = 'Illegal ID3v1 tag present.';
}
if (isset($ThisFileInfo['ape'])) {
$ThisFileInfo['warning'][] = 'Illegal APE tag present.';
}
// Page 1 - Stream Header
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$oggpageinfo = getid3_ogg::ParseOggPageHeader($fd);
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
if (ftell($fd) >= GETID3_FREAD_BUFFER_SIZE) {
$ThisFileInfo['error'][] = 'Could not find start of Ogg page in the first '.GETID3_FREAD_BUFFER_SIZE.' bytes (this might not be an Ogg-Vorbis file?)';
unset($ThisFileInfo['fileformat']);
unset($ThisFileInfo['ogg']);
return false;
}
$filedata = fread($fd, $oggpageinfo['page_length']);
$filedataoffset = 0;
if (substr($filedata, 0, 4) == 'fLaC') {
$ThisFileInfo['audio']['dataformat'] = 'flac';
$ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
$ThisFileInfo['audio']['lossless'] = true;
} elseif (substr($filedata, 1, 6) == 'vorbis') {
$this->ParseVorbisPageHeader($filedata, $filedataoffset, $ThisFileInfo, $oggpageinfo);
} elseif (substr($filedata, 0, 8) == 'Speex ') {
// http://www.speex.org/manual/node10.html
$ThisFileInfo['audio']['dataformat'] = 'speex';
$ThisFileInfo['mime_type'] = 'audio/speex';
$ThisFileInfo['audio']['bitrate_mode'] = 'abr';
$ThisFileInfo['audio']['lossless'] = false;
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_string'] = substr($filedata, $filedataoffset, 8); // hard-coded to 'Speex '
$filedataoffset += 8;
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_version'] = substr($filedata, $filedataoffset, 20);
$filedataoffset += 20;
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_version_id'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['header_size'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['rate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['mode'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['mode_bitstream_version'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['nb_channels'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['bitrate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['framesize'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['vbr'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['frames_per_packet'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['extra_headers'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['reserved1'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['reserved2'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$ThisFileInfo['speex']['speex_version'] = trim($ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_version']);
$ThisFileInfo['speex']['sample_rate'] = $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['rate'];
$ThisFileInfo['speex']['channels'] = $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['nb_channels'];
$ThisFileInfo['speex']['vbr'] = (bool) $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['vbr'];
$ThisFileInfo['speex']['band_type'] = getid3_ogg::SpeexBandModeLookup($ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['mode']);
$ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['speex']['sample_rate'];
$ThisFileInfo['audio']['channels'] = $ThisFileInfo['speex']['channels'];
if ($ThisFileInfo['speex']['vbr']) {
$ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
}
} else {
$ThisFileInfo['error'][] = 'Expecting either "Speex " or "vorbis" identifier strings, found neither';
unset($ThisFileInfo['ogg']);
unset($ThisFileInfo['mime_type']);
return false;
}
// Page 2 - Comment Header
$oggpageinfo = getid3_ogg::ParseOggPageHeader($fd);
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
switch ($ThisFileInfo['audio']['dataformat']) {
case 'vorbis':
$filedata = fread($fd, $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['packet_type'] = getid3_lib::LittleEndian2Int(substr($filedata, 0, 1));
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['stream_type'] = substr($filedata, 1, 6); // hard-coded to 'vorbis'
getid3_ogg::ParseVorbisCommentsFilepointer($fd, $ThisFileInfo);
break;
case 'flac':
if (!getid3_flac::FLACparseMETAdata($fd, $ThisFileInfo)) {
$ThisFileInfo['error'][] = 'Failed to parse FLAC headers';
return false;
}
break;
case 'speex':
fseek($fd, $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length'], SEEK_CUR);
getid3_ogg::ParseVorbisCommentsFilepointer($fd, $ThisFileInfo);
break;
}
// Last Page - Number of Samples
if ($ThisFileInfo['avdataend'] >= pow(2, 31)) {
$ThisFileInfo['warning'][] = 'Unable to parse Ogg end chunk file (PHP does not support file operations beyond 2GB)';
} else {
fseek($fd, max($ThisFileInfo['avdataend'] - GETID3_FREAD_BUFFER_SIZE, 0), SEEK_SET);
$LastChunkOfOgg = strrev(fread($fd, GETID3_FREAD_BUFFER_SIZE));
if ($LastOggSpostion = strpos($LastChunkOfOgg, 'SggO')) {
fseek($fd, $ThisFileInfo['avdataend'] - ($LastOggSpostion + strlen('SggO')), SEEK_SET);
$ThisFileInfo['avdataend'] = ftell($fd);
$ThisFileInfo['ogg']['pageheader']['eos'] = getid3_ogg::ParseOggPageHeader($fd);
$ThisFileInfo['ogg']['samples'] = $ThisFileInfo['ogg']['pageheader']['eos']['pcm_abs_position'];
if ($ThisFileInfo['ogg']['samples'] == 0) {
$ThisFileInfo['error'][] = 'Corrupt Ogg file: eos.number of samples == zero';
return false;
}
$ThisFileInfo['ogg']['bitrate_average'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / ($ThisFileInfo['ogg']['samples'] / $ThisFileInfo['audio']['sample_rate']);
}
}
if (!empty($ThisFileInfo['ogg']['bitrate_average'])) {
$ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['ogg']['bitrate_average'];
} elseif (!empty($ThisFileInfo['ogg']['bitrate_nominal'])) {
$ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['ogg']['bitrate_nominal'];
} elseif (!empty($ThisFileInfo['ogg']['bitrate_min']) && !empty($ThisFileInfo['ogg']['bitrate_max'])) {
$ThisFileInfo['audio']['bitrate'] = ($ThisFileInfo['ogg']['bitrate_min'] + $ThisFileInfo['ogg']['bitrate_max']) / 2;
}
if (isset($ThisFileInfo['audio']['bitrate']) && !isset($ThisFileInfo['playtime_seconds'])) {
if ($ThisFileInfo['audio']['bitrate'] == 0) {
$ThisFileInfo['error'][] = 'Corrupt Ogg file: bitrate_audio == zero';
return false;
}
$ThisFileInfo['playtime_seconds'] = (float) ((($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['audio']['bitrate']);
}
if (isset($ThisFileInfo['ogg']['vendor'])) {
$ThisFileInfo['audio']['encoder'] = preg_replace('/^Encoded with /', '', $ThisFileInfo['ogg']['vendor']);
// Vorbis only
if ($ThisFileInfo['audio']['dataformat'] == 'vorbis') {
// Vorbis 1.0 starts with Xiph.Org
if (preg_match('/^Xiph.Org/', $ThisFileInfo['audio']['encoder'])) {
if ($ThisFileInfo['audio']['bitrate_mode'] == 'abr') {
// Set -b 128 on abr files
$ThisFileInfo['audio']['encoder_options'] = '-b '.round($ThisFileInfo['ogg']['bitrate_nominal'] / 1000);
} elseif (($ThisFileInfo['audio']['bitrate_mode'] == 'vbr') && ($ThisFileInfo['audio']['channels'] == 2) && ($ThisFileInfo['audio']['sample_rate'] >= 44100) && ($ThisFileInfo['audio']['sample_rate'] <= 48000)) {
// Set -q N on vbr files
$ThisFileInfo['audio']['encoder_options'] = '-q '.$this->get_quality_from_nominal_bitrate($ThisFileInfo['ogg']['bitrate_nominal']);
}
}
if (empty($ThisFileInfo['audio']['encoder_options']) && !empty($ThisFileInfo['ogg']['bitrate_nominal'])) {
$ThisFileInfo['audio']['encoder_options'] = 'Nominal bitrate: '.intval(round($ThisFileInfo['ogg']['bitrate_nominal'] / 1000)).'kbps';
}
}
}
return true;
}
function ParseVorbisPageHeader(&$filedata, &$filedataoffset, &$ThisFileInfo, &$oggpageinfo) {
$ThisFileInfo['audio']['dataformat'] = 'vorbis';
$ThisFileInfo['audio']['lossless'] = false;
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['packet_type'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
$filedataoffset += 1;
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['stream_type'] = substr($filedata, $filedataoffset, 6); // hard-coded to 'vorbis'
$filedataoffset += 6;
$ThisFileInfo['ogg']['bitstreamversion'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$ThisFileInfo['ogg']['numberofchannels'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
$filedataoffset += 1;
$ThisFileInfo['audio']['channels'] = $ThisFileInfo['ogg']['numberofchannels'];
$ThisFileInfo['ogg']['samplerate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
if ($ThisFileInfo['ogg']['samplerate'] == 0) {
$ThisFileInfo['error'][] = 'Corrupt Ogg file: sample rate == zero';
return false;
}
$ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['ogg']['samplerate'];
$ThisFileInfo['ogg']['samples'] = 0; // filled in later
$ThisFileInfo['ogg']['bitrate_average'] = 0; // filled in later
$ThisFileInfo['ogg']['bitrate_max'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$ThisFileInfo['ogg']['bitrate_nominal'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$ThisFileInfo['ogg']['bitrate_min'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$ThisFileInfo['ogg']['blocksize_small'] = pow(2, getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)) & 0x0F);
$ThisFileInfo['ogg']['blocksize_large'] = pow(2, (getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)) & 0xF0) >> 4);
$ThisFileInfo['ogg']['stop_bit'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); // must be 1, marks end of packet
$ThisFileInfo['audio']['bitrate_mode'] = 'vbr'; // overridden if actually abr
if ($ThisFileInfo['ogg']['bitrate_max'] == 0xFFFFFFFF) {
unset($ThisFileInfo['ogg']['bitrate_max']);
$ThisFileInfo['audio']['bitrate_mode'] = 'abr';
}
if ($ThisFileInfo['ogg']['bitrate_nominal'] == 0xFFFFFFFF) {
unset($ThisFileInfo['ogg']['bitrate_nominal']);
}
if ($ThisFileInfo['ogg']['bitrate_min'] == 0xFFFFFFFF) {
unset($ThisFileInfo['ogg']['bitrate_min']);
$ThisFileInfo['audio']['bitrate_mode'] = 'abr';
}
return true;
}
function ParseOggPageHeader(&$fd) {
// http://xiph.org/ogg/vorbis/doc/framing.html
$oggheader['page_start_offset'] = ftell($fd); // where we started from in the file
$filedata = fread($fd, GETID3_FREAD_BUFFER_SIZE);
$filedataoffset = 0;
while ((substr($filedata, $filedataoffset++, 4) != 'OggS')) {
if ((ftell($fd) - $oggheader['page_start_offset']) >= GETID3_FREAD_BUFFER_SIZE) {
// should be found before here
return false;
}
if ((($filedataoffset + 28) > strlen($filedata)) || (strlen($filedata) < 28)) {
if (feof($fd) || (($filedata .= fread($fd, GETID3_FREAD_BUFFER_SIZE)) === false)) {
// get some more data, unless eof, in which case fail
return false;
}
}
}
$filedataoffset += strlen('OggS') - 1; // page, delimited by 'OggS'
$oggheader['stream_structver'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
$filedataoffset += 1;
$oggheader['flags_raw'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
$filedataoffset += 1;
$oggheader['flags']['fresh'] = (bool) ($oggheader['flags_raw'] & 0x01); // fresh packet
$oggheader['flags']['bos'] = (bool) ($oggheader['flags_raw'] & 0x02); // first page of logical bitstream (bos)
$oggheader['flags']['eos'] = (bool) ($oggheader['flags_raw'] & 0x04); // last page of logical bitstream (eos)
$oggheader['pcm_abs_position'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
$filedataoffset += 8;
$oggheader['stream_serialno'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$oggheader['page_seqno'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$oggheader['page_checksum'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
$filedataoffset += 4;
$oggheader['page_segments'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
$filedataoffset += 1;
$oggheader['page_length'] = 0;
for ($i = 0; $i < $oggheader['page_segments']; $i++) {
$oggheader['segment_table'][$i] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
$filedataoffset += 1;
$oggheader['page_length'] += $oggheader['segment_table'][$i];
}
$oggheader['header_end_offset'] = $oggheader['page_start_offset'] + $filedataoffset;
$oggheader['page_end_offset'] = $oggheader['header_end_offset'] + $oggheader['page_length'];
fseek($fd, $oggheader['header_end_offset'], SEEK_SET);
return $oggheader;
}
function ParseVorbisCommentsFilepointer(&$fd, &$ThisFileInfo) {
$OriginalOffset = ftell($fd);
$CommentStartOffset = $OriginalOffset;
$commentdataoffset = 0;
$VorbisCommentPage = 1;
switch ($ThisFileInfo['audio']['dataformat']) {
case 'vorbis':
$CommentStartOffset = $ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage]['page_start_offset']; // Second Ogg page, after header block
fseek($fd, $CommentStartOffset, SEEK_SET);
$commentdataoffset = 27 + $ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage]['page_segments'];
$commentdata = fread($fd, getid3_ogg::OggPageSegmentLength($ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage], 1) + $commentdataoffset);
$commentdataoffset += (strlen('vorbis') + 1);
break;
case 'flac':
fseek($fd, $ThisFileInfo['flac']['VORBIS_COMMENT']['raw']['offset'] + 4, SEEK_SET);
$commentdata = fread($fd, $ThisFileInfo['flac']['VORBIS_COMMENT']['raw']['block_length']);
break;
case 'speex':
$CommentStartOffset = $ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage]['page_start_offset']; // Second Ogg page, after header block
fseek($fd, $CommentStartOffset, SEEK_SET);
$commentdataoffset = 27 + $ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage]['page_segments'];
$commentdata = fread($fd, getid3_ogg::OggPageSegmentLength($ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage], 1) + $commentdataoffset);
break;
default:
return false;
break;
}
$VendorSize = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4));
$commentdataoffset += 4;
$ThisFileInfo['ogg']['vendor'] = substr($commentdata, $commentdataoffset, $VendorSize);
$commentdataoffset += $VendorSize;
$CommentsCount = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4));
$commentdataoffset += 4;
$ThisFileInfo['avdataoffset'] = $CommentStartOffset + $commentdataoffset;
$basicfields = array('TITLE', 'ARTIST', 'ALBUM', 'TRACKNUMBER', 'GENRE', 'DATE', 'DESCRIPTION', 'COMMENT');
for ($i = 0; $i < $CommentsCount; $i++) {
$ThisFileInfo['ogg']['comments_raw'][$i]['dataoffset'] = $CommentStartOffset + $commentdataoffset;
if (ftell($fd) < ($ThisFileInfo['ogg']['comments_raw'][$i]['dataoffset'] + 4)) {
$VorbisCommentPage++;
$oggpageinfo = getid3_ogg::ParseOggPageHeader($fd);
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
// First, save what we haven't read yet
$AsYetUnusedData = substr($commentdata, $commentdataoffset);
// Then take that data off the end
$commentdata = substr($commentdata, 0, $commentdataoffset);
// Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct
$commentdata .= str_repeat("\x00", 27 + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
$commentdataoffset += (27 + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
// Finally, stick the unused data back on the end
$commentdata .= $AsYetUnusedData;
//$commentdata .= fread($fd, $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
$commentdata .= fread($fd, getid3_ogg::OggPageSegmentLength($ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage], 1));
}
$ThisFileInfo['ogg']['comments_raw'][$i]['size'] = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4));
// replace avdataoffset with position just after the last vorbiscomment
$ThisFileInfo['avdataoffset'] = $ThisFileInfo['ogg']['comments_raw'][$i]['dataoffset'] + $ThisFileInfo['ogg']['comments_raw'][$i]['size'] + 4;
$commentdataoffset += 4;
while ((strlen($commentdata) - $commentdataoffset) < $ThisFileInfo['ogg']['comments_raw'][$i]['size']) {
if (($ThisFileInfo['ogg']['comments_raw'][$i]['size'] > $ThisFileInfo['avdataend']) || ($ThisFileInfo['ogg']['comments_raw'][$i]['size'] < 0)) {
$ThisFileInfo['error'][] = 'Invalid Ogg comment size (comment #'.$i.', claims to be '.number_format($ThisFileInfo['ogg']['comments_raw'][$i]['size']).' bytes) - aborting reading comments';
break 2;
}
$VorbisCommentPage++;
$oggpageinfo = getid3_ogg::ParseOggPageHeader($fd);
$ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
// First, save what we haven't read yet
$AsYetUnusedData = substr($commentdata, $commentdataoffset);
// Then take that data off the end
$commentdata = substr($commentdata, 0, $commentdataoffset);
// Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct
$commentdata .= str_repeat("\x00", 27 + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
$commentdataoffset += (27 + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
// Finally, stick the unused data back on the end
$commentdata .= $AsYetUnusedData;
//$commentdata .= fread($fd, $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
$commentdata .= fread($fd, getid3_ogg::OggPageSegmentLength($ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage], 1));
//$filebaseoffset += $oggpageinfo['header_end_offset'] - $oggpageinfo['page_start_offset'];
}
$commentstring = substr($commentdata, $commentdataoffset, $ThisFileInfo['ogg']['comments_raw'][$i]['size']);
$commentdataoffset += $ThisFileInfo['ogg']['comments_raw'][$i]['size'];
if (!$commentstring) {
// no comment?
$ThisFileInfo['warning'][] = 'Blank Ogg comment ['.$i.']';
} elseif (strstr($commentstring, '=')) {
$commentexploded = explode('=', $commentstring, 2);
$ThisFileInfo['ogg']['comments_raw'][$i]['key'] = strtoupper($commentexploded[0]);
$ThisFileInfo['ogg']['comments_raw'][$i]['value'] = @$commentexploded[1];
$ThisFileInfo['ogg']['comments_raw'][$i]['data'] = base64_decode($ThisFileInfo['ogg']['comments_raw'][$i]['value']);
$ThisFileInfo['ogg']['comments'][strtolower($ThisFileInfo['ogg']['comments_raw'][$i]['key'])][] = $ThisFileInfo['ogg']['comments_raw'][$i]['value'];
$imageinfo = array();
$imagechunkcheck = getid3_lib::GetDataImageSize($ThisFileInfo['ogg']['comments_raw'][$i]['data'], $imageinfo);
$ThisFileInfo['ogg']['comments_raw'][$i]['image_mime'] = getid3_lib::image_type_to_mime_type($imagechunkcheck[2]);
if (!$ThisFileInfo['ogg']['comments_raw'][$i]['image_mime'] || ($ThisFileInfo['ogg']['comments_raw'][$i]['image_mime'] == 'application/octet-stream')) {
unset($ThisFileInfo['ogg']['comments_raw'][$i]['image_mime']);
unset($ThisFileInfo['ogg']['comments_raw'][$i]['data']);
}
} else {
$ThisFileInfo['warning'][] = '[known problem with CDex >= v1.40, < v1.50b7] Invalid Ogg comment name/value pair ['.$i.']: '.$commentstring;
}
}
// Replay Gain Adjustment
// http://privatewww.essex.ac.uk/~djmrob/replaygain/
if (isset($ThisFileInfo['ogg']['comments']) && is_array($ThisFileInfo['ogg']['comments'])) {
foreach ($ThisFileInfo['ogg']['comments'] as $index => $commentvalue) {
switch ($index) {
case 'rg_audiophile':
case 'replaygain_album_gain':
$ThisFileInfo['replay_gain']['album']['adjustment'] = (double) $commentvalue[0];
unset($ThisFileInfo['ogg']['comments'][$index]);
break;
case 'rg_radio':
case 'replaygain_track_gain':
$ThisFileInfo['replay_gain']['track']['adjustment'] = (double) $commentvalue[0];
unset($ThisFileInfo['ogg']['comments'][$index]);
break;
case 'replaygain_album_peak':
$ThisFileInfo['replay_gain']['album']['peak'] = (double) $commentvalue[0];
unset($ThisFileInfo['ogg']['comments'][$index]);
break;
case 'rg_peak':
case 'replaygain_track_peak':
$ThisFileInfo['replay_gain']['track']['peak'] = (double) $commentvalue[0];
unset($ThisFileInfo['ogg']['comments'][$index]);
break;
default:
// do nothing
break;
}
}
}
fseek($fd, $OriginalOffset, SEEK_SET);
return true;
}
function SpeexBandModeLookup($mode) {
static $SpeexBandModeLookup = array();
if (empty($SpeexBandModeLookup)) {
$SpeexBandModeLookup[0] = 'narrow';
$SpeexBandModeLookup[1] = 'wide';
$SpeexBandModeLookup[2] = 'ultra-wide';
}
return (isset($SpeexBandModeLookup[$mode]) ? $SpeexBandModeLookup[$mode] : null);
}
function OggPageSegmentLength($OggInfoArray, $SegmentNumber=1) {
for ($i = 0; $i < $SegmentNumber; $i++) {
$segmentlength = 0;
foreach ($OggInfoArray['segment_table'] as $key => $value) {
$segmentlength += $value;
if ($value < 255) {
break;
}
}
}
return $segmentlength;
}
function get_quality_from_nominal_bitrate($nominal_bitrate) {
// decrease precision
$nominal_bitrate = $nominal_bitrate / 1000;
if ($nominal_bitrate < 128) {
// q-1 to q4
$qval = ($nominal_bitrate - 64) / 16;
} elseif ($nominal_bitrate < 256) {
// q4 to q8
$qval = $nominal_bitrate / 32;
} elseif ($nominal_bitrate < 320) {
// q8 to q9
$qval = ($nominal_bitrate + 256) / 64;
} else {
// q9 to q10
$qval = ($nominal_bitrate + 1300) / 180;
}
//return $qval; // 5.031324
//return intval($qval); // 5
return round($qval, 1); // 5 or 4.9
}
}
?>

View File

@ -1,408 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio.optimfrog.php //
// module for analyzing OptimFROG audio files //
// dependencies: module.audio.riff.php //
// ///
/////////////////////////////////////////////////////////////////
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
class getid3_optimfrog
{
function getid3_optimfrog(&$fd, &$ThisFileInfo) {
$ThisFileInfo['fileformat'] = 'ofr';
$ThisFileInfo['audio']['dataformat'] = 'ofr';
$ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
$ThisFileInfo['audio']['lossless'] = true;
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$OFRheader = fread($fd, 8);
if (substr($OFRheader, 0, 5) == '*RIFF') {
return $this->ParseOptimFROGheader42($fd, $ThisFileInfo);
} elseif (substr($OFRheader, 0, 3) == 'OFR') {
return $this->ParseOptimFROGheader45($fd, $ThisFileInfo);
}
$ThisFileInfo['error'][] = 'Expecting "*RIFF" or "OFR " at offset '.$ThisFileInfo['avdataoffset'].', found "'.$OFRheader.'"';
unset($ThisFileInfo['fileformat']);
return false;
}
function ParseOptimFROGheader42(&$fd, &$ThisFileInfo) {
// for fileformat of v4.21 and older
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$OptimFROGheaderData = fread($fd, 45);
$ThisFileInfo['avdataoffset'] = 45;
$OptimFROGencoderVersion_raw = getid3_lib::LittleEndian2Int(substr($OptimFROGheaderData, 0, 1));
$OptimFROGencoderVersion_major = floor($OptimFROGencoderVersion_raw / 10);
$OptimFROGencoderVersion_minor = $OptimFROGencoderVersion_raw - ($OptimFROGencoderVersion_major * 10);
$RIFFdata = substr($OptimFROGheaderData, 1, 44);
$OrignalRIFFheaderSize = getid3_lib::LittleEndian2Int(substr($RIFFdata, 4, 4)) + 8;
$OrignalRIFFdataSize = getid3_lib::LittleEndian2Int(substr($RIFFdata, 40, 4)) + 44;
if ($OrignalRIFFheaderSize > $OrignalRIFFdataSize) {
$ThisFileInfo['avdataend'] -= ($OrignalRIFFheaderSize - $OrignalRIFFdataSize);
fseek($fd, $ThisFileInfo['avdataend'], SEEK_SET);
$RIFFdata .= fread($fd, $OrignalRIFFheaderSize - $OrignalRIFFdataSize);
}
// move the data chunk after all other chunks (if any)
// so that the RIFF parser doesn't see EOF when trying
// to skip over the data chunk
$RIFFdata = substr($RIFFdata, 0, 36).substr($RIFFdata, 44).substr($RIFFdata, 36, 8);
getid3_riff::ParseRIFFdata($RIFFdata, $ThisFileInfo);
$ThisFileInfo['audio']['encoder'] = 'OptimFROG '.$OptimFROGencoderVersion_major.'.'.$OptimFROGencoderVersion_minor;
$ThisFileInfo['audio']['channels'] = $ThisFileInfo['riff']['audio'][0]['channels'];
$ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['riff']['audio'][0]['sample_rate'];
$ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['riff']['audio'][0]['bits_per_sample'];
$ThisFileInfo['playtime_seconds'] = $OrignalRIFFdataSize / ($ThisFileInfo['audio']['channels'] * $ThisFileInfo['audio']['sample_rate'] * ($ThisFileInfo['audio']['bits_per_sample'] / 8));
$ThisFileInfo['audio']['bitrate'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['playtime_seconds'];
return true;
}
function ParseOptimFROGheader45(&$fd, &$ThisFileInfo) {
// for fileformat of v4.50a and higher
$RIFFdata = '';
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
while (!feof($fd) && (ftell($fd) < $ThisFileInfo['avdataend'])) {
$BlockOffset = ftell($fd);
$BlockData = fread($fd, 8);
$offset = 8;
$BlockName = substr($BlockData, 0, 4);
$BlockSize = getid3_lib::LittleEndian2Int(substr($BlockData, 4, 4));
if ($BlockName == 'OFRX') {
$BlockName = 'OFR ';
}
if (!isset($ThisFileInfo['ofr'][$BlockName])) {
$ThisFileInfo['ofr'][$BlockName] = array();
}
$thisfile_ofr_thisblock = &$ThisFileInfo['ofr'][$BlockName];
switch ($BlockName) {
case 'OFR ':
// shortcut
$thisfile_ofr_thisblock['offset'] = $BlockOffset;
$thisfile_ofr_thisblock['size'] = $BlockSize;
$ThisFileInfo['audio']['encoder'] = 'OptimFROG 4.50 alpha';
switch ($BlockSize) {
case 12:
case 15:
// good
break;
default:
$ThisFileInfo['warning'][] = '"'.$BlockName.'" contains more data than expected (expected 12 or 15 bytes, found '.$BlockSize.' bytes)';
break;
}
$BlockData .= fread($fd, $BlockSize);
$thisfile_ofr_thisblock['total_samples'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 6));
$offset += 6;
$thisfile_ofr_thisblock['raw']['sample_type'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 1));
$thisfile_ofr_thisblock['sample_type'] = $this->OptimFROGsampleTypeLookup($thisfile_ofr_thisblock['raw']['sample_type']);
$offset += 1;
$thisfile_ofr_thisblock['channel_config'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 1));
$thisfile_ofr_thisblock['channels'] = $thisfile_ofr_thisblock['channel_config'];
$offset += 1;
$thisfile_ofr_thisblock['sample_rate'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 4));
$offset += 4;
if ($BlockSize > 12) {
// OFR 4.504b or higher
$thisfile_ofr_thisblock['channels'] = $this->OptimFROGchannelConfigNumChannelsLookup($thisfile_ofr_thisblock['channel_config']);
$thisfile_ofr_thisblock['raw']['encoder_id'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 2));
$thisfile_ofr_thisblock['encoder'] = $this->OptimFROGencoderNameLookup($thisfile_ofr_thisblock['raw']['encoder_id']);
$offset += 2;
$thisfile_ofr_thisblock['raw']['compression'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 1));
$thisfile_ofr_thisblock['compression'] = $this->OptimFROGcompressionLookup($thisfile_ofr_thisblock['raw']['compression']);
$thisfile_ofr_thisblock['speedup'] = $this->OptimFROGspeedupLookup($thisfile_ofr_thisblock['raw']['compression']);
$offset += 1;
$ThisFileInfo['audio']['encoder'] = 'OptimFROG '.$thisfile_ofr_thisblock['encoder'];
$ThisFileInfo['audio']['encoder_options'] = '--mode '.$thisfile_ofr_thisblock['compression'];
if ((($thisfile_ofr_thisblock['raw']['encoder_id'] & 0xF0) >> 4) == 7) { // v4.507
if (strtolower(getid3_lib::fileextension($ThisFileInfo['filename'])) == 'ofs') {
// OptimFROG DualStream format is lossy, but as of v4.507 there is no way to tell the difference
// between lossless and lossy other than the file extension.
$ThisFileInfo['audio']['dataformat'] = 'ofs';
$ThisFileInfo['audio']['lossless'] = true;
}
}
}
$ThisFileInfo['audio']['channels'] = $thisfile_ofr_thisblock['channels'];
$ThisFileInfo['audio']['sample_rate'] = $thisfile_ofr_thisblock['sample_rate'];
$ThisFileInfo['audio']['bits_per_sample'] = $this->OptimFROGbitsPerSampleTypeLookup($thisfile_ofr_thisblock['raw']['sample_type']);
break;
case 'COMP':
// unlike other block types, there CAN be multiple COMP blocks
$COMPdata['offset'] = $BlockOffset;
$COMPdata['size'] = $BlockSize;
if ($ThisFileInfo['avdataoffset'] == 0) {
$ThisFileInfo['avdataoffset'] = $BlockOffset;
}
// Only interested in first 14 bytes (only first 12 needed for v4.50 alpha), not actual audio data
$BlockData .= fread($fd, 14);
fseek($fd, $BlockSize - 14, SEEK_CUR);
$COMPdata['crc_32'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 4));
$offset += 4;
$COMPdata['sample_count'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 4));
$offset += 4;
$COMPdata['raw']['sample_type'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 1));
$COMPdata['sample_type'] = $this->OptimFROGsampleTypeLookup($COMPdata['raw']['sample_type']);
$offset += 1;
$COMPdata['raw']['channel_configuration'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 1));
$COMPdata['channel_configuration'] = $this->OptimFROGchannelConfigurationLookup($COMPdata['raw']['channel_configuration']);
$offset += 1;
$COMPdata['raw']['algorithm_id'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 2));
//$COMPdata['algorithm'] = OptimFROGalgorithmNameLookup($COMPdata['raw']['algorithm_id']);
$offset += 2;
if ($ThisFileInfo['ofr']['OFR ']['size'] > 12) {
// OFR 4.504b or higher
$COMPdata['raw']['encoder_id'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 2));
$COMPdata['encoder'] = $this->OptimFROGencoderNameLookup($COMPdata['raw']['encoder_id']);
$offset += 2;
}
if ($COMPdata['crc_32'] == 0x454E4F4E) {
// ASCII value of 'NONE' - placeholder value in v4.50a
$COMPdata['crc_32'] = false;
}
$thisfile_ofr_thisblock[] = $COMPdata;
break;
case 'HEAD':
$thisfile_ofr_thisblock['offset'] = $BlockOffset;
$thisfile_ofr_thisblock['size'] = $BlockSize;
$RIFFdata .= fread($fd, $BlockSize);
break;
case 'TAIL':
$thisfile_ofr_thisblock['offset'] = $BlockOffset;
$thisfile_ofr_thisblock['size'] = $BlockSize;
if ($BlockSize > 0) {
$RIFFdata .= fread($fd, $BlockSize);
}
break;
case 'RECV':
// block contains no useful meta data - simply note and skip
$thisfile_ofr_thisblock['offset'] = $BlockOffset;
$thisfile_ofr_thisblock['size'] = $BlockSize;
fseek($fd, $BlockSize, SEEK_CUR);
break;
case 'APET':
// APEtag v2
$thisfile_ofr_thisblock['offset'] = $BlockOffset;
$thisfile_ofr_thisblock['size'] = $BlockSize;
$ThisFileInfo['warning'][] = 'APEtag processing inside OptimFROG not supported in this version ('.GETID3_VERSION.') of getID3()';
fseek($fd, $BlockSize, SEEK_CUR);
break;
case 'MD5 ':
// APEtag v2
$thisfile_ofr_thisblock['offset'] = $BlockOffset;
$thisfile_ofr_thisblock['size'] = $BlockSize;
if ($BlockSize == 16) {
$thisfile_ofr_thisblock['md5_binary'] = fread($fd, $BlockSize);
$thisfile_ofr_thisblock['md5_string'] = getid3_lib::PrintHexBytes($thisfile_ofr_thisblock['md5_binary'], true, false, false);
$ThisFileInfo['md5_data_source'] = $thisfile_ofr_thisblock['md5_string'];
} else {
$ThisFileInfo['warning'][] = 'Expecting block size of 16 in "MD5 " chunk, found '.$BlockSize.' instead';
fseek($fd, $BlockSize, SEEK_CUR);
}
break;
default:
$thisfile_ofr_thisblock['offset'] = $BlockOffset;
$thisfile_ofr_thisblock['size'] = $BlockSize;
$ThisFileInfo['warning'][] = 'Unhandled OptimFROG block type "'.$BlockName.'" at offset '.$thisfile_ofr_thisblock['offset'];
fseek($fd, $BlockSize, SEEK_CUR);
break;
}
}
if (isset($ThisFileInfo['ofr']['TAIL']['offset'])) {
$ThisFileInfo['avdataend'] = $ThisFileInfo['ofr']['TAIL']['offset'];
}
$ThisFileInfo['playtime_seconds'] = (float) $ThisFileInfo['ofr']['OFR ']['total_samples'] / ($ThisFileInfo['audio']['channels'] * $ThisFileInfo['audio']['sample_rate']);
$ThisFileInfo['audio']['bitrate'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['playtime_seconds'];
// move the data chunk after all other chunks (if any)
// so that the RIFF parser doesn't see EOF when trying
// to skip over the data chunk
$RIFFdata = substr($RIFFdata, 0, 36).substr($RIFFdata, 44).substr($RIFFdata, 36, 8);
getid3_riff::ParseRIFFdata($RIFFdata, $ThisFileInfo);
return true;
}
function OptimFROGsampleTypeLookup($SampleType) {
static $OptimFROGsampleTypeLookup = array(
0 => 'unsigned int (8-bit)',
1 => 'signed int (8-bit)',
2 => 'unsigned int (16-bit)',
3 => 'signed int (16-bit)',
4 => 'unsigned int (24-bit)',
5 => 'signed int (24-bit)',
6 => 'unsigned int (32-bit)',
7 => 'signed int (32-bit)',
8 => 'float 0.24 (32-bit)',
9 => 'float 16.8 (32-bit)',
10 => 'float 24.0 (32-bit)'
);
return (isset($OptimFROGsampleTypeLookup[$SampleType]) ? $OptimFROGsampleTypeLookup[$SampleType] : false);
}
function OptimFROGbitsPerSampleTypeLookup($SampleType) {
static $OptimFROGbitsPerSampleTypeLookup = array(
0 => 8,
1 => 8,
2 => 16,
3 => 16,
4 => 24,
5 => 24,
6 => 32,
7 => 32,
8 => 32,
9 => 32,
10 => 32
);
return (isset($OptimFROGbitsPerSampleTypeLookup[$SampleType]) ? $OptimFROGbitsPerSampleTypeLookup[$SampleType] : false);
}
function OptimFROGchannelConfigurationLookup($ChannelConfiguration) {
static $OptimFROGchannelConfigurationLookup = array(
0 => 'mono',
1 => 'stereo'
);
return (isset($OptimFROGchannelConfigurationLookup[$ChannelConfiguration]) ? $OptimFROGchannelConfigurationLookup[$ChannelConfiguration] : false);
}
function OptimFROGchannelConfigNumChannelsLookup($ChannelConfiguration) {
static $OptimFROGchannelConfigNumChannelsLookup = array(
0 => 1,
1 => 2
);
return (isset($OptimFROGchannelConfigNumChannelsLookup[$ChannelConfiguration]) ? $OptimFROGchannelConfigNumChannelsLookup[$ChannelConfiguration] : false);
}
// function OptimFROGalgorithmNameLookup($AlgorithID) {
// static $OptimFROGalgorithmNameLookup = array();
// return (isset($OptimFROGalgorithmNameLookup[$AlgorithID]) ? $OptimFROGalgorithmNameLookup[$AlgorithID] : false);
// }
function OptimFROGencoderNameLookup($EncoderID) {
// version = (encoderID >> 4) + 4500
// system = encoderID & 0xF
$EncoderVersion = number_format(((($EncoderID & 0xF0) >> 4) + 4500) / 1000, 3);
$EncoderSystemID = ($EncoderID & 0x0F);
static $OptimFROGencoderSystemLookup = array(
0x00 => 'Windows console',
0x01 => 'Linux console',
0x0F => 'unknown'
);
return $EncoderVersion.' ('.(isset($OptimFROGencoderSystemLookup[$EncoderSystemID]) ? $OptimFROGencoderSystemLookup[$EncoderSystemID] : 'undefined encoder type (0x'.dechex($EncoderSystemID).')').')';
}
function OptimFROGcompressionLookup($CompressionID) {
// mode = compression >> 3
// speedup = compression & 0x07
$CompressionModeID = ($CompressionID & 0xF8) >> 3;
//$CompressionSpeedupID = ($CompressionID & 0x07);
static $OptimFROGencoderModeLookup = array(
0x00 => 'fast',
0x01 => 'normal',
0x02 => 'high',
0x03 => 'extra', // extranew (some versions)
0x04 => 'best', // bestnew (some versions)
0x05 => 'ultra',
0x06 => 'insane',
0x07 => 'highnew',
0x08 => 'extranew',
0x09 => 'bestnew'
);
return (isset($OptimFROGencoderModeLookup[$CompressionModeID]) ? $OptimFROGencoderModeLookup[$CompressionModeID] : 'undefined mode (0x'.str_pad(dechex($CompressionModeID), 2, '0', STR_PAD_LEFT).')');
}
function OptimFROGspeedupLookup($CompressionID) {
// mode = compression >> 3
// speedup = compression & 0x07
//$CompressionModeID = ($CompressionID & 0xF8) >> 3;
$CompressionSpeedupID = ($CompressionID & 0x07);
static $OptimFROGencoderSpeedupLookup = array(
0x00 => '1x',
0x01 => '2x',
0x02 => '4x'
);
return (isset($OptimFROGencoderSpeedupLookup[$CompressionSpeedupID]) ? $OptimFROGencoderSpeedupLookup[$CompressionSpeedupID] : 'undefined mode (0x'.dechex($CompressionSpeedupID));
}
}
?>

View File

@ -1,92 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio.shorten.php //
// module for analyzing Shorten Audio files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_rkau
{
function getid3_rkau(&$fd, &$ThisFileInfo) {
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$RKAUHeader = fread($fd, 20);
if (substr($RKAUHeader, 0, 3) != 'RKA') {
$ThisFileInfo['error'][] = 'Expecting "RKA" at offset '.$ThisFileInfo['avdataoffset'].', found "'.substr($RKAUHeader, 0, 3).'"';
return false;
}
$ThisFileInfo['fileformat'] = 'rkau';
$ThisFileInfo['audio']['dataformat'] = 'rkau';
$ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
$ThisFileInfo['rkau']['raw']['version'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 3, 1));
$ThisFileInfo['rkau']['version'] = '1.'.str_pad($ThisFileInfo['rkau']['raw']['version'] & 0x0F, 2, '0', STR_PAD_LEFT);
if (($ThisFileInfo['rkau']['version'] > 1.07) || ($ThisFileInfo['rkau']['version'] < 1.06)) {
$ThisFileInfo['error'][] = 'This version of getID3() can only parse RKAU files v1.06 and 1.07 (this file is v'.$ThisFileInfo['rkau']['version'].')';
unset($ThisFileInfo['rkau']);
return false;
}
$ThisFileInfo['rkau']['source_bytes'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 4, 4));
$ThisFileInfo['rkau']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 8, 4));
$ThisFileInfo['rkau']['channels'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 12, 1));
$ThisFileInfo['rkau']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 13, 1));
$ThisFileInfo['rkau']['raw']['quality'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 14, 1));
$this->RKAUqualityLookup($ThisFileInfo['rkau']);
$ThisFileInfo['rkau']['raw']['flags'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 15, 1));
$ThisFileInfo['rkau']['flags']['joint_stereo'] = (bool) (!($ThisFileInfo['rkau']['raw']['flags'] & 0x01));
$ThisFileInfo['rkau']['flags']['streaming'] = (bool) ($ThisFileInfo['rkau']['raw']['flags'] & 0x02);
$ThisFileInfo['rkau']['flags']['vrq_lossy_mode'] = (bool) ($ThisFileInfo['rkau']['raw']['flags'] & 0x04);
if ($ThisFileInfo['rkau']['flags']['streaming']) {
$ThisFileInfo['avdataoffset'] += 20;
$ThisFileInfo['rkau']['compressed_bytes'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 16, 4));
} else {
$ThisFileInfo['avdataoffset'] += 16;
$ThisFileInfo['rkau']['compressed_bytes'] = $ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset'] - 1;
}
// Note: compressed_bytes does not always equal what appears to be the actual number of compressed bytes,
// sometimes it's more, sometimes less. No idea why(?)
$ThisFileInfo['audio']['lossless'] = $ThisFileInfo['rkau']['lossless'];
$ThisFileInfo['audio']['channels'] = $ThisFileInfo['rkau']['channels'];
$ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['rkau']['bits_per_sample'];
$ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['rkau']['sample_rate'];
$ThisFileInfo['playtime_seconds'] = $ThisFileInfo['rkau']['source_bytes'] / ($ThisFileInfo['rkau']['sample_rate'] * $ThisFileInfo['rkau']['channels'] * ($ThisFileInfo['rkau']['bits_per_sample'] / 8));
$ThisFileInfo['audio']['bitrate'] = ($ThisFileInfo['rkau']['compressed_bytes'] * 8) / $ThisFileInfo['playtime_seconds'];
return true;
}
function RKAUqualityLookup(&$RKAUdata) {
$level = ($RKAUdata['raw']['quality'] & 0xF0) >> 4;
$quality = $RKAUdata['raw']['quality'] & 0x0F;
$RKAUdata['lossless'] = (($quality == 0) ? true : false);
$RKAUdata['compression_level'] = $level + 1;
if (!$RKAUdata['lossless']) {
$RKAUdata['quality_setting'] = $quality;
}
return true;
}
}
?>

View File

@ -1,180 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio.shorten.php //
// module for analyzing Shorten Audio files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_shorten
{
function getid3_shorten(&$fd, &$ThisFileInfo) {
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$ShortenHeader = fread($fd, 8);
if (substr($ShortenHeader, 0, 4) != 'ajkg') {
$ThisFileInfo['error'][] = 'Expecting "ajkg" at offset '.$ThisFileInfo['avdataoffset'].', found "'.substr($ShortenHeader, 0, 4).'"';
return false;
}
$ThisFileInfo['fileformat'] = 'shn';
$ThisFileInfo['audio']['dataformat'] = 'shn';
$ThisFileInfo['audio']['lossless'] = true;
$ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
$ThisFileInfo['shn']['version'] = getid3_lib::LittleEndian2Int(substr($ShortenHeader, 4, 1));
fseek($fd, $ThisFileInfo['avdataend'] - 12, SEEK_SET);
$SeekTableSignatureTest = fread($fd, 12);
$ThisFileInfo['shn']['seektable']['present'] = (bool) (substr($SeekTableSignatureTest, 4, 8) == 'SHNAMPSK');
if ($ThisFileInfo['shn']['seektable']['present']) {
$ThisFileInfo['shn']['seektable']['length'] = getid3_lib::LittleEndian2Int(substr($SeekTableSignatureTest, 0, 4));
$ThisFileInfo['shn']['seektable']['offset'] = $ThisFileInfo['avdataend'] - $ThisFileInfo['shn']['seektable']['length'];
fseek($fd, $ThisFileInfo['shn']['seektable']['offset'], SEEK_SET);
$SeekTableMagic = fread($fd, 4);
if ($SeekTableMagic != 'SEEK') {
$ThisFileInfo['error'][] = 'Expecting "SEEK" at offset '.$ThisFileInfo['shn']['seektable']['offset'].', found "'.$SeekTableMagic.'"';
return false;
} else {
// typedef struct tag_TSeekEntry
// {
// unsigned long SampleNumber;
// unsigned long SHNFileByteOffset;
// unsigned long SHNLastBufferReadPosition;
// unsigned short SHNByteGet;
// unsigned short SHNBufferOffset;
// unsigned short SHNFileBitOffset;
// unsigned long SHNGBuffer;
// unsigned short SHNBitShift;
// long CBuf0[3];
// long CBuf1[3];
// long Offset0[4];
// long Offset1[4];
// }TSeekEntry;
$SeekTableData = fread($fd, $ThisFileInfo['shn']['seektable']['length'] - 16);
$ThisFileInfo['shn']['seektable']['entry_count'] = floor(strlen($SeekTableData) / 80);
//$ThisFileInfo['shn']['seektable']['entries'] = array();
//$SeekTableOffset = 0;
//for ($i = 0; $i < $ThisFileInfo['shn']['seektable']['entry_count']; $i++) {
// $SeekTableEntry['sample_number'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
// $SeekTableOffset += 4;
// $SeekTableEntry['shn_file_byte_offset'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
// $SeekTableOffset += 4;
// $SeekTableEntry['shn_last_buffer_read_position'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
// $SeekTableOffset += 4;
// $SeekTableEntry['shn_byte_get'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2));
// $SeekTableOffset += 2;
// $SeekTableEntry['shn_buffer_offset'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2));
// $SeekTableOffset += 2;
// $SeekTableEntry['shn_file_bit_offset'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2));
// $SeekTableOffset += 2;
// $SeekTableEntry['shn_gbuffer'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
// $SeekTableOffset += 4;
// $SeekTableEntry['shn_bit_shift'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2));
// $SeekTableOffset += 2;
// for ($j = 0; $j < 3; $j++) {
// $SeekTableEntry['cbuf0'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
// $SeekTableOffset += 4;
// }
// for ($j = 0; $j < 3; $j++) {
// $SeekTableEntry['cbuf1'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
// $SeekTableOffset += 4;
// }
// for ($j = 0; $j < 4; $j++) {
// $SeekTableEntry['offset0'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
// $SeekTableOffset += 4;
// }
// for ($j = 0; $j < 4; $j++) {
// $SeekTableEntry['offset1'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4));
// $SeekTableOffset += 4;
// }
//
// $ThisFileInfo['shn']['seektable']['entries'][] = $SeekTableEntry;
//}
}
}
if ((bool) ini_get('safe_mode')) {
$ThisFileInfo['error'][] = 'PHP running in Safe Mode - backtick operator not available, cannot run shntool to analyze Shorten files';
return false;
}
if (GETID3_OS_ISWINDOWS) {
$RequiredFiles = array('shorten.exe', 'cygwin1.dll', 'head.exe');
foreach ($RequiredFiles as $required_file) {
if (!is_readable(GETID3_HELPERAPPSDIR.$required_file)) {
$ThisFileInfo['error'][] = GETID3_HELPERAPPSDIR.$required_file.' does not exist';
return false;
}
}
$commandline = GETID3_HELPERAPPSDIR.'shorten.exe -x "'.$ThisFileInfo['filenamepath'].'" - | '.GETID3_HELPERAPPSDIR.'head.exe -c 64';
$commandline = str_replace('/', '\\', $commandline);
} else {
static $shorten_present;
if (!isset($shorten_present)) {
$shorten_present = file_exists('/usr/local/bin/shorten') || `which shorten`;
}
if (!$shorten_present) {
$ThisFileInfo['error'][] = 'shorten binary was not found in path or /usr/local/bin';
return false;
}
$commandline = (file_exists('/usr/local/bin/shorten') ? '/usr/local/bin/' : '' ) . 'shorten -x '.escapeshellarg($ThisFileInfo['filenamepath']).' - | head -c 64';
}
$output = `$commandline`;
if (!empty($output) && (substr($output, 12, 4) == 'fmt ')) {
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
$fmt_size = getid3_lib::LittleEndian2Int(substr($output, 16, 4));
$DecodedWAVFORMATEX = getid3_riff::RIFFparseWAVEFORMATex(substr($output, 20, $fmt_size));
$ThisFileInfo['audio']['channels'] = $DecodedWAVFORMATEX['channels'];
$ThisFileInfo['audio']['bits_per_sample'] = $DecodedWAVFORMATEX['bits_per_sample'];
$ThisFileInfo['audio']['sample_rate'] = $DecodedWAVFORMATEX['sample_rate'];
if (substr($output, 20 + $fmt_size, 4) == 'data') {
$ThisFileInfo['playtime_seconds'] = getid3_lib::LittleEndian2Int(substr($output, 20 + 4 + $fmt_size, 4)) / $DecodedWAVFORMATEX['raw']['nAvgBytesPerSec'];
} else {
$ThisFileInfo['error'][] = 'shorten failed to decode DATA chunk to expected location, cannot determine playtime';
return false;
}
$ThisFileInfo['audio']['bitrate'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / $ThisFileInfo['playtime_seconds']) * 8;
} else {
$ThisFileInfo['error'][] = 'shorten failed to decode file to WAV for parsing';
return false;
}
return true;
}
}
?>

View File

@ -1,107 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio.tta.php //
// module for analyzing TTA Audio files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_tta
{
function getid3_tta(&$fd, &$ThisFileInfo) {
$ThisFileInfo['fileformat'] = 'tta';
$ThisFileInfo['audio']['dataformat'] = 'tta';
$ThisFileInfo['audio']['lossless'] = true;
$ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$ttaheader = fread($fd, 26);
$ThisFileInfo['tta']['magic'] = substr($ttaheader, 0, 3);
if ($ThisFileInfo['tta']['magic'] != 'TTA') {
$ThisFileInfo['error'][] = 'Expecting "TTA" at offset '.$ThisFileInfo['avdataoffset'].', found "'.$ThisFileInfo['tta']['magic'].'"';
unset($ThisFileInfo['fileformat']);
unset($ThisFileInfo['audio']);
unset($ThisFileInfo['tta']);
return false;
}
switch ($ttaheader{3}) {
case "\x01": // TTA v1.x
case "\x02": // TTA v1.x
case "\x03": // TTA v1.x
// "It was the demo-version of the TTA encoder. There is no released format with such header. TTA encoder v1 is not supported about a year."
$ThisFileInfo['tta']['major_version'] = 1;
$ThisFileInfo['avdataoffset'] += 16;
$ThisFileInfo['tta']['compression_level'] = ord($ttaheader{3});
$ThisFileInfo['tta']['channels'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 4, 2));
$ThisFileInfo['tta']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 6, 2));
$ThisFileInfo['tta']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 8, 4));
$ThisFileInfo['tta']['samples_per_channel'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 12, 4));
$ThisFileInfo['audio']['encoder_options'] = '-e'.$ThisFileInfo['tta']['compression_level'];
$ThisFileInfo['playtime_seconds'] = $ThisFileInfo['tta']['samples_per_channel'] / $ThisFileInfo['tta']['sample_rate'];
break;
case '2': // TTA v2.x
// "I have hurried to release the TTA 2.0 encoder. Format documentation is removed from our site. This format still in development. Please wait the TTA2 format, encoder v4."
$ThisFileInfo['tta']['major_version'] = 2;
$ThisFileInfo['avdataoffset'] += 20;
$ThisFileInfo['tta']['compression_level'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 4, 2));
$ThisFileInfo['tta']['audio_format'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 6, 2));
$ThisFileInfo['tta']['channels'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 8, 2));
$ThisFileInfo['tta']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 10, 2));
$ThisFileInfo['tta']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 12, 4));
$ThisFileInfo['tta']['data_length'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 16, 4));
$ThisFileInfo['audio']['encoder_options'] = '-e'.$ThisFileInfo['tta']['compression_level'];
$ThisFileInfo['playtime_seconds'] = $ThisFileInfo['tta']['data_length'] / $ThisFileInfo['tta']['sample_rate'];
break;
case '1': // TTA v3.x
// "This is a first stable release of the TTA format. It will be supported by the encoders v3 or higher."
$ThisFileInfo['tta']['major_version'] = 3;
$ThisFileInfo['avdataoffset'] += 26;
$ThisFileInfo['tta']['audio_format'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 4, 2)); // getid3_riff::RIFFwFormatTagLookup()
$ThisFileInfo['tta']['channels'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 6, 2));
$ThisFileInfo['tta']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 8, 2));
$ThisFileInfo['tta']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 10, 4));
$ThisFileInfo['tta']['data_length'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 14, 4));
$ThisFileInfo['tta']['crc32_footer'] = substr($ttaheader, 18, 4);
$ThisFileInfo['tta']['seek_point'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 22, 4));
$ThisFileInfo['playtime_seconds'] = $ThisFileInfo['tta']['data_length'] / $ThisFileInfo['tta']['sample_rate'];
break;
default:
$ThisFileInfo['error'][] = 'This version of getID3() only knows how to handle TTA v1 and v2 - it may not work correctly with this file which appears to be TTA v'.$ttaheader{3};
return false;
break;
}
$ThisFileInfo['audio']['encoder'] = 'TTA v'.$ThisFileInfo['tta']['major_version'];
$ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['tta']['bits_per_sample'];
$ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['tta']['sample_rate'];
$ThisFileInfo['audio']['channels'] = $ThisFileInfo['tta']['channels'];
$ThisFileInfo['audio']['bitrate'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['playtime_seconds'];
return true;
}
}
?>

View File

@ -1,205 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio.voc.php //
// module for analyzing Creative VOC Audio files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_voc
{
function getid3_voc(&$fd, &$ThisFileInfo) {
$OriginalAVdataOffset = $ThisFileInfo['avdataoffset'];
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$VOCheader = fread($fd, 26);
if (substr($VOCheader, 0, 19) != 'Creative Voice File') {
$ThisFileInfo['error'][] = 'Expecting "Creative Voice File" at offset '.$ThisFileInfo['avdataoffset'].', found "'.substr($VOCheader, 0, 19).'"';
return false;
}
// shortcuts
$thisfile_audio = &$ThisFileInfo['audio'];
$ThisFileInfo['voc'] = array();
$thisfile_voc = &$ThisFileInfo['voc'];
$ThisFileInfo['fileformat'] = 'voc';
$thisfile_audio['dataformat'] = 'voc';
$thisfile_audio['bitrate_mode'] = 'cbr';
$thisfile_audio['lossless'] = true;
$thisfile_audio['channels'] = 1; // might be overriden below
$thisfile_audio['bits_per_sample'] = 8; // might be overriden below
// byte # Description
// ------ ------------------------------------------
// 00-12 'Creative Voice File'
// 13 1A (eof to abort printing of file)
// 14-15 Offset of first datablock in .voc file (std 1A 00 in Intel Notation)
// 16-17 Version number (minor,major) (VOC-HDR puts 0A 01)
// 18-19 2's Comp of Ver. # + 1234h (VOC-HDR puts 29 11)
$thisfile_voc['header']['datablock_offset'] = getid3_lib::LittleEndian2Int(substr($VOCheader, 20, 2));
$thisfile_voc['header']['minor_version'] = getid3_lib::LittleEndian2Int(substr($VOCheader, 22, 1));
$thisfile_voc['header']['major_version'] = getid3_lib::LittleEndian2Int(substr($VOCheader, 23, 1));
do {
$BlockOffset = ftell($fd);
$BlockData = fread($fd, 4);
$BlockType = ord($BlockData{0});
$BlockSize = getid3_lib::LittleEndian2Int(substr($BlockData, 1, 3));
$ThisBlock = array();
@$thisfile_voc['blocktypes'][$BlockType]++;
switch ($BlockType) {
case 0: // Terminator
// do nothing, we'll break out of the loop down below
break;
case 1: // Sound data
$BlockData .= fread($fd, 2);
if ($ThisFileInfo['avdataoffset'] <= $OriginalAVdataOffset) {
$ThisFileInfo['avdataoffset'] = ftell($fd);
}
fseek($fd, $BlockSize - 2, SEEK_CUR);
$ThisBlock['sample_rate_id'] = getid3_lib::LittleEndian2Int(substr($BlockData, 4, 1));
$ThisBlock['compression_type'] = getid3_lib::LittleEndian2Int(substr($BlockData, 5, 1));
$ThisBlock['compression_name'] = $this->VOCcompressionTypeLookup($ThisBlock['compression_type']);
if ($ThisBlock['compression_type'] <= 3) {
$thisfile_voc['compressed_bits_per_sample'] = getid3_lib::CastAsInt(str_replace('-bit', '', $ThisBlock['compression_name']));
}
// Less accurate sample_rate calculation than the Extended block (#8) data (but better than nothing if Extended Block is not available)
if (empty($thisfile_audio['sample_rate'])) {
// SR byte = 256 - (1000000 / sample_rate)
$thisfile_audio['sample_rate'] = getid3_lib::trunc((1000000 / (256 - $ThisBlock['sample_rate_id'])) / $thisfile_audio['channels']);
}
break;
case 2: // Sound continue
case 3: // Silence
case 4: // Marker
case 6: // Repeat
case 7: // End repeat
// nothing useful, just skip
fseek($fd, $BlockSize, SEEK_CUR);
break;
case 8: // Extended
$BlockData .= fread($fd, 4);
//00-01 Time Constant:
// Mono: 65536 - (256000000 / sample_rate)
// Stereo: 65536 - (256000000 / (sample_rate * 2))
$ThisBlock['time_constant'] = getid3_lib::LittleEndian2Int(substr($BlockData, 4, 2));
$ThisBlock['pack_method'] = getid3_lib::LittleEndian2Int(substr($BlockData, 6, 1));
$ThisBlock['stereo'] = (bool) getid3_lib::LittleEndian2Int(substr($BlockData, 7, 1));
$thisfile_audio['channels'] = ($ThisBlock['stereo'] ? 2 : 1);
$thisfile_audio['sample_rate'] = getid3_lib::trunc((256000000 / (65536 - $ThisBlock['time_constant'])) / $thisfile_audio['channels']);
break;
case 9: // data block that supersedes blocks 1 and 8. Used for stereo, 16 bit
$BlockData .= fread($fd, 12);
if ($ThisFileInfo['avdataoffset'] <= $OriginalAVdataOffset) {
$ThisFileInfo['avdataoffset'] = ftell($fd);
}
fseek($fd, $BlockSize - 12, SEEK_CUR);
$ThisBlock['sample_rate'] = getid3_lib::LittleEndian2Int(substr($BlockData, 4, 4));
$ThisBlock['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($BlockData, 8, 1));
$ThisBlock['channels'] = getid3_lib::LittleEndian2Int(substr($BlockData, 9, 1));
$ThisBlock['wFormat'] = getid3_lib::LittleEndian2Int(substr($BlockData, 10, 2));
$ThisBlock['compression_name'] = $this->VOCwFormatLookup($ThisBlock['wFormat']);
if ($this->VOCwFormatActualBitsPerSampleLookup($ThisBlock['wFormat'])) {
$thisfile_voc['compressed_bits_per_sample'] = $this->VOCwFormatActualBitsPerSampleLookup($ThisBlock['wFormat']);
}
$thisfile_audio['sample_rate'] = $ThisBlock['sample_rate'];
$thisfile_audio['bits_per_sample'] = $ThisBlock['bits_per_sample'];
$thisfile_audio['channels'] = $ThisBlock['channels'];
break;
default:
$ThisFileInfo['warning'][] = 'Unhandled block type "'.$BlockType.'" at offset '.$BlockOffset;
fseek($fd, $BlockSize, SEEK_CUR);
break;
}
if (!empty($ThisBlock)) {
$ThisBlock['block_offset'] = $BlockOffset;
$ThisBlock['block_size'] = $BlockSize;
$ThisBlock['block_type_id'] = $BlockType;
$thisfile_voc['blocks'][] = $ThisBlock;
}
} while (!feof($fd) && ($BlockType != 0));
// Terminator block doesn't have size field, so seek back 3 spaces
fseek($fd, -3, SEEK_CUR);
ksort($thisfile_voc['blocktypes']);
if (!empty($thisfile_voc['compressed_bits_per_sample'])) {
$ThisFileInfo['playtime_seconds'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / ($thisfile_voc['compressed_bits_per_sample'] * $thisfile_audio['channels'] * $thisfile_audio['sample_rate']);
$thisfile_audio['bitrate'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['playtime_seconds'];
}
return true;
}
function VOCcompressionTypeLookup($index) {
static $VOCcompressionTypeLookup = array(
0 => '8-bit',
1 => '4-bit',
2 => '2.6-bit',
3 => '2-bit'
);
return (isset($VOCcompressionTypeLookup[$index]) ? $VOCcompressionTypeLookup[$index] : 'Multi DAC ('.($index - 3).') channels');
}
function VOCwFormatLookup($index) {
static $VOCwFormatLookup = array(
0x0000 => '8-bit unsigned PCM',
0x0001 => 'Creative 8-bit to 4-bit ADPCM',
0x0002 => 'Creative 8-bit to 3-bit ADPCM',
0x0003 => 'Creative 8-bit to 2-bit ADPCM',
0x0004 => '16-bit signed PCM',
0x0006 => 'CCITT a-Law',
0x0007 => 'CCITT u-Law',
0x2000 => 'Creative 16-bit to 4-bit ADPCM'
);
return (isset($VOCwFormatLookup[$index]) ? $VOCwFormatLookup[$index] : false);
}
function VOCwFormatActualBitsPerSampleLookup($index) {
static $VOCwFormatLookup = array(
0x0000 => 8,
0x0001 => 4,
0x0002 => 3,
0x0003 => 2,
0x0004 => 16,
0x0006 => 8,
0x0007 => 8,
0x2000 => 4
);
return (isset($VOCwFormatLookup[$index]) ? $VOCwFormatLookup[$index] : false);
}
}
?>

View File

@ -1,159 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio.vqf.php //
// module for analyzing VQF audio files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_vqf
{
function getid3_vqf(&$fd, &$ThisFileInfo) {
// based loosely on code from TTwinVQ by Jurgen Faul <jfaulØgmx*de>
// http://jfaul.de/atl or http://j-faul.virtualave.net/atl/atl.html
$ThisFileInfo['fileformat'] = 'vqf';
$ThisFileInfo['audio']['dataformat'] = 'vqf';
$ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
$ThisFileInfo['audio']['lossless'] = false;
// shortcut
$ThisFileInfo['vqf']['raw'] = array();
$thisfile_vqf = &$ThisFileInfo['vqf'];
$thisfile_vqf_raw = &$thisfile_vqf['raw'];
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$VQFheaderData = fread($fd, 16);
$offset = 0;
$thisfile_vqf_raw['header_tag'] = substr($VQFheaderData, $offset, 4);
if ($thisfile_vqf_raw['header_tag'] != 'TWIN') {
$ThisFileInfo['error'][] = 'Expecting "TWIN" at offset '.$ThisFileInfo['avdataoffset'].', found "'.$thisfile_vqf_raw['header_tag'].'"';
unset($ThisFileInfo['vqf']);
unset($ThisFileInfo['fileformat']);
return false;
}
$offset += 4;
$thisfile_vqf_raw['version'] = substr($VQFheaderData, $offset, 8);
$offset += 8;
$thisfile_vqf_raw['size'] = getid3_lib::BigEndian2Int(substr($VQFheaderData, $offset, 4));
$offset += 4;
while (ftell($fd) < $ThisFileInfo['avdataend']) {
$ChunkBaseOffset = ftell($fd);
$chunkoffset = 0;
$ChunkData = fread($fd, 8);
$ChunkName = substr($ChunkData, $chunkoffset, 4);
if ($ChunkName == 'DATA') {
$ThisFileInfo['avdataoffset'] = $ChunkBaseOffset;
break;
}
$chunkoffset += 4;
$ChunkSize = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4));
$chunkoffset += 4;
if ($ChunkSize > ($ThisFileInfo['avdataend'] - ftell($fd))) {
$ThisFileInfo['error'][] = 'Invalid chunk size ('.$ChunkSize.') for chunk "'.$ChunkName.'" at offset '.$ChunkBaseOffset;
break;
}
if ($ChunkSize > 0) {
$ChunkData .= fread($fd, $ChunkSize);
}
switch ($ChunkName) {
case 'COMM':
// shortcut
$thisfile_vqf['COMM'] = array();
$thisfile_vqf_COMM = &$thisfile_vqf['COMM'];
$thisfile_vqf_COMM['channel_mode'] = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4));
$chunkoffset += 4;
$thisfile_vqf_COMM['bitrate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4));
$chunkoffset += 4;
$thisfile_vqf_COMM['sample_rate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4));
$chunkoffset += 4;
$thisfile_vqf_COMM['security_level'] = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4));
$chunkoffset += 4;
$ThisFileInfo['audio']['channels'] = $thisfile_vqf_COMM['channel_mode'] + 1;
$ThisFileInfo['audio']['sample_rate'] = $this->VQFchannelFrequencyLookup($thisfile_vqf_COMM['sample_rate']);
$ThisFileInfo['audio']['bitrate'] = $thisfile_vqf_COMM['bitrate'] * 1000;
$ThisFileInfo['audio']['encoder_options'] = 'CBR' . ceil($ThisFileInfo['audio']['bitrate']/1000);
if ($ThisFileInfo['audio']['bitrate'] == 0) {
$ThisFileInfo['error'][] = 'Corrupt VQF file: bitrate_audio == zero';
return false;
}
break;
case 'NAME':
case 'AUTH':
case '(c) ':
case 'FILE':
case 'COMT':
case 'ALBM':
$thisfile_vqf['comments'][$this->VQFcommentNiceNameLookup($ChunkName)][] = trim(substr($ChunkData, 8));
break;
case 'DSIZ':
$thisfile_vqf['DSIZ'] = getid3_lib::BigEndian2Int(substr($ChunkData, 8, 4));
break;
default:
$ThisFileInfo['warning'][] = 'Unhandled chunk type "'.$ChunkName.'" at offset '.$ChunkBaseOffset;
break;
}
}
$ThisFileInfo['playtime_seconds'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['audio']['bitrate'];
if (isset($thisfile_vqf['DSIZ']) && (($thisfile_vqf['DSIZ'] != ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset'] - strlen('DATA'))))) {
switch ($thisfile_vqf['DSIZ']) {
case 0:
case 1:
$ThisFileInfo['warning'][] = 'Invalid DSIZ value "'.$thisfile_vqf['DSIZ'].'". This is known to happen with VQF files encoded by Ahead Nero, and seems to be its way of saying this is TwinVQF v'.($thisfile_vqf['DSIZ'] + 1).'.0';
$ThisFileInfo['audio']['encoder'] = 'Ahead Nero';
break;
default:
$ThisFileInfo['warning'][] = 'Probable corrupted file - should be '.$thisfile_vqf['DSIZ'].' bytes, actually '.($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset'] - strlen('DATA'));
break;
}
}
return true;
}
function VQFchannelFrequencyLookup($frequencyid) {
static $VQFchannelFrequencyLookup = array(
11 => 11025,
22 => 22050,
44 => 44100
);
return (isset($VQFchannelFrequencyLookup[$frequencyid]) ? $VQFchannelFrequencyLookup[$frequencyid] : $frequencyid * 1000);
}
function VQFcommentNiceNameLookup($shortname) {
static $VQFcommentNiceNameLookup = array(
'NAME' => 'title',
'AUTH' => 'artist',
'(c) ' => 'copyright',
'FILE' => 'filename',
'COMT' => 'comment',
'ALBM' => 'album'
);
return (isset($VQFcommentNiceNameLookup[$shortname]) ? $VQFcommentNiceNameLookup[$shortname] : $shortname);
}
}
?>

View File

@ -1,372 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio.wavpack.php //
// module for analyzing WavPack v4.0+ Audio files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_wavpack
{
function getid3_wavpack(&$fd, &$ThisFileInfo) {
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
while (true) {
$wavpackheader = fread($fd, 32);
if (ftell($fd) >= $ThisFileInfo['avdataend']) {
break;
} elseif (feof($fd)) {
break;
} elseif (
(@$ThisFileInfo['wavpack']['blockheader']['total_samples'] > 0) &&
(@$ThisFileInfo['wavpack']['blockheader']['block_samples'] > 0) &&
(!isset($ThisFileInfo['wavpack']['riff_trailer_size']) || ($ThisFileInfo['wavpack']['riff_trailer_size'] <= 0)) &&
((@$ThisFileInfo['wavpack']['config_flags']['md5_checksum'] === false) || !empty($ThisFileInfo['md5_data_source']))) {
break;
}
$blockheader_offset = ftell($fd) - 32;
$blockheader_magic = substr($wavpackheader, 0, 4);
$blockheader_size = getid3_lib::LittleEndian2Int(substr($wavpackheader, 4, 4));
if ($blockheader_magic != 'wvpk') {
$ThisFileInfo['error'][] = 'Expecting "wvpk" at offset '.$blockheader_offset.', found "'.$blockheader_magic.'"';
if ((@$ThisFileInfo['audio']['dataformat'] != 'wavpack') && (@$ThisFileInfo['audio']['dataformat'] != 'wvc')) {
unset($ThisFileInfo['fileformat']);
unset($ThisFileInfo['audio']);
unset($ThisFileInfo['wavpack']);
}
return false;
}
if ((@$ThisFileInfo['wavpack']['blockheader']['block_samples'] <= 0) ||
(@$ThisFileInfo['wavpack']['blockheader']['total_samples'] <= 0)) {
// Also, it is possible that the first block might not have
// any samples (block_samples == 0) and in this case you should skip blocks
// until you find one with samples because the other information (like
// total_samples) are not guaranteed to be correct until (block_samples > 0)
// Finally, I have defined a format for files in which the length is not known
// (for example when raw files are created using pipes). In these cases
// total_samples will be -1 and you must seek to the final block to determine
// the total number of samples.
$ThisFileInfo['audio']['dataformat'] = 'wavpack';
$ThisFileInfo['fileformat'] = 'wavpack';
$ThisFileInfo['audio']['lossless'] = true;
$ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
$ThisFileInfo['wavpack']['blockheader']['offset'] = $blockheader_offset;
$ThisFileInfo['wavpack']['blockheader']['magic'] = $blockheader_magic;
$ThisFileInfo['wavpack']['blockheader']['size'] = $blockheader_size;
if ($ThisFileInfo['wavpack']['blockheader']['size'] >= 0x100000) {
$ThisFileInfo['error'][] = 'Expecting WavPack block size less than "0x100000", found "'.$ThisFileInfo['wavpack']['blockheader']['size'].'" at offset '.$ThisFileInfo['wavpack']['blockheader']['offset'];
if ((@$ThisFileInfo['audio']['dataformat'] != 'wavpack') && (@$ThisFileInfo['audio']['dataformat'] != 'wvc')) {
unset($ThisFileInfo['fileformat']);
unset($ThisFileInfo['audio']);
unset($ThisFileInfo['wavpack']);
}
return false;
}
$ThisFileInfo['wavpack']['blockheader']['minor_version'] = ord($wavpackheader{8});
$ThisFileInfo['wavpack']['blockheader']['major_version'] = ord($wavpackheader{9});
if (($ThisFileInfo['wavpack']['blockheader']['major_version'] != 4) ||
(($ThisFileInfo['wavpack']['blockheader']['minor_version'] < 4) &&
($ThisFileInfo['wavpack']['blockheader']['minor_version'] > 16))) {
$ThisFileInfo['error'][] = 'Expecting WavPack version between "4.2" and "4.16", found version "'.$ThisFileInfo['wavpack']['blockheader']['major_version'].'.'.$ThisFileInfo['wavpack']['blockheader']['minor_version'].'" at offset '.$ThisFileInfo['wavpack']['blockheader']['offset'];
if ((@$ThisFileInfo['audio']['dataformat'] != 'wavpack') && (@$ThisFileInfo['audio']['dataformat'] != 'wvc')) {
unset($ThisFileInfo['fileformat']);
unset($ThisFileInfo['audio']);
unset($ThisFileInfo['wavpack']);
}
return false;
}
$ThisFileInfo['wavpack']['blockheader']['track_number'] = ord($wavpackheader{10}); // unused
$ThisFileInfo['wavpack']['blockheader']['index_number'] = ord($wavpackheader{11}); // unused
$ThisFileInfo['wavpack']['blockheader']['total_samples'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 12, 4));
$ThisFileInfo['wavpack']['blockheader']['block_index'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 16, 4));
$ThisFileInfo['wavpack']['blockheader']['block_samples'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 20, 4));
$ThisFileInfo['wavpack']['blockheader']['flags_raw'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 24, 4));
$ThisFileInfo['wavpack']['blockheader']['crc'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 28, 4));
$ThisFileInfo['wavpack']['blockheader']['flags']['bytes_per_sample'] = 1 + ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000003);
$ThisFileInfo['wavpack']['blockheader']['flags']['mono'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000004);
$ThisFileInfo['wavpack']['blockheader']['flags']['hybrid'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000008);
$ThisFileInfo['wavpack']['blockheader']['flags']['joint_stereo'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000010);
$ThisFileInfo['wavpack']['blockheader']['flags']['cross_decorrelation'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000020);
$ThisFileInfo['wavpack']['blockheader']['flags']['hybrid_noiseshape'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000040);
$ThisFileInfo['wavpack']['blockheader']['flags']['ieee_32bit_float'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000080);
$ThisFileInfo['wavpack']['blockheader']['flags']['int_32bit'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000100);
$ThisFileInfo['wavpack']['blockheader']['flags']['hybrid_bitrate_noise'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000200);
$ThisFileInfo['wavpack']['blockheader']['flags']['hybrid_balance_noise'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000400);
$ThisFileInfo['wavpack']['blockheader']['flags']['multichannel_initial'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00000800);
$ThisFileInfo['wavpack']['blockheader']['flags']['multichannel_final'] = (bool) ($ThisFileInfo['wavpack']['blockheader']['flags_raw'] & 0x00001000);
$ThisFileInfo['audio']['lossless'] = !$ThisFileInfo['wavpack']['blockheader']['flags']['hybrid'];
}
while (!feof($fd) && (ftell($fd) < ($blockheader_offset + $blockheader_size + 8))) {
$metablock = array('offset'=>ftell($fd));
$metablockheader = fread($fd, 2);
if (feof($fd)) {
break;
}
$metablock['id'] = ord($metablockheader{0});
$metablock['function_id'] = ($metablock['id'] & 0x3F);
$metablock['function_name'] = $this->WavPackMetablockNameLookup($metablock['function_id']);
// The 0x20 bit in the id of the meta subblocks (which is defined as
// ID_OPTIONAL_DATA) is a permanent part of the id. The idea is that
// if a decoder encounters an id that it does not know about, it uses
// that "ID_OPTIONAL_DATA" flag to determine what to do. If it is set
// then the decoder simply ignores the metadata, but if it is zero
// then the decoder should quit because it means that an understanding
// of the metadata is required to correctly decode the audio.
$metablock['non_decoder'] = (bool) ($metablock['id'] & 0x20);
$metablock['padded_data'] = (bool) ($metablock['id'] & 0x40);
$metablock['large_block'] = (bool) ($metablock['id'] & 0x80);
if ($metablock['large_block']) {
$metablockheader .= fread($fd, 2);
}
$metablock['size'] = getid3_lib::LittleEndian2Int(substr($metablockheader, 1)) * 2; // size is stored in words
$metablock['data'] = null;
if ($metablock['size'] > 0) {
switch ($metablock['function_id']) {
case 0x21: // ID_RIFF_HEADER
case 0x22: // ID_RIFF_TRAILER
case 0x23: // ID_REPLAY_GAIN
case 0x24: // ID_CUESHEET
case 0x25: // ID_CONFIG_BLOCK
case 0x26: // ID_MD5_CHECKSUM
$metablock['data'] = fread($fd, $metablock['size']);
if ($metablock['padded_data']) {
// padded to the nearest even byte
$metablock['size']--;
$metablock['data'] = substr($metablock['data'], 0, -1);
}
break;
case 0x00: // ID_DUMMY
case 0x01: // ID_ENCODER_INFO
case 0x02: // ID_DECORR_TERMS
case 0x03: // ID_DECORR_WEIGHTS
case 0x04: // ID_DECORR_SAMPLES
case 0x05: // ID_ENTROPY_VARS
case 0x06: // ID_HYBRID_PROFILE
case 0x07: // ID_SHAPING_WEIGHTS
case 0x08: // ID_FLOAT_INFO
case 0x09: // ID_INT32_INFO
case 0x0A: // ID_WV_BITSTREAM
case 0x0B: // ID_WVC_BITSTREAM
case 0x0C: // ID_WVX_BITSTREAM
case 0x0D: // ID_CHANNEL_INFO
fseek($fd, $metablock['offset'] + ($metablock['large_block'] ? 4 : 2) + $metablock['size'], SEEK_SET);
break;
default:
$ThisFileInfo['warning'][] = 'Unexpected metablock type "0x'.str_pad(dechex($metablock['function_id']), 2, '0', STR_PAD_LEFT).'" at offset '.$metablock['offset'];
fseek($fd, $metablock['offset'] + ($metablock['large_block'] ? 4 : 2) + $metablock['size'], SEEK_SET);
break;
}
switch ($metablock['function_id']) {
case 0x21: // ID_RIFF_HEADER
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
$original_wav_filesize = getid3_lib::LittleEndian2Int(substr($metablock['data'], 4, 4));
getid3_riff::ParseRIFFdata($metablock['data'], $ParsedRIFFheader);
$metablock['riff'] = $ParsedRIFFheader['riff'];
$metablock['riff']['original_filesize'] = $original_wav_filesize;
$ThisFileInfo['wavpack']['riff_trailer_size'] = $original_wav_filesize - $metablock['riff']['WAVE']['data'][0]['size'] - $metablock['riff']['header_size'];
$ThisFileInfo['audio']['sample_rate'] = $ParsedRIFFheader['riff']['raw']['fmt ']['nSamplesPerSec'];
$ThisFileInfo['playtime_seconds'] = $ThisFileInfo['wavpack']['blockheader']['total_samples'] / $ThisFileInfo['audio']['sample_rate'];
// Safe RIFF header in case there's a RIFF footer later
$metablockRIFFheader = $metablock['data'];
break;
case 0x22: // ID_RIFF_TRAILER
$metablockRIFFfooter = $metablockRIFFheader.$metablock['data'];
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
$ftell_old = ftell($fd);
$startoffset = $metablock['offset'] + ($metablock['large_block'] ? 4 : 2);
$ParsedRIFFfooter = array('avdataend'=>$ThisFileInfo['avdataend'], 'fileformat'=>'riff', 'error'=>array(), 'warning'=>array());
$metablock['riff'] = getid3_riff::ParseRIFF($fd, $startoffset, $startoffset + $metablock['size'], $ParsedRIFFfooter);
fseek($fd, $ftell_old, SEEK_SET);
if (!empty($metablock['riff']['INFO'])) {
getid3_riff::RIFFcommentsParse($metablock['riff']['INFO'], $metablock['comments']);
$ThisFileInfo['tags']['riff'] = $metablock['comments'];
}
break;
case 0x23: // ID_REPLAY_GAIN
$ThisFileInfo['warning'][] = 'WavPack "Replay Gain" contents not yet handled by getID3() in metablock at offset '.$metablock['offset'];
break;
case 0x24: // ID_CUESHEET
$ThisFileInfo['warning'][] = 'WavPack "Cuesheet" contents not yet handled by getID3() in metablock at offset '.$metablock['offset'];
break;
case 0x25: // ID_CONFIG_BLOCK
$metablock['flags_raw'] = getid3_lib::LittleEndian2Int(substr($metablock['data'], 0, 3));
$metablock['flags']['adobe_mode'] = (bool) ($metablock['flags_raw'] & 0x000001); // "adobe" mode for 32-bit floats
$metablock['flags']['fast_flag'] = (bool) ($metablock['flags_raw'] & 0x000002); // fast mode
$metablock['flags']['very_fast_flag'] = (bool) ($metablock['flags_raw'] & 0x000004); // double fast
$metablock['flags']['high_flag'] = (bool) ($metablock['flags_raw'] & 0x000008); // high quality mode
$metablock['flags']['very_high_flag'] = (bool) ($metablock['flags_raw'] & 0x000010); // double high (not used yet)
$metablock['flags']['bitrate_kbps'] = (bool) ($metablock['flags_raw'] & 0x000020); // bitrate is kbps, not bits / sample
$metablock['flags']['auto_shaping'] = (bool) ($metablock['flags_raw'] & 0x000040); // automatic noise shaping
$metablock['flags']['shape_override'] = (bool) ($metablock['flags_raw'] & 0x000080); // shaping mode specified
$metablock['flags']['joint_override'] = (bool) ($metablock['flags_raw'] & 0x000100); // joint-stereo mode specified
$metablock['flags']['copy_time'] = (bool) ($metablock['flags_raw'] & 0x000200); // copy file-time from source
$metablock['flags']['create_exe'] = (bool) ($metablock['flags_raw'] & 0x000400); // create executable
$metablock['flags']['create_wvc'] = (bool) ($metablock['flags_raw'] & 0x000800); // create correction file
$metablock['flags']['optimize_wvc'] = (bool) ($metablock['flags_raw'] & 0x001000); // maximize bybrid compression
$metablock['flags']['quality_mode'] = (bool) ($metablock['flags_raw'] & 0x002000); // psychoacoustic quality mode
$metablock['flags']['raw_flag'] = (bool) ($metablock['flags_raw'] & 0x004000); // raw mode (not implemented yet)
$metablock['flags']['calc_noise'] = (bool) ($metablock['flags_raw'] & 0x008000); // calc noise in hybrid mode
$metablock['flags']['lossy_mode'] = (bool) ($metablock['flags_raw'] & 0x010000); // obsolete (for information)
$metablock['flags']['extra_mode'] = (bool) ($metablock['flags_raw'] & 0x020000); // extra processing mode
$metablock['flags']['skip_wvx'] = (bool) ($metablock['flags_raw'] & 0x040000); // no wvx stream w/ floats & big ints
$metablock['flags']['md5_checksum'] = (bool) ($metablock['flags_raw'] & 0x080000); // compute & store MD5 signature
$metablock['flags']['quiet_mode'] = (bool) ($metablock['flags_raw'] & 0x100000); // don't report progress %
$ThisFileInfo['wavpack']['config_flags'] = $metablock['flags'];
if ($ThisFileInfo['wavpack']['blockheader']['flags']['hybrid']) {
@$ThisFileInfo['audio']['encoder_options'] .= ' -b???';
}
@$ThisFileInfo['audio']['encoder_options'] .= ($metablock['flags']['adobe_mode'] ? ' -a' : '');
@$ThisFileInfo['audio']['encoder_options'] .= ($metablock['flags']['optimize_wvc'] ? ' -cc' : '');
@$ThisFileInfo['audio']['encoder_options'] .= ($metablock['flags']['create_exe'] ? ' -e' : '');
@$ThisFileInfo['audio']['encoder_options'] .= ($metablock['flags']['fast_flag'] ? ' -f' : '');
@$ThisFileInfo['audio']['encoder_options'] .= ($metablock['flags']['joint_override'] ? ' -j?' : '');
@$ThisFileInfo['audio']['encoder_options'] .= ($metablock['flags']['high_flag'] ? ' -h' : '');
@$ThisFileInfo['audio']['encoder_options'] .= ($metablock['flags']['md5_checksum'] ? ' -m' : '');
@$ThisFileInfo['audio']['encoder_options'] .= ($metablock['flags']['calc_noise'] ? ' -n' : '');
@$ThisFileInfo['audio']['encoder_options'] .= ($metablock['flags']['shape_override'] ? ' -s?' : '');
@$ThisFileInfo['audio']['encoder_options'] .= ($metablock['flags']['extra_mode'] ? ' -x?' : '');
if (@$ThisFileInfo['audio']['encoder_options']) {
$ThisFileInfo['audio']['encoder_options'] = trim(@$ThisFileInfo['audio']['encoder_options']);
}
elseif (isset($ThisFileInfo['audio']['encoder_options'])) {
unset($ThisFileInfo['audio']['encoder_options']);
}
break;
case 0x26: // ID_MD5_CHECKSUM
if (strlen($metablock['data']) == 16) {
$ThisFileInfo['md5_data_source'] = strtolower(getid3_lib::PrintHexBytes($metablock['data'], true, false, false));
} else {
$ThisFileInfo['warning'][] = 'Expecting 16 bytes of WavPack "MD5 Checksum" in metablock at offset '.$metablock['offset'].', but found '.strlen($metablock['data']).' bytes';
}
break;
case 0x00: // ID_DUMMY
case 0x01: // ID_ENCODER_INFO
case 0x02: // ID_DECORR_TERMS
case 0x03: // ID_DECORR_WEIGHTS
case 0x04: // ID_DECORR_SAMPLES
case 0x05: // ID_ENTROPY_VARS
case 0x06: // ID_HYBRID_PROFILE
case 0x07: // ID_SHAPING_WEIGHTS
case 0x08: // ID_FLOAT_INFO
case 0x09: // ID_INT32_INFO
case 0x0A: // ID_WV_BITSTREAM
case 0x0B: // ID_WVC_BITSTREAM
case 0x0C: // ID_WVX_BITSTREAM
case 0x0D: // ID_CHANNEL_INFO
unset($metablock);
break;
}
}
if (!empty($metablock)) {
$ThisFileInfo['wavpack']['metablocks'][] = $metablock;
}
}
}
$ThisFileInfo['audio']['encoder'] = 'WavPack v'.$ThisFileInfo['wavpack']['blockheader']['major_version'].'.'.str_pad($ThisFileInfo['wavpack']['blockheader']['minor_version'], 2, '0', STR_PAD_LEFT);
$ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['wavpack']['blockheader']['flags']['bytes_per_sample'] * 8;
$ThisFileInfo['audio']['channels'] = ($ThisFileInfo['wavpack']['blockheader']['flags']['mono'] ? 1 : 2);
if (@$ThisFileInfo['playtime_seconds']) {
$ThisFileInfo['audio']['bitrate'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['playtime_seconds'];
} else {
$ThisFileInfo['audio']['dataformat'] = 'wvc';
}
return true;
}
function WavPackMetablockNameLookup(&$id) {
static $WavPackMetablockNameLookup = array(
0x00 => 'Dummy',
0x01 => 'Encoder Info',
0x02 => 'Decorrelation Terms',
0x03 => 'Decorrelation Weights',
0x04 => 'Decorrelation Samples',
0x05 => 'Entropy Variables',
0x06 => 'Hybrid Profile',
0x07 => 'Shaping Weights',
0x08 => 'Float Info',
0x09 => 'Int32 Info',
0x0A => 'WV Bitstream',
0x0B => 'WVC Bitstream',
0x0C => 'WVX Bitstream',
0x0D => 'Channel Info',
0x21 => 'RIFF header',
0x22 => 'RIFF trailer',
0x23 => 'Replay Gain',
0x24 => 'Cuesheet',
0x25 => 'Config Block',
0x26 => 'MD5 Checksum',
);
return (@$WavPackMetablockNameLookup[$id]);
}
}
?>

View File

@ -1,685 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.graphic.bmp.php //
// module for analyzing BMP Image files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_bmp
{
function getid3_bmp(&$fd, &$ThisFileInfo, $ExtractPalette=false, $ExtractData=false) {
// shortcuts
$ThisFileInfo['bmp']['header']['raw'] = array();
$thisfile_bmp = &$ThisFileInfo['bmp'];
$thisfile_bmp_header = &$thisfile_bmp['header'];
$thisfile_bmp_header_raw = &$thisfile_bmp_header['raw'];
// BITMAPFILEHEADER [14 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_62uq.asp
// all versions
// WORD bfType;
// DWORD bfSize;
// WORD bfReserved1;
// WORD bfReserved2;
// DWORD bfOffBits;
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$offset = 0;
$BMPheader = fread($fd, 14 + 40);
$thisfile_bmp_header_raw['identifier'] = substr($BMPheader, $offset, 2);
$offset += 2;
if ($thisfile_bmp_header_raw['identifier'] != 'BM') {
$ThisFileInfo['error'][] = 'Expecting "BM" at offset '.$ThisFileInfo['avdataoffset'].', found "'.$thisfile_bmp_header_raw['identifier'].'"';
unset($ThisFileInfo['fileformat']);
unset($ThisFileInfo['bmp']);
return false;
}
$thisfile_bmp_header_raw['filesize'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
$offset += 4;
$thisfile_bmp_header_raw['reserved1'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
$offset += 2;
$thisfile_bmp_header_raw['reserved2'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
$offset += 2;
$thisfile_bmp_header_raw['data_offset'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
$offset += 4;
$thisfile_bmp_header_raw['header_size'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
$offset += 4;
// check if the hardcoded-to-1 "planes" is at offset 22 or 26
$planes22 = getid3_lib::LittleEndian2Int(substr($BMPheader, 22, 2));
$planes26 = getid3_lib::LittleEndian2Int(substr($BMPheader, 26, 2));
if (($planes22 == 1) && ($planes26 != 1)) {
$thisfile_bmp['type_os'] = 'OS/2';
$thisfile_bmp['type_version'] = 1;
} elseif (($planes26 == 1) && ($planes22 != 1)) {
$thisfile_bmp['type_os'] = 'Windows';
$thisfile_bmp['type_version'] = 1;
} elseif ($thisfile_bmp_header_raw['header_size'] == 12) {
$thisfile_bmp['type_os'] = 'OS/2';
$thisfile_bmp['type_version'] = 1;
} elseif ($thisfile_bmp_header_raw['header_size'] == 40) {
$thisfile_bmp['type_os'] = 'Windows';
$thisfile_bmp['type_version'] = 1;
} elseif ($thisfile_bmp_header_raw['header_size'] == 84) {
$thisfile_bmp['type_os'] = 'Windows';
$thisfile_bmp['type_version'] = 4;
} elseif ($thisfile_bmp_header_raw['header_size'] == 100) {
$thisfile_bmp['type_os'] = 'Windows';
$thisfile_bmp['type_version'] = 5;
} else {
$ThisFileInfo['error'][] = 'Unknown BMP subtype (or not a BMP file)';
unset($ThisFileInfo['fileformat']);
unset($ThisFileInfo['bmp']);
return false;
}
$ThisFileInfo['fileformat'] = 'bmp';
$ThisFileInfo['video']['dataformat'] = 'bmp';
$ThisFileInfo['video']['lossless'] = true;
$ThisFileInfo['video']['pixel_aspect_ratio'] = (float) 1;
if ($thisfile_bmp['type_os'] == 'OS/2') {
// OS/2-format BMP
// http://netghost.narod.ru/gff/graphics/summary/os2bmp.htm
// DWORD Size; /* Size of this structure in bytes */
// DWORD Width; /* Bitmap width in pixels */
// DWORD Height; /* Bitmap height in pixel */
// WORD NumPlanes; /* Number of bit planes (color depth) */
// WORD BitsPerPixel; /* Number of bits per pixel per plane */
$thisfile_bmp_header_raw['width'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
$offset += 2;
$thisfile_bmp_header_raw['height'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
$offset += 2;
$thisfile_bmp_header_raw['planes'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
$offset += 2;
$thisfile_bmp_header_raw['bits_per_pixel'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
$offset += 2;
$ThisFileInfo['video']['resolution_x'] = $thisfile_bmp_header_raw['width'];
$ThisFileInfo['video']['resolution_y'] = $thisfile_bmp_header_raw['height'];
$ThisFileInfo['video']['codec'] = 'BI_RGB '.$thisfile_bmp_header_raw['bits_per_pixel'].'-bit';
$ThisFileInfo['video']['bits_per_sample'] = $thisfile_bmp_header_raw['bits_per_pixel'];
if ($thisfile_bmp['type_version'] >= 2) {
// DWORD Compression; /* Bitmap compression scheme */
// DWORD ImageDataSize; /* Size of bitmap data in bytes */
// DWORD XResolution; /* X resolution of display device */
// DWORD YResolution; /* Y resolution of display device */
// DWORD ColorsUsed; /* Number of color table indices used */
// DWORD ColorsImportant; /* Number of important color indices */
// WORD Units; /* Type of units used to measure resolution */
// WORD Reserved; /* Pad structure to 4-byte boundary */
// WORD Recording; /* Recording algorithm */
// WORD Rendering; /* Halftoning algorithm used */
// DWORD Size1; /* Reserved for halftoning algorithm use */
// DWORD Size2; /* Reserved for halftoning algorithm use */
// DWORD ColorEncoding; /* Color model used in bitmap */
// DWORD Identifier; /* Reserved for application use */
$thisfile_bmp_header_raw['compression'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
$offset += 4;
$thisfile_bmp_header_raw['bmp_data_size'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
$offset += 4;
$thisfile_bmp_header_raw['resolution_h'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
$offset += 4;
$thisfile_bmp_header_raw['resolution_v'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
$offset += 4;
$thisfile_bmp_header_raw['colors_used'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
$offset += 4;
$thisfile_bmp_header_raw['colors_important'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
$offset += 4;
$thisfile_bmp_header_raw['resolution_units'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
$offset += 2;
$thisfile_bmp_header_raw['reserved1'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
$offset += 2;
$thisfile_bmp_header_raw['recording'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
$offset += 2;
$thisfile_bmp_header_raw['rendering'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
$offset += 2;
$thisfile_bmp_header_raw['size1'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
$offset += 4;
$thisfile_bmp_header_raw['size2'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
$offset += 4;
$thisfile_bmp_header_raw['color_encoding'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
$offset += 4;
$thisfile_bmp_header_raw['identifier'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
$offset += 4;
$thisfile_bmp_header['compression'] = $this->BMPcompressionOS2Lookup($thisfile_bmp_header_raw['compression']);
$ThisFileInfo['video']['codec'] = $thisfile_bmp_header['compression'].' '.$thisfile_bmp_header_raw['bits_per_pixel'].'-bit';
}
} elseif ($thisfile_bmp['type_os'] == 'Windows') {
// Windows-format BMP
// BITMAPINFOHEADER - [40 bytes] http://msdn.microsoft.com/library/en-us/gdi/bitmaps_1rw2.asp
// all versions
// DWORD biSize;
// LONG biWidth;
// LONG biHeight;
// WORD biPlanes;
// WORD biBitCount;
// DWORD biCompression;
// DWORD biSizeImage;
// LONG biXPelsPerMeter;
// LONG biYPelsPerMeter;
// DWORD biClrUsed;
// DWORD biClrImportant;
// possibly integrate this section and module.audio-video.riff.php::ParseBITMAPINFOHEADER() ?
$thisfile_bmp_header_raw['width'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4), true);
$offset += 4;
$thisfile_bmp_header_raw['height'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4), true);
$offset += 4;
$thisfile_bmp_header_raw['planes'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
$offset += 2;
$thisfile_bmp_header_raw['bits_per_pixel'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2));
$offset += 2;
$thisfile_bmp_header_raw['compression'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
$offset += 4;
$thisfile_bmp_header_raw['bmp_data_size'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
$offset += 4;
$thisfile_bmp_header_raw['resolution_h'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4), true);
$offset += 4;
$thisfile_bmp_header_raw['resolution_v'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4), true);
$offset += 4;
$thisfile_bmp_header_raw['colors_used'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
$offset += 4;
$thisfile_bmp_header_raw['colors_important'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
$offset += 4;
$thisfile_bmp_header['compression'] = $this->BMPcompressionWindowsLookup($thisfile_bmp_header_raw['compression']);
$ThisFileInfo['video']['resolution_x'] = $thisfile_bmp_header_raw['width'];
$ThisFileInfo['video']['resolution_y'] = $thisfile_bmp_header_raw['height'];
$ThisFileInfo['video']['codec'] = $thisfile_bmp_header['compression'].' '.$thisfile_bmp_header_raw['bits_per_pixel'].'-bit';
$ThisFileInfo['video']['bits_per_sample'] = $thisfile_bmp_header_raw['bits_per_pixel'];
if (($thisfile_bmp['type_version'] >= 4) || ($thisfile_bmp_header_raw['compression'] == 3)) {
// should only be v4+, but BMPs with type_version==1 and BI_BITFIELDS compression have been seen
$BMPheader .= fread($fd, 44);
// BITMAPV4HEADER - [44 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_2k1e.asp
// Win95+, WinNT4.0+
// DWORD bV4RedMask;
// DWORD bV4GreenMask;
// DWORD bV4BlueMask;
// DWORD bV4AlphaMask;
// DWORD bV4CSType;
// CIEXYZTRIPLE bV4Endpoints;
// DWORD bV4GammaRed;
// DWORD bV4GammaGreen;
// DWORD bV4GammaBlue;
$thisfile_bmp_header_raw['red_mask'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
$offset += 4;
$thisfile_bmp_header_raw['green_mask'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
$offset += 4;
$thisfile_bmp_header_raw['blue_mask'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
$offset += 4;
$thisfile_bmp_header_raw['alpha_mask'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
$offset += 4;
$thisfile_bmp_header_raw['cs_type'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
$offset += 4;
$thisfile_bmp_header_raw['ciexyz_red'] = substr($BMPheader, $offset, 4);
$offset += 4;
$thisfile_bmp_header_raw['ciexyz_green'] = substr($BMPheader, $offset, 4);
$offset += 4;
$thisfile_bmp_header_raw['ciexyz_blue'] = substr($BMPheader, $offset, 4);
$offset += 4;
$thisfile_bmp_header_raw['gamma_red'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
$offset += 4;
$thisfile_bmp_header_raw['gamma_green'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
$offset += 4;
$thisfile_bmp_header_raw['gamma_blue'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
$offset += 4;
$thisfile_bmp_header['ciexyz_red'] = getid3_lib::FixedPoint2_30(strrev($thisfile_bmp_header_raw['ciexyz_red']));
$thisfile_bmp_header['ciexyz_green'] = getid3_lib::FixedPoint2_30(strrev($thisfile_bmp_header_raw['ciexyz_green']));
$thisfile_bmp_header['ciexyz_blue'] = getid3_lib::FixedPoint2_30(strrev($thisfile_bmp_header_raw['ciexyz_blue']));
}
if ($thisfile_bmp['type_version'] >= 5) {
$BMPheader .= fread($fd, 16);
// BITMAPV5HEADER - [16 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_7c36.asp
// Win98+, Win2000+
// DWORD bV5Intent;
// DWORD bV5ProfileData;
// DWORD bV5ProfileSize;
// DWORD bV5Reserved;
$thisfile_bmp_header_raw['intent'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
$offset += 4;
$thisfile_bmp_header_raw['profile_data_offset'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
$offset += 4;
$thisfile_bmp_header_raw['profile_data_size'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
$offset += 4;
$thisfile_bmp_header_raw['reserved3'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4));
$offset += 4;
}
} else {
$ThisFileInfo['error'][] = 'Unknown BMP format in header.';
return false;
}
if ($ExtractPalette || $ExtractData) {
$PaletteEntries = 0;
if ($thisfile_bmp_header_raw['bits_per_pixel'] < 16) {
$PaletteEntries = pow(2, $thisfile_bmp_header_raw['bits_per_pixel']);
} elseif (isset($thisfile_bmp_header_raw['colors_used']) && ($thisfile_bmp_header_raw['colors_used'] > 0) && ($thisfile_bmp_header_raw['colors_used'] <= 256)) {
$PaletteEntries = $thisfile_bmp_header_raw['colors_used'];
}
if ($PaletteEntries > 0) {
$BMPpalette = fread($fd, 4 * $PaletteEntries);
$paletteoffset = 0;
for ($i = 0; $i < $PaletteEntries; $i++) {
// RGBQUAD - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_5f8y.asp
// BYTE rgbBlue;
// BYTE rgbGreen;
// BYTE rgbRed;
// BYTE rgbReserved;
$blue = getid3_lib::LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1));
$green = getid3_lib::LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1));
$red = getid3_lib::LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1));
if (($thisfile_bmp['type_os'] == 'OS/2') && ($thisfile_bmp['type_version'] == 1)) {
// no padding byte
} else {
$paletteoffset++; // padding byte
}
$thisfile_bmp['palette'][$i] = (($red << 16) | ($green << 8) | $blue);
}
}
}
if ($ExtractData) {
fseek($fd, $thisfile_bmp_header_raw['data_offset'], SEEK_SET);
$RowByteLength = ceil(($thisfile_bmp_header_raw['width'] * ($thisfile_bmp_header_raw['bits_per_pixel'] / 8)) / 4) * 4; // round up to nearest DWORD boundry
$BMPpixelData = fread($fd, $thisfile_bmp_header_raw['height'] * $RowByteLength);
$pixeldataoffset = 0;
switch (@$thisfile_bmp_header_raw['compression']) {
case 0: // BI_RGB
switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
case 1:
for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col = $col) {
$paletteindexbyte = ord($BMPpixelData{$pixeldataoffset++});
for ($i = 7; $i >= 0; $i--) {
$paletteindex = ($paletteindexbyte & (0x01 << $i)) >> $i;
$thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
$col++;
}
}
while (($pixeldataoffset % 4) != 0) {
// lines are padded to nearest DWORD
$pixeldataoffset++;
}
}
break;
case 4:
for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col = $col) {
$paletteindexbyte = ord($BMPpixelData{$pixeldataoffset++});
for ($i = 1; $i >= 0; $i--) {
$paletteindex = ($paletteindexbyte & (0x0F << (4 * $i))) >> (4 * $i);
$thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
$col++;
}
}
while (($pixeldataoffset % 4) != 0) {
// lines are padded to nearest DWORD
$pixeldataoffset++;
}
}
break;
case 8:
for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
$paletteindex = ord($BMPpixelData{$pixeldataoffset++});
$thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
}
while (($pixeldataoffset % 4) != 0) {
// lines are padded to nearest DWORD
$pixeldataoffset++;
}
}
break;
case 24:
for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
$thisfile_bmp['data'][$row][$col] = (ord($BMPpixelData{$pixeldataoffset+2}) << 16) | (ord($BMPpixelData{$pixeldataoffset+1}) << 8) | ord($BMPpixelData{$pixeldataoffset});
$pixeldataoffset += 3;
}
while (($pixeldataoffset % 4) != 0) {
// lines are padded to nearest DWORD
$pixeldataoffset++;
}
}
break;
case 32:
for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
$thisfile_bmp['data'][$row][$col] = (ord($BMPpixelData{$pixeldataoffset+3}) << 24) | (ord($BMPpixelData{$pixeldataoffset+2}) << 16) | (ord($BMPpixelData{$pixeldataoffset+1}) << 8) | ord($BMPpixelData{$pixeldataoffset});
$pixeldataoffset += 4;
}
while (($pixeldataoffset % 4) != 0) {
// lines are padded to nearest DWORD
$pixeldataoffset++;
}
}
break;
case 16:
// ?
break;
default:
$ThisFileInfo['error'][] = 'Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data';
break;
}
break;
case 1: // BI_RLE8 - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_6x0u.asp
switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
case 8:
$pixelcounter = 0;
while ($pixeldataoffset < strlen($BMPpixelData)) {
$firstbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
$secondbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
if ($firstbyte == 0) {
// escaped/absolute mode - the first byte of the pair can be set to zero to
// indicate an escape character that denotes the end of a line, the end of
// a bitmap, or a delta, depending on the value of the second byte.
switch ($secondbyte) {
case 0:
// end of line
// no need for special processing, just ignore
break;
case 1:
// end of bitmap
$pixeldataoffset = strlen($BMPpixelData); // force to exit loop just in case
break;
case 2:
// delta - The 2 bytes following the escape contain unsigned values
// indicating the horizontal and vertical offsets of the next pixel
// from the current position.
$colincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
$rowincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
$col = ($pixelcounter % $thisfile_bmp_header_raw['width']) + $colincrement;
$row = ($thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width'])) - $rowincrement;
$pixelcounter = ($row * $thisfile_bmp_header_raw['width']) + $col;
break;
default:
// In absolute mode, the first byte is zero and the second byte is a
// value in the range 03H through FFH. The second byte represents the
// number of bytes that follow, each of which contains the color index
// of a single pixel. Each run must be aligned on a word boundary.
for ($i = 0; $i < $secondbyte; $i++) {
$paletteindex = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
$col = $pixelcounter % $thisfile_bmp_header_raw['width'];
$row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']);
$thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
$pixelcounter++;
}
while (($pixeldataoffset % 2) != 0) {
// Each run must be aligned on a word boundary.
$pixeldataoffset++;
}
break;
}
} else {
// encoded mode - the first byte specifies the number of consecutive pixels
// to be drawn using the color index contained in the second byte.
for ($i = 0; $i < $firstbyte; $i++) {
$col = $pixelcounter % $thisfile_bmp_header_raw['width'];
$row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']);
$thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$secondbyte];
$pixelcounter++;
}
}
}
break;
default:
$ThisFileInfo['error'][] = 'Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data';
break;
}
break;
case 2: // BI_RLE4 - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_6x0u.asp
switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
case 4:
$pixelcounter = 0;
while ($pixeldataoffset < strlen($BMPpixelData)) {
$firstbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
$secondbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
if ($firstbyte == 0) {
// escaped/absolute mode - the first byte of the pair can be set to zero to
// indicate an escape character that denotes the end of a line, the end of
// a bitmap, or a delta, depending on the value of the second byte.
switch ($secondbyte) {
case 0:
// end of line
// no need for special processing, just ignore
break;
case 1:
// end of bitmap
$pixeldataoffset = strlen($BMPpixelData); // force to exit loop just in case
break;
case 2:
// delta - The 2 bytes following the escape contain unsigned values
// indicating the horizontal and vertical offsets of the next pixel
// from the current position.
$colincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
$rowincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
$col = ($pixelcounter % $thisfile_bmp_header_raw['width']) + $colincrement;
$row = ($thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width'])) - $rowincrement;
$pixelcounter = ($row * $thisfile_bmp_header_raw['width']) + $col;
break;
default:
// In absolute mode, the first byte is zero. The second byte contains the number
// of color indexes that follow. Subsequent bytes contain color indexes in their
// high- and low-order 4 bits, one color index for each pixel. In absolute mode,
// each run must be aligned on a word boundary.
unset($paletteindexes);
for ($i = 0; $i < ceil($secondbyte / 2); $i++) {
$paletteindexbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1));
$paletteindexes[] = ($paletteindexbyte & 0xF0) >> 4;
$paletteindexes[] = ($paletteindexbyte & 0x0F);
}
while (($pixeldataoffset % 2) != 0) {
// Each run must be aligned on a word boundary.
$pixeldataoffset++;
}
foreach ($paletteindexes as $paletteindex) {
$col = $pixelcounter % $thisfile_bmp_header_raw['width'];
$row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']);
$thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex];
$pixelcounter++;
}
break;
}
} else {
// encoded mode - the first byte of the pair contains the number of pixels to be
// drawn using the color indexes in the second byte. The second byte contains two
// color indexes, one in its high-order 4 bits and one in its low-order 4 bits.
// The first of the pixels is drawn using the color specified by the high-order
// 4 bits, the second is drawn using the color in the low-order 4 bits, the third
// is drawn using the color in the high-order 4 bits, and so on, until all the
// pixels specified by the first byte have been drawn.
$paletteindexes[0] = ($secondbyte & 0xF0) >> 4;
$paletteindexes[1] = ($secondbyte & 0x0F);
for ($i = 0; $i < $firstbyte; $i++) {
$col = $pixelcounter % $thisfile_bmp_header_raw['width'];
$row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']);
$thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindexes[($i % 2)]];
$pixelcounter++;
}
}
}
break;
default:
$ThisFileInfo['error'][] = 'Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data';
break;
}
break;
case 3: // BI_BITFIELDS
switch ($thisfile_bmp_header_raw['bits_per_pixel']) {
case 16:
case 32:
$redshift = 0;
$greenshift = 0;
$blueshift = 0;
while ((($thisfile_bmp_header_raw['red_mask'] >> $redshift) & 0x01) == 0) {
$redshift++;
}
while ((($thisfile_bmp_header_raw['green_mask'] >> $greenshift) & 0x01) == 0) {
$greenshift++;
}
while ((($thisfile_bmp_header_raw['blue_mask'] >> $blueshift) & 0x01) == 0) {
$blueshift++;
}
for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) {
for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) {
$pixelvalue = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset, $thisfile_bmp_header_raw['bits_per_pixel'] / 8));
$pixeldataoffset += $thisfile_bmp_header_raw['bits_per_pixel'] / 8;
$red = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['red_mask']) >> $redshift) / ($thisfile_bmp_header_raw['red_mask'] >> $redshift)) * 255));
$green = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['green_mask']) >> $greenshift) / ($thisfile_bmp_header_raw['green_mask'] >> $greenshift)) * 255));
$blue = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['blue_mask']) >> $blueshift) / ($thisfile_bmp_header_raw['blue_mask'] >> $blueshift)) * 255));
$thisfile_bmp['data'][$row][$col] = (($red << 16) | ($green << 8) | ($blue));
}
while (($pixeldataoffset % 4) != 0) {
// lines are padded to nearest DWORD
$pixeldataoffset++;
}
}
break;
default:
$ThisFileInfo['error'][] = 'Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data';
break;
}
break;
default: // unhandled compression type
$ThisFileInfo['error'][] = 'Unknown/unhandled compression type value ('.$thisfile_bmp_header_raw['compression'].') - cannot decompress pixel data';
break;
}
}
return true;
}
function PlotBMP(&$BMPinfo) {
$starttime = time();
if (!isset($BMPinfo['bmp']['data']) || !is_array($BMPinfo['bmp']['data'])) {
echo 'ERROR: no pixel data<BR>';
return false;
}
set_time_limit(intval(round($BMPinfo['resolution_x'] * $BMPinfo['resolution_y'] / 10000)));
if ($im = ImageCreateTrueColor($BMPinfo['resolution_x'], $BMPinfo['resolution_y'])) {
for ($row = 0; $row < $BMPinfo['resolution_y']; $row++) {
for ($col = 0; $col < $BMPinfo['resolution_x']; $col++) {
if (isset($BMPinfo['bmp']['data'][$row][$col])) {
$red = ($BMPinfo['bmp']['data'][$row][$col] & 0x00FF0000) >> 16;
$green = ($BMPinfo['bmp']['data'][$row][$col] & 0x0000FF00) >> 8;
$blue = ($BMPinfo['bmp']['data'][$row][$col] & 0x000000FF);
$pixelcolor = ImageColorAllocate($im, $red, $green, $blue);
ImageSetPixel($im, $col, $row, $pixelcolor);
} else {
//echo 'ERROR: no data for pixel '.$row.' x '.$col.'<BR>';
//return false;
}
}
}
if (headers_sent()) {
echo 'plotted '.($BMPinfo['resolution_x'] * $BMPinfo['resolution_y']).' pixels in '.(time() - $starttime).' seconds<BR>';
ImageDestroy($im);
exit;
} else {
header('Content-type: image/png');
ImagePNG($im);
ImageDestroy($im);
return true;
}
}
return false;
}
function BMPcompressionWindowsLookup($compressionid) {
static $BMPcompressionWindowsLookup = array(
0 => 'BI_RGB',
1 => 'BI_RLE8',
2 => 'BI_RLE4',
3 => 'BI_BITFIELDS',
4 => 'BI_JPEG',
5 => 'BI_PNG'
);
return (isset($BMPcompressionWindowsLookup[$compressionid]) ? $BMPcompressionWindowsLookup[$compressionid] : 'invalid');
}
function BMPcompressionOS2Lookup($compressionid) {
static $BMPcompressionOS2Lookup = array(
0 => 'BI_RGB',
1 => 'BI_RLE8',
2 => 'BI_RLE4',
3 => 'Huffman 1D',
4 => 'BI_RLE24',
);
return (isset($BMPcompressionOS2Lookup[$compressionid]) ? $BMPcompressionOS2Lookup[$compressionid] : 'invalid');
}
}
?>

View File

@ -1,183 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.graphic.gif.php //
// module for analyzing GIF Image files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_gif
{
function getid3_gif(&$fd, &$ThisFileInfo) {
$ThisFileInfo['fileformat'] = 'gif';
$ThisFileInfo['video']['dataformat'] = 'gif';
$ThisFileInfo['video']['lossless'] = true;
$ThisFileInfo['video']['pixel_aspect_ratio'] = (float) 1;
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$GIFheader = fread($fd, 13);
$offset = 0;
$ThisFileInfo['gif']['header']['raw']['identifier'] = substr($GIFheader, $offset, 3);
$offset += 3;
if ($ThisFileInfo['gif']['header']['raw']['identifier'] != 'GIF') {
$ThisFileInfo['error'][] = 'Expecting "GIF" at offset '.$ThisFileInfo['avdataoffset'].', found "'.$ThisFileInfo['gif']['header']['raw']['identifier'].'"';
unset($ThisFileInfo['fileformat']);
unset($ThisFileInfo['gif']);
return false;
}
$ThisFileInfo['gif']['header']['raw']['version'] = substr($GIFheader, $offset, 3);
$offset += 3;
$ThisFileInfo['gif']['header']['raw']['width'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 2));
$offset += 2;
$ThisFileInfo['gif']['header']['raw']['height'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 2));
$offset += 2;
$ThisFileInfo['gif']['header']['raw']['flags'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 1));
$offset += 1;
$ThisFileInfo['gif']['header']['raw']['bg_color_index'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 1));
$offset += 1;
$ThisFileInfo['gif']['header']['raw']['aspect_ratio'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 1));
$offset += 1;
$ThisFileInfo['video']['resolution_x'] = $ThisFileInfo['gif']['header']['raw']['width'];
$ThisFileInfo['video']['resolution_y'] = $ThisFileInfo['gif']['header']['raw']['height'];
$ThisFileInfo['gif']['version'] = $ThisFileInfo['gif']['header']['raw']['version'];
$ThisFileInfo['gif']['header']['flags']['global_color_table'] = (bool) ($ThisFileInfo['gif']['header']['raw']['flags'] & 0x80);
if ($ThisFileInfo['gif']['header']['raw']['flags'] & 0x80) {
// Number of bits per primary color available to the original image, minus 1
$ThisFileInfo['gif']['header']['bits_per_pixel'] = 3 * ((($ThisFileInfo['gif']['header']['raw']['flags'] & 0x70) >> 4) + 1);
} else {
$ThisFileInfo['gif']['header']['bits_per_pixel'] = 0;
}
$ThisFileInfo['gif']['header']['flags']['global_color_sorted'] = (bool) ($ThisFileInfo['gif']['header']['raw']['flags'] & 0x40);
if ($ThisFileInfo['gif']['header']['flags']['global_color_table']) {
// the number of bytes contained in the Global Color Table. To determine that
// actual size of the color table, raise 2 to [the value of the field + 1]
$ThisFileInfo['gif']['header']['global_color_size'] = pow(2, ($ThisFileInfo['gif']['header']['raw']['flags'] & 0x07) + 1);
$ThisFileInfo['video']['bits_per_sample'] = ($ThisFileInfo['gif']['header']['raw']['flags'] & 0x07) + 1;
} else {
$ThisFileInfo['gif']['header']['global_color_size'] = 0;
}
if ($ThisFileInfo['gif']['header']['raw']['aspect_ratio'] != 0) {
// Aspect Ratio = (Pixel Aspect Ratio + 15) / 64
$ThisFileInfo['gif']['header']['aspect_ratio'] = ($ThisFileInfo['gif']['header']['raw']['aspect_ratio'] + 15) / 64;
}
// if ($ThisFileInfo['gif']['header']['flags']['global_color_table']) {
// $GIFcolorTable = fread($fd, 3 * $ThisFileInfo['gif']['header']['global_color_size']);
// $offset = 0;
// for ($i = 0; $i < $ThisFileInfo['gif']['header']['global_color_size']; $i++) {
// $red = getid3_lib::LittleEndian2Int(substr($GIFcolorTable, $offset++, 1));
// $green = getid3_lib::LittleEndian2Int(substr($GIFcolorTable, $offset++, 1));
// $blue = getid3_lib::LittleEndian2Int(substr($GIFcolorTable, $offset++, 1));
// $ThisFileInfo['gif']['global_color_table'][$i] = (($red << 16) | ($green << 8) | ($blue));
// }
// }
//
// // Image Descriptor
// while (!feof($fd)) {
// $NextBlockTest = fread($fd, 1);
// switch ($NextBlockTest) {
//
// case ',': // ',' - Image separator character
//
// $ImageDescriptorData = $NextBlockTest.fread($fd, 9);
// $ImageDescriptor = array();
// $ImageDescriptor['image_left'] = getid3_lib::LittleEndian2Int(substr($ImageDescriptorData, 1, 2));
// $ImageDescriptor['image_top'] = getid3_lib::LittleEndian2Int(substr($ImageDescriptorData, 3, 2));
// $ImageDescriptor['image_width'] = getid3_lib::LittleEndian2Int(substr($ImageDescriptorData, 5, 2));
// $ImageDescriptor['image_height'] = getid3_lib::LittleEndian2Int(substr($ImageDescriptorData, 7, 2));
// $ImageDescriptor['flags_raw'] = getid3_lib::LittleEndian2Int(substr($ImageDescriptorData, 9, 1));
// $ImageDescriptor['flags']['use_local_color_map'] = (bool) ($ImageDescriptor['flags_raw'] & 0x80);
// $ImageDescriptor['flags']['image_interlaced'] = (bool) ($ImageDescriptor['flags_raw'] & 0x40);
// $ThisFileInfo['gif']['image_descriptor'][] = $ImageDescriptor;
//
// if ($ImageDescriptor['flags']['use_local_color_map']) {
//
// $ThisFileInfo['warning'][] = 'This version of getID3() cannot parse local color maps for GIFs';
// return true;
//
// }
//echo 'Start of raster data: '.ftell($fd).'<BR>';
// $RasterData = array();
// $RasterData['code_size'] = getid3_lib::LittleEndian2Int(fread($fd, 1));
// $RasterData['block_byte_count'] = getid3_lib::LittleEndian2Int(fread($fd, 1));
// $ThisFileInfo['gif']['raster_data'][count($ThisFileInfo['gif']['image_descriptor']) - 1] = $RasterData;
//
// $CurrentCodeSize = $RasterData['code_size'] + 1;
// for ($i = 0; $i < pow(2, $RasterData['code_size']); $i++) {
// $DefaultDataLookupTable[$i] = chr($i);
// }
// $DefaultDataLookupTable[pow(2, $RasterData['code_size']) + 0] = ''; // Clear Code
// $DefaultDataLookupTable[pow(2, $RasterData['code_size']) + 1] = ''; // End Of Image Code
//
//
// $NextValue = $this->GetLSBits($fd, $CurrentCodeSize);
// echo 'Clear Code: '.$NextValue.'<BR>';
//
// $NextValue = $this->GetLSBits($fd, $CurrentCodeSize);
// echo 'First Color: '.$NextValue.'<BR>';
//
// $Prefix = $NextValue;
//$i = 0;
// while ($i++ < 20) {
// $NextValue = $this->GetLSBits($fd, $CurrentCodeSize);
// echo $NextValue.'<BR>';
// }
//return true;
// break;
//
// case '!':
// // GIF Extension Block
// $ExtensionBlockData = $NextBlockTest.fread($fd, 2);
// $ExtensionBlock = array();
// $ExtensionBlock['function_code'] = getid3_lib::LittleEndian2Int(substr($ExtensionBlockData, 1, 1));
// $ExtensionBlock['byte_length'] = getid3_lib::LittleEndian2Int(substr($ExtensionBlockData, 2, 1));
// $ExtensionBlock['data'] = fread($fd, $ExtensionBlock['byte_length']);
// $ThisFileInfo['gif']['extension_blocks'][] = $ExtensionBlock;
// break;
//
// case ';':
// $ThisFileInfo['gif']['terminator_offset'] = ftell($fd) - 1;
// // GIF Terminator
// break;
//
// default:
// break;
//
//
// }
// }
return true;
}
function GetLSBits($fd, $bits) {
static $bitbuffer = '';
while (strlen($bitbuffer) < $bits) {
//echo 'Read another byte: '.ftell($fd).'<BR>';
$bitbuffer = str_pad(decbin(ord(fread($fd, 1))), 8, '0', STR_PAD_LEFT).$bitbuffer;
}
$value = bindec(substr($bitbuffer, 0 - $bits));
$bitbuffer = substr($bitbuffer, 0, 0 - $bits);
return $value;
}
}
?>

View File

@ -1,249 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.graphic.jpg.php //
// module for analyzing JPEG Image files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_jpg
{
function getid3_jpg(&$fd, &$ThisFileInfo) {
$ThisFileInfo['fileformat'] = 'jpg';
$ThisFileInfo['video']['dataformat'] = 'jpg';
$ThisFileInfo['video']['lossless'] = false;
$ThisFileInfo['video']['bits_per_sample'] = 24;
$ThisFileInfo['video']['pixel_aspect_ratio'] = (float) 1;
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$imageinfo = array();
list($width, $height, $type) = getid3_lib::GetDataImageSize(fread($fd, $ThisFileInfo['filesize']), $imageinfo);
if (isset($imageinfo['APP13'])) {
// http://php.net/iptcparse
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/IPTC.html
$iptc_parsed = iptcparse($imageinfo['APP13']);
if (is_array($iptc_parsed)) {
foreach ($iptc_parsed as $iptc_key_raw => $iptc_values) {
list($iptc_record, $iptc_tagkey) = explode('#', $iptc_key_raw);
$iptc_tagkey = intval(ltrim($iptc_tagkey, '0'));
foreach ($iptc_values as $key => $value) {
@$ThisFileInfo['iptc'][$this->IPTCrecordName($iptc_record)][$this->IPTCrecordTagName($iptc_record, $iptc_tagkey)][] = $value;
}
}
}
//echo '<pre>'.htmlentities(print_r($iptc_parsed, true)).'</pre>';
}
switch ($type) {
case 2: // JPEG
$ThisFileInfo['video']['resolution_x'] = $width;
$ThisFileInfo['video']['resolution_y'] = $height;
if (version_compare(phpversion(), '4.2.0', '>=')) {
if (function_exists('exif_read_data')) {
ob_start();
$ThisFileInfo['jpg']['exif'] = exif_read_data($ThisFileInfo['filenamepath'], '', true, false);
$errors = ob_get_contents();
if ($errors) {
$ThisFileInfo['warning'][] = strip_tags($errors);
unset($ThisFileInfo['jpg']['exif']);
}
ob_end_clean();
} else {
$ThisFileInfo['warning'][] = 'EXIF parsing only available when '.(GETID3_OS_ISWINDOWS ? 'php_exif.dll enabled' : 'compiled with --enable-exif');
}
} else {
$ThisFileInfo['warning'][] = 'EXIF parsing only available in PHP v4.2.0 and higher compiled with --enable-exif (or php_exif.dll enabled for Windows). You are using PHP v'.phpversion();
}
return true;
break;
default:
break;
}
unset($ThisFileInfo['fileformat']);
return false;
}
function IPTCrecordName($iptc_record) {
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/IPTC.html
static $IPTCrecordName = array();
if (empty($IPTCrecordName)) {
$IPTCrecordName = array(
1 => 'IPTCEnvelope',
2 => 'IPTCApplication',
3 => 'IPTCNewsPhoto',
7 => 'IPTCPreObjectData',
8 => 'IPTCObjectData',
9 => 'IPTCPostObjectData',
);
}
return (isset($IPTCrecordName[$iptc_record]) ? $IPTCrecordName[$iptc_record] : '');
}
function IPTCrecordTagName($iptc_record, $iptc_tagkey) {
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/IPTC.html
static $IPTCrecordTagName = array();
if (empty($IPTCrecordTagName)) {
$IPTCrecordTagName = array(
1 => array( // IPTC EnvelopeRecord Tags
0 => 'EnvelopeRecordVersion',
5 => 'Destination',
20 => 'FileFormat',
22 => 'FileVersion',
30 => 'ServiceIdentifier',
40 => 'EnvelopeNumber',
50 => 'ProductID',
60 => 'EnvelopePriority',
70 => 'DateSent',
80 => 'TimeSent',
90 => 'CodedCharacterSet',
100 => 'UniqueObjectName',
120 => 'ARMIdentifier',
122 => 'ARMVersion',
),
2 => array( // IPTC ApplicationRecord Tags
0 => 'ApplicationRecordVersion',
3 => 'ObjectTypeReference',
4 => 'ObjectAttributeReference',
5 => 'ObjectName',
7 => 'EditStatus',
8 => 'EditorialUpdate',
10 => 'Urgency',
12 => 'SubjectReference',
15 => 'Category',
20 => 'SupplementalCategories',
22 => 'FixtureIdentifier',
25 => 'Keywords',
26 => 'ContentLocationCode',
27 => 'ContentLocationName',
30 => 'ReleaseDate',
35 => 'ReleaseTime',
37 => 'ExpirationDate',
38 => 'ExpirationTime',
40 => 'SpecialInstructions',
42 => 'ActionAdvised',
45 => 'ReferenceService',
47 => 'ReferenceDate',
50 => 'ReferenceNumber',
55 => 'DateCreated',
60 => 'TimeCreated',
62 => 'DigitalCreationDate',
63 => 'DigitalCreationTime',
65 => 'OriginatingProgram',
70 => 'ProgramVersion',
75 => 'ObjectCycle',
80 => 'By-line',
85 => 'By-lineTitle',
90 => 'City',
92 => 'Sub-location',
95 => 'Province-State',
100 => 'Country-PrimaryLocationCode',
101 => 'Country-PrimaryLocationName',
103 => 'OriginalTransmissionReference',
105 => 'Headline',
110 => 'Credit',
115 => 'Source',
116 => 'CopyrightNotice',
118 => 'Contact',
120 => 'Caption-Abstract',
121 => 'LocalCaption',
122 => 'Writer-Editor',
125 => 'RasterizedCaption',
130 => 'ImageType',
131 => 'ImageOrientation',
135 => 'LanguageIdentifier',
150 => 'AudioType',
151 => 'AudioSamplingRate',
152 => 'AudioSamplingResolution',
153 => 'AudioDuration',
154 => 'AudioOutcue',
184 => 'JobID',
185 => 'MasterDocumentID',
186 => 'ShortDocumentID',
187 => 'UniqueDocumentID',
188 => 'OwnerID',
200 => 'ObjectPreviewFileFormat',
201 => 'ObjectPreviewFileVersion',
202 => 'ObjectPreviewData',
221 => 'Prefs',
225 => 'ClassifyState',
228 => 'SimilarityIndex',
230 => 'DocumentNotes',
231 => 'DocumentHistory',
232 => 'ExifCameraInfo',
),
3 => array( // IPTC NewsPhoto Tags
0 => 'NewsPhotoVersion',
10 => 'IPTCPictureNumber',
20 => 'IPTCImageWidth',
30 => 'IPTCImageHeight',
40 => 'IPTCPixelWidth',
50 => 'IPTCPixelHeight',
55 => 'SupplementalType',
60 => 'ColorRepresentation',
64 => 'InterchangeColorSpace',
65 => 'ColorSequence',
66 => 'ICC_Profile',
70 => 'ColorCalibrationMatrix',
80 => 'LookupTable',
84 => 'NumIndexEntries',
85 => 'ColorPalette',
86 => 'IPTCBitsPerSample',
90 => 'SampleStructure',
100 => 'ScanningDirection',
102 => 'IPTCImageRotation',
110 => 'DataCompressionMethod',
120 => 'QuantizationMethod',
125 => 'EndPoints',
130 => 'ExcursionTolerance',
135 => 'BitsPerComponent',
140 => 'MaximumDensityRange',
145 => 'GammaCompensatedValue',
),
7 => array( // IPTC PreObjectData Tags
10 => 'SizeMode',
20 => 'MaxSubfileSize',
90 => 'ObjectSizeAnnounced',
95 => 'MaximumObjectSize',
),
8 => array( // IPTC ObjectData Tags
10 => 'SubFile',
),
9 => array( // IPTC PostObjectData Tags
10 => 'ConfirmedObjectSize',
),
);
}
return (isset($IPTCrecordTagName[$iptc_record][$iptc_tagkey]) ? $IPTCrecordTagName[$iptc_record][$iptc_tagkey] : $iptc_tagkey);
}
}
?>

View File

@ -1,130 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.graphic.pcd.php //
// module for analyzing PhotoCD (PCD) Image files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_pcd
{
function getid3_pcd(&$fd, &$ThisFileInfo, $ExtractData=0) {
$ThisFileInfo['fileformat'] = 'pcd';
$ThisFileInfo['video']['dataformat'] = 'pcd';
$ThisFileInfo['video']['lossless'] = false;
fseek($fd, $ThisFileInfo['avdataoffset'] + 72, SEEK_SET);
$PCDflags = fread($fd, 1);
$PCDisVertical = ((ord($PCDflags) & 0x01) ? true : false);
if ($PCDisVertical) {
$ThisFileInfo['video']['resolution_x'] = 3072;
$ThisFileInfo['video']['resolution_y'] = 2048;
} else {
$ThisFileInfo['video']['resolution_x'] = 2048;
$ThisFileInfo['video']['resolution_y'] = 3072;
}
if ($ExtractData > 3) {
$ThisFileInfo['error'][] = 'Cannot extract PSD image data for detail levels above BASE (3)';
} elseif ($ExtractData > 0) {
$PCD_levels[1] = array( 192, 128, 0x02000); // BASE/16
$PCD_levels[2] = array( 384, 256, 0x0B800); // BASE/4
$PCD_levels[3] = array( 768, 512, 0x30000); // BASE
//$PCD_levels[4] = array(1536, 1024, ??); // BASE*4 - encrypted with Kodak-proprietary compression/encryption
//$PCD_levels[5] = array(3072, 2048, ??); // BASE*16 - encrypted with Kodak-proprietary compression/encryption
//$PCD_levels[6] = array(6144, 4096, ??); // BASE*64 - encrypted with Kodak-proprietary compression/encryption; PhotoCD-Pro only
list($PCD_width, $PCD_height, $PCD_dataOffset) = $PCD_levels[3];
fseek($fd, $ThisFileInfo['avdataoffset'] + $PCD_dataOffset, SEEK_SET);
for ($y = 0; $y < $PCD_height; $y += 2) {
// The image-data of these subtypes start at the respective offsets of 02000h, 0b800h and 30000h.
// To decode the YcbYr to the more usual RGB-code, three lines of data have to be read, each
// consisting of w bytes, where w is the width of the image-subtype. The first w bytes and
// the first half of the third w bytes contain data for the first RGB-line, the second w bytes
// and the second half of the third w bytes contain data for a second RGB-line.
$PCD_data_Y1 = fread($fd, $PCD_width);
$PCD_data_Y2 = fread($fd, $PCD_width);
$PCD_data_Cb = fread($fd, intval(round($PCD_width / 2)));
$PCD_data_Cr = fread($fd, intval(round($PCD_width / 2)));
for ($x = 0; $x < $PCD_width; $x++) {
if ($PCDisVertical) {
$ThisFileInfo['pcd']['data'][$PCD_width - $x][$y] = $this->YCbCr2RGB(ord($PCD_data_Y1{$x}), ord($PCD_data_Cb{floor($x / 2)}), ord($PCD_data_Cr{floor($x / 2)}));
$ThisFileInfo['pcd']['data'][$PCD_width - $x][$y + 1] = $this->YCbCr2RGB(ord($PCD_data_Y2{$x}), ord($PCD_data_Cb{floor($x / 2)}), ord($PCD_data_Cr{floor($x / 2)}));
} else {
$ThisFileInfo['pcd']['data'][$y][$x] = $this->YCbCr2RGB(ord($PCD_data_Y1{$x}), ord($PCD_data_Cb{floor($x / 2)}), ord($PCD_data_Cr{floor($x / 2)}));
$ThisFileInfo['pcd']['data'][$y + 1][$x] = $this->YCbCr2RGB(ord($PCD_data_Y2{$x}), ord($PCD_data_Cb{floor($x / 2)}), ord($PCD_data_Cr{floor($x / 2)}));
}
}
}
// Example for plotting extracted data
//getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ac3.php', __FILE__, true);
//if ($PCDisVertical) {
// $BMPinfo['resolution_x'] = $PCD_height;
// $BMPinfo['resolution_y'] = $PCD_width;
//} else {
// $BMPinfo['resolution_x'] = $PCD_width;
// $BMPinfo['resolution_y'] = $PCD_height;
//}
//$BMPinfo['bmp']['data'] = $ThisFileInfo['pcd']['data'];
//getid3_bmp::PlotBMP($BMPinfo);
//exit;
}
}
function YCbCr2RGB($Y, $Cb, $Cr) {
static $YCbCr_constants = array();
if (empty($YCbCr_constants)) {
$YCbCr_constants['red']['Y'] = 0.0054980 * 256;
$YCbCr_constants['red']['Cb'] = 0.0000000 * 256;
$YCbCr_constants['red']['Cr'] = 0.0051681 * 256;
$YCbCr_constants['green']['Y'] = 0.0054980 * 256;
$YCbCr_constants['green']['Cb'] = -0.0015446 * 256;
$YCbCr_constants['green']['Cr'] = -0.0026325 * 256;
$YCbCr_constants['blue']['Y'] = 0.0054980 * 256;
$YCbCr_constants['blue']['Cb'] = 0.0079533 * 256;
$YCbCr_constants['blue']['Cr'] = 0.0000000 * 256;
}
$RGBcolor = array('red'=>0, 'green'=>0, 'blue'=>0);
foreach ($RGBcolor as $rgbname => $dummy) {
$RGBcolor[$rgbname] = max(0,
min(255,
intval(
round(
($YCbCr_constants[$rgbname]['Y'] * $Y) +
($YCbCr_constants[$rgbname]['Cb'] * ($Cb - 156)) +
($YCbCr_constants[$rgbname]['Cr'] * ($Cr - 137))
)
)
)
);
}
return (($RGBcolor['red'] * 65536) + ($RGBcolor['green'] * 256) + $RGBcolor['blue']);
}
}
?>

View File

@ -1,519 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.graphic.png.php //
// module for analyzing PNG Image files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_png
{
function getid3_png(&$fd, &$ThisFileInfo) {
// shortcut
$ThisFileInfo['png'] = array();
$thisfile_png = &$ThisFileInfo['png'];
$ThisFileInfo['fileformat'] = 'png';
$ThisFileInfo['video']['dataformat'] = 'png';
$ThisFileInfo['video']['lossless'] = false;
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$PNGfiledata = fread($fd, GETID3_FREAD_BUFFER_SIZE);
$offset = 0;
$PNGidentifier = substr($PNGfiledata, $offset, 8); // $89 $50 $4E $47 $0D $0A $1A $0A
$offset += 8;
if ($PNGidentifier != "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A") {
$ThisFileInfo['error'][] = 'First 8 bytes of file ('.getid3_lib::PrintHexBytes($PNGidentifier).') did not match expected PNG identifier';
unset($ThisFileInfo['fileformat']);
return false;
}
while (((ftell($fd) - (strlen($PNGfiledata) - $offset)) < $ThisFileInfo['filesize'])) {
$chunk['data_length'] = getid3_lib::BigEndian2Int(substr($PNGfiledata, $offset, 4));
$offset += 4;
while (((strlen($PNGfiledata) - $offset) < ($chunk['data_length'] + 4)) && (ftell($fd) < $ThisFileInfo['filesize'])) {
$PNGfiledata .= fread($fd, GETID3_FREAD_BUFFER_SIZE);
}
$chunk['type_text'] = substr($PNGfiledata, $offset, 4);
$offset += 4;
$chunk['type_raw'] = getid3_lib::BigEndian2Int($chunk['type_text']);
$chunk['data'] = substr($PNGfiledata, $offset, $chunk['data_length']);
$offset += $chunk['data_length'];
$chunk['crc'] = getid3_lib::BigEndian2Int(substr($PNGfiledata, $offset, 4));
$offset += 4;
$chunk['flags']['ancilliary'] = (bool) ($chunk['type_raw'] & 0x20000000);
$chunk['flags']['private'] = (bool) ($chunk['type_raw'] & 0x00200000);
$chunk['flags']['reserved'] = (bool) ($chunk['type_raw'] & 0x00002000);
$chunk['flags']['safe_to_copy'] = (bool) ($chunk['type_raw'] & 0x00000020);
// shortcut
$thisfile_png[$chunk['type_text']] = array();
$thisfile_png_chunk_type_text = &$thisfile_png[$chunk['type_text']];
switch ($chunk['type_text']) {
case 'IHDR': // Image Header
$thisfile_png_chunk_type_text['header'] = $chunk;
$thisfile_png_chunk_type_text['width'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 4));
$thisfile_png_chunk_type_text['height'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 4));
$thisfile_png_chunk_type_text['raw']['bit_depth'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 8, 1));
$thisfile_png_chunk_type_text['raw']['color_type'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 9, 1));
$thisfile_png_chunk_type_text['raw']['compression_method'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 10, 1));
$thisfile_png_chunk_type_text['raw']['filter_method'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 11, 1));
$thisfile_png_chunk_type_text['raw']['interlace_method'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 12, 1));
$thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['raw']['compression_method']);
$thisfile_png_chunk_type_text['color_type']['palette'] = (bool) ($thisfile_png_chunk_type_text['raw']['color_type'] & 0x01);
$thisfile_png_chunk_type_text['color_type']['true_color'] = (bool) ($thisfile_png_chunk_type_text['raw']['color_type'] & 0x02);
$thisfile_png_chunk_type_text['color_type']['alpha'] = (bool) ($thisfile_png_chunk_type_text['raw']['color_type'] & 0x04);
$ThisFileInfo['video']['resolution_x'] = $thisfile_png_chunk_type_text['width'];
$ThisFileInfo['video']['resolution_y'] = $thisfile_png_chunk_type_text['height'];
$ThisFileInfo['video']['bits_per_sample'] = $this->IHDRcalculateBitsPerSample($thisfile_png_chunk_type_text['raw']['color_type'], $thisfile_png_chunk_type_text['raw']['bit_depth']);
break;
case 'PLTE': // Palette
$thisfile_png_chunk_type_text['header'] = $chunk;
$paletteoffset = 0;
for ($i = 0; $i <= 255; $i++) {
//$thisfile_png_chunk_type_text['red'][$i] = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
//$thisfile_png_chunk_type_text['green'][$i] = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
//$thisfile_png_chunk_type_text['blue'][$i] = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
$red = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
$green = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
$blue = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
$thisfile_png_chunk_type_text[$i] = (($red << 16) | ($green << 8) | ($blue));
}
break;
case 'tRNS': // Transparency
$thisfile_png_chunk_type_text['header'] = $chunk;
switch ($thisfile_png['IHDR']['raw']['color_type']) {
case 0:
$thisfile_png_chunk_type_text['transparent_color_gray'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 2));
break;
case 2:
$thisfile_png_chunk_type_text['transparent_color_red'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 2));
$thisfile_png_chunk_type_text['transparent_color_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 2));
$thisfile_png_chunk_type_text['transparent_color_blue'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 2));
break;
case 3:
for ($i = 0; $i < strlen($chunk['data']); $i++) {
$thisfile_png_chunk_type_text['palette_opacity'][$i] = getid3_lib::BigEndian2Int(substr($chunk['data'], $i, 1));
}
break;
case 4:
case 6:
$ThisFileInfo['error'][] = 'Invalid color_type in tRNS chunk: '.$thisfile_png['IHDR']['raw']['color_type'];
default:
$ThisFileInfo['warning'][] = 'Unhandled color_type in tRNS chunk: '.$thisfile_png['IHDR']['raw']['color_type'];
break;
}
break;
case 'gAMA': // Image Gamma
$thisfile_png_chunk_type_text['header'] = $chunk;
$thisfile_png_chunk_type_text['gamma'] = getid3_lib::BigEndian2Int($chunk['data']) / 100000;
break;
case 'cHRM': // Primary Chromaticities
$thisfile_png_chunk_type_text['header'] = $chunk;
$thisfile_png_chunk_type_text['white_x'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 4)) / 100000;
$thisfile_png_chunk_type_text['white_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 4)) / 100000;
$thisfile_png_chunk_type_text['red_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 8, 4)) / 100000;
$thisfile_png_chunk_type_text['red_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 12, 4)) / 100000;
$thisfile_png_chunk_type_text['green_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 16, 4)) / 100000;
$thisfile_png_chunk_type_text['green_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 20, 4)) / 100000;
$thisfile_png_chunk_type_text['blue_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 24, 4)) / 100000;
$thisfile_png_chunk_type_text['blue_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 28, 4)) / 100000;
break;
case 'sRGB': // Standard RGB Color Space
$thisfile_png_chunk_type_text['header'] = $chunk;
$thisfile_png_chunk_type_text['reindering_intent'] = getid3_lib::BigEndian2Int($chunk['data']);
$thisfile_png_chunk_type_text['reindering_intent_text'] = $this->PNGsRGBintentLookup($thisfile_png_chunk_type_text['reindering_intent']);
break;
case 'iCCP': // Embedded ICC Profile
$thisfile_png_chunk_type_text['header'] = $chunk;
list($profilename, $compressiondata) = explode("\x00", $chunk['data'], 2);
$thisfile_png_chunk_type_text['profile_name'] = $profilename;
$thisfile_png_chunk_type_text['compression_method'] = getid3_lib::BigEndian2Int(substr($compressiondata, 0, 1));
$thisfile_png_chunk_type_text['compression_profile'] = substr($compressiondata, 1);
$thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['compression_method']);
break;
case 'tEXt': // Textual Data
$thisfile_png_chunk_type_text['header'] = $chunk;
list($keyword, $text) = explode("\x00", $chunk['data'], 2);
$thisfile_png_chunk_type_text['keyword'] = $keyword;
$thisfile_png_chunk_type_text['text'] = $text;
$thisfile_png['comments'][$thisfile_png_chunk_type_text['keyword']][] = $thisfile_png_chunk_type_text['text'];
break;
case 'zTXt': // Compressed Textual Data
$thisfile_png_chunk_type_text['header'] = $chunk;
list($keyword, $otherdata) = explode("\x00", $chunk['data'], 2);
$thisfile_png_chunk_type_text['keyword'] = $keyword;
$thisfile_png_chunk_type_text['compression_method'] = getid3_lib::BigEndian2Int(substr($otherdata, 0, 1));
$thisfile_png_chunk_type_text['compressed_text'] = substr($otherdata, 1);
$thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['compression_method']);
switch ($thisfile_png_chunk_type_text['compression_method']) {
case 0:
$thisfile_png_chunk_type_text['text'] = gzuncompress($thisfile_png_chunk_type_text['compressed_text']);
break;
default:
// unknown compression method
break;
}
if (isset($thisfile_png_chunk_type_text['text'])) {
$thisfile_png['comments'][$thisfile_png_chunk_type_text['keyword']][] = $thisfile_png_chunk_type_text['text'];
}
break;
case 'iTXt': // International Textual Data
$thisfile_png_chunk_type_text['header'] = $chunk;
list($keyword, $otherdata) = explode("\x00", $chunk['data'], 2);
$thisfile_png_chunk_type_text['keyword'] = $keyword;
$thisfile_png_chunk_type_text['compression'] = (bool) getid3_lib::BigEndian2Int(substr($otherdata, 0, 1));
$thisfile_png_chunk_type_text['compression_method'] = getid3_lib::BigEndian2Int(substr($otherdata, 1, 1));
$thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['compression_method']);
list($languagetag, $translatedkeyword, $text) = explode("\x00", substr($otherdata, 2), 3);
$thisfile_png_chunk_type_text['language_tag'] = $languagetag;
$thisfile_png_chunk_type_text['translated_keyword'] = $translatedkeyword;
if ($thisfile_png_chunk_type_text['compression']) {
switch ($thisfile_png_chunk_type_text['compression_method']) {
case 0:
$thisfile_png_chunk_type_text['text'] = gzuncompress($text);
break;
default:
// unknown compression method
break;
}
} else {
$thisfile_png_chunk_type_text['text'] = $text;
}
if (isset($thisfile_png_chunk_type_text['text'])) {
$thisfile_png['comments'][$thisfile_png_chunk_type_text['keyword']][] = $thisfile_png_chunk_type_text['text'];
}
break;
case 'bKGD': // Background Color
$thisfile_png_chunk_type_text['header'] = $chunk;
switch ($thisfile_png['IHDR']['raw']['color_type']) {
case 0:
case 4:
$thisfile_png_chunk_type_text['background_gray'] = getid3_lib::BigEndian2Int($chunk['data']);
break;
case 2:
case 6:
$thisfile_png_chunk_type_text['background_red'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0 * $thisfile_png['IHDR']['raw']['bit_depth'], $thisfile_png['IHDR']['raw']['bit_depth']));
$thisfile_png_chunk_type_text['background_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1 * $thisfile_png['IHDR']['raw']['bit_depth'], $thisfile_png['IHDR']['raw']['bit_depth']));
$thisfile_png_chunk_type_text['background_blue'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2 * $thisfile_png['IHDR']['raw']['bit_depth'], $thisfile_png['IHDR']['raw']['bit_depth']));
break;
case 3:
$thisfile_png_chunk_type_text['background_index'] = getid3_lib::BigEndian2Int($chunk['data']);
break;
default:
break;
}
break;
case 'pHYs': // Physical Pixel Dimensions
$thisfile_png_chunk_type_text['header'] = $chunk;
$thisfile_png_chunk_type_text['pixels_per_unit_x'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 4));
$thisfile_png_chunk_type_text['pixels_per_unit_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 4));
$thisfile_png_chunk_type_text['unit_specifier'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 8, 1));
$thisfile_png_chunk_type_text['unit'] = $this->PNGpHYsUnitLookup($thisfile_png_chunk_type_text['unit_specifier']);
break;
case 'sBIT': // Significant Bits
$thisfile_png_chunk_type_text['header'] = $chunk;
switch ($thisfile_png['IHDR']['raw']['color_type']) {
case 0:
$thisfile_png_chunk_type_text['significant_bits_gray'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1));
break;
case 2:
case 3:
$thisfile_png_chunk_type_text['significant_bits_red'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1));
$thisfile_png_chunk_type_text['significant_bits_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1, 1));
$thisfile_png_chunk_type_text['significant_bits_blue'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 1));
break;
case 4:
$thisfile_png_chunk_type_text['significant_bits_gray'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1));
$thisfile_png_chunk_type_text['significant_bits_alpha'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1, 1));
break;
case 6:
$thisfile_png_chunk_type_text['significant_bits_red'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1));
$thisfile_png_chunk_type_text['significant_bits_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1, 1));
$thisfile_png_chunk_type_text['significant_bits_blue'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 1));
$thisfile_png_chunk_type_text['significant_bits_alpha'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 3, 1));
break;
default:
break;
}
break;
case 'sPLT': // Suggested Palette
$thisfile_png_chunk_type_text['header'] = $chunk;
list($palettename, $otherdata) = explode("\x00", $chunk['data'], 2);
$thisfile_png_chunk_type_text['palette_name'] = $palettename;
$sPLToffset = 0;
$thisfile_png_chunk_type_text['sample_depth_bits'] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, 1));
$sPLToffset += 1;
$thisfile_png_chunk_type_text['sample_depth_bytes'] = $thisfile_png_chunk_type_text['sample_depth_bits'] / 8;
$paletteCounter = 0;
while ($sPLToffset < strlen($otherdata)) {
$thisfile_png_chunk_type_text['red'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes']));
$sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes'];
$thisfile_png_chunk_type_text['green'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes']));
$sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes'];
$thisfile_png_chunk_type_text['blue'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes']));
$sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes'];
$thisfile_png_chunk_type_text['alpha'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes']));
$sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes'];
$thisfile_png_chunk_type_text['frequency'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, 2));
$sPLToffset += 2;
$paletteCounter++;
}
break;
case 'hIST': // Palette Histogram
$thisfile_png_chunk_type_text['header'] = $chunk;
$hISTcounter = 0;
while ($hISTcounter < strlen($chunk['data'])) {
$thisfile_png_chunk_type_text[$hISTcounter] = getid3_lib::BigEndian2Int(substr($chunk['data'], $hISTcounter / 2, 2));
$hISTcounter += 2;
}
break;
case 'tIME': // Image Last-Modification Time
$thisfile_png_chunk_type_text['header'] = $chunk;
$thisfile_png_chunk_type_text['year'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 2));
$thisfile_png_chunk_type_text['month'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 1));
$thisfile_png_chunk_type_text['day'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 3, 1));
$thisfile_png_chunk_type_text['hour'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 1));
$thisfile_png_chunk_type_text['minute'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 5, 1));
$thisfile_png_chunk_type_text['second'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 6, 1));
$thisfile_png_chunk_type_text['unix'] = gmmktime($thisfile_png_chunk_type_text['hour'], $thisfile_png_chunk_type_text['minute'], $thisfile_png_chunk_type_text['second'], $thisfile_png_chunk_type_text['month'], $thisfile_png_chunk_type_text['day'], $thisfile_png_chunk_type_text['year']);
break;
case 'oFFs': // Image Offset
$thisfile_png_chunk_type_text['header'] = $chunk;
$thisfile_png_chunk_type_text['position_x'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 4), false, true);
$thisfile_png_chunk_type_text['position_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 4), false, true);
$thisfile_png_chunk_type_text['unit_specifier'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 8, 1));
$thisfile_png_chunk_type_text['unit'] = $this->PNGoFFsUnitLookup($thisfile_png_chunk_type_text['unit_specifier']);
break;
case 'pCAL': // Calibration Of Pixel Values
$thisfile_png_chunk_type_text['header'] = $chunk;
list($calibrationname, $otherdata) = explode("\x00", $chunk['data'], 2);
$thisfile_png_chunk_type_text['calibration_name'] = $calibrationname;
$pCALoffset = 0;
$thisfile_png_chunk_type_text['original_zero'] = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset, 4), false, true);
$pCALoffset += 4;
$thisfile_png_chunk_type_text['original_max'] = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset, 4), false, true);
$pCALoffset += 4;
$thisfile_png_chunk_type_text['equation_type'] = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset, 1));
$pCALoffset += 1;
$thisfile_png_chunk_type_text['equation_type_text'] = $this->PNGpCALequationTypeLookup($thisfile_png_chunk_type_text['equation_type']);
$thisfile_png_chunk_type_text['parameter_count'] = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset, 1));
$pCALoffset += 1;
$thisfile_png_chunk_type_text['parameters'] = explode("\x00", substr($chunk['data'], $pCALoffset));
break;
case 'sCAL': // Physical Scale Of Image Subject
$thisfile_png_chunk_type_text['header'] = $chunk;
$thisfile_png_chunk_type_text['unit_specifier'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1));
$thisfile_png_chunk_type_text['unit'] = $this->PNGsCALUnitLookup($thisfile_png_chunk_type_text['unit_specifier']);
list($pixelwidth, $pixelheight) = explode("\x00", substr($chunk['data'], 1));
$thisfile_png_chunk_type_text['pixel_width'] = $pixelwidth;
$thisfile_png_chunk_type_text['pixel_height'] = $pixelheight;
break;
case 'gIFg': // GIF Graphic Control Extension
$gIFgCounter = 0;
if (isset($thisfile_png_chunk_type_text) && is_array($thisfile_png_chunk_type_text)) {
$gIFgCounter = count($thisfile_png_chunk_type_text);
}
$thisfile_png_chunk_type_text[$gIFgCounter]['header'] = $chunk;
$thisfile_png_chunk_type_text[$gIFgCounter]['disposal_method'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1));
$thisfile_png_chunk_type_text[$gIFgCounter]['user_input_flag'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1, 1));
$thisfile_png_chunk_type_text[$gIFgCounter]['delay_time'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 2));
break;
case 'gIFx': // GIF Application Extension
$gIFxCounter = 0;
if (isset($thisfile_png_chunk_type_text) && is_array($thisfile_png_chunk_type_text)) {
$gIFxCounter = count($thisfile_png_chunk_type_text);
}
$thisfile_png_chunk_type_text[$gIFxCounter]['header'] = $chunk;
$thisfile_png_chunk_type_text[$gIFxCounter]['application_identifier'] = substr($chunk['data'], 0, 8);
$thisfile_png_chunk_type_text[$gIFxCounter]['authentication_code'] = substr($chunk['data'], 8, 3);
$thisfile_png_chunk_type_text[$gIFxCounter]['application_data'] = substr($chunk['data'], 11);
break;
case 'IDAT': // Image Data
$idatinformationfieldindex = 0;
if (isset($thisfile_png['IDAT']) && is_array($thisfile_png['IDAT'])) {
$idatinformationfieldindex = count($thisfile_png['IDAT']);
}
unset($chunk['data']);
$thisfile_png_chunk_type_text[$idatinformationfieldindex]['header'] = $chunk;
break;
case 'IEND': // Image Trailer
$thisfile_png_chunk_type_text['header'] = $chunk;
break;
default:
//unset($chunk['data']);
$thisfile_png_chunk_type_text['header'] = $chunk;
$ThisFileInfo['warning'][] = 'Unhandled chunk type: '.$chunk['type_text'];
break;
}
}
return true;
}
function PNGsRGBintentLookup($sRGB) {
static $PNGsRGBintentLookup = array(
0 => 'Perceptual',
1 => 'Relative colorimetric',
2 => 'Saturation',
3 => 'Absolute colorimetric'
);
return (isset($PNGsRGBintentLookup[$sRGB]) ? $PNGsRGBintentLookup[$sRGB] : 'invalid');
}
function PNGcompressionMethodLookup($compressionmethod) {
static $PNGcompressionMethodLookup = array(
0 => 'deflate/inflate'
);
return (isset($PNGcompressionMethodLookup[$compressionmethod]) ? $PNGcompressionMethodLookup[$compressionmethod] : 'invalid');
}
function PNGpHYsUnitLookup($unitid) {
static $PNGpHYsUnitLookup = array(
0 => 'unknown',
1 => 'meter'
);
return (isset($PNGpHYsUnitLookup[$unitid]) ? $PNGpHYsUnitLookup[$unitid] : 'invalid');
}
function PNGoFFsUnitLookup($unitid) {
static $PNGoFFsUnitLookup = array(
0 => 'pixel',
1 => 'micrometer'
);
return (isset($PNGoFFsUnitLookup[$unitid]) ? $PNGoFFsUnitLookup[$unitid] : 'invalid');
}
function PNGpCALequationTypeLookup($equationtype) {
static $PNGpCALequationTypeLookup = array(
0 => 'Linear mapping',
1 => 'Base-e exponential mapping',
2 => 'Arbitrary-base exponential mapping',
3 => 'Hyperbolic mapping'
);
return (isset($PNGpCALequationTypeLookup[$equationtype]) ? $PNGpCALequationTypeLookup[$equationtype] : 'invalid');
}
function PNGsCALUnitLookup($unitid) {
static $PNGsCALUnitLookup = array(
0 => 'meter',
1 => 'radian'
);
return (isset($PNGsCALUnitLookup[$unitid]) ? $PNGsCALUnitLookup[$unitid] : 'invalid');
}
function IHDRcalculateBitsPerSample($color_type, $bit_depth) {
switch ($color_type) {
case 0: // Each pixel is a grayscale sample.
return $bit_depth;
break;
case 2: // Each pixel is an R,G,B triple
return 3 * $bit_depth;
break;
case 3: // Each pixel is a palette index; a PLTE chunk must appear.
return $bit_depth;
break;
case 4: // Each pixel is a grayscale sample, followed by an alpha sample.
return 2 * $bit_depth;
break;
case 6: // Each pixel is an R,G,B triple, followed by an alpha sample.
return 4 * $bit_depth;
break;
}
return false;
}
}
?>

View File

@ -1,52 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.graphic.svg.php //
// module for analyzing SVG Image files //
// dependencies: NONE //
// author: Bryce Harrington <bryceØbryceharrington*org> //
// ///
/////////////////////////////////////////////////////////////////
class getid3_svg
{
function getid3_svg(&$fd, &$ThisFileInfo) {
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
// I'm making this up, please modify as appropriate
$SVGheader = fread($fd, 32);
$ThisFileInfo['svg']['magic'] = substr($SVGheader, 0, 4);
if ($ThisFileInfo['svg']['magic'] == 'aBcD') {
$ThisFileInfo['fileformat'] = 'svg';
$ThisFileInfo['video']['dataformat'] = 'svg';
$ThisFileInfo['video']['lossless'] = true;
$ThisFileInfo['video']['bits_per_sample'] = 24;
$ThisFileInfo['video']['pixel_aspect_ratio'] = (float) 1;
$ThisFileInfo['svg']['width'] = getid3_lib::LittleEndian2Int(substr($fileData, 4, 4));
$ThisFileInfo['svg']['height'] = getid3_lib::LittleEndian2Int(substr($fileData, 8, 4));
$ThisFileInfo['video']['resolution_x'] = $ThisFileInfo['svg']['width'];
$ThisFileInfo['video']['resolution_y'] = $ThisFileInfo['svg']['height'];
return true;
}
$ThisFileInfo['error'][] = 'Did not find SVG magic bytes "aBcD" at '.$ThisFileInfo['avdataoffset'];
unset($ThisFileInfo['fileformat']);
return false;
}
}
?>

View File

@ -1,221 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.archive.tiff.php //
// module for analyzing TIFF files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_tiff
{
function getid3_tiff(&$fd, &$ThisFileInfo) {
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$TIFFheader = fread($fd, 4);
switch (substr($TIFFheader, 0, 2)) {
case 'II':
$ThisFileInfo['tiff']['byte_order'] = 'Intel';
break;
case 'MM':
$ThisFileInfo['tiff']['byte_order'] = 'Motorola';
break;
default:
$ThisFileInfo['error'][] = 'Invalid TIFF byte order identifier ('.substr($TIFFheader, 0, 2).') at offset '.$ThisFileInfo['avdataoffset'];
return false;
break;
}
$ThisFileInfo['fileformat'] = 'tiff';
$ThisFileInfo['video']['dataformat'] = 'tiff';
$ThisFileInfo['video']['lossless'] = true;
$ThisFileInfo['tiff']['ifd'] = array();
$CurrentIFD = array();
$FieldTypeByteLength = array(1=>1, 2=>1, 3=>2, 4=>4, 5=>8);
$nextIFDoffset = $this->TIFFendian2Int(fread($fd, 4), $ThisFileInfo['tiff']['byte_order']);
while ($nextIFDoffset > 0) {
$CurrentIFD['offset'] = $nextIFDoffset;
fseek($fd, $ThisFileInfo['avdataoffset'] + $nextIFDoffset, SEEK_SET);
$CurrentIFD['fieldcount'] = $this->TIFFendian2Int(fread($fd, 2), $ThisFileInfo['tiff']['byte_order']);
for ($i = 0; $i < $CurrentIFD['fieldcount']; $i++) {
$CurrentIFD['fields'][$i]['raw']['tag'] = $this->TIFFendian2Int(fread($fd, 2), $ThisFileInfo['tiff']['byte_order']);
$CurrentIFD['fields'][$i]['raw']['type'] = $this->TIFFendian2Int(fread($fd, 2), $ThisFileInfo['tiff']['byte_order']);
$CurrentIFD['fields'][$i]['raw']['length'] = $this->TIFFendian2Int(fread($fd, 4), $ThisFileInfo['tiff']['byte_order']);
$CurrentIFD['fields'][$i]['raw']['offset'] = fread($fd, 4);
switch ($CurrentIFD['fields'][$i]['raw']['type']) {
case 1: // BYTE An 8-bit unsigned integer.
if ($CurrentIFD['fields'][$i]['raw']['length'] <= 4) {
$CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int(substr($CurrentIFD['fields'][$i]['raw']['offset'], 0, 1), $ThisFileInfo['tiff']['byte_order']);
} else {
$CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $ThisFileInfo['tiff']['byte_order']);
}
break;
case 2: // ASCII 8-bit bytes that store ASCII codes; the last byte must be null.
if ($CurrentIFD['fields'][$i]['raw']['length'] <= 4) {
$CurrentIFD['fields'][$i]['value'] = substr($CurrentIFD['fields'][$i]['raw']['offset'], 3);
} else {
$CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $ThisFileInfo['tiff']['byte_order']);
}
break;
case 3: // SHORT A 16-bit (2-byte) unsigned integer.
if ($CurrentIFD['fields'][$i]['raw']['length'] <= 2) {
$CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int(substr($CurrentIFD['fields'][$i]['raw']['offset'], 0, 2), $ThisFileInfo['tiff']['byte_order']);
} else {
$CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $ThisFileInfo['tiff']['byte_order']);
}
break;
case 4: // LONG A 32-bit (4-byte) unsigned integer.
if ($CurrentIFD['fields'][$i]['raw']['length'] <= 1) {
$CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $ThisFileInfo['tiff']['byte_order']);
} else {
$CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $ThisFileInfo['tiff']['byte_order']);
}
break;
case 5: // RATIONAL Two LONG_s: the first represents the numerator of a fraction, the second the denominator.
break;
}
}
$ThisFileInfo['tiff']['ifd'][] = $CurrentIFD;
$CurrentIFD = array();
$nextIFDoffset = $this->TIFFendian2Int(fread($fd, 4), $ThisFileInfo['tiff']['byte_order']);
}
foreach ($ThisFileInfo['tiff']['ifd'] as $IFDid => $IFDarray) {
foreach ($IFDarray['fields'] as $key => $fieldarray) {
switch ($fieldarray['raw']['tag']) {
case 256: // ImageWidth
case 257: // ImageLength
case 258: // BitsPerSample
case 259: // Compression
if (!isset($fieldarray['value'])) {
fseek($fd, $fieldarray['offset'], SEEK_SET);
$ThisFileInfo['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = fread($fd, $fieldarray['raw']['length'] * $FieldTypeByteLength[$fieldarray['raw']['type']]);
}
break;
case 270: // ImageDescription
case 271: // Make
case 272: // Model
case 305: // Software
case 306: // DateTime
case 315: // Artist
case 316: // HostComputer
if (isset($fieldarray['value'])) {
$ThisFileInfo['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = $fieldarray['value'];
} else {
fseek($fd, $fieldarray['offset'], SEEK_SET);
$ThisFileInfo['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = fread($fd, $fieldarray['raw']['length'] * $FieldTypeByteLength[$fieldarray['raw']['type']]);
}
break;
}
switch ($fieldarray['raw']['tag']) {
case 256: // ImageWidth
$ThisFileInfo['video']['resolution_x'] = $fieldarray['value'];
break;
case 257: // ImageLength
$ThisFileInfo['video']['resolution_y'] = $fieldarray['value'];
break;
case 258: // BitsPerSample
if (isset($fieldarray['value'])) {
$ThisFileInfo['video']['bits_per_sample'] = $fieldarray['value'];
} else {
$ThisFileInfo['video']['bits_per_sample'] = 0;
for ($i = 0; $i < $fieldarray['raw']['length']; $i++) {
$ThisFileInfo['video']['bits_per_sample'] += $this->TIFFendian2Int(substr($ThisFileInfo['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'], $i * $FieldTypeByteLength[$fieldarray['raw']['type']], $FieldTypeByteLength[$fieldarray['raw']['type']]), $ThisFileInfo['tiff']['byte_order']);
}
}
break;
case 259: // Compression
$ThisFileInfo['video']['codec'] = $this->TIFFcompressionMethod($fieldarray['value']);
break;
case 270: // ImageDescription
case 271: // Make
case 272: // Model
case 305: // Software
case 306: // DateTime
case 315: // Artist
case 316: // HostComputer
@$ThisFileInfo['tiff']['comments'][$this->TIFFcommentName($fieldarray['raw']['tag'])][] = $ThisFileInfo['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'];
break;
default:
break;
}
}
}
return true;
}
function TIFFendian2Int($bytestring, $byteorder) {
if ($byteorder == 'Intel') {
return getid3_lib::LittleEndian2Int($bytestring);
} elseif ($byteorder == 'Motorola') {
return getid3_lib::BigEndian2Int($bytestring);
}
return false;
}
function TIFFcompressionMethod($id) {
static $TIFFcompressionMethod = array();
if (empty($TIFFcompressionMethod)) {
$TIFFcompressionMethod = array(
1 => 'Uncompressed',
2 => 'Huffman',
3 => 'Fax - CCITT 3',
5 => 'LZW',
32773 => 'PackBits',
);
}
return (isset($TIFFcompressionMethod[$id]) ? $TIFFcompressionMethod[$id] : 'unknown/invalid ('.$id.')');
}
function TIFFcommentName($id) {
static $TIFFcommentName = array();
if (empty($TIFFcommentName)) {
$TIFFcommentName = array(
270 => 'imagedescription',
271 => 'make',
272 => 'model',
305 => 'software',
306 => 'datetime',
315 => 'artist',
316 => 'hostcomputer',
);
}
return (isset($TIFFcommentName[$id]) ? $TIFFcommentName[$id] : 'unknown/invalid ('.$id.')');
}
}
?>

View File

@ -1,32 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.archive.doc.php //
// module for analyzing MS Office (.doc, .xls, etc) files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_doc
{
function getid3_doc(&$fd, &$ThisFileInfo) {
$ThisFileInfo['fileformat'] = 'doc';
$ThisFileInfo['error'][] = 'MS Office (.doc, .xls, etc) parsing not enabled in this version of getID3()';
return false;
}
}
?>

View File

@ -1,59 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.misc.exe.php //
// module for analyzing EXE files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_exe
{
function getid3_exe(&$fd, &$ThisFileInfo) {
fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
$EXEheader = fread($fd, 28);
if (substr($EXEheader, 0, 2) != 'MZ') {
$ThisFileInfo['error'][] = 'Expecting "MZ" at offset '.$ThisFileInfo['avdataoffset'].', found "'.substr($EXEheader, 0, 2).'" instead.';
return false;
}
$ThisFileInfo['fileformat'] = 'exe';
$ThisFileInfo['exe']['mz']['magic'] = 'MZ';
$ThisFileInfo['exe']['mz']['raw']['last_page_size'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 2, 2));
$ThisFileInfo['exe']['mz']['raw']['page_count'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 4, 2));
$ThisFileInfo['exe']['mz']['raw']['relocation_count'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 6, 2));
$ThisFileInfo['exe']['mz']['raw']['header_paragraphs'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 8, 2));
$ThisFileInfo['exe']['mz']['raw']['min_memory_paragraphs'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 10, 2));
$ThisFileInfo['exe']['mz']['raw']['max_memory_paragraphs'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 12, 2));
$ThisFileInfo['exe']['mz']['raw']['initial_ss'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 14, 2));
$ThisFileInfo['exe']['mz']['raw']['initial_sp'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 16, 2));
$ThisFileInfo['exe']['mz']['raw']['checksum'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 18, 2));
$ThisFileInfo['exe']['mz']['raw']['cs_ip'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 20, 4));
$ThisFileInfo['exe']['mz']['raw']['relocation_table_offset'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 24, 2));
$ThisFileInfo['exe']['mz']['raw']['overlay_number'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 26, 2));
$ThisFileInfo['exe']['mz']['byte_size'] = (($ThisFileInfo['exe']['mz']['raw']['page_count'] - 1)) * 512 + $ThisFileInfo['exe']['mz']['raw']['last_page_size'];
$ThisFileInfo['exe']['mz']['header_size'] = $ThisFileInfo['exe']['mz']['raw']['header_paragraphs'] * 16;
$ThisFileInfo['exe']['mz']['memory_minimum'] = $ThisFileInfo['exe']['mz']['raw']['min_memory_paragraphs'] * 16;
$ThisFileInfo['exe']['mz']['memory_recommended'] = $ThisFileInfo['exe']['mz']['raw']['max_memory_paragraphs'] * 16;
$ThisFileInfo['error'][] = 'EXE parsing not enabled in this version of getID3()';
return false;
}
}
?>

View File

@ -1,386 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.misc.iso.php //
// module for analyzing ISO files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_iso
{
function getid3_iso($fd, &$ThisFileInfo) {
$ThisFileInfo['fileformat'] = 'iso';
for ($i = 16; $i <= 19; $i++) {
fseek($fd, 2048 * $i, SEEK_SET);
$ISOheader = fread($fd, 2048);
if (substr($ISOheader, 1, 5) == 'CD001') {
switch (ord($ISOheader{0})) {
case 1:
$ThisFileInfo['iso']['primary_volume_descriptor']['offset'] = 2048 * $i;
$this->ParsePrimaryVolumeDescriptor($ISOheader, $ThisFileInfo);
break;
case 2:
$ThisFileInfo['iso']['supplementary_volume_descriptor']['offset'] = 2048 * $i;
$this->ParseSupplementaryVolumeDescriptor($ISOheader, $ThisFileInfo);
break;
default:
// skip
break;
}
}
}
$this->ParsePathTable($fd, $ThisFileInfo);
$ThisFileInfo['iso']['files'] = array();
foreach ($ThisFileInfo['iso']['path_table']['directories'] as $directorynum => $directorydata) {
$ThisFileInfo['iso']['directories'][$directorynum] = $this->ParseDirectoryRecord($fd, $directorydata, $ThisFileInfo);
}
return true;
}
function ParsePrimaryVolumeDescriptor(&$ISOheader, &$ThisFileInfo) {
// ISO integer values are stored *BOTH* Little-Endian AND Big-Endian format!!
// ie 12345 == 0x3039 is stored as $39 $30 $30 $39 in a 4-byte field
// shortcuts
$ThisFileInfo['iso']['primary_volume_descriptor']['raw'] = array();
$thisfile_iso_primaryVD = &$ThisFileInfo['iso']['primary_volume_descriptor'];
$thisfile_iso_primaryVD_raw = &$thisfile_iso_primaryVD['raw'];
$thisfile_iso_primaryVD_raw['volume_descriptor_type'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 0, 1));
$thisfile_iso_primaryVD_raw['standard_identifier'] = substr($ISOheader, 1, 5);
if ($thisfile_iso_primaryVD_raw['standard_identifier'] != 'CD001') {
$ThisFileInfo['error'][] = 'Expected "CD001" at offset ('.($thisfile_iso_primaryVD['offset'] + 1).'), found "'.$thisfile_iso_primaryVD_raw['standard_identifier'].'" instead';
unset($ThisFileInfo['fileformat']);
unset($ThisFileInfo['iso']);
return false;
}
$thisfile_iso_primaryVD_raw['volume_descriptor_version'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 6, 1));
//$thisfile_iso_primaryVD_raw['unused_1'] = substr($ISOheader, 7, 1);
$thisfile_iso_primaryVD_raw['system_identifier'] = substr($ISOheader, 8, 32);
$thisfile_iso_primaryVD_raw['volume_identifier'] = substr($ISOheader, 40, 32);
//$thisfile_iso_primaryVD_raw['unused_2'] = substr($ISOheader, 72, 8);
$thisfile_iso_primaryVD_raw['volume_space_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 80, 4));
//$thisfile_iso_primaryVD_raw['unused_3'] = substr($ISOheader, 88, 32);
$thisfile_iso_primaryVD_raw['volume_set_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 120, 2));
$thisfile_iso_primaryVD_raw['volume_sequence_number'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 124, 2));
$thisfile_iso_primaryVD_raw['logical_block_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 128, 2));
$thisfile_iso_primaryVD_raw['path_table_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 132, 4));
$thisfile_iso_primaryVD_raw['path_table_l_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 140, 2));
$thisfile_iso_primaryVD_raw['path_table_l_opt_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 144, 2));
$thisfile_iso_primaryVD_raw['path_table_m_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 148, 2));
$thisfile_iso_primaryVD_raw['path_table_m_opt_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 152, 2));
$thisfile_iso_primaryVD_raw['root_directory_record'] = substr($ISOheader, 156, 34);
$thisfile_iso_primaryVD_raw['volume_set_identifier'] = substr($ISOheader, 190, 128);
$thisfile_iso_primaryVD_raw['publisher_identifier'] = substr($ISOheader, 318, 128);
$thisfile_iso_primaryVD_raw['data_preparer_identifier'] = substr($ISOheader, 446, 128);
$thisfile_iso_primaryVD_raw['application_identifier'] = substr($ISOheader, 574, 128);
$thisfile_iso_primaryVD_raw['copyright_file_identifier'] = substr($ISOheader, 702, 37);
$thisfile_iso_primaryVD_raw['abstract_file_identifier'] = substr($ISOheader, 739, 37);
$thisfile_iso_primaryVD_raw['bibliographic_file_identifier'] = substr($ISOheader, 776, 37);
$thisfile_iso_primaryVD_raw['volume_creation_date_time'] = substr($ISOheader, 813, 17);
$thisfile_iso_primaryVD_raw['volume_modification_date_time'] = substr($ISOheader, 830, 17);
$thisfile_iso_primaryVD_raw['volume_expiration_date_time'] = substr($ISOheader, 847, 17);
$thisfile_iso_primaryVD_raw['volume_effective_date_time'] = substr($ISOheader, 864, 17);
$thisfile_iso_primaryVD_raw['file_structure_version'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 881, 1));
//$thisfile_iso_primaryVD_raw['unused_4'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 882, 1));
$thisfile_iso_primaryVD_raw['application_data'] = substr($ISOheader, 883, 512);
//$thisfile_iso_primaryVD_raw['unused_5'] = substr($ISOheader, 1395, 653);
$thisfile_iso_primaryVD['system_identifier'] = trim($thisfile_iso_primaryVD_raw['system_identifier']);
$thisfile_iso_primaryVD['volume_identifier'] = trim($thisfile_iso_primaryVD_raw['volume_identifier']);
$thisfile_iso_primaryVD['volume_set_identifier'] = trim($thisfile_iso_primaryVD_raw['volume_set_identifier']);
$thisfile_iso_primaryVD['publisher_identifier'] = trim($thisfile_iso_primaryVD_raw['publisher_identifier']);
$thisfile_iso_primaryVD['data_preparer_identifier'] = trim($thisfile_iso_primaryVD_raw['data_preparer_identifier']);
$thisfile_iso_primaryVD['application_identifier'] = trim($thisfile_iso_primaryVD_raw['application_identifier']);
$thisfile_iso_primaryVD['copyright_file_identifier'] = trim($thisfile_iso_primaryVD_raw['copyright_file_identifier']);
$thisfile_iso_primaryVD['abstract_file_identifier'] = trim($thisfile_iso_primaryVD_raw['abstract_file_identifier']);
$thisfile_iso_primaryVD['bibliographic_file_identifier'] = trim($thisfile_iso_primaryVD_raw['bibliographic_file_identifier']);
$thisfile_iso_primaryVD['volume_creation_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_primaryVD_raw['volume_creation_date_time']);
$thisfile_iso_primaryVD['volume_modification_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_primaryVD_raw['volume_modification_date_time']);
$thisfile_iso_primaryVD['volume_expiration_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_primaryVD_raw['volume_expiration_date_time']);
$thisfile_iso_primaryVD['volume_effective_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_primaryVD_raw['volume_effective_date_time']);
if (($thisfile_iso_primaryVD_raw['volume_space_size'] * 2048) > $ThisFileInfo['filesize']) {
$ThisFileInfo['error'][] = 'Volume Space Size ('.($thisfile_iso_primaryVD_raw['volume_space_size'] * 2048).' bytes) is larger than the file size ('.$ThisFileInfo['filesize'].' bytes) (truncated file?)';
}
return true;
}
function ParseSupplementaryVolumeDescriptor(&$ISOheader, &$ThisFileInfo) {
// ISO integer values are stored Both-Endian format!!
// ie 12345 == 0x3039 is stored as $39 $30 $30 $39 in a 4-byte field
// shortcuts
$ThisFileInfo['iso']['supplementary_volume_descriptor']['raw'] = array();
$thisfile_iso_supplementaryVD = &$ThisFileInfo['iso']['supplementary_volume_descriptor'];
$thisfile_iso_supplementaryVD_raw = &$thisfile_iso_supplementaryVD['raw'];
$thisfile_iso_supplementaryVD_raw['volume_descriptor_type'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 0, 1));
$thisfile_iso_supplementaryVD_raw['standard_identifier'] = substr($ISOheader, 1, 5);
if ($thisfile_iso_supplementaryVD_raw['standard_identifier'] != 'CD001') {
$ThisFileInfo['error'][] = 'Expected "CD001" at offset ('.($thisfile_iso_supplementaryVD['offset'] + 1).'), found "'.$thisfile_iso_supplementaryVD_raw['standard_identifier'].'" instead';
unset($ThisFileInfo['fileformat']);
unset($ThisFileInfo['iso']);
return false;
}
$thisfile_iso_supplementaryVD_raw['volume_descriptor_version'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 6, 1));
//$thisfile_iso_supplementaryVD_raw['unused_1'] = substr($ISOheader, 7, 1);
$thisfile_iso_supplementaryVD_raw['system_identifier'] = substr($ISOheader, 8, 32);
$thisfile_iso_supplementaryVD_raw['volume_identifier'] = substr($ISOheader, 40, 32);
//$thisfile_iso_supplementaryVD_raw['unused_2'] = substr($ISOheader, 72, 8);
$thisfile_iso_supplementaryVD_raw['volume_space_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 80, 4));
if ($thisfile_iso_supplementaryVD_raw['volume_space_size'] == 0) {
// Supplementary Volume Descriptor not used
//unset($thisfile_iso_supplementaryVD);
//return false;
}
//$thisfile_iso_supplementaryVD_raw['unused_3'] = substr($ISOheader, 88, 32);
$thisfile_iso_supplementaryVD_raw['volume_set_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 120, 2));
$thisfile_iso_supplementaryVD_raw['volume_sequence_number'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 124, 2));
$thisfile_iso_supplementaryVD_raw['logical_block_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 128, 2));
$thisfile_iso_supplementaryVD_raw['path_table_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 132, 4));
$thisfile_iso_supplementaryVD_raw['path_table_l_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 140, 2));
$thisfile_iso_supplementaryVD_raw['path_table_l_opt_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 144, 2));
$thisfile_iso_supplementaryVD_raw['path_table_m_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 148, 2));
$thisfile_iso_supplementaryVD_raw['path_table_m_opt_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 152, 2));
$thisfile_iso_supplementaryVD_raw['root_directory_record'] = substr($ISOheader, 156, 34);
$thisfile_iso_supplementaryVD_raw['volume_set_identifier'] = substr($ISOheader, 190, 128);
$thisfile_iso_supplementaryVD_raw['publisher_identifier'] = substr($ISOheader, 318, 128);
$thisfile_iso_supplementaryVD_raw['data_preparer_identifier'] = substr($ISOheader, 446, 128);
$thisfile_iso_supplementaryVD_raw['application_identifier'] = substr($ISOheader, 574, 128);
$thisfile_iso_supplementaryVD_raw['copyright_file_identifier'] = substr($ISOheader, 702, 37);
$thisfile_iso_supplementaryVD_raw['abstract_file_identifier'] = substr($ISOheader, 739, 37);
$thisfile_iso_supplementaryVD_raw['bibliographic_file_identifier'] = substr($ISOheader, 776, 37);
$thisfile_iso_supplementaryVD_raw['volume_creation_date_time'] = substr($ISOheader, 813, 17);
$thisfile_iso_supplementaryVD_raw['volume_modification_date_time'] = substr($ISOheader, 830, 17);
$thisfile_iso_supplementaryVD_raw['volume_expiration_date_time'] = substr($ISOheader, 847, 17);
$thisfile_iso_supplementaryVD_raw['volume_effective_date_time'] = substr($ISOheader, 864, 17);
$thisfile_iso_supplementaryVD_raw['file_structure_version'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 881, 1));
//$thisfile_iso_supplementaryVD_raw['unused_4'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 882, 1));
$thisfile_iso_supplementaryVD_raw['application_data'] = substr($ISOheader, 883, 512);
//$thisfile_iso_supplementaryVD_raw['unused_5'] = substr($ISOheader, 1395, 653);
$thisfile_iso_supplementaryVD['system_identifier'] = trim($thisfile_iso_supplementaryVD_raw['system_identifier']);
$thisfile_iso_supplementaryVD['volume_identifier'] = trim($thisfile_iso_supplementaryVD_raw['volume_identifier']);
$thisfile_iso_supplementaryVD['volume_set_identifier'] = trim($thisfile_iso_supplementaryVD_raw['volume_set_identifier']);
$thisfile_iso_supplementaryVD['publisher_identifier'] = trim($thisfile_iso_supplementaryVD_raw['publisher_identifier']);
$thisfile_iso_supplementaryVD['data_preparer_identifier'] = trim($thisfile_iso_supplementaryVD_raw['data_preparer_identifier']);
$thisfile_iso_supplementaryVD['application_identifier'] = trim($thisfile_iso_supplementaryVD_raw['application_identifier']);
$thisfile_iso_supplementaryVD['copyright_file_identifier'] = trim($thisfile_iso_supplementaryVD_raw['copyright_file_identifier']);
$thisfile_iso_supplementaryVD['abstract_file_identifier'] = trim($thisfile_iso_supplementaryVD_raw['abstract_file_identifier']);
$thisfile_iso_supplementaryVD['bibliographic_file_identifier'] = trim($thisfile_iso_supplementaryVD_raw['bibliographic_file_identifier']);
$thisfile_iso_supplementaryVD['volume_creation_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_supplementaryVD_raw['volume_creation_date_time']);
$thisfile_iso_supplementaryVD['volume_modification_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_supplementaryVD_raw['volume_modification_date_time']);
$thisfile_iso_supplementaryVD['volume_expiration_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_supplementaryVD_raw['volume_expiration_date_time']);
$thisfile_iso_supplementaryVD['volume_effective_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_supplementaryVD_raw['volume_effective_date_time']);
if (($thisfile_iso_supplementaryVD_raw['volume_space_size'] * $thisfile_iso_supplementaryVD_raw['logical_block_size']) > $ThisFileInfo['filesize']) {
$ThisFileInfo['error'][] = 'Volume Space Size ('.($thisfile_iso_supplementaryVD_raw['volume_space_size'] * $thisfile_iso_supplementaryVD_raw['logical_block_size']).' bytes) is larger than the file size ('.$ThisFileInfo['filesize'].' bytes) (truncated file?)';
}
return true;
}
function ParsePathTable($fd, &$ThisFileInfo) {
if (!isset($ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['path_table_l_location']) && !isset($ThisFileInfo['iso']['primary_volume_descriptor']['raw']['path_table_l_location'])) {
return false;
}
if (isset($ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['path_table_l_location'])) {
$PathTableLocation = $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['path_table_l_location'];
$PathTableSize = $ThisFileInfo['iso']['supplementary_volume_descriptor']['raw']['path_table_size'];
$TextEncoding = 'UTF-16BE'; // Big-Endian Unicode
} else {
$PathTableLocation = $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['path_table_l_location'];
$PathTableSize = $ThisFileInfo['iso']['primary_volume_descriptor']['raw']['path_table_size'];
$TextEncoding = 'ISO-8859-1'; // Latin-1
}
if (($PathTableLocation * 2048) > $ThisFileInfo['filesize']) {
$ThisFileInfo['error'][] = 'Path Table Location specifies an offset ('.($PathTableLocation * 2048).') beyond the end-of-file ('.$ThisFileInfo['filesize'].')';
return false;
}
$ThisFileInfo['iso']['path_table']['offset'] = $PathTableLocation * 2048;
fseek($fd, $ThisFileInfo['iso']['path_table']['offset'], SEEK_SET);
$ThisFileInfo['iso']['path_table']['raw'] = fread($fd, $PathTableSize);
$offset = 0;
$pathcounter = 1;
while ($offset < $PathTableSize) {
// shortcut
$ThisFileInfo['iso']['path_table']['directories'][$pathcounter] = array();
$thisfile_iso_pathtable_directories_current = &$ThisFileInfo['iso']['path_table']['directories'][$pathcounter];
$thisfile_iso_pathtable_directories_current['length'] = getid3_lib::LittleEndian2Int(substr($ThisFileInfo['iso']['path_table']['raw'], $offset, 1));
$offset += 1;
$thisfile_iso_pathtable_directories_current['extended_length'] = getid3_lib::LittleEndian2Int(substr($ThisFileInfo['iso']['path_table']['raw'], $offset, 1));
$offset += 1;
$thisfile_iso_pathtable_directories_current['location_logical'] = getid3_lib::LittleEndian2Int(substr($ThisFileInfo['iso']['path_table']['raw'], $offset, 4));
$offset += 4;
$thisfile_iso_pathtable_directories_current['parent_directory'] = getid3_lib::LittleEndian2Int(substr($ThisFileInfo['iso']['path_table']['raw'], $offset, 2));
$offset += 2;
$thisfile_iso_pathtable_directories_current['name'] = substr($ThisFileInfo['iso']['path_table']['raw'], $offset, $thisfile_iso_pathtable_directories_current['length']);
$offset += $thisfile_iso_pathtable_directories_current['length'] + ($thisfile_iso_pathtable_directories_current['length'] % 2);
$thisfile_iso_pathtable_directories_current['name_ascii'] = getid3_lib::iconv_fallback($TextEncoding, $ThisFileInfo['encoding'], $thisfile_iso_pathtable_directories_current['name']);
$thisfile_iso_pathtable_directories_current['location_bytes'] = $thisfile_iso_pathtable_directories_current['location_logical'] * 2048;
if ($pathcounter == 1) {
$thisfile_iso_pathtable_directories_current['full_path'] = '/';
} else {
$thisfile_iso_pathtable_directories_current['full_path'] = $ThisFileInfo['iso']['path_table']['directories'][$thisfile_iso_pathtable_directories_current['parent_directory']]['full_path'].$thisfile_iso_pathtable_directories_current['name_ascii'].'/';
}
$FullPathArray[] = $thisfile_iso_pathtable_directories_current['full_path'];
$pathcounter++;
}
return true;
}
function ParseDirectoryRecord(&$fd, $directorydata, &$ThisFileInfo) {
if (isset($ThisFileInfo['iso']['supplementary_volume_descriptor'])) {
$TextEncoding = 'UTF-16BE'; // Big-Endian Unicode
} else {
$TextEncoding = 'ISO-8859-1'; // Latin-1
}
fseek($fd, $directorydata['location_bytes'], SEEK_SET);
$DirectoryRecordData = fread($fd, 1);
while (ord($DirectoryRecordData{0}) > 33) {
$DirectoryRecordData .= fread($fd, ord($DirectoryRecordData{0}) - 1);
$ThisDirectoryRecord['raw']['length'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 0, 1));
$ThisDirectoryRecord['raw']['extended_attribute_length'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 1, 1));
$ThisDirectoryRecord['raw']['offset_logical'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 2, 4));
$ThisDirectoryRecord['raw']['filesize'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 10, 4));
$ThisDirectoryRecord['raw']['recording_date_time'] = substr($DirectoryRecordData, 18, 7);
$ThisDirectoryRecord['raw']['file_flags'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 25, 1));
$ThisDirectoryRecord['raw']['file_unit_size'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 26, 1));
$ThisDirectoryRecord['raw']['interleave_gap_size'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 27, 1));
$ThisDirectoryRecord['raw']['volume_sequence_number'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 28, 2));
$ThisDirectoryRecord['raw']['file_identifier_length'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 32, 1));
$ThisDirectoryRecord['raw']['file_identifier'] = substr($DirectoryRecordData, 33, $ThisDirectoryRecord['raw']['file_identifier_length']);
$ThisDirectoryRecord['file_identifier_ascii'] = getid3_lib::iconv_fallback($TextEncoding, $ThisFileInfo['encoding'], $ThisDirectoryRecord['raw']['file_identifier']);
$ThisDirectoryRecord['filesize'] = $ThisDirectoryRecord['raw']['filesize'];
$ThisDirectoryRecord['offset_bytes'] = $ThisDirectoryRecord['raw']['offset_logical'] * 2048;
$ThisDirectoryRecord['file_flags']['hidden'] = (bool) ($ThisDirectoryRecord['raw']['file_flags'] & 0x01);
$ThisDirectoryRecord['file_flags']['directory'] = (bool) ($ThisDirectoryRecord['raw']['file_flags'] & 0x02);
$ThisDirectoryRecord['file_flags']['associated'] = (bool) ($ThisDirectoryRecord['raw']['file_flags'] & 0x04);
$ThisDirectoryRecord['file_flags']['extended'] = (bool) ($ThisDirectoryRecord['raw']['file_flags'] & 0x08);
$ThisDirectoryRecord['file_flags']['permissions'] = (bool) ($ThisDirectoryRecord['raw']['file_flags'] & 0x10);
$ThisDirectoryRecord['file_flags']['multiple'] = (bool) ($ThisDirectoryRecord['raw']['file_flags'] & 0x80);
$ThisDirectoryRecord['recording_timestamp'] = $this->ISOtime2UNIXtime($ThisDirectoryRecord['raw']['recording_date_time']);
if ($ThisDirectoryRecord['file_flags']['directory']) {
$ThisDirectoryRecord['filename'] = $directorydata['full_path'];
} else {
$ThisDirectoryRecord['filename'] = $directorydata['full_path'].$this->ISOstripFilenameVersion($ThisDirectoryRecord['file_identifier_ascii']);
$ThisFileInfo['iso']['files'] = getid3_lib::array_merge_clobber($ThisFileInfo['iso']['files'], getid3_lib::CreateDeepArray($ThisDirectoryRecord['filename'], '/', $ThisDirectoryRecord['filesize']));
}
$DirectoryRecord[] = $ThisDirectoryRecord;
$DirectoryRecordData = fread($fd, 1);
}
return $DirectoryRecord;
}
function ISOstripFilenameVersion($ISOfilename) {
// convert 'filename.ext;1' to 'filename.ext'
if (!strstr($ISOfilename, ';')) {
return $ISOfilename;
} else {
return substr($ISOfilename, 0, strpos($ISOfilename, ';'));
}
}
function ISOtimeText2UNIXtime($ISOtime) {
$UNIXyear = (int) substr($ISOtime, 0, 4);
$UNIXmonth = (int) substr($ISOtime, 4, 2);
$UNIXday = (int) substr($ISOtime, 6, 2);
$UNIXhour = (int) substr($ISOtime, 8, 2);
$UNIXminute = (int) substr($ISOtime, 10, 2);
$UNIXsecond = (int) substr($ISOtime, 12, 2);
if (!$UNIXyear) {
return false;
}
return gmmktime($UNIXhour, $UNIXminute, $UNIXsecond, $UNIXmonth, $UNIXday, $UNIXyear);
}
function ISOtime2UNIXtime($ISOtime) {
// Represented by seven bytes:
// 1: Number of years since 1900
// 2: Month of the year from 1 to 12
// 3: Day of the Month from 1 to 31
// 4: Hour of the day from 0 to 23
// 5: Minute of the hour from 0 to 59
// 6: second of the minute from 0 to 59
// 7: Offset from Greenwich Mean Time in number of 15 minute intervals from -48 (West) to +52 (East)
$UNIXyear = ord($ISOtime{0}) + 1900;
$UNIXmonth = ord($ISOtime{1});
$UNIXday = ord($ISOtime{2});
$UNIXhour = ord($ISOtime{3});
$UNIXminute = ord($ISOtime{4});
$UNIXsecond = ord($ISOtime{5});
$GMToffset = $this->TwosCompliment2Decimal(ord($ISOtime{5}));
return gmmktime($UNIXhour, $UNIXminute, $UNIXsecond, $UNIXmonth, $UNIXday, $UNIXyear);
}
function TwosCompliment2Decimal($BinaryValue) {
// http://sandbox.mc.edu/~bennet/cs110/tc/tctod.html
// First check if the number is negative or positive by looking at the sign bit.
// If it is positive, simply convert it to decimal.
// If it is negative, make it positive by inverting the bits and adding one.
// Then, convert the result to decimal.
// The negative of this number is the value of the original binary.
if ($BinaryValue & 0x80) {
// negative number
return (0 - ((~$BinaryValue & 0xFF) + 1));
} else {
// positive number
return $BinaryValue;
}
}
}
?>

View File

@ -1,32 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.archive.doc.php //
// module for analyzing MS Office (.doc, .xls, etc) files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_doc
{
function getid3_doc(&$fd, &$ThisFileInfo) {
$ThisFileInfo['fileformat'] = 'doc';
$ThisFileInfo['error'][] = 'MS Office (.doc, .xls, etc) parsing not enabled in this version of getID3()';
return false;
}
}
?>

View File

@ -1,32 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.misc.par2.php //
// module for analyzing PAR2 files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_par2
{
function getid3_par2(&$fd, &$ThisFileInfo) {
$ThisFileInfo['fileformat'] = 'par2';
$ThisFileInfo['error'][] = 'PAR2 parsing not enabled in this version of getID3()';
return false;
}
}
?>

View File

@ -1,32 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.misc.pdf.php //
// module for analyzing PDF files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_pdf
{
function getid3_pdf(&$fd, &$ThisFileInfo) {
$ThisFileInfo['fileformat'] = 'pdf';
$ThisFileInfo['error'][] = 'PDF parsing not enabled in this version of getID3()';
return false;
}
}
?>

View File

@ -1,290 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.tag.apetag.php //
// module for analyzing APE tags //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_apetag
{
function getid3_apetag(&$fd, &$ThisFileInfo, $overrideendoffset=0) {
if ($ThisFileInfo['filesize'] >= pow(2, 31)) {
$ThisFileInfo['warning'][] = 'Unable to check for APEtags because file is larger than 2GB';
return false;
}
$id3v1tagsize = 128;
$apetagheadersize = 32;
$lyrics3tagsize = 10;
if ($overrideendoffset == 0) {
fseek($fd, 0 - $id3v1tagsize - $apetagheadersize - $lyrics3tagsize, SEEK_END);
$APEfooterID3v1 = fread($fd, $id3v1tagsize + $apetagheadersize + $lyrics3tagsize);
//if (preg_match('/APETAGEX.{24}TAG.{125}$/i', $APEfooterID3v1)) {
if (substr($APEfooterID3v1, strlen($APEfooterID3v1) - $id3v1tagsize - $apetagheadersize, 8) == 'APETAGEX') {
// APE tag found before ID3v1
$ThisFileInfo['ape']['tag_offset_end'] = $ThisFileInfo['filesize'] - $id3v1tagsize;
//} elseif (preg_match('/APETAGEX.{24}$/i', $APEfooterID3v1)) {
} elseif (substr($APEfooterID3v1, strlen($APEfooterID3v1) - $apetagheadersize, 8) == 'APETAGEX') {
// APE tag found, no ID3v1
$ThisFileInfo['ape']['tag_offset_end'] = $ThisFileInfo['filesize'];
}
} else {
fseek($fd, $overrideendoffset - $apetagheadersize, SEEK_SET);
if (fread($fd, 8) == 'APETAGEX') {
$ThisFileInfo['ape']['tag_offset_end'] = $overrideendoffset;
}
}
if (!isset($ThisFileInfo['ape']['tag_offset_end'])) {
// APE tag not found
unset($ThisFileInfo['ape']);
return false;
}
// shortcut
$thisfile_ape = &$ThisFileInfo['ape'];
fseek($fd, $thisfile_ape['tag_offset_end'] - $apetagheadersize, SEEK_SET);
$APEfooterData = fread($fd, 32);
if (!($thisfile_ape['footer'] = $this->parseAPEheaderFooter($APEfooterData))) {
$ThisFileInfo['error'][] = 'Error parsing APE footer at offset '.$thisfile_ape['tag_offset_end'];
return false;
}
if (isset($thisfile_ape['footer']['flags']['header']) && $thisfile_ape['footer']['flags']['header']) {
fseek($fd, $thisfile_ape['tag_offset_end'] - $thisfile_ape['footer']['raw']['tagsize'] - $apetagheadersize, SEEK_SET);
$thisfile_ape['tag_offset_start'] = ftell($fd);
$APEtagData = fread($fd, $thisfile_ape['footer']['raw']['tagsize'] + $apetagheadersize);
} else {
$thisfile_ape['tag_offset_start'] = $thisfile_ape['tag_offset_end'] - $thisfile_ape['footer']['raw']['tagsize'];
fseek($fd, $thisfile_ape['tag_offset_start'], SEEK_SET);
$APEtagData = fread($fd, $thisfile_ape['footer']['raw']['tagsize']);
}
$ThisFileInfo['avdataend'] = $thisfile_ape['tag_offset_start'];
if (isset($ThisFileInfo['id3v1']['tag_offset_start']) && ($ThisFileInfo['id3v1']['tag_offset_start'] < $thisfile_ape['tag_offset_end'])) {
$ThisFileInfo['warning'][] = 'ID3v1 tag information ignored since it appears to be a false synch in APEtag data';
unset($ThisFileInfo['id3v1']);
foreach ($ThisFileInfo['warning'] as $key => $value) {
if ($value == 'Some ID3v1 fields do not use NULL characters for padding') {
unset($ThisFileInfo['warning'][$key]);
sort($ThisFileInfo['warning']);
break;
}
}
}
$offset = 0;
if (isset($thisfile_ape['footer']['flags']['header']) && $thisfile_ape['footer']['flags']['header']) {
if ($thisfile_ape['header'] = $this->parseAPEheaderFooter(substr($APEtagData, 0, $apetagheadersize))) {
$offset += $apetagheadersize;
} else {
$ThisFileInfo['error'][] = 'Error parsing APE header at offset '.$thisfile_ape['tag_offset_start'];
return false;
}
}
// shortcut
$ThisFileInfo['replay_gain'] = array();
$thisfile_replaygain = &$ThisFileInfo['replay_gain'];
for ($i = 0; $i < $thisfile_ape['footer']['raw']['tag_items']; $i++) {
$value_size = getid3_lib::LittleEndian2Int(substr($APEtagData, $offset, 4));
$offset += 4;
$item_flags = getid3_lib::LittleEndian2Int(substr($APEtagData, $offset, 4));
$offset += 4;
if (strstr(substr($APEtagData, $offset), "\x00") === false) {
$ThisFileInfo['error'][] = 'Cannot find null-byte (0x00) seperator between ItemKey #'.$i.' and value. ItemKey starts '.$offset.' bytes into the APE tag, at file offset '.($thisfile_ape['tag_offset_start'] + $offset);
return false;
}
$ItemKeyLength = strpos($APEtagData, "\x00", $offset) - $offset;
$item_key = strtolower(substr($APEtagData, $offset, $ItemKeyLength));
// shortcut
$thisfile_ape['items'][$item_key] = array();
$thisfile_ape_items_current = &$thisfile_ape['items'][$item_key];
$offset += ($ItemKeyLength + 1); // skip 0x00 terminator
$thisfile_ape_items_current['data'] = substr($APEtagData, $offset, $value_size);
$offset += $value_size;
$thisfile_ape_items_current['flags'] = $this->parseAPEtagFlags($item_flags);
switch ($thisfile_ape_items_current['flags']['item_contents_raw']) {
case 0: // UTF-8
case 3: // Locator (URL, filename, etc), UTF-8 encoded
$thisfile_ape_items_current['data'] = explode("\x00", trim($thisfile_ape_items_current['data']));
break;
default: // binary data
break;
}
switch (strtolower($item_key)) {
case 'replaygain_track_gain':
$thisfile_replaygain['track']['adjustment'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
$thisfile_replaygain['track']['originator'] = 'unspecified';
break;
case 'replaygain_track_peak':
$thisfile_replaygain['track']['peak'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
$thisfile_replaygain['track']['originator'] = 'unspecified';
if ($thisfile_replaygain['track']['peak'] <= 0) {
$ThisFileInfo['warning'][] = 'ReplayGain Track peak from APEtag appears invalid: '.$thisfile_replaygain['track']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")';
}
break;
case 'replaygain_album_gain':
$thisfile_replaygain['album']['adjustment'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
$thisfile_replaygain['album']['originator'] = 'unspecified';
break;
case 'replaygain_album_peak':
$thisfile_replaygain['album']['peak'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
$thisfile_replaygain['album']['originator'] = 'unspecified';
if ($thisfile_replaygain['album']['peak'] <= 0) {
$ThisFileInfo['warning'][] = 'ReplayGain Album peak from APEtag appears invalid: '.$thisfile_replaygain['album']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")';
}
break;
case 'mp3gain_undo':
list($mp3gain_undo_left, $mp3gain_undo_right, $mp3gain_undo_wrap) = explode(',', $thisfile_ape_items_current['data'][0]);
$thisfile_replaygain['mp3gain']['undo_left'] = intval($mp3gain_undo_left);
$thisfile_replaygain['mp3gain']['undo_right'] = intval($mp3gain_undo_right);
$thisfile_replaygain['mp3gain']['undo_wrap'] = (($mp3gain_undo_wrap == 'Y') ? true : false);
break;
case 'mp3gain_minmax':
list($mp3gain_globalgain_min, $mp3gain_globalgain_max) = explode(',', $thisfile_ape_items_current['data'][0]);
$thisfile_replaygain['mp3gain']['globalgain_track_min'] = intval($mp3gain_globalgain_min);
$thisfile_replaygain['mp3gain']['globalgain_track_max'] = intval($mp3gain_globalgain_max);
break;
case 'mp3gain_album_minmax':
list($mp3gain_globalgain_album_min, $mp3gain_globalgain_album_max) = explode(',', $thisfile_ape_items_current['data'][0]);
$thisfile_replaygain['mp3gain']['globalgain_album_min'] = intval($mp3gain_globalgain_album_min);
$thisfile_replaygain['mp3gain']['globalgain_album_max'] = intval($mp3gain_globalgain_album_max);
break;
case 'tracknumber':
foreach ($thisfile_ape_items_current['data'] as $comment) {
$thisfile_ape['comments']['track'][] = $comment;
}
break;
default:
foreach ($thisfile_ape_items_current['data'] as $comment) {
$thisfile_ape['comments'][strtolower($item_key)][] = $comment;
}
break;
}
}
if (empty($thisfile_replaygain)) {
unset($ThisFileInfo['replay_gain']);
}
return true;
}
function parseAPEheaderFooter($APEheaderFooterData) {
// http://www.uni-jena.de/~pfk/mpp/sv8/apeheader.html
// shortcut
$headerfooterinfo['raw'] = array();
$headerfooterinfo_raw = &$headerfooterinfo['raw'];
$headerfooterinfo_raw['footer_tag'] = substr($APEheaderFooterData, 0, 8);
if ($headerfooterinfo_raw['footer_tag'] != 'APETAGEX') {
return false;
}
$headerfooterinfo_raw['version'] = getid3_lib::LittleEndian2Int(substr($APEheaderFooterData, 8, 4));
$headerfooterinfo_raw['tagsize'] = getid3_lib::LittleEndian2Int(substr($APEheaderFooterData, 12, 4));
$headerfooterinfo_raw['tag_items'] = getid3_lib::LittleEndian2Int(substr($APEheaderFooterData, 16, 4));
$headerfooterinfo_raw['global_flags'] = getid3_lib::LittleEndian2Int(substr($APEheaderFooterData, 20, 4));
$headerfooterinfo_raw['reserved'] = substr($APEheaderFooterData, 24, 8);
$headerfooterinfo['tag_version'] = $headerfooterinfo_raw['version'] / 1000;
if ($headerfooterinfo['tag_version'] >= 2) {
$headerfooterinfo['flags'] = $this->parseAPEtagFlags($headerfooterinfo_raw['global_flags']);
}
return $headerfooterinfo;
}
function parseAPEtagFlags($rawflagint) {
// "Note: APE Tags 1.0 do not use any of the APE Tag flags.
// All are set to zero on creation and ignored on reading."
// http://www.uni-jena.de/~pfk/mpp/sv8/apetagflags.html
$flags['header'] = (bool) ($rawflagint & 0x80000000);
$flags['footer'] = (bool) ($rawflagint & 0x40000000);
$flags['this_is_header'] = (bool) ($rawflagint & 0x20000000);
$flags['item_contents_raw'] = ($rawflagint & 0x00000006) >> 1;
$flags['read_only'] = (bool) ($rawflagint & 0x00000001);
$flags['item_contents'] = $this->APEcontentTypeFlagLookup($flags['item_contents_raw']);
return $flags;
}
function APEcontentTypeFlagLookup($contenttypeid) {
static $APEcontentTypeFlagLookup = array(
0 => 'utf-8',
1 => 'binary',
2 => 'external',
3 => 'reserved'
);
return (isset($APEcontentTypeFlagLookup[$contenttypeid]) ? $APEcontentTypeFlagLookup[$contenttypeid] : 'invalid');
}
function APEtagItemIsUTF8Lookup($itemkey) {
static $APEtagItemIsUTF8Lookup = array(
'title',
'subtitle',
'artist',
'album',
'debut album',
'publisher',
'conductor',
'track',
'composer',
'comment',
'copyright',
'publicationright',
'file',
'year',
'record date',
'record location',
'genre',
'media',
'related',
'isrc',
'abstract',
'language',
'bibliography'
);
return in_array(strtolower($itemkey), $APEtagItemIsUTF8Lookup);
}
}
?>

View File

@ -1,361 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.tag.id3v1.php //
// module for analyzing ID3v1 tags //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
class getid3_id3v1
{
function getid3_id3v1(&$fd, &$ThisFileInfo) {
if ($ThisFileInfo['filesize'] >= pow(2, 31)) {
$ThisFileInfo['warning'][] = 'Unable to check for ID3v1 because file is larger than 2GB';
return false;
}
fseek($fd, -256, SEEK_END);
$preid3v1 = fread($fd, 128);
$id3v1tag = fread($fd, 128);
if (substr($id3v1tag, 0, 3) == 'TAG') {
$ThisFileInfo['avdataend'] = $ThisFileInfo['filesize'] - 128;
$ParsedID3v1['title'] = $this->cutfield(substr($id3v1tag, 3, 30));
$ParsedID3v1['artist'] = $this->cutfield(substr($id3v1tag, 33, 30));
$ParsedID3v1['album'] = $this->cutfield(substr($id3v1tag, 63, 30));
$ParsedID3v1['year'] = $this->cutfield(substr($id3v1tag, 93, 4));
$ParsedID3v1['comment'] = substr($id3v1tag, 97, 30); // can't remove nulls yet, track detection depends on them
$ParsedID3v1['genreid'] = ord(substr($id3v1tag, 127, 1));
// If second-last byte of comment field is null and last byte of comment field is non-null
// then this is ID3v1.1 and the comment field is 28 bytes long and the 30th byte is the track number
if (($id3v1tag{125} === "\x00") && ($id3v1tag{126} !== "\x00")) {
$ParsedID3v1['track'] = ord(substr($ParsedID3v1['comment'], 29, 1));
$ParsedID3v1['comment'] = substr($ParsedID3v1['comment'], 0, 28);
}
$ParsedID3v1['comment'] = $this->cutfield($ParsedID3v1['comment']);
$ParsedID3v1['genre'] = $this->LookupGenreName($ParsedID3v1['genreid']);
if (!empty($ParsedID3v1['genre'])) {
unset($ParsedID3v1['genreid']);
}
if (empty($ParsedID3v1['genre']) || (@$ParsedID3v1['genre'] == 'Unknown')) {
unset($ParsedID3v1['genre']);
}
foreach ($ParsedID3v1 as $key => $value) {
$ParsedID3v1['comments'][$key][0] = $value;
}
// ID3v1 data is supposed to be padded with NULL characters, but some taggers pad with spaces
$GoodFormatID3v1tag = $this->GenerateID3v1Tag(
$ParsedID3v1['title'],
$ParsedID3v1['artist'],
$ParsedID3v1['album'],
$ParsedID3v1['year'],
(isset($ParsedID3v1['genre']) ? $this->LookupGenreID($ParsedID3v1['genre']) : false),
$ParsedID3v1['comment'],
@$ParsedID3v1['track']);
$ParsedID3v1['padding_valid'] = true;
if ($id3v1tag !== $GoodFormatID3v1tag) {
$ParsedID3v1['padding_valid'] = false;
$ThisFileInfo['warning'][] = 'Some ID3v1 fields do not use NULL characters for padding';
}
$ParsedID3v1['tag_offset_end'] = $ThisFileInfo['filesize'];
$ParsedID3v1['tag_offset_start'] = $ParsedID3v1['tag_offset_end'] - 128;
$ThisFileInfo['id3v1'] = $ParsedID3v1;
}
if (substr($preid3v1, 0, 3) == 'TAG') {
// The way iTunes handles tags is, well, brain-damaged.
// It completely ignores v1 if ID3v2 is present.
// This goes as far as adding a new v1 tag *even if there already is one*
// A suspected double-ID3v1 tag has been detected, but it could be that
// the "TAG" identifier is a legitimate part of an APE or Lyrics3 tag
if (substr($preid3v1, 96, 8) == 'APETAGEX') {
// an APE tag footer was found before the last ID3v1, assume false "TAG" synch
} elseif (substr($preid3v1, 119, 6) == 'LYRICS') {
// a Lyrics3 tag footer was found before the last ID3v1, assume false "TAG" synch
} else {
// APE and Lyrics3 footers not found - assume double ID3v1
$ThisFileInfo['warning'][] = 'Duplicate ID3v1 tag detected - this has been known to happen with iTunes';
$ThisFileInfo['avdataend'] -= 128;
}
}
return true;
}
function cutfield($str) {
return trim(substr($str, 0, strcspn($str, "\x00")));
}
function ArrayOfGenres($allowSCMPXextended=false) {
static $GenreLookup = array(
0 => 'Blues',
1 => 'Classic Rock',
2 => 'Country',
3 => 'Dance',
4 => 'Disco',
5 => 'Funk',
6 => 'Grunge',
7 => 'Hip-Hop',
8 => 'Jazz',
9 => 'Metal',
10 => 'New Age',
11 => 'Oldies',
12 => 'Other',
13 => 'Pop',
14 => 'R&B',
15 => 'Rap',
16 => 'Reggae',
17 => 'Rock',
18 => 'Techno',
19 => 'Industrial',
20 => 'Alternative',
21 => 'Ska',
22 => 'Death Metal',
23 => 'Pranks',
24 => 'Soundtrack',
25 => 'Euro-Techno',
26 => 'Ambient',
27 => 'Trip-Hop',
28 => 'Vocal',
29 => 'Jazz+Funk',
30 => 'Fusion',
31 => 'Trance',
32 => 'Classical',
33 => 'Instrumental',
34 => 'Acid',
35 => 'House',
36 => 'Game',
37 => 'Sound Clip',
38 => 'Gospel',
39 => 'Noise',
40 => 'Alt. Rock',
41 => 'Bass',
42 => 'Soul',
43 => 'Punk',
44 => 'Space',
45 => 'Meditative',
46 => 'Instrumental Pop',
47 => 'Instrumental Rock',
48 => 'Ethnic',
49 => 'Gothic',
50 => 'Darkwave',
51 => 'Techno-Industrial',
52 => 'Electronic',
53 => 'Pop-Folk',
54 => 'Eurodance',
55 => 'Dream',
56 => 'Southern Rock',
57 => 'Comedy',
58 => 'Cult',
59 => 'Gangsta Rap',
60 => 'Top 40',
61 => 'Christian Rap',
62 => 'Pop/Funk',
63 => 'Jungle',
64 => 'Native American',
65 => 'Cabaret',
66 => 'New Wave',
67 => 'Psychedelic',
68 => 'Rave',
69 => 'Showtunes',
70 => 'Trailer',
71 => 'Lo-Fi',
72 => 'Tribal',
73 => 'Acid Punk',
74 => 'Acid Jazz',
75 => 'Polka',
76 => 'Retro',
77 => 'Musical',
78 => 'Rock & Roll',
79 => 'Hard Rock',
80 => 'Folk',
81 => 'Folk/Rock',
82 => 'National Folk',
83 => 'Swing',
84 => 'Fast-Fusion',
85 => 'Bebob',
86 => 'Latin',
87 => 'Revival',
88 => 'Celtic',
89 => 'Bluegrass',
90 => 'Avantgarde',
91 => 'Gothic Rock',
92 => 'Progressive Rock',
93 => 'Psychedelic Rock',
94 => 'Symphonic Rock',
95 => 'Slow Rock',
96 => 'Big Band',
97 => 'Chorus',
98 => 'Easy Listening',
99 => 'Acoustic',
100 => 'Humour',
101 => 'Speech',
102 => 'Chanson',
103 => 'Opera',
104 => 'Chamber Music',
105 => 'Sonata',
106 => 'Symphony',
107 => 'Booty Bass',
108 => 'Primus',
109 => 'Porn Groove',
110 => 'Satire',
111 => 'Slow Jam',
112 => 'Club',
113 => 'Tango',
114 => 'Samba',
115 => 'Folklore',
116 => 'Ballad',
117 => 'Power Ballad',
118 => 'Rhythmic Soul',
119 => 'Freestyle',
120 => 'Duet',
121 => 'Punk Rock',
122 => 'Drum Solo',
123 => 'A Cappella',
124 => 'Euro-House',
125 => 'Dance Hall',
126 => 'Goa',
127 => 'Drum & Bass',
128 => 'Club-House',
129 => 'Hardcore',
130 => 'Terror',
131 => 'Indie',
132 => 'BritPop',
133 => 'Negerpunk',
134 => 'Polsk Punk',
135 => 'Beat',
136 => 'Christian Gangsta Rap',
137 => 'Heavy Metal',
138 => 'Black Metal',
139 => 'Crossover',
140 => 'Contemporary Christian',
141 => 'Christian Rock',
142 => 'Merengue',
143 => 'Salsa',
144 => 'Trash Metal',
145 => 'Anime',
146 => 'JPop',
147 => 'Synthpop',
255 => 'Unknown',
'CR' => 'Cover',
'RX' => 'Remix'
);
static $GenreLookupSCMPX = array();
if ($allowSCMPXextended && empty($GenreLookupSCMPX)) {
$GenreLookupSCMPX = $GenreLookup;
// http://www.geocities.co.jp/SiliconValley-Oakland/3664/alittle.html#GenreExtended
// Extended ID3v1 genres invented by SCMPX
// Note that 255 "Japanese Anime" conflicts with standard "Unknown"
$GenreLookupSCMPX[240] = 'Sacred';
$GenreLookupSCMPX[241] = 'Northern Europe';
$GenreLookupSCMPX[242] = 'Irish & Scottish';
$GenreLookupSCMPX[243] = 'Scotland';
$GenreLookupSCMPX[244] = 'Ethnic Europe';
$GenreLookupSCMPX[245] = 'Enka';
$GenreLookupSCMPX[246] = 'Children\'s Song';
$GenreLookupSCMPX[247] = 'Japanese Sky';
$GenreLookupSCMPX[248] = 'Japanese Heavy Rock';
$GenreLookupSCMPX[249] = 'Japanese Doom Rock';
$GenreLookupSCMPX[250] = 'Japanese J-POP';
$GenreLookupSCMPX[251] = 'Japanese Seiyu';
$GenreLookupSCMPX[252] = 'Japanese Ambient Techno';
$GenreLookupSCMPX[253] = 'Japanese Moemoe';
$GenreLookupSCMPX[254] = 'Japanese Tokusatsu';
//$GenreLookupSCMPX[255] = 'Japanese Anime';
}
return ($allowSCMPXextended ? $GenreLookupSCMPX : $GenreLookup);
}
function LookupGenreName($genreid, $allowSCMPXextended=true) {
switch ($genreid) {
case 'RX':
case 'CR':
break;
default:
$genreid = intval($genreid); // to handle 3 or '3' or '03'
break;
}
$GenreLookup = getid3_id3v1::ArrayOfGenres($allowSCMPXextended);
return (isset($GenreLookup[$genreid]) ? $GenreLookup[$genreid] : false);
}
function LookupGenreID($genre, $allowSCMPXextended=false) {
$GenreLookup = getid3_id3v1::ArrayOfGenres($allowSCMPXextended);
$LowerCaseNoSpaceSearchTerm = strtolower(str_replace(' ', '', $genre));
foreach ($GenreLookup as $key => $value) {
foreach ($GenreLookup as $key => $value) {
if (strtolower(str_replace(' ', '', $value)) == $LowerCaseNoSpaceSearchTerm) {
return $key;
}
}
return false;
}
return (isset($GenreLookup[$genreid]) ? $GenreLookup[$genreid] : false);
}
function StandardiseID3v1GenreName($OriginalGenre) {
if (($GenreID = getid3_id3v1::LookupGenreID($OriginalGenre)) !== false) {
return getid3_id3v1::LookupGenreName($GenreID);
}
return $OriginalGenre;
}
function GenerateID3v1Tag($title, $artist, $album, $year, $genreid, $comment, $track='') {
$ID3v1Tag = 'TAG';
$ID3v1Tag .= str_pad(trim(substr($title, 0, 30)), 30, "\x00", STR_PAD_RIGHT);
$ID3v1Tag .= str_pad(trim(substr($artist, 0, 30)), 30, "\x00", STR_PAD_RIGHT);
$ID3v1Tag .= str_pad(trim(substr($album, 0, 30)), 30, "\x00", STR_PAD_RIGHT);
$ID3v1Tag .= str_pad(trim(substr($year, 0, 4)), 4, "\x00", STR_PAD_LEFT);
if (!empty($track) && ($track > 0) && ($track <= 255)) {
$ID3v1Tag .= str_pad(trim(substr($comment, 0, 28)), 28, "\x00", STR_PAD_RIGHT);
$ID3v1Tag .= "\x00";
if (gettype($track) == 'string') {
$track = (int) $track;
}
$ID3v1Tag .= chr($track);
} else {
$ID3v1Tag .= str_pad(trim(substr($comment, 0, 30)), 30, "\x00", STR_PAD_RIGHT);
}
if (($genreid < 0) || ($genreid > 147)) {
$genreid = 255; // 'unknown' genre
}
switch (gettype($genreid)) {
case 'string':
case 'integer':
$ID3v1Tag .= chr(intval($genreid));
break;
default:
$ID3v1Tag .= chr(255); // 'unknown' genre
break;
}
return $ID3v1Tag;
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@ -1,282 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
/// //
// module.tag.lyrics3.php //
// module for analyzing Lyrics3 tags //
// dependencies: module.tag.apetag.php (optional) //
// ///
/////////////////////////////////////////////////////////////////
class getid3_lyrics3
{
function getid3_lyrics3(&$fd, &$ThisFileInfo) {
// http://www.volweb.cz/str/tags.htm
if ($ThisFileInfo['filesize'] >= pow(2, 31)) {
$ThisFileInfo['warning'][] = 'Unable to check for Lyrics3 because file is larger than 2GB';
return false;
}
fseek($fd, (0 - 128 - 9 - 6), SEEK_END); // end - ID3v1 - LYRICSEND - [Lyrics3size]
$lyrics3_id3v1 = fread($fd, 128 + 9 + 6);
$lyrics3lsz = substr($lyrics3_id3v1, 0, 6); // Lyrics3size
$lyrics3end = substr($lyrics3_id3v1, 6, 9); // LYRICSEND or LYRICS200
$id3v1tag = substr($lyrics3_id3v1, 15, 128); // ID3v1
if ($lyrics3end == 'LYRICSEND') {
// Lyrics3v1, ID3v1, no APE
$lyrics3size = 5100;
$lyrics3offset = $ThisFileInfo['filesize'] - 128 - $lyrics3size;
$lyrics3version = 1;
} elseif ($lyrics3end == 'LYRICS200') {
// Lyrics3v2, ID3v1, no APE
// LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200'
$lyrics3size = $lyrics3lsz + 6 + strlen('LYRICS200');
$lyrics3offset = $ThisFileInfo['filesize'] - 128 - $lyrics3size;
$lyrics3version = 2;
} elseif (substr(strrev($lyrics3_id3v1), 0, 9) == strrev('LYRICSEND')) {
// Lyrics3v1, no ID3v1, no APE
$lyrics3size = 5100;
$lyrics3offset = $ThisFileInfo['filesize'] - $lyrics3size;
$lyrics3version = 1;
$lyrics3offset = $ThisFileInfo['filesize'] - $lyrics3size;
} elseif (substr(strrev($lyrics3_id3v1), 0, 9) == strrev('LYRICS200')) {
// Lyrics3v2, no ID3v1, no APE
$lyrics3size = strrev(substr(strrev($lyrics3_id3v1), 9, 6)) + 6 + strlen('LYRICS200'); // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200'
$lyrics3offset = $ThisFileInfo['filesize'] - $lyrics3size;
$lyrics3version = 2;
} else {
if (isset($ThisFileInfo['ape']['tag_offset_start']) && ($ThisFileInfo['ape']['tag_offset_start'] > 15)) {
fseek($fd, $ThisFileInfo['ape']['tag_offset_start'] - 15, SEEK_SET);
$lyrics3lsz = fread($fd, 6);
$lyrics3end = fread($fd, 9);
if ($lyrics3end == 'LYRICSEND') {
// Lyrics3v1, APE, maybe ID3v1
$lyrics3size = 5100;
$lyrics3offset = $ThisFileInfo['ape']['tag_offset_start'] - $lyrics3size;
$ThisFileInfo['avdataend'] = $lyrics3offset;
$lyrics3version = 1;
$ThisFileInfo['warning'][] = 'APE tag located after Lyrics3, will probably break Lyrics3 compatability';
} elseif ($lyrics3end == 'LYRICS200') {
// Lyrics3v2, APE, maybe ID3v1
$lyrics3size = $lyrics3lsz + 6 + strlen('LYRICS200'); // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200'
$lyrics3offset = $ThisFileInfo['ape']['tag_offset_start'] - $lyrics3size;
$lyrics3version = 2;
$ThisFileInfo['warning'][] = 'APE tag located after Lyrics3, will probably break Lyrics3 compatability';
}
}
}
if (isset($lyrics3offset)) {
$ThisFileInfo['avdataend'] = $lyrics3offset;
$this->getLyrics3Data($ThisFileInfo, $fd, $lyrics3offset, $lyrics3version, $lyrics3size);
if (!isset($ThisFileInfo['ape'])) {
$GETID3_ERRORARRAY = &$ThisFileInfo['warning'];
if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.apetag.php', __FILE__, false)) {
$tag = new getid3_apetag($fd, $ThisFileInfo, $ThisFileInfo['lyrics3']['tag_offset_start']);
unset($tag);
}
}
}
return true;
}
function getLyrics3Data(&$ThisFileInfo, &$fd, $endoffset, $version, $length) {
// http://www.volweb.cz/str/tags.htm
if ($endoffset >= pow(2, 31)) {
$ThisFileInfo['warning'][] = 'Unable to check for Lyrics3 because file is larger than 2GB';
return false;
}
fseek($fd, $endoffset, SEEK_SET);
if ($length <= 0) {
return false;
}
$rawdata = fread($fd, $length);
if (substr($rawdata, 0, 11) != 'LYRICSBEGIN') {
if (strpos($rawdata, 'LYRICSBEGIN') !== false) {
$ThisFileInfo['warning'][] = '"LYRICSBEGIN" expected at '.$endoffset.' but actually found at '.($endoffset + strpos($rawdata, 'LYRICSBEGIN')).' - this is invalid for Lyrics3 v'.$version;
$ThisFileInfo['avdataend'] = $endoffset + strpos($rawdata, 'LYRICSBEGIN');
$ParsedLyrics3['tag_offset_start'] = $ThisFileInfo['avdataend'];
$rawdata = substr($rawdata, strpos($rawdata, 'LYRICSBEGIN'));
$length = strlen($rawdata);
} else {
$ThisFileInfo['error'][] = '"LYRICSBEGIN" expected at '.$endoffset.' but found "'.substr($rawdata, 0, 11).'" instead';
return false;
}
}
$ParsedLyrics3['raw']['lyrics3version'] = $version;
$ParsedLyrics3['raw']['lyrics3tagsize'] = $length;
$ParsedLyrics3['tag_offset_start'] = $endoffset;
$ParsedLyrics3['tag_offset_end'] = $endoffset + $length;
switch ($version) {
case 1:
if (substr($rawdata, strlen($rawdata) - 9, 9) == 'LYRICSEND') {
$ParsedLyrics3['raw']['LYR'] = trim(substr($rawdata, 11, strlen($rawdata) - 11 - 9));
$this->Lyrics3LyricsTimestampParse($ParsedLyrics3);
} else {
$ThisFileInfo['error'][] = '"LYRICSEND" expected at '.(ftell($fd) - 11 + $length - 9).' but found "'.substr($rawdata, strlen($rawdata) - 9, 9).'" instead';
return false;
}
break;
case 2:
if (substr($rawdata, strlen($rawdata) - 9, 9) == 'LYRICS200') {
$ParsedLyrics3['raw']['unparsed'] = substr($rawdata, 11, strlen($rawdata) - 11 - 9 - 6); // LYRICSBEGIN + LYRICS200 + LSZ
$rawdata = $ParsedLyrics3['raw']['unparsed'];
while (strlen($rawdata) > 0) {
$fieldname = substr($rawdata, 0, 3);
$fieldsize = (int) substr($rawdata, 3, 5);
$ParsedLyrics3['raw'][$fieldname] = substr($rawdata, 8, $fieldsize);
$rawdata = substr($rawdata, 3 + 5 + $fieldsize);
}
if (isset($ParsedLyrics3['raw']['IND'])) {
$i = 0;
$flagnames = array('lyrics', 'timestamps', 'inhibitrandom');
foreach ($flagnames as $flagname) {
if (strlen($ParsedLyrics3['raw']['IND']) > $i++) {
$ParsedLyrics3['flags'][$flagname] = $this->IntString2Bool(substr($ParsedLyrics3['raw']['IND'], $i, 1 - 1));
}
}
}
$fieldnametranslation = array('ETT'=>'title', 'EAR'=>'artist', 'EAL'=>'album', 'INF'=>'comment', 'AUT'=>'author');
foreach ($fieldnametranslation as $key => $value) {
if (isset($ParsedLyrics3['raw'][$key])) {
$ParsedLyrics3['comments'][$value][] = trim($ParsedLyrics3['raw'][$key]);
}
}
if (isset($ParsedLyrics3['raw']['IMG'])) {
$imagestrings = explode("\r\n", $ParsedLyrics3['raw']['IMG']);
foreach ($imagestrings as $key => $imagestring) {
if (strpos($imagestring, '||') !== false) {
$imagearray = explode('||', $imagestring);
$ParsedLyrics3['images'][$key]['filename'] = @$imagearray[0];
$ParsedLyrics3['images'][$key]['description'] = @$imagearray[1];
$ParsedLyrics3['images'][$key]['timestamp'] = $this->Lyrics3Timestamp2Seconds(@$imagearray[2]);
}
}
}
if (isset($ParsedLyrics3['raw']['LYR'])) {
$this->Lyrics3LyricsTimestampParse($ParsedLyrics3);
}
} else {
$ThisFileInfo['error'][] = '"LYRICS200" expected at '.(ftell($fd) - 11 + $length - 9).' but found "'.substr($rawdata, strlen($rawdata) - 9, 9).'" instead';
return false;
}
break;
default:
$ThisFileInfo['error'][] = 'Cannot process Lyrics3 version '.$version.' (only v1 and v2)';
return false;
break;
}
if (isset($ThisFileInfo['id3v1']['tag_offset_start']) && ($ThisFileInfo['id3v1']['tag_offset_start'] < $ParsedLyrics3['tag_offset_end'])) {
$ThisFileInfo['warning'][] = 'ID3v1 tag information ignored since it appears to be a false synch in Lyrics3 tag data';
unset($ThisFileInfo['id3v1']);
foreach ($ThisFileInfo['warning'] as $key => $value) {
if ($value == 'Some ID3v1 fields do not use NULL characters for padding') {
unset($ThisFileInfo['warning'][$key]);
sort($ThisFileInfo['warning']);
break;
}
}
}
$ThisFileInfo['lyrics3'] = $ParsedLyrics3;
return true;
}
function Lyrics3Timestamp2Seconds($rawtimestamp) {
if (ereg('^\\[([0-9]{2}):([0-9]{2})\\]$', $rawtimestamp, $regs)) {
return (int) (($regs[1] * 60) + $regs[2]);
}
return false;
}
function Lyrics3LyricsTimestampParse(&$Lyrics3data) {
$lyricsarray = explode("\r\n", $Lyrics3data['raw']['LYR']);
foreach ($lyricsarray as $key => $lyricline) {
$regs = array();
unset($thislinetimestamps);
while (ereg('^(\\[[0-9]{2}:[0-9]{2}\\])', $lyricline, $regs)) {
$thislinetimestamps[] = $this->Lyrics3Timestamp2Seconds($regs[0]);
$lyricline = str_replace($regs[0], '', $lyricline);
}
$notimestamplyricsarray[$key] = $lyricline;
if (isset($thislinetimestamps) && is_array($thislinetimestamps)) {
sort($thislinetimestamps);
foreach ($thislinetimestamps as $timestampkey => $timestamp) {
if (isset($Lyrics3data['synchedlyrics'][$timestamp])) {
// timestamps only have a 1-second resolution, it's possible that multiple lines
// could have the same timestamp, if so, append
$Lyrics3data['synchedlyrics'][$timestamp] .= "\r\n".$lyricline;
} else {
$Lyrics3data['synchedlyrics'][$timestamp] = $lyricline;
}
}
}
}
$Lyrics3data['unsynchedlyrics'] = implode("\r\n", $notimestamplyricsarray);
if (isset($Lyrics3data['synchedlyrics']) && is_array($Lyrics3data['synchedlyrics'])) {
ksort($Lyrics3data['synchedlyrics']);
}
return true;
}
function IntString2Bool($char) {
if ($char == '1') {
return true;
} elseif ($char == '0') {
return false;
}
return null;
}
}
?>

View File

@ -1,228 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// write.apetag.php //
// module for writing APE tags //
// dependencies: module.tag.apetag.php //
// ///
/////////////////////////////////////////////////////////////////
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.apetag.php', __FILE__, true);
class getid3_write_apetag
{
var $filename;
var $tag_data;
var $always_preserve_replaygain = true; // ReplayGain / MP3gain tags will be copied from old tag even if not passed in data
var $warnings = array(); // any non-critical errors will be stored here
var $errors = array(); // any critical errors will be stored here
function getid3_write_apetag() {
return true;
}
function WriteAPEtag() {
// NOTE: All data passed to this function must be UTF-8 format
$getID3 = new getID3;
$ThisFileInfo = $getID3->analyze($this->filename);
if (isset($ThisFileInfo['ape']['tag_offset_start']) && isset($ThisFileInfo['lyrics3']['tag_offset_end'])) {
if ($ThisFileInfo['ape']['tag_offset_start'] >= $ThisFileInfo['lyrics3']['tag_offset_end']) {
// Current APE tag between Lyrics3 and ID3v1/EOF
// This break Lyrics3 functionality
if (!$this->DeleteAPEtag()) {
return false;
}
$ThisFileInfo = $getID3->analyze($this->filename);
}
}
if ($this->always_preserve_replaygain) {
$ReplayGainTagsToPreserve = array('mp3gain_minmax', 'mp3gain_album_minmax', 'mp3gain_undo', 'replaygain_track_peak', 'replaygain_track_gain', 'replaygain_album_peak', 'replaygain_album_gain');
foreach ($ReplayGainTagsToPreserve as $rg_key) {
if (isset($ThisFileInfo['ape']['items'][strtolower($rg_key)]['data'][0]) && !isset($this->tag_data[strtoupper($rg_key)][0])) {
$this->tag_data[strtoupper($rg_key)][0] = $ThisFileInfo['ape']['items'][strtolower($rg_key)]['data'][0];
}
}
}
if ($APEtag = $this->GenerateAPEtag()) {
if ($fp = @fopen($this->filename, 'a+b')) {
$oldignoreuserabort = ignore_user_abort(true);
flock($fp, LOCK_EX);
$PostAPEdataOffset = $ThisFileInfo['avdataend'];
if (isset($ThisFileInfo['ape']['tag_offset_end'])) {
$PostAPEdataOffset = max($PostAPEdataOffset, $ThisFileInfo['ape']['tag_offset_end']);
}
if (isset($ThisFileInfo['lyrics3']['tag_offset_start'])) {
$PostAPEdataOffset = max($PostAPEdataOffset, $ThisFileInfo['lyrics3']['tag_offset_start']);
}
fseek($fp, $PostAPEdataOffset, SEEK_SET);
$PostAPEdata = '';
if ($ThisFileInfo['filesize'] > $PostAPEdataOffset) {
$PostAPEdata = fread($fp, $ThisFileInfo['filesize'] - $PostAPEdataOffset);
}
fseek($fp, $PostAPEdataOffset, SEEK_SET);
if (isset($ThisFileInfo['ape']['tag_offset_start'])) {
fseek($fp, $ThisFileInfo['ape']['tag_offset_start'], SEEK_SET);
}
ftruncate($fp, ftell($fp));
fwrite($fp, $APEtag, strlen($APEtag));
if (!empty($PostAPEdata)) {
fwrite($fp, $PostAPEdata, strlen($PostAPEdata));
}
flock($fp, LOCK_UN);
fclose($fp);
ignore_user_abort($oldignoreuserabort);
return true;
}
return false;
}
return false;
}
function DeleteAPEtag() {
$getID3 = new getID3;
$ThisFileInfo = $getID3->analyze($this->filename);
if (isset($ThisFileInfo['ape']['tag_offset_start']) && isset($ThisFileInfo['ape']['tag_offset_end'])) {
if ($fp = @fopen($this->filename, 'a+b')) {
flock($fp, LOCK_EX);
$oldignoreuserabort = ignore_user_abort(true);
fseek($fp, $ThisFileInfo['ape']['tag_offset_end'], SEEK_SET);
$DataAfterAPE = '';
if ($ThisFileInfo['filesize'] > $ThisFileInfo['ape']['tag_offset_end']) {
$DataAfterAPE = fread($fp, $ThisFileInfo['filesize'] - $ThisFileInfo['ape']['tag_offset_end']);
}
ftruncate($fp, $ThisFileInfo['ape']['tag_offset_start']);
fseek($fp, $ThisFileInfo['ape']['tag_offset_start'], SEEK_SET);
if (!empty($DataAfterAPE)) {
fwrite($fp, $DataAfterAPE, strlen($DataAfterAPE));
}
flock($fp, LOCK_UN);
fclose($fp);
ignore_user_abort($oldignoreuserabort);
return true;
}
return false;
}
return true;
}
function GenerateAPEtag() {
// NOTE: All data passed to this function must be UTF-8 format
$items = array();
if (!is_array($this->tag_data)) {
return false;
}
foreach ($this->tag_data as $key => $arrayofvalues) {
if (!is_array($arrayofvalues)) {
return false;
}
$valuestring = '';
foreach ($arrayofvalues as $value) {
$valuestring .= str_replace("\x00", '', $value)."\x00";
}
$valuestring = rtrim($valuestring, "\x00");
// Length of the assigned value in bytes
$tagitem = getid3_lib::LittleEndian2String(strlen($valuestring), 4);
//$tagitem .= $this->GenerateAPEtagFlags(true, true, false, 0, false);
$tagitem .= "\x00\x00\x00\x00";
$tagitem .= $this->CleanAPEtagItemKey($key)."\x00";
$tagitem .= $valuestring;
$items[] = $tagitem;
}
return $this->GenerateAPEtagHeaderFooter($items, true).implode('', $items).$this->GenerateAPEtagHeaderFooter($items, false);
}
function GenerateAPEtagHeaderFooter(&$items, $isheader=false) {
$tagdatalength = 0;
foreach ($items as $itemdata) {
$tagdatalength += strlen($itemdata);
}
$APEheader = 'APETAGEX';
$APEheader .= getid3_lib::LittleEndian2String(2000, 4);
$APEheader .= getid3_lib::LittleEndian2String(32 + $tagdatalength, 4);
$APEheader .= getid3_lib::LittleEndian2String(count($items), 4);
$APEheader .= $this->GenerateAPEtagFlags(true, true, $isheader, 0, false);
$APEheader .= str_repeat("\x00", 8);
return $APEheader;
}
function GenerateAPEtagFlags($header=true, $footer=true, $isheader=false, $encodingid=0, $readonly=false) {
$APEtagFlags = array_fill(0, 4, 0);
if ($header) {
$APEtagFlags[0] |= 0x80; // Tag contains a header
}
if (!$footer) {
$APEtagFlags[0] |= 0x40; // Tag contains no footer
}
if ($isheader) {
$APEtagFlags[0] |= 0x20; // This is the header, not the footer
}
// 0: Item contains text information coded in UTF-8
// 1: Item contains binary information °)
// 2: Item is a locator of external stored information °°)
// 3: reserved
$APEtagFlags[3] |= ($encodingid << 1);
if ($readonly) {
$APEtagFlags[3] |= 0x01; // Tag or Item is Read Only
}
return chr($APEtagFlags[3]).chr($APEtagFlags[2]).chr($APEtagFlags[1]).chr($APEtagFlags[0]);
}
function CleanAPEtagItemKey($itemkey) {
$itemkey = eregi_replace("[^\x20-\x7E]", '', $itemkey);
// http://www.personal.uni-jena.de/~pfk/mpp/sv8/apekey.html
switch (strtoupper($itemkey)) {
case 'EAN/UPC':
case 'ISBN':
case 'LC':
case 'ISRC':
$itemkey = strtoupper($itemkey);
break;
default:
$itemkey = ucwords($itemkey);
break;
}
return $itemkey;
}
}
?>

View File

@ -1,119 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// write.id3v1.php //
// module for writing ID3v1 tags //
// dependencies: module.tag.id3v1.php //
// ///
/////////////////////////////////////////////////////////////////
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v1.php', __FILE__, true);
class getid3_write_id3v1
{
var $filename;
var $tag_data;
var $warnings = array(); // any non-critical errors will be stored here
var $errors = array(); // any critical errors will be stored here
function getid3_write_id3v1() {
return true;
}
function WriteID3v1() {
if ((filesize($this->filename) >= (pow(2, 31) - 128)) || (filesize($this->filename) < 0)) {
$this->errors[] = 'Unable to write ID3v1 because file is larger than 2GB';
return false;
}
// File MUST be writeable - CHMOD(646) at least
if (is_writeable($this->filename)) {
if ($fp_source = @fopen($this->filename, 'r+b')) {
fseek($fp_source, -128, SEEK_END);
if (fread($fp_source, 3) == 'TAG') {
fseek($fp_source, -128, SEEK_END); // overwrite existing ID3v1 tag
} else {
fseek($fp_source, 0, SEEK_END); // append new ID3v1 tag
}
$this->tag_data['track'] = (isset($this->tag_data['track']) ? $this->tag_data['track'] : (isset($this->tag_data['track_number']) ? $this->tag_data['track_number'] : (isset($this->tag_data['tracknumber']) ? $this->tag_data['tracknumber'] : '')));
$new_id3v1_tag_data = getid3_id3v1::GenerateID3v1Tag(
@$this->tag_data['title'],
@$this->tag_data['artist'],
@$this->tag_data['album'],
@$this->tag_data['year'],
@$this->tag_data['genreid'],
@$this->tag_data['comment'],
@$this->tag_data['track']);
fwrite($fp_source, $new_id3v1_tag_data, 128);
fclose($fp_source);
return true;
} else {
$this->errors[] = 'Could not open '.$this->filename.' mode "r+b"';
return false;
}
}
$this->errors[] = 'File is not writeable: '.$this->filename;
return false;
}
function FixID3v1Padding() {
// ID3v1 data is supposed to be padded with NULL characters, but some taggers incorrectly use spaces
// This function rewrites the ID3v1 tag with correct padding
// Initialize getID3 engine
$getID3 = new getID3;
$ThisFileInfo = $getID3->analyze($this->filename);
if ($ThisFileInfo['filesize'] >= (pow(2, 31) - 128)) {
// cannot write tags on files > 2GB
return false;
}
if (isset($ThisFileInfo['tags']['id3v1'])) {
foreach ($ThisFileInfo['tags']['id3v1'] as $key => $value) {
$id3v1data[$key] = implode(',', $value);
}
$this->tag_data = $id3v1data;
return $this->WriteID3v1();
}
return false;
}
function RemoveID3v1() {
if ($ThisFileInfo['filesize'] >= pow(2, 31)) {
$this->errors[] = 'Unable to write ID3v1 because file is larger than 2GB';
return false;
}
// File MUST be writeable - CHMOD(646) at least
if (is_writeable($this->filename)) {
if ($fp_source = @fopen($this->filename, 'r+b')) {
fseek($fp_source, -128, SEEK_END);
if (fread($fp_source, 3) == 'TAG') {
ftruncate($fp_source, filesize($this->filename) - 128);
} else {
// no ID3v1 tag to begin with - do nothing
}
fclose($fp_source);
return true;
} else {
$this->errors[] = 'Could not open '.$this->filename.' mode "r+b"';
}
} else {
$this->errors[] = $this->filename.' is not writeable';
}
return false;
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@ -1,78 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// write.lyrics3.php //
// module for writing Lyrics3 tags //
// dependencies: module.tag.lyrics3.php //
// ///
/////////////////////////////////////////////////////////////////
class getid3_write_lyrics3
{
var $filename;
var $tag_data;
//var $lyrics3_version = 2; // 1 or 2
var $warnings = array(); // any non-critical errors will be stored here
var $errors = array(); // any critical errors will be stored here
function getid3_write_lyrics3() {
return true;
}
function WriteLyrics3() {
$this->errors[] = 'WriteLyrics3() not yet functional - cannot write Lyrics3';
return false;
}
function DeleteLyrics3() {
// Initialize getID3 engine
$getID3 = new getID3;
$ThisFileInfo = $getID3->analyze($this->filename);
if (isset($ThisFileInfo['lyrics3']['tag_offset_start']) && isset($ThisFileInfo['lyrics3']['tag_offset_end'])) {
if ($fp = @fopen($this->filename, 'a+b')) {
flock($fp, LOCK_EX);
$oldignoreuserabort = ignore_user_abort(true);
fseek($fp, $ThisFileInfo['lyrics3']['tag_offset_end'], SEEK_SET);
$DataAfterLyrics3 = '';
if ($ThisFileInfo['filesize'] > $ThisFileInfo['lyrics3']['tag_offset_end']) {
$DataAfterLyrics3 = fread($fp, $ThisFileInfo['filesize'] - $ThisFileInfo['lyrics3']['tag_offset_end']);
}
ftruncate($fp, $ThisFileInfo['lyrics3']['tag_offset_start']);
if (!empty($DataAfterLyrics3)) {
fseek($fp, $ThisFileInfo['lyrics3']['tag_offset_start'], SEEK_SET);
fwrite($fp, $DataAfterLyrics3, strlen($DataAfterLyrics3));
}
flock($fp, LOCK_UN);
fclose($fp);
ignore_user_abort($oldignoreuserabort);
return true;
} else {
$this->errors[] = 'Cannot open "'.$this->filename.'" in "a+b" mode';
return false;
}
}
// no Lyrics3 present
return true;
}
}
?>

View File

@ -1,167 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// write.metaflac.php //
// module for writing metaflac tags //
// dependencies: /helperapps/metaflac.exe //
// ///
/////////////////////////////////////////////////////////////////
class getid3_write_metaflac
{
var $filename;
var $tag_data;
var $warnings = array(); // any non-critical errors will be stored here
var $errors = array(); // any critical errors will be stored here
function getid3_write_metaflac() {
return true;
}
function WriteMetaFLAC() {
if (!ini_get('safe_mode')) {
// Create file with new comments
$tempcommentsfilename = tempnam('*', 'getID3');
if ($fpcomments = @fopen($tempcommentsfilename, 'wb')) {
foreach ($this->tag_data as $key => $value) {
foreach ($value as $commentdata) {
fwrite($fpcomments, $this->CleanmetaflacName($key).'='.$commentdata."\n");
}
}
fclose($fpcomments);
} else {
$this->errors[] = 'failed to open temporary tags file "'.$tempcommentsfilename.'", tags not written';
return false;
}
$oldignoreuserabort = ignore_user_abort(true);
if (GETID3_OS_ISWINDOWS) {
if (file_exists(GETID3_HELPERAPPSDIR.'metaflac.exe')) {
//$commandline = '"'.GETID3_HELPERAPPSDIR.'metaflac.exe" --no-utf8-convert --remove-all-tags --import-tags-from="'.$tempcommentsfilename.'" "'.str_replace('/', '\\', $this->filename).'"';
// metaflac works fine if you copy-paste the above commandline into a command prompt,
// but refuses to work with `backtick` if there are "doublequotes" present around BOTH
// the metaflac pathname and the target filename. For whatever reason...??
// The solution is simply ensure that the metaflac pathname has no spaces,
// and therefore does not need to be quoted
// On top of that, if error messages are not always captured properly under Windows
// To at least see if there was a problem, compare file modification timestamps before and after writing
clearstatcache();
$timestampbeforewriting = filemtime($this->filename);
$commandline = GETID3_HELPERAPPSDIR.'metaflac.exe --no-utf8-convert --remove-all-tags --import-tags-from="'.$tempcommentsfilename.'" "'.$this->filename.'" 2>&1';
$metaflacError = `$commandline`;
if (empty($metaflacError)) {
clearstatcache();
if ($timestampbeforewriting == filemtime($this->filename)) {
$metaflacError = 'File modification timestamp has not changed - it looks like the tags were not written';
}
}
} else {
$metaflacError = 'metaflac.exe not found in '.GETID3_HELPERAPPSDIR;
}
} else {
// It's simpler on *nix
$commandline = 'metaflac --no-utf8-convert --remove-all-tags --import-tags-from='.$tempcommentsfilename.' "'.$this->filename.'" 2>&1';
$metaflacError = `$commandline`;
}
// Remove temporary comments file
unlink($tempcommentsfilename);
ignore_user_abort($oldignoreuserabort);
if (!empty($metaflacError)) {
$this->errors[] = 'System call to metaflac failed with this message returned: '."\n\n".$metaflacError;
return false;
}
return true;
}
$this->errors[] = 'PHP running in Safe Mode (backtick operator not available) - cannot call metaflac, tags not written';
return false;
}
function DeleteMetaFLAC() {
if (!ini_get('safe_mode')) {
$oldignoreuserabort = ignore_user_abort(true);
if (GETID3_OS_ISWINDOWS) {
if (file_exists(GETID3_HELPERAPPSDIR.'metaflac.exe')) {
// To at least see if there was a problem, compare file modification timestamps before and after writing
clearstatcache();
$timestampbeforewriting = filemtime($this->filename);
$commandline = GETID3_HELPERAPPSDIR.'metaflac.exe --remove-all-tags "'.$this->filename.'" 2>&1';
$metaflacError = `$commandline`;
if (empty($metaflacError)) {
clearstatcache();
if ($timestampbeforewriting == filemtime($this->filename)) {
$metaflacError = 'File modification timestamp has not changed - it looks like the tags were not deleted';
}
}
} else {
$metaflacError = 'metaflac.exe not found in '.GETID3_HELPERAPPSDIR;
}
} else {
// It's simpler on *nix
$commandline = 'metaflac --remove-all-tags "'.$this->filename.'" 2>&1';
$metaflacError = `$commandline`;
}
ignore_user_abort($oldignoreuserabort);
if (!empty($metaflacError)) {
$this->errors[] = 'System call to metaflac failed with this message returned: '."\n\n".$metaflacError;
return false;
}
return true;
}
$this->errors[] = 'PHP running in Safe Mode (backtick operator not available) - cannot call metaflac, tags not deleted';
return false;
}
function CleanmetaflacName($originalcommentname) {
// A case-insensitive field name that may consist of ASCII 0x20 through 0x7D, 0x3D ('=') excluded.
// ASCII 0x41 through 0x5A inclusive (A-Z) is to be considered equivalent to ASCII 0x61 through
// 0x7A inclusive (a-z).
// replace invalid chars with a space, return uppercase text
// Thanks Chris Bolt <chris-getid3Øbolt*cx> for improving this function
// note: ereg_replace() replaces nulls with empty string (not space)
return strtoupper(ereg_replace('[^ -<>-}]', ' ', str_replace("\x00", ' ', $originalcommentname)));
}
}
?>

View File

@ -1,592 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
/// //
// write.php //
// module for writing tags (APEv2, ID3v1, ID3v2) //
// dependencies: getid3.lib.php //
// write.apetag.php (optional) //
// write.id3v1.php (optional) //
// write.id3v2.php (optional) //
// write.vorbiscomment.php (optional) //
// write.metaflac.php (optional) //
// write.lyrics3.php (optional) //
// ///
/////////////////////////////////////////////////////////////////
if (!defined('GETID3_INCLUDEPATH')) {
die('getid3.php MUST be included before calling getid3_writetags');
}
if (!include_once(GETID3_INCLUDEPATH.'getid3.lib.php')) {
die('write.php depends on getid3.lib.php, which is missing.');
}
// NOTES:
//
// You should pass data here with standard field names as follows:
// * TITLE
// * ARTIST
// * ALBUM
// * TRACKNUMBER
// * COMMENT
// * GENRE
// * YEAR
// * ATTACHED_PICTURE (ID3v2 only)
//
// http://www.personal.uni-jena.de/~pfk/mpp/sv8/apekey.html
// The APEv2 Tag Items Keys definition says "TRACK" is correct but foobar2000 uses "TRACKNUMBER" instead
// Pass data here as "TRACKNUMBER" for compatability with all formats
class getid3_writetags
{
// public
var $filename; // absolute filename of file to write tags to
var $tagformats = array(); // array of tag formats to write ('id3v1', 'id3v2.2', 'id2v2.3', 'id3v2.4', 'ape', 'vorbiscomment', 'metaflac', 'real')
var $tag_data = array(array()); // 2-dimensional array of tag data (ex: $data['ARTIST'][0] = 'Elvis')
var $tag_encoding = 'ISO-8859-1'; // text encoding used for tag data ('ISO-8859-1', 'UTF-8', 'UTF-16', 'UTF-16LE', 'UTF-16BE', )
var $overwrite_tags = true; // if true will erase existing tag data and write only passed data; if false will merge passed data with existing tag data
var $remove_other_tags = false; // if true will erase remove all existing tags and only write those passed in $tagformats; if false will ignore any tags not mentioned in $tagformats
var $id3v2_tag_language = 'eng'; // ISO-639-2 3-character language code needed for some ID3v2 frames (http://www.id3.org/iso639-2.html)
var $id3v2_paddedlength = 4096; // minimum length of ID3v2 tags (will be padded to this length if tag data is shorter)
var $warnings = array(); // any non-critical errors will be stored here
var $errors = array(); // any critical errors will be stored here
// private
var $ThisFileInfo; // analysis of file before writing
function getid3_writetags() {
return true;
}
function WriteTags() {
if (empty($this->filename)) {
$this->errors[] = 'filename is undefined in getid3_writetags';
return false;
} elseif (!file_exists($this->filename)) {
$this->errors[] = 'filename set to non-existant file "'.$this->filename.'" in getid3_writetags';
return false;
}
if (!is_array($this->tagformats)) {
$this->errors[] = 'tagformats must be an array in getid3_writetags';
return false;
}
$TagFormatsToRemove = array();
if (filesize($this->filename) == 0) {
// empty file special case - allow any tag format, don't check existing format
// could be useful if you want to generate tag data for a non-existant file
$this->ThisFileInfo = array('fileformat'=>'');
$AllowedTagFormats = array('id3v1', 'id3v2.2', 'id3v2.3', 'id3v2.4', 'ape', 'lyrics3');
} else {
$getID3 = new getID3;
$getID3->encoding = $this->tag_encoding;
$this->ThisFileInfo = $getID3->analyze($this->filename);
// check for what file types are allowed on this fileformat
switch (@$this->ThisFileInfo['fileformat']) {
case 'mp3':
case 'mp2':
case 'mp1':
case 'riff': // maybe not officially, but people do it anyway
$AllowedTagFormats = array('id3v1', 'id3v2.2', 'id3v2.3', 'id3v2.4', 'ape', 'lyrics3');
break;
case 'mpc':
$AllowedTagFormats = array('ape');
break;
case 'flac':
$AllowedTagFormats = array('metaflac');
break;
case 'real':
$AllowedTagFormats = array('real');
break;
case 'ogg':
switch (@$this->ThisFileInfo['audio']['dataformat']) {
case 'flac':
//$AllowedTagFormats = array('metaflac');
$this->errors[] = 'metaflac is not (yet) compatible with OggFLAC files';
return false;
break;
case 'vorbis':
$AllowedTagFormats = array('vorbiscomment');
break;
default:
$this->errors[] = 'metaflac is not (yet) compatible with Ogg files other than OggVorbis';
return false;
break;
}
break;
default:
$AllowedTagFormats = array();
break;
}
foreach ($this->tagformats as $requested_tag_format) {
if (!in_array($requested_tag_format, $AllowedTagFormats)) {
$errormessage = 'Tag format "'.$requested_tag_format.'" is not allowed on "'.@$this->ThisFileInfo['fileformat'];
if (@$this->ThisFileInfo['fileformat'] != @$this->ThisFileInfo['audio']['dataformat']) {
$errormessage .= '.'.@$this->ThisFileInfo['audio']['dataformat'];
}
$errormessage .= '" files';
$this->errors[] = $errormessage;
return false;
}
}
// List of other tag formats, removed if requested
if ($this->remove_other_tags) {
foreach ($AllowedTagFormats as $AllowedTagFormat) {
switch ($AllowedTagFormat) {
case 'id3v2.2':
case 'id3v2.3':
case 'id3v2.4':
if (!in_array('id3v2', $TagFormatsToRemove) && !in_array('id3v2.2', $this->tagformats) && !in_array('id3v2.3', $this->tagformats) && !in_array('id3v2.4', $this->tagformats)) {
$TagFormatsToRemove[] = 'id3v2';
}
break;
default:
if (!in_array($AllowedTagFormat, $this->tagformats)) {
$TagFormatsToRemove[] = $AllowedTagFormat;
}
break;
}
}
}
}
$WritingFilesToInclude = array_merge($this->tagformats, $TagFormatsToRemove);
// Check for required include files and include them
foreach ($WritingFilesToInclude as $tagformat) {
switch ($tagformat) {
case 'ape':
$GETID3_ERRORARRAY = &$this->errors;
if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'write.apetag.php', __FILE__, false)) {
return false;
}
break;
case 'id3v1':
case 'lyrics3':
case 'vorbiscomment':
case 'metaflac':
case 'real':
$GETID3_ERRORARRAY = &$this->errors;
if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'write.'.$tagformat.'.php', __FILE__, false)) {
return false;
}
break;
case 'id3v2.2':
case 'id3v2.3':
case 'id3v2.4':
case 'id3v2':
$GETID3_ERRORARRAY = &$this->errors;
if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'write.id3v2.php', __FILE__, false)) {
return false;
}
break;
default:
$this->errors[] = 'unknown tag format "'.$tagformat.'" in $tagformats in WriteTags()';
return false;
break;
}
}
// Validation of supplied data
if (!is_array($this->tag_data)) {
$this->errors[] = '$tag_data is not an array in WriteTags()';
return false;
}
// convert supplied data array keys to upper case, if they're not already
foreach ($this->tag_data as $tag_key => $tag_array) {
if (strtoupper($tag_key) !== $tag_key) {
$this->tag_data[strtoupper($tag_key)] = $this->tag_data[$tag_key];
unset($this->tag_data[$tag_key]);
}
}
// convert source data array keys to upper case, if they're not already
if (!empty($this->ThisFileInfo['tags'])) {
foreach ($this->ThisFileInfo['tags'] as $tag_format => $tag_data_array) {
foreach ($tag_data_array as $tag_key => $tag_array) {
if (strtoupper($tag_key) !== $tag_key) {
$this->ThisFileInfo['tags'][$tag_format][strtoupper($tag_key)] = $this->ThisFileInfo['tags'][$tag_format][$tag_key];
unset($this->ThisFileInfo['tags'][$tag_format][$tag_key]);
}
}
}
}
// Convert "TRACK" to "TRACKNUMBER" (if needed) for compatability with all formats
if (isset($this->tag_data['TRACK']) && !isset($this->tag_data['TRACKNUMBER'])) {
$this->tag_data['TRACKNUMBER'] = $this->tag_data['TRACK'];
unset($this->tag_data['TRACK']);
}
// Remove all other tag formats, if requested
if ($this->remove_other_tags) {
$this->DeleteTags($TagFormatsToRemove);
}
// Write data for each tag format
foreach ($this->tagformats as $tagformat) {
$success = false; // overridden if tag writing is successful
switch ($tagformat) {
case 'ape':
$ape_writer = new getid3_write_apetag;
if (($ape_writer->tag_data = $this->FormatDataForAPE()) !== false) {
$ape_writer->filename = $this->filename;
if (($success = $ape_writer->WriteAPEtag()) === false) {
$this->errors[] = 'WriteAPEtag() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $ape_writer->errors)).'</LI></UL></PRE>';
}
} else {
$this->errors[] = 'FormatDataForAPE() failed';
}
break;
case 'id3v1':
$id3v1_writer = new getid3_write_id3v1;
if (($id3v1_writer->tag_data = $this->FormatDataForID3v1()) !== false) {
$id3v1_writer->filename = $this->filename;
if (($success = $id3v1_writer->WriteID3v1()) === false) {
$this->errors[] = 'WriteID3v1() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $id3v1_writer->errors)).'</LI></UL></PRE>';
}
} else {
$this->errors[] = 'FormatDataForID3v1() failed';
}
break;
case 'id3v2.2':
case 'id3v2.3':
case 'id3v2.4':
$id3v2_writer = new getid3_write_id3v2;
$id3v2_writer->majorversion = intval(substr($tagformat, -1));
$id3v2_writer->paddedlength = $this->id3v2_paddedlength;
if (($id3v2_writer->tag_data = $this->FormatDataForID3v2($id3v2_writer->majorversion)) !== false) {
$id3v2_writer->filename = $this->filename;
if (($success = $id3v2_writer->WriteID3v2()) === false) {
$this->errors[] = 'WriteID3v2() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $id3v2_writer->errors)).'</LI></UL></PRE>';
}
} else {
$this->errors[] = 'FormatDataForID3v2() failed';
}
break;
case 'vorbiscomment':
$vorbiscomment_writer = new getid3_write_vorbiscomment;
if (($vorbiscomment_writer->tag_data = $this->FormatDataForVorbisComment()) !== false) {
$vorbiscomment_writer->filename = $this->filename;
if (($success = $vorbiscomment_writer->WriteVorbisComment()) === false) {
$this->errors[] = 'WriteVorbisComment() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $vorbiscomment_writer->errors)).'</LI></UL></PRE>';
}
} else {
$this->errors[] = 'FormatDataForVorbisComment() failed';
}
break;
case 'metaflac':
$metaflac_writer = new getid3_write_metaflac;
if (($metaflac_writer->tag_data = $this->FormatDataForMetaFLAC()) !== false) {
$metaflac_writer->filename = $this->filename;
if (($success = $metaflac_writer->WriteMetaFLAC()) === false) {
$this->errors[] = 'WriteMetaFLAC() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $metaflac_writer->errors)).'</LI></UL></PRE>';
}
} else {
$this->errors[] = 'FormatDataForMetaFLAC() failed';
}
break;
case 'real':
$real_writer = new getid3_write_real;
if (($real_writer->tag_data = $this->FormatDataForReal()) !== false) {
$real_writer->filename = $this->filename;
if (($success = $real_writer->WriteReal()) === false) {
$this->errors[] = 'WriteReal() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $real_writer->errors)).'</LI></UL></PRE>';
}
} else {
$this->errors[] = 'FormatDataForReal() failed';
}
break;
default:
$this->errors[] = 'Invalid tag format to write: "'.$tagformat.'"';
return false;
break;
}
if (!$success) {
return false;
}
}
return true;
}
function DeleteTags($TagFormatsToDelete) {
foreach ($TagFormatsToDelete as $DeleteTagFormat) {
$success = false; // overridden if tag deletion is successful
switch ($DeleteTagFormat) {
case 'id3v1':
$id3v1_writer = new getid3_write_id3v1;
$id3v1_writer->filename = $this->filename;
if (($success = $id3v1_writer->RemoveID3v1()) === false) {
$this->errors[] = 'RemoveID3v1() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $id3v1_writer->errors)).'</LI></UL></PRE>';
}
break;
case 'id3v2':
$id3v2_writer = new getid3_write_id3v2;
$id3v2_writer->filename = $this->filename;
if (($success = $id3v2_writer->RemoveID3v2()) === false) {
$this->errors[] = 'RemoveID3v2() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $id3v2_writer->errors)).'</LI></UL></PRE>';
}
break;
case 'ape':
$ape_writer = new getid3_write_apetag;
$ape_writer->filename = $this->filename;
if (($success = $ape_writer->DeleteAPEtag()) === false) {
$this->errors[] = 'DeleteAPEtag() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $ape_writer->errors)).'</LI></UL></PRE>';
}
break;
case 'vorbiscomment':
$vorbiscomment_writer = new getid3_write_vorbiscomment;
$vorbiscomment_writer->filename = $this->filename;
if (($success = $vorbiscomment_writer->DeleteVorbisComment()) === false) {
$this->errors[] = 'DeleteVorbisComment() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $vorbiscomment_writer->errors)).'</LI></UL></PRE>';
}
break;
case 'metaflac':
$metaflac_writer = new getid3_write_metaflac;
$metaflac_writer->filename = $this->filename;
if (($success = $metaflac_writer->DeleteMetaFLAC()) === false) {
$this->errors[] = 'DeleteMetaFLAC() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $metaflac_writer->errors)).'</LI></UL></PRE>';
}
break;
case 'lyrics3':
$lyrics3_writer = new getid3_write_lyrics3;
$lyrics3_writer->filename = $this->filename;
if (($success = $lyrics3_writer->DeleteLyrics3()) === false) {
$this->errors[] = 'DeleteLyrics3() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $lyrics3_writer->errors)).'</LI></UL></PRE>';
}
break;
case 'real':
$real_writer = new getid3_write_real;
$real_writer->filename = $this->filename;
if (($success = $real_writer->RemoveReal()) === false) {
$this->errors[] = 'RemoveReal() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $real_writer->errors)).'</LI></UL></PRE>';
}
break;
default:
$this->errors[] = 'Invalid tag format to delete: "'.$tagformat.'"';
return false;
break;
}
if (!$success) {
return false;
}
}
return true;
}
function MergeExistingTagData($TagFormat, &$tag_data) {
// Merge supplied data with existing data, if requested
if ($this->overwrite_tags) {
// do nothing - ignore previous data
} else {
if (!isset($this->ThisFileInfo['tags'][$TagFormat])) {
return false;
}
$tag_data = array_merge_recursive($tag_data, $this->ThisFileInfo['tags'][$TagFormat]);
}
return true;
}
function FormatDataForAPE() {
$ape_tag_data = array();
foreach ($this->tag_data as $tag_key => $valuearray) {
switch ($tag_key) {
case 'ATTACHED_PICTURE':
// ATTACHED_PICTURE is ID3v2 only - ignore
$this->warnings[] = '$data['.$tag_key.'] is assumed to be ID3v2 APIC data - NOT written to APE tag';
break;
default:
foreach ($valuearray as $key => $value) {
if (is_string($value) || is_numeric($value)) {
$ape_tag_data[$tag_key][$key] = getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-8', $value);
} else {
$this->warnings[] = '$data['.$tag_key.']['.$key.'] is not a string value - all of $data['.$tag_key.'] NOT written to APE tag';
unset($ape_tag_data[$tag_key]);
break;
}
}
break;
}
}
$this->MergeExistingTagData('ape', $ape_tag_data);
return $ape_tag_data;
}
function FormatDataForID3v1() {
$tag_data_id3v1['genreid'] = 255;
if (!empty($this->tag_data['GENRE'])) {
foreach ($this->tag_data['GENRE'] as $key => $value) {
if (getid3_id3v1::LookupGenreID($value) !== false) {
$tag_data_id3v1['genreid'] = getid3_id3v1::LookupGenreID($value);
break;
}
}
}
$tag_data_id3v1['title'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', @implode(' ', @$this->tag_data['TITLE']));
$tag_data_id3v1['artist'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', @implode(' ', @$this->tag_data['ARTIST']));
$tag_data_id3v1['album'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', @implode(' ', @$this->tag_data['ALBUM']));
$tag_data_id3v1['year'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', @implode(' ', @$this->tag_data['YEAR']));
$tag_data_id3v1['comment'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', @implode(' ', @$this->tag_data['COMMENT']));
$tag_data_id3v1['track'] = intval(getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', @implode(' ', @$this->tag_data['TRACKNUMBER'])));
if ($tag_data_id3v1['track'] <= 0) {
$tag_data_id3v1['track'] = '';
}
$this->MergeExistingTagData('id3v1', $tag_data_id3v1);
return $tag_data_id3v1;
}
function FormatDataForID3v2($id3v2_majorversion) {
$tag_data_id3v2 = array();
$ID3v2_text_encoding_lookup[2] = array('ISO-8859-1'=>0, 'UTF-16'=>1);
$ID3v2_text_encoding_lookup[3] = array('ISO-8859-1'=>0, 'UTF-16'=>1);
$ID3v2_text_encoding_lookup[4] = array('ISO-8859-1'=>0, 'UTF-16'=>1, 'UTF-16BE'=>2, 'UTF-8'=>3);
foreach ($this->tag_data as $tag_key => $valuearray) {
$ID3v2_framename = getid3_write_id3v2::ID3v2ShortFrameNameLookup($id3v2_majorversion, $tag_key);
switch ($ID3v2_framename) {
case 'APIC':
foreach ($valuearray as $key => $apic_data_array) {
if (isset($apic_data_array['data']) &&
isset($apic_data_array['picturetypeid']) &&
isset($apic_data_array['description']) &&
isset($apic_data_array['mime'])) {
$tag_data_id3v2['APIC'][] = $apic_data_array;
} else {
$this->errors[] = 'ID3v2 APIC data is not properly structured';
return false;
}
}
break;
case '':
$this->errors[] = 'ID3v2: Skipping "'.$tag_key.'" because cannot match it to a known ID3v2 frame type';
// some other data type, don't know how to handle it, ignore it
break;
default:
// most other (text) frames can be copied over as-is
foreach ($valuearray as $key => $value) {
if (isset($ID3v2_text_encoding_lookup[$id3v2_majorversion][$this->tag_encoding])) {
// source encoding is valid in ID3v2 - use it with no conversion
$tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = $ID3v2_text_encoding_lookup[$id3v2_majorversion][$this->tag_encoding];
$tag_data_id3v2[$ID3v2_framename][$key]['data'] = $value;
} else {
// source encoding is NOT valid in ID3v2 - convert it to an ID3v2-valid encoding first
if ($id3v2_majorversion < 4) {
// convert data from other encoding to UTF-16
$tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = 1;
$tag_data_id3v2[$ID3v2_framename][$key]['data'] = getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-16', $value);
} else {
// convert data from other encoding to UTF-8
$tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = 3;
$tag_data_id3v2[$ID3v2_framename][$key]['data'] = getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-8', $value);
}
}
// These values are not needed for all frame types, but if they're not used no matter
$tag_data_id3v2[$ID3v2_framename][$key]['description'] = '';
$tag_data_id3v2[$ID3v2_framename][$key]['language'] = $this->id3v2_tag_language;
}
break;
}
}
$this->MergeExistingTagData('id3v2', $tag_data_id3v2);
return $tag_data_id3v2;
}
function FormatDataForVorbisComment() {
$tag_data_vorbiscomment = $this->tag_data;
// check for multi-line comment values - split out to multiple comments if neccesary
// and convert data to UTF-8 strings
foreach ($tag_data_vorbiscomment as $tag_key => $valuearray) {
foreach ($valuearray as $key => $value) {
str_replace("\r", "\n", $value);
if (strstr($value, "\n")) {
unset($tag_data_vorbiscomment[$tag_key][$key]);
$multilineexploded = explode("\n", $value);
foreach ($multilineexploded as $newcomment) {
if (strlen(trim($newcomment)) > 0) {
$tag_data_vorbiscomment[$tag_key][] = getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-8', $newcomment);
}
}
} elseif (is_string($value) || is_numeric($value)) {
$tag_data_vorbiscomment[$tag_key][$key] = getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-8', $value);
} else {
$this->warnings[] = '$data['.$tag_key.']['.$key.'] is not a string value - all of $data['.$tag_key.'] NOT written to VorbisComment tag';
unset($tag_data_vorbiscomment[$tag_key]);
break;
}
}
}
$this->MergeExistingTagData('vorbiscomment', $tag_data_vorbiscomment);
return $tag_data_vorbiscomment;
}
function FormatDataForMetaFLAC() {
// FLAC & OggFLAC use VorbisComments same as OggVorbis
// but require metaflac to do the writing rather than vorbiscomment
return $this->FormatDataForVorbisComment();
}
function FormatDataForReal() {
$tag_data_real['title'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', @implode(' ', @$this->tag_data['TITLE']));
$tag_data_real['artist'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', @implode(' ', @$this->tag_data['ARTIST']));
$tag_data_real['copyright'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', @implode(' ', @$this->tag_data['COPYRIGHT']));
$tag_data_real['comment'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', @implode(' ', @$this->tag_data['COMMENT']));
$this->MergeExistingTagData('real', $tag_data_real);
return $tag_data_real;
}
}
?>

View File

@ -1,295 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// write.real.php //
// module for writing RealAudio/RealVideo tags //
// dependencies: module.tag.real.php //
// ///
/////////////////////////////////////////////////////////////////
class getid3_write_real
{
var $filename;
var $tag_data = array();
var $warnings = array(); // any non-critical errors will be stored here
var $errors = array(); // any critical errors will be stored here
var $paddedlength = 512; // minimum length of CONT tag in bytes
function getid3_write_real() {
return true;
}
function WriteReal() {
// File MUST be writeable - CHMOD(646) at least
if (is_writeable($this->filename)) {
if ($fp_source = @fopen($this->filename, 'r+b')) {
// Initialize getID3 engine
$getID3 = new getID3;
$OldThisFileInfo = $getID3->analyze($this->filename);
if (empty($OldThisFileInfo['real']['chunks']) && !empty($OldThisFileInfo['real']['old_ra_header'])) {
$this->errors[] = 'Cannot write Real tags on old-style file format';
fclose($fp_source);
return false;
}
if (empty($OldThisFileInfo['real']['chunks'])) {
$this->errors[] = 'Cannot write Real tags because cannot find DATA chunk in file';
fclose($fp_source);
return false;
}
foreach ($OldThisFileInfo['real']['chunks'] as $chunknumber => $chunkarray) {
$oldChunkInfo[$chunkarray['name']] = $chunkarray;
}
if (!empty($oldChunkInfo['CONT']['length'])) {
$this->paddedlength = max($oldChunkInfo['CONT']['length'], $this->paddedlength);
}
$new_CONT_tag_data = $this->GenerateCONTchunk();
$new_PROP_tag_data = $this->GeneratePROPchunk($OldThisFileInfo['real']['chunks'], $new_CONT_tag_data);
$new__RMF_tag_data = $this->GenerateRMFchunk($OldThisFileInfo['real']['chunks']);
if (@$oldChunkInfo['.RMF']['length'] == strlen($new__RMF_tag_data)) {
fseek($fp_source, $oldChunkInfo['.RMF']['offset'], SEEK_SET);
fwrite($fp_source, $new__RMF_tag_data);
} else {
$this->errors[] = 'new .RMF tag ('.strlen($new__RMF_tag_data).' bytes) different length than old .RMF tag ('.$oldChunkInfo['.RMF']['length'].' bytes)';
fclose($fp_source);
return false;
}
if (@$oldChunkInfo['PROP']['length'] == strlen($new_PROP_tag_data)) {
fseek($fp_source, $oldChunkInfo['PROP']['offset'], SEEK_SET);
fwrite($fp_source, $new_PROP_tag_data);
} else {
$this->errors[] = 'new PROP tag ('.strlen($new_PROP_tag_data).' bytes) different length than old PROP tag ('.$oldChunkInfo['PROP']['length'].' bytes)';
fclose($fp_source);
return false;
}
if (@$oldChunkInfo['CONT']['length'] == strlen($new_CONT_tag_data)) {
// new data length is same as old data length - just overwrite
fseek($fp_source, $oldChunkInfo['CONT']['offset'], SEEK_SET);
fwrite($fp_source, $new_CONT_tag_data);
fclose($fp_source);
return true;
} else {
if (empty($oldChunkInfo['CONT'])) {
// no existing CONT chunk
$BeforeOffset = $oldChunkInfo['DATA']['offset'];
$AfterOffset = $oldChunkInfo['DATA']['offset'];
} else {
// new data is longer than old data
$BeforeOffset = $oldChunkInfo['CONT']['offset'];
$AfterOffset = $oldChunkInfo['CONT']['offset'] + $oldChunkInfo['CONT']['length'];
}
if ($tempfilename = tempnam('*', 'getID3')) {
ob_start();
if ($fp_temp = fopen($tempfilename, 'wb')) {
rewind($fp_source);
fwrite($fp_temp, fread($fp_source, $BeforeOffset));
fwrite($fp_temp, $new_CONT_tag_data);
fseek($fp_source, $AfterOffset, SEEK_SET);
while ($buffer = fread($fp_source, GETID3_FREAD_BUFFER_SIZE)) {
fwrite($fp_temp, $buffer, strlen($buffer));
}
fclose($fp_temp);
if (copy($tempfilename, $this->filename)) {
unlink($tempfilename);
fclose($fp_source);
return true;
}
unlink($tempfilename);
$this->errors[] = 'FAILED: copy('.$tempfilename.', '.$this->filename.') - '.strip_tags(ob_get_contents());
} else {
$this->errors[] = 'Could not open '.$tempfilename.' mode "wb" - '.strip_tags(ob_get_contents());
}
ob_end_clean();
}
fclose($fp_source);
return false;
}
} else {
$this->errors[] = 'Could not open '.$this->filename.' mode "r+b"';
return false;
}
}
$this->errors[] = 'File is not writeable: '.$this->filename;
return false;
}
function GenerateRMFchunk(&$chunks) {
$oldCONTexists = false;
foreach ($chunks as $key => $chunk) {
$chunkNameKeys[$chunk['name']] = $key;
if ($chunk['name'] == 'CONT') {
$oldCONTexists = true;
}
}
$newHeadersCount = $chunks[$chunkNameKeys['.RMF']]['headers_count'] + ($oldCONTexists ? 0 : 1);
$RMFchunk = "\x00\x00"; // object version
$RMFchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['.RMF']]['file_version'], 4);
$RMFchunk .= getid3_lib::BigEndian2String($newHeadersCount, 4);
$RMFchunk = '.RMF'.getid3_lib::BigEndian2String(strlen($RMFchunk) + 8, 4).$RMFchunk; // .RMF chunk identifier + chunk length
return $RMFchunk;
}
function GeneratePROPchunk(&$chunks, &$new_CONT_tag_data) {
$old_CONT_length = 0;
$old_DATA_offset = 0;
$old_INDX_offset = 0;
foreach ($chunks as $key => $chunk) {
$chunkNameKeys[$chunk['name']] = $key;
if ($chunk['name'] == 'CONT') {
$old_CONT_length = $chunk['length'];
} elseif ($chunk['name'] == 'DATA') {
if (!$old_DATA_offset) {
$old_DATA_offset = $chunk['offset'];
}
} elseif ($chunk['name'] == 'INDX') {
if (!$old_INDX_offset) {
$old_INDX_offset = $chunk['offset'];
}
}
}
$CONTdelta = strlen($new_CONT_tag_data) - $old_CONT_length;
$PROPchunk = "\x00\x00"; // object version
$PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['max_bit_rate'], 4);
$PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['avg_bit_rate'], 4);
$PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['max_packet_size'], 4);
$PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['avg_packet_size'], 4);
$PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['num_packets'], 4);
$PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['duration'], 4);
$PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['preroll'], 4);
$PROPchunk .= getid3_lib::BigEndian2String(max(0, $old_INDX_offset + $CONTdelta), 4);
$PROPchunk .= getid3_lib::BigEndian2String(max(0, $old_DATA_offset + $CONTdelta), 4);
$PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['num_streams'], 2);
$PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['flags_raw'], 2);
$PROPchunk = 'PROP'.getid3_lib::BigEndian2String(strlen($PROPchunk) + 8, 4).$PROPchunk; // PROP chunk identifier + chunk length
return $PROPchunk;
}
function GenerateCONTchunk() {
foreach ($this->tag_data as $key => $value) {
// limit each value to 0xFFFF bytes
$this->tag_data[$key] = substr($value, 0, 65535);
}
$CONTchunk = "\x00\x00"; // object version
$CONTchunk .= getid3_lib::BigEndian2String(strlen(@$this->tag_data['title']), 2);
$CONTchunk .= @$this->tag_data['title'];
$CONTchunk .= getid3_lib::BigEndian2String(strlen(@$this->tag_data['artist']), 2);
$CONTchunk .= @$this->tag_data['artist'];
$CONTchunk .= getid3_lib::BigEndian2String(strlen(@$this->tag_data['copyright']), 2);
$CONTchunk .= @$this->tag_data['copyright'];
$CONTchunk .= getid3_lib::BigEndian2String(strlen(@$this->tag_data['comment']), 2);
$CONTchunk .= @$this->tag_data['comment'];
if ($this->paddedlength > (strlen($CONTchunk) + 8)) {
$CONTchunk .= str_repeat("\x00", $this->paddedlength - strlen($CONTchunk) - 8);
}
$CONTchunk = 'CONT'.getid3_lib::BigEndian2String(strlen($CONTchunk) + 8, 4).$CONTchunk; // CONT chunk identifier + chunk length
return $CONTchunk;
}
function RemoveReal() {
// File MUST be writeable - CHMOD(646) at least
if (is_writeable($this->filename)) {
if ($fp_source = @fopen($this->filename, 'r+b')) {
// Initialize getID3 engine
$getID3 = new getID3;
$OldThisFileInfo = $getID3->analyze($this->filename);
if (empty($OldThisFileInfo['real']['chunks']) && !empty($OldThisFileInfo['real']['old_ra_header'])) {
$this->errors[] = 'Cannot remove Real tags from old-style file format';
fclose($fp_source);
return false;
}
if (empty($OldThisFileInfo['real']['chunks'])) {
$this->errors[] = 'Cannot remove Real tags because cannot find DATA chunk in file';
fclose($fp_source);
return false;
}
foreach ($OldThisFileInfo['real']['chunks'] as $chunknumber => $chunkarray) {
$oldChunkInfo[$chunkarray['name']] = $chunkarray;
}
if (empty($oldChunkInfo['CONT'])) {
// no existing CONT chunk
fclose($fp_source);
return true;
}
$BeforeOffset = $oldChunkInfo['CONT']['offset'];
$AfterOffset = $oldChunkInfo['CONT']['offset'] + $oldChunkInfo['CONT']['length'];
if ($tempfilename = tempnam('*', 'getID3')) {
ob_start();
if ($fp_temp = fopen($tempfilename, 'wb')) {
rewind($fp_source);
fwrite($fp_temp, fread($fp_source, $BeforeOffset));
fseek($fp_source, $AfterOffset, SEEK_SET);
while ($buffer = fread($fp_source, GETID3_FREAD_BUFFER_SIZE)) {
fwrite($fp_temp, $buffer, strlen($buffer));
}
fclose($fp_temp);
if (copy($tempfilename, $this->filename)) {
unlink($tempfilename);
fclose($fp_source);
return true;
}
unlink($tempfilename);
$this->errors[] = 'FAILED: copy('.$tempfilename.', '.$this->filename.') - '.strip_tags(ob_get_contents());
} else {
$this->errors[] = 'Could not open '.$tempfilename.' mode "wb" - '.strip_tags(ob_get_contents());
}
ob_end_clean();
}
fclose($fp_source);
return false;
} else {
$this->errors[] = 'Could not open '.$this->filename.' mode "r+b"';
return false;
}
}
$this->errors[] = 'File is not writeable: '.$this->filename;
return false;
}
}
?>

View File

@ -1,124 +0,0 @@
<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// write.vorbiscomment.php //
// module for writing VorbisComment tags //
// dependencies: /helperapps/vorbiscomment.exe //
// ///
/////////////////////////////////////////////////////////////////
class getid3_write_vorbiscomment
{
var $filename;
var $tag_data;
var $warnings = array(); // any non-critical errors will be stored here
var $errors = array(); // any critical errors will be stored here
function getid3_write_vorbiscomment() {
return true;
}
function WriteVorbisComment() {
if (!ini_get('safe_mode')) {
// Create file with new comments
$tempcommentsfilename = tempnam('*', 'getID3');
if ($fpcomments = @fopen($tempcommentsfilename, 'wb')) {
foreach ($this->tag_data as $key => $value) {
foreach ($value as $commentdata) {
fwrite($fpcomments, $this->CleanVorbisCommentName($key).'='.$commentdata."\n");
}
}
fclose($fpcomments);
} else {
$this->errors[] = 'failed to open temporary tags file "'.$tempcommentsfilename.'", tags not written';
return false;
}
$oldignoreuserabort = ignore_user_abort(true);
if (GETID3_OS_ISWINDOWS) {
if (file_exists(GETID3_HELPERAPPSDIR.'vorbiscomment.exe')) {
//$commandline = '"'.GETID3_HELPERAPPSDIR.'vorbiscomment.exe" -w --raw -c "'.$tempcommentsfilename.'" "'.str_replace('/', '\\', $this->filename).'"';
// vorbiscomment works fine if you copy-paste the above commandline into a command prompt,
// but refuses to work with `backtick` if there are "doublequotes" present around BOTH
// the metaflac pathname and the target filename. For whatever reason...??
// The solution is simply ensure that the metaflac pathname has no spaces,
// and therefore does not need to be quoted
// On top of that, if error messages are not always captured properly under Windows
// To at least see if there was a problem, compare file modification timestamps before and after writing
clearstatcache();
$timestampbeforewriting = filemtime($this->filename);
$commandline = GETID3_HELPERAPPSDIR.'vorbiscomment.exe -w --raw -c "'.$tempcommentsfilename.'" "'.$this->filename.'" 2>&1';
$VorbiscommentError = `$commandline`;
if (empty($VorbiscommentError)) {
clearstatcache();
if ($timestampbeforewriting == filemtime($this->filename)) {
$VorbiscommentError = 'File modification timestamp has not changed - it looks like the tags were not written';
}
}
} else {
$VorbiscommentError = 'vorbiscomment.exe not found in '.GETID3_HELPERAPPSDIR;
}
} else {
$commandline = 'vorbiscomment -w --raw -c "'.$tempcommentsfilename.'" "'.$this->filename.'" 2>&1';
$VorbiscommentError = `$commandline`;
}
// Remove temporary comments file
unlink($tempcommentsfilename);
ignore_user_abort($oldignoreuserabort);
if (!empty($VorbiscommentError)) {
$this->errors[] = 'system call to vorbiscomment failed with message: '."\n\n".$VorbiscommentError;
return false;
}
return true;
}
$this->errors[] = 'PHP running in Safe Mode (backtick operator not available) - cannot call vorbiscomment, tags not written';
return false;
}
function DeleteVorbisComment() {
$this->tag_data = array(array());
return $this->WriteVorbisComment();
}
function CleanVorbisCommentName($originalcommentname) {
// A case-insensitive field name that may consist of ASCII 0x20 through 0x7D, 0x3D ('=') excluded.
// ASCII 0x41 through 0x5A inclusive (A-Z) is to be considered equivalent to ASCII 0x61 through
// 0x7A inclusive (a-z).
// replace invalid chars with a space, return uppercase text
// Thanks Chris Bolt <chris-getid3Øbolt*cx> for improving this function
// note: ereg_replace() replaces nulls with empty string (not space)
return strtoupper(ereg_replace('[^ -<>-}]', ' ', str_replace("\x00", ' ', $originalcommentname)));
}
}
?>

View File

@ -1,274 +0,0 @@
<?php
/**
* $Header$
* $Horde: horde/lib/Log/composite.php,v 1.2 2000/06/28 21:36:13 jon Exp $
*
* @version $Revision: 303597 $
* @package Log
*/
/**
* The Log_composite:: class implements a Composite pattern which
* allows multiple Log implementations to receive the same events.
*
* @author Chuck Hagenbuch <chuck@horde.org>
* @author Jon Parise <jon@php.net>
*
* @since Horde 1.3
* @since Log 1.0
* @package Log
*
* @example composite.php Using the composite handler.
*/
class Log_composite extends Log
{
/**
* Array holding all of the Log instances to which log events should be
* sent.
*
* @var array
* @access private
*/
var $_children = array();
/**
* Constructs a new composite Log object.
*
* @param boolean $name This parameter is ignored.
* @param boolean $ident This parameter is ignored.
* @param boolean $conf This parameter is ignored.
* @param boolean $level This parameter is ignored.
*
* @access public
*/
function Log_composite($name, $ident = '', $conf = array(),
$level = PEAR_LOG_DEBUG)
{
$this->_ident = $ident;
}
/**
* Opens all of the child instances.
*
* @return True if all of the child instances were successfully opened.
*
* @access public
*/
function open()
{
/* Attempt to open each of our children. */
$this->_opened = true;
foreach ($this->_children as $child) {
$this->_opened &= $child->open();
}
/* If all children were opened, return success. */
return $this->_opened;
}
/**
* Closes all open child instances.
*
* @return True if all of the opened child instances were successfully
* closed.
*
* @access public
*/
function close()
{
/* If we haven't been opened, there's nothing more to do. */
if (!$this->_opened) {
return true;
}
/* Attempt to close each of our children. */
$closed = true;
foreach ($this->_children as $child) {
if ($child->_opened) {
$closed &= $child->close();
}
}
/* Clear the opened state for consistency. */
$this->_opened = false;
/* If all children were closed, return success. */
return $closed;
}
/**
* Flushes all child instances. It is assumed that all of the children
* have been successfully opened.
*
* @return True if all of the child instances were successfully flushed.
*
* @access public
* @since Log 1.8.2
*/
function flush()
{
/* Attempt to flush each of our children. */
$flushed = true;
foreach ($this->_children as $child) {
$flushed &= $child->flush();
}
/* If all children were flushed, return success. */
return $flushed;
}
/**
* Sends $message and $priority to each child of this composite. If the
* appropriate children aren't already open, they will be opened here.
*
* @param mixed $message String or object containing the message
* to log.
* @param string $priority (optional) The priority of the message.
* Valid values are: PEAR_LOG_EMERG,
* PEAR_LOG_ALERT, PEAR_LOG_CRIT,
* PEAR_LOG_ERR, PEAR_LOG_WARNING,
* PEAR_LOG_NOTICE, PEAR_LOG_INFO, and
* PEAR_LOG_DEBUG.
*
* @return boolean True if the entry is successfully logged.
*
* @access public
*/
function log($message, $priority = null)
{
/* If a priority hasn't been specified, use the default value. */
if ($priority === null) {
$priority = $this->_priority;
}
/*
* Abort early if the priority is above the composite handler's
* maximum logging level.
*
* XXX: Consider whether or not introducing this change would break
* backwards compatibility. Some users may be expecting composite
* handlers to pass on all events to their children regardless of
* their own priority.
*/
#if (!$this->_isMasked($priority)) {
# return false;
#}
/*
* Iterate over all of our children. If a unopened child will respond
* to this log event, we attempt to open it immediately. The composite
* handler's opened state will be enabled as soon as the first child
* handler is successfully opened.
*
* We track an overall success state that indicates whether or not all
* of the relevant child handlers were opened and successfully logged
* the event. If one handler fails, we still attempt any remaining
* children, but we consider the overall result a failure.
*/
$success = true;
foreach ($this->_children as $child) {
/* If this child won't respond to this event, skip it. */
if (!$child->_isMasked($priority)) {
continue;
}
/* If this child has yet to be opened, attempt to do so now. */
if (!$child->_opened) {
$success &= $child->open();
/*
* If we've successfully opened our first handler, the
* composite handler itself is considered to be opened.
*/
if (!$this->_opened && $success) {
$this->_opened = true;
}
}
/* Finally, attempt to log the message to the child handler. */
if ($child->_opened) {
$success &= $child->log($message, $priority);
}
}
/* Notify the observers. */
$this->_announce(array('priority' => $priority, 'message' => $message));
/* Return success if all of the open children logged the event. */
return $success;
}
/**
* Returns true if this is a composite.
*
* @return boolean True if this is a composite class.
*
* @access public
*/
function isComposite()
{
return true;
}
/**
* Sets this identification string for all of this composite's children.
*
* @param string $ident The new identification string.
*
* @access public
* @since Log 1.6.7
*/
function setIdent($ident)
{
/* Call our base class's setIdent() method. */
parent::setIdent($ident);
/* ... and then call setIdent() on all of our children. */
foreach ($this->_children as $child) {
$child->setIdent($ident);
}
}
/**
* Adds a Log instance to the list of children.
*
* @param object $child The Log instance to add.
*
* @return boolean True if the Log instance was successfully added.
*
* @access public
*/
function addChild(&$child)
{
/* Make sure this is a Log instance. */
if (!is_a($child, 'Log')) {
return false;
}
$this->_children[$child->_id] = &$child;
return true;
}
/**
* Removes a Log instance from the list of children.
*
* @param object $child The Log instance to remove.
*
* @return boolean True if the Log instance was successfully removed.
*
* @access public
*/
function removeChild($child)
{
if (!is_a($child, 'Log') || !isset($this->_children[$child->_id])) {
return false;
}
unset($this->_children[$child->_id]);
return true;
}
}

View File

@ -1,208 +0,0 @@
<?php
/**
* $Header$
*
* @version $Revision: 224513 $
* @package Log
*/
/**
* The Log_console class is a concrete implementation of the Log::
* abstract class which writes message to the text console.
*
* @author Jon Parise <jon@php.net>
* @since Log 1.1
* @package Log
*
* @example console.php Using the console handler.
*/
class Log_console extends Log
{
/**
* Handle to the current output stream.
* @var resource
* @access private
*/
var $_stream = STDOUT;
/**
* Should the output be buffered or displayed immediately?
* @var string
* @access private
*/
var $_buffering = false;
/**
* String holding the buffered output.
* @var string
* @access private
*/
var $_buffer = '';
/**
* String containing the format of a log line.
* @var string
* @access private
*/
var $_lineFormat = '%1$s %2$s [%3$s] %4$s';
/**
* String containing the timestamp format. It will be passed directly to
* strftime(). Note that the timestamp string will generated using the
* current locale.
* @var string
* @access private
*/
var $_timeFormat = '%b %d %H:%M:%S';
/**
* Constructs a new Log_console object.
*
* @param string $name Ignored.
* @param string $ident The identity string.
* @param array $conf The configuration array.
* @param int $level Log messages up to and including this level.
* @access public
*/
function Log_console($name, $ident = '', $conf = array(),
$level = PEAR_LOG_DEBUG)
{
$this->_id = md5(microtime());
$this->_ident = $ident;
$this->_mask = Log::UPTO($level);
if (!empty($conf['stream'])) {
$this->_stream = $conf['stream'];
}
if (isset($conf['buffering'])) {
$this->_buffering = $conf['buffering'];
}
if (!empty($conf['lineFormat'])) {
$this->_lineFormat = str_replace(array_keys($this->_formatMap),
array_values($this->_formatMap),
$conf['lineFormat']);
}
if (!empty($conf['timeFormat'])) {
$this->_timeFormat = $conf['timeFormat'];
}
/*
* If output buffering has been requested, we need to register a
* shutdown function that will dump the buffer upon termination.
*/
if ($this->_buffering) {
register_shutdown_function(array(&$this, '_Log_console'));
}
}
/**
* Destructor
*/
function _Log_console()
{
$this->close();
}
/**
* Open the output stream.
*
* @access public
* @since Log 1.9.7
*/
function open()
{
$this->_opened = true;
return true;
}
/**
* Closes the output stream.
*
* This results in a call to flush().
*
* @access public
* @since Log 1.9.0
*/
function close()
{
$this->flush();
$this->_opened = false;
return true;
}
/**
* Flushes all pending ("buffered") data to the output stream.
*
* @access public
* @since Log 1.8.2
*/
function flush()
{
/*
* If output buffering is enabled, dump the contents of the buffer to
* the output stream.
*/
if ($this->_buffering && (strlen($this->_buffer) > 0)) {
fwrite($this->_stream, $this->_buffer);
$this->_buffer = '';
}
if (is_resource($this->_stream)) {
return fflush($this->_stream);
}
return false;
}
/**
* Writes $message to the text console. Also, passes the message
* along to any Log_observer instances that are observing this Log.
*
* @param mixed $message String or object containing the message to log.
* @param string $priority The priority of the message. Valid
* values are: PEAR_LOG_EMERG, PEAR_LOG_ALERT,
* PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
* PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
* @return boolean True on success or false on failure.
* @access public
*/
function log($message, $priority = null)
{
/* If a priority hasn't been specified, use the default value. */
if ($priority === null) {
$priority = $this->_priority;
}
/* Abort early if the priority is above the maximum logging level. */
if (!$this->_isMasked($priority)) {
return false;
}
/* Extract the string representation of the message. */
$message = $this->_extractMessage($message);
/* Build the string containing the complete log line. */
$line = $this->_format($this->_lineFormat,
strftime($this->_timeFormat),
$priority, $message) . "\n";
/*
* If buffering is enabled, append this line to the output buffer.
* Otherwise, print the line to the output stream immediately.
*/
if ($this->_buffering) {
$this->_buffer .= $line;
} else {
fwrite($this->_stream, $line);
}
/* Notify observers about this log message. */
$this->_announce(array('priority' => $priority, 'message' => $message));
return true;
}
}

View File

@ -1,235 +0,0 @@
<?php
/**
* $Header$
*
* @version $Revision: 250926 $
* @package Log
*/
/**
* The Log_daemon class is a concrete implementation of the Log::
* abstract class which sends messages to syslog daemon on UNIX-like machines.
* This class uses the syslog protocol: http://www.ietf.org/rfc/rfc3164.txt
*
* @author Bart van der Schans <schans@dds.nl>
* @version $Revision: 250926 $
* @package Log
*/
class Log_daemon extends Log
{
/**
* Integer holding the log facility to use.
* @var string
*/
var $_name = LOG_DAEMON;
/**
* Var holding the resource pointer to the socket
* @var resource
*/
var $_socket;
/**
* The ip address or servername
* @see http://www.php.net/manual/en/transports.php
* @var string
*/
var $_ip = '127.0.0.1';
/**
* Protocol to use (tcp, udp, etc.)
* @see http://www.php.net/manual/en/transports.php
* @var string
*/
var $_proto = 'udp';
/**
* Port to connect to
* @var int
*/
var $_port = 514;
/**
* Maximum message length in bytes
* @var int
*/
var $_maxsize = 4096;
/**
* Socket timeout in seconds
* @var int
*/
var $_timeout = 1;
/**
* Constructs a new syslog object.
*
* @param string $name The syslog facility.
* @param string $ident The identity string.
* @param array $conf The configuration array.
* @param int $maxLevel Maximum level at which to log.
* @access public
*/
function Log_daemon($name, $ident = '', $conf = array(),
$level = PEAR_LOG_DEBUG)
{
/* Ensure we have a valid integer value for $name. */
if (empty($name) || !is_int($name)) {
$name = LOG_SYSLOG;
}
$this->_id = md5(microtime());
$this->_name = $name;
$this->_ident = $ident;
$this->_mask = Log::UPTO($level);
if (isset($conf['ip'])) {
$this->_ip = $conf['ip'];
}
if (isset($conf['proto'])) {
$this->_proto = $conf['proto'];
}
if (isset($conf['port'])) {
$this->_port = $conf['port'];
}
if (isset($conf['maxsize'])) {
$this->_maxsize = $conf['maxsize'];
}
if (isset($conf['timeout'])) {
$this->_timeout = $conf['timeout'];
}
$this->_proto = $this->_proto . '://';
register_shutdown_function(array(&$this, '_Log_daemon'));
}
/**
* Destructor.
*
* @access private
*/
function _Log_daemon()
{
$this->close();
}
/**
* Opens a connection to the system logger, if it has not already
* been opened. This is implicitly called by log(), if necessary.
* @access public
*/
function open()
{
if (!$this->_opened) {
$this->_opened = (bool)($this->_socket = @fsockopen(
$this->_proto . $this->_ip,
$this->_port,
$errno,
$errstr,
$this->_timeout));
}
return $this->_opened;
}
/**
* Closes the connection to the system logger, if it is open.
* @access public
*/
function close()
{
if ($this->_opened) {
$this->_opened = false;
return fclose($this->_socket);
}
return true;
}
/**
* Sends $message to the currently open syslog connection. Calls
* open() if necessary. Also passes the message along to any Log_observer
* instances that are observing this Log.
*
* @param string $message The textual message to be logged.
* @param int $priority (optional) The priority of the message. Valid
* values are: LOG_EMERG, LOG_ALERT, LOG_CRIT,
* LOG_ERR, LOG_WARNING, LOG_NOTICE, LOG_INFO,
* and LOG_DEBUG. The default is LOG_INFO.
* @access public
*/
function log($message, $priority = null)
{
/* If a priority hasn't been specified, use the default value. */
if ($priority === null) {
$priority = $this->_priority;
}
/* Abort early if the priority is above the maximum logging level. */
if (!$this->_isMasked($priority)) {
return false;
}
/* If the connection isn't open and can't be opened, return failure. */
if (!$this->_opened && !$this->open()) {
return false;
}
/* Extract the string representation of the message. */
$message = $this->_extractMessage($message);
/* Set the facility level. */
$facility_level = intval($this->_name) +
intval($this->_toSyslog($priority));
/* Prepend ident info. */
if (!empty($this->_ident)) {
$message = $this->_ident . ' ' . $message;
}
/* Check for message length. */
if (strlen($message) > $this->_maxsize) {
$message = substr($message, 0, ($this->_maxsize) - 10) . ' [...]';
}
/* Write to socket. */
fwrite($this->_socket, '<' . $facility_level . '>' . $message . "\n");
$this->_announce(array('priority' => $priority, 'message' => $message));
}
/**
* Converts a PEAR_LOG_* constant into a syslog LOG_* constant.
*
* This function exists because, under Windows, not all of the LOG_*
* constants have unique values. Instead, the PEAR_LOG_* were introduced
* for global use, with the conversion to the LOG_* constants kept local to
* to the syslog driver.
*
* @param int $priority PEAR_LOG_* value to convert to LOG_* value.
*
* @return The LOG_* representation of $priority.
*
* @access private
*/
function _toSyslog($priority)
{
static $priorities = array(
PEAR_LOG_EMERG => LOG_EMERG,
PEAR_LOG_ALERT => LOG_ALERT,
PEAR_LOG_CRIT => LOG_CRIT,
PEAR_LOG_ERR => LOG_ERR,
PEAR_LOG_WARNING => LOG_WARNING,
PEAR_LOG_NOTICE => LOG_NOTICE,
PEAR_LOG_INFO => LOG_INFO,
PEAR_LOG_DEBUG => LOG_DEBUG
);
/* If we're passed an unknown priority, default to LOG_INFO. */
if (!is_int($priority) || !in_array($priority, $priorities)) {
return LOG_INFO;
}
return $priorities[$priority];
}
}

View File

@ -1,161 +0,0 @@
<?php
/**
* $Header$
*
* @version $Revision: 255603 $
* @package Log
*/
/**
* The Log_display class is a concrete implementation of the Log::
* abstract class which writes message into browser in usual PHP maner.
* This may be useful because when you use PEAR::setErrorHandling in
* PEAR_ERROR_CALLBACK mode error messages are not displayed by
* PHP error handler.
*
* @author Paul Yanchenko <pusher@inaco.ru>
* @since Log 1.8.0
* @package Log
*
* @example display.php Using the display handler.
*/
class Log_display extends Log
{
/**
* String containing the format of a log line.
* @var string
* @access private
*/
var $_lineFormat = '<b>%3$s</b>: %4$s';
/**
* String containing the timestamp format. It will be passed directly to
* strftime(). Note that the timestamp string will generated using the
* current locale.
* @var string
* @access private
*/
var $_timeFormat = '%b %d %H:%M:%S';
/**
* Constructs a new Log_display object.
*
* @param string $name Ignored.
* @param string $ident The identity string.
* @param array $conf The configuration array.
* @param int $level Log messages up to and including this level.
* @access public
*/
function Log_display($name = '', $ident = '', $conf = array(),
$level = PEAR_LOG_DEBUG)
{
$this->_id = md5(microtime());
$this->_ident = $ident;
$this->_mask = Log::UPTO($level);
/* Start by configuring the line format. */
if (!empty($conf['lineFormat'])) {
$this->_lineFormat = str_replace(array_keys($this->_formatMap),
array_values($this->_formatMap),
$conf['lineFormat']);
}
/* We may need to prepend a string to our line format. */
$prepend = null;
if (isset($conf['error_prepend'])) {
$prepend = $conf['error_prepend'];
} else {
$prepend = ini_get('error_prepend_string');
}
if (!empty($prepend)) {
$this->_lineFormat = $prepend . $this->_lineFormat;
}
/* We may also need to append a string to our line format. */
$append = null;
if (isset($conf['error_append'])) {
$append = $conf['error_append'];
} else {
$append = ini_get('error_append_string');
}
if (!empty($append)) {
$this->_lineFormat .= $append;
}
/* Lastly, the line ending sequence is also configurable. */
if (isset($conf['linebreak'])) {
$this->_lineFormat .= $conf['linebreak'];
} else {
$this->_lineFormat .= "<br />\n";
}
/* The user can also change the time format. */
if (!empty($conf['timeFormat'])) {
$this->_timeFormat = $conf['timeFormat'];
}
}
/**
* Opens the display handler.
*
* @access public
* @since Log 1.9.6
*/
function open()
{
$this->_opened = true;
return true;
}
/**
* Closes the display handler.
*
* @access public
* @since Log 1.9.6
*/
function close()
{
$this->_opened = false;
return true;
}
/**
* Writes $message to the text browser. Also, passes the message
* along to any Log_observer instances that are observing this Log.
*
* @param mixed $message String or object containing the message to log.
* @param string $priority The priority of the message. Valid
* values are: PEAR_LOG_EMERG, PEAR_LOG_ALERT,
* PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
* PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
* @return boolean True on success or false on failure.
* @access public
*/
function log($message, $priority = null)
{
/* If a priority hasn't been specified, use the default value. */
if ($priority === null) {
$priority = $this->_priority;
}
/* Abort early if the priority is above the maximum logging level. */
if (!$this->_isMasked($priority)) {
return false;
}
/* Extract the string representation of the message. */
$message = $this->_extractMessage($message);
/* Build and output the complete log line. */
echo $this->_format($this->_lineFormat,
strftime($this->_timeFormat),
$priority,
nl2br(htmlspecialchars($message)));
/* Notify observers about this log message. */
$this->_announce(array('priority' => $priority, 'message' => $message));
return true;
}
}

View File

@ -1,160 +0,0 @@
<?php
/**
* $Header$
*
* @version $Revision: 293927 $
* @package Log
*/
/**
* The Log_error_log class is a concrete implementation of the Log abstract
* class that logs messages using PHP's error_log() function.
*
* @author Jon Parise <jon@php.net>
* @since Log 1.7.0
* @package Log
*
* @example error_log.php Using the error_log handler.
*/
class Log_error_log extends Log
{
/**
* The error_log() log type.
* @var integer
* @access private
*/
var $_type = PEAR_LOG_TYPE_SYSTEM;
/**
* The type-specific destination value.
* @var string
* @access private
*/
var $_destination = '';
/**
* Additional headers to pass to the mail() function when the
* PEAR_LOG_TYPE_MAIL type is used.
* @var string
* @access private
*/
var $_extra_headers = '';
/**
* String containing the format of a log line.
* @var string
* @access private
*/
var $_lineFormat = '%2$s: %4$s';
/**
* String containing the timestamp format. It will be passed directly to
* strftime(). Note that the timestamp string will generated using the
* current locale.
* @var string
* @access private
*/
var $_timeFormat = '%b %d %H:%M:%S';
/**
* Constructs a new Log_error_log object.
*
* @param string $name One of the PEAR_LOG_TYPE_* constants.
* @param string $ident The identity string.
* @param array $conf The configuration array.
* @param int $level Log messages up to and including this level.
* @access public
*/
function Log_error_log($name, $ident = '', $conf = array(),
$level = PEAR_LOG_DEBUG)
{
$this->_id = md5(microtime());
$this->_type = $name;
$this->_ident = $ident;
$this->_mask = Log::UPTO($level);
if (!empty($conf['destination'])) {
$this->_destination = $conf['destination'];
}
if (!empty($conf['extra_headers'])) {
$this->_extra_headers = $conf['extra_headers'];
}
if (!empty($conf['lineFormat'])) {
$this->_lineFormat = str_replace(array_keys($this->_formatMap),
array_values($this->_formatMap),
$conf['lineFormat']);
}
if (!empty($conf['timeFormat'])) {
$this->_timeFormat = $conf['timeFormat'];
}
}
/**
* Opens the handler.
*
* @access public
* @since Log 1.9.6
*/
function open()
{
$this->_opened = true;
return true;
}
/**
* Closes the handler.
*
* @access public
* @since Log 1.9.6
*/
function close()
{
$this->_opened = false;
return true;
}
/**
* Logs $message using PHP's error_log() function. The message is also
* passed along to any Log_observer instances that are observing this Log.
*
* @param mixed $message String or object containing the message to log.
* @param string $priority The priority of the message. Valid
* values are: PEAR_LOG_EMERG, PEAR_LOG_ALERT,
* PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
* PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
* @return boolean True on success or false on failure.
* @access public
*/
function log($message, $priority = null)
{
/* If a priority hasn't been specified, use the default value. */
if ($priority === null) {
$priority = $this->_priority;
}
/* Abort early if the priority is above the maximum logging level. */
if (!$this->_isMasked($priority)) {
return false;
}
/* Extract the string representation of the message. */
$message = $this->_extractMessage($message);
/* Build the string containing the complete log line. */
$line = $this->_format($this->_lineFormat,
strftime($this->_timeFormat),
$priority, $message);
/* Pass the log line and parameters to the error_log() function. */
$success = error_log($line, $this->_type, $this->_destination,
$this->_extra_headers);
$this->_announce(array('priority' => $priority, 'message' => $message));
return $success;
}
}

View File

@ -1,316 +0,0 @@
<?php
/**
* $Header$
*
* @version $Revision: 224513 $
* @package Log
*/
/**
* The Log_file class is a concrete implementation of the Log abstract
* class that logs messages to a text file.
*
* @author Jon Parise <jon@php.net>
* @author Roman Neuhauser <neuhauser@bellavista.cz>
* @since Log 1.0
* @package Log
*
* @example file.php Using the file handler.
*/
class Log_file extends Log
{
/**
* String containing the name of the log file.
* @var string
* @access private
*/
var $_filename = 'php.log';
/**
* Handle to the log file.
* @var resource
* @access private
*/
var $_fp = false;
/**
* Should new log entries be append to an existing log file, or should the
* a new log file overwrite an existing one?
* @var boolean
* @access private
*/
var $_append = true;
/**
* Should advisory file locking (i.e., flock()) be used?
* @var boolean
* @access private
*/
var $_locking = false;
/**
* Integer (in octal) containing the log file's permissions mode.
* @var integer
* @access private
*/
var $_mode = 0644;
/**
* Integer (in octal) specifying the file permission mode that will be
* used when creating directories that do not already exist.
* @var integer
* @access private
*/
var $_dirmode = 0755;
/**
* String containing the format of a log line.
* @var string
* @access private
*/
var $_lineFormat = '%1$s %2$s [%3$s] %4$s';
/**
* String containing the timestamp format. It will be passed directly to
* strftime(). Note that the timestamp string will generated using the
* current locale.
* @var string
* @access private
*/
var $_timeFormat = '%b %d %H:%M:%S';
/**
* String containing the end-on-line character sequence.
* @var string
* @access private
*/
var $_eol = "\n";
/**
* Constructs a new Log_file object.
*
* @param string $name Ignored.
* @param string $ident The identity string.
* @param array $conf The configuration array.
* @param int $level Log messages up to and including this level.
* @access public
*/
function Log_file($name, $ident = '', $conf = array(),
$level = PEAR_LOG_DEBUG)
{
$this->_id = md5(microtime());
$this->_filename = $name;
$this->_ident = $ident;
$this->_mask = Log::UPTO($level);
if (isset($conf['append'])) {
$this->_append = $conf['append'];
}
if (isset($conf['locking'])) {
$this->_locking = $conf['locking'];
}
if (!empty($conf['mode'])) {
if (is_string($conf['mode'])) {
$this->_mode = octdec($conf['mode']);
} else {
$this->_mode = $conf['mode'];
}
}
if (!empty($conf['dirmode'])) {
if (is_string($conf['dirmode'])) {
$this->_dirmode = octdec($conf['dirmode']);
} else {
$this->_dirmode = $conf['dirmode'];
}
}
if (!empty($conf['lineFormat'])) {
$this->_lineFormat = str_replace(array_keys($this->_formatMap),
array_values($this->_formatMap),
$conf['lineFormat']);
}
if (!empty($conf['timeFormat'])) {
$this->_timeFormat = $conf['timeFormat'];
}
if (!empty($conf['eol'])) {
$this->_eol = $conf['eol'];
} else {
$this->_eol = (strstr(PHP_OS, 'WIN')) ? "\r\n" : "\n";
}
register_shutdown_function(array(&$this, '_Log_file'));
}
/**
* Destructor
*/
function _Log_file()
{
if ($this->_opened) {
$this->close();
}
}
/**
* Creates the given directory path. If the parent directories don't
* already exist, they will be created, too.
*
* This implementation is inspired by Python's os.makedirs function.
*
* @param string $path The full directory path to create.
* @param integer $mode The permissions mode with which the
* directories will be created.
*
* @return True if the full path is successfully created or already
* exists.
*
* @access private
*/
function _mkpath($path, $mode = 0700)
{
/* Separate the last pathname component from the rest of the path. */
$head = dirname($path);
$tail = basename($path);
/* Make sure we've split the path into two complete components. */
if (empty($tail)) {
$head = dirname($path);
$tail = basename($path);
}
/* Recurse up the path if our current segment does not exist. */
if (!empty($head) && !empty($tail) && !is_dir($head)) {
$this->_mkpath($head, $mode);
}
/* Create this segment of the path. */
return @mkdir($head, $mode);
}
/**
* Opens the log file for output. If the specified log file does not
* already exist, it will be created. By default, new log entries are
* appended to the end of the log file.
*
* This is implicitly called by log(), if necessary.
*
* @access public
*/
function open()
{
if (!$this->_opened) {
/* If the log file's directory doesn't exist, create it. */
if (!is_dir(dirname($this->_filename))) {
$this->_mkpath($this->_filename, $this->_dirmode);
}
/* Determine whether the log file needs to be created. */
$creating = !file_exists($this->_filename);
/* Obtain a handle to the log file. */
$this->_fp = fopen($this->_filename, ($this->_append) ? 'a' : 'w');
/* We consider the file "opened" if we have a valid file pointer. */
$this->_opened = ($this->_fp !== false);
/* Attempt to set the file's permissions if we just created it. */
if ($creating && $this->_opened) {
chmod($this->_filename, $this->_mode);
}
}
return $this->_opened;
}
/**
* Closes the log file if it is open.
*
* @access public
*/
function close()
{
/* If the log file is open, close it. */
if ($this->_opened && fclose($this->_fp)) {
$this->_opened = false;
}
return ($this->_opened === false);
}
/**
* Flushes all pending data to the file handle.
*
* @access public
* @since Log 1.8.2
*/
function flush()
{
if (is_resource($this->_fp)) {
return fflush($this->_fp);
}
return false;
}
/**
* Logs $message to the output window. The message is also passed along
* to any Log_observer instances that are observing this Log.
*
* @param mixed $message String or object containing the message to log.
* @param string $priority The priority of the message. Valid
* values are: PEAR_LOG_EMERG, PEAR_LOG_ALERT,
* PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
* PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
* @return boolean True on success or false on failure.
* @access public
*/
function log($message, $priority = null)
{
/* If a priority hasn't been specified, use the default value. */
if ($priority === null) {
$priority = $this->_priority;
}
/* Abort early if the priority is above the maximum logging level. */
if (!$this->_isMasked($priority)) {
return false;
}
/* If the log file isn't already open, open it now. */
if (!$this->_opened && !$this->open()) {
return false;
}
/* Extract the string representation of the message. */
$message = $this->_extractMessage($message);
/* Build the string containing the complete log line. */
$line = $this->_format($this->_lineFormat,
strftime($this->_timeFormat),
$priority, $message) . $this->_eol;
/* If locking is enabled, acquire an exclusive lock on the file. */
if ($this->_locking) {
flock($this->_fp, LOCK_EX);
}
/* Write the log line to the log file. */
$success = (fwrite($this->_fp, $line) !== false);
/* Unlock the file now that we're finished writing to it. */
if ($this->_locking) {
flock($this->_fp, LOCK_UN);
}
/* Notify observers about this log message. */
$this->_announce(array('priority' => $priority, 'message' => $message));
return $success;
}
}

View File

@ -1,214 +0,0 @@
<?php
/**
* $Header$
*
* @version $Revision: 250923 $
* @package Log
*/
/**
* The Log_firebug class is a concrete implementation of the Log::
* abstract class which writes message into Firebug console.
*
* http://www.getfirebug.com/
*
* @author Mika Tuupola <tuupola@appelsiini.net>
* @since Log 1.9.11
* @package Log
*
* @example firebug.php Using the firebug handler.
*/
class Log_firebug extends Log
{
/**
* Should the output be buffered or displayed immediately?
* @var string
* @access private
*/
var $_buffering = false;
/**
* String holding the buffered output.
* @var string
* @access private
*/
var $_buffer = array();
/**
* String containing the format of a log line.
* @var string
* @access private
*/
var $_lineFormat = '%2$s [%3$s] %4$s';
/**
* String containing the timestamp format. It will be passed directly to
* strftime(). Note that the timestamp string will generated using the
* current locale.
*
* Note! Default lineFormat of this driver does not display time.
*
* @var string
* @access private
*/
var $_timeFormat = '%b %d %H:%M:%S';
/**
* Mapping of log priorities to Firebug methods.
* @var array
* @access private
*/
var $_methods = array(
PEAR_LOG_EMERG => 'error',
PEAR_LOG_ALERT => 'error',
PEAR_LOG_CRIT => 'error',
PEAR_LOG_ERR => 'error',
PEAR_LOG_WARNING => 'warn',
PEAR_LOG_NOTICE => 'info',
PEAR_LOG_INFO => 'info',
PEAR_LOG_DEBUG => 'debug'
);
/**
* Constructs a new Log_firebug object.
*
* @param string $name Ignored.
* @param string $ident The identity string.
* @param array $conf The configuration array.
* @param int $level Log messages up to and including this level.
* @access public
*/
function Log_firebug($name = '', $ident = 'PHP', $conf = array(),
$level = PEAR_LOG_DEBUG)
{
$this->_id = md5(microtime());
$this->_ident = $ident;
$this->_mask = Log::UPTO($level);
if (isset($conf['buffering'])) {
$this->_buffering = $conf['buffering'];
}
if ($this->_buffering) {
register_shutdown_function(array(&$this, '_Log_firebug'));
}
if (!empty($conf['lineFormat'])) {
$this->_lineFormat = str_replace(array_keys($this->_formatMap),
array_values($this->_formatMap),
$conf['lineFormat']);
}
if (!empty($conf['timeFormat'])) {
$this->_timeFormat = $conf['timeFormat'];
}
}
/**
* Opens the firebug handler.
*
* @access public
*/
function open()
{
$this->_opened = true;
return true;
}
/**
* Destructor
*/
function _Log_firebug()
{
$this->close();
}
/**
* Closes the firebug handler.
*
* @access public
*/
function close()
{
$this->flush();
$this->_opened = false;
return true;
}
/**
* Flushes all pending ("buffered") data.
*
* @access public
*/
function flush() {
if (count($this->_buffer)) {
print '<script type="text/javascript">';
print "\nif (('console' in window) && ('firebug' in console)) {\n";
foreach ($this->_buffer as $line) {
print " $line\n";
}
print "}\n";
print "</script>\n";
};
$this->_buffer = array();
}
/**
* Writes $message to Firebug console. Also, passes the message
* along to any Log_observer instances that are observing this Log.
*
* @param mixed $message String or object containing the message to log.
* @param string $priority The priority of the message. Valid
* values are: PEAR_LOG_EMERG, PEAR_LOG_ALERT,
* PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
* PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
* @return boolean True on success or false on failure.
* @access public
*/
function log($message, $priority = null)
{
/* If a priority hasn't been specified, use the default value. */
if ($priority === null) {
$priority = $this->_priority;
}
/* Abort early if the priority is above the maximum logging level. */
if (!$this->_isMasked($priority)) {
return false;
}
/* Extract the string representation of the message. */
$message = $this->_extractMessage($message);
$method = $this->_methods[$priority];
/* normalize line breaks */
$message = str_replace("\r\n", "\n", $message);
/* escape line breaks */
$message = str_replace("\n", "\\n\\\n", $message);
/* escape quotes */
$message = str_replace('"', '\\"', $message);
/* Build the string containing the complete log line. */
$line = $this->_format($this->_lineFormat,
strftime($this->_timeFormat),
$priority,
$message);
if ($this->_buffering) {
$this->_buffer[] = sprintf('console.%s("%s");', $method, $line);
} else {
print '<script type="text/javascript">';
print "\nif (('console' in window) && ('firebug' in console)) {\n";
/* Build and output the complete log line. */
printf(' console.%s("%s");', $method, $line);
print "\n}\n";
print "</script>\n";
}
/* Notify observers about this log message. */
$this->_announce(array('priority' => $priority, 'message' => $message));
return true;
}
}

View File

@ -1,294 +0,0 @@
<?php
/**
* $Header$
*
* @version $Revision: 266658 $
* @package Log
*/
/**
* The Log_mail class is a concrete implementation of the Log:: abstract class
* which sends log messages to a mailbox.
* The mail is actually sent when you close() the logger, or when the destructor
* is called (when the script is terminated).
*
* PLEASE NOTE that you must create a Log_mail object using =&, like this :
* $logger =& Log::factory("mail", "recipient@example.com", ...)
*
* This is a PEAR requirement for destructors to work properly.
* See http://pear.php.net/manual/en/class.pear.php
*
* @author Ronnie Garcia <ronnie@mk2.net>
* @author Jon Parise <jon@php.net>
* @since Log 1.3
* @package Log
*
* @example mail.php Using the mail handler.
*/
class Log_mail extends Log
{
/**
* String holding the recipients' email addresses. Multiple addresses
* should be separated with commas.
* @var string
* @access private
*/
var $_recipients = '';
/**
* String holding the sender's email address.
* @var string
* @access private
*/
var $_from = '';
/**
* String holding the email's subject.
* @var string
* @access private
*/
var $_subject = '[Log_mail] Log message';
/**
* String holding an optional preamble for the log messages.
* @var string
* @access private
*/
var $_preamble = '';
/**
* String containing the format of a log line.
* @var string
* @access private
*/
var $_lineFormat = '%1$s %2$s [%3$s] %4$s';
/**
* String containing the timestamp format. It will be passed directly to
* strftime(). Note that the timestamp string will generated using the
* current locale.
* @var string
* @access private
*/
var $_timeFormat = '%b %d %H:%M:%S';
/**
* String holding the mail message body.
* @var string
* @access private
*/
var $_message = '';
/**
* Flag used to indicated that log lines have been written to the message
* body and the message should be sent on close().
* @var boolean
* @access private
*/
var $_shouldSend = false;
/**
* String holding the backend name of PEAR::Mail
* @var string
* @access private
*/
var $_mailBackend = '';
/**
* Array holding the params for PEAR::Mail
* @var array
* @access private
*/
var $_mailParams = array();
/**
* Constructs a new Log_mail object.
*
* Here is how you can customize the mail driver with the conf[] hash :
* $conf['from']: the mail's "From" header line,
* $conf['subject']: the mail's "Subject" line.
* $conf['mailBackend']: backend name of PEAR::Mail
* $conf['mailParams']: parameters for the PEAR::Mail backend
*
* @param string $name The message's recipients.
* @param string $ident The identity string.
* @param array $conf The configuration array.
* @param int $level Log messages up to and including this level.
* @access public
*/
function Log_mail($name, $ident = '', $conf = array(),
$level = PEAR_LOG_DEBUG)
{
$this->_id = md5(microtime());
$this->_recipients = $name;
$this->_ident = $ident;
$this->_mask = Log::UPTO($level);
if (!empty($conf['from'])) {
$this->_from = $conf['from'];
} else {
$this->_from = ini_get('sendmail_from');
}
if (!empty($conf['subject'])) {
$this->_subject = $conf['subject'];
}
if (!empty($conf['preamble'])) {
$this->_preamble = $conf['preamble'];
}
if (!empty($conf['lineFormat'])) {
$this->_lineFormat = str_replace(array_keys($this->_formatMap),
array_values($this->_formatMap),
$conf['lineFormat']);
}
if (!empty($conf['timeFormat'])) {
$this->_timeFormat = $conf['timeFormat'];
}
if (!empty($conf['mailBackend'])) {
$this->_mailBackend = $conf['mailBackend'];
}
if (!empty($conf['mailParams'])) {
$this->_mailParams = $conf['mailParams'];
}
/* register the destructor */
register_shutdown_function(array(&$this, '_Log_mail'));
}
/**
* Destructor. Calls close().
*
* @access private
*/
function _Log_mail()
{
$this->close();
}
/**
* Starts a new mail message.
* This is implicitly called by log(), if necessary.
*
* @access public
*/
function open()
{
if (!$this->_opened) {
if (!empty($this->_preamble)) {
$this->_message = $this->_preamble . "\r\n\r\n";
}
$this->_opened = true;
$_shouldSend = false;
}
return $this->_opened;
}
/**
* Closes the message, if it is open, and sends the mail.
* This is implicitly called by the destructor, if necessary.
*
* @access public
*/
function close()
{
if ($this->_opened) {
if ($this->_shouldSend && !empty($this->_message)) {
if ($this->_mailBackend === '') { // use mail()
$headers = "From: $this->_from\r\n";
$headers .= 'User-Agent: PEAR Log Package';
if (mail($this->_recipients, $this->_subject,
$this->_message, $headers) == false) {
return false;
}
} else { // use PEAR::Mail
include_once 'Mail.php';
$headers = array('From' => $this->_from,
'To' => $this->_recipients,
'User-Agent' => 'PEAR Log Package',
'Subject' => $this->_subject);
$mailer = &Mail::factory($this->_mailBackend,
$this->_mailParams);
$res = $mailer->send($this->_recipients, $headers,
$this->_message);
if (PEAR::isError($res)) {
return false;
}
}
/* Clear the message string now that the email has been sent. */
$this->_message = '';
$this->_shouldSend = false;
}
$this->_opened = false;
}
return ($this->_opened === false);
}
/**
* Flushes the log output by forcing the email message to be sent now.
* Events that are logged after flush() is called will be appended to a
* new email message.
*
* @access public
* @since Log 1.8.2
*/
function flush()
{
/*
* It's sufficient to simply call close() to flush the output.
* The next call to log() will cause the handler to be reopened.
*/
return $this->close();
}
/**
* Writes $message to the currently open mail message.
* Calls open(), if necessary.
*
* @param mixed $message String or object containing the message to log.
* @param string $priority The priority of the message. Valid
* values are: PEAR_LOG_EMERG, PEAR_LOG_ALERT,
* PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
* PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
* @return boolean True on success or false on failure.
* @access public
*/
function log($message, $priority = null)
{
/* If a priority hasn't been specified, use the default value. */
if ($priority === null) {
$priority = $this->_priority;
}
/* Abort early if the priority is above the maximum logging level. */
if (!$this->_isMasked($priority)) {
return false;
}
/* If the message isn't open and can't be opened, return failure. */
if (!$this->_opened && !$this->open()) {
return false;
}
/* Extract the string representation of the message. */
$message = $this->_extractMessage($message);
/* Append the string containing the complete log line. */
$this->_message .= $this->_format($this->_lineFormat,
strftime($this->_timeFormat),
$priority, $message) . "\r\n";
$this->_shouldSend = true;
/* Notify observers about this log message. */
$this->_announce(array('priority' => $priority, 'message' => $message));
return true;
}
}

View File

@ -1,170 +0,0 @@
<?php
/**
* $Header$
* $Horde: horde/lib/Log/mcal.php,v 1.2 2000/06/28 21:36:13 jon Exp $
*
* @version $Revision: 180836 $
* @package Log
*/
/**
* The Log_mcal class is a concrete implementation of the Log::
* abstract class which sends messages to a local or remote calendar
* store accessed through MCAL.
*
* @author Chuck Hagenbuch <chuck@horde.org>
* @since Horde 1.3
* @since Log 1.0
* @package Log
*/
class Log_mcal extends Log
{
/**
* holding the calendar specification to connect to.
* @var string
* @access private
*/
var $_calendar = '{localhost/mstore}';
/**
* holding the username to use.
* @var string
* @access private
*/
var $_username = '';
/**
* holding the password to use.
* @var string
* @access private
*/
var $_password = '';
/**
* holding the options to pass to the calendar stream.
* @var integer
* @access private
*/
var $_options = 0;
/**
* ResourceID of the MCAL stream.
* @var string
* @access private
*/
var $_stream = '';
/**
* Integer holding the log facility to use.
* @var string
* @access private
*/
var $_name = LOG_SYSLOG;
/**
* Constructs a new Log_mcal object.
*
* @param string $name The category to use for our events.
* @param string $ident The identity string.
* @param array $conf The configuration array.
* @param int $level Log messages up to and including this level.
* @access public
*/
function Log_mcal($name, $ident = '', $conf = array(),
$level = PEAR_LOG_DEBUG)
{
$this->_id = md5(microtime());
$this->_name = $name;
$this->_ident = $ident;
$this->_mask = Log::UPTO($level);
$this->_calendar = $conf['calendar'];
$this->_username = $conf['username'];
$this->_password = $conf['password'];
$this->_options = $conf['options'];
}
/**
* Opens a calendar stream, if it has not already been
* opened. This is implicitly called by log(), if necessary.
* @access public
*/
function open()
{
if (!$this->_opened) {
$this->_stream = mcal_open($this->_calendar, $this->_username,
$this->_password, $this->_options);
$this->_opened = true;
}
return $this->_opened;
}
/**
* Closes the calendar stream, if it is open.
* @access public
*/
function close()
{
if ($this->_opened) {
mcal_close($this->_stream);
$this->_opened = false;
}
return ($this->_opened === false);
}
/**
* Logs $message and associated information to the currently open
* calendar stream. Calls open() if necessary. Also passes the
* message along to any Log_observer instances that are observing
* this Log.
*
* @param mixed $message String or object containing the message to log.
* @param string $priority The priority of the message. Valid
* values are: PEAR_LOG_EMERG, PEAR_LOG_ALERT,
* PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
* PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
* @return boolean True on success or false on failure.
* @access public
*/
function log($message, $priority = null)
{
/* If a priority hasn't been specified, use the default value. */
if ($priority === null) {
$priority = $this->_priority;
}
/* Abort early if the priority is above the maximum logging level. */
if (!$this->_isMasked($priority)) {
return false;
}
/* If the connection isn't open and can't be opened, return failure. */
if (!$this->_opened && !$this->open()) {
return false;
}
/* Extract the string representation of the message. */
$message = $this->_extractMessage($message);
$date_str = date('Y:n:j:G:i:s');
$dates = explode(':', $date_str);
mcal_event_init($this->_stream);
mcal_event_set_title($this->_stream, $this->_ident);
mcal_event_set_category($this->_stream, $this->_name);
mcal_event_set_description($this->_stream, $message);
mcal_event_add_attribute($this->_stream, 'priority', $priority);
mcal_event_set_start($this->_stream, $dates[0], $dates[1], $dates[2],
$dates[3], $dates[4], $dates[5]);
mcal_event_set_end($this->_stream, $dates[0], $dates[1], $dates[2],
$dates[3], $dates[4], $dates[5]);
mcal_append_event($this->_stream);
$this->_announce(array('priority' => $priority, 'message' => $message));
return true;
}
}

View File

@ -1,358 +0,0 @@
<?php
/**
* $Header$
*
* @version $Revision: 204814 $
* @package Log
*/
/** PEAR's MDB2 package */
require_once 'MDB2.php';
MDB2::loadFile('Date');
/**
* The Log_mdb2 class is a concrete implementation of the Log:: abstract class
* which sends messages to an SQL server. Each entry occupies a separate row
* in the database.
*
* This implementation uses PEAR's MDB2 database abstraction layer.
*
* CREATE TABLE log_table (
* id INT NOT NULL,
* logtime TIMESTAMP NOT NULL,
* ident CHAR(16) NOT NULL,
* priority INT NOT NULL,
* message VARCHAR(200),
* PRIMARY KEY (id)
* );
*
* @author Lukas Smith <smith@backendmedia.com>
* @author Jon Parise <jon@php.net>
* @since Log 1.9.0
* @package Log
*/
class Log_mdb2 extends Log
{
/**
* Variable containing the DSN information.
* @var mixed
* @access private
*/
var $_dsn = '';
/**
* Array containing our set of DB configuration options.
* @var array
* @access private
*/
var $_options = array('persistent' => true);
/**
* Object holding the database handle.
* @var object
* @access private
*/
var $_db = null;
/**
* Resource holding the prepared statement handle.
* @var resource
* @access private
*/
var $_statement = null;
/**
* Flag indicating that we're using an existing database connection.
* @var boolean
* @access private
*/
var $_existingConnection = false;
/**
* String holding the database table to use.
* @var string
* @access private
*/
var $_table = 'log_table';
/**
* String holding the name of the ID sequence.
* @var string
* @access private
*/
var $_sequence = 'log_id';
/**
* Maximum length of the $ident string. This corresponds to the size of
* the 'ident' column in the SQL table.
* @var integer
* @access private
*/
var $_identLimit = 16;
/**
* Set of field types used in the database table.
* @var array
* @access private
*/
var $_types = array(
'id' => 'integer',
'logtime' => 'timestamp',
'ident' => 'text',
'priority' => 'text',
'message' => 'clob'
);
/**
* Constructs a new sql logging object.
*
* @param string $name The target SQL table.
* @param string $ident The identification field.
* @param array $conf The connection configuration array.
* @param int $level Log messages up to and including this level.
* @access public
*/
function Log_mdb2($name, $ident = '', $conf = array(),
$level = PEAR_LOG_DEBUG)
{
$this->_id = md5(microtime());
$this->_table = $name;
$this->_mask = Log::UPTO($level);
/* If an options array was provided, use it. */
if (isset($conf['options']) && is_array($conf['options'])) {
$this->_options = $conf['options'];
}
/* If a specific sequence name was provided, use it. */
if (!empty($conf['sequence'])) {
$this->_sequence = $conf['sequence'];
}
/* If a specific sequence name was provided, use it. */
if (isset($conf['identLimit'])) {
$this->_identLimit = $conf['identLimit'];
}
/* Now that the ident limit is confirmed, set the ident string. */
$this->setIdent($ident);
/* If an existing database connection was provided, use it. */
if (isset($conf['db'])) {
$this->_db = &$conf['db'];
$this->_existingConnection = true;
$this->_opened = true;
} elseif (isset($conf['singleton'])) {
$this->_db = &MDB2::singleton($conf['singleton'], $this->_options);
$this->_existingConnection = true;
$this->_opened = true;
} else {
$this->_dsn = $conf['dsn'];
}
}
/**
* Opens a connection to the database, if it has not already
* been opened. This is implicitly called by log(), if necessary.
*
* @return boolean True on success, false on failure.
* @access public
*/
function open()
{
if (!$this->_opened) {
/* Use the DSN and options to create a database connection. */
$this->_db = &MDB2::connect($this->_dsn, $this->_options);
if (PEAR::isError($this->_db)) {
return false;
}
/* Create a prepared statement for repeated use in log(). */
if (!$this->_prepareStatement()) {
return false;
}
/* We now consider out connection open. */
$this->_opened = true;
}
return $this->_opened;
}
/**
* Closes the connection to the database if it is still open and we were
* the ones that opened it. It is the caller's responsible to close an
* existing connection that was passed to us via $conf['db'].
*
* @return boolean True on success, false on failure.
* @access public
*/
function close()
{
/* If we have a statement object, free it. */
if (is_object($this->_statement)) {
$this->_statement->free();
$this->_statement = null;
}
/* If we opened the database connection, disconnect it. */
if ($this->_opened && !$this->_existingConnection) {
$this->_opened = false;
return $this->_db->disconnect();
}
return ($this->_opened === false);
}
/**
* Sets this Log instance's identification string. Note that this
* SQL-specific implementation will limit the length of the $ident string
* to sixteen (16) characters.
*
* @param string $ident The new identification string.
*
* @access public
* @since Log 1.8.5
*/
function setIdent($ident)
{
$this->_ident = substr($ident, 0, $this->_identLimit);
}
/**
* Inserts $message to the currently open database. Calls open(),
* if necessary. Also passes the message along to any Log_observer
* instances that are observing this Log.
*
* @param mixed $message String or object containing the message to log.
* @param string $priority The priority of the message. Valid
* values are: PEAR_LOG_EMERG, PEAR_LOG_ALERT,
* PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
* PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
* @return boolean True on success or false on failure.
* @access public
*/
function log($message, $priority = null)
{
/* If a priority hasn't been specified, use the default value. */
if ($priority === null) {
$priority = $this->_priority;
}
/* Abort early if the priority is above the maximum logging level. */
if (!$this->_isMasked($priority)) {
return false;
}
/* If the connection isn't open and can't be opened, return failure. */
if (!$this->_opened && !$this->open()) {
return false;
}
/* If we don't already have a statement object, create one. */
if (!is_object($this->_statement) && !$this->_prepareStatement()) {
return false;
}
/* Extract the string representation of the message. */
$message = $this->_extractMessage($message);
/* Build our set of values for this log entry. */
$values = array(
'id' => $this->_db->nextId($this->_sequence),
'logtime' => MDB2_Date::mdbNow(),
'ident' => $this->_ident,
'priority' => $priority,
'message' => $message
);
/* Execute the SQL query for this log entry insertion. */
$this->_db->expectError(MDB2_ERROR_NOSUCHTABLE);
$result = &$this->_statement->execute($values);
$this->_db->popExpect();
/* Attempt to handle any errors. */
if (PEAR::isError($result)) {
/* We can only handle MDB2_ERROR_NOSUCHTABLE errors. */
if ($result->getCode() != MDB2_ERROR_NOSUCHTABLE) {
return false;
}
/* Attempt to create the target table. */
if (!$this->_createTable()) {
return false;
}
/* Recreate our prepared statement resource. */
$this->_statement->free();
if (!$this->_prepareStatement()) {
return false;
}
/* Attempt to re-execute the insertion query. */
$result = $this->_statement->execute($values);
if (PEAR::isError($result)) {
return false;
}
}
$this->_announce(array('priority' => $priority, 'message' => $message));
return true;
}
/**
* Create the log table in the database.
*
* @return boolean True on success or false on failure.
* @access private
*/
function _createTable()
{
$this->_db->loadModule('Manager', null, true);
$result = $this->_db->manager->createTable(
$this->_table,
array(
'id' => array('type' => $this->_types['id']),
'logtime' => array('type' => $this->_types['logtime']),
'ident' => array('type' => $this->_types['ident']),
'priority' => array('type' => $this->_types['priority']),
'message' => array('type' => $this->_types['message'])
)
);
if (PEAR::isError($result)) {
return false;
}
$result = $this->_db->manager->createIndex(
$this->_table,
'unique_id',
array('fields' => array('id' => true), 'unique' => true)
);
if (PEAR::isError($result)) {
return false;
}
return true;
}
/**
* Prepare the SQL insertion statement.
*
* @return boolean True if the statement was successfully created.
*
* @access private
* @since Log 1.9.0
*/
function _prepareStatement()
{
$this->_statement = &$this->_db->prepare(
'INSERT INTO ' . $this->_table .
' (id, logtime, ident, priority, message)' .
' VALUES(:id, :logtime, :ident, :priority, :message)',
$this->_types, MDB2_PREPARE_MANIP);
/* Return success if we didn't generate an error. */
return (PEAR::isError($this->_statement) === false);
}
}

View File

@ -1,91 +0,0 @@
<?php
/**
* $Header$
*
* @version $Revision: 215527 $
* @package Log
*/
/**
* The Log_null class is a concrete implementation of the Log:: abstract
* class. It simply consumes log events.
*
* @author Jon Parise <jon@php.net>
* @since Log 1.8.2
* @package Log
*
* @example null.php Using the null handler.
*/
class Log_null extends Log
{
/**
* Constructs a new Log_null object.
*
* @param string $name Ignored.
* @param string $ident The identity string.
* @param array $conf The configuration array.
* @param int $level Log messages up to and including this level.
* @access public
*/
function Log_null($name, $ident = '', $conf = array(),
$level = PEAR_LOG_DEBUG)
{
$this->_id = md5(microtime());
$this->_ident = $ident;
$this->_mask = Log::UPTO($level);
}
/**
* Opens the handler.
*
* @access public
* @since Log 1.9.6
*/
function open()
{
$this->_opened = true;
return true;
}
/**
* Closes the handler.
*
* @access public
* @since Log 1.9.6
*/
function close()
{
$this->_opened = false;
return true;
}
/**
* Simply consumes the log event. The message will still be passed
* along to any Log_observer instances that are observing this Log.
*
* @param mixed $message String or object containing the message to log.
* @param string $priority The priority of the message. Valid
* values are: PEAR_LOG_EMERG, PEAR_LOG_ALERT,
* PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
* PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
* @return boolean True on success or false on failure.
* @access public
*/
function log($message, $priority = null)
{
/* If a priority hasn't been specified, use the default value. */
if ($priority === null) {
$priority = $this->_priority;
}
/* Abort early if the priority is above the maximum logging level. */
if (!$this->_isMasked($priority)) {
return false;
}
$this->_announce(array('priority' => $priority, 'message' => $message));
return true;
}
}

View File

@ -1,129 +0,0 @@
<?php
/**
* $Header$
* $Horde: horde/lib/Log/observer.php,v 1.5 2000/06/28 21:36:13 jon Exp $
*
* @version $Revision: 211953 $
* @package Log
*/
/**
* The Log_observer:: class implements the Observer end of a Subject-Observer
* pattern for watching log activity and taking actions on exceptional events.
*
* @author Chuck Hagenbuch <chuck@horde.org>
* @since Horde 1.3
* @since Log 1.0
* @package Log
*
* @example observer_mail.php An example Log_observer implementation.
*/
class Log_observer
{
/**
* Instance-specific unique identification number.
*
* @var integer
* @access private
*/
var $_id = 0;
/**
* The minimum priority level of message that we want to hear about.
* PEAR_LOG_EMERG is the highest priority, so we will only hear messages
* with an integer priority value less than or equal to ours. It defaults
* to PEAR_LOG_INFO, which listens to everything except PEAR_LOG_DEBUG.
*
* @var string
* @access private
*/
var $_priority = PEAR_LOG_INFO;
/**
* Creates a new basic Log_observer instance.
*
* @param integer $priority The highest priority at which to receive
* log event notifications.
*
* @access public
*/
function Log_observer($priority = PEAR_LOG_INFO)
{
$this->_id = md5(microtime());
$this->_priority = $priority;
}
/**
* Attempts to return a new concrete Log_observer instance of the requested
* type.
*
* @param string $type The type of concreate Log_observer subclass
* to return.
* @param integer $priority The highest priority at which to receive
* log event notifications.
* @param array $conf Optional associative array of additional
* configuration values.
*
* @return object The newly created concrete Log_observer
* instance, or null on an error.
*/
function &factory($type, $priority = PEAR_LOG_INFO, $conf = array())
{
$type = strtolower($type);
$class = 'Log_observer_' . $type;
/*
* If the desired class already exists (because the caller has supplied
* it from some custom location), simply instantiate and return a new
* instance.
*/
if (class_exists($class)) {
$object = &new $class($priority, $conf);
return $object;
}
/* Support both the new-style and old-style file naming conventions. */
$newstyle = true;
$classfile = dirname(__FILE__) . '/observer_' . $type . '.php';
if (!file_exists($classfile)) {
$classfile = 'Log/' . $type . '.php';
$newstyle = false;
}
/*
* Attempt to include our version of the named class, but don't treat
* a failure as fatal. The caller may have already included their own
* version of the named class.
*/
@include_once $classfile;
/* If the class exists, return a new instance of it. */
if (class_exists($class)) {
/* Support both new-style and old-style construction. */
if ($newstyle) {
$object = &new $class($priority, $conf);
} else {
$object = &new $class($priority);
}
return $object;
}
$null = null;
return $null;
}
/**
* This is a stub method to make sure that Log_Observer classes do
* something when they are notified of a message. The default behavior
* is to just print the message, which is obviously not desireable in
* practically any situation - which is why you need to override this
* method. :)
*
* @param array $event A hash describing the log event.
*/
function notify($event)
{
print_r($event);
}
}

View File

@ -1,294 +0,0 @@
<?php
/**
* $Header$
* $Horde: horde/lib/Log/sql.php,v 1.12 2000/08/16 20:27:34 chuck Exp $
*
* @version $Revision: 250926 $
* @package Log
*/
/**
* We require the PEAR DB class. This is generally defined in the DB.php file,
* but it's possible that the caller may have provided the DB class, or a
* compatible wrapper (such as the one shipped with MDB2), so we first check
* for an existing 'DB' class before including 'DB.php'.
*/
if (!class_exists('DB')) {
require_once 'DB.php';
}
/**
* The Log_sql class is a concrete implementation of the Log::
* abstract class which sends messages to an SQL server. Each entry
* occupies a separate row in the database.
*
* This implementation uses PHP's PEAR database abstraction layer.
*
* CREATE TABLE log_table (
* id INT NOT NULL,
* logtime TIMESTAMP NOT NULL,
* ident CHAR(16) NOT NULL,
* priority INT NOT NULL,
* message VARCHAR(200),
* PRIMARY KEY (id)
* );
*
* @author Jon Parise <jon@php.net>
* @since Horde 1.3
* @since Log 1.0
* @package Log
*
* @example sql.php Using the SQL handler.
*/
class Log_sql extends Log
{
/**
* Variable containing the DSN information.
* @var mixed
* @access private
*/
var $_dsn = '';
/**
* String containing the SQL insertion statement.
*
* @var string
* @access private
*/
var $_sql = '';
/**
* Array containing our set of DB configuration options.
* @var array
* @access private
*/
var $_options = array('persistent' => true);
/**
* Object holding the database handle.
* @var object
* @access private
*/
var $_db = null;
/**
* Resource holding the prepared statement handle.
* @var resource
* @access private
*/
var $_statement = null;
/**
* Flag indicating that we're using an existing database connection.
* @var boolean
* @access private
*/
var $_existingConnection = false;
/**
* String holding the database table to use.
* @var string
* @access private
*/
var $_table = 'log_table';
/**
* String holding the name of the ID sequence.
* @var string
* @access private
*/
var $_sequence = 'log_id';
/**
* Maximum length of the $ident string. This corresponds to the size of
* the 'ident' column in the SQL table.
* @var integer
* @access private
*/
var $_identLimit = 16;
/**
* Constructs a new sql logging object.
*
* @param string $name The target SQL table.
* @param string $ident The identification field.
* @param array $conf The connection configuration array.
* @param int $level Log messages up to and including this level.
* @access public
*/
function Log_sql($name, $ident = '', $conf = array(),
$level = PEAR_LOG_DEBUG)
{
$this->_id = md5(microtime());
$this->_table = $name;
$this->_mask = Log::UPTO($level);
/* Now that we have a table name, assign our SQL statement. */
if (!empty($conf['sql'])) {
$this->_sql = $conf['sql'];
} else {
$this->_sql = 'INSERT INTO ' . $this->_table .
' (id, logtime, ident, priority, message)' .
' VALUES(?, CURRENT_TIMESTAMP, ?, ?, ?)';
}
/* If an options array was provided, use it. */
if (isset($conf['options']) && is_array($conf['options'])) {
$this->_options = $conf['options'];
}
/* If a specific sequence name was provided, use it. */
if (!empty($conf['sequence'])) {
$this->_sequence = $conf['sequence'];
}
/* If a specific sequence name was provided, use it. */
if (isset($conf['identLimit'])) {
$this->_identLimit = $conf['identLimit'];
}
/* Now that the ident limit is confirmed, set the ident string. */
$this->setIdent($ident);
/* If an existing database connection was provided, use it. */
if (isset($conf['db'])) {
$this->_db = &$conf['db'];
$this->_existingConnection = true;
$this->_opened = true;
} else {
$this->_dsn = $conf['dsn'];
}
}
/**
* Opens a connection to the database, if it has not already
* been opened. This is implicitly called by log(), if necessary.
*
* @return boolean True on success, false on failure.
* @access public
*/
function open()
{
if (!$this->_opened) {
/* Use the DSN and options to create a database connection. */
$this->_db = &DB::connect($this->_dsn, $this->_options);
if (DB::isError($this->_db)) {
return false;
}
/* Create a prepared statement for repeated use in log(). */
if (!$this->_prepareStatement()) {
return false;
}
/* We now consider out connection open. */
$this->_opened = true;
}
return $this->_opened;
}
/**
* Closes the connection to the database if it is still open and we were
* the ones that opened it. It is the caller's responsible to close an
* existing connection that was passed to us via $conf['db'].
*
* @return boolean True on success, false on failure.
* @access public
*/
function close()
{
if ($this->_opened && !$this->_existingConnection) {
$this->_opened = false;
$this->_db->freePrepared($this->_statement);
return $this->_db->disconnect();
}
return ($this->_opened === false);
}
/**
* Sets this Log instance's identification string. Note that this
* SQL-specific implementation will limit the length of the $ident string
* to sixteen (16) characters.
*
* @param string $ident The new identification string.
*
* @access public
* @since Log 1.8.5
*/
function setIdent($ident)
{
$this->_ident = substr($ident, 0, $this->_identLimit);
}
/**
* Inserts $message to the currently open database. Calls open(),
* if necessary. Also passes the message along to any Log_observer
* instances that are observing this Log.
*
* @param mixed $message String or object containing the message to log.
* @param string $priority The priority of the message. Valid
* values are: PEAR_LOG_EMERG, PEAR_LOG_ALERT,
* PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
* PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
* @return boolean True on success or false on failure.
* @access public
*/
function log($message, $priority = null)
{
/* If a priority hasn't been specified, use the default value. */
if ($priority === null) {
$priority = $this->_priority;
}
/* Abort early if the priority is above the maximum logging level. */
if (!$this->_isMasked($priority)) {
return false;
}
/* If the connection isn't open and can't be opened, return failure. */
if (!$this->_opened && !$this->open()) {
return false;
}
/* If we don't already have our statement object yet, create it. */
if (!is_object($this->_statement) && !$this->_prepareStatement()) {
return false;
}
/* Extract the string representation of the message. */
$message = $this->_extractMessage($message);
/* Build our set of values for this log entry. */
$id = $this->_db->nextId($this->_sequence);
$values = array($id, $this->_ident, $priority, $message);
/* Execute the SQL query for this log entry insertion. */
$result =& $this->_db->execute($this->_statement, $values);
if (DB::isError($result)) {
return false;
}
$this->_announce(array('priority' => $priority, 'message' => $message));
return true;
}
/**
* Prepare the SQL insertion statement.
*
* @return boolean True if the statement was successfully created.
*
* @access private
* @since Log 1.9.1
*/
function _prepareStatement()
{
$this->_statement = $this->_db->prepare($this->_sql);
/* Return success if we didn't generate an error. */
return (DB::isError($this->_statement) === false);
}
}

View File

@ -1,225 +0,0 @@
<?php
/**
* $Header$
*
* @version $Revision: 202069 $
* @package Log
*/
/**
* The Log_sqlite class is a concrete implementation of the Log::
* abstract class which sends messages to an Sqlite database.
* Each entry occupies a separate row in the database.
*
* This implementation uses PHP native Sqlite functions.
*
* CREATE TABLE log_table (
* id INTEGER PRIMARY KEY NOT NULL,
* logtime NOT NULL,
* ident CHAR(16) NOT NULL,
* priority INT NOT NULL,
* message
* );
*
* @author Bertrand Mansion <bmansion@mamasam.com>
* @author Jon Parise <jon@php.net>
* @since Log 1.8.3
* @package Log
*
* @example sqlite.php Using the Sqlite handler.
*/
class Log_sqlite extends Log
{
/**
* Array containing the connection defaults
* @var array
* @access private
*/
var $_options = array('mode' => 0666,
'persistent' => false);
/**
* Object holding the database handle.
* @var object
* @access private
*/
var $_db = null;
/**
* Flag indicating that we're using an existing database connection.
* @var boolean
* @access private
*/
var $_existingConnection = false;
/**
* String holding the database table to use.
* @var string
* @access private
*/
var $_table = 'log_table';
/**
* Constructs a new sql logging object.
*
* @param string $name The target SQL table.
* @param string $ident The identification field.
* @param mixed $conf Can be an array of configuration options used
* to open a new database connection
* or an already opened sqlite connection.
* @param int $level Log messages up to and including this level.
* @access public
*/
function Log_sqlite($name, $ident = '', &$conf, $level = PEAR_LOG_DEBUG)
{
$this->_id = md5(microtime());
$this->_table = $name;
$this->_ident = $ident;
$this->_mask = Log::UPTO($level);
if (is_array($conf)) {
foreach ($conf as $k => $opt) {
$this->_options[$k] = $opt;
}
} else {
// If an existing database connection was provided, use it.
$this->_db =& $conf;
$this->_existingConnection = true;
}
}
/**
* Opens a connection to the database, if it has not already
* been opened. This is implicitly called by log(), if necessary.
*
* @return boolean True on success, false on failure.
* @access public
*/
function open()
{
if (is_resource($this->_db)) {
$this->_opened = true;
return $this->_createTable();
} else {
/* Set the connection function based on the 'persistent' option. */
if (empty($this->_options['persistent'])) {
$connectFunction = 'sqlite_open';
} else {
$connectFunction = 'sqlite_popen';
}
/* Attempt to connect to the database. */
if ($this->_db = $connectFunction($this->_options['filename'],
(int)$this->_options['mode'],
$error)) {
$this->_opened = true;
return $this->_createTable();
}
}
return $this->_opened;
}
/**
* Closes the connection to the database if it is still open and we were
* the ones that opened it. It is the caller's responsible to close an
* existing connection that was passed to us via $conf['db'].
*
* @return boolean True on success, false on failure.
* @access public
*/
function close()
{
/* We never close existing connections. */
if ($this->_existingConnection) {
return false;
}
if ($this->_opened) {
$this->_opened = false;
sqlite_close($this->_db);
}
return ($this->_opened === false);
}
/**
* Inserts $message to the currently open database. Calls open(),
* if necessary. Also passes the message along to any Log_observer
* instances that are observing this Log.
*
* @param mixed $message String or object containing the message to log.
* @param string $priority The priority of the message. Valid
* values are: PEAR_LOG_EMERG, PEAR_LOG_ALERT,
* PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
* PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
* @return boolean True on success or false on failure.
* @access public
*/
function log($message, $priority = null)
{
/* If a priority hasn't been specified, use the default value. */
if ($priority === null) {
$priority = $this->_priority;
}
/* Abort early if the priority is above the maximum logging level. */
if (!$this->_isMasked($priority)) {
return false;
}
/* If the connection isn't open and can't be opened, return failure. */
if (!$this->_opened && !$this->open()) {
return false;
}
// Extract the string representation of the message.
$message = $this->_extractMessage($message);
// Build the SQL query for this log entry insertion.
$q = sprintf('INSERT INTO [%s] (logtime, ident, priority, message) ' .
"VALUES ('%s', '%s', %d, '%s')",
$this->_table,
strftime('%Y-%m-%d %H:%M:%S', time()),
sqlite_escape_string($this->_ident),
$priority,
sqlite_escape_string($message));
if (!($res = @sqlite_unbuffered_query($this->_db, $q))) {
return false;
}
$this->_announce(array('priority' => $priority, 'message' => $message));
return true;
}
/**
* Checks whether the log table exists and creates it if necessary.
*
* @return boolean True on success or false on failure.
* @access private
*/
function _createTable()
{
$q = "SELECT name FROM sqlite_master WHERE name='" . $this->_table .
"' AND type='table'";
$res = sqlite_query($this->_db, $q);
if (sqlite_num_rows($res) == 0) {
$q = 'CREATE TABLE [' . $this->_table . '] (' .
'id INTEGER PRIMARY KEY NOT NULL, ' .
'logtime NOT NULL, ' .
'ident CHAR(16) NOT NULL, ' .
'priority INT NOT NULL, ' .
'message)';
if (!($res = sqlite_unbuffered_query($this->_db, $q))) {
return false;
}
}
return true;
}
}

View File

@ -1,228 +0,0 @@
<?php
/**
* $Header$
* $Horde: horde/lib/Log/syslog.php,v 1.6 2000/06/28 21:36:13 jon Exp $
*
* @version $Revision: 302789 $
* @package Log
*/
/**
* The Log_syslog class is a concrete implementation of the Log::
* abstract class which sends messages to syslog on UNIX-like machines
* (PHP emulates this with the Event Log on Windows machines).
*
* @author Chuck Hagenbuch <chuck@horde.org>
* @author Jon Parise <jon@php.net>
* @since Horde 1.3
* @since Log 1.0
* @package Log
*
* @example syslog.php Using the syslog handler.
*/
class Log_syslog extends Log
{
/**
* Integer holding the log facility to use.
* @var integer
* @access private
*/
var $_name = LOG_SYSLOG;
/**
* Should we inherit the current syslog connection for this process, or
* should we call openlog() to start a new syslog connection?
* @var boolean
* @access private
*/
var $_inherit = false;
/**
* Maximum message length that will be sent to syslog(). If the handler
* receives a message longer than this length limit, it will be split into
* multiple syslog() calls.
* @var integer
* @access private
*/
var $_maxLength = 500;
/**
* String containing the format of a message.
* @var string
* @access private
*/
var $_lineFormat = '%4$s';
/**
* String containing the timestamp format. It will be passed directly to
* strftime(). Note that the timestamp string will generated using the
* current locale.
* @var string
* @access private
*/
var $_timeFormat = '%b %d %H:%M:%S';
/**
* Constructs a new syslog object.
*
* @param string $name The syslog facility.
* @param string $ident The identity string.
* @param array $conf The configuration array.
* @param int $level Log messages up to and including this level.
* @access public
*/
function Log_syslog($name, $ident = '', $conf = array(),
$level = PEAR_LOG_DEBUG)
{
/* Ensure we have a valid integer value for $name. */
if (empty($name) || !is_int($name)) {
$name = LOG_SYSLOG;
}
if (isset($conf['inherit'])) {
$this->_inherit = $conf['inherit'];
$this->_opened = $this->_inherit;
}
if (isset($conf['maxLength'])) {
$this->_maxLength = $conf['maxLength'];
}
if (!empty($conf['lineFormat'])) {
$this->_lineFormat = str_replace(array_keys($this->_formatMap),
array_values($this->_formatMap),
$conf['lineFormat']);
}
if (!empty($conf['timeFormat'])) {
$this->_timeFormat = $conf['timeFormat'];
}
$this->_id = md5(microtime());
$this->_name = $name;
$this->_ident = $ident;
$this->_mask = Log::UPTO($level);
}
/**
* Opens a connection to the system logger, if it has not already
* been opened. This is implicitly called by log(), if necessary.
* @access public
*/
function open()
{
if (!$this->_opened) {
$this->_opened = openlog($this->_ident, LOG_PID, $this->_name);
}
return $this->_opened;
}
/**
* Closes the connection to the system logger, if it is open.
* @access public
*/
function close()
{
if ($this->_opened && !$this->_inherit) {
closelog();
$this->_opened = false;
}
return true;
}
/**
* Sends $message to the currently open syslog connection. Calls
* open() if necessary. Also passes the message along to any Log_observer
* instances that are observing this Log.
*
* @param mixed $message String or object containing the message to log.
* @param int $priority (optional) The priority of the message. Valid
* values are: PEAR_LOG_EMERG, PEAR_LOG_ALERT,
* PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
* PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
* @return boolean True on success or false on failure.
* @access public
*/
function log($message, $priority = null)
{
/* If a priority hasn't been specified, use the default value. */
if ($priority === null) {
$priority = $this->_priority;
}
/* Abort early if the priority is above the maximum logging level. */
if (!$this->_isMasked($priority)) {
return false;
}
/* If the connection isn't open and can't be opened, return failure. */
if (!$this->_opened && !$this->open()) {
return false;
}
/* Extract the string representation of the message. */
$message = $this->_extractMessage($message);
/* Build a syslog priority value based on our current configuration. */
$priority = $this->_toSyslog($priority);
if ($this->_inherit) {
$priority |= $this->_name;
}
/* Apply the configured line format to the message string. */
$message = $this->_format($this->_lineFormat,
strftime($this->_timeFormat),
$priority, $message);
/* Split the string into parts based on our maximum length setting. */
$parts = str_split($message, $this->_maxLength);
if ($parts === false) {
return false;
}
foreach ($parts as $part) {
if (!syslog($priority, $part)) {
return false;
}
}
$this->_announce(array('priority' => $priority, 'message' => $message));
return true;
}
/**
* Converts a PEAR_LOG_* constant into a syslog LOG_* constant.
*
* This function exists because, under Windows, not all of the LOG_*
* constants have unique values. Instead, the PEAR_LOG_* were introduced
* for global use, with the conversion to the LOG_* constants kept local to
* to the syslog driver.
*
* @param int $priority PEAR_LOG_* value to convert to LOG_* value.
*
* @return The LOG_* representation of $priority.
*
* @access private
*/
function _toSyslog($priority)
{
static $priorities = array(
PEAR_LOG_EMERG => LOG_EMERG,
PEAR_LOG_ALERT => LOG_ALERT,
PEAR_LOG_CRIT => LOG_CRIT,
PEAR_LOG_ERR => LOG_ERR,
PEAR_LOG_WARNING => LOG_WARNING,
PEAR_LOG_NOTICE => LOG_NOTICE,
PEAR_LOG_INFO => LOG_INFO,
PEAR_LOG_DEBUG => LOG_DEBUG
);
/* If we're passed an unknown priority, default to LOG_INFO. */
if (!is_int($priority) || !in_array($priority, $priorities)) {
return LOG_INFO;
}
return $priorities[$priority];
}
}

View File

@ -1,286 +0,0 @@
<?php
/**
* $Header$
*
* @version $Revision: 278003 $
* @package Log
*/
/**
* The Log_win class is a concrete implementation of the Log abstract
* class that logs messages to a separate browser window.
*
* The concept for this log handler is based on part by Craig Davis' article
* entitled "JavaScript Power PHP Debugging:
*
* http://www.zend.com/zend/tut/tutorial-DebugLib.php
*
* @author Jon Parise <jon@php.net>
* @since Log 1.7.0
* @package Log
*
* @example win.php Using the window handler.
*/
class Log_win extends Log
{
/**
* The name of the output window.
* @var string
* @access private
*/
var $_name = 'LogWindow';
/**
* The title of the output window.
* @var string
* @access private
*/
var $_title = 'Log Output Window';
/**
* Mapping of log priorities to styles.
* @var array
* @access private
*/
var $_styles = array(
PEAR_LOG_EMERG => 'color: red;',
PEAR_LOG_ALERT => 'color: orange;',
PEAR_LOG_CRIT => 'color: yellow;',
PEAR_LOG_ERR => 'color: green;',
PEAR_LOG_WARNING => 'color: blue;',
PEAR_LOG_NOTICE => 'color: indigo;',
PEAR_LOG_INFO => 'color: violet;',
PEAR_LOG_DEBUG => 'color: black;'
);
/**
* String buffer that holds line that are pending output.
* @var array
* @access private
*/
var $_buffer = array();
/**
* Constructs a new Log_win object.
*
* @param string $name Ignored.
* @param string $ident The identity string.
* @param array $conf The configuration array.
* @param int $level Log messages up to and including this level.
* @access public
*/
function Log_win($name, $ident = '', $conf = array(),
$level = PEAR_LOG_DEBUG)
{
$this->_id = md5(microtime());
$this->_name = str_replace(' ', '_', $name);
$this->_ident = $ident;
$this->_mask = Log::UPTO($level);
if (isset($conf['title'])) {
$this->_title = $conf['title'];
}
if (isset($conf['styles']) && is_array($conf['styles'])) {
$this->_styles = $conf['styles'];
}
if (isset($conf['colors']) && is_array($conf['colors'])) {
foreach ($conf['colors'] as $level => $color) {
$this->_styles[$level] .= "color: $color;";
}
}
register_shutdown_function(array(&$this, '_Log_win'));
}
/**
* Destructor
*/
function _Log_win()
{
if ($this->_opened || (count($this->_buffer) > 0)) {
$this->close();
}
}
/**
* The first time open() is called, it will open a new browser window and
* prepare it for output.
*
* This is implicitly called by log(), if necessary.
*
* @access public
*/
function open()
{
if (!$this->_opened) {
$win = $this->_name;
$styles = $this->_styles;
if (!empty($this->_ident)) {
$identHeader = "$win.document.writeln('<th>Ident</th>')";
} else {
$identHeader = '';
}
echo <<< EOT
<script language="JavaScript">
$win = window.open('', '{$this->_name}', 'toolbar=no,scrollbars,width=600,height=400');
$win.document.writeln('<html>');
$win.document.writeln('<head>');
$win.document.writeln('<title>{$this->_title}</title>');
$win.document.writeln('<style type="text/css">');
$win.document.writeln('body { font-family: monospace; font-size: 8pt; }');
$win.document.writeln('td,th { font-size: 8pt; }');
$win.document.writeln('td,th { border-bottom: #999999 solid 1px; }');
$win.document.writeln('td,th { border-right: #999999 solid 1px; }');
$win.document.writeln('tr { text-align: left; vertical-align: top; }');
$win.document.writeln('td.l0 { $styles[0] }');
$win.document.writeln('td.l1 { $styles[1] }');
$win.document.writeln('td.l2 { $styles[2] }');
$win.document.writeln('td.l3 { $styles[3] }');
$win.document.writeln('td.l4 { $styles[4] }');
$win.document.writeln('td.l5 { $styles[5] }');
$win.document.writeln('td.l6 { $styles[6] }');
$win.document.writeln('td.l7 { $styles[7] }');
$win.document.writeln('</style>');
$win.document.writeln('<script type="text/javascript">');
$win.document.writeln('function scroll() {');
$win.document.writeln(' body = document.getElementById("{$this->_name}");');
$win.document.writeln(' body.scrollTop = body.scrollHeight;');
$win.document.writeln('}');
$win.document.writeln('<\/script>');
$win.document.writeln('</head>');
$win.document.writeln('<body id="{$this->_name}" onclick="scroll()">');
$win.document.writeln('<table border="0" cellpadding="2" cellspacing="0">');
$win.document.writeln('<tr><th>Time</th>');
$identHeader
$win.document.writeln('<th>Priority</th><th width="100%">Message</th></tr>');
</script>
EOT;
$this->_opened = true;
}
return $this->_opened;
}
/**
* Closes the output stream if it is open. If there are still pending
* lines in the output buffer, the output window will be opened so that
* the buffer can be drained.
*
* @access public
*/
function close()
{
/*
* If there are still lines waiting to be written, open the output
* window so that we can drain the buffer.
*/
if (!$this->_opened && (count($this->_buffer) > 0)) {
$this->open();
}
if ($this->_opened) {
$this->_writeln('</table>');
$this->_writeln('</body></html>');
$this->_drainBuffer();
$this->_opened = false;
}
return ($this->_opened === false);
}
/**
* Writes the contents of the output buffer to the output window.
*
* @access private
*/
function _drainBuffer()
{
$win = $this->_name;
foreach ($this->_buffer as $line) {
echo "<script language='JavaScript'>\n";
echo "$win.document.writeln('" . addslashes($line) . "');\n";
echo "self.focus();\n";
echo "</script>\n";
}
/* Now that the buffer has been drained, clear it. */
$this->_buffer = array();
}
/**
* Writes a single line of text to the output buffer.
*
* @param string $line The line of text to write.
*
* @access private
*/
function _writeln($line)
{
/* Add this line to our output buffer. */
$this->_buffer[] = $line;
/* Buffer the output until this page's headers have been sent. */
if (!headers_sent()) {
return;
}
/* If we haven't already opened the output window, do so now. */
if (!$this->_opened && !$this->open()) {
return;
}
/* Drain the buffer to the output window. */
$this->_drainBuffer();
}
/**
* Logs $message to the output window. The message is also passed along
* to any Log_observer instances that are observing this Log.
*
* @param mixed $message String or object containing the message to log.
* @param string $priority The priority of the message. Valid
* values are: PEAR_LOG_EMERG, PEAR_LOG_ALERT,
* PEAR_LOG_CRIT, PEAR_LOG_ERR, PEAR_LOG_WARNING,
* PEAR_LOG_NOTICE, PEAR_LOG_INFO, and PEAR_LOG_DEBUG.
* @return boolean True on success or false on failure.
* @access public
*/
function log($message, $priority = null)
{
/* If a priority hasn't been specified, use the default value. */
if ($priority === null) {
$priority = $this->_priority;
}
/* Abort early if the priority is above the maximum logging level. */
if (!$this->_isMasked($priority)) {
return false;
}
/* Extract the string representation of the message. */
$message = $this->_extractMessage($message);
$message = preg_replace('/\r\n|\n|\r/', '<br />', $message);
list($usec, $sec) = explode(' ', microtime());
/* Build the output line that contains the log entry row. */
$line = '<tr>';
$line .= sprintf('<td>%s.%s</td>',
strftime('%H:%M:%S', $sec), substr($usec, 2, 2));
if (!empty($this->_ident)) {
$line .= '<td>' . $this->_ident . '</td>';
}
$line .= '<td>' . ucfirst($this->priorityToString($priority)) . '</td>';
$line .= sprintf('<td class="l%d">%s</td>', $priority, $message);
$line .= '</tr>';
$this->_writeln($line);
$this->_announce(array('priority' => $priority, 'message' => $message));
return true;
}
}

View File

@ -1,7 +0,0 @@
Smarty is supported only in PHP 4.0.6 or later.
Smarty versions previous to 2.0 require the PEAR libraries. Be sure to include
the path to the PEAR libraries in your php include_path. Config_file.class.php
uses the PEAR library for its error handling routines. PEAR comes with the PHP
distribution. Unix users check /usr/local/lib/php, windows users check
C:/php/pear.

View File

@ -1,458 +0,0 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS

File diff suppressed because it is too large Load Diff

View File

@ -1,284 +0,0 @@
QUESTION INDEX
--------------
GENERAL
Q: What is Smarty?
Q: What's the difference between Smarty and other template engines?
Q: What do you mean "Compiled PHP Scripts" ?
Q: Why can't I just use PHPA (http://php-accelerator.co.uk) or Zend Cache?
Q: Why does smarty have a built in cache? Wouldn't it be better to handle this
in a separate class?
Q: Is Smarty faster than <insert other PHP template engine>?
Q: How can I be sure to get the best performance from Smarty?
Q: Do you have a mailing list?
Q: Can you change the mailing list so reply-to sends to the list and not the
user?
TROUBLESHOOTING
Q: Smarty doesn't work.
Q: I get the following error when running Smarty:
Warning: Smarty error: problem creating directory "templates_c/239/239105369"
in /path/to/Smarty.class.php on line 542
Q: I get the following error when running Smarty:
Warning: Wrong parameter count for preg_replace() in
Smarty.class.php on line 371
Q: I get this error when passing variables to {include}:
Fatal error: Call to undefined function: get_defined_vars() in
/path/to/Smarty/templates_c/index.tpl.php on line 8
Q: I get PHP errors in my {if} tag logic.
Q: I'm changing my php code and/or templates, and my results are not getting
updated.
Q: I'm running Windows 2000 and I get blank content. My compiled PHP files are
also zero length.
Q: The template goes into an infinite loop when I include included templates
that pass local variables
Q: Javascript is causing Smarty errors in my templates.
Q: I get "SAFE MODE Restriction in effect. ..."-errors when running smarty.
MISC
Q: Can I use Macromedia's Dreamweaver to edit my templates?
Q: Dreamweaver is urlencoding the template delimiters when they are in a SRC or
HREF link. How do I get around this?
HOWTO
Q: How do I generate different cache files per template based on arguments
passed to the page?
Q: How do I pass a template variable as a parameter? {function param={$varname}}
does not work.
Q: How do I include cached template(s) within a non-cached template?
GENERAL
-------
Q: What is Smarty?
A: Smarty is a template engine for PHP... but be aware this isn't just another
PHP template engine. It's much more than that.
Q: What's the difference between Smarty and other template engines?
A: Most other template engines for PHP provide basic variable substitution and
dynamic block functionality. Smarty takes a step further to be a "smart"
template engine, adding features such as configuration files, template
functions, variable modifiers (see the docs!) and making all of this
functionality as easy as possible to use for both programmers and template
designers. Smarty also compiles the templates into PHP scripts, eliminating
the need to parse the templates on every invocation, making Smarty extremely
scalable and manageable for large application needs.
Q: What do you mean "Compiled PHP Scripts" ?
A: Smarty reads the template files and creates PHP scripts from them. Once
these PHP scripts are created, Smarty executes these, never having to parse
the template files again. If you change a template file, Smarty will
recreate the PHP script for it. All this is done automatically by Smarty.
Template designers never need to mess with the generated PHP scripts or even
know of their existance. (NOTE: you can turn off this compile checking step
in Smarty for increased performance.)
Q: Why can't I just use PHPA (http://php-accelerator.co.uk) or Zend Cache?
A: You certainly can, and we highly recommend it! What PHPA does is caches
compiled bytecode of your PHP scripts in shared memory or in a file. This
speeds up server response and saves the compilation step. Smarty creates PHP
scripts, which PHPA will cache nicely. Now, Smarty's built-in cache is
something completely different. It caches the _output_ of the template
contents. For example, if you have a template that requires several database
queries, Smarty can cache this output, saving the need to call the database
every time. Smarty and PHPA (or Zend Cache) complement each other nicely. If
performance is of the utmost importance, we would recommend using one of
these with any PHP application, using Smarty or not. As you can see in the
benchmarks, Smartys performance _really_ excels in combination with a PHP
accelerator.
Q: Why does Smarty have a built in cache? Wouldn't it be better to handle this
in a separate class?
A: Smarty's caching functionality is tightly integrated with the template
engine, making it quite a bit more flexible than a simple caching wrapper.
For instance, you can cache select portions of a template page. Let's say
you have a polling box on your site. With Smarty, you can leave the poll
dynamic and cache the rest of the page. You can also pass templates
multiple cache ids, meaning that a template can have several caches
depending on URL, cookies, etc.
Q: Is Smarty faster than <insert other PHP template engine>?
A: See the benchmark page for some performance comparisons. Smarty's approach
to templates is a bit different from some languages: it compiles templates
into PHP scripts instead of parsing them on each invocation. This usually
results in great performance gains, especially with complex templates.
Coupled with the built-in caching of Smarty templates, the performance is
outstanding.
Q: How can I be sure to get the best performance from Smarty?
A: Be sure you set $compile_check=false once your templates are initially
compiled. This will skip the unneeded step of testing if the template has
changed since it was last compiled. If you have complex pages that don't
change too often, turn on the caching engine and adjust your application so
it doesn't do unnecessary work (like db calls) if a cached page is
available. See the documentation for examples.
Q: Do you have a mailing list?
A: We have a few mailing lists. "general" for you to share your ideas or ask
questions, "dev" for those interested in the development efforts of Smarty,
and "cvs" for those that would like to track the updates made in the cvs
repository.
send a blank e-mail message to:
smarty-general-subscribe@lists.php.net (subscribe to the general list)
smarty-general-unsubscribe@lists.php.net (unsubscribe from the general list)
smarty-general-digest-subscribe@lists.php.net (subscribe to digest)
smarty-general-digest-unsubscribe@lists.php.net (unsubscribe from digest)
smarty-dev-subscribe@lists.php.net (subscribe to the dev list)
smarty-dev-unsubscribe@lists.php.net (unsubscribe from the dev list)
smarty-cvs-subscribe@lists.php.net (subscribe to the cvs list)
smarty-cvs-unsubscribe@lists.php.net (unsubscribe from the cvs list)
You can also browse the mailing list archives at
http://marc.theaimsgroup.com/?l=smarty&r=1&w=2
Q: Can you change the mailing list so Reply-To sends to the list and not the
user?
A: Yes we could, but no we won't. Use "Reply-All" in your e-mail client to send
to the list. http://www.unicom.com/pw/reply-to-harmful.html
TROUBLESHOOTING
---------------
Q: Smarty doesn't work.
A: You must be using PHP 4.0.6 or later if you use any version of Smarty
past 2.0.1. Read the BUGS file for more info.
Q: I get the following error when running Smarty:
Warning: Smarty error: problem creating directory "templates_c/239/239105369"
in /path/to/Smarty.class.php on line 542
A: Your web server user does not have permission to write to the templates_c
directory, or is unable to create the templates_c directory. Be sure the
templates_c directory exists in the location defined in Smarty.class.php,
and the web server user can write to it. If you do not know the web server
user, chmod 777 the templates_c directory, reload the page, then check the
file ownership of the files created in templates_c. Or, you can check the
httpd.conf (usually in /usr/local/apache/conf) file for this setting:
User nobody
Group nobody
Q: I get the following error when running Smarty: Warning: Wrong parameter
count for preg_replace() in Smarty.class.php on line 371
A: preg_replace had a parameter added in PHP 4.0.2 that Smarty
requires. Upgrade to at least 4.0.6 to fix all known PHP issues with
Smarty.
Q: I get this error when passing variables to {include}:
Fatal error: Call to undefined function: get_defined_vars() in
/path/to/Smarty/templates_c/index.tpl.php on line 8
A: get_defined_vars() was added to PHP 4.0.4. If you plan on passing
variables to included templates, you will need PHP 4.0.6 or later.
Q: I get PHP errors in my {if} tag logic.
A: All conditional qualifiers must be separated by spaces. This syntax will not
work: {if $name=="Wilma"} You must instead do this: {if $name == "Wilma"}.
The reason for this is syntax ambiguity. Both "==" and "eq" are equivalent
in the template parser, so something like {if $nameeq"Wilma"} wouldn't be
parsable by the tokenizer.
Q: I'm changing my php code and/or templates, and my results are not getting
updated.
A: This may be the result of your compile or cache settings. If you are
changing your php code, your templates will not necessarily get recompiled
to reflect the changes. Use $force_compile during develpment to avoid these
situations. Also turn off caching during development when you aren't
specifically testing it. You can also remove everything from your
compile_dir and cache_dir and reload the page to be sure everything gets
regenerated.
Q: I'm running Windows 2000 and I get blank content. My compiled PHP files are
also zero length.
A: There seems to be a problem with some W2k machines and exclusive file
locking. Comment out the flock() call in _write_file to get around this,
although be aware this could possibly cause a problem with simultaneous
writes to a file, especially with caching turned on. NOTE: As of Smarty
1.4.0, a workaround was put in place that should solve this.
Q: The template goes into an infinite loop when I include included templates
that pass local variables
A: This was fixed in 1.3.2 (new global attribute)
Q: Javascript is causing Smarty errors in my templates.
A: Surround your javascript with {literal}{/literal} tags. See the docs.
Q: I get "SAFE MODE Restriction in effect. ..."-errors when running smarty.
A: Use $smarty->use_sub_dirs = false when running php in safe mode.
MISC
----
Q: Can I use Macromedia's Dreamweaver to edit my templates?
A: Certainly. You might want to change your tag delimiters from {} to something
that resembles valid HTML, like <!--{ }--> or <{ }> or something similar.
This way the editor won't view the template tags as errors.
Q: Dreamweaver is urlencoding the template delimiters when they are in a SRC or
HREF link. How do I get around this?
A: In Edit - Properties - Rewrite HTML you can specify if Dreamweaver should
change special letters to %-equivalent or not. The default is on which
produces this error.
HOWTO
-----
Q: How do I generate different cache files per template based on arguments
passed to the page?
A: Use your $REQUEST_URI as the cache_id when fetching the page:
global $REQUEST_URI; // if not already present
$smarty->display('index.tpl',$REQUEST_URI);
This will create a separate cache file for each unique URL when you call
index.tpl. See the documentation for display() and fetch()
Q: How do I pass a template variable as a parameter? {function param={$varname}}
does not work.
A: {function param=$varname} (You cannot nest template delimiters.)
Q: How do I include cached template(s) within a non-cached template?
A: One way to do it:
$smarty->caching = true;
$tpl1 = $smarty->fetch("internal1.tpl");
$tpl2 = $smarty->fetch("internal2.tpl");
$tpl3 = $smarty->fetch("internal3.tpl");
$smarty->assign("tpl1_contents",$tpl1);
$smarty->assign("tpl2_contents",$tpl2);
$smarty->assign("tpl3_contents",$tpl3);
$smarty->caching = false;
$smarty->display('index.tpl');
index.tpl
---------
<table>
<tr>
<td>{$tpl1_contents}</td>
<td>{$tpl2_contents}</td>
<td>{$tpl3_contents}</td>
</tr>
</table>
Another approach:
You could write a custom insert function to fetch your internal
templates:
<table>
<tr>
<td>{insert name=fetch_tpl tpl="internal1.tpl"}</td>
<td>{insert name=fetch_tpl tpl="internal2.tpl"}</td>
<td>{insert name=fetch_tpl tpl="internal3.tpl"}</td>
</tr>
</table>

View File

@ -1,29 +0,0 @@
REQUIREMENTS:
Smarty requires PHP 4.0.6 or later.
See the on-line documentation for complete install instructions.
INSTALLATION (quick):
* copy the files under the libs/ directory to a directory that is in your PHP
include_path, or set the SMARTY_DIR constant and put them in this directory.
(if you upgrade from versions before 2.5.0 be aware that up to Smarty 2.4.2
all necessary files where in the distribution's root directory, but are now
in libs/.)
* for each application using Smarty, create a "templates", "configs", and a
"templates_c" directory, be sure to set the appropriate directory settings in
Smarty for them. If they are located in the same directory as your
application, they shouldn't need to be modified. Be sure the "templates_c"
directory is writable by your web server user (usually nobody). chown
nobody:nobody templates_c; chmod 700 templates_c You can also chmod 777 this
directory, but be aware of security issues for multi-user systems. If you are
using Smarty's built-in caching, create a "cache" directory and also chown
nobody:nobody.
* setup your php and template files. A good working example is in the on-line
documentation.
* TECHNICAL NOTE: If you do not have access to the php.ini file, you can change
non-server settings (such as your include_path) with the ini_set() command.
example: ini_set("include_path",".:/usr/local/lib/php");

View File

@ -1,865 +0,0 @@
Version 2.6.6 (Oct 13, 2004)
----------------------------
- fixed nocache-handling with nested includes (Lars Jankowfsky, messju)
- moved /libs/core to /libs/internals (boots)
- fixed more parsing problems (messju)
Version 2.6.5 (Sept 13, 2004)
-----------------------------
- fixed some parsing problems with object calls introduced
in 2.6.4 (Monte)
- add $smarty->security_settings['ALLOW_CONSTANTS']. note: this
defaults to false which means you have to allow them explicitly
in your secured templates from now on! (messju)
Version 2.6.4 (Sept 7, 2004)
----------------------------
- add $smarty.ldelim and $smarty.rdelim to smarty special var (Monte)
- fall back to old uniqid()-behaviour when tempnam() fails in
core.write_file.php (messju)
- fix capitalize modifier, don't rely on buggy ucwords (Monte)
- make html_select_date work with negative timestamps, also
force year range to include given date unless explicitly
set (Garo, Monte)
- fix bug with {fetch}, passing user/pass in url did not work
(Monte)
- fix occasional wrong error messages on mismatched tags when
{else}, {elseif}, {foreachelse} or {sectionelse} is involved (messju)
- fix handling of methods arguments (messju, Manfred Wischin)
- remove touch() call that made the compiled-template's timestamp the
same as the source-template's one. (messju)
- add assign attribute to html_checkboxes and html_radios
(pcg, Monte)
- remove non-xhtml conformant tag from mailto function
(tacker, Monte)
- handle date_format codes %e, %T and %D for windows (tip,
Monte)
- fix unnecessary call to smarty_core_get_include_path() inside
Smarty::_get_auto_filename() (c960657, messju)
- add error-messages when anything else than an identifier is passed
to foreach's key- or item-attribute (messju)
- fix handling of digits inside tagnames (messju)
- fix escaping of backslashes in Smarty_Compiler::_quote_replace() (messju)
Version 2.6.3 (June 16, 2004)
-----------------------------
- added escapement of '</' to '<\/' in escape:javascript
modifier (c960657, Monte)
- added obfuscation of protocol-string in {mailto} when using hex-
encoding (bharat, messju)
- enhanced auto-generated filenames for templates_c and cache (messju)
- add 'nonstd' to escape modifier for escaping non-std chars,
such as ms doc quote (Monte)
- adjusted textformat to not output wrap chars after last para
(Monte)
- use tempnam() instead of unqid() to create better temporary files in
smarty_core_write_file() (xces, messju)
- add 'mail' to escape modifier for safe display of e-mail
addresses (Monte)
- add cycle function attribute "reset" to english docs (Monte)
- enhanced support of numeric constants as variable-expressions (messju)
- add case decentity to smarty_modifier_escape() (Konstantin A. Pelepelin,
messju)
- make smarty_core_write_compiled_include() php5-aware (messju)
- removed unused functionality to load a subset of lines from a file (messju)
- fix is_secure() should only check if a file is_readable, not if
the directory where it is in is readable (sagi, messju)
- fix problem displaying debug console when $default_resource_type
is not "file:" (c960657, Monte)
- fix permission handling with security and config_load (messju)
- removed '.' from the list of default template locations in
_parse_resource_name() (messju)
- fix avoid warning with template_exists() on an absolute paths (messju)
- fix parameters passed to resource's secure()-function (messju)
- fix handling of integer values like width and delay im
smarty_function_popup() (messju)
Version 2.6.2 (Feb 17, 2004)
----------------------------
- fix allow empty years, months and days in html_select_date's
time-attribute (messju)
- fix YES and NO should not be booleanized inside triple-quotes in a
config-file (messju)
- fix accidently slurped line following a triple-quoted value in a
config-file (messju)
- change default for use_sub_dirs to false (messju)
- fix quoting of values in smarty_function_popup() (messju)
- fix handling of hidden sections in Config_File (messju)
- add handling of resources for {config_load} (messju)
- fix bug when using arrays with tr_attr and td_attr in {html_table} (messju)
- add unit testing to cvs core (Monte)
Version 2.6.1 (Jan 16, 2004)
----------------------------
- rename $smarty->tpl_error_reporting to $smarty->error_reporting
(messju)
- fix interpretation of $smarty->security in {html_image} (messju)
- add caching of requested paths to _assemble_plugin_filepath() (messju)
- fix handling of comments inside {php}- and {literal}-blocks (messju)
- fix bug handling triple-quotes in config-files (BRDude, messju)
- change default of request_use_auto_globals to true - $_SERVER is
now preferred over $HTTP_SERVER_VARS (messju)
- re-add support for $SCRIPT_NAME (messju)
- reactivate $smarty->default_modifiers (messju)
- add cookie persistance to debug console (Monte)
- allow single-digit days and months without smarty_make_timestamp()
in html_select_date (messju)
- fix headers sent erroneously with cache_modified_check and fetch()
(wphilips, messju)
- fix config_file path bug (Marc Cabadas, Monte)
- fix 'is even by' and 'is odd by' logic (Monte)
- add day_empty, month_empty, year_empty and all_empty attributes to
html_select_date (messju)
- add table of explanation for {if} qualifiers in docs (boots)
- fix bug when comparing array-keys to "selected" in html_options
and html_checkboxes (messju)
- add better checks for correctly nested tags when compiling (messju)
- remove {$SCRIPT_NAME}. use {$smarty.server.SCRIPT_NAME} instead (messju)
- remove $global_assign. assign global variables explicitly instead (messju)
- fix example for count_characters in docs (boots)
- add section new basic syntax section "Escaping Smarty Parsing" in docs (boots)
- fix error handler call in config_load (boots)
- remove warning in debug_print_var on php-resources (messju)
- move function.assign.php to compiler.assign.php (messju)
- add property $tpl_error_reporting (messju)
- remove property $undefined. "null" is used literally instead (messju)
Version 2.6.0 (Nov 19, 2003)
----------------------------
- move Smarty::quote_replace() to Smarty_Compiler::_quote_replace() (messju)
- remove import of of attributes of {include_php} to php's namespace.
use $params[name] instead (messju)
Version 2.6.0-RC3 (Nov 13, 2003)
--------------------------------
- fix handling of $var.key inside [] (messju)
- fix handling of assign inside {insert}-tags (messju)
- fix handling if [...] inside triple-quotes in config-files (messju)
- fix handling of simple-math-operators inside modifiers (Dominik, messju)
- fix handling of trailing-slashes in open_basedir in
smarty_core_create_dir_structure() (packman, messju)
Version 2.6.0-RC2 (Oct 8, 2003)
-------------------------------
- apply modifiers only once to section-loop and foreach-from attrs (messju)
- remove use of _smarty_cached_paths-files (messju)
- remove Smarty::_plugin_implementation_exists() - use is_callable() (messju)
- ignore {strip}/{/strip) inside {strip}-blocks (messju)
- fixed removal of leading/trailing newlines in {strip}-blocks (messju)
- fixed proper escaping of " and ' with escape:javascript (messju)
- fixed bug in traversal of $smarty->plugins_dir-array. now the
first matching plugin is taken (messju)
- moved {strip} back into the compiler (messju)
- fixed config_load: handling of section-attribute and use of
multiple config-files in one template (atu, messju)
Version 2.6.0-RC1 (August 11, 2003)
-----------------------------------
- fixed status-header for cache_modified_check under cgi-sapi (messju)
- added optional parameter $cache_attrs to register_function() and
register_block(). $cache_attrs is an array containing attribute-
names that should be cached on calls to functions that have
$cacheable set to false. (messju)
- enabled registration of class-methods as callbacks for the register_*-
functions (use: array('classname', 'method_name')) as callback) (messju)
- added filepath caching (Monte)
- added optional assign-attribute to {capture}-tag (messju)
- added $cacheable-parameter to register_compiler_function() (messju)
- added $cacheable-parameter with default=true to register_function()
and register_block() (messju)
- add math speedup to core (Dominik, Monte)
- fix newlines for tags without template output (Monte)
- added config-option "request_use_auto_globals" to make auto-globals be
used as request vars instead of HTTP_*_VARS (messju)
- speed up config_load, simplify compiling (Monte)
- added block-methods for registered objects (Bharat Mediratta, messju)
- ignore one char resource names like c:foo.tpl (Monte)
- added default_resource_type feature (Monte)
- fix bug where config file starts with hidden section (boots, Monte)
- add discrete error checking pertaining to $cache_dir
and $compile_dir, their existance and writability (Monte)
- fixed behaviour of start=... for {counter} (messju)
- fixed assign for {counter} (messju)
- added params vdir, hdir and inner to html_table to allow looping
over the data in various directions (messju)
- allow spaces in literal tags (Paul Lockaby, Monte)
- speed up compiled templates, hardcode plugin filepaths
instead of dynamically calculate at runtime. (Monte)
- abstract many core components from Smarty.class.php,
speeding up core class instantiation (Monte)
- fixed bug in _create_dir_structure() when used with open_basedir-
restriction and relative paths (messju)
- use DIRECTORY_SEPARATOR exclusively, keep DIR_SEP for BC (Monte)
- changed "link" to "href" in html_image. "link" is still working
but deprecated (messju)
- html_image always renders an alt-tag now (default alt="") (messju)
- fixed assign attribute for multiple counters (messju)
- added simple math operators to variables (Monte)
- enabled array(&$obj. 'source', 'timestamp', 'secure', 'trusted')
as callback for register_resource() (messju);
- enabled array(&$obj, 'method') as callback for
$default_template_handler_func (messju)
- remove unnecessary close/open tags from compiled templates
(Monte)
- fixed errornous creation of '//' in image_path in html_image (messju)
- fix escapement of special chars for key vals in debug
console (Monte)
- fixed debug timing logic for config_load (Tom Sommer, Monte)
- all in-code doc comments converted to phpDocumentor format (Greg)
- moved strip from smarty core to plugin (Monte)
- moved config_load from smarty core to plugin (Monte)
- added &$repeat-parameter to block-functions (messju)
- enabled hex-constants in function.math.php (messju)
- enabled hex-constants (0x...) as function-attributes, inside if-statements
and as modifier-parameters (messju)
- fixed bug with passing $smarty as reference in Smarty.compiler.class
(messju)
- corrected output with {strip} and PHP tag newlines (Monte)
- added possibility to register function-callbacks as "array(&$obj, 'method)"
this affects register_function(), -block, -compiler_function, -modifier,
-prefilter, -postfilter, -outputfilter-functions() and $cache_handler_func
(messju)
- added <labels> to html_checkboxes and html_radios (Philippe, messju)
- added "labels"-options to turn off labels in html_checkboxes and _radios
(messju)
Version 2.5.0 (April 11, 2003)
------------------------------
- fixed bug with default modifier when passing integer 0
(Monte)
- change backtic syntax from $`foo` to `$foo` (Monte)
- recognize $foo[][] syntax inside embedded quotes without
backtics (Monte)
- name=123 is passed as an integer (not a string) to plugins now (messju)
- $length is now propagated to sub-values in debug_print_var (messju)
Version 2.5.0-RC2 (March 26, 2003)
----------------------------------
- made clear_cache() ignore compile_id, when clearing cache-groups (this
is when no $tpl_file is supplied) (messju)
- made onmouseout XHTML-compliant in function.popup.php (messju)
- applied local-var-naming-scheme to fetch() (messju)
- renamed $localvars to $_localvars in cache-file-handling-functions,
added _get_auto_id()-function (messju)
- swapped compile_id and cache_id in read_cache_file and write_cache_file
(messju)
- reverted patch for cache-file-handling (messju)
- made html_radios and html_checkboxes accept "selected" instead
of "checked" optionally. (messju)
- made compile_id ignored in clear_cache, made order of
auto_file_name $cache_id.$compile_id again, applied the the new
variable-naming-scheme for cache_file_handing functions (messju)
- removed notice of undefined var in _rm_auto() (messju)
- added warning message when an array is passed as
the "checked" value of html_radios (Monte)
- fixed errormessage in _compile_smarty_ref() (messju)
- updated docs for html_image "name" -> "file" (messju)
- fixed bug with html_options-optgroups (Nichlas Löfdahl, messju)
- cleaned up calls to readdir() (messju)
- fixed bug with passing multiple modifiers to a parameter
(Monte)
- updated docs for html_checkboxes, html_options and html_radios (messju)
- fixed wrong default "name" attribute for html_options (messju)
- html_checkboxes now expect the options as attribute "options" instead
of "checkboxes. html_radios expect "options" instead of "radios".
cleaned up indentiation (messju)
- fixed too greedy str_replace in trimwhitespace outputfilter (messju)
- html_checkboxes and html_radios passthru all unknown paramters now
additionally their output is now XHTML compliant (messju)
- html_options passthru all unknown paramters now (messju)
- fix link functionality of html_image, also make
output XHTML compatible (Hinrich Donner, Monte)
- append "@" to default modifier vars/args
supress possible warnings (Monte)
- fix problem with escaped double quotes (Monte)
- fix html_radios to not return an array (Monte)
- fixed length in modifier.truncate.php (messju)
- fixed handling of '$'-signs in trimwhitespace outputfilter (messju)
- fix bug that makes config files recompile every time
(Nagger, Monte)
- add dpi functionality to html_image, change "name"
parameter to "file" (Thomas Shulz, Monte)
- fix height/width parameter index in html_image (Gerard,
Monte)
- get rid of unsetting name and script attributes
to insert tag (Thomas Schulz, Monte)
- changed argument order of string_format modifier back,
was right in the first place (Monte)
Version 2.5.0-RC1 (March 5, 2003)
---------------------------------
- fixed notice in popup function (Nagger, Monte)
- fix "once" var compiling for include_php (Monte)
- added nl2br modifier to distribution (Monte)
- added html_image to distribution (Monte)
- added cat modifier to distribution (Monte)
- added html_table to distribution (Monte)
- added << >> <> support to if statments (SMK, Monte)
- fix _assign_smarty_interface to not overwrite keys
other than 'request' (Jerome Poudevigne, Monte)
- added html_checkboxes to distribution (Christopher Kvarme, Monte)
- added html_radios to distribution (Christopher Kvarme, Monte)
- fixed string_format modifier args (wrong order) (Paul
Lockaby, Monte)
- use tmp file for file writes, avoid file lock race (Monte)
- support syntax "$`smarty.config.foo`.tpl" for embedded
vars in quotes, and allow full dollar var syntax (Monte)
- add $smarty.config.varname variable for accessing config vars (Paul
Lockaby, Monte)
- silence PHP warnings in function.fetch.php (Eduardo,
Monte)
- added get_config_vars(), same basic functionality as
get_template_vars() (Monte)
- update get_template_vars() to be able to get
individual vars (Monte)
- fix minor logic in _fetch_template_info (Dennis Gearon,
Monte)
- fix cache groups with compile_id set (Monte)
- add support for merging appended vars (messju, Monte)
- allow null as function attribute value
(André Rabold, Monte)
- support $foo->bar[index] syntax (Monte)
- add get_registered_object function (messju, Monte)
- treat unrecognized param attribute syntax as string (Monte)
- support $smarty.const.$foo syntax (messju, Monte)
- remove E_NOTICE warnings from debug.tpl,
escape modifier (Kanstantin, Monte)
- don't count non-ascii chars in count_words modifier
(Kanstantin, Monte)
- clean up param calls to _parse_var and _parse_attrs (Monte)
- define $template_source var, elude possible warning
(Monte)
- fix syntax problem with evaluating PHP constants (Monte)
- add @ and === as valid if statement tokens (Monte)
- enable error messages for config_load errors,
use $this->config_class for loading class name (Monte)
- fix html_options to not escape already escaped entities (Monte)
- send Last-Modified header on cache creation (Monte)
- check strict syntax of function attributes (Monte)
- dropped support for modifers on object parameters,
added support for objects as modifier parameters (Monte)
- fixed bug with decimal numbers in if statements (Monte)
Version 2.4.2 (Feb 11, 2003)
----------------------------
- support embedded variables in objects (Monte)
- fix bug with objects with no properties (M Mohr, Monte)
- support full dollar var syntax in quoted text (Monte)
- fixed bug in $smarty.const.FOO introduced in 2.4.1 (M
Mohr, Monte)
Version 2.4.1 (Feb 6, 2003)
---------------------------
- ignore case in IF statements (Rainer Collet, Monte)
- treat undefined constants as null (Ferdinand Beyer, Monte)
- fix problem with inserts and nested fetches
(Rainer Collet, Monte)
- added support for passing params to include_php
(Tim Riley, Monte)
- added support for math operators in if statements (Monte)
- added support for $foo->bar[$x].blah syntax (Monte)
Version 2.4.0 (Feb 2, 2003)
---------------------------
- fix known problems with php tag handling in templates
(recursion, echoing xml tags) (Monte)
- add support for object registration (Monte)
- add debug template to secure_dir, add template_dir
to secure_dir by default (Ferdinand Beyer, Monte)
- added support for assigned object access (Monte)
- fixed bug with directories named '0' (Frank Bauer, Monte)
- add javascript parameter to escape modifier (Monte)
- added calling function line numbers to syntax error
messages in compiler (Monte)
- added support for modifiers to function calls (Monte)
- support return value for custom functions
instead of echoing (but echo still works) (Monte)
- added direct access to constants
via $smarty.const.FOO (Monte)
- added support for passing modifiers
to static values (Monte)
- fix up regex code in compiler, more accurate and
maintainable (Monte)
- added day_value_format to html_select_date (Marcus
Bointon, Monte)
- assigned variables are no longer in global
namespace, saving extract() calls and speeding
up fetch() and display() linearly with no. of
assigned variables (Monte)
- added trimwhitespace output filter to dist. (Monte)
- fix popup function to allow newlines in text (Monte)
- escape html entities in html_options (Monte)
- fixed bug with label for html_options (Monte)
- added config_load API function (Monte)
- added caching to config file loading (Monte)
- added "extra" parameter to mailto function (Monte,
Massimiliano Perantoni)
- added mailto plugin to dist. (Monte)
Version 2.3.1 (Nov 19, 2002)
----------------------------
- added optgroup support to html_options (Monte, Robert
Amos)
- set mtime on compile files so they match source
files (Monte, Peter Bowen)
- added proper support for open_basedir setting
(Monte, Alessandro Astarita)
- added strip variable modifier, updated docs (Monte)
- fixed access to $smarty.x variables as arrays. (Andrei)
- fixed errors with example setup docs (Monte, Matthew
Hagerty)
- added textformat block function (Monte)
Version 2.3.0 (Aug 7, 2002)
---------------------------
- added assign_by_ref() and append_by_ref() functions
(Bob Silva, Monte)
- changed default warning type for plugin errors from
E_USER_WARNING to E_USER_ERROR (Monte)
- added $all_extra, $hour_extra, $minute_extra,
$second_extra and $meridian_extra parameters to
html_select_time function (Rainer Collet, Monte)
- update debug console to print objects (Simon Willison,
Monte)
- fix Config_File class to not error when there are no
sections (Peter Kmet, Monte)
- add default modifier logic (Monte)
- updated popup_init to be xhtml compliant (Tom Oram, Monte)
- fix filename bug with windows (Gary Loescher, Monte)
- add ability to supply expire time in seconds when clearing
cache or compile files (Monte)
- add {debug} plugin to distribution (Monte)
- fixed bug with insert tags, loading from "script" attribute
when caching is enabled (Monte)
- fix bug with debug_tpl file path with Windows (.SMK., Monte)
- fix append() function with string/array problem (Monte)
Version 2.2.0 (July 11, 2002)
-----------------------------
- make debug.tpl work with any delimiter (Monte)
- change logic in assign() and append() to test var names
against != '' instead of empty() (Monte)
- fix PHP notice in append() function (Monte)
- allow $plugins_dir to be an array of directories
(Andreas Kossmeier, Monte)
- move debug.tpl to SMARTY_DIR, add to constructor (Monte)
- fixed warning message in function.assign_debug_info (Monte)
- fixed $template_dir, $compile_dir, $cache_dir, $config_dir,
$plugin_dir to respect include_path (Monte)
- fixed warning message with output filter array (Monte)
- add optional 2nd parameter to date_format, used as
the default date if the passed date is empty (Monte)
- gave $reset a default value in cycle plugin (Monte)
- fixed warnings with html_select_date and timestamp
functions (Monte)
- added support for sub directory exlusion format (Monte)
- added support for grouping by cache_id, compile_id
and segments thereof (Monte)
- changed cache and compile files to human readable
format (Monte)
- remove overlib.js file from distribution (Monte)
- fixed bug with 304 Not Modified response sending
content (Monte)
- fixed cycle function to respect delimiter after
initial setting (Monte)
- update $GLOBALS references to work properly with
track_globals settings (Michal Prinke, Monte)
- fixed bug in math function with call to assign
(Grigory V. Kareev, Monte)
- optimized for loops with count() function calls (Monte)
- add month_value_format attribute to html_select_date
plugin (Gary Loescher, Monte)
- made it possible to use simple variables inside [] for
indexing. (Andrei)
- added "once" attribute to {include_php}. (Monte)
Version 2.1.1
-------------
- added cycle function. (Monte)
- fixed bug with resource testing, and include_path. (Monte)
- fixed a bug with register_outputfilter function. (Monte)
Version 2.1.0
-------------
- introduced output filters. (Andrei)
- changed the way filters are loaded, added load_filter()
API function and $autoload_filters variable. (Andrei)
- added caching logic for expire times per cache file
(Norbert Rocher, Monte)
- fixed html_select_date when field separator is "/"
(Roberto Berto, Monte)
- added YYYY-MM-DD format support to html_select_date
(Jan Rosier, Monte)
- fixed cache_lifetime logic bug, also made -1 = never
expire (Monte)
- fixed directory separator issue for Windows. (Andrei)
- added ability to use simple variables as array indices or
object properties. (Andrei)
- added ability to unregister pre/postfilters plugins at
runtime. (Andrei)
- added 'htmlall' attribute to escape modifier. (Monte)
- added template_exists() API function. (Andrei)
- fixed a problem with using dynamic values for 'file'
attribute of {include_php} tag. (Andrei)
- added $smarty.template variable. (Andrei)
- fixed several plugins that would not work if the plugin
directory was not the default one. (Andrei)
- implemented support for block functions. (Andrei)
- made it possible to assign variables in pre/postfilter
plugins. (Andrei)
Version 2.0.1
-------------
- rename plugin .make_timestamp.php to shared.make_timestamp.php.
(Monte)
- changed crc32() generated values, replace '-' with 'N'. (Monte)
- added support for +/- N syntax in html_select_date year values.
(Monte)
- fixed behavior of inserts with script attribute. (Andrei)
- fixed bug with $smarty.cookies and $smarty.server. (Andrei)
- wordwrap and indent are missing from 2.0 release, now fixed.
(Monte)
- removed show_info_header and show_info_include variables. (Monte)
Version 2.0.0
-------------
- added "eval" function plugin for evaluating variables as
templates. (Monte)
- removed $tpl_file_ext class variable, no longer used. (Monte)
- added "hex" and "hexentity" escape types to escape modifier.
(Monte)
- removed dependency on PEAR. (Andrei)
- update popup_init to accept src attribute. (Monte, Duncan Forrest)
- implemented several optimizations, speeding up Smarty
significantly in most cases. (Andrei,Monte)
- implemented plugin architecture. (Andrei)
- added wordwrap and indent modifiers. (Monte)
- added support for 'If-Modified-Since' headers for cached content.
(Monte)
- removed insert_tag_check class variable, no longer needed. (Monte)
- optimized cache fetches by scanning for insert tags only if they
exist. (Monte)
- fixed bugs in overlib. (Monte, Duncan Forrest)
- fixed a problem with compile_id usage. (Andrei)
- fixed problem with using assigned vars with {include_php ...}
filepath. (Monte)
Version 1.5.2
-------------
- added Smarty object as fifth argument for template resource functions.
(Monte)
- fixed a bug with incorrectly combined cache and compile id in
clear_cache(). (Andrei)
- fixed bug in smarty_make_timestamp introduced in PHP 4.1.0. (Monte)
- fixed bug with cached insert debug timing. (Monte)
- added 'script' attribute to {insert..} which specifies the script that
the insert function can be found in. (Andrei)
- added default template function handler. (Monte)
Version 1.5.1
-------------
- removed error message from the generic _read_file() method, the caller
should take care of that. (Andrei)
- fixed a bug with incorrectly combined cache and compile id. (Andrei)
Version 1.5.0
-------------
- added include_php built-in function, documented. (Monte)
- added trusted_dir functionality, documented. (Monte)
- consolidated secure_dir tests to one function. (Monte)
- prepended _smarty_ to variable names in fetch() class function to avoid
namespace conflicts. (Monte)
- introduced $compile_id class variable that can be used to set persistent
compile identifier across multiple display calls, documented. (Andrei)
- fixed bug with concatenated null cache and compile identifiers. (Andrei)
- added $smarty.section.* syntax for accessing section properties,
documented. (Andrei)
- added custom cache handling function ability, documented. (Monte)
- added assign attribute to include, include_php, insert, fetch, math, and
counter functions, documented. (Monte)
- fixed bug with fetch testing for local file when http address. (Monte)
- fixed bug with counter and skipval setting. (Monte)
- made {config_load ...} merge globals from each config file only once per
scope, thus avoiding several problems. (Andrei)
- added {foreach ...} tag that can be used to iterate through
non-sequential and associative arrays, documented. (Andrei)
- speeded up section property access a bit. (Andrei)
- removed $smarty variable from storage used by normal template variables,
to prevent any problems. (Andrei)
- fixed a bug that could cause parse error with quotes inside literal
blocks. (Andrei, Alexander Belonosov)
- added 'field_array' attribute to html_select_time function, documented.
(Andrei, Michael Caplan)
- documented {section} "max" attribute. (Monte)
- fixed notice message in Smarty_Compiler.class.php. (Monte)
- fixed bug with clear_cache introduced in 1.4.6, third parameter should
default to null. (Monte)
- updated Config_File class to support '\' path separator in OS/2. (Monte,
Francesco Cipriani)
- removed secure_ext setting (not used). (Monte)
- made cache reading process more efficient. (Monte)
- fixed bug, is_cached() now supports new 1.4.6 caching behavior. (Monte)
- update FAQ with mailing list Reply-To header FAQ. (Monte)
- supress error messages for fopen(), fix cache to regenerate if cache
file is not available (i.e. cluster race condition). (Monte)
- added index key example to QUICKSTART guide. (Monte)
Version 1.4.6
-------------
- fixed bug with {assign ...} when passing an empty value. (Monte)
- add more warning message fixes. (Monte, Tara Johnson)
- documentation updates. (Monte)
- update fetch function to give proper warning when fetching a non-readable
or non-existant file. (Monte)
- fixed problem with newline at the end of included templates (Monte, Andrei)
- added feature to regenerate cache if compile_check is enabled and an
involved template or config file gets modified. (Monte)
- added DEBUG execution times to included files: REQUIRES updated debug.tpl
file! (Monte)
- added support for hidden config variables that cannot be read by
templates. (Andrei)
- added execution time to DEBUG console, total and inserts. (Monte)
- fixed bug where DEBUG console would not appear with cached content. (Monte)
- added support for postfilter functions that are applied to compiled
template right after compilation. (Andrei)
- fixed the name of clear_compile_tpl() API function to clear_compiled_tpl.
(Andrei)
- added fix for removing comments so that the line numbers are reported
correctly in case of errors. (patch from Anders Janson)
- made html_options output xhtml compatible code. (Monte, Arnaud Limbourg)
Version 1.4.5
-------------
- update FAQ with index of questions at the top
- update overlib to 3.50, adjust addon code so that the overlib.js
file isn't modified, and not using the mini one. (Monte)
- added many more options to html_select_date. (Alexander Skwar, Andrei)
- added support for generating different compiled templates from the same
source template. (Hans-Peter Oeri, Andrei)
- modified Smarty to pass itself to insert functions as the second
parameter. (Andrei)
- modified Smarty to pass itself to prefilter functions as the second
parameter. (Andrei)
- fixed syntax error when including a non-existant template with security
enabled. (Monte)
- fixed comments handling to allow commenting out template blocks. (Andrei)
- implemented named capture buffers, with results accessible via
$smarty.capture.<name>. (Andrei)
- added ability to index arrays directly by numbers. (Andrei)
- fixed bug with SMARTY_DIR not prepended to Config_File include. (Monte)
Version 1.4.4
-------------
- fixed problem with including insecure templates with security enabled.
(Monte)
- numerous documentation updates. (Monte)
- added ENT_QUOTES to escapement of html. (Monte, Sam Beckwith)
- implemented access to request variables via auto-assigned $smarty
template variable. (Andrei)
- fixed a bug with parsing function arguments inside {if} tags if a comma
was present. (Andrei)
- updated debug console with config file vars. (Monte)
- added SMARTY_DIR constant as an alternative to relying on include_path.
(Monte)
- added popup_init and popup functions (requires overlib.js). (Monte)
- updated debug console with config file vars. (Monte)
- added debugging url control. (Monte)
- added 'quotes' type to escape modifier. (Monte, Mike Krus)
- added 'total' and 'iteration' section properties. (Andrei)
- added 'start', 'max', and 'step' section attributes/properties. (Andrei)
- fixed a bug with security checking of functions inside {if} tags.
(Andrei)
- fixed a bug in Config_File that would incorrectly booleanize values that
weren't really booleans. (Andrei)
Version 1.4.3
-------------
- added regex_replace modifier, documented. (Monte)
- added debugging console feature and custom function assign_debug_info,
documented. (Monte)
- added 'scope' attribute for {config_load}, 'global' is now deprecated but
is still supported. (Andrei)
- reduced template symbol table pollution by moving config array into the
class itself. (Andrei)
- fixed a bug with passing quoted arguments to modifiers inside {if}
statements. (Andrei, Sam Beckwith)
- added security features for third party template editing, documented
(Monte)
- added assign custom function, documented. (Monte)
- fixed bug with template header using version instead of _version. (Monte)
- fixed a problem with putting $ followed by numbers inside {strip} and
{/strip} tags. (Andrei)
- fixed Config_File class to allow empty config paths (defaults to current
directory). (Andrei)
Version 1.4.2
-------------
- move $version to internal variable, remove from docs. (Monte)
- cleaned up compiled templates global scope by moving some variables into
the class itself. (Andrei)
- fixed a bug that would not allow referring to a section in the including
file from the included file. (Andrei)
- configs directory missing from 1.4.1 release, added back in. (Monte)
- added windows include_path setup instructions to FAQ & QUICKSTART.
(Monte)
Version 1.4.1
-------------
- fix LOCK_EX logic for all windows platforms (Monte)
- fixed indexing by section properties with the new syntax. (Andrei)
- updated Smarty to use absolute paths when requiring/including Smarty
components. (Andrei, John Lim)
Version 1.4.0
-------------
- added {capture}{/capture} function, documented (Monte)
- added {counter} function, documented (Monte)
Version 1.4.0b2
---------------
- fixed issue in Config_File.class with referencing blank sections (Andrei)
- fixed problem with passing variables to included files (Andrei)
- fixed resource path recognition for windows (Monte)
Version 1.4.0b1
---------------
- added "componentized templates" tip into documentation (Monte)
- added {php}{/php} tags for embedding php code into templates (Monte)
- changed default value of $show_info_header to false (Monte)
- implemented '->' syntax for accessing properties of objects passed to the
template. (Andrei)
- allowed custom functions to receive Smarty object as the second
parameter; this can be used to dynamically change template variables, for
example. (Andrei)
- added custom compiler functions support, register_compiler_function() and
unregister_compiler_function() API functions. (Andrei, Ivo Jansch).
- updated GLOBAL_ASSIGN to take SCRIPT_NAME from HTTP_SERVER_VARS
instead of global variable. You can also assign several variables
in one shot with an array. (Monte, Roman Neuhauser)
- added template prefilters, register_prefilter() and
unregister_prefilter() API functions. (Monte)
- added RELEASE_NOTES file to distribution. (Monte)
- moved CREDITS out of manual into its own file. (Monte)
- added register_resource() and unregister_resource() API functions. (Monte)
- changed the syntax of indexing template variables, thus supporting
structures of arbitrary complexity; supplied fix_vars.php script to fix
old syntax. (Andrei)
- added $insert_tag_check to speed up cached pages if {insert ...} is not
used. (Monte)
- added $compiler_class variable to allow specifying a different compiler
class. (Andrei)
- changed Smarty to compile templates at runtime, allowing for arbitrary
template resources. (Monte)
- added fix for LOCK_EX under Windows and changed a couple of file
permissions for security. (Monte, Fernando Nunes)
- allow arbitrary date strings to date_format, html_select_date and
html_select_time (Monte)
Version 1.3.2
-------------
- fixed a bug that caused some nested includes to loop infinitely. (Andrei)
- added optional HTML header to output. (Monte)
- significantly improved config_load performance. (Andrei)
- added format attribute to math function. (Monte)
- added html_select_time custom function. (Andrei)
- fixed minor PHP warning when attempting to unset an unset variable
(Monte)
- added count_characters, count_words, count_sentences, count_paragraphs
modifiers (Monte)
Version 1.3.1pl1
--------------
- bug fix, recovered missing _syntax_error function (Monte)
Version 1.3.1
-------------
- document first, last, index_prev, index_next (Monte)
- added 'first' and 'last' section properties. (Andrei)
- split out compiling code to separate class for faster template execution
time (Monte)
- fixed a couple of minor PHP warnings (Monte)
- added and documented unregister_modifier() and unregister_function() API
calls. (Monte)
- added and documented 'fetch' and 'math' functions. (Monte)
- added ability to index looped variables by section properties, e.g.
$foo.index_prev/bar. (Andrei)
- added index_prev and index_next section properties. (Andrei)
- fixed issue with php executing in literal blocks. (Monte)
Version 1.3.0
-------------
- moved license from GPL to LGPL (Monte)
- implemented workaround for PHP "feature" that eats carriage returns
if the PHP tag is at the end of the line. (Andrei)
- removed $allow_php, added $php_handling logic (Monte)
- added file locking to prevent reader/writer problem. (Andrei)
- made Smarty catch unimplemented modifiers and custom functions and output
error messages during compilation instead of failing during run time.
(Andrei)
- removed short-tags at the top of the smarty scripts (Monte)
- added register_function() and register_modifier() API calls to make
registering stuff easier. (Andrei)
- added template results caching capability. (Monte, Andrei)
- added optional 'options' attribute to html_options custom function
that allows passing associative arrays for values/output. (Andrei)
- modifier arguments can now contain '|' and ':' characters inside quoted
strings. (Andrei)
Version 1.2.2
-------------
- fixed bug that would not respect nested template directories and would
put all compiled files into top-level one. (Andrei)
- fixed bug using $PHP_VERSION instead of environment var PHP_VERSION.
(Monte)
- a couple small warning fixes. (Monte)
Version 1.2.1
-------------
- added $compile_dir, removed $compile_dir_ext, simplified usage. (Monte)
- added tips & tricks chapter to documentation. (Monte)
- misc documentation updates. (Monte)
Version 1.2.0
-------------
- updated documentation (Monte)
- added file and line number information to syntax error messages. (Andrei)
- added ability to index template vars by a key. (Andrei)
Version 1.1.0
-------------
- misc documentation changes, official stable release
Version 1.0b
------------
- fixed the bug that prevented using non-array values for 'loop' attribute.
(Andrei)
- many misc documentation changes & additions (Monte)
Version 1.0a
------------
- fixed bug that caused templates to recompile every time (Monte)
Version 1.0
------------
- initial release
/* vim: set et tw=64 ft=changelog: */

View File

@ -1,80 +0,0 @@
NAME:
Smarty - the PHP compiling template engine
VERSION: 2.6.0
AUTHORS:
Monte Ohrt <monte@ispi.net>
Andrei Zmievski <andrei@php.net>
MAILING LISTS:
We have a few mailing lists. "general" for you to share your ideas or ask
questions, "dev" for those interested in the development efforts of Smarty,
and "cvs" for those that would like to track the updates made in the cvs
repository.
send a blank e-mail message to:
smarty-general-subscribe@lists.php.net (subscribe to the general list)
smarty-general-unsubscribe@lists.php.net (unsubscribe from the general list)
smarty-general-digest-subscribe@lists.php.net (subscribe to digest)
smarty-general-digest-unsubscribe@lists.php.net (unsubscribe from digest)
smarty-dev-subscribe@lists.php.net (subscribe to the dev list)
smarty-dev-unsubscribe@lists.php.net (unsubscribe from the dev list)
smarty-cvs-subscribe@lists.php.net (subscribe to the cvs list)
smarty-cvs-unsubscribe@lists.php.net (unsubscribe from the cvs list)
You can also browse the mailing list archives at
http://marc.theaimsgroup.com/?l=smarty&r=1&w=2
SYNOPSIS:
require("Smarty.class.php");
$smarty = new Smarty;
$smarty->assign("Title","My Homepage");
$smarty->assign("Names",array("John","Gary","Gregg","James"));
$smarty->display("index.tpl");
DESCRIPTION:
What is Smarty?
Smarty is a template engine for PHP. Many other template engines for PHP
provide basic variable substitution and dynamic block functionality.
Smarty takes a step further to be a "smart" template engine, adding
features such as configuration files, template functions, and variable
modifiers, and making all of this functionality as easy as possible to
use for both programmers and template designers. Smarty also converts
the templates into PHP scripts, eliminating the need to parse the
templates on every invocation. This makes Smarty extremely scalable and
manageable for large application needs.
Some of Smarty's features:
* it is extremely fast
* no template parsing overhead, only compiles once.
* it is smart about recompiling only the template files that have
changed.
* the template language is remarkably extensible via the plugin
architecture.
* configurable template delimiter tag syntax, so you can use
{}, {{}}, <!--{}-->, or whatever you like.
* built-in caching of template output.
* arbitrary template sources (filesystem, databases, etc.)
* template if/elseif/else/endif constructs are passed to the PHP parser,
so the if syntax can be as simple or as complex as you like.
* unlimited nesting of sections, conditionals, etc. allowed
* it is possible to embed PHP code right in your template files,
although not recommended and doubtfully needed since the engine
is so customizable.
* and many more.
COPYRIGHT:
Copyright (c) 2001,2002 ispi of Lincoln, Inc. All rights reserved.
This software is released under the GNU Lesser General Public License.
Please read the disclaimer at the top of the Smarty.class.php file.

View File

@ -1,423 +0,0 @@
2.5.0
-----
Very minor adjustments since RC2, see the NEWS file for details.
2.5.0-RC2
---------
Many fixes since the RC1 release. This one is as close to production quality as
they come, so this will be the last release before 2.5.0. The SGML documentation
files have also been removed from the tarball. If you want them, get them from
the CVS repository.
2.5.0-RC1
---------
Release Candidate 1. All $smarty vars can now be dynamic, such as
$smarty.get.$foo. A new class function get_function_object() gets you a
reference to an assigned object, useful within your own custom functions.
append() can now merge as well as append with a third optional attribute. A new
class function get_config_vars() was added, and get_template_vars() can now be
used to get individual vars. Full variable syntax is now supported within
double quotes via a backtick (`) syntax. Files created by smarty are now
written to a tmp file then renamed to avoid file lock retention. html_radios,
html_checkboxes, html_table, html_image, nl2br functions added, see the NEWS
file for full details.
2.4.2
-----
Another point release. Added support for dynamic object reference syntax
($foo->$bar), support for full variable syntax within quotes ("$foo[0].bar"),
and other minor fixes. See the NEWS file for full details.
2.4.1
-----
This is basically a point release, cleaning up a few things caught
in the 2.4.0 release. See the NEWS file for full details.
2.4.0
-----
Smarty now supports the ability to access objects within the templates. Two
methods are available, one which closely follows Smartys conventions, and
another that follows more traditional object syntax for those familiar with
PHP.
The internal compiling engine has also undergone some major work. The regex
parsing was rewritten to be much more strict, more secure and more
maintainable. Config files are now compiled, which can speed up pages quite a
bit that use config files extensively. Assigned variables are no longer
extracted to PHP namespace, saving an extract call for every template. There is
now support for applying modifiers to static values and functions. You can now
access constants with $smarty.const.VAR. See the NEWS file for complete
changes.
2.3.1
-----
The mtime on compiled files will now match the source files, in the case where
the source file may not get the current timestamp, recompiling will still work
as expected. Proper support for open_basedir has been added, so Smarty should
work correctly in safe mode. Added a few new features such as textformat block
function, strip variable modifier and optgroup support for html_options. Also
other minor bug fixes, see the Change Log.
2.3.0
-----
Smarty now has a {debug} template function that brings up the debugging console
right where {debug} is called, regardless of $debugging settings. This works a
little different than turning on $debugging in the sense that it shows all the
template variables available at the time {debug} is called, including local
scope vars. It does not show the templates names however, since this
executed during runtime of the template.
You can now supply an expire time when clearing cache or compile files. This is
mostly useful for removing stale files via the API.
Plugins now stop execution upon error, instead of outputting a warning and
continuing.
Two new API functions, assign_by_ref() and append_by_ref() were added. They
allow assigning template variables by reference. This can make a significant
performance gain, especially if you are assigning large arrays of data. PHP 5.0
will do this implicitly, so these functions are basically workarounds.
Several misc bug fixes, see the Change Log for information.
2.2.0
-----
Smarty now allows an array of paths for the $plugin_dir class variable. The
directories will be searched in the order they are given, so for efficiency keep
the most-used plugins at the top. Also, absolute paths to the plugin directories are
more efficient than relying on the PHP include_path.
Cache files can now be grouped with the cache_id. See the documentation under
the new "Caching" section for details. compile_id also respects the same
grouping syntax. The cache/compile file structure changed, so be sure to clear
out all your cache and compile files when upgrading Smarty. Also if you are
using PHP-accelerator, restart apache. I've seen some quirky things happen if
the phpa files do not get cleared (known issue with phpa and parent
class-member changes, so just clear 'em.)
Smarty now correctly respects the PHP include_path for $template_dir, $compile_dir,
$cache_dir, $config_dir and $plugin_dir. Be aware that relying on the
include_path is an overhead, try to use absolute pathnames when possible
(or relative to working directory.)
Documentation has been updated and rearranged a bit. Most notably, the
installation instructions are completely revamped, and a new Caching section
explains Smarty's caching in detail along with the new grouping functionality.
Many misc. bug fixes and enhancements, see the full ChangeLog (NEWS file) for
details.
2.1.1
-----
There was a bug with template paths and the include_path, this has been fixed.
Also register_outputfilter() did not work, this is fixed. A new template
function named "cycle" has been added to the distribution, nice for cycling
through a list (or array) of values.
2.1.0
-----
This release has quite a few new features and fixes. Most notable are the
introduction of block functions, so you can write plugins that work on a block
of text with {func}{/func} notation. Also output filters were added, so you can
apply a function against the output of your templates. This differs from the
postfilter function, which works on the compiled template at compile time, and
output filters work on the template output at runtime.
Many other features and bug fixes are noted in the NEWS file.
2.0.1
-----
This is a point release, fixing a few bugs and cleaning things up. A plugin
was renamed, the dash "-" was removed from compiled template and cached file
names. If you're upgrading, you might want to clear them out first. See the
ChangeLog for details.
2.0.0
-----
This release is a huge milestone for Smarty. Most notable new things are a
plugin architecture, removal of PEAR dependency, and optimizations that
drastically improve the performance of Smarty in most cases.
The plugin architecture allows modifiers, custom functions, compiler functions,
prefilters, postfilters, resources, and insert functions to be added by
simply dropping a file into the plugins directory. Once dropped in, they are
automatically registered by the template engine. This makes user-contributed
plugins easy to manage, as well as the internal workings of Smarty easy to
control and customize. This new architecture depends on the __FILE__ constant,
which contains the full path to the executing script. Some older versions of
PHP incorrectly gave the script name and not the full filesystem path. Be sure
your version of PHP populates __FILE__ correctly. If you use custom template
resource functions, the format of these changed with the plugin architecture.
Be sure to update your functions accordingly. See the template resource section
of the documentation.
The PEAR dependancy was removed from Smarty. The Config_File class that comes
with Smarty was actually what needed PEAR for error handling which Smarty didn't
use, but now everything is self-contained.
Performance improvements are graphed on the benchmark page, you will see that
overall performance has been sped up by as much as 80% in some cases.
Smarty-cached pages now support If-Modified-Since headers, meaning that if a
cached template page has not changed since the last request, a "304 Not
Modified" header will be sent instead of resending the same page. This is
disabled by default, change the setting of $cache_modified_check.
1.5.2
-----
Mostly bug fixes, added a default template resource handler.
1.5.1
-----
Critical bug fix release. If you use caching, you'll need to upgrade.
1.5.0
-----
Several feature enhancements were made to this version, most notably the
{foreach ...} command which is an alternative to {section ...} with an easier
syntax for looping through a single array of values. Several functions were
enhanced so that the output can be automatically assigned to a template
variable instead of displayed (assign attribute). Cache files can now be
controlled with a custom function as an alternative to the built-in file based
method. Many code cleanups and bug fixed went into this release as well.
1.4.6
-----
The behavior with caching and compile_check has been slightly enhanced. If
caching is enabled AND compile_check is enabled, the cache will immediately get
regenerated if _any_ involved template or config file is updated. This imposes
a slight performance hit because it must check all the files for changes, so be
sure to run live sites with caching enabled and compile_check disabled for best
performance. If you update a template or config file, simply turn on
compile_check, load the page, then turn it back off. This will update the cache
file with the new content. This is accomplished by maintaining a list of
included/loaded templates and config files at the beginning of the cache file.
Therefore it is advisable to remove all cache files after upgrading to 1.4.6
(although not absolutely necessary, old cache files will regenerate)
The debug console now has script timing and array values printed. You MUST
update your debug.tpl file with this version of Smarty. Also, the new debug.tpl
will not work with older versions of Smarty.
1.4.5
-----
Mostly bug fixes and minor improvements. Added compile id for separate compiled
versions of the same script. The directory format and filename convention for
the files in templates_c has changed, so you may want to remove all of the
existing ones before you upgrade.
1.4.4
-----
A few bug fixes, new section looping attributes and properties, debugging
console function for control via URL, and overLib integration and access
to request variables from within the template.
1.4.3
-----
This release has a few bug fixes and several enhancements. Smarty now supports
template security for third-party template editing. These features disallow the
ability for someone to execute commands or PHP code from the template language.
Smarty also now has a built-in debugging console, which is a javascript pop-up
window that displays all the included template names and assigned variables.
1.4.2
-----
This was mostly one bug fix with variable scoping within included templates
and a few documentation changes and updates. See the ChangeLog file for full
details.
1.4.1
-----
It seems that the EX_LOCK logic from the previous release didn't fix all the
problems with windows platforms. Hopefully this one does. It basically
disables file locking on windows, so there is a potential that two programs
could write over the same file at the same time, fyi.
The reset is minor bug fixes, please refer to the ChangeLog file.
1.4.0
-----
IMPORTANT NOTICE
Smarty now has a new syntax for accessing elements within section loops. The
new syntax is easier to use and nicely handles data structures of any
complexity. Consequently, this breaks the old syntax.
Here is an example of the syntax change:
old syntax:
{$sec1/sec2/sec3/customer.phone}
new syntax:
{$customer[$sec1][$sec2][$sec3].phone}
The section names used to come first, followed by the variable name. Now the
variable name always comes first, followed by the section names in brackets.
You can access variable indexes anywhere, depending on how you passed the
variables in.
To fix your current templates, we have provided a script that will adjust the
syntax for you. Located in misc/fix_vars.php, run this script from the the
command line, giving each template as an argument. Be sure to use absolute
pathnames, or pathnames relative to the executing script. Probably the easiest
way to do this is to copy the fix_vars.php script into your template directory
and run 'php -q fix_vars.php *.tpl' Be sure you have proper write permission,
and backup your scripts first to be safe! The examples in the 1.4.0
documentation have been updated to reflect the changes.
cd /path/to/templates
cp /path/to/fix_vars.php .
find . -name "*.tpl" -exec php -q ./fix_vars.php {} \;
NEW AND IMPROVED COMPILATION PROCESS
Smarty 1.4.0 also has a new compilation process. Instead of compiling all the
templates up front, it now compiles them at runtime. This has several
advantages. First of all, there is no longer a need to have a single template
directory. You can now have arbitrary template sources, such as multiple
directories or even database calls. This also speeds the performance of Smarty
when $compile_check is enabled, since it is only checking the template that is
being executed instead of everything found in the template directory. The
$tpl_file_ext is no longer needed, but kept for backward compatability.
Templates can now be named anything you like with any extension.
MINOR FIXES
A workaround for LOCK_EX on Windows systems was added, and changed a couple of
file permissions for better security on public servers.
$show_info_header is now defaulted to false instead of true. This header causes
problems when displaying content other than HTML, so now you must explicitly
set this flag to true to show the header information (or change the default in
your copy of Smarty.)
Documentation is written in docbook format. I updated the docbook -> HTML
generating software & style-sheets, and consequently the examples are no longer
in a different background color. If anyone wants to contribute a better
stylesheet or help with documentation, drop me a line. <monte@ispi.net>
CHANGES/ENHANCEMENTS/UPDATES
date_format, html_select_date and html_select_time used to require a unix
timestamp as the format of the date passed into the template. Smarty is now a
bit smarter at this. It will take a unix timestamp, a mysql timestamp, or any
date string that is parsable by strtotime, such as 10/01/2001 or 2001-10-01,
etc. Just give some formats a try and see what works.
Smarty now has template prefilters, meaning that you can run your templates
through custom functions before they are compiled. This is good for things like
removing unwanted comments, keeping an eye on words or functionality people are
putting in templates, translating XML -> HTML, etc. See the register_prefilter
documentation for more info.
Another addition are the so-called compiler functions. These are custom
functions registered by the user that are executed at compilation time of the
template. They can be used to inject PHP code or time-sensitive static content
into the compiled template.
The run-time custom functions are now passed the Smarty object as the second
parameter. This can be used, for example, to assign or clear template variables
from inside the custom function.
clear_compile_dir() was added for clearing out compiled versions of your
templates. Not something normally needed, but you may have a need for this if
you have $compile_check set to false and you periodically update templates via
some automated process. As of 1.4.0, uncompiled templates _always_ get
compiled regardless of $compile_check setting, although they won't be checked
for recompile if $compile_check is set to false.
You can now refer to properties of objects assigned from PHP by using the '->'
symbol and specifying the property name after it, e.g. $foo->bar.
{php}{/php} tags were added to embed php into the templates. Not normally
needed, but some circumstances may call for it. Check out the "componentized
templates" tip in the documentation for an example.
{capture}{/capture} and {counter} functions were added. See the documentation
for a complete description and examples.
UPGRADE NOTES
The format of the files created in the $compile_dir are now a bit different.
The compiled template filename is the template resource name url-encoded.
Therefore, all compiled files are now in the top directory of $compile_dir.
This was done to make way for arbitrary template resources. Each compiled
template also has a header that states what template resource was used to
create it. From a unix command prompt, you can use "head -2 *" to see the first
two lines of each file.
When upgrading to 1.4.0, you will want to clear out all your old files in the
$compile_dir. If you have $compile_check set to false and the compiled template
does not yet exist, it will compile it regardless of this setting. This way you
can clear out the $compile_dir and not worry about setting $compile_check to
true to get the inital compilation under way.
1.3.2
-----
Smarty now has (an optional) header prepended to the output of the Smarty
templates. This displays the Smarty version and the date/time when the page was
generated. This is useful for debugging your cache routines, and purely
informational so there is evidence that the page was generated by Smarty. Set
$show_info_header to false to disable it.
{config_load ...} performance was tuned by placing the loaded variables into a
global array, so basically a config file is read from the file system and
placed into a php array structure only once, no matter how many times it is
called in any of the templates. The scope of the loaded variables has changed a
bit as well. Variables loaded by config_load used to be treated as global
variables, meaning that parent templates (templates that included the current
template) could see them. Now the default behavior is such that loaded
variables are only visible by the current template and child templates (all
templates included after the {config_load ...} is called.) To mimic the
original behavior, provide the attribute "global=yes" like so: {config_load
file="mystuff.conf" global=yes}. Now when you load in mystuff.conf, the
variables will be visible to parent templates (merged with any existing config
variables.)
A formatting attribute was added to the {math ...} function, adding the ability
to control the format of the output. Use the same formatting syntax as the PHP
function sprintf().
{html_select_time ...} was added, a custom function that works much like
{html_select_date ...} except it displays time elements instead of dates.
A few custom modifiers were added: count_characters, count_words,
count_sentences, count_paragraphs. All pretty self-explanatory.
/* vim: set et: */

View File

@ -1,10 +0,0 @@
* handle asp style tags in $php_handler
* fix all E_NOTICE warnings
* make simple math easier
* caching all but parts of the template
* change plugins so $smarty variable always comes first
* get cache ttl with function call
FIX: make inserts use normal functions before plugins
UPD: change it so that if template comes from some resource,
that resource stays as the default, no need to specify it
in includes.

View File

@ -1,5 +0,0 @@
title = Welcome to Smarty!
cutoff_size = 40
[setup]
bold = true

View File

@ -1,25 +0,0 @@
<?php
require '../libs/Smarty.class.php';
$smarty = new Smarty;
$smarty->compile_check = true;
$smarty->debugging = true;
$smarty->assign("Name","Fred Irving Johnathan Bradley Peppergill");
$smarty->assign("FirstName",array("John","Mary","James","Henry"));
$smarty->assign("LastName",array("Doe","Smith","Johnson","Case"));
$smarty->assign("Class",array(array("A","B","C","D"), array("E", "F", "G", "H"),
array("I", "J", "K", "L"), array("M", "N", "O", "P")));
$smarty->assign("contacts", array(array("phone" => "1", "fax" => "2", "cell" => "3"),
array("phone" => "555-4444", "fax" => "555-3333", "cell" => "760-1234")));
$smarty->assign("option_values", array("NY","NE","KS","IA","OK","TX"));
$smarty->assign("option_output", array("New York","Nebraska","Kansas","Iowa","Oklahoma","Texas"));
$smarty->assign("option_selected", "NE");
$smarty->display('index.tpl');
?>

Some files were not shown because too many files have changed in this diff Show More