188 lines
8.2 KiB
PHP
188 lines
8.2 KiB
PHP
<?php
|
|
/////////////////////////////////////////////////////////////////
|
|
/// getID3() by James Heinrich <getid3@users.sourceforge.net> //
|
|
// available at http://getid3.sourceforge.net ///
|
|
/////////////////////////////////////////////////////////////////
|
|
// //
|
|
// getid3.ape.php - part of getID3() //
|
|
// See getid3.readme.txt for more details //
|
|
// //
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
function getAPEtagFilepointer(&$fd, &$ThisFileInfo) {
|
|
$id3v1tagsize = 128;
|
|
$apetagheadersize = 32;
|
|
fseek($fd, 0 - $id3v1tagsize - $apetagheadersize, SEEK_END);
|
|
$APEfooterID3v1 = fread($fd, $id3v1tagsize + $apetagheadersize);
|
|
if (substr($APEfooterID3v1, 0, strlen('APETAGEX')) == 'APETAGEX') {
|
|
|
|
// APE tag found before ID3v1
|
|
$APEfooterData = substr($APEfooterID3v1, 0, $apetagheadersize);
|
|
$APEfooterOffset = 0 - $apetagheadersize - $id3v1tagsize;
|
|
|
|
} elseif (substr($APEfooterID3v1, $id3v1tagsize, strlen('APETAGEX')) == 'APETAGEX') {
|
|
|
|
// APE tag found, no ID3v1
|
|
$APEfooterData = substr($APEfooterID3v1, $id3v1tagsize, $apetagheadersize);
|
|
$APEfooterOffset = 0 - $apetagheadersize;
|
|
|
|
} else {
|
|
|
|
// APE tag not found
|
|
return false;
|
|
|
|
}
|
|
|
|
if (empty($ThisFileInfo['fileformat'])) {
|
|
$ThisFileInfo['fileformat'] = 'ape';
|
|
}
|
|
$ThisFileInfo['ape']['footer'] = parseAPEheaderFooter($APEfooterData);
|
|
|
|
if (isset($ThisFileInfo['ape']['footer']['flags']['header']) && $ThisFileInfo['ape']['footer']['flags']['header']) {
|
|
fseek($fd, $APEfooterOffset - $ThisFileInfo['ape']['footer']['raw']['tagsize'] + $apetagheadersize - $apetagheadersize, SEEK_END);
|
|
$APEtagData = fread($fd, $ThisFileInfo['ape']['footer']['raw']['tagsize'] + $apetagheadersize);
|
|
} else {
|
|
fseek($fd, $APEfooterOffset - $ThisFileInfo['ape']['footer']['raw']['tagsize'] + $apetagheadersize, SEEK_END);
|
|
$APEtagData = fread($fd, $ThisFileInfo['ape']['footer']['raw']['tagsize']);
|
|
}
|
|
$offset = 0;
|
|
if (isset($ThisFileInfo['ape']['footer']['flags']['header']) && $ThisFileInfo['ape']['footer']['flags']['header']) {
|
|
$ThisFileInfo['ape']['header'] = parseAPEheaderFooter(substr($APEtagData, 0, $apetagheadersize));
|
|
$offset += $apetagheadersize;
|
|
}
|
|
|
|
for ($i = 0; $i < $ThisFileInfo['ape']['footer']['raw']['tag_items']; $i++) {
|
|
$value_size = LittleEndian2Int(substr($APEtagData, $offset, 4));
|
|
$offset += 4;
|
|
$item_flags = LittleEndian2Int(substr($APEtagData, $offset, 4));
|
|
$offset += 4;
|
|
$ItemKeyLength = strpos($APEtagData, chr(0), $offset) - $offset;
|
|
$item_key = strtolower(substr($APEtagData, $offset, $ItemKeyLength));
|
|
$offset += $ItemKeyLength + 1; // skip 0x00 terminator
|
|
$data = substr($APEtagData, $offset, $value_size);
|
|
$offset += $value_size;
|
|
|
|
$ThisFileInfo['ape']['items']["$item_key"]['raw']['value_size'] = $value_size;
|
|
$ThisFileInfo['ape']['items']["$item_key"]['raw']['item_flags'] = $item_flags;
|
|
if ($ThisFileInfo['ape']['footer']['tag_version'] >= 2) {
|
|
$ThisFileInfo['ape']['items']["$item_key"]['flags'] = parseAPEtagFlags($item_flags);
|
|
}
|
|
$ThisFileInfo['ape']['items']["$item_key"]['data'] = $data;
|
|
$ThisFileInfo['ape']['items']["$item_key"]['data_ascii'] = $data;
|
|
if (APEtagItemIsUTF8Lookup($item_key)) {
|
|
$ThisFileInfo['ape']['items']["$item_key"]['data_ascii'] = RoughTranslateUnicodeToASCII($ThisFileInfo['ape']['items']["$item_key"]['data'], 3);
|
|
}
|
|
|
|
switch ($item_key) {
|
|
case 'replaygain_track_gain':
|
|
$ThisFileInfo['replay_gain']['radio']['adjustment'] = (float) $ThisFileInfo['ape']['items']["$item_key"]['data_ascii'];
|
|
$ThisFileInfo['replay_gain']['radio']['originator'] = 'unspecified';
|
|
break;
|
|
|
|
case 'replaygain_track_peak':
|
|
$ThisFileInfo['replay_gain']['radio']['peak'] = (float) $ThisFileInfo['ape']['items']["$item_key"]['data_ascii'];
|
|
$ThisFileInfo['replay_gain']['radio']['originator'] = 'unspecified';
|
|
break;
|
|
|
|
case 'replaygain_album_gain':
|
|
$ThisFileInfo['replay_gain']['audiophile']['adjustment'] = (float) $ThisFileInfo['ape']['items']["$item_key"]['data_ascii'];
|
|
$ThisFileInfo['replay_gain']['audiophile']['originator'] = 'unspecified';
|
|
break;
|
|
|
|
case 'replaygain_album_peak':
|
|
$ThisFileInfo['replay_gain']['audiophile']['peak'] = (float) $ThisFileInfo['ape']['items']["$item_key"]['data_ascii'];
|
|
$ThisFileInfo['replay_gain']['audiophile']['originator'] = 'unspecified';
|
|
break;
|
|
|
|
case 'title':
|
|
case 'artist':
|
|
case 'album':
|
|
case 'track':
|
|
case 'genre':
|
|
case 'comment':
|
|
case 'year':
|
|
$ThisFileInfo['ape']['comments']["$item_key"][] = $ThisFileInfo['ape']['items']["$item_key"]['data_ascii'];
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
if (isset($ThisFileInfo['ape']['comments'])) {
|
|
CopyFormatCommentsToRootComments($ThisFileInfo['ape']['comments'], $ThisFileInfo, true, true, true);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
function parseAPEheaderFooter($APEheaderFooterData) {
|
|
// http://www.uni-jena.de/~pfk/mpp/sv8/apeheader.html
|
|
$headerfooterinfo['raw']['footer_tag'] = substr($APEheaderFooterData, 0, 8);
|
|
$headerfooterinfo['raw']['version'] = LittleEndian2Int(substr($APEheaderFooterData, 8, 4));
|
|
$headerfooterinfo['raw']['tagsize'] = LittleEndian2Int(substr($APEheaderFooterData, 12, 4));
|
|
$headerfooterinfo['raw']['tag_items'] = LittleEndian2Int(substr($APEheaderFooterData, 16, 4));
|
|
$headerfooterinfo['raw']['global_flags'] = LittleEndian2Int(substr($APEheaderFooterData, 20, 4));
|
|
$headerfooterinfo['raw']['reserved'] = substr($APEheaderFooterData, 24, 8);
|
|
|
|
$headerfooterinfo['tag_version'] = $headerfooterinfo['raw']['version'] / 1000;
|
|
if ($headerfooterinfo['tag_version'] >= 2) {
|
|
$headerfooterinfo['flags'] = parseAPEtagFlags($headerfooterinfo['raw']['global_flags']);
|
|
}
|
|
return $headerfooterinfo;
|
|
}
|
|
|
|
function parseAPEtagFlags($rawflagint) {
|
|
// "Note: APE Tags 1.0 do not use any of the APE Tag flags.
|
|
// All are set to zero on creation and ignored on reading."
|
|
// http://www.uni-jena.de/~pfk/mpp/sv8/apetagflags.html
|
|
$flags['header'] = (bool) ($rawflagint & 0x80000000);
|
|
$flags['footer'] = (bool) ($rawflagint & 0x40000000);
|
|
$flags['this_is_header'] = (bool) ($rawflagint & 0x20000000);
|
|
$flags['item_contents_raw'] = ($rawflagint & 0x00000006) >> 1;
|
|
$flags['item_contents'] = APEcontentTypeFlagLookup($flags['item_contents_raw']);
|
|
$flags['read_only'] = (bool) ($rawflagint & 0x00000001);
|
|
|
|
return $flags;
|
|
}
|
|
|
|
function APEcontentTypeFlagLookup($contenttypeid) {
|
|
static $APEcontentTypeFlagLookup = array();
|
|
if (empty($APEcontentTypeFlagLookup)) {
|
|
$APEcontentTypeFlagLookup[0] = 'utf-8';
|
|
$APEcontentTypeFlagLookup[1] = 'binary';
|
|
$APEcontentTypeFlagLookup[2] = 'external';
|
|
$APEcontentTypeFlagLookup[3] = 'reserved';
|
|
}
|
|
return (isset($APEcontentTypeFlagLookup[$contenttypeid]) ? $APEcontentTypeFlagLookup[$contenttypeid] : 'invalid');
|
|
}
|
|
|
|
function APEtagItemIsUTF8Lookup($itemkey) {
|
|
static $APEtagItemIsUTF8Lookup = array();
|
|
if (empty($APEtagItemIsUTF8Lookup)) {
|
|
$APEtagItemIsUTF8Lookup[] = 'Title';
|
|
$APEtagItemIsUTF8Lookup[] = 'Subtitle';
|
|
$APEtagItemIsUTF8Lookup[] = 'Artist';
|
|
$APEtagItemIsUTF8Lookup[] = 'Album';
|
|
$APEtagItemIsUTF8Lookup[] = 'Debut Album';
|
|
$APEtagItemIsUTF8Lookup[] = 'Publisher';
|
|
$APEtagItemIsUTF8Lookup[] = 'Conductor';
|
|
$APEtagItemIsUTF8Lookup[] = 'Track';
|
|
$APEtagItemIsUTF8Lookup[] = 'Composer';
|
|
$APEtagItemIsUTF8Lookup[] = 'Comment';
|
|
$APEtagItemIsUTF8Lookup[] = 'Copyright';
|
|
$APEtagItemIsUTF8Lookup[] = 'Publicationright';
|
|
$APEtagItemIsUTF8Lookup[] = 'File';
|
|
$APEtagItemIsUTF8Lookup[] = 'Year';
|
|
$APEtagItemIsUTF8Lookup[] = 'Record Date';
|
|
$APEtagItemIsUTF8Lookup[] = 'Record Location';
|
|
$APEtagItemIsUTF8Lookup[] = 'Genre';
|
|
$APEtagItemIsUTF8Lookup[] = 'Media';
|
|
$APEtagItemIsUTF8Lookup[] = 'Related';
|
|
$APEtagItemIsUTF8Lookup[] = 'ISRC';
|
|
$APEtagItemIsUTF8Lookup[] = 'Abstract';
|
|
$APEtagItemIsUTF8Lookup[] = 'Language';
|
|
$APEtagItemIsUTF8Lookup[] = 'Bibliography';
|
|
}
|
|
return in_array($itemkey, $APEtagItemIsUTF8Lookup);
|
|
}
|
|
|
|
?>
|