Updated getID3() to the latest version.

This commit is contained in:
Peter Deltchev 2015-12-20 03:20:04 -08:00
parent c99ec8fc54
commit 476e6b4800
111 changed files with 730 additions and 305 deletions

0
app/Library/getid3/.gitattributes vendored Executable file → Normal file
View file

7
app/Library/getid3/.gitignore vendored Executable file → Normal file
View file

@ -1,4 +1,4 @@
helperapps/sha1sum.exe helperapps/*.exe
helperapps/*.dll helperapps/*.dll
@ -110,7 +110,9 @@ ClientBin
stylecop.* stylecop.*
~$* ~$*
*.dbmdl *.dbmdl
Generated_Code #added for RIA/Silverlight projects
#added for RIA/Silverlight projects
Generated_Code
# Backup & report files from converting an old project file to a newer # Backup & report files from converting an old project file to a newer
# Visual Studio version. Backup files are not needed, because we have git ;-) # Visual Studio version. Backup files are not needed, because we have git ;-)
@ -165,3 +167,4 @@ pip-log.txt
# Mac crap # Mac crap
.DS_Store .DS_Store
demos/php_error.log

2
app/Library/getid3/README.md Executable file → Normal file
View file

@ -186,7 +186,7 @@ if ($fp_remote = fopen($remotefilename, 'rb')) {
fclose($fp_local); fclose($fp_local);
// Initialize getID3 engine // Initialize getID3 engine
$getID3 = new getID3; $getID3 = new getID3;
$ThisFileInfo = $getID3->analyze($filename); $ThisFileInfo = $getID3->analyze($localtempfilename);
// Delete temporary file // Delete temporary file
unlink($localtempfilename); unlink($localtempfilename);
} }

11
app/Library/getid3/changelog.txt Executable file → Normal file
View file

@ -18,6 +18,17 @@
Version History Version History
=============== ===============
1.9.10: [2015-09-14] James Heinrich
* bugfix (G:49): Declaration of getID3_cached_sqlite3
* bugfix (#1892): extension.cache.mysql
* bugfix (#1891): duplicate default clause [Quicktime]
* bugfix (G:41): incorrect MP3 playtime
* bugfix: iconv problems on musl with //TRANSLIT
* Add arguments to analyze() for original filesize (and filename)
* ID3v2 simplify handling of multiple genres
* Corrected merging of multiple genres for ID3v2
* getid3_lib::GetDataImageSize return false on error
1.9.9: [2014-12-18] James Heinrich 1.9.9: [2014-12-18] James Heinrich
» Added basic support for OggOpus » Added basic support for OggOpus
» Add ID3v2 CHAP + CTOC support » Add ID3v2 CHAP + CTOC support

0
app/Library/getid3/composer.json Executable file → Normal file
View file

0
app/Library/getid3/demos/demo.audioinfo.class.php Executable file → Normal file
View file

0
app/Library/getid3/demos/demo.basic.php Executable file → Normal file
View file

8
app/Library/getid3/demos/demo.browse.php Executable file → Normal file
View file

@ -480,8 +480,11 @@ function table_var_dump($variable, $wrap_in_td=false, $encoding='ISO-8859-1') {
//if (($key == 'data') && isset($variable['image_mime']) && isset($variable['dataoffset'])) { //if (($key == 'data') && isset($variable['image_mime']) && isset($variable['dataoffset'])) {
if (($key == 'data') && isset($variable['image_mime'])) { if (($key == 'data') && isset($variable['image_mime'])) {
$imageinfo = array(); $imageinfo = array();
$imagechunkcheck = getid3_lib::GetDataImageSize($value, $imageinfo); if ($imagechunkcheck = getid3_lib::GetDataImageSize($value, $imageinfo)) {
$returnstring .= '</td>'."\n".'<td><img src="data:'.$variable['image_mime'].';base64,'.base64_encode($value).'" width="'.$imagechunkcheck[0].'" height="'.$imagechunkcheck[1].'"></td></tr>'."\n"; $returnstring .= '</td>'."\n".'<td><img src="data:'.$variable['image_mime'].';base64,'.base64_encode($value).'" width="'.$imagechunkcheck[0].'" height="'.$imagechunkcheck[1].'"></td></tr>'."\n";
} else {
$returnstring .= '</td>'."\n".'<td><i>invalid image data</i></td></tr>'."\n";
}
} else { } else {
$returnstring .= '</td>'."\n".table_var_dump($value, true, $encoding).'</tr>'."\n"; $returnstring .= '</td>'."\n".table_var_dump($value, true, $encoding).'</tr>'."\n";
} }
@ -515,8 +518,7 @@ function table_var_dump($variable, $wrap_in_td=false, $encoding='ISO-8859-1') {
default: default:
$imageinfo = array(); $imageinfo = array();
$imagechunkcheck = getid3_lib::GetDataImageSize($variable, $imageinfo); if (($imagechunkcheck = getid3_lib::GetDataImageSize($variable, $imageinfo)) && ($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3)) {
if (($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3)) {
$returnstring .= ($wrap_in_td ? '<td>' : ''); $returnstring .= ($wrap_in_td ? '<td>' : '');
$returnstring .= '<table class="dump" cellspacing="0" cellpadding="2">'; $returnstring .= '<table class="dump" cellspacing="0" cellpadding="2">';
$returnstring .= '<tr><td><b>type</b></td><td>'.getid3_lib::ImageTypesLookup($imagechunkcheck[2]).'</td></tr>'."\n"; $returnstring .= '<tr><td><b>type</b></td><td>'.getid3_lib::ImageTypesLookup($imagechunkcheck[2]).'</td></tr>'."\n";

0
app/Library/getid3/demos/demo.cache.dbm.php Executable file → Normal file
View file

1
app/Library/getid3/demos/demo.cache.mysql.php Executable file → Normal file
View file

@ -17,6 +17,7 @@ die('Due to a security issue, this demo has been disabled. It can be enabled by
require_once('../getid3/getid3.php'); require_once('../getid3/getid3.php');
require_once('../getid3/getid3.lib.php');
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'extension.cache.mysql.php', __FILE__, true); getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'extension.cache.mysql.php', __FILE__, true);
$getID3 = new getID3_cached_mysql('localhost', 'database', 'username', 'password'); $getID3 = new getID3_cached_mysql('localhost', 'database', 'username', 'password');

62
app/Library/getid3/demos/demo.joinmp3.php Executable file → Normal file
View file

@ -9,6 +9,7 @@
// /demo/demo.joinmp3.php - part of getID3() // // /demo/demo.joinmp3.php - part of getID3() //
// Sample script for splicing two or more MP3s together into // // Sample script for splicing two or more MP3s together into //
// one file. Does not attempt to fix VBR header frames. // // one file. Does not attempt to fix VBR header frames. //
// Can also be used to extract portion from single file. //
// See readme.txt for more details // // See readme.txt for more details //
// /// // ///
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
@ -16,30 +17,39 @@
// sample usage: // sample usage:
// $FilenameOut = 'combined.mp3'; // $FilenameOut = 'combined.mp3';
// $FilenamesIn[] = 'file1.mp3'; // $FilenamesIn[] = 'first.mp3'; // filename with no start/length parameters
// $FilenamesIn[] = 'file2.mp3'; // $FilenamesIn[] = array('second.mp3', 0, 0); // filename with zero for start/length is the same as not specified (start = beginning, length = full duration)
// $FilenamesIn[] = 'file3.mp3'; // $FilenamesIn[] = array('third.mp3', 0, 10); // extract first 10 seconds of audio
// // $FilenamesIn[] = array('fourth.mp3', -10, 0); // extract last 10 seconds of audio
// $FilenamesIn[] = array('fifth.mp3', 10, 0); // extract everything except first 10 seconds of audio
// $FilenamesIn[] = array('sixth.mp3', 0, -10); // extract everything except last 10 seconds of audio
// if (CombineMultipleMP3sTo($FilenameOut, $FilenamesIn)) { // if (CombineMultipleMP3sTo($FilenameOut, $FilenamesIn)) {
// echo 'Successfully copied '.implode(' + ', $FilenamesIn).' to '.$FilenameOut; // echo 'Successfully copied '.implode(' + ', $FilenamesIn).' to '.$FilenameOut;
// } else { // } else {
// echo 'Failed to copy '.implode(' + ', $FilenamesIn).' to '.$FilenameOut; // echo 'Failed to copy '.implode(' + ', $FilenamesIn).' to '.$FilenameOut;
// } // }
//
// Could also be called like this to extract portion from single file:
// CombineMultipleMP3sTo('sample.mp3', array(array('input.mp3', 0, 30))); // extract first 30 seconds of audio
function CombineMultipleMP3sTo($FilenameOut, $FilenamesIn) { function CombineMultipleMP3sTo($FilenameOut, $FilenamesIn) {
foreach ($FilenamesIn as $nextinputfilename) { foreach ($FilenamesIn as $nextinputfilename) {
if (is_array($nextinputfilename)) {
$nextinputfilename = $nextinputfilename[0];
}
if (!is_readable($nextinputfilename)) { if (!is_readable($nextinputfilename)) {
echo 'Cannot read "'.$nextinputfilename.'"<BR>'; echo 'Cannot read "'.$nextinputfilename.'"<BR>';
return false; return false;
} }
} }
if (!is_writeable($FilenameOut)) { if ((file_exists($FilenameOut) && !is_writeable($FilenameOut)) || (!file_exists($FilenameOut) && !is_writeable(dirname($FilenameOut)))) {
echo 'Cannot write "'.$FilenameOut.'"<BR>'; echo 'Cannot write "'.$FilenameOut.'"<BR>';
return false; return false;
} }
require_once('../getid3/getid3.php'); require_once(dirname(__FILE__).'/../getid3/getid3.php');
ob_start(); ob_start();
if ($fp_output = fopen($FilenameOut, 'wb')) { if ($fp_output = fopen($FilenameOut, 'wb')) {
@ -47,7 +57,11 @@ function CombineMultipleMP3sTo($FilenameOut, $FilenamesIn) {
// Initialize getID3 engine // Initialize getID3 engine
$getID3 = new getID3; $getID3 = new getID3;
foreach ($FilenamesIn as $nextinputfilename) { foreach ($FilenamesIn as $nextinputfilename) {
$startoffset = 0;
$length_seconds = 0;
if (is_array($nextinputfilename)) {
@list($nextinputfilename, $startoffset, $length_seconds) = $nextinputfilename;
}
$CurrentFileInfo = $getID3->analyze($nextinputfilename); $CurrentFileInfo = $getID3->analyze($nextinputfilename);
if ($CurrentFileInfo['fileformat'] == 'mp3') { if ($CurrentFileInfo['fileformat'] == 'mp3') {
@ -58,17 +72,35 @@ function CombineMultipleMP3sTo($FilenameOut, $FilenamesIn) {
$CurrentOutputPosition = ftell($fp_output); $CurrentOutputPosition = ftell($fp_output);
// copy audio data from first file // copy audio data from first file
fseek($fp_source, $CurrentFileInfo['avdataoffset'], SEEK_SET); $start_offset_bytes = $CurrentFileInfo['avdataoffset'];
while (!feof($fp_source) && (ftell($fp_source) < $CurrentFileInfo['avdataend'])) { if ($startoffset > 0) { // start X seconds from start of audio
fwrite($fp_output, fread($fp_source, 32768)); $start_offset_bytes = $CurrentFileInfo['avdataoffset'] + round($CurrentFileInfo['bitrate'] / 8 * $startoffset);
} elseif ($startoffset < 0) { // start X seconds from end of audio
$start_offset_bytes = $CurrentFileInfo['avdataend'] + round($CurrentFileInfo['bitrate'] / 8 * $startoffset);
}
$start_offset_bytes = max($CurrentFileInfo['avdataoffset'], min($CurrentFileInfo['avdataend'], $start_offset_bytes));
$end_offset_bytes = $CurrentFileInfo['avdataend'];
if ($length_seconds > 0) { // seconds from start of audio
$end_offset_bytes = $start_offset_bytes + round($CurrentFileInfo['bitrate'] / 8 * $length_seconds);
} elseif ($length_seconds < 0) { // seconds from start of audio
$end_offset_bytes = $CurrentFileInfo['avdataend'] + round($CurrentFileInfo['bitrate'] / 8 * $startoffset);
}
$end_offset_bytes = max($CurrentFileInfo['avdataoffset'], min($CurrentFileInfo['avdataend'], $end_offset_bytes));
if ($end_offset_bytes <= $start_offset_bytes) {
echo 'failed to copy '.$nextinputfilename.' from '.$startoffset.'-seconds start for '.$length_seconds.'-seconds length (not enough data)';
fclose($fp_source);
fclose($fp_output);
return false;
}
fseek($fp_source, $start_offset_bytes, SEEK_SET);
while (!feof($fp_source) && (ftell($fp_source) < $end_offset_bytes)) {
fwrite($fp_output, fread($fp_source, min(32768, $end_offset_bytes - ftell($fp_source))));
} }
fclose($fp_source); fclose($fp_source);
// trim post-audio data (if any) copied from first file that we don't need or want
$EndOfFileOffset = $CurrentOutputPosition + ($CurrentFileInfo['avdataend'] - $CurrentFileInfo['avdataoffset']);
fseek($fp_output, $EndOfFileOffset, SEEK_SET);
ftruncate($fp_output, $EndOfFileOffset);
} else { } else {
$errormessage = ob_get_contents(); $errormessage = ob_get_contents();

0
app/Library/getid3/demos/demo.mimeonly.php Executable file → Normal file
View file

21
app/Library/getid3/demos/demo.mp3header.php Executable file → Normal file
View file

@ -29,10 +29,10 @@ if (!function_exists('table_var_dump')) {
$returnstring = ''; $returnstring = '';
switch (gettype($variable)) { switch (gettype($variable)) {
case 'array': case 'array':
$returnstring .= '<TABLE BORDER="1" CELLSPACING="0" CELLPADDING="2">'; $returnstring .= '<table border="1" cellspacing="0" cellpadding="2">';
foreach ($variable as $key => $value) { foreach ($variable as $key => $value) {
$returnstring .= '<TR><TD VALIGN="TOP"><B>'.str_replace(chr(0), ' ', $key).'</B></TD>'; $returnstring .= '<tr><td valign="top"><b>'.str_replace(chr(0), ' ', $key).'</b></td>';
$returnstring .= '<TD VALIGN="TOP">'.gettype($value); $returnstring .= '<td valign="top">'.gettype($value);
if (is_array($value)) { if (is_array($value)) {
$returnstring .= '&nbsp;('.count($value).')'; $returnstring .= '&nbsp;('.count($value).')';
} elseif (is_string($value)) { } elseif (is_string($value)) {
@ -41,18 +41,21 @@ if (!function_exists('table_var_dump')) {
if (($key == 'data') && isset($variable['image_mime']) && isset($variable['dataoffset'])) { if (($key == 'data') && isset($variable['image_mime']) && isset($variable['dataoffset'])) {
require_once(GETID3_INCLUDEPATH.'getid3.getimagesize.php'); require_once(GETID3_INCLUDEPATH.'getid3.getimagesize.php');
$imageinfo = array(); $imageinfo = array();
$imagechunkcheck = GetDataImageSize($value, $imageinfo); if ($imagechunkcheck = GetDataImageSize($value, $imageinfo)) {
$DumpedImageSRC = (!empty($_REQUEST['filename']) ? $_REQUEST['filename'] : '.getid3').'.'.$variable['dataoffset'].'.'.ImageTypesLookup($imagechunkcheck[2]); $DumpedImageSRC = (!empty($_REQUEST['filename']) ? $_REQUEST['filename'] : '.getid3').'.'.$variable['dataoffset'].'.'.ImageTypesLookup($imagechunkcheck[2]);
if ($tempimagefile = fopen($DumpedImageSRC, 'wb')) { if ($tempimagefile = fopen($DumpedImageSRC, 'wb')) {
fwrite($tempimagefile, $value); fwrite($tempimagefile, $value);
fclose($tempimagefile); fclose($tempimagefile);
} }
$returnstring .= '</TD><TD><IMG SRC="'.$DumpedImageSRC.'" WIDTH="'.$imagechunkcheck[0].'" HEIGHT="'.$imagechunkcheck[1].'"></TD></TR>'; $returnstring .= '</td><td><img src="'.$DumpedImageSRC.'" width="'.$imagechunkcheck[0].'" height="'.$imagechunkcheck[1].'"></td></tr>';
} else { } else {
$returnstring .= '</TD><TD>'.table_var_dump($value).'</TD></TR>'; $returnstring .= '</td><td><i>invalid image data</i></td></tr>';
}
} else {
$returnstring .= '</td><td>'.table_var_dump($value).'</td></tr>';
} }
} }
$returnstring .= '</TABLE>'; $returnstring .= '</table>';
break; break;
case 'boolean': case 'boolean':
@ -86,9 +89,7 @@ if (!function_exists('table_var_dump')) {
default: default:
require_once(GETID3_INCLUDEPATH.'getid3.getimagesize.php'); require_once(GETID3_INCLUDEPATH.'getid3.getimagesize.php');
$imageinfo = array(); $imageinfo = array();
$imagechunkcheck = GetDataImageSize(substr($variable, 0, 32768), $imageinfo); if (($imagechunkcheck = GetDataImageSize(substr($variable, 0, 32768), $imageinfo)) && ($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3)) {
if (($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3)) {
$returnstring .= '<table border="1" cellspacing="0" cellpadding="2">'; $returnstring .= '<table border="1" cellspacing="0" cellpadding="2">';
$returnstring .= '<tr><td><b>type</b></td><td>'.ImageTypesLookup($imagechunkcheck[2]).'</td></tr>'; $returnstring .= '<tr><td><b>type</b></td><td>'.ImageTypesLookup($imagechunkcheck[2]).'</td></tr>';
$returnstring .= '<tr><td><b>width</b></td><td>'.number_format($imagechunkcheck[0]).' px</td></tr>'; $returnstring .= '<tr><td><b>width</b></td><td>'.number_format($imagechunkcheck[0]).' px</td></tr>';

0
app/Library/getid3/demos/demo.mysql.php Executable file → Normal file
View file

0
app/Library/getid3/demos/demo.simple.php Executable file → Normal file
View file

0
app/Library/getid3/demos/demo.simple.write.php Executable file → Normal file
View file

0
app/Library/getid3/demos/demo.write.php Executable file → Normal file
View file

0
app/Library/getid3/demos/demo.zip.php Executable file → Normal file
View file

0
app/Library/getid3/demos/getid3.css vendored Executable file → Normal file
View file

0
app/Library/getid3/demos/getid3.demo.dirscan.php Executable file → Normal file
View file

0
app/Library/getid3/demos/index.php Executable file → Normal file
View file

0
app/Library/getid3/dependencies.txt Executable file → Normal file
View file

0
app/Library/getid3/getid3/extension.cache.dbm.php Executable file → Normal file
View file

8
app/Library/getid3/getid3/extension.cache.mysql.php Executable file → Normal file
View file

@ -134,7 +134,7 @@ class getID3_cached_mysql extends getID3
// public: analyze file // public: analyze file
public function analyze($filename) { public function analyze($filename, $filesize=null, $original_filename='') {
if (file_exists($filename)) { if (file_exists($filename)) {
@ -157,7 +157,7 @@ class getID3_cached_mysql extends getID3
} }
// Miss // Miss
$analysis = parent::analyze($filename); $analysis = parent::analyze($filename, $filesize, $original_filename);
// Save result // Save result
if (file_exists($filename)) { if (file_exists($filename)) {
@ -178,11 +178,11 @@ class getID3_cached_mysql extends getID3
private function create_table($drop=false) { private function create_table($drop=false) {
$SQLquery = 'CREATE TABLE IF NOT EXISTS `'.mysql_real_escape_string($this->table).'` ('; $SQLquery = 'CREATE TABLE IF NOT EXISTS `'.mysql_real_escape_string($this->table).'` (';
$SQLquery .= '`filename` VARCHAR(255) NOT NULL DEFAULT \'\''; $SQLquery .= '`filename` VARCHAR(500) NOT NULL DEFAULT \'\'';
$SQLquery .= ', `filesize` INT(11) NOT NULL DEFAULT \'0\''; $SQLquery .= ', `filesize` INT(11) NOT NULL DEFAULT \'0\'';
$SQLquery .= ', `filetime` INT(11) NOT NULL DEFAULT \'0\''; $SQLquery .= ', `filetime` INT(11) NOT NULL DEFAULT \'0\'';
$SQLquery .= ', `analyzetime` INT(11) NOT NULL DEFAULT \'0\''; $SQLquery .= ', `analyzetime` INT(11) NOT NULL DEFAULT \'0\'';
$SQLquery .= ', `value` TEXT NOT NULL'; $SQLquery .= ', `value` LONGTEXT NOT NULL';
$SQLquery .= ', PRIMARY KEY (`filename`, `filesize`, `filetime`)) ENGINE=MyISAM'; $SQLquery .= ', PRIMARY KEY (`filename`, `filesize`, `filetime`)) ENGINE=MyISAM';
$this->cursor = mysql_query($SQLquery, $this->connection); $this->cursor = mysql_query($SQLquery, $this->connection);
echo mysql_error($this->connection); echo mysql_error($this->connection);

41
app/Library/getid3/getid3/extension.cache.sqlite3.php Executable file → Normal file
View file

@ -49,20 +49,20 @@
* *
* sqlite3 table='getid3_cache', hide=false (PHP5) * sqlite3 table='getid3_cache', hide=false (PHP5)
* *
*
*** database file will be stored in the same directory as this script, * *** database file will be stored in the same directory as this script,
*** webserver must have write access to that directory! * *** webserver must have write access to that directory!
*** set $hide to TRUE to prefix db file with .ht to pervent access from web client * *** set $hide to TRUE to prefix db file with .ht to pervent access from web client
*** this is a default setting in the Apache configuration: * *** this is a default setting in the Apache configuration:
*
# The following lines prevent .htaccess and .htpasswd files from being viewed by Web clients. * The following lines prevent .htaccess and .htpasswd files from being viewed by Web clients.
*
<Files ~ "^\.ht"> * <Files ~ "^\.ht">
Order allow,deny * Order allow,deny
Deny from all * Deny from all
Satisfy all * Satisfy all
</Files> * </Files>
*
******************************************************************************** ********************************************************************************
* *
* ------------------------------------------------------------------- * -------------------------------------------------------------------
@ -159,13 +159,13 @@ class getID3_cached_sqlite3 extends getID3 {
* @param type $filename * @param type $filename
* @return boolean * @return boolean
*/ */
public function analyze($filename) { public function analyze($filename, $filesize=null, $original_filename='') {
if (!file_exists($filename)) { if (!file_exists($filename)) {
return false; return false;
} }
// items to track for caching // items to track for caching
$filetime = filemtime($filename); $filetime = filemtime($filename);
$filesize = filesize($filename); $filesize_real = filesize($filename);
// this will be saved for a quick directory lookup of analized files // this will be saved for a quick directory lookup of analized files
// ... why do 50 seperate sql quries when you can do 1 for the same result // ... why do 50 seperate sql quries when you can do 1 for the same result
$dirname = dirname($filename); $dirname = dirname($filename);
@ -174,7 +174,7 @@ class getID3_cached_sqlite3 extends getID3 {
$sql = $this->get_id3_data; $sql = $this->get_id3_data;
$stmt = $db->prepare($sql); $stmt = $db->prepare($sql);
$stmt->bindValue(':filename', $filename, SQLITE3_TEXT); $stmt->bindValue(':filename', $filename, SQLITE3_TEXT);
$stmt->bindValue(':filesize', $filesize, SQLITE3_INTEGER); $stmt->bindValue(':filesize', $filesize_real, SQLITE3_INTEGER);
$stmt->bindValue(':filetime', $filetime, SQLITE3_INTEGER); $stmt->bindValue(':filetime', $filetime, SQLITE3_INTEGER);
$res = $stmt->execute(); $res = $stmt->execute();
list($result) = $res->fetchArray(); list($result) = $res->fetchArray();
@ -182,13 +182,13 @@ class getID3_cached_sqlite3 extends getID3 {
return unserialize(base64_decode($result)); return unserialize(base64_decode($result));
} }
// if it hasn't been analyzed before, then do it now // if it hasn't been analyzed before, then do it now
$analysis = parent::analyze($filename); $analysis = parent::analyze($filename, $filesize, $original_filename);
// Save result // Save result
$sql = $this->cache_file; $sql = $this->cache_file;
$stmt = $db->prepare($sql); $stmt = $db->prepare($sql);
$stmt->bindValue(':filename', $filename, SQLITE3_TEXT); $stmt->bindValue(':filename', $filename, SQLITE3_TEXT);
$stmt->bindValue(':dirname', $dirname, SQLITE3_TEXT); $stmt->bindValue(':dirname', $dirname, SQLITE3_TEXT);
$stmt->bindValue(':filesize', $filesize, SQLITE3_INTEGER); $stmt->bindValue(':filesize', $filesize_real, SQLITE3_INTEGER);
$stmt->bindValue(':filetime', $filetime, SQLITE3_INTEGER); $stmt->bindValue(':filetime', $filetime, SQLITE3_INTEGER);
$stmt->bindValue(':atime', time(), SQLITE3_INTEGER); $stmt->bindValue(':atime', time(), SQLITE3_INTEGER);
$stmt->bindValue(':val', base64_encode(serialize($analysis)), SQLITE3_TEXT); $stmt->bindValue(':val', base64_encode(serialize($analysis)), SQLITE3_TEXT);
@ -253,7 +253,8 @@ class getID3_cached_sqlite3 extends getID3 {
return "INSERT INTO $this->table (filename, dirname, filesize, filetime, analyzetime, val) VALUES (:filename, :dirname, :filesize, :filetime, :atime, :val)"; return "INSERT INTO $this->table (filename, dirname, filesize, filetime, analyzetime, val) VALUES (:filename, :dirname, :filesize, :filetime, :atime, :val)";
break; break;
case 'make_table': case 'make_table':
return "CREATE TABLE IF NOT EXISTS $this->table (filename VARCHAR(255) NOT NULL DEFAULT '', dirname 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', val text not null, PRIMARY KEY (filename, filesize, filetime))"; //return "CREATE TABLE IF NOT EXISTS $this->table (filename VARCHAR(255) NOT NULL DEFAULT '', dirname 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', val text not null, PRIMARY KEY (filename, filesize, filetime))";
return "CREATE TABLE IF NOT EXISTS $this->table (filename VARCHAR(255) DEFAULT '', dirname VARCHAR(255) DEFAULT '', filesize INT(11) DEFAULT '0', filetime INT(11) DEFAULT '0', analyzetime INT(11) DEFAULT '0', val text, PRIMARY KEY (filename, filesize, filetime))";
break; break;
case 'get_cached_dir': case 'get_cached_dir':
return "SELECT val FROM $this->table WHERE dirname = :dirname"; return "SELECT val FROM $this->table WHERE dirname = :dirname";

33
app/Library/getid3/getid3/getid3.lib.php Executable file → Normal file
View file

@ -414,6 +414,20 @@ class getid3_lib
return $newarray; return $newarray;
} }
public static function flipped_array_merge_noclobber($array1, $array2) {
if (!is_array($array1) || !is_array($array2)) {
return false;
}
# naturally, this only works non-recursively
$newarray = array_flip($array1);
foreach (array_flip($array2) as $key => $val) {
if (!isset($newarray[$key])) {
$newarray[$key] = count($newarray);
}
}
return array_flip($newarray);
}
public static function ksort_recursive(&$theArray) { public static function ksort_recursive(&$theArray) {
ksort($theArray); ksort($theArray);
@ -1153,11 +1167,19 @@ class getid3_lib
public static function GetDataImageSize($imgData, &$imageinfo=array()) { public static function GetDataImageSize($imgData, &$imageinfo=array()) {
static $tempdir = ''; static $tempdir = '';
if (empty($tempdir)) { if (empty($tempdir)) {
if (function_exists('sys_get_temp_dir')) {
$tempdir = sys_get_temp_dir(); // https://github.com/JamesHeinrich/getID3/issues/52
}
// yes this is ugly, feel free to suggest a better way // yes this is ugly, feel free to suggest a better way
require_once(dirname(__FILE__) . '/getid3.php'); if (include_once(dirname(__FILE__).'/getid3.php')) {
$getid3_temp = new getID3(); if ($getid3_temp = new getID3()) {
$tempdir = $getid3_temp->tempdir; if ($getid3_temp_tempdir = $getid3_temp->tempdir) {
unset($getid3_temp); $tempdir = $getid3_temp_tempdir;
}
unset($getid3_temp, $getid3_temp_tempdir);
}
}
} }
$GetDataImageSize = false; $GetDataImageSize = false;
if ($tempfilename = tempnam($tempdir, 'gI3')) { if ($tempfilename = tempnam($tempdir, 'gI3')) {
@ -1165,6 +1187,9 @@ class getid3_lib
fwrite($tmp, $imgData); fwrite($tmp, $imgData);
fclose($tmp); fclose($tmp);
$GetDataImageSize = @getimagesize($tempfilename, $imageinfo); $GetDataImageSize = @getimagesize($tempfilename, $imageinfo);
if (($GetDataImageSize === false) || !isset($GetDataImageSize[0]) || !isset($GetDataImageSize[1])) {
return false;
}
$GetDataImageSize['height'] = $GetDataImageSize[0]; $GetDataImageSize['height'] = $GetDataImageSize[0];
$GetDataImageSize['width'] = $GetDataImageSize[1]; $GetDataImageSize['width'] = $GetDataImageSize[1];
} }

37
app/Library/getid3/getid3/getid3.php Executable file → Normal file
View file

@ -109,7 +109,7 @@ class getID3
protected $startup_error = ''; protected $startup_error = '';
protected $startup_warning = ''; protected $startup_warning = '';
const VERSION = '1.9.9-20141121'; const VERSION = '1.9.10-201511241457';
const FREAD_BUFFER_SIZE = 32768; const FREAD_BUFFER_SIZE = 32768;
const ATTACHMENTS_NONE = false; const ATTACHMENTS_NONE = false;
@ -243,7 +243,7 @@ class getID3
} }
public function openfile($filename) { public function openfile($filename, $filesize=null) {
try { try {
if (!empty($this->startup_error)) { if (!empty($this->startup_error)) {
throw new getid3_exception($this->startup_error); throw new getid3_exception($this->startup_error);
@ -287,7 +287,7 @@ class getID3
throw new getid3_exception('Could not open "'.$filename.'" ('.implode('; ', $errormessagelist).')'); throw new getid3_exception('Could not open "'.$filename.'" ('.implode('; ', $errormessagelist).')');
} }
$this->info['filesize'] = filesize($filename); $this->info['filesize'] = (!is_null($filesize) ? $filesize : filesize($filename));
// set redundant parameters - might be needed in some include file // set redundant parameters - might be needed in some include file
// filenames / filepaths in getID3 are always expressed with forward slashes (unix-style) for both Windows and other to try and minimize confusion // filenames / filepaths in getID3 are always expressed with forward slashes (unix-style) for both Windows and other to try and minimize confusion
$filename = str_replace('\\', '/', $filename); $filename = str_replace('\\', '/', $filename);
@ -342,9 +342,9 @@ class getID3
} }
// public: analyze file // public: analyze file
public function analyze($filename) { public function analyze($filename, $filesize=null, $original_filename='') {
try { try {
if (!$this->openfile($filename)) { if (!$this->openfile($filename, $filesize)) {
return $this->info; return $this->info;
} }
@ -389,7 +389,7 @@ class getID3
$formattest = fread($this->fp, 32774); $formattest = fread($this->fp, 32774);
// determine format // determine format
$determined_format = $this->GetFileFormat($formattest, $filename); $determined_format = $this->GetFileFormat($formattest, ($original_filename ? $original_filename : $filename));
// unable to determine file format // unable to determine file format
if (!$determined_format) { if (!$determined_format) {
@ -876,7 +876,7 @@ class getID3
'pattern' => '^(RIFF|SDSS|FORM)', 'pattern' => '^(RIFF|SDSS|FORM)',
'group' => 'audio-video', 'group' => 'audio-video',
'module' => 'riff', 'module' => 'riff',
'mime_type' => 'audio/x-wave', 'mime_type' => 'audio/x-wav',
'fail_ape' => 'WARNING', 'fail_ape' => 'WARNING',
), ),
@ -1235,6 +1235,29 @@ class getID3
} }
} }
// ID3v1 encoding detection hack start
// ID3v1 is defined as always using ISO-8859-1 encoding, but it is not uncommon to find files tagged with ID3v1 using Windows-1251 or other character sets
// Since ID3v1 has no concept of character sets there is no certain way to know we have the correct non-ISO-8859-1 character set, but we can guess
if ($comment_name == 'id3v1') {
if ($encoding == 'ISO-8859-1') {
if (function_exists('iconv')) {
foreach ($this->info['tags'][$tag_name] as $tag_key => $valuearray) {
foreach ($valuearray as $key => $value) {
if (preg_match('#^[\\x80-\\xFF]+$#', $value)) {
foreach (array('windows-1251', 'KOI8-R') as $id3v1_bad_encoding) {
if (@iconv($id3v1_bad_encoding, $id3v1_bad_encoding, $value) === $value) {
$encoding = $id3v1_bad_encoding;
break 3;
}
}
}
}
}
}
}
}
// ID3v1 encoding detection hack end
$this->CharConvert($this->info['tags'][$tag_name], $encoding); // only copy gets converted! $this->CharConvert($this->info['tags'][$tag_name], $encoding); // only copy gets converted!
} }

0
app/Library/getid3/getid3/module.archive.gzip.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.archive.rar.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.archive.szip.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.archive.tar.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.archive.zip.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.audio-video.asf.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.audio-video.bink.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.audio-video.flv.php Executable file → Normal file
View file

View file

@ -457,6 +457,7 @@ class getid3_matroska extends getid3_handler
default: default:
$this->warning('Unhandled audio type "'.(isset($trackarray['CodecID']) ? $trackarray['CodecID'] : '').'"'); $this->warning('Unhandled audio type "'.(isset($trackarray['CodecID']) ? $trackarray['CodecID'] : '').'"');
break;
} }
$info['audio']['streams'][] = $track_info; $info['audio']['streams'][] = $track_info;
@ -524,6 +525,7 @@ class getid3_matroska extends getid3_handler
default: default:
$this->unhandledElement('header', __LINE__, $element_data); $this->unhandledElement('header', __LINE__, $element_data);
break;
} }
unset($element_data['offset'], $element_data['end']); unset($element_data['offset'], $element_data['end']);
@ -562,6 +564,7 @@ class getid3_matroska extends getid3_handler
default: default:
$this->unhandledElement('seekhead.seek', __LINE__, $sub_seek_entry); } $this->unhandledElement('seekhead.seek', __LINE__, $sub_seek_entry); }
break;
} }
if ($seek_entry['target_id'] != EBML_ID_CLUSTER || !self::$hide_clusters) { // collect clusters only if required if ($seek_entry['target_id'] != EBML_ID_CLUSTER || !self::$hide_clusters) { // collect clusters only if required
@ -571,6 +574,7 @@ class getid3_matroska extends getid3_handler
default: default:
$this->unhandledElement('seekhead', __LINE__, $seek_entry); $this->unhandledElement('seekhead', __LINE__, $seek_entry);
break;
} }
} }
break; break;
@ -653,6 +657,7 @@ class getid3_matroska extends getid3_handler
default: default:
$this->unhandledElement('track.video', __LINE__, $sub_subelement); $this->unhandledElement('track.video', __LINE__, $sub_subelement);
break;
} }
} }
break; break;
@ -678,6 +683,7 @@ class getid3_matroska extends getid3_handler
default: default:
$this->unhandledElement('track.audio', __LINE__, $sub_subelement); $this->unhandledElement('track.audio', __LINE__, $sub_subelement);
break;
} }
} }
break; break;
@ -713,6 +719,7 @@ class getid3_matroska extends getid3_handler
default: default:
$this->unhandledElement('track.contentencodings.contentencoding.contentcompression', __LINE__, $sub_sub_sub_subelement); $this->unhandledElement('track.contentencodings.contentencoding.contentcompression', __LINE__, $sub_sub_sub_subelement);
break;
} }
} }
break; break;
@ -736,24 +743,28 @@ class getid3_matroska extends getid3_handler
default: default:
$this->unhandledElement('track.contentencodings.contentencoding.contentcompression', __LINE__, $sub_sub_sub_subelement); $this->unhandledElement('track.contentencodings.contentencoding.contentcompression', __LINE__, $sub_sub_sub_subelement);
break;
} }
} }
break; break;
default: default:
$this->unhandledElement('track.contentencodings.contentencoding', __LINE__, $sub_sub_subelement); $this->unhandledElement('track.contentencodings.contentencoding', __LINE__, $sub_sub_subelement);
break;
} }
} }
break; break;
default: default:
$this->unhandledElement('track.contentencodings', __LINE__, $sub_subelement); $this->unhandledElement('track.contentencodings', __LINE__, $sub_subelement);
break;
} }
} }
break; break;
default: default:
$this->unhandledElement('track', __LINE__, $subelement); $this->unhandledElement('track', __LINE__, $subelement);
break;
} }
} }
@ -762,6 +773,7 @@ class getid3_matroska extends getid3_handler
default: default:
$this->unhandledElement('tracks', __LINE__, $track_entry); $this->unhandledElement('tracks', __LINE__, $track_entry);
break;
} }
} }
break; break;
@ -825,6 +837,7 @@ class getid3_matroska extends getid3_handler
default: default:
$this->unhandledElement('info.chaptertranslate', __LINE__, $sub_subelement); $this->unhandledElement('info.chaptertranslate', __LINE__, $sub_subelement);
break;
} }
} }
$info_entry[$subelement['id_name']] = $chaptertranslate_entry; $info_entry[$subelement['id_name']] = $chaptertranslate_entry;
@ -832,6 +845,7 @@ class getid3_matroska extends getid3_handler
default: default:
$this->unhandledElement('info', __LINE__, $subelement); $this->unhandledElement('info', __LINE__, $subelement);
break;
} }
} }
$info['matroska']['info'][] = $info_entry; $info['matroska']['info'][] = $info_entry;
@ -868,6 +882,7 @@ class getid3_matroska extends getid3_handler
default: default:
$this->unhandledElement('cues.cuepoint.cuetrackpositions', __LINE__, $sub_sub_subelement); $this->unhandledElement('cues.cuepoint.cuetrackpositions', __LINE__, $sub_sub_subelement);
break;
} }
} }
$cuepoint_entry[$sub_subelement['id_name']][] = $cuetrackpositions_entry; $cuepoint_entry[$sub_subelement['id_name']][] = $cuetrackpositions_entry;
@ -879,6 +894,7 @@ class getid3_matroska extends getid3_handler
default: default:
$this->unhandledElement('cues.cuepoint', __LINE__, $sub_subelement); $this->unhandledElement('cues.cuepoint', __LINE__, $sub_subelement);
break;
} }
} }
$cues_entry[] = $cuepoint_entry; $cues_entry[] = $cuepoint_entry;
@ -886,6 +902,7 @@ class getid3_matroska extends getid3_handler
default: default:
$this->unhandledElement('cues', __LINE__, $subelement); $this->unhandledElement('cues', __LINE__, $subelement);
break;
} }
} }
$info['matroska']['cues'] = $cues_entry; $info['matroska']['cues'] = $cues_entry;
@ -927,6 +944,7 @@ class getid3_matroska extends getid3_handler
default: default:
$this->unhandledElement('tags.tag.targets', __LINE__, $sub_sub_subelement); $this->unhandledElement('tags.tag.targets', __LINE__, $sub_sub_subelement);
break;
} }
} }
$tag_entry[$sub_subelement['id_name']] = $targets_entry; $tag_entry[$sub_subelement['id_name']] = $targets_entry;
@ -938,6 +956,7 @@ class getid3_matroska extends getid3_handler
default: default:
$this->unhandledElement('tags.tag', __LINE__, $sub_subelement); $this->unhandledElement('tags.tag', __LINE__, $sub_subelement);
break;
} }
} }
$tags_entry[] = $tag_entry; $tags_entry[] = $tag_entry;
@ -945,6 +964,7 @@ class getid3_matroska extends getid3_handler
default: default:
$this->unhandledElement('tags', __LINE__, $subelement); $this->unhandledElement('tags', __LINE__, $subelement);
break;
} }
} }
$info['matroska']['tags'] = $tags_entry; $info['matroska']['tags'] = $tags_entry;
@ -985,6 +1005,7 @@ class getid3_matroska extends getid3_handler
default: default:
$this->unhandledElement('attachments.attachedfile', __LINE__, $sub_subelement); $this->unhandledElement('attachments.attachedfile', __LINE__, $sub_subelement);
break;
} }
} }
$info['matroska']['attachments'][] = $attachedfile_entry; $info['matroska']['attachments'][] = $attachedfile_entry;
@ -992,6 +1013,7 @@ class getid3_matroska extends getid3_handler
default: default:
$this->unhandledElement('attachments', __LINE__, $subelement); $this->unhandledElement('attachments', __LINE__, $subelement);
break;
} }
} }
break; break;
@ -1051,6 +1073,7 @@ class getid3_matroska extends getid3_handler
default: default:
$this->unhandledElement('chapters.editionentry.chapteratom.chaptertrack', __LINE__, $sub_sub_sub_subelement); $this->unhandledElement('chapters.editionentry.chapteratom.chaptertrack', __LINE__, $sub_sub_sub_subelement);
break;
} }
} }
$chapteratom_entry[$sub_sub_subelement['id_name']][] = $chaptertrack_entry; $chapteratom_entry[$sub_sub_subelement['id_name']][] = $chaptertrack_entry;
@ -1070,6 +1093,7 @@ class getid3_matroska extends getid3_handler
default: default:
$this->unhandledElement('chapters.editionentry.chapteratom.chapterdisplay', __LINE__, $sub_sub_sub_subelement); $this->unhandledElement('chapters.editionentry.chapteratom.chapterdisplay', __LINE__, $sub_sub_sub_subelement);
break;
} }
} }
$chapteratom_entry[$sub_sub_subelement['id_name']][] = $chapterdisplay_entry; $chapteratom_entry[$sub_sub_subelement['id_name']][] = $chapterdisplay_entry;
@ -1077,6 +1101,7 @@ class getid3_matroska extends getid3_handler
default: default:
$this->unhandledElement('chapters.editionentry.chapteratom', __LINE__, $sub_sub_subelement); $this->unhandledElement('chapters.editionentry.chapteratom', __LINE__, $sub_sub_subelement);
break;
} }
} }
$editionentry_entry[$sub_subelement['id_name']][] = $chapteratom_entry; $editionentry_entry[$sub_subelement['id_name']][] = $chapteratom_entry;
@ -1084,6 +1109,7 @@ class getid3_matroska extends getid3_handler
default: default:
$this->unhandledElement('chapters.editionentry', __LINE__, $sub_subelement); $this->unhandledElement('chapters.editionentry', __LINE__, $sub_subelement);
break;
} }
} }
$info['matroska']['chapters'][] = $editionentry_entry; $info['matroska']['chapters'][] = $editionentry_entry;
@ -1091,6 +1117,7 @@ class getid3_matroska extends getid3_handler
default: default:
$this->unhandledElement('chapters', __LINE__, $subelement); $this->unhandledElement('chapters', __LINE__, $subelement);
break;
} }
} }
break; break;
@ -1119,6 +1146,7 @@ class getid3_matroska extends getid3_handler
default: default:
$this->unhandledElement('cluster.silenttracks', __LINE__, $sub_subelement); $this->unhandledElement('cluster.silenttracks', __LINE__, $sub_subelement);
break;
} }
} }
$cluster_entry[$subelement['id_name']][] = $cluster_silent_tracks; $cluster_entry[$subelement['id_name']][] = $cluster_silent_tracks;
@ -1149,6 +1177,7 @@ class getid3_matroska extends getid3_handler
default: default:
$this->unhandledElement('clusters.blockgroup', __LINE__, $sub_subelement); $this->unhandledElement('clusters.blockgroup', __LINE__, $sub_subelement);
break;
} }
} }
$cluster_entry[$subelement['id_name']][] = $cluster_block_group; $cluster_entry[$subelement['id_name']][] = $cluster_block_group;
@ -1160,6 +1189,7 @@ class getid3_matroska extends getid3_handler
default: default:
$this->unhandledElement('cluster', __LINE__, $subelement); $this->unhandledElement('cluster', __LINE__, $subelement);
break;
} }
$this->current_offset = $subelement['end']; $this->current_offset = $subelement['end'];
} }
@ -1181,12 +1211,14 @@ class getid3_matroska extends getid3_handler
default: default:
$this->unhandledElement('segment', __LINE__, $element_data); $this->unhandledElement('segment', __LINE__, $element_data);
break;
} }
} }
break; break;
default: default:
$this->unhandledElement('root', __LINE__, $top_element); $this->unhandledElement('root', __LINE__, $top_element);
break;
} }
} }
} }
@ -1339,6 +1371,7 @@ class getid3_matroska extends getid3_handler
default: default:
$this->unhandledElement('tag.simpletag', __LINE__, $element); $this->unhandledElement('tag.simpletag', __LINE__, $element);
break;
} }
} }

0
app/Library/getid3/getid3/module.audio-video.mpeg.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.audio-video.nsv.php Executable file → Normal file
View file

View file

@ -81,6 +81,81 @@ class getid3_quicktime extends getid3_handler
unset($info['avdataend_tmp']); unset($info['avdataend_tmp']);
} }
if (!empty($info['quicktime']['comments']['chapters']) && is_array($info['quicktime']['comments']['chapters']) && (count($info['quicktime']['comments']['chapters']) > 0)) {
$durations = $this->quicktime_time_to_sample_table($info);
for ($i = 0; $i < count($info['quicktime']['comments']['chapters']); $i++) {
$bookmark = array();
$bookmark['title'] = $info['quicktime']['comments']['chapters'][$i];
if (isset($durations[$i])) {
$bookmark['duration_sample'] = $durations[$i]['sample_duration'];
if ($i > 0) {
$bookmark['start_sample'] = $info['quicktime']['bookmarks'][($i - 1)]['start_sample'] + $info['quicktime']['bookmarks'][($i - 1)]['duration_sample'];
} else {
$bookmark['start_sample'] = 0;
}
if ($time_scale = $this->quicktime_bookmark_time_scale($info)) {
$bookmark['duration_seconds'] = $bookmark['duration_sample'] / $time_scale;
$bookmark['start_seconds'] = $bookmark['start_sample'] / $time_scale;
}
}
$info['quicktime']['bookmarks'][] = $bookmark;
}
}
if (isset($info['quicktime']['temp_meta_key_names'])) {
unset($info['quicktime']['temp_meta_key_names']);
}
if (!empty($info['quicktime']['comments']['location.ISO6709'])) {
// https://en.wikipedia.org/wiki/ISO_6709
foreach ($info['quicktime']['comments']['location.ISO6709'] as $ISO6709string) {
$latitude = false;
$longitude = false;
$altitude = false;
if (preg_match('#^([\\+\\-])([0-9]{2}|[0-9]{4}|[0-9]{6})(\\.[0-9]+)?([\\+\\-])([0-9]{3}|[0-9]{5}|[0-9]{7})(\\.[0-9]+)?(([\\+\\-])([0-9]{3}|[0-9]{5}|[0-9]{7})(\\.[0-9]+)?)?/$#', $ISO6709string, $matches)) {
@list($dummy, $lat_sign, $lat_deg, $lat_deg_dec, $lon_sign, $lon_deg, $lon_deg_dec, $dummy, $alt_sign, $alt_deg, $alt_deg_dec) = $matches;
if (strlen($lat_deg) == 2) { // [+-]DD.D
$latitude = floatval(ltrim($lat_deg, '0').$lat_deg_dec);
} elseif (strlen($lat_deg) == 4) { // [+-]DDMM.M
$latitude = floatval(ltrim(substr($lat_deg, 0, 2), '0')) + floatval(ltrim(substr($lat_deg, 2, 2), '0').$lat_deg_dec / 60);
} elseif (strlen($lat_deg) == 6) { // [+-]DDMMSS.S
$latitude = floatval(ltrim(substr($lat_deg, 0, 2), '0')) + floatval(ltrim(substr($lat_deg, 2, 2), '0') / 60) + floatval(ltrim(substr($lat_deg, 4, 2), '0').$lat_deg_dec / 3600);
}
if (strlen($lon_deg) == 3) { // [+-]DDD.D
$longitude = floatval(ltrim($lon_deg, '0').$lon_deg_dec);
} elseif (strlen($lon_deg) == 5) { // [+-]DDDMM.M
$longitude = floatval(ltrim(substr($lon_deg, 0, 2), '0')) + floatval(ltrim(substr($lon_deg, 2, 2), '0').$lon_deg_dec / 60);
} elseif (strlen($lon_deg) == 7) { // [+-]DDDMMSS.S
$longitude = floatval(ltrim(substr($lon_deg, 0, 2), '0')) + floatval(ltrim(substr($lon_deg, 2, 2), '0') / 60) + floatval(ltrim(substr($lon_deg, 4, 2), '0').$lon_deg_dec / 3600);
}
if (strlen($alt_deg) == 3) { // [+-]DDD.D
$altitude = floatval(ltrim($alt_deg, '0').$alt_deg_dec);
} elseif (strlen($alt_deg) == 5) { // [+-]DDDMM.M
$altitude = floatval(ltrim(substr($alt_deg, 0, 2), '0')) + floatval(ltrim(substr($alt_deg, 2, 2), '0').$alt_deg_dec / 60);
} elseif (strlen($alt_deg) == 7) { // [+-]DDDMMSS.S
$altitude = floatval(ltrim(substr($alt_deg, 0, 2), '0')) + floatval(ltrim(substr($alt_deg, 2, 2), '0') / 60) + floatval(ltrim(substr($alt_deg, 4, 2), '0').$alt_deg_dec / 3600);
}
if ($latitude !== false) {
$info['quicktime']['comments']['gps_latitude'][] = (($lat_sign == '-') ? -1 : 1) * floatval($latitude);
}
if ($longitude !== false) {
$info['quicktime']['comments']['gps_longitude'][] = (($lon_sign == '-') ? -1 : 1) * floatval($longitude);
}
if ($altitude !== false) {
$info['quicktime']['comments']['gps_altitude'][] = (($alt_sign == '-') ? -1 : 1) * floatval($altitude);
}
}
if ($latitude === false) {
$info['warning'][] = 'location.ISO6709 string not parsed correctly: "'.$ISO6709string.'", please submit as a bug';
}
break;
}
}
if (!isset($info['bitrate']) && isset($info['playtime_seconds'])) { if (!isset($info['bitrate']) && isset($info['playtime_seconds'])) {
$info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
} }
@ -120,6 +195,7 @@ class getid3_quicktime extends getid3_handler
public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) { public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
// http://developer.apple.com/techpubs/quicktime/qtdevdocs/APIREF/INDEX/atomalphaindex.htm // http://developer.apple.com/techpubs/quicktime/qtdevdocs/APIREF/INDEX/atomalphaindex.htm
// https://code.google.com/p/mp4v2/wiki/iTunesMetadata
$info = &$this->getid3->info; $info = &$this->getid3->info;
@ -222,81 +298,88 @@ class getid3_quicktime extends getid3_handler
break; break;
case "\xA9".'alb': // ALBum
case "\xA9".'ART': //
case "\xA9".'art': // ARTist
case "\xA9".'aut': //
case "\xA9".'cmt': // CoMmenT
case "\xA9".'com': // COMposer
case "\xA9".'cpy': //
case "\xA9".'day': // content created year
case "\xA9".'dir': //
case "\xA9".'ed1': //
case "\xA9".'ed2': //
case "\xA9".'ed3': //
case "\xA9".'ed4': //
case "\xA9".'ed5': //
case "\xA9".'ed6': //
case "\xA9".'ed7': //
case "\xA9".'ed8': //
case "\xA9".'ed9': //
case "\xA9".'enc': //
case "\xA9".'fmt': //
case "\xA9".'gen': // GENre
case "\xA9".'grp': // GRouPing
case "\xA9".'hst': //
case "\xA9".'inf': //
case "\xA9".'lyr': // LYRics
case "\xA9".'mak': //
case "\xA9".'mod': //
case "\xA9".'nam': // full NAMe
case "\xA9".'ope': //
case "\xA9".'PRD': //
case "\xA9".'prf': //
case "\xA9".'req': //
case "\xA9".'src': //
case "\xA9".'swr': //
case "\xA9".'too': // encoder
case "\xA9".'trk': // TRacK
case "\xA9".'url': //
case "\xA9".'wrn': //
case "\xA9".'wrt': // WRiTer
case '----': // itunes specific
case 'aART': // Album ARTist case 'aART': // Album ARTist
case 'akID': // iTunes store account type
case 'apID': // Purchase Account
case 'atID': //
case 'catg': // CaTeGory case 'catg': // CaTeGory
case 'cmID': //
case 'cnID': //
case 'covr': // COVeR artwork case 'covr': // COVeR artwork
case 'cpil': // ComPILation case 'cpil': // ComPILation
case 'cprt': // CoPyRighT case 'cprt': // CoPyRighT
case 'desc': // DESCription case 'desc': // DESCription
case 'disk': // DISK number case 'disk': // DISK number
case 'egid': // Episode Global ID case 'egid': // Episode Global ID
case 'geID': //
case 'gnre': // GeNRE case 'gnre': // GeNRE
case 'hdvd': // HD ViDeo
case 'keyw': // KEYWord case 'keyw': // KEYWord
case 'ldes': case 'ldes': // Long DEScription
case 'pcst': // PodCaST case 'pcst': // PodCaST
case 'pgap': // GAPless Playback case 'pgap': // GAPless Playback
case 'plID': //
case 'purd': // PURchase Date case 'purd': // PURchase Date
case 'purl': // Podcast URL case 'purl': // Podcast URL
case 'rati': case 'rati': //
case 'rndu': case 'rndu': //
case 'rpdu': case 'rpdu': //
case 'rtng': // RaTiNG case 'rtng': // RaTiNG
case 'stik': case 'sfID': // iTunes store country
case 'soaa': // SOrt Album Artist
case 'soal': // SOrt ALbum
case 'soar': // SOrt ARtist
case 'soco': // SOrt COmposer
case 'sonm': // SOrt NaMe
case 'sosn': // SOrt Show Name
case 'stik': //
case 'tmpo': // TeMPO (BPM) case 'tmpo': // TeMPO (BPM)
case 'trkn': // TRacK Number case 'trkn': // TRacK Number
case 'tven': // tvEpisodeID
case 'tves': // TV EpiSode case 'tves': // TV EpiSode
case 'tvnn': // TV Network Name case 'tvnn': // TV Network Name
case 'tvsh': // TV SHow Name case 'tvsh': // TV SHow Name
case 'tvsn': // TV SeasoN case 'tvsn': // TV SeasoN
case 'akID': // iTunes store account type
case 'apID':
case 'atID':
case 'cmID':
case 'cnID':
case 'geID':
case 'plID':
case 'sfID': // iTunes store country
case "\xA9".'alb': // ALBum
case "\xA9".'art': // ARTist
case "\xA9".'ART':
case "\xA9".'aut':
case "\xA9".'cmt': // CoMmenT
case "\xA9".'com': // COMposer
case "\xA9".'cpy':
case "\xA9".'day': // content created year
case "\xA9".'dir':
case "\xA9".'ed1':
case "\xA9".'ed2':
case "\xA9".'ed3':
case "\xA9".'ed4':
case "\xA9".'ed5':
case "\xA9".'ed6':
case "\xA9".'ed7':
case "\xA9".'ed8':
case "\xA9".'ed9':
case "\xA9".'enc':
case "\xA9".'fmt':
case "\xA9".'gen': // GENre
case "\xA9".'grp': // GRouPing
case "\xA9".'hst':
case "\xA9".'inf':
case "\xA9".'lyr': // LYRics
case "\xA9".'mak':
case "\xA9".'mod':
case "\xA9".'nam': // full NAMe
case "\xA9".'ope':
case "\xA9".'PRD':
case "\xA9".'prd':
case "\xA9".'prf':
case "\xA9".'req':
case "\xA9".'src':
case "\xA9".'swr':
case "\xA9".'too': // encoder
case "\xA9".'trk': // TRacK
case "\xA9".'url':
case "\xA9".'wrn':
case "\xA9".'wrt': // WRiTer
case '----': // itunes specific
if ($atom_parent == 'udta') { if ($atom_parent == 'udta') {
// User data atom handler // User data atom handler
$atom_structure['data_length'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2)); $atom_structure['data_length'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2));
@ -361,17 +444,21 @@ class getid3_quicktime extends getid3_handler
case 21: // tmpo/cpil flag case 21: // tmpo/cpil flag
switch ($atomname) { switch ($atomname) {
case 'cpil': case 'cpil':
case 'hdvd':
case 'pcst': case 'pcst':
case 'pgap': case 'pgap':
// 8-bit integer (boolean)
$atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1)); $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));
break; break;
case 'tmpo': case 'tmpo':
// 16-bit integer
$atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 2)); $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 2));
break; break;
case 'disk': case 'disk':
case 'trkn': case 'trkn':
// binary
$num = getid3_lib::BigEndian2Int(substr($boxdata, 10, 2)); $num = getid3_lib::BigEndian2Int(substr($boxdata, 10, 2));
$num_total = getid3_lib::BigEndian2Int(substr($boxdata, 12, 2)); $num_total = getid3_lib::BigEndian2Int(substr($boxdata, 12, 2));
$atom_structure['data'] = empty($num) ? '' : $num; $atom_structure['data'] = empty($num) ? '' : $num;
@ -379,21 +466,25 @@ class getid3_quicktime extends getid3_handler
break; break;
case 'gnre': case 'gnre':
// enum
$GenreID = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4)); $GenreID = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));
$atom_structure['data'] = getid3_id3v1::LookupGenreName($GenreID - 1); $atom_structure['data'] = getid3_id3v1::LookupGenreName($GenreID - 1);
break; break;
case 'rtng': case 'rtng':
// 8-bit integer
$atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1)); $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));
$atom_structure['data'] = $this->QuicktimeContentRatingLookup($atom_structure[$atomname]); $atom_structure['data'] = $this->QuicktimeContentRatingLookup($atom_structure[$atomname]);
break; break;
case 'stik': case 'stik':
// 8-bit integer (enum)
$atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1)); $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));
$atom_structure['data'] = $this->QuicktimeSTIKLookup($atom_structure[$atomname]); $atom_structure['data'] = $this->QuicktimeSTIKLookup($atom_structure[$atomname]);
break; break;
case 'sfID': case 'sfID':
// 32-bit integer
$atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4)); $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));
$atom_structure['data'] = $this->QuicktimeStoreFrontCodeLookup($atom_structure[$atomname]); $atom_structure['data'] = $this->QuicktimeStoreFrontCodeLookup($atom_structure[$atomname]);
break; break;
@ -403,7 +494,18 @@ class getid3_quicktime extends getid3_handler
$atom_structure['data'] = substr($boxdata, 8); $atom_structure['data'] = substr($boxdata, 8);
break; break;
case 'plID':
// 64-bit integer
$atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 8));
break;
case 'atID':
case 'cnID':
case 'geID':
case 'tves':
case 'tvsn':
default: default:
// 32-bit integer
$atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4)); $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));
} }
break; break;
@ -1004,7 +1106,7 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
$info['error'][] = 'Corrupt Quicktime file: mdhd.time_scale == zero'; $info['error'][] = 'Corrupt Quicktime file: mdhd.time_scale == zero';
return false; return false;
} }
$info['quicktime']['time_scale'] = (isset($info['quicktime']['time_scale']) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']); $info['quicktime']['time_scale'] = ((isset($info['quicktime']['time_scale']) && ($info['quicktime']['time_scale'] < 1000)) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']);
$atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']); $atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']);
$atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']); $atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']);
@ -1120,7 +1222,7 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
} }
$atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']); $atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']);
$atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']); $atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']);
$info['quicktime']['time_scale'] = (isset($info['quicktime']['time_scale']) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']); $info['quicktime']['time_scale'] = ((isset($info['quicktime']['time_scale']) && ($info['quicktime']['time_scale'] < 1000)) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']);
$info['quicktime']['display_scale'] = $atom_structure['matrix_a']; $info['quicktime']['display_scale'] = $atom_structure['matrix_a'];
$info['playtime_seconds'] = $atom_structure['duration'] / $atom_structure['time_scale']; $info['playtime_seconds'] = $atom_structure['duration'] / $atom_structure['time_scale'];
break; break;
@ -1240,14 +1342,20 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
} }
// check to see if it looks like chapter titles, in the form of unterminated strings with a leading 16-bit size field // check to see if it looks like chapter titles, in the form of unterminated strings with a leading 16-bit size field
while (($chapter_string_length = getid3_lib::BigEndian2Int(substr($atom_data, $mdat_offset, 2))) while (($mdat_offset < (strlen($atom_data) - 8))
&& ($chapter_string_length = getid3_lib::BigEndian2Int(substr($atom_data, $mdat_offset, 2)))
&& ($chapter_string_length < 1000) && ($chapter_string_length < 1000)
&& ($chapter_string_length <= (strlen($atom_data) - $mdat_offset - 2)) && ($chapter_string_length <= (strlen($atom_data) - $mdat_offset - 2))
&& preg_match('#^[\x20-\xFF]+$#', substr($atom_data, $mdat_offset + 2, $chapter_string_length), $chapter_matches)) { && preg_match('#^([\x00-\xFF]{2})([\x20-\xFF]+)$#', substr($atom_data, $mdat_offset, $chapter_string_length + 2), $chapter_matches)) {
list($dummy, $chapter_string_length_hex, $chapter_string) = $chapter_matches;
$mdat_offset += (2 + $chapter_string_length); $mdat_offset += (2 + $chapter_string_length);
@$info['quicktime']['comments']['chapters'][] = $chapter_matches[0]; @$info['quicktime']['comments']['chapters'][] = $chapter_string;
}
// "encd" atom specifies encoding. In theory could be anything, almost always UTF-8, but may be UTF-16 with BOM (not currently handled)
if (substr($atom_data, $mdat_offset, 12) == "\x00\x00\x00\x0C\x65\x6E\x63\x64\x00\x00\x01\x00") { // UTF-8
$mdat_offset += 12;
}
}
if (($atomsize > 8) && (!isset($info['avdataend_tmp']) || ($info['quicktime'][$atomname]['size'] > ($info['avdataend_tmp'] - $info['avdataoffset'])))) { if (($atomsize > 8) && (!isset($info['avdataend_tmp']) || ($info['quicktime'][$atomname]['size'] > ($info['avdataend_tmp'] - $info['avdataoffset'])))) {
@ -1397,7 +1505,6 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
break; break;
case "\x00\x00\x00\x00": case "\x00\x00\x00\x00":
case 'meta': // METAdata atom
// some kind of metacontainer, may contain a big data dump such as: // some kind of metacontainer, may contain a big data dump such as:
// mdta keys \005 mdtacom.apple.quicktime.make (mdtacom.apple.quicktime.creationdate ,mdtacom.apple.quicktime.location.ISO6709 $mdtacom.apple.quicktime.software !mdtacom.apple.quicktime.model ilst \01D \001 \015data \001DE\010Apple 0 \002 (data \001DE\0102011-05-11T17:54:04+0200 2 \003 *data \001DE\010+52.4936+013.3897+040.247/ \01D \004 \015data \001DE\0104.3.1 \005 \018data \001DE\010iPhone 4 // mdta keys \005 mdtacom.apple.quicktime.make (mdtacom.apple.quicktime.creationdate ,mdtacom.apple.quicktime.location.ISO6709 $mdtacom.apple.quicktime.software !mdtacom.apple.quicktime.model ilst \01D \001 \015data \001DE\010Apple 0 \002 (data \001DE\0102011-05-11T17:54:04+0200 2 \003 *data \001DE\010+52.4936+013.3897+040.247/ \01D \004 \015data \001DE\0104.3.1 \005 \018data \001DE\010iPhone 4
// http://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt // http://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt
@ -1408,11 +1515,43 @@ if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($
//$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms); //$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
break; break;
case 'meta': // METAdata atom
// https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/Metadata/Metadata.html
$atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
$atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
break;
case 'data': // metaDATA atom case 'data': // metaDATA atom
static $metaDATAkey = 1; // real ugly, but so is the QuickTime structure that stores keys and values in different multinested locations that are hard to relate to each other
// seems to be 2 bytes language code (ASCII), 2 bytes unknown (set to 0x10B5 in sample I have), remainder is useful data // seems to be 2 bytes language code (ASCII), 2 bytes unknown (set to 0x10B5 in sample I have), remainder is useful data
$atom_structure['language'] = substr($atom_data, 4 + 0, 2); $atom_structure['language'] = substr($atom_data, 4 + 0, 2);
$atom_structure['unknown'] = getid3_lib::BigEndian2Int(substr($atom_data, 4 + 2, 2)); $atom_structure['unknown'] = getid3_lib::BigEndian2Int(substr($atom_data, 4 + 2, 2));
$atom_structure['data'] = substr($atom_data, 4 + 4); $atom_structure['data'] = substr($atom_data, 4 + 4);
$atom_structure['key_name'] = @$info['quicktime']['temp_meta_key_names'][$metaDATAkey++];
if ($atom_structure['key_name'] && $atom_structure['data']) {
@$info['quicktime']['comments'][str_replace('com.apple.quicktime.', '', $atom_structure['key_name'])][] = $atom_structure['data'];
}
break;
case 'keys': // KEYS that may be present in the metadata atom.
// https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/Metadata/Metadata.html#//apple_ref/doc/uid/TP40000939-CH1-SW21
// The metadata item keys atom holds a list of the metadata keys that may be present in the metadata atom.
// This list is indexed starting with 1; 0 is a reserved index value. The metadata item keys atom is a full atom with an atom type of "keys".
$atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
$atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
$atom_structure['entry_count'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
$keys_atom_offset = 8;
for ($i = 1; $i <= $atom_structure['entry_count']; $i++) {
$atom_structure['keys'][$i]['key_size'] = getid3_lib::BigEndian2Int(substr($atom_data, $keys_atom_offset + 0, 4));
$atom_structure['keys'][$i]['key_namespace'] = substr($atom_data, $keys_atom_offset + 4, 4);
$atom_structure['keys'][$i]['key_value'] = substr($atom_data, $keys_atom_offset + 8, $atom_structure['keys'][$i]['key_size'] - 8);
$keys_atom_offset += $atom_structure['keys'][$i]['key_size']; // key_size includes the 4+4 bytes for key_size and key_namespace
$info['quicktime']['temp_meta_key_names'][$i] = $atom_structure['keys'][$i]['key_value'];
}
break; break;
default: default:
@ -2111,6 +2250,16 @@ echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br
public function CopyToAppropriateCommentsSection($keyname, $data, $boxname='') { public function CopyToAppropriateCommentsSection($keyname, $data, $boxname='') {
static $handyatomtranslatorarray = array(); static $handyatomtranslatorarray = array();
if (empty($handyatomtranslatorarray)) { if (empty($handyatomtranslatorarray)) {
// http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt
// http://www.geocities.com/xhelmboyx/quicktime/formats/mp4-layout.txt
// http://atomicparsley.sourceforge.net/mpeg-4files.html
// https://code.google.com/p/mp4v2/wiki/iTunesMetadata
$handyatomtranslatorarray["\xA9".'alb'] = 'album'; // iTunes 4.0
$handyatomtranslatorarray["\xA9".'ART'] = 'artist';
$handyatomtranslatorarray["\xA9".'art'] = 'artist'; // iTunes 4.0
$handyatomtranslatorarray["\xA9".'aut'] = 'author';
$handyatomtranslatorarray["\xA9".'cmt'] = 'comment'; // iTunes 4.0
$handyatomtranslatorarray["\xA9".'com'] = 'comment';
$handyatomtranslatorarray["\xA9".'cpy'] = 'copyright'; $handyatomtranslatorarray["\xA9".'cpy'] = 'copyright';
$handyatomtranslatorarray["\xA9".'day'] = 'creation_date'; // iTunes 4.0 $handyatomtranslatorarray["\xA9".'day'] = 'creation_date'; // iTunes 4.0
$handyatomtranslatorarray["\xA9".'dir'] = 'director'; $handyatomtranslatorarray["\xA9".'dir'] = 'director';
@ -2123,64 +2272,60 @@ echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br
$handyatomtranslatorarray["\xA9".'ed7'] = 'edit7'; $handyatomtranslatorarray["\xA9".'ed7'] = 'edit7';
$handyatomtranslatorarray["\xA9".'ed8'] = 'edit8'; $handyatomtranslatorarray["\xA9".'ed8'] = 'edit8';
$handyatomtranslatorarray["\xA9".'ed9'] = 'edit9'; $handyatomtranslatorarray["\xA9".'ed9'] = 'edit9';
$handyatomtranslatorarray["\xA9".'enc'] = 'encoded_by';
$handyatomtranslatorarray["\xA9".'fmt'] = 'format'; $handyatomtranslatorarray["\xA9".'fmt'] = 'format';
$handyatomtranslatorarray["\xA9".'gen'] = 'genre'; // iTunes 4.0
$handyatomtranslatorarray["\xA9".'grp'] = 'grouping'; // iTunes 4.2
$handyatomtranslatorarray["\xA9".'hst'] = 'host_computer';
$handyatomtranslatorarray["\xA9".'inf'] = 'information'; $handyatomtranslatorarray["\xA9".'inf'] = 'information';
$handyatomtranslatorarray["\xA9".'lyr'] = 'lyrics'; // iTunes 5.0
$handyatomtranslatorarray["\xA9".'mak'] = 'make';
$handyatomtranslatorarray["\xA9".'mod'] = 'model';
$handyatomtranslatorarray["\xA9".'nam'] = 'title'; // iTunes 4.0
$handyatomtranslatorarray["\xA9".'ope'] = 'composer';
$handyatomtranslatorarray["\xA9".'prd'] = 'producer'; $handyatomtranslatorarray["\xA9".'prd'] = 'producer';
$handyatomtranslatorarray["\xA9".'PRD'] = 'product';
$handyatomtranslatorarray["\xA9".'prf'] = 'performers'; $handyatomtranslatorarray["\xA9".'prf'] = 'performers';
$handyatomtranslatorarray["\xA9".'req'] = 'system_requirements'; $handyatomtranslatorarray["\xA9".'req'] = 'system_requirements';
$handyatomtranslatorarray["\xA9".'src'] = 'source_credit'; $handyatomtranslatorarray["\xA9".'src'] = 'source_credit';
$handyatomtranslatorarray["\xA9".'wrt'] = 'writer';
// http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt
$handyatomtranslatorarray["\xA9".'nam'] = 'title'; // iTunes 4.0
$handyatomtranslatorarray["\xA9".'cmt'] = 'comment'; // iTunes 4.0
$handyatomtranslatorarray["\xA9".'wrn'] = 'warning';
$handyatomtranslatorarray["\xA9".'hst'] = 'host_computer';
$handyatomtranslatorarray["\xA9".'mak'] = 'make';
$handyatomtranslatorarray["\xA9".'mod'] = 'model';
$handyatomtranslatorarray["\xA9".'PRD'] = 'product';
$handyatomtranslatorarray["\xA9".'swr'] = 'software'; $handyatomtranslatorarray["\xA9".'swr'] = 'software';
$handyatomtranslatorarray["\xA9".'aut'] = 'author'; $handyatomtranslatorarray["\xA9".'too'] = 'encoding_tool'; // iTunes 4.0
$handyatomtranslatorarray["\xA9".'ART'] = 'artist';
$handyatomtranslatorarray["\xA9".'trk'] = 'track'; $handyatomtranslatorarray["\xA9".'trk'] = 'track';
$handyatomtranslatorarray["\xA9".'alb'] = 'album'; // iTunes 4.0
$handyatomtranslatorarray["\xA9".'com'] = 'comment';
$handyatomtranslatorarray["\xA9".'gen'] = 'genre'; // iTunes 4.0
$handyatomtranslatorarray["\xA9".'ope'] = 'composer';
$handyatomtranslatorarray["\xA9".'url'] = 'url'; $handyatomtranslatorarray["\xA9".'url'] = 'url';
$handyatomtranslatorarray["\xA9".'enc'] = 'encoder'; $handyatomtranslatorarray["\xA9".'wrn'] = 'warning';
$handyatomtranslatorarray["\xA9".'wrt'] = 'composer';
// http://atomicparsley.sourceforge.net/mpeg-4files.html
$handyatomtranslatorarray["\xA9".'art'] = 'artist'; // iTunes 4.0
$handyatomtranslatorarray['aART'] = 'album_artist'; $handyatomtranslatorarray['aART'] = 'album_artist';
$handyatomtranslatorarray['trkn'] = 'track_number'; // iTunes 4.0 $handyatomtranslatorarray['apID'] = 'purchase_account';
$handyatomtranslatorarray['disk'] = 'disc_number'; // iTunes 4.0
$handyatomtranslatorarray['gnre'] = 'genre'; // iTunes 4.0
$handyatomtranslatorarray["\xA9".'too'] = 'encoder'; // iTunes 4.0
$handyatomtranslatorarray['tmpo'] = 'bpm'; // iTunes 4.0
$handyatomtranslatorarray['cprt'] = 'copyright'; // iTunes 4.0?
$handyatomtranslatorarray['cpil'] = 'compilation'; // iTunes 4.0
$handyatomtranslatorarray['covr'] = 'picture'; // iTunes 4.0
$handyatomtranslatorarray['rtng'] = 'rating'; // iTunes 4.0
$handyatomtranslatorarray["\xA9".'grp'] = 'grouping'; // iTunes 4.2
$handyatomtranslatorarray['stik'] = 'stik'; // iTunes 4.9
$handyatomtranslatorarray['pcst'] = 'podcast'; // iTunes 4.9
$handyatomtranslatorarray['catg'] = 'category'; // iTunes 4.9 $handyatomtranslatorarray['catg'] = 'category'; // iTunes 4.9
$handyatomtranslatorarray['keyw'] = 'keyword'; // iTunes 4.9 $handyatomtranslatorarray['covr'] = 'picture'; // iTunes 4.0
$handyatomtranslatorarray['purl'] = 'podcast_url'; // iTunes 4.9 $handyatomtranslatorarray['cpil'] = 'compilation'; // iTunes 4.0
$handyatomtranslatorarray['egid'] = 'episode_guid'; // iTunes 4.9 $handyatomtranslatorarray['cprt'] = 'copyright'; // iTunes 4.0?
$handyatomtranslatorarray['desc'] = 'description'; // iTunes 5.0 $handyatomtranslatorarray['desc'] = 'description'; // iTunes 5.0
$handyatomtranslatorarray["\xA9".'lyr'] = 'lyrics'; // iTunes 5.0 $handyatomtranslatorarray['disk'] = 'disc_number'; // iTunes 4.0
$handyatomtranslatorarray['egid'] = 'episode_guid'; // iTunes 4.9
$handyatomtranslatorarray['gnre'] = 'genre'; // iTunes 4.0
$handyatomtranslatorarray['hdvd'] = 'hd_video'; // iTunes 4.0
$handyatomtranslatorarray['ldes'] = 'description_long'; //
$handyatomtranslatorarray['keyw'] = 'keyword'; // iTunes 4.9
$handyatomtranslatorarray['pcst'] = 'podcast'; // iTunes 4.9
$handyatomtranslatorarray['pgap'] = 'gapless_playback'; // iTunes 7.0
$handyatomtranslatorarray['purd'] = 'purchase_date'; // iTunes 6.0.2
$handyatomtranslatorarray['purl'] = 'podcast_url'; // iTunes 4.9
$handyatomtranslatorarray['rtng'] = 'rating'; // iTunes 4.0
$handyatomtranslatorarray['soaa'] = 'sort_album_artist'; //
$handyatomtranslatorarray['soal'] = 'sort_album'; //
$handyatomtranslatorarray['soar'] = 'sort_artist'; //
$handyatomtranslatorarray['soco'] = 'sort_composer'; //
$handyatomtranslatorarray['sonm'] = 'sort_title'; //
$handyatomtranslatorarray['sosn'] = 'sort_show'; //
$handyatomtranslatorarray['stik'] = 'stik'; // iTunes 4.9
$handyatomtranslatorarray['tmpo'] = 'bpm'; // iTunes 4.0
$handyatomtranslatorarray['trkn'] = 'track_number'; // iTunes 4.0
$handyatomtranslatorarray['tven'] = 'tv_episode_id'; //
$handyatomtranslatorarray['tves'] = 'tv_episode'; // iTunes 6.0
$handyatomtranslatorarray['tvnn'] = 'tv_network_name'; // iTunes 6.0 $handyatomtranslatorarray['tvnn'] = 'tv_network_name'; // iTunes 6.0
$handyatomtranslatorarray['tvsh'] = 'tv_show_name'; // iTunes 6.0 $handyatomtranslatorarray['tvsh'] = 'tv_show_name'; // iTunes 6.0
$handyatomtranslatorarray['tvsn'] = 'tv_season'; // iTunes 6.0 $handyatomtranslatorarray['tvsn'] = 'tv_season'; // iTunes 6.0
$handyatomtranslatorarray['tves'] = 'tv_episode'; // iTunes 6.0
$handyatomtranslatorarray['purd'] = 'purchase_date'; // iTunes 6.0.2
$handyatomtranslatorarray['pgap'] = 'gapless_playback'; // iTunes 7.0
// http://www.geocities.com/xhelmboyx/quicktime/formats/mp4-layout.txt
// boxnames: // boxnames:
/* /*
@ -2225,8 +2370,15 @@ echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br
$data = array('data'=>$data, 'image_mime'=>$image_mime); $data = array('data'=>$data, 'image_mime'=>$image_mime);
} }
} }
$gooddata = array($data);
if ($comment_key == 'genre') {
// some other taggers separate multiple genres with semicolon, e.g. "Heavy Metal;Thrash Metal;Metal"
$gooddata = explode(';', $data);
}
foreach ($gooddata as $data) {
$info['quicktime']['comments'][$comment_key][] = $data; $info['quicktime']['comments'][$comment_key][] = $data;
} }
}
return true; return true;
} }
@ -2243,4 +2395,79 @@ echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br
return substr($pascalstring, 1); return substr($pascalstring, 1);
} }
/*
// helper functions for m4b audiobook chapters
// code by Steffen Hartmann 2015-Nov-08
*/
public function search_tag_by_key($info, $tag, $history, &$result) {
foreach ($info as $key => $value) {
$key_history = $history.'/'.$key;
if ($key === $tag) {
$result[] = array($key_history, $info);
} else {
if (is_array($value)) {
$this->search_tag_by_key($value, $tag, $key_history, $result);
}
}
}
}
public function search_tag_by_pair($info, $k, $v, $history, &$result) {
foreach ($info as $key => $value) {
$key_history = $history.'/'.$key;
if (($key === $k) && ($value === $v)) {
$result[] = array($key_history, $info);
} else {
if (is_array($value)) {
$this->search_tag_by_pair($value, $k, $v, $key_history, $result);
}
}
}
}
public function quicktime_time_to_sample_table($info) {
$res = array();
$this->search_tag_by_pair($info['quicktime']['moov'], 'name', 'stbl', 'quicktime/moov', $res);
foreach ($res as $value) {
$stbl_res = array();
$this->search_tag_by_pair($value[1], 'data_format', 'text', $value[0], $stbl_res);
if (count($stbl_res) > 0) {
$stts_res = array();
$this->search_tag_by_key($value[1], 'time_to_sample_table', $value[0], $stts_res);
if (count($stts_res) > 0) {
return $stts_res[0][1]['time_to_sample_table'];
}
}
}
return array();
}
function quicktime_bookmark_time_scale($info) {
$time_scale = '';
$ts_prefix_len = 0;
$res = array();
$this->search_tag_by_pair($info['quicktime']['moov'], 'name', 'stbl', 'quicktime/moov', $res);
foreach ($res as $value) {
$stbl_res = array();
$this->search_tag_by_pair($value[1], 'data_format', 'text', $value[0], $stbl_res);
if (count($stbl_res) > 0) {
$ts_res = array();
$this->search_tag_by_key($info['quicktime']['moov'], 'time_scale', 'quicktime/moov', $ts_res);
foreach ($ts_res as $value) {
$prefix = substr($value[0], 0, -12);
if ((substr($stbl_res[0][0], 0, strlen($prefix)) === $prefix) && ($ts_prefix_len < strlen($prefix))) {
$time_scale = $value[1]['time_scale'];
$ts_prefix_len = strlen($prefix);
}
}
}
}
return $time_scale;
}
/*
// END helper functions for m4b audiobook chapters
*/
} }

0
app/Library/getid3/getid3/module.audio-video.real.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.audio-video.riff.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.audio-video.swf.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.audio-video.ts.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.audio.aa.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.audio.aac.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.audio.ac3.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.audio.amr.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.audio.au.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.audio.avr.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.audio.bonk.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.audio.dss.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.audio.dts.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.audio.flac.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.audio.la.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.audio.lpac.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.audio.midi.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.audio.mod.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.audio.monkey.php Executable file → Normal file
View file

16
app/Library/getid3/getid3/module.audio.mp3.php Executable file → Normal file
View file

@ -437,7 +437,6 @@ class getid3_mp3 extends getid3_handler
// and $cc... is the audio data // and $cc... is the audio data
$head4 = substr($headerstring, 0, 4); $head4 = substr($headerstring, 0, 4);
static $MPEGaudioHeaderDecodeCache = array(); static $MPEGaudioHeaderDecodeCache = array();
if (isset($MPEGaudioHeaderDecodeCache[$head4])) { if (isset($MPEGaudioHeaderDecodeCache[$head4])) {
$MPEGheaderRawArray = $MPEGaudioHeaderDecodeCache[$head4]; $MPEGheaderRawArray = $MPEGaudioHeaderDecodeCache[$head4];
@ -648,9 +647,20 @@ class getid3_mp3 extends getid3_handler
} }
//if (($thisfile_mpeg_audio['bitrate'] == 'free') && !empty($thisfile_mpeg_audio['VBR_frames']) && !empty($thisfile_mpeg_audio['VBR_bytes'])) { //if (($thisfile_mpeg_audio['bitrate'] == 'free') && !empty($thisfile_mpeg_audio['VBR_frames']) && !empty($thisfile_mpeg_audio['VBR_bytes'])) {
if (!empty($thisfile_mpeg_audio['VBR_frames']) && !empty($thisfile_mpeg_audio['VBR_bytes'])) { //if (!empty($thisfile_mpeg_audio['VBR_frames']) && !empty($thisfile_mpeg_audio['VBR_bytes'])) {
if (!empty($thisfile_mpeg_audio['VBR_frames'])) {
$used_filesize = 0;
if (!empty($thisfile_mpeg_audio['VBR_bytes'])) {
$used_filesize = $thisfile_mpeg_audio['VBR_bytes'];
} elseif (!empty($info['filesize'])) {
$used_filesize = $info['filesize'];
$used_filesize -= intval(@$info['id3v2']['headerlength']);
$used_filesize -= (isset($info['id3v1']) ? 128 : 0);
$used_filesize -= (isset($info['tag_offset_end']) ? $info['tag_offset_end'] - $info['tag_offset_start'] : 0);
$info['warning'][] = 'MP3.Xing header missing VBR_bytes, assuming MPEG audio portion of file is '.number_format($used_filesize).' bytes';
}
$framelengthfloat = $thisfile_mpeg_audio['VBR_bytes'] / $thisfile_mpeg_audio['VBR_frames']; $framelengthfloat = $used_filesize / $thisfile_mpeg_audio['VBR_frames'];
if ($thisfile_mpeg_audio['layer'] == '1') { if ($thisfile_mpeg_audio['layer'] == '1') {
// BitRate = (((FrameLengthInBytes / 4) - Padding) * SampleRate) / 12 // BitRate = (((FrameLengthInBytes / 4) - Padding) * SampleRate) / 12

0
app/Library/getid3/getid3/module.audio.mpc.php Executable file → Normal file
View file

1
app/Library/getid3/getid3/module.audio.ogg.php Executable file → Normal file
View file

@ -562,6 +562,7 @@ $info['warning'][] = 'Ogg Theora (v3) not fully supported in this version of get
default: default:
return false; return false;
break;
} }
$VendorSize = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4)); $VendorSize = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4));

0
app/Library/getid3/getid3/module.audio.optimfrog.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.audio.rkau.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.audio.shorten.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.audio.tta.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.audio.voc.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.audio.vqf.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.audio.wavpack.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.graphic.bmp.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.graphic.efax.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.graphic.gif.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.graphic.jpg.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.graphic.pcd.php Executable file → Normal file
View file

12
app/Library/getid3/getid3/module.graphic.png.php Executable file → Normal file
View file

@ -17,8 +17,10 @@
class getid3_png extends getid3_handler class getid3_png extends getid3_handler
{ {
public $max_data_bytes = 10000000; // if data chunk is larger than this do not read it completely (getID3 only needs the first few dozen bytes for parsing)
public function Analyze() { public function Analyze() {
$info = &$this->getid3->info; $info = &$this->getid3->info;
// shortcut // shortcut
@ -44,9 +46,19 @@ class getid3_png extends getid3_handler
while ((($this->ftell() - (strlen($PNGfiledata) - $offset)) < $info['filesize'])) { while ((($this->ftell() - (strlen($PNGfiledata) - $offset)) < $info['filesize'])) {
$chunk['data_length'] = getid3_lib::BigEndian2Int(substr($PNGfiledata, $offset, 4)); $chunk['data_length'] = getid3_lib::BigEndian2Int(substr($PNGfiledata, $offset, 4));
if ($chunk['data_length'] === false) {
$info['error'][] = 'Failed to read data_length at offset '.$offset;
return false;
}
$offset += 4; $offset += 4;
$truncated_data = false;
while (((strlen($PNGfiledata) - $offset) < ($chunk['data_length'] + 4)) && ($this->ftell() < $info['filesize'])) { while (((strlen($PNGfiledata) - $offset) < ($chunk['data_length'] + 4)) && ($this->ftell() < $info['filesize'])) {
if (strlen($PNGfiledata) < $this->max_data_bytes) {
$PNGfiledata .= $this->fread($this->getid3->fread_buffer_size()); $PNGfiledata .= $this->fread($this->getid3->fread_buffer_size());
} else {
$info['warning'][] = 'At offset '.$offset.' chunk "'.substr($PNGfiledata, $offset, 4).'" exceeded max_data_bytes value of '.$this->max_data_bytes.', data chunk will be truncated at '.(strlen($PNGfiledata) - 8).' bytes';
break;
}
} }
$chunk['type_text'] = substr($PNGfiledata, $offset, 4); $chunk['type_text'] = substr($PNGfiledata, $offset, 4);
$offset += 4; $offset += 4;

0
app/Library/getid3/getid3/module.graphic.svg.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.graphic.tiff.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.misc.cue.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.misc.exe.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.misc.iso.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.misc.msoffice.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.misc.par2.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.misc.pdf.php Executable file → Normal file
View file

6
app/Library/getid3/getid3/module.tag.apetag.php Executable file → Normal file
View file

@ -260,12 +260,16 @@ class getid3_apetag extends getid3_handler
$thisfile_ape_items_current['data_offset'] = $thisfile_ape_items_current['offset'] + strlen($thisfile_ape_items_current['filename']."\x00"); $thisfile_ape_items_current['data_offset'] = $thisfile_ape_items_current['offset'] + strlen($thisfile_ape_items_current['filename']."\x00");
$thisfile_ape_items_current['data_length'] = strlen($thisfile_ape_items_current['data']); $thisfile_ape_items_current['data_length'] = strlen($thisfile_ape_items_current['data']);
do {
$thisfile_ape_items_current['image_mime'] = ''; $thisfile_ape_items_current['image_mime'] = '';
$imageinfo = array(); $imageinfo = array();
$imagechunkcheck = getid3_lib::GetDataImageSize($thisfile_ape_items_current['data'], $imageinfo); $imagechunkcheck = getid3_lib::GetDataImageSize($thisfile_ape_items_current['data'], $imageinfo);
if (($imagechunkcheck === false) || !isset($imagechunkcheck[2])) {
$info['warning'][] = 'APEtag "'.$item_key.'" contains invalid image data';
break;
}
$thisfile_ape_items_current['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]); $thisfile_ape_items_current['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]);
do {
if ($this->inline_attachments === false) { if ($this->inline_attachments === false) {
// skip entirely // skip entirely
unset($thisfile_ape_items_current['data']); unset($thisfile_ape_items_current['data']);

0
app/Library/getid3/getid3/module.tag.id3v1.php Executable file → Normal file
View file

49
app/Library/getid3/getid3/module.tag.id3v2.php Executable file → Normal file
View file

@ -442,11 +442,15 @@ class getid3_id3v2 extends getid3_handler
} // end footer } // end footer
if (isset($thisfile_id3v2['comments']['genre'])) { if (isset($thisfile_id3v2['comments']['genre'])) {
$genres = array();
foreach ($thisfile_id3v2['comments']['genre'] as $key => $value) { foreach ($thisfile_id3v2['comments']['genre'] as $key => $value) {
unset($thisfile_id3v2['comments']['genre'][$key]); foreach ($this->ParseID3v2GenreString($value) as $genre) {
$thisfile_id3v2['comments'] = getid3_lib::array_merge_noclobber($thisfile_id3v2['comments'], array('genre'=>$this->ParseID3v2GenreString($value))); $genres[] = $genre;
} }
} }
$thisfile_id3v2['comments']['genre'] = array_unique($genres);
unset($key, $value, $genres, $genre);
}
if (isset($thisfile_id3v2['comments']['track'])) { if (isset($thisfile_id3v2['comments']['track'])) {
foreach ($thisfile_id3v2['comments']['track'] as $key => $value) { foreach ($thisfile_id3v2['comments']['track'] as $key => $value) {
@ -503,6 +507,16 @@ class getid3_id3v2 extends getid3_handler
if (strpos($genrestring, "\x00") === false) { if (strpos($genrestring, "\x00") === false) {
$genrestring = preg_replace('#\(([0-9]{1,3})\)#', '$1'."\x00", $genrestring); $genrestring = preg_replace('#\(([0-9]{1,3})\)#', '$1'."\x00", $genrestring);
} }
// note: MusicBrainz Picard incorrectly stores plaintext genres separated by "/" when writing in ID3v2.3 mode, hack-fix here:
// replace / with NULL, then replace back the two ID3v1 genres that legitimately have "/" as part of the single genre name
$genrestring = str_replace('/', "\x00", $genrestring);
$genrestring = str_replace('Pop'."\x00".'Funk', 'Pop/Funk', $genrestring);
$genrestring = str_replace('Rock'."\x00".'Rock', 'Folk/Rock', $genrestring);
// some other taggers separate multiple genres with semicolon, e.g. "Heavy Metal;Thrash Metal;Metal"
$genrestring = str_replace(';', "\x00", $genrestring);
$genre_elements = explode("\x00", $genrestring); $genre_elements = explode("\x00", $genrestring);
foreach ($genre_elements as $element) { foreach ($genre_elements as $element) {
$element = trim($element); $element = trim($element);
@ -635,7 +649,8 @@ class getid3_id3v2 extends getid3_handler
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
} }
$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
if (ord($frame_description) === 0) { if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) {
// if description only contains a BOM or terminator then make it blank
$frame_description = ''; $frame_description = '';
} }
$parsedFrame['encodingid'] = $frame_textencoding; $parsedFrame['encodingid'] = $frame_textencoding;
@ -728,8 +743,8 @@ class getid3_id3v2 extends getid3_handler
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
} }
$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) {
if (ord($frame_description) === 0) { // if description only contains a BOM or terminator then make it blank
$frame_description = ''; $frame_description = '';
} }
$parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator)); $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
@ -971,7 +986,8 @@ class getid3_id3v2 extends getid3_handler
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
} }
$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
if (ord($frame_description) === 0) { if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) {
// if description only contains a BOM or terminator then make it blank
$frame_description = ''; $frame_description = '';
} }
$parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator)); $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
@ -979,7 +995,6 @@ class getid3_id3v2 extends getid3_handler
$parsedFrame['encodingid'] = $frame_textencoding; $parsedFrame['encodingid'] = $frame_textencoding;
$parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
$parsedFrame['data'] = $parsedFrame['data'];
$parsedFrame['language'] = $frame_language; $parsedFrame['language'] = $frame_language;
$parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false); $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
$parsedFrame['description'] = $frame_description; $parsedFrame['description'] = $frame_description;
@ -1079,7 +1094,8 @@ class getid3_id3v2 extends getid3_handler
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
} }
$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
if (ord($frame_description) === 0) { if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) {
// if description only contains a BOM or terminator then make it blank
$frame_description = ''; $frame_description = '';
} }
$frame_text = (string) substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator)); $frame_text = (string) substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
@ -1383,7 +1399,8 @@ class getid3_id3v2 extends getid3_handler
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
} }
$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
if (ord($frame_description) === 0) { if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) {
// if description only contains a BOM or terminator then make it blank
$frame_description = ''; $frame_description = '';
} }
$parsedFrame['encodingid'] = $frame_textencoding; $parsedFrame['encodingid'] = $frame_textencoding;
@ -1402,7 +1419,7 @@ class getid3_id3v2 extends getid3_handler
$parsedFrame['image_mime'] = ''; $parsedFrame['image_mime'] = '';
$imageinfo = array(); $imageinfo = array();
$imagechunkcheck = getid3_lib::GetDataImageSize($parsedFrame['data'], $imageinfo); if ($imagechunkcheck = getid3_lib::GetDataImageSize($parsedFrame['data'], $imageinfo)) {
if (($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3)) { if (($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3)) {
$parsedFrame['image_mime'] = 'image/'.getid3_lib::ImageTypesLookup($imagechunkcheck[2]); $parsedFrame['image_mime'] = 'image/'.getid3_lib::ImageTypesLookup($imagechunkcheck[2]);
if ($imagechunkcheck[0]) { if ($imagechunkcheck[0]) {
@ -1412,6 +1429,7 @@ class getid3_id3v2 extends getid3_handler
$parsedFrame['image_height'] = $imagechunkcheck[1]; $parsedFrame['image_height'] = $imagechunkcheck[1];
} }
} }
}
do { do {
if ($this->getid3->option_save_attachments === false) { if ($this->getid3->option_save_attachments === false) {
@ -1507,7 +1525,8 @@ class getid3_id3v2 extends getid3_handler
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
} }
$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
if (ord($frame_description) === 0) { if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) {
// if description only contains a BOM or terminator then make it blank
$frame_description = ''; $frame_description = '';
} }
$frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator); $frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator);
@ -1589,7 +1608,8 @@ class getid3_id3v2 extends getid3_handler
$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
if (ord($frame_description) === 0) { if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) {
// if description only contains a BOM or terminator then make it blank
$frame_description = ''; $frame_description = '';
} }
$frame_offset = $frame_terminatorpos + strlen("\x00"); $frame_offset = $frame_terminatorpos + strlen("\x00");
@ -1614,7 +1634,7 @@ class getid3_id3v2 extends getid3_handler
$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
$frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
if (ord($frame_ownerid) === 0) { if (ord($frame_ownerid) === 0) {
$frame_ownerid == ''; $frame_ownerid = '';
} }
$frame_offset = $frame_terminatorpos + strlen("\x00"); $frame_offset = $frame_terminatorpos + strlen("\x00");
$parsedFrame['ownerid'] = $frame_ownerid; $parsedFrame['ownerid'] = $frame_ownerid;
@ -1789,7 +1809,8 @@ class getid3_id3v2 extends getid3_handler
$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
} }
$frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
if (ord($frame_description) === 0) { if (in_array($frame_description, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) {
// if description only contains a BOM or terminator then make it blank
$frame_description = ''; $frame_description = '';
} }
$frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator); $frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator);

0
app/Library/getid3/getid3/module.tag.lyrics3.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/module.tag.xmp.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/write.apetag.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/write.id3v1.php Executable file → Normal file
View file

13
app/Library/getid3/getid3/write.id3v2.php Executable file → Normal file
View file

@ -1759,10 +1759,15 @@ class getid3_write_id3v2
} }
public function ID3v2IsValidTextEncoding($textencodingbyte) { public function ID3v2IsValidTextEncoding($textencodingbyte) {
// 0 = ISO-8859-1
// 1 = UTF-16 with BOM
// 2 = UTF-16BE without BOM
// 3 = UTF-8
static $ID3v2IsValidTextEncoding_cache = array( static $ID3v2IsValidTextEncoding_cache = array(
2 => array(true, true), 2 => array(true, true), // ID3v2.2 - allow 0=ISO-8859-1, 1=UTF-16
3 => array(true, true), 3 => array(true, true), // ID3v2.3 - allow 0=ISO-8859-1, 1=UTF-16
4 => array(true, true, true, true)); 4 => array(true, true, true, true), // ID3v2.4 - allow 0=ISO-8859-1, 1=UTF-16, 2=UTF-16BE, 3=UTF-8
);
return isset($ID3v2IsValidTextEncoding_cache[$this->majorversion][$textencodingbyte]); return isset($ID3v2IsValidTextEncoding_cache[$this->majorversion][$textencodingbyte]);
} }
@ -1906,6 +1911,7 @@ class getid3_write_id3v2
$ID3v2ShortFrameNameLookup[2]['comment'] = 'COM'; $ID3v2ShortFrameNameLookup[2]['comment'] = 'COM';
$ID3v2ShortFrameNameLookup[2]['album'] = 'TAL'; $ID3v2ShortFrameNameLookup[2]['album'] = 'TAL';
$ID3v2ShortFrameNameLookup[2]['beats_per_minute'] = 'TBP'; $ID3v2ShortFrameNameLookup[2]['beats_per_minute'] = 'TBP';
$ID3v2ShortFrameNameLookup[2]['bpm'] = 'TBP';
$ID3v2ShortFrameNameLookup[2]['composer'] = 'TCM'; $ID3v2ShortFrameNameLookup[2]['composer'] = 'TCM';
$ID3v2ShortFrameNameLookup[2]['genre'] = 'TCO'; $ID3v2ShortFrameNameLookup[2]['genre'] = 'TCO';
$ID3v2ShortFrameNameLookup[2]['itunescompilation'] = 'TCP'; $ID3v2ShortFrameNameLookup[2]['itunescompilation'] = 'TCP';
@ -1966,6 +1972,7 @@ class getid3_write_id3v2
$ID3v2ShortFrameNameLookup[3]['synchronised_tempo_codes'] = 'SYTC'; $ID3v2ShortFrameNameLookup[3]['synchronised_tempo_codes'] = 'SYTC';
$ID3v2ShortFrameNameLookup[3]['album'] = 'TALB'; $ID3v2ShortFrameNameLookup[3]['album'] = 'TALB';
$ID3v2ShortFrameNameLookup[3]['beats_per_minute'] = 'TBPM'; $ID3v2ShortFrameNameLookup[3]['beats_per_minute'] = 'TBPM';
$ID3v2ShortFrameNameLookup[3]['bpm'] = 'TBPM';
$ID3v2ShortFrameNameLookup[3]['itunescompilation'] = 'TCMP'; $ID3v2ShortFrameNameLookup[3]['itunescompilation'] = 'TCMP';
$ID3v2ShortFrameNameLookup[3]['composer'] = 'TCOM'; $ID3v2ShortFrameNameLookup[3]['composer'] = 'TCOM';
$ID3v2ShortFrameNameLookup[3]['genre'] = 'TCON'; $ID3v2ShortFrameNameLookup[3]['genre'] = 'TCON';

0
app/Library/getid3/getid3/write.lyrics3.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/write.metaflac.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/write.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/write.real.php Executable file → Normal file
View file

0
app/Library/getid3/getid3/write.vorbiscomment.php Executable file → Normal file
View file

0
app/Library/getid3/helperapps/head.exe Executable file → Normal file
View file

0
app/Library/getid3/helperapps/md5sum.exe Executable file → Normal file
View file

0
app/Library/getid3/helperapps/metaflac.exe Executable file → Normal file
View file

0
app/Library/getid3/helperapps/readme.helperapps.txt Executable file → Normal file
View file

0
app/Library/getid3/helperapps/shorten.exe Executable file → Normal file
View file

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