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