Example #1
0
function getVOCheaderFilepointer(&$fd, &$ThisFileInfo)
{
    $OriginalAVdataOffset = $ThisFileInfo['avdataoffset'];
    fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
    $VOCheader = fread($fd, 26);
    if (substr($VOCheader, 0, 19) != 'Creative Voice File') {
        $ThisFileInfo['error'] .= "\n" . 'Expecting "Creative Voice File" at offset ' . $ThisFileInfo['avdataoffset'] . ', found "' . substr($VOCheader, 0, 19) . '"';
        return false;
    }
    $ThisFileInfo['fileformat'] = 'voc';
    $ThisFileInfo['audio']['dataformat'] = 'voc';
    $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
    $ThisFileInfo['audio']['channels'] = 1;
    // might be overriden below
    $ThisFileInfo['audio']['bits_per_sample'] = 8;
    // might be overriden below
    // byte #     Description
    // ------     ------------------------------------------
    // 00-12      'Creative Voice File'
    // 13         1A (eof to abort printing of file)
    // 14-15      Offset of first datablock in .voc file (std 1A 00 in Intel Notation)
    // 16-17      Version number (minor,major) (VOC-HDR puts 0A 01)
    // 18-19      2's Comp of Ver. # + 1234h (VOC-HDR puts 29 11)
    $ThisFileInfo['voc']['header']['datablock_offset'] = LittleEndian2Int(substr($VOCheader, 20, 2));
    $ThisFileInfo['voc']['header']['minor_version'] = LittleEndian2Int(substr($VOCheader, 22, 1));
    $ThisFileInfo['voc']['header']['major_version'] = LittleEndian2Int(substr($VOCheader, 23, 1));
    do {
        $BlockOffset = ftell($fd);
        $BlockData = fread($fd, 4);
        $BlockType = LittleEndian2Int(substr($BlockData, 0, 1));
        $BlockSize = LittleEndian2Int(substr($BlockData, 1, 3));
        $ThisBlock = array();
        switch ($BlockType) {
            case 0:
                // Terminator
                // do nothing, we'll break out of the loop down below
                break;
            case 1:
                // Sound data
                $BlockData .= fread($fd, 2);
                if ($ThisFileInfo['avdataoffset'] <= $OriginalAVdataOffset) {
                    $ThisFileInfo['avdataoffset'] = ftell($fd);
                }
                fseek($fd, $BlockSize - 2, SEEK_CUR);
                $ThisBlock['sample_rate_id'] = LittleEndian2Int(substr($BlockData, 4, 1));
                $ThisBlock['compression_type'] = LittleEndian2Int(substr($BlockData, 5, 1));
                $ThisBlock['compression_name'] = VOCcompressionTypeLookup($ThisBlock['compression_type']);
                if ($ThisBlock['compression_type'] <= 3) {
                    $ThisFileInfo['voc']['compressed_bits_per_sample'] = CastAsInt(str_replace('-bit', '', $ThisBlock['compression_name']));
                }
                if (empty($ThisFileInfo['audio']['sample_rate'])) {
                    // Less accurate than the Extended block (#8) data
                    // SR byte = 256-(1000000/sample_rate)
                    $ThisFileInfo['audio']['sample_rate'] = trunc(1000000 / (256 - $ThisBlock['sample_rate_id']) / $ThisFileInfo['audio']['channels']);
                }
                break;
            case 2:
                // Sound continue
            // Sound continue
            case 3:
                // Silence
            // Silence
            case 4:
                // Marker
            // Marker
            case 6:
                // Repeat
            // Repeat
            case 7:
                // End repeat
                // nothing useful, just skip
                fseek($fd, $BlockSize, SEEK_CUR);
                break;
            case 8:
                // Extended
                $BlockData .= fread($fd, 4);
                //00-01  Time Constant:
                //   Mono: 65536 - (256000000 / sample_rate)
                // Stereo: 65536 - (256000000 / (sample_rate * 2))
                $ThisBlock['time_constant'] = LittleEndian2Int(substr($BlockData, 4, 2));
                $ThisBlock['pack_method'] = LittleEndian2Int(substr($BlockData, 6, 1));
                $ThisBlock['stereo'] = (bool) LittleEndian2Int(substr($BlockData, 7, 1));
                $ThisFileInfo['audio']['channels'] = $ThisBlock['stereo'] ? 2 : 1;
                $ThisFileInfo['audio']['sample_rate'] = trunc(256000000 / (65536 - $ThisBlock['time_constant']) / $ThisFileInfo['audio']['channels']);
                break;
            case 9:
                // data block that supersedes blocks 1 and 8. Used for stereo, 16 bit
                $BlockData .= fread($fd, 12);
                if ($ThisFileInfo['avdataoffset'] <= $OriginalAVdataOffset) {
                    $ThisFileInfo['avdataoffset'] = ftell($fd);
                }
                fseek($fd, $BlockSize - 12, SEEK_CUR);
                $ThisBlock['sample_rate'] = LittleEndian2Int(substr($BlockData, 4, 4));
                $ThisBlock['bits_per_sample'] = LittleEndian2Int(substr($BlockData, 8, 1));
                $ThisBlock['channels'] = LittleEndian2Int(substr($BlockData, 9, 1));
                $ThisBlock['wFormat'] = LittleEndian2Int(substr($BlockData, 10, 2));
                $ThisBlock['compression_name'] = VOCwFormatLookup($ThisBlock['wFormat']);
                if (VOCwFormatActualBitsPerSampleLookup($ThisBlock['wFormat'])) {
                    $ThisFileInfo['voc']['compressed_bits_per_sample'] = VOCwFormatActualBitsPerSampleLookup($ThisBlock['wFormat']);
                }
                $ThisFileInfo['audio']['sample_rate'] = $ThisBlock['sample_rate'];
                $ThisFileInfo['audio']['bits_per_sample'] = $ThisBlock['bits_per_sample'];
                $ThisFileInfo['audio']['channels'] = $ThisBlock['channels'];
                break;
            default:
                $ThisFileInfo['warning'] .= "\n" . 'Unhandled block type "' . $BlockType . '" at offset ' . $BlockOffset;
                fseek($fd, $BlockSize, SEEK_CUR);
                break;
        }
        if (!empty($ThisBlock)) {
            $ThisBlock['block_offset'] = $BlockOffset;
            $ThisBlock['block_size'] = $BlockSize;
            $ThisBlock['block_type_id'] = $BlockType;
            $ThisFileInfo['voc']['blocks'][] = $ThisBlock;
        }
    } while (!feof($fd) && $BlockType != 0);
    // Terminator block doesn't have size field, so seek back 3 spaces
    fseek($fd, -3, SEEK_CUR);
    if (!empty($ThisFileInfo['voc']['compressed_bits_per_sample'])) {
        $ThisFileInfo['playtime_seconds'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8 / ($ThisFileInfo['voc']['compressed_bits_per_sample'] * $ThisFileInfo['audio']['channels'] * $ThisFileInfo['audio']['sample_rate']);
        $ThisFileInfo['audio']['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8 / $ThisFileInfo['playtime_seconds'];
    }
    return true;
}
 function DateMac2Unix($macdate)
 {
     // Macintosh timestamp: seconds since 00:00h January 1, 1904
     // UNIX timestamp:      seconds since 00:00h January 1, 1970
     return CastAsInt($macdate - 2082844800);
 }
function Bin2Dec($binstring)
{
    $decvalue = 0;
    for ($i = 0; $i < strlen($binstring); $i++) {
        $decvalue += (int) substr($binstring, strlen($binstring) - $i - 1, 1) * pow(2, $i);
    }
    return CastAsInt($decvalue);
}
Example #4
0
function getMPCHeaderFilepointer(&$fd, &$ThisFileInfo)
{
    // http://www.uni-jena.de/~pfk/mpp/sv8/header.html
    $ThisFileInfo['fileformat'] = 'mpc';
    $ThisFileInfo['audio']['dataformat'] = 'mpc';
    $ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
    $ThisFileInfo['audio']['channels'] = 2;
    // the format appears to be hardcoded for stereo only
    fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
    $ThisFileInfo['mpc']['header']['size'] = 30;
    $MPCheaderData = fread($fd, $ThisFileInfo['mpc']['header']['size']);
    $offset = 0;
    $ThisFileInfo['mpc']['header']['raw']['preamble'] = substr($MPCheaderData, $offset, 3);
    // should be 'MP+'
    $offset += 3;
    $StreamVersionByte = LittleEndian2Int(substr($MPCheaderData, $offset, 1));
    $offset += 1;
    $ThisFileInfo['mpc']['header']['stream_major_version'] = $StreamVersionByte & 0xf;
    $ThisFileInfo['mpc']['header']['stream_minor_version'] = ($StreamVersionByte & 0xf0) >> 4;
    $ThisFileInfo['mpc']['header']['frame_count'] = LittleEndian2Int(substr($MPCheaderData, $offset, 4));
    $offset += 4;
    switch ($ThisFileInfo['mpc']['header']['stream_major_version']) {
        case 7:
            //$ThisFileInfo['fileformat'] = 'SV7';
            break;
        default:
            $ThisFileInfo['error'] .= "\n" . 'Only MPEGplus/Musepack SV7 supported';
            return false;
    }
    $FlagsByte1 = LittleEndian2Int(substr($MPCheaderData, $offset, 4));
    $offset += 4;
    $ThisFileInfo['mpc']['header']['intensity_stereo'] = (bool) (($FlagsByte1 & 2147483648.0) >> 31);
    $ThisFileInfo['mpc']['header']['mid_side_stereo'] = (bool) (($FlagsByte1 & 0x40000000) >> 30);
    $ThisFileInfo['mpc']['header']['max_subband'] = ($FlagsByte1 & 0x3f000000) >> 24;
    $ThisFileInfo['mpc']['header']['raw']['profile'] = ($FlagsByte1 & 0xf00000) >> 20;
    $ThisFileInfo['mpc']['header']['begin_loud'] = (bool) (($FlagsByte1 & 0x80000) >> 19);
    $ThisFileInfo['mpc']['header']['end_loud'] = (bool) (($FlagsByte1 & 0x40000) >> 18);
    $ThisFileInfo['mpc']['header']['raw']['sample_rate'] = ($FlagsByte1 & 0x30000) >> 16;
    $ThisFileInfo['mpc']['header']['max_level'] = $FlagsByte1 & 0xffff;
    $ThisFileInfo['mpc']['header']['raw']['title_peak'] = LittleEndian2Int(substr($MPCheaderData, $offset, 2));
    $offset += 2;
    $ThisFileInfo['mpc']['header']['raw']['title_gain'] = LittleEndian2Int(substr($MPCheaderData, $offset, 2), true);
    $offset += 2;
    $ThisFileInfo['mpc']['header']['raw']['album_peak'] = LittleEndian2Int(substr($MPCheaderData, $offset, 2));
    $offset += 2;
    $ThisFileInfo['mpc']['header']['raw']['album_gain'] = LittleEndian2Int(substr($MPCheaderData, $offset, 2), true);
    $offset += 2;
    $FlagsByte2 = LittleEndian2Int(substr($MPCheaderData, $offset, 4));
    $offset += 4;
    $ThisFileInfo['mpc']['header']['true_gapless'] = (bool) (($FlagsByte2 & 2147483648.0) >> 31);
    $ThisFileInfo['mpc']['header']['last_frame_length'] = ($FlagsByte2 & 0x7ff00000) >> 20;
    $offset += 3;
    // unused?
    $ThisFileInfo['mpc']['header']['raw']['encoder_version'] = LittleEndian2Int(substr($MPCheaderData, $offset, 1));
    $offset += 1;
    $ThisFileInfo['mpc']['header']['profile'] = MPCprofileNameLookup($ThisFileInfo['mpc']['header']['raw']['profile']);
    $ThisFileInfo['mpc']['header']['sample_rate'] = MPCfrequencyLookup($ThisFileInfo['mpc']['header']['raw']['sample_rate']);
    if ($ThisFileInfo['mpc']['header']['sample_rate'] == 0) {
        $ThisFileInfo['error'] .= "\n" . 'Corrupt MPC file: frequency == zero';
        return false;
    }
    $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['mpc']['header']['sample_rate'];
    $ThisFileInfo['mpc']['header']['samples'] = (($ThisFileInfo['mpc']['header']['frame_count'] - 1) * 1152 + $ThisFileInfo['mpc']['header']['last_frame_length']) * $ThisFileInfo['audio']['channels'];
    $ThisFileInfo['playtime_seconds'] = $ThisFileInfo['mpc']['header']['samples'] / $ThisFileInfo['audio']['channels'] / $ThisFileInfo['audio']['sample_rate'];
    if ($ThisFileInfo['playtime_seconds'] == 0) {
        $ThisFileInfo['error'] .= "\n" . 'Corrupt MPC file: playtime_seconds == zero';
        return false;
    }
    // add size of file header to avdataoffset - calc bitrate correctly + MD5 data
    $ThisFileInfo['avdataoffset'] += $ThisFileInfo['mpc']['header']['size'];
    $ThisFileInfo['audio']['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8 / $ThisFileInfo['playtime_seconds'];
    $ThisFileInfo['mpc']['header']['title_peak'] = $ThisFileInfo['mpc']['header']['raw']['title_peak'];
    $ThisFileInfo['mpc']['header']['title_peak_db'] = MPCpeakDBLookup($ThisFileInfo['mpc']['header']['title_peak']);
    $ThisFileInfo['mpc']['header']['title_gain_db'] = $ThisFileInfo['mpc']['header']['raw']['title_gain'] / 100;
    $ThisFileInfo['mpc']['header']['album_peak'] = $ThisFileInfo['mpc']['header']['raw']['album_peak'];
    $ThisFileInfo['mpc']['header']['album_peak_db'] = MPCpeakDBLookup($ThisFileInfo['mpc']['header']['album_peak']);
    $ThisFileInfo['mpc']['header']['album_gain_db'] = $ThisFileInfo['mpc']['header']['raw']['album_gain'] / 100;
    $ThisFileInfo['mpc']['header']['encoder_version'] = MPCencoderVersionLookup($ThisFileInfo['mpc']['header']['raw']['encoder_version']);
    if ($ThisFileInfo['mpc']['header']['title_peak_db']) {
        $ThisFileInfo['replay_gain']['radio']['peak'] = $ThisFileInfo['mpc']['header']['title_peak'];
        $ThisFileInfo['replay_gain']['radio']['adjustment'] = $ThisFileInfo['mpc']['header']['title_gain_db'];
    } else {
        $ThisFileInfo['replay_gain']['radio']['peak'] = CastAsInt(round($ThisFileInfo['mpc']['header']['max_level'] * 1.18));
        // why? I don't know - see mppdec.c
        $ThisFileInfo['replay_gain']['radio']['adjustment'] = 0;
    }
    if ($ThisFileInfo['mpc']['header']['album_peak_db']) {
        $ThisFileInfo['replay_gain']['audiophile']['peak'] = $ThisFileInfo['mpc']['header']['album_peak'];
        $ThisFileInfo['replay_gain']['audiophile']['adjustment'] = $ThisFileInfo['mpc']['header']['album_gain_db'];
    }
    $ThisFileInfo['audio']['encoder'] = $ThisFileInfo['mpc']['header']['encoder_version'] . ', SV' . $ThisFileInfo['mpc']['header']['stream_major_version'] . '.' . $ThisFileInfo['mpc']['header']['stream_minor_version'];
    return true;
}
Example #5
0
function getRIFFHeaderFilepointer(&$fd, &$ThisFileInfo)
{
    $Original['avdataoffset'] = $ThisFileInfo['avdataoffset'];
    $Original['avdataend'] = $ThisFileInfo['avdataend'];
    fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
    $RIFFheader = fread($fd, 12);
    switch (substr($RIFFheader, 0, 4)) {
        case 'FORM':
            $ThisFileInfo['fileformat'] = 'aiff';
            $RIFFheaderSize = EitherEndian2Int($ThisFileInfo, substr($RIFFheader, 4, 4));
            $ThisFileInfo['RIFF'][substr($RIFFheader, 8, 4)] = ParseRIFF($fd, $ThisFileInfo['avdataoffset'] + 12, $ThisFileInfo['avdataoffset'] + $RIFFheaderSize, $ThisFileInfo);
            $ThisFileInfo['RIFF']['header_size'] = $RIFFheaderSize;
            break;
        case 'RIFF':
        case 'SDSS':
            // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com)
        // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com)
        case 'RMP3':
            // RMP3 is identical to RIFF, just renamed. Used by [unknown program] when creating RIFF-MP3s
            $RIFFtype = substr($RIFFheader, 8, 4);
            if ($RIFFtype == 'RMP3') {
                $RIFFtype == 'WAVE';
            }
            $ThisFileInfo['fileformat'] = 'riff';
            $RIFFheaderSize = EitherEndian2Int($ThisFileInfo, substr($RIFFheader, 4, 4));
            $ThisFileInfo['RIFF']["{$RIFFtype}"] = ParseRIFF($fd, $ThisFileInfo['avdataoffset'] + 12, $ThisFileInfo['avdataoffset'] + $RIFFheaderSize, $ThisFileInfo);
            $ThisFileInfo['RIFF']['header_size'] = $RIFFheaderSize;
            break;
        default:
            $ThisFileInfo['error'] .= "\n" . 'Cannot parse RIFF (this is maybe not a RIFF / WAV / AVI file?)';
            unset($ThisFileInfo['fileformat']);
            return false;
            break;
    }
    $streamindex = 0;
    $arraykeys = array_keys($ThisFileInfo['RIFF']);
    switch ($arraykeys[0]) {
        case 'WAVE':
        case 'RMP3':
            // RMP3 is identical to WAVE, just renamed. Used by [unknown program] when creating RIFF-MP3s
            if (empty($ThisFileInfo['audio']['bitrate_mode'])) {
                $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
            }
            if (empty($ThisFileInfo['audio']['dataformat'])) {
                $ThisFileInfo['audio']['dataformat'] = 'wav';
            }
            if (isset($ThisFileInfo['RIFF'][$arraykeys[0]]['data'][0]['offset'])) {
                $ThisFileInfo['avdataoffset'] = $ThisFileInfo['RIFF'][$arraykeys[0]]['data'][0]['offset'] + 8;
                $ThisFileInfo['avdataend'] = $ThisFileInfo['avdataoffset'] + $ThisFileInfo['RIFF'][$arraykeys[0]]['data'][0]['size'];
            }
            if (isset($ThisFileInfo['RIFF']['WAVE']['fmt '][0]['data'])) {
                $ThisFileInfo['RIFF']['audio'][$streamindex] = RIFFparseWAVEFORMATex($ThisFileInfo['RIFF']['WAVE']['fmt '][0]['data']);
                if ($ThisFileInfo['RIFF']['audio'][$streamindex] == 0) {
                    $ThisFileInfo['error'] .= 'Corrupt RIFF file: bitrate_audio == zero';
                    return false;
                }
                $ThisFileInfo['RIFF']['raw']['fmt '] = $ThisFileInfo['RIFF']['audio'][$streamindex]['raw'];
                unset($ThisFileInfo['RIFF']['audio'][$streamindex]['raw']);
                $ThisFileInfo['audio'] = array_merge_noclobber($ThisFileInfo['audio'], $ThisFileInfo['RIFF']['audio'][$streamindex]);
                if (substr($ThisFileInfo['audio']['codec'], 0, strlen('unknown: 0x')) == 'unknown: 0x') {
                    $ThisFileInfo['warning'] .= "\n" . 'Audio codec = ' . $ThisFileInfo['audio']['codec'];
                }
                $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['RIFF']['audio'][$streamindex]['bitrate'];
                if ($ThisFileInfo['audio']['bits_per_sample'] == 0) {
                    unset($ThisFileInfo['audio']['bits_per_sample']);
                }
                $ThisFileInfo['playtime_seconds'] = (double) (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8 / $ThisFileInfo['audio']['bitrate']);
                if (isset($ThisFileInfo['RIFF']['WAVE']['data'][0]['offset']) && isset($ThisFileInfo['RIFF']['raw']['fmt ']['wFormatTag'])) {
                    $ThisFileInfo['audio']['lossless'] = false;
                    switch ($ThisFileInfo['RIFF']['raw']['fmt ']['wFormatTag']) {
                        case 1:
                            // PCM
                            $ThisFileInfo['audio']['lossless'] = true;
                            break;
                        default:
                            // do nothing
                            break;
                    }
                }
            }
            if (isset($ThisFileInfo['RIFF']['WAVE']['rgad'][0]['data'])) {
                require_once GETID3_INCLUDEPATH . 'getid3.rgad.php';
                $rgadData = $ThisFileInfo['RIFF']['WAVE']['rgad'][0]['data'];
                $ThisFileInfo['RIFF']['raw']['rgad']['fPeakAmplitude'] = LittleEndian2Float(substr($rgadData, 0, 4));
                $ThisFileInfo['RIFF']['raw']['rgad']['nRadioRgAdjust'] = EitherEndian2Int($ThisFileInfo, substr($rgadData, 4, 2));
                $ThisFileInfo['RIFF']['raw']['rgad']['nAudiophileRgAdjust'] = EitherEndian2Int($ThisFileInfo, substr($rgadData, 6, 2));
                $nRadioRgAdjustBitstring = str_pad(Dec2Bin($ThisFileInfo['RIFF']['raw']['rgad']['nRadioRgAdjust']), 16, '0', STR_PAD_LEFT);
                $nAudiophileRgAdjustBitstring = str_pad(Dec2Bin($ThisFileInfo['RIFF']['raw']['rgad']['nAudiophileRgAdjust']), 16, '0', STR_PAD_LEFT);
                $ThisFileInfo['RIFF']['raw']['rgad']['radio']['name'] = Bin2Dec(substr($nRadioRgAdjustBitstring, 0, 3));
                $ThisFileInfo['RIFF']['raw']['rgad']['radio']['originator'] = Bin2Dec(substr($nRadioRgAdjustBitstring, 3, 3));
                $ThisFileInfo['RIFF']['raw']['rgad']['radio']['signbit'] = Bin2Dec(substr($nRadioRgAdjustBitstring, 6, 1));
                $ThisFileInfo['RIFF']['raw']['rgad']['radio']['adjustment'] = Bin2Dec(substr($nRadioRgAdjustBitstring, 7, 9));
                $ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['name'] = Bin2Dec(substr($nAudiophileRgAdjustBitstring, 0, 3));
                $ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['originator'] = Bin2Dec(substr($nAudiophileRgAdjustBitstring, 3, 3));
                $ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['signbit'] = Bin2Dec(substr($nAudiophileRgAdjustBitstring, 6, 1));
                $ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['adjustment'] = Bin2Dec(substr($nAudiophileRgAdjustBitstring, 7, 9));
                $ThisFileInfo['RIFF']['rgad']['peakamplitude'] = $ThisFileInfo['RIFF']['raw']['rgad']['fPeakAmplitude'];
                if ($ThisFileInfo['RIFF']['raw']['rgad']['radio']['name'] != 0 && $ThisFileInfo['RIFF']['raw']['rgad']['radio']['originator'] != 0) {
                    $ThisFileInfo['RIFF']['rgad']['radio']['name'] = RGADnameLookup($ThisFileInfo['RIFF']['raw']['rgad']['radio']['name']);
                    $ThisFileInfo['RIFF']['rgad']['radio']['originator'] = RGADoriginatorLookup($ThisFileInfo['RIFF']['raw']['rgad']['radio']['originator']);
                    $ThisFileInfo['RIFF']['rgad']['radio']['adjustment'] = RGADadjustmentLookup($ThisFileInfo['RIFF']['raw']['rgad']['radio']['adjustment'], $ThisFileInfo['RIFF']['raw']['rgad']['radio']['signbit']);
                }
                if ($ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['name'] != 0 && $ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['originator'] != 0) {
                    $ThisFileInfo['RIFF']['rgad']['audiophile']['name'] = RGADnameLookup($ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['name']);
                    $ThisFileInfo['RIFF']['rgad']['audiophile']['originator'] = RGADoriginatorLookup($ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['originator']);
                    $ThisFileInfo['RIFF']['rgad']['audiophile']['adjustment'] = RGADadjustmentLookup($ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['adjustment'], $ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['signbit']);
                }
            }
            if (isset($ThisFileInfo['RIFF']['WAVE']['fact'][0]['data'])) {
                $ThisFileInfo['RIFF']['raw']['fact']['NumberOfSamples'] = EitherEndian2Int($ThisFileInfo, substr($ThisFileInfo['RIFF']['WAVE']['fact'][0]['data'], 0, 4));
                if (isset($ThisFileInfo['RIFF']['raw']['fmt ']['nSamplesPerSec']) && $ThisFileInfo['RIFF']['raw']['fmt ']['nSamplesPerSec'] > 0) {
                    $ThisFileInfo['playtime_seconds'] = (double) $ThisFileInfo['RIFF']['raw']['fact']['NumberOfSamples'] / $ThisFileInfo['RIFF']['raw']['fmt ']['nSamplesPerSec'];
                }
                if (isset($ThisFileInfo['RIFF']['raw']['fmt ']['nAvgBytesPerSec']) && $ThisFileInfo['RIFF']['raw']['fmt ']['nAvgBytesPerSec']) {
                    $ThisFileInfo['audio']['bitrate'] = CastAsInt($ThisFileInfo['RIFF']['raw']['fmt ']['nAvgBytesPerSec'] * 8);
                }
            }
            if (isset($ThisFileInfo['RIFF']['WAVE']['bext'][0]['data'])) {
                $ThisFileInfo['RIFF']['WAVE']['bext'][0]['title'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['data'], 0, 256));
                $ThisFileInfo['RIFF']['WAVE']['bext'][0]['author'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['data'], 256, 32));
                $ThisFileInfo['RIFF']['WAVE']['bext'][0]['reference'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['data'], 288, 32));
                $ThisFileInfo['RIFF']['WAVE']['bext'][0]['origin_date'] = substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['data'], 320, 10);
                $ThisFileInfo['RIFF']['WAVE']['bext'][0]['origin_time'] = substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['data'], 330, 8);
                $ThisFileInfo['RIFF']['WAVE']['bext'][0]['time_reference'] = LittleEndian2Int(substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['data'], 338, 8));
                $ThisFileInfo['RIFF']['WAVE']['bext'][0]['bwf_version'] = LittleEndian2Int(substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['data'], 346, 1));
                $ThisFileInfo['RIFF']['WAVE']['bext'][0]['reserved'] = LittleEndian2Int(substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['data'], 347, 254));
                $ThisFileInfo['RIFF']['WAVE']['bext'][0]['coding_history'] = explode("\r\n", trim(substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['data'], 601)));
                $ThisFileInfo['RIFF']['WAVE']['bext'][0]['origin_date_unix'] = mktime(substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['origin_time'], 0, 2), substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['origin_time'], 3, 2), substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['origin_time'], 6, 2), substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['origin_date'], 5, 2), substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['origin_date'], 8, 2), substr($ThisFileInfo['RIFF']['WAVE']['bext'][0]['origin_date'], 0, 4));
                $ThisFileInfo['RIFF']['comments']['author'][] = $ThisFileInfo['RIFF']['WAVE']['bext'][0]['author'];
                $ThisFileInfo['RIFF']['comments']['title'][] = $ThisFileInfo['RIFF']['WAVE']['bext'][0]['title'];
            }
            if (isset($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['data'])) {
                $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['raw']['sound_information'] = LittleEndian2Int(substr($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['data'], 0, 2));
                $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['flags']['homogenous'] = (bool) ($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['raw']['sound_information'] & 0x1);
                if ($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['flags']['homogenous']) {
                    $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['flags']['padding'] = InverseBoolean($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['raw']['sound_information'] & 0x2);
                    $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['flags']['22_or_44'] = (bool) ($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['raw']['sound_information'] & 0x4);
                    $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['flags']['free_format'] = (bool) ($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['raw']['sound_information'] & 0x8);
                    $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['nominal_frame_size'] = LittleEndian2Int(substr($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['data'], 2, 2));
                }
                $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['anciliary_data_length'] = LittleEndian2Int(substr($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['data'], 6, 2));
                $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['raw']['anciliary_data_def'] = LittleEndian2Int(substr($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['data'], 8, 2));
                $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['flags']['anciliary_data_left'] = (bool) ($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['raw']['anciliary_data_def'] & 0x1);
                $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['flags']['anciliary_data_free'] = (bool) ($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['raw']['anciliary_data_def'] & 0x2);
                $ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['flags']['anciliary_data_right'] = (bool) ($ThisFileInfo['RIFF']['WAVE']['MEXT'][0]['raw']['anciliary_data_def'] & 0x4);
            }
            if (isset($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'])) {
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['version'] = substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 0, 4);
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['title'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 4, 64));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['artist'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 68, 64));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['cut_id'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 132, 64));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['client_id'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 196, 64));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['category'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 260, 64));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['classification'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 324, 64));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['out_cue'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 388, 64));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['start_date'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 452, 10));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['start_time'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 462, 8));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['end_date'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 470, 10));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['end_time'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 480, 8));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['producer_app_id'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 488, 64));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['producer_app_version'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 552, 64));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['user_defined_text'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 616, 64));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['zero_db_reference'] = LittleEndian2Int(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 680, 4), true);
                for ($i = 0; $i < 8; $i++) {
                    $ThisFileInfo['RIFF']['WAVE']['cart'][0]['post_time'][$i]['usage_fourcc'] = substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 684 + $i * 8, 4);
                    $ThisFileInfo['RIFF']['WAVE']['cart'][0]['post_time'][$i]['timer_value'] = LittleEndian2Int(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 684 + $i * 8 + 4, 4));
                }
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['url'] = trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 748, 1024));
                $ThisFileInfo['RIFF']['WAVE']['cart'][0]['tag_text'] = explode("\r\n", trim(substr($ThisFileInfo['RIFF']['WAVE']['cart'][0]['data'], 1772)));
                $ThisFileInfo['RIFF']['comments']['artist'][] = $ThisFileInfo['RIFF']['WAVE']['cart'][0]['artist'];
                $ThisFileInfo['RIFF']['comments']['title'][] = $ThisFileInfo['RIFF']['WAVE']['cart'][0]['title'];
            }
            if (!isset($ThisFileInfo['audio']['bitrate']) && isset($ThisFileInfo['RIFF']['audio'][$streamindex]['bitrate'])) {
                $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['RIFF']['audio'][$streamindex]['bitrate'];
                $ThisFileInfo['playtime_seconds'] = (double) (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8 / $ThisFileInfo['audio']['bitrate']);
            }
            if (!empty($ThisFileInfo['wavpack'])) {
                $ThisFileInfo['audio']['dataformat'] = 'wavpack';
                $ThisFileInfo['audio']['bitrate_mode'] = 'vbr';
                $ThisFileInfo['audio']['encoder'] = 'WavPack v' . $ThisFileInfo['wavpack']['version'];
                // Reset to the way it was - RIFF parsing will have messed this up
                $ThisFileInfo['avdataend'] = $Original['avdataend'];
                $ThisFileInfo['audio']['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8 / $ThisFileInfo['playtime_seconds'];
                fseek($fd, $ThisFileInfo['avdataoffset'] - 44, SEEK_SET);
                $RIFFdata = fread($fd, 44);
                $OrignalRIFFheaderSize = LittleEndian2Int(substr($RIFFdata, 4, 4)) + 8;
                $OrignalRIFFdataSize = LittleEndian2Int(substr($RIFFdata, 40, 4)) + 44;
                if ($OrignalRIFFheaderSize > $OrignalRIFFdataSize) {
                    $ThisFileInfo['avdataend'] -= $OrignalRIFFheaderSize - $OrignalRIFFdataSize;
                    fseek($fd, $ThisFileInfo['avdataend'], SEEK_SET);
                    $RIFFdata .= fread($fd, $OrignalRIFFheaderSize - $OrignalRIFFdataSize);
                }
                // move the data chunk after all other chunks (if any)
                // so that the RIFF parser doesn't see EOF when trying
                // to skip over the data chunk
                $RIFFdata = substr($RIFFdata, 0, 36) . substr($RIFFdata, 44) . substr($RIFFdata, 36, 8);
                ParseRIFFdata($RIFFdata, $ThisFileInfo);
            }
            break;
        case 'AVI ':
            $ThisFileInfo['video']['bitrate_mode'] = 'cbr';
            $ThisFileInfo['video']['dataformat'] = 'avi';
            $ThisFileInfo['mime_type'] = 'video/avi';
            if (isset($ThisFileInfo['RIFF'][$arraykeys[0]]['movi']['offset'])) {
                $ThisFileInfo['avdataoffset'] = $ThisFileInfo['RIFF'][$arraykeys[0]]['movi']['offset'] + 8;
                $ThisFileInfo['avdataend'] = $ThisFileInfo['avdataoffset'] + $ThisFileInfo['RIFF'][$arraykeys[0]]['movi']['size'];
            }
            if (isset($ThisFileInfo['RIFF']['AVI ']['hdrl']['avih'][$streamindex]['data'])) {
                $avihData = $ThisFileInfo['RIFF']['AVI ']['hdrl']['avih'][$streamindex]['data'];
                $ThisFileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 0, 4));
                // frame display rate (or 0L)
                if ($ThisFileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'] == 0) {
                    $ThisFileInfo['error'] .= 'Corrupt RIFF file: avih.dwMicroSecPerFrame == zero';
                    return false;
                }
                $ThisFileInfo['RIFF']['raw']['avih']['dwMaxBytesPerSec'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 4, 4));
                // max. transfer rate
                $ThisFileInfo['RIFF']['raw']['avih']['dwPaddingGranularity'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 8, 4));
                // pad to multiples of this size; normally 2K.
                $ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 12, 4));
                // the ever-present flags
                $ThisFileInfo['RIFF']['raw']['avih']['dwTotalFrames'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 16, 4));
                // # frames in file
                $ThisFileInfo['RIFF']['raw']['avih']['dwInitialFrames'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 20, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwStreams'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 24, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwSuggestedBufferSize'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 28, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwWidth'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 32, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwHeight'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 36, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwScale'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 40, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwRate'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 44, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwStart'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 48, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwLength'] = EitherEndian2Int($ThisFileInfo, substr($avihData, 52, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['flags']['hasindex'] = (bool) ($ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x10);
                $ThisFileInfo['RIFF']['raw']['avih']['flags']['mustuseindex'] = (bool) ($ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x20);
                $ThisFileInfo['RIFF']['raw']['avih']['flags']['interleaved'] = (bool) ($ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x100);
                $ThisFileInfo['RIFF']['raw']['avih']['flags']['trustcktype'] = (bool) ($ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x800);
                $ThisFileInfo['RIFF']['raw']['avih']['flags']['capturedfile'] = (bool) ($ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x10000);
                $ThisFileInfo['RIFF']['raw']['avih']['flags']['copyrighted'] = (bool) ($ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x20010);
                if ($ThisFileInfo['RIFF']['raw']['avih']['dwWidth'] > 0) {
                    $ThisFileInfo['RIFF']['video'][$streamindex]['frame_width'] = $ThisFileInfo['RIFF']['raw']['avih']['dwWidth'];
                    $ThisFileInfo['video']['resolution_x'] = $ThisFileInfo['RIFF']['video'][$streamindex]['frame_width'];
                }
                if ($ThisFileInfo['RIFF']['raw']['avih']['dwHeight'] > 0) {
                    $ThisFileInfo['RIFF']['video'][$streamindex]['frame_height'] = $ThisFileInfo['RIFF']['raw']['avih']['dwHeight'];
                    $ThisFileInfo['video']['resolution_y'] = $ThisFileInfo['RIFF']['video'][$streamindex]['frame_height'];
                }
                $ThisFileInfo['RIFF']['video'][$streamindex]['frame_rate'] = round(1000000 / $ThisFileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'], 3);
                $ThisFileInfo['video']['frame_rate'] = $ThisFileInfo['RIFF']['video'][$streamindex]['frame_rate'];
            }
            if (isset($ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strh'][0]['data'])) {
                if (is_array($ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strh'])) {
                    for ($i = 0; $i < count($ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strh']); $i++) {
                        if (isset($ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strh'][$i]['data'])) {
                            $strhData = $ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strh'][$i]['data'];
                            $strhfccType = substr($strhData, 0, 4);
                            if (isset($ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strf'][$i]['data'])) {
                                $strfData = $ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strf'][$i]['data'];
                                switch ($strhfccType) {
                                    case 'auds':
                                        $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
                                        $ThisFileInfo['audio']['dataformat'] = 'wav';
                                        if (isset($ThisFileInfo['RIFF']['audio']) && is_array($ThisFileInfo['RIFF']['audio'])) {
                                            $streamindex = count($ThisFileInfo['RIFF']['audio']);
                                        }
                                        $ThisFileInfo['RIFF']['audio'][$streamindex] = RIFFparseWAVEFORMATex($strfData);
                                        $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex] = $ThisFileInfo['RIFF']['audio'][$streamindex]['raw'];
                                        unset($ThisFileInfo['RIFF']['audio'][$streamindex]['raw']);
                                        $ThisFileInfo['audio'] = array_merge_noclobber($ThisFileInfo['audio'], $ThisFileInfo['RIFF']['audio'][$streamindex]);
                                        $ThisFileInfo['audio']['lossless'] = false;
                                        switch ($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['wFormatTag']) {
                                            case 1:
                                                // PCM
                                                $ThisFileInfo['audio']['lossless'] = true;
                                                break;
                                            case 85:
                                                // MPEG Layer 3
                                                $ThisFileInfo['audio']['dataformat'] = 'mp3';
                                                break;
                                            case 8192:
                                                // AC-3
                                                $ThisFileInfo['audio']['dataformat'] = 'ac3';
                                                break;
                                            default:
                                                $ThisFileInfo['audio']['dataformat'] = 'wav';
                                                break;
                                        }
                                        break;
                                    case 'iavs':
                                    case 'vids':
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['fccType'] = substr($strhData, 0, 4);
                                        // same as $strhfccType;
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['fccHandler'] = substr($strhData, 4, 4);
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwFlags'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 8, 4));
                                        // Contains AVITF_* flags
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['wPriority'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 12, 2));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['wLanguage'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 14, 2));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwInitialFrames'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 16, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwScale'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 20, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwRate'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 24, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwStart'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 28, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwLength'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 32, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwSuggestedBufferSize'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 36, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwQuality'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 40, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwSampleSize'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 44, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['rcFrame'] = EitherEndian2Int($ThisFileInfo, substr($strhData, 48, 4));
                                        $ThisFileInfo['RIFF']['video'][$streamindex]['codec'] = RIFFfourccLookup($ThisFileInfo['RIFF']['raw']['strh'][$i]['fccHandler']);
                                        if (!$ThisFileInfo['RIFF']['video'][$streamindex]['codec'] && isset($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc']) && RIFFfourccLookup($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc'])) {
                                            $ThisFileInfo['RIFF']['video'][$streamindex]['codec'] = RIFFfourccLookup($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc']);
                                        }
                                        $ThisFileInfo['video']['codec'] = $ThisFileInfo['RIFF']['video'][$streamindex]['codec'];
                                        switch ($ThisFileInfo['RIFF']['raw']['strh'][$i]['fccHandler']) {
                                            case 'HFYU':
                                                // Huffman Lossless Codec
                                            // Huffman Lossless Codec
                                            case 'IRAW':
                                                // Intel YUV Uncompressed
                                            // Intel YUV Uncompressed
                                            case 'YUY2':
                                                // Uncompressed YUV 4:2:2
                                                $ThisFileInfo['video']['lossless'] = true;
                                                break;
                                            default:
                                                $ThisFileInfo['video']['lossless'] = false;
                                                break;
                                        }
                                        switch ($strhfccType) {
                                            case 'vids':
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biSize'] = EitherEndian2Int($ThisFileInfo, substr($strfData, 0, 4));
                                                // number of bytes required by the BITMAPINFOHEADER structure
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biWidth'] = EitherEndian2Int($ThisFileInfo, substr($strfData, 4, 4));
                                                // width of the bitmap in pixels
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biHeight'] = EitherEndian2Int($ThisFileInfo, substr($strfData, 8, 4));
                                                // height of the bitmap in pixels. If biHeight is positive, the bitmap is a 'bottom-up' DIB and its origin is the lower left corner. If biHeight is negative, the bitmap is a 'top-down' DIB and its origin is the upper left corner
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biPlanes'] = EitherEndian2Int($ThisFileInfo, substr($strfData, 12, 2));
                                                // number of color planes on the target device. In most cases this value must be set to 1
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biBitCount'] = EitherEndian2Int($ThisFileInfo, substr($strfData, 14, 2));
                                                // Specifies the number of bits per pixels
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc'] = substr($strfData, 16, 4);
                                                //
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biSizeImage'] = EitherEndian2Int($ThisFileInfo, substr($strfData, 20, 4));
                                                // size of the bitmap data section of the image (the actual pixel data, excluding BITMAPINFOHEADER and RGBQUAD structures)
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biXPelsPerMeter'] = EitherEndian2Int($ThisFileInfo, substr($strfData, 24, 4));
                                                // horizontal resolution, in pixels per metre, of the target device
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biYPelsPerMeter'] = EitherEndian2Int($ThisFileInfo, substr($strfData, 28, 4));
                                                // vertical resolution, in pixels per metre, of the target device
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biClrUsed'] = EitherEndian2Int($ThisFileInfo, substr($strfData, 32, 4));
                                                // actual number of color indices in the color table used by the bitmap. If this value is zero, the bitmap uses the maximum number of colors corresponding to the value of the biBitCount member for the compression mode specified by biCompression
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biClrImportant'] = EitherEndian2Int($ThisFileInfo, substr($strfData, 36, 4));
                                                // number of color indices that are considered important for displaying the bitmap. If this value is zero, all colors are important
                                                $ThisFileInfo['video']['bits_per_sample'] = $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biBitCount'];
                                                if ($ThisFileInfo['RIFF']['video'][$streamindex]['codec'] == 'DV') {
                                                    $ThisFileInfo['RIFF']['video'][$streamindex]['dv_type'] = 2;
                                                }
                                                break;
                                            case 'iavs':
                                                $ThisFileInfo['RIFF']['video'][$streamindex]['dv_type'] = 1;
                                                break;
                                        }
                                        break;
                                    default:
                                        $ThisFileInfo['warning'] .= "\n" . 'Unhandled fccType for stream (' . $i . '): "' . $strhfccType . '"';
                                        break;
                                }
                            }
                        }
                        if (isset($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc']) && RIFFfourccLookup($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc'])) {
                            $ThisFileInfo['RIFF']['video'][$streamindex]['codec'] = RIFFfourccLookup($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc']);
                            $ThisFileInfo['video']['codec'] = $ThisFileInfo['RIFF']['video'][$streamindex]['codec'];
                            switch ($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc']) {
                                case 'HFYU':
                                    // Huffman Lossless Codec
                                // Huffman Lossless Codec
                                case 'IRAW':
                                    // Intel YUV Uncompressed
                                // Intel YUV Uncompressed
                                case 'YUY2':
                                    // Uncompressed YUV 4:2:2
                                    $ThisFileInfo['video']['lossless'] = true;
                                    $ThisFileInfo['video']['bits_per_sample'] = 24;
                                    break;
                                default:
                                    $ThisFileInfo['video']['lossless'] = false;
                                    $ThisFileInfo['video']['bits_per_sample'] = 24;
                                    break;
                            }
                        }
                    }
                }
            }
            break;
        case 'CDDA':
            $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
            $ThisFileInfo['audio']['dataformat'] = 'cda';
            $ThisFileInfo['audio']['lossless'] = true;
            unset($ThisFileInfo['mime_type']);
            $ThisFileInfo['avdataoffset'] = 44;
            if (isset($ThisFileInfo['RIFF']['CDDA']['fmt '][0]['data'])) {
                $fmtData = $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['data'];
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['unknown1'] = EitherEndian2Int($ThisFileInfo, substr($fmtData, 0, 2));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['track_num'] = EitherEndian2Int($ThisFileInfo, substr($fmtData, 2, 2));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['disc_id'] = EitherEndian2Int($ThisFileInfo, substr($fmtData, 4, 4));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['start_offset_frame'] = EitherEndian2Int($ThisFileInfo, substr($fmtData, 8, 4));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['playtime_frames'] = EitherEndian2Int($ThisFileInfo, substr($fmtData, 12, 4));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['unknown6'] = EitherEndian2Int($ThisFileInfo, substr($fmtData, 16, 4));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['unknown7'] = EitherEndian2Int($ThisFileInfo, substr($fmtData, 20, 4));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['start_offset_seconds'] = (double) $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['start_offset_frame'] / 75;
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['playtime_seconds'] = (double) $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['playtime_frames'] / 75;
                $ThisFileInfo['comments']['track'] = $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['track_num'];
                $ThisFileInfo['playtime_seconds'] = $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['playtime_seconds'];
                // hardcoded data for CD-audio
                $ThisFileInfo['audio']['sample_rate'] = 44100;
                $ThisFileInfo['audio']['channels'] = 2;
                $ThisFileInfo['audio']['bits_per_sample'] = 16;
                $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['audio']['sample_rate'] * $ThisFileInfo['audio']['channels'] * $ThisFileInfo['audio']['bits_per_sample'];
                $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
            }
            break;
        case 'AIFF':
        case 'AIFC':
            $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
            $ThisFileInfo['audio']['dataformat'] = 'aiff';
            $ThisFileInfo['audio']['lossless'] = true;
            $ThisFileInfo['mime_type'] = 'audio/x-aiff';
            if (isset($ThisFileInfo['RIFF'][$arraykeys[0]]['SSND'][0]['offset'])) {
                $ThisFileInfo['avdataoffset'] = $ThisFileInfo['RIFF'][$arraykeys[0]]['SSND'][0]['offset'] + 8;
                $ThisFileInfo['avdataend'] = $ThisFileInfo['avdataoffset'] + $ThisFileInfo['RIFF'][$arraykeys[0]]['SSND'][0]['size'];
                if ($ThisFileInfo['avdataend'] > $ThisFileInfo['filesize']) {
                    if ($ThisFileInfo['avdataend'] == $ThisFileInfo['filesize'] + 1 && $ThisFileInfo['filesize'] % 2 == 1) {
                        // structures rounded to 2-byte boundary, but dumb encoders
                        // forget to pad end of file to make this actually work
                    } else {
                        $ThisFileInfo['warning'] .= "\n" . 'Probable truncated AIFF file: expecting ' . $ThisFileInfo['RIFF'][$arraykeys[0]]['SSND'][0]['size'] . ' bytes of audio data, only ' . ($ThisFileInfo['filesize'] - $ThisFileInfo['avdataoffset']) . ' bytes found';
                    }
                    $ThisFileInfo['avdataend'] = $ThisFileInfo['filesize'];
                }
            }
            if (isset($ThisFileInfo['RIFF'][$arraykeys[0]]['COMM'][0]['data'])) {
                $ThisFileInfo['RIFF']['audio']['channels'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMM'][0]['data'], 0, 2), true);
                $ThisFileInfo['RIFF']['audio']['total_samples'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMM'][0]['data'], 2, 4), false);
                $ThisFileInfo['RIFF']['audio']['bits_per_sample'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMM'][0]['data'], 6, 2), true);
                $ThisFileInfo['RIFF']['audio']['sample_rate'] = (int) BigEndian2Float(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMM'][0]['data'], 8, 10));
                if ($ThisFileInfo['RIFF'][$arraykeys[0]]['COMM'][0]['size'] > 18) {
                    $ThisFileInfo['RIFF']['audio']['codec_fourcc'] = substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMM'][0]['data'], 18, 4);
                    $CodecNameSize = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMM'][0]['data'], 22, 1), false);
                    $ThisFileInfo['RIFF']['audio']['codec_name'] = substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMM'][0]['data'], 23, $CodecNameSize);
                    if ($ThisFileInfo['RIFF']['audio']['codec_name'] == 'NONE') {
                        $ThisFileInfo['audio']['codec'] = 'Pulse Code Modulation (PCM)';
                        $ThisFileInfo['audio']['lossless'] = true;
                    } else {
                        $ThisFileInfo['audio']['codec'] = $ThisFileInfo['RIFF']['audio']['codec_name'];
                        $ThisFileInfo['audio']['lossless'] = false;
                    }
                }
                $ThisFileInfo['audio']['channels'] = $ThisFileInfo['RIFF']['audio']['channels'];
                if ($ThisFileInfo['RIFF']['audio']['bits_per_sample'] > 0) {
                    $ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['RIFF']['audio']['bits_per_sample'];
                }
                $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['RIFF']['audio']['sample_rate'];
                if ($ThisFileInfo['audio']['sample_rate'] == 0) {
                    $ThisFileInfo['error'] .= "\n" . 'Corrupted AIFF file: sample_rate == zero';
                    return false;
                }
                $ThisFileInfo['playtime_seconds'] = $ThisFileInfo['RIFF']['audio']['total_samples'] / $ThisFileInfo['audio']['sample_rate'];
            }
            if (isset($ThisFileInfo['RIFF'][$arraykeys[0]]['COMT'])) {
                $offset = 0;
                $CommentCount = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMT'][0]['data'], $offset, 2), false);
                $offset += 2;
                for ($i = 0; $i < $CommentCount; $i++) {
                    $ThisFileInfo['comments_raw'][$i]['timestamp'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMT'][0]['data'], $offset, 4), false);
                    $offset += 4;
                    $ThisFileInfo['comments_raw'][$i]['marker_id'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMT'][0]['data'], $offset, 2), true);
                    $offset += 2;
                    $CommentLength = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMT'][0]['data'], $offset, 2), false);
                    $offset += 2;
                    $ThisFileInfo['comments_raw'][$i]['comment'] = substr($ThisFileInfo['RIFF'][$arraykeys[0]]['COMT'][0]['data'], $offset, $CommentLength);
                    $offset += $CommentLength;
                    $ThisFileInfo['comments_raw'][$i]['timestamp_unix'] = DateMac2Unix($ThisFileInfo['comments_raw'][$i]['timestamp']);
                    $ThisFileInfo['RIFF']['comments']['comment'][] = $ThisFileInfo['comments_raw'][$i]['comment'];
                }
            }
            $CommentsChunkNames = array('NAME' => 'title', 'author' => 'artist', '(c) ' => 'copyright', 'ANNO' => 'comment');
            foreach ($CommentsChunkNames as $key => $value) {
                if (isset($ThisFileInfo['RIFF'][$arraykeys[0]][$key][0]['data'])) {
                    $ThisFileInfo['RIFF']['comments'][$value][] = $ThisFileInfo['RIFF'][$arraykeys[0]][$key][0]['data'];
                }
            }
            if (isset($ThisFileInfo['RIFF']['comments'])) {
                CopyFormatCommentsToRootComments($ThisFileInfo['RIFF']['comments'], $ThisFileInfo, true, true, true);
            }
            break;
        case '8SVX':
            $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
            $ThisFileInfo['audio']['dataformat'] = '8svx';
            $ThisFileInfo['audio']['bits_per_sample'] = 8;
            $ThisFileInfo['audio']['channels'] = 1;
            // overridden below, if need be
            $ThisFileInfo['mime_type'] = 'audio/x-aiff';
            if (isset($ThisFileInfo['RIFF'][$arraykeys[0]]['BODY'][0]['offset'])) {
                $ThisFileInfo['avdataoffset'] = $ThisFileInfo['RIFF'][$arraykeys[0]]['BODY'][0]['offset'] + 8;
                $ThisFileInfo['avdataend'] = $ThisFileInfo['avdataoffset'] + $ThisFileInfo['RIFF'][$arraykeys[0]]['BODY'][0]['size'];
                if ($ThisFileInfo['avdataend'] > $ThisFileInfo['filesize']) {
                    $ThisFileInfo['warning'] .= "\n" . 'Probable truncated AIFF file: expecting ' . $ThisFileInfo['RIFF'][$arraykeys[0]]['BODY'][0]['size'] . ' bytes of audio data, only ' . ($ThisFileInfo['filesize'] - $ThisFileInfo['avdataoffset']) . ' bytes found';
                }
            }
            if (isset($ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['offset'])) {
                $ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['oneShotHiSamples'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['data'], 0, 4));
                $ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['repeatHiSamples'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['data'], 4, 4));
                $ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['samplesPerHiCycle'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['data'], 8, 4));
                $ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['samplesPerSec'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['data'], 12, 2));
                $ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['ctOctave'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['data'], 14, 1));
                $ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['sCompression'] = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['data'], 15, 1));
                $ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['Volume'] = FixedPoint16_16(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['data'], 16, 4));
                $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['samplesPerSec'];
                switch ($ThisFileInfo['RIFF'][$arraykeys[0]]['VHDR'][0]['sCompression']) {
                    case 0:
                        $ThisFileInfo['audio']['codec'] = 'Pulse Code Modulation (PCM)';
                        $ThisFileInfo['audio']['lossless'] = true;
                        $ActualBitsPerSample = 8;
                        break;
                    case 1:
                        $ThisFileInfo['audio']['codec'] = 'Fibonacci-delta encoding';
                        $ThisFileInfo['audio']['lossless'] = false;
                        $ActualBitsPerSample = 4;
                        break;
                    default:
                        $ThisFileInfo['warning'] .= "\n" . 'Unexpected sCompression value in 8SVX.VHDR chunk - expecting 0 or 1, found "' . sCompression . '"';
                        break;
                }
            }
            if (isset($ThisFileInfo['RIFF'][$arraykeys[0]]['CHAN'][0]['data'])) {
                $ChannelsIndex = BigEndian2Int(substr($ThisFileInfo['RIFF'][$arraykeys[0]]['CHAN'][0]['data'], 0, 4));
                switch ($ChannelsIndex) {
                    case 6:
                        // Stereo
                        $ThisFileInfo['audio']['channels'] = 2;
                        break;
                    case 2:
                        // Left channel only
                    // Left channel only
                    case 4:
                        // Right channel only
                        $ThisFileInfo['audio']['channels'] = 1;
                        break;
                    default:
                        $ThisFileInfo['warning'] .= "\n" . 'Unexpected value in 8SVX.CHAN chunk - expecting 2 or 4 or 6, found "' . $ChannelsIndex . '"';
                        break;
                }
            }
            $CommentsChunkNames = array('NAME' => 'title', 'author' => 'artist', '(c) ' => 'copyright', 'ANNO' => 'comment');
            foreach ($CommentsChunkNames as $key => $value) {
                if (isset($ThisFileInfo['RIFF'][$arraykeys[0]][$key][0]['data'])) {
                    $ThisFileInfo['RIFF']['comments'][$value][] = $ThisFileInfo['RIFF'][$arraykeys[0]][$key][0]['data'];
                }
            }
            if (isset($ThisFileInfo['RIFF']['comments'])) {
                CopyFormatCommentsToRootComments($ThisFileInfo['RIFF']['comments'], $ThisFileInfo, true, true, true);
            }
            $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['audio']['sample_rate'] * $ActualBitsPerSample * $ThisFileInfo['audio']['channels'];
            if (!empty($ThisFileInfo['audio']['bitrate'])) {
                $ThisFileInfo['playtime_seconds'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / ($ThisFileInfo['audio']['bitrate'] / 8);
            }
            break;
        default:
            $ThisFileInfo['error'] .= "\n" . 'Unknown RIFF type: expecting one of (WAVE|RMP3|AVI |CDDA|AIFF|AIFC|8SVX|), found "' . $arraykeys[0] . '" instead';
            unset($ThisFileInfo['fileformat']);
            break;
    }
    if (isset($ThisFileInfo['RIFF']['WAVE']['DISP']) && is_array($ThisFileInfo['RIFF']['WAVE']['DISP'])) {
        $ThisFileInfo['tags'][] = 'riff';
        $ThisFileInfo['RIFF']['comments']['title'][] = trim(substr($ThisFileInfo['RIFF']['WAVE']['DISP'][count($ThisFileInfo['RIFF']['WAVE']['DISP']) - 1]['data'], 4));
    }
    if (isset($ThisFileInfo['RIFF']['WAVE']['INFO']) && is_array($ThisFileInfo['RIFF']['WAVE']['INFO'])) {
        $ThisFileInfo['tags'][] = 'riff';
        $RIFFinfoKeyLookup = array('IART' => 'artist', 'IGNR' => 'genre', 'ICMT' => 'comment', 'ICOP' => 'copyright', 'IENG' => 'engineers', 'IKEY' => 'keywords', 'IMED' => 'orignalmedium', 'INAM' => 'name', 'ISRC' => 'sourcesupplier', 'ITCH' => 'digitizer', 'ISBJ' => 'subject', 'ISRF' => 'digitizationsource', 'ISFT' => 'encoded_by');
        foreach ($RIFFinfoKeyLookup as $key => $value) {
            if (isset($ThisFileInfo['RIFF']['WAVE']['INFO']["{$key}"])) {
                foreach ($ThisFileInfo['RIFF']['WAVE']['INFO']["{$key}"] as $commentid => $commentdata) {
                    if (trim($commentdata['data']) != '') {
                        $ThisFileInfo['RIFF']['comments']["{$value}"][] = trim($commentdata['data']);
                    }
                }
            }
        }
    }
    if (!empty($ThisFileInfo['RIFF']['comments'])) {
        CopyFormatCommentsToRootComments($ThisFileInfo['RIFF']['comments'], $ThisFileInfo, true, false, true);
    }
    if (empty($ThisFileInfo['audio']['encoder']) && !empty($ThisFileInfo['mpeg']['audio']['LAME']['short_version'])) {
        $ThisFileInfo['audio']['encoder'] = $ThisFileInfo['mpeg']['audio']['LAME']['short_version'];
    }
    if (!isset($ThisFileInfo['playtime_seconds'])) {
        $ThisFileInfo['playtime_seconds'] = 0;
    }
    if (isset($ThisFileInfo['RIFF']['raw']['avih']['dwTotalFrames']) && isset($ThisFileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'])) {
        $ThisFileInfo['playtime_seconds'] = $ThisFileInfo['RIFF']['raw']['avih']['dwTotalFrames'] * ($ThisFileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'] / 1000000);
    }
    if ($ThisFileInfo['playtime_seconds'] > 0) {
        if (isset($ThisFileInfo['RIFF']['audio']) && isset($ThisFileInfo['RIFF']['video'])) {
            if (!isset($ThisFileInfo['bitrate'])) {
                $ThisFileInfo['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / $ThisFileInfo['playtime_seconds'] * 8;
            }
        } elseif (isset($ThisFileInfo['RIFF']['audio']) && !isset($ThisFileInfo['RIFF']['video'])) {
            if (!isset($ThisFileInfo['audio']['bitrate'])) {
                $ThisFileInfo['audio']['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / $ThisFileInfo['playtime_seconds'] * 8;
            }
        } elseif (!isset($ThisFileInfo['RIFF']['audio']) && isset($ThisFileInfo['RIFF']['video'])) {
            if (!isset($ThisFileInfo['video']['bitrate'])) {
                $ThisFileInfo['video']['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / $ThisFileInfo['playtime_seconds'] * 8;
            }
        }
    }
    if (isset($ThisFileInfo['RIFF']['video']) && isset($ThisFileInfo['audio']['bitrate']) && $ThisFileInfo['audio']['bitrate'] > 0 && $ThisFileInfo['playtime_seconds'] > 0) {
        $ThisFileInfo['audio']['bitrate'] = 0;
        $ThisFileInfo['video']['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / $ThisFileInfo['playtime_seconds'] * 8;
        foreach ($ThisFileInfo['RIFF']['audio'] as $channelnumber => $audioinfoarray) {
            $ThisFileInfo['video']['bitrate'] -= $audioinfoarray['bitrate'];
            $ThisFileInfo['audio']['bitrate'] += $audioinfoarray['bitrate'];
        }
        if ($ThisFileInfo['video']['bitrate'] <= 0) {
            unset($ThisFileInfo['video']['bitrate']);
        }
        if ($ThisFileInfo['audio']['bitrate'] <= 0) {
            unset($ThisFileInfo['audio']['bitrate']);
        }
    }
    if (!empty($ThisFileInfo['RIFF']['raw']['fmt ']['nBitsPerSample']) && $ThisFileInfo['RIFF']['raw']['fmt ']['nBitsPerSample'] > 0) {
        $ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['RIFF']['raw']['fmt ']['nBitsPerSample'];
    }
    return true;
}
Example #6
0
function getID3v2Filepointer(&$fd, &$ThisFileInfo)
{
    //    Overall tag structure:
    //        +-----------------------------+
    //        |      Header (10 bytes)      |
    //        +-----------------------------+
    //        |       Extended Header       |
    //        | (variable length, OPTIONAL) |
    //        +-----------------------------+
    //        |   Frames (variable length)  |
    //        +-----------------------------+
    //        |           Padding           |
    //        | (variable length, OPTIONAL) |
    //        +-----------------------------+
    //        | Footer (10 bytes, OPTIONAL) |
    //        +-----------------------------+
    //    Header
    //        ID3v2/file identifier      "ID3"
    //        ID3v2 version              $04 00
    //        ID3v2 flags                (%ab000000 in v2.2, %abc00000 in v2.3, %abcd0000 in v2.4.x)
    //        ID3v2 size             4 * %0xxxxxxx
    rewind($fd);
    $header = fread($fd, 10);
    if (substr($header, 0, 3) == 'ID3') {
        $ThisFileInfo['id3v2']['header'] = true;
        $ThisFileInfo['id3v2']['majorversion'] = ord($header[3]);
        $ThisFileInfo['id3v2']['minorversion'] = ord($header[4]);
    } else {
        return false;
    }
    if ($ThisFileInfo['id3v2']['majorversion'] > 4) {
        // this script probably won't correctly parse ID3v2.5.x and above.
        $ThisFileInfo['error'] .= "\n" . 'this script only parses up to ID3v2.4.x - this tag is ID3v2.' . $ThisFileInfo['id3v2']['majorversion'] . '.' . $ThisFileInfo['id3v2']['minorversion'];
        return false;
    }
    $id3_flags = BigEndian2Bin($header[5]);
    switch ($ThisFileInfo['id3v2']['majorversion']) {
        case 2:
            // %ab000000 in v2.2
            $ThisFileInfo['id3v2']['flags']['unsynch'] = $id3_flags[0];
            // a - Unsynchronisation
            $ThisFileInfo['id3v2']['flags']['compression'] = $id3_flags[1];
            // b - Compression
            break;
        case 3:
            // %abc00000 in v2.3
            $ThisFileInfo['id3v2']['flags']['unsynch'] = $id3_flags[0];
            // a - Unsynchronisation
            $ThisFileInfo['id3v2']['flags']['exthead'] = $id3_flags[1];
            // b - Extended header
            $ThisFileInfo['id3v2']['flags']['experim'] = $id3_flags[2];
            // c - Experimental indicator
            break;
        case 4:
            // %abcd0000 in v2.4
            $ThisFileInfo['id3v2']['flags']['unsynch'] = $id3_flags[0];
            // a - Unsynchronisation
            $ThisFileInfo['id3v2']['flags']['exthead'] = $id3_flags[1];
            // b - Extended header
            $ThisFileInfo['id3v2']['flags']['experim'] = $id3_flags[2];
            // c - Experimental indicator
            $ThisFileInfo['id3v2']['flags']['isfooter'] = $id3_flags[3];
            // d - Footer present
            break;
    }
    $ThisFileInfo['id3v2']['headerlength'] = BigEndian2Int(substr($header, 6, 4), 1) + ID3v2HeaderLength($ThisFileInfo['id3v2']['majorversion']);
    //    Extended Header
    if (isset($ThisFileInfo['id3v2']['flags']['exthead']) && $ThisFileInfo['id3v2']['flags']['exthead']) {
        //            Extended header size   4 * %0xxxxxxx
        //            Number of flag bytes       $01
        //            Extended Flags             $xx
        //            Where the 'Extended header size' is the size of the whole extended header, stored as a 32 bit synchsafe integer.
        $extheader = fread($fd, 4);
        $ThisFileInfo['id3v2']['extheaderlength'] = BigEndian2Int($extheader, 1);
        //            The extended flags field, with its size described by 'number of flag  bytes', is defined as:
        //                %0bcd0000
        //            b - Tag is an update
        //                Flag data length       $00
        //            c - CRC data present
        //                Flag data length       $05
        //                Total frame CRC    5 * %0xxxxxxx
        //            d - Tag restrictions
        //                Flag data length       $01
        $extheaderflagbytes = fread($fd, 1);
        $extheaderflags = fread($fd, $extheaderflagbytes);
        $id3_exthead_flags = BigEndian2Bin(substr($header, 5, 1));
        $ThisFileInfo['id3v2']['exthead_flags']['update'] = substr($id3_exthead_flags, 1, 1);
        $ThisFileInfo['id3v2']['exthead_flags']['CRC'] = substr($id3_exthead_flags, 2, 1);
        if ($ThisFileInfo['id3v2']['exthead_flags']['CRC']) {
            $extheaderrawCRC = fread($fd, 5);
            $ThisFileInfo['id3v2']['exthead_flags']['CRC'] = BigEndian2Int($extheaderrawCRC, 1);
        }
        $ThisFileInfo['id3v2']['exthead_flags']['restrictions'] = substr($id3_exthead_flags, 3, 1);
        if ($ThisFileInfo['id3v2']['exthead_flags']['restrictions']) {
            // Restrictions           %ppqrrstt
            $extheaderrawrestrictions = fread($fd, 1);
            $ThisFileInfo['id3v2']['exthead_flags']['restrictions_tagsize'] = (bindec('11000000') & ord($extheaderrawrestrictions)) >> 6;
            // p - Tag size restrictions
            $ThisFileInfo['id3v2']['exthead_flags']['restrictions_textenc'] = (bindec('00100000') & ord($extheaderrawrestrictions)) >> 5;
            // q - Text encoding restrictions
            $ThisFileInfo['id3v2']['exthead_flags']['restrictions_textsize'] = (bindec('00011000') & ord($extheaderrawrestrictions)) >> 3;
            // r - Text fields size restrictions
            $ThisFileInfo['id3v2']['exthead_flags']['restrictions_imgenc'] = (bindec('00000100') & ord($extheaderrawrestrictions)) >> 2;
            // s - Image encoding restrictions
            $ThisFileInfo['id3v2']['exthead_flags']['restrictions_imgsize'] = (bindec('00000011') & ord($extheaderrawrestrictions)) >> 0;
            // t - Image size restrictions
        }
    }
    // end extended header
    //    Frames
    //        All ID3v2 frames consists of one frame header followed by one or more
    //        fields containing the actual information. The header is always 10
    //        bytes and laid out as follows:
    //
    //        Frame ID      $xx xx xx xx  (four characters)
    //        Size      4 * %0xxxxxxx
    //        Flags         $xx xx
    $sizeofframes = $ThisFileInfo['id3v2']['headerlength'] - ID3v2HeaderLength($ThisFileInfo['id3v2']['majorversion']);
    if (isset($ThisFileInfo['id3v2']['extheaderlength'])) {
        $sizeofframes -= $ThisFileInfo['id3v2']['extheaderlength'];
    }
    if (isset($ThisFileInfo['id3v2']['flags']['isfooter']) && $ThisFileInfo['id3v2']['flags']['isfooter']) {
        $sizeofframes -= 10;
        // footer takes last 10 bytes of ID3v2 header, after frame data, before audio
    }
    if ($sizeofframes > 0) {
        $framedata = fread($fd, $sizeofframes);
        // read all frames from file into $framedata variable
        //    if entire frame data is unsynched, de-unsynch it now (ID3v2.3.x)
        if (isset($ThisFileInfo['id3v2']['flags']['unsynch']) && $ThisFileInfo['id3v2']['flags']['unsynch'] && $ThisFileInfo['id3v2']['majorversion'] <= 3) {
            $framedata = DeUnSynchronise($framedata);
        }
        //        [in ID3v2.4.0] Unsynchronisation [S:6.1] is done on frame level, instead
        //        of on tag level, making it easier to skip frames, increasing the streamability
        //        of the tag. The unsynchronisation flag in the header [S:3.1] indicates that
        //        there exists an unsynchronised frame, while the new unsynchronisation flag in
        //        the frame header [S:4.1.2] indicates unsynchronisation.
        $framedataoffset = 10;
        // how many bytes into the stream - start from after the 10-byte header
        while (isset($framedata) && strlen($framedata) > 0) {
            // cycle through until no more frame data is left to parse
            if (strlen($framedata) < ID3v2HeaderLength($ThisFileInfo['id3v2']['majorversion'])) {
                // insufficient room left in ID3v2 header for actual data - must be padding
                $ThisFileInfo['id3v2']['padding']['start'] = $framedataoffset;
                $ThisFileInfo['id3v2']['padding']['length'] = strlen($framedata);
                $ThisFileInfo['id3v2']['padding']['valid'] = true;
                for ($i = 0; $i < $ThisFileInfo['id3v2']['padding']['length']; $i++) {
                    if (substr($framedata, $i, 1) != chr(0)) {
                        $ThisFileInfo['id3v2']['padding']['valid'] = false;
                        $ThisFileInfo['id3v2']['padding']['errorpos'] = $ThisFileInfo['id3v2']['padding']['start'] + $i;
                        $ThisFileInfo['warning'] .= "\n" . 'Invalid ID3v2 padding found at offset ' . $ThisFileInfo['id3v2']['padding']['errorpos'];
                        break;
                    }
                }
                break;
                // skip rest of ID3v2 header
            }
            if ($ThisFileInfo['id3v2']['majorversion'] == 2) {
                // Frame ID  $xx xx xx (three characters)
                // Size      $xx xx xx (24-bit integer)
                // Flags     $xx xx
                $frame_header = substr($framedata, 0, 6);
                // take next 6 bytes for header
                $framedata = substr($framedata, 6);
                // and leave the rest in $framedata
                $frame_name = substr($frame_header, 0, 3);
                $frame_size = BigEndian2Int(substr($frame_header, 3, 3), 0);
                $frame_flags = '';
                // not used for anything, just to avoid E_NOTICEs
            } elseif ($ThisFileInfo['id3v2']['majorversion'] > 2) {
                // Frame ID  $xx xx xx xx (four characters)
                // Size      $xx xx xx xx (32-bit integer in v2.3, 28-bit synchsafe in v2.4+)
                // Flags     $xx xx
                $frame_header = substr($framedata, 0, 10);
                // take next 10 bytes for header
                $framedata = substr($framedata, 10);
                // and leave the rest in $framedata
                $frame_name = substr($frame_header, 0, 4);
                if ($ThisFileInfo['id3v2']['majorversion'] == 3) {
                    $frame_size = BigEndian2Int(substr($frame_header, 4, 4), 0);
                    // 32-bit integer
                } else {
                    // ID3v2.4+
                    $frame_size = BigEndian2Int(substr($frame_header, 4, 4), 1);
                    // 32-bit synchsafe integer (28-bit value)
                }
                if ($frame_size < strlen($framedata) + 4) {
                    $nextFrameID = substr($framedata, $frame_size, 4);
                    if (IsValidID3v2FrameName($nextFrameID, $ThisFileInfo['id3v2']['majorversion'])) {
                        // next frame is OK
                    } elseif ($frame_name == chr(0) . 'MP3' || $frame_name == chr(0) . chr(0) . 'MP' || $frame_name == ' MP3' || $frame_name == 'MP3e') {
                        // MP3ext known broken frames - "ok" for the purposes of this test
                    } elseif ($ThisFileInfo['id3v2']['majorversion'] == 4 && IsValidID3v2FrameName(substr($framedata, BigEndian2Int(substr($frame_header, 4, 4), 0), 4), 3)) {
                        $ThisFileInfo['warning'] .= "\n" . 'ID3v2 tag written as ID3v2.4, but with non-synchsafe integers (ID3v2.3 style). Older versions of Helium2 (www.helium2.com) is a known culprit of this. Tag has been parsed as ID3v2.3';
                        $ThisFileInfo['id3v2']['majorversion'] = 3;
                        $frame_size = BigEndian2Int(substr($frame_header, 4, 4), 0);
                        // 32-bit integer
                    }
                }
                $frame_flags = BigEndian2Bin(substr($frame_header, 8, 2));
            }
            if ($ThisFileInfo['id3v2']['majorversion'] == 2 && $frame_name == chr(0) . chr(0) . chr(0) || $frame_name == chr(0) . chr(0) . chr(0) . chr(0)) {
                // padding encountered
                $ThisFileInfo['id3v2']['padding']['start'] = $framedataoffset;
                $ThisFileInfo['id3v2']['padding']['length'] = strlen($framedata);
                $ThisFileInfo['id3v2']['padding']['valid'] = true;
                for ($i = 0; $i < $ThisFileInfo['id3v2']['padding']['length']; $i++) {
                    if (substr($framedata, $i, 1) != chr(0)) {
                        $ThisFileInfo['id3v2']['padding']['valid'] = false;
                        $ThisFileInfo['id3v2']['padding']['errorpos'] = $ThisFileInfo['id3v2']['padding']['start'] + $i;
                        $ThisFileInfo['warning'] .= "\n" . 'Invalid ID3v2 padding found at offset ' . $ThisFileInfo['id3v2']['padding']['errorpos'];
                        break;
                    }
                }
                break;
                // skip rest of ID3v2 header
            }
            if ($frame_name == 'COM ') {
                $ThisFileInfo['warning'] .= "\n" . 'error parsing "' . $frame_name . '" (' . $framedataoffset . ' bytes into the ID3v2.' . $ThisFileInfo['id3v2']['majorversion'] . ' tag). (ERROR: !IsValidID3v2FrameName("' . str_replace(chr(0), ' ', $frame_name) . '", ' . $ThisFileInfo['id3v2']['majorversion'] . '))). [Note: this particular error has been known to happen with tags edited by iTunes (versions "X v2.0.3", "v3.0.1" are known-guilty, probably others too)]';
                $frame_name = 'COMM';
            }
            if ($frame_size <= strlen($framedata) && IsValidID3v2FrameName($frame_name, $ThisFileInfo['id3v2']['majorversion'])) {
                $ThisFileInfo['id3v2']["{$frame_name}"]['data'] = substr($framedata, 0, $frame_size);
                $ThisFileInfo['id3v2']["{$frame_name}"]['datalength'] = CastAsInt($frame_size);
                $ThisFileInfo['id3v2']["{$frame_name}"]['dataoffset'] = $framedataoffset;
                $framedata = substr($framedata, $frame_size);
                // in getid3.frames.php - this function does all the FrameID-level parsing
                ID3v2FrameProcessing($frame_name, $frame_flags, $ThisFileInfo);
            } else {
                // invalid frame length or FrameID
                if ($frame_size <= strlen($framedata)) {
                    if (IsValidID3v2FrameName(substr($framedata, $frame_size, 4), $ThisFileInfo['id3v2']['majorversion'])) {
                        // next frame is valid, just skip the current frame
                        $framedata = substr($framedata, $frame_size);
                        $InvalidFrameMessageType = 'warning';
                        $InvalidFrameMessageText = ' Next frame is valid, skipping current frame.';
                    } else {
                        // next frame is invalid too, abort processing
                        unset($framedata);
                        $InvalidFrameMessageType = 'error';
                        $InvalidFrameMessageText = ' Next frame is also invalid, aborting processing.';
                    }
                } elseif ($frame_size == strlen($framedata)) {
                    // this is the last frame, just skip
                    $InvalidFrameMessageType = 'warning';
                    $InvalidFrameMessageText = ' This was the last frame.';
                } else {
                    // next frame is invalid too, abort processing
                    unset($framedata);
                    $InvalidFrameMessageType = 'error';
                    $InvalidFrameMessageText = ' Invalid frame size, aborting.';
                }
                if (!IsValidID3v2FrameName($frame_name, $ThisFileInfo['id3v2']['majorversion'])) {
                    switch ($frame_name) {
                        case chr(0) . chr(0) . 'MP':
                        case chr(0) . 'MP3':
                        case ' MP3':
                        case 'MP3e':
                        case chr(0) . 'MP':
                        case ' MP':
                        case 'MP3':
                            $InvalidFrameMessageType = 'warning';
                            $ThisFileInfo["{$InvalidFrameMessageType}"] .= "\n" . 'error parsing "' . $frame_name . '" (' . $framedataoffset . ' bytes into the ID3v2.' . $ThisFileInfo['id3v2']['majorversion'] . ' tag). (ERROR: !IsValidID3v2FrameName("' . str_replace(chr(0), ' ', $frame_name) . '", ' . $ThisFileInfo['id3v2']['majorversion'] . '))). [Note: this particular error has been known to happen with tags edited by "MP3ext (www.mutschler.de/mp3ext/)"]';
                            break;
                        default:
                            $ThisFileInfo["{$InvalidFrameMessageType}"] .= "\n" . 'error parsing "' . $frame_name . '" (' . $framedataoffset . ' bytes into the ID3v2.' . $ThisFileInfo['id3v2']['majorversion'] . ' tag). (ERROR: !IsValidID3v2FrameName("' . str_replace(chr(0), ' ', $frame_name) . '", ' . $ThisFileInfo['id3v2']['majorversion'] . '))).';
                            break;
                    }
                } elseif ($frame_size > strlen($framedata)) {
                    $ThisFileInfo["{$InvalidFrameMessageType}"] .= "\n" . 'error parsing "' . $frame_name . '" (' . $framedataoffset . ' bytes into the ID3v2.' . $ThisFileInfo['id3v2']['majorversion'] . ' tag). (ERROR: $frame_size (' . $frame_size . ') > strlen($framedata) (' . strlen($framedata) . ')).';
                } else {
                    $ThisFileInfo["{$InvalidFrameMessageType}"] .= "\n" . 'error parsing "' . $frame_name . '" (' . $framedataoffset . ' bytes into the ID3v2.' . $ThisFileInfo['id3v2']['majorversion'] . ' tag).';
                }
                $ThisFileInfo["{$InvalidFrameMessageType}"] .= $InvalidFrameMessageText;
            }
            $framedataoffset += $frame_size + ID3v2HeaderLength($ThisFileInfo['id3v2']['majorversion']);
        }
    }
    //    Footer
    //    The footer is a copy of the header, but with a different identifier.
    //        ID3v2 identifier           "3DI"
    //        ID3v2 version              $04 00
    //        ID3v2 flags                %abcd0000
    //        ID3v2 size             4 * %0xxxxxxx
    if (isset($ThisFileInfo['id3v2']['flags']['isfooter']) && $ThisFileInfo['id3v2']['flags']['isfooter']) {
        $footer = fread($fd, 10);
        if (substr($footer, 0, 3) == '3DI') {
            $ThisFileInfo['id3v2']['footer'] = true;
            $ThisFileInfo['id3v2']['majorversion_footer'] = ord(substr($footer, 3, 1));
            $ThisFileInfo['id3v2']['minorversion_footer'] = ord(substr($footer, 4, 1));
        }
        if ($ThisFileInfo['id3v2']['majorversion_footer'] <= 4) {
            $id3_flags = BigEndian2Bin(substr($footer, 5, 1));
            $ThisFileInfo['id3v2']['flags']['unsynch_footer'] = substr($id3_flags, 0, 1);
            $ThisFileInfo['id3v2']['flags']['extfoot_footer'] = substr($id3_flags, 1, 1);
            $ThisFileInfo['id3v2']['flags']['experim_footer'] = substr($id3_flags, 2, 1);
            $ThisFileInfo['id3v2']['flags']['isfooter_footer'] = substr($id3_flags, 3, 1);
            $ThisFileInfo['id3v2']['footerlength'] = BigEndian2Int(substr($footer, 6, 4), 1);
        }
    }
    // end footer
    if (isset($ThisFileInfo['id3v2']['comments']['genre'])) {
        foreach ($ThisFileInfo['id3v2']['comments']['genre'] as $key => $value) {
            unset($ThisFileInfo['id3v2']['comments']['genre'][$key]);
            $ThisFileInfo['id3v2']['comments'] = array_merge_noclobber($ThisFileInfo['id3v2']['comments'], ParseID3v2GenreString($value));
        }
    }
    if (isset($ThisFileInfo['id3v2']['comments']['track'])) {
        foreach ($ThisFileInfo['id3v2']['comments']['track'] as $key => $value) {
            if (strstr($value, '/')) {
                list($ThisFileInfo['id3v2']['comments']['track'][$key], $ThisFileInfo['id3v2']['comments']['totaltracks'][$key]) = explode('/', $ThisFileInfo['id3v2']['comments']['track'][$key]);
            }
            // Convert track number to integer (ID3v2 track numbers could be returned as a
            // string ('03' for example) - this will ensure all track numbers are integers
            $ThisFileInfo['id3v2']['comments']['track'][$key] = intval($ThisFileInfo['id3v2']['comments']['track'][$key]);
        }
    }
    return true;
}
function getRIFFHeaderFilepointer(&$fd, &$MP3fileInfo)
{
    $offset = 0;
    rewind($fd);
    $MP3fileInfo['RIFF'] = ParseRIFF($fd, $offset, $MP3fileInfo['filesize']);
    $streamindex = 0;
    if (!is_array($MP3fileInfo['RIFF'])) {
        $MP3fileInfo['error'] .= "\n" . 'Cannot parse RIFF (this is maybe not a RIFF / WAV / AVI file?)';
        unset($MP3fileInfo['RIFF']);
        unset($MP3fileInfo['fileformat']);
        return FALSE;
    }
    $arraykeys = array_keys($MP3fileInfo['RIFF']);
    switch ($arraykeys[0]) {
        case 'WAVE':
            $MP3fileInfo['fileformat'] = 'wav';
            if (isset($MP3fileInfo['RIFF']['WAVE']['fmt '][0]['data'])) {
                $fmtData = $MP3fileInfo['RIFF']['WAVE']['fmt '][0]['data'];
                $MP3fileInfo['RIFF']['raw']['fmt ']['wFormatTag'] = LittleEndian2Int(substr($fmtData, 0, 2));
                $MP3fileInfo['RIFF']['raw']['fmt ']['nChannels'] = LittleEndian2Int(substr($fmtData, 2, 2));
                $MP3fileInfo['RIFF']['raw']['fmt ']['nSamplesPerSec'] = LittleEndian2Int(substr($fmtData, 4, 4));
                $MP3fileInfo['RIFF']['raw']['fmt ']['nAvgBytesPerSec'] = LittleEndian2Int(substr($fmtData, 8, 4));
                $MP3fileInfo['RIFF']['raw']['fmt ']['nBlockAlign'] = LittleEndian2Int(substr($fmtData, 12, 2));
                $MP3fileInfo['RIFF']['raw']['fmt ']['nBitsPerSample'] = LittleEndian2Int(substr($fmtData, 14, 2));
                $MP3fileInfo['RIFF']['audio']["{$streamindex}"]['format'] = RIFFwFormatTagLookup($MP3fileInfo['RIFF']['raw']['fmt ']['wFormatTag']);
                $MP3fileInfo['RIFF']['audio']["{$streamindex}"]['channels'] = $MP3fileInfo['RIFF']['raw']['fmt ']['nChannels'];
                $MP3fileInfo['RIFF']['audio']["{$streamindex}"]['channelmode'] = $MP3fileInfo['RIFF']['audio']["{$streamindex}"]['channels'] == 1 ? 'mono' : 'stereo';
                $MP3fileInfo['RIFF']['audio']["{$streamindex}"]['frequency'] = $MP3fileInfo['RIFF']['raw']['fmt ']['nSamplesPerSec'];
                $MP3fileInfo['RIFF']['audio']["{$streamindex}"]['bitrate'] = $MP3fileInfo['RIFF']['raw']['fmt ']['nAvgBytesPerSec'] * 8;
                $MP3fileInfo['RIFF']['audio']["{$streamindex}"]['bitspersample'] = $MP3fileInfo['RIFF']['raw']['fmt ']['nBitsPerSample'];
            }
            if (isset($MP3fileInfo['RIFF']['WAVE']['rgad'][0]['data'])) {
                $rgadData = $MP3fileInfo['RIFF']['WAVE']['rgad'][0]['data'];
                $MP3fileInfo['RIFF']['raw']['rgad']['fPeakAmplitude'] = LittleEndian2Float(substr($rgadData, 0, 4));
                $MP3fileInfo['RIFF']['raw']['rgad']['nRadioRgAdjust'] = LittleEndian2Int(substr($rgadData, 4, 2));
                $MP3fileInfo['RIFF']['raw']['rgad']['nAudiophileRgAdjust'] = LittleEndian2Int(substr($rgadData, 6, 2));
                $nRadioRgAdjustBitstring = str_pad(Dec2Bin($MP3fileInfo['RIFF']['raw']['rgad']['nRadioRgAdjust']), 16, '0', STR_PAD_LEFT);
                $nAudiophileRgAdjustBitstring = str_pad(Dec2Bin($MP3fileInfo['RIFF']['raw']['rgad']['nAudiophileRgAdjust']), 16, '0', STR_PAD_LEFT);
                $MP3fileInfo['RIFF']['raw']['rgad']['radio']['name'] = Bin2Dec(substr($nRadioRgAdjustBitstring, 0, 3));
                $MP3fileInfo['RIFF']['raw']['rgad']['radio']['originator'] = Bin2Dec(substr($nRadioRgAdjustBitstring, 3, 3));
                $MP3fileInfo['RIFF']['raw']['rgad']['radio']['signbit'] = Bin2Dec(substr($nRadioRgAdjustBitstring, 6, 1));
                $MP3fileInfo['RIFF']['raw']['rgad']['radio']['adjustment'] = Bin2Dec(substr($nRadioRgAdjustBitstring, 7, 9));
                $MP3fileInfo['RIFF']['raw']['rgad']['audiophile']['name'] = Bin2Dec(substr($nAudiophileRgAdjustBitstring, 0, 3));
                $MP3fileInfo['RIFF']['raw']['rgad']['audiophile']['originator'] = Bin2Dec(substr($nAudiophileRgAdjustBitstring, 3, 3));
                $MP3fileInfo['RIFF']['raw']['rgad']['audiophile']['signbit'] = Bin2Dec(substr($nAudiophileRgAdjustBitstring, 6, 1));
                $MP3fileInfo['RIFF']['raw']['rgad']['audiophile']['adjustment'] = Bin2Dec(substr($nAudiophileRgAdjustBitstring, 7, 9));
                $MP3fileInfo['RIFF']['rgad']['peakamplitude'] = $MP3fileInfo['RIFF']['raw']['rgad']['fPeakAmplitude'];
                if ($MP3fileInfo['RIFF']['raw']['rgad']['radio']['name'] != 0 && $MP3fileInfo['RIFF']['raw']['rgad']['radio']['originator'] != 0) {
                    $MP3fileInfo['RIFF']['rgad']['radio']['name'] = RGADnameLookup($MP3fileInfo['RIFF']['raw']['rgad']['radio']['name']);
                    $MP3fileInfo['RIFF']['rgad']['radio']['originator'] = RGADoriginatorLookup($MP3fileInfo['RIFF']['raw']['rgad']['radio']['originator']);
                    $MP3fileInfo['RIFF']['rgad']['radio']['adjustment'] = RGADadjustmentLookup($MP3fileInfo['RIFF']['raw']['rgad']['radio']['adjustment'], $MP3fileInfo['RIFF']['raw']['rgad']['radio']['signbit']);
                }
                if ($MP3fileInfo['RIFF']['raw']['rgad']['audiophile']['name'] != 0 && $MP3fileInfo['RIFF']['raw']['rgad']['audiophile']['originator'] != 0) {
                    $MP3fileInfo['RIFF']['rgad']['audiophile']['name'] = RGADnameLookup($MP3fileInfo['RIFF']['raw']['rgad']['audiophile']['name']);
                    $MP3fileInfo['RIFF']['rgad']['audiophile']['originator'] = RGADoriginatorLookup($MP3fileInfo['RIFF']['raw']['rgad']['audiophile']['originator']);
                    $MP3fileInfo['RIFF']['rgad']['audiophile']['adjustment'] = RGADadjustmentLookup($MP3fileInfo['RIFF']['raw']['rgad']['audiophile']['adjustment'], $MP3fileInfo['RIFF']['raw']['rgad']['audiophile']['signbit']);
                }
            }
            if (isset($MP3fileInfo['RIFF']['WAVE']['fact'][0]['data'])) {
                $MP3fileInfo['RIFF']['raw']['fact']['NumberOfSamples'] = LittleEndian2Int(substr($MP3fileInfo['RIFF']['WAVE']['fact'][0]['data'], 0, 4));
                if (isset($MP3fileInfo['RIFF']['raw']['fmt ']['nSamplesPerSec']) && $MP3fileInfo['RIFF']['raw']['fmt ']['nSamplesPerSec']) {
                    $MP3fileInfo['playtime_seconds'] = (double) $MP3fileInfo['RIFF']['raw']['fact']['NumberOfSamples'] / $MP3fileInfo['RIFF']['raw']['fmt ']['nSamplesPerSec'];
                }
                if (isset($MP3fileInfo['RIFF']['raw']['fmt ']['nAvgBytesPerSec']) && $MP3fileInfo['RIFF']['raw']['fmt ']['nAvgBytesPerSec']) {
                    $MP3fileInfo['audiobytes'] = CastAsInt(round($MP3fileInfo['playtime_seconds'] * $MP3fileInfo['RIFF']['raw']['fmt ']['nAvgBytesPerSec']));
                    $MP3fileInfo['bitrate'] = CastAsInt($MP3fileInfo['RIFF']['raw']['fmt ']['nAvgBytesPerSec'] * 8);
                }
            }
            if (!isset($MP3fileInfo['audiobytes']) && isset($MP3fileInfo['RIFF']['WAVE']['data'][0]['size'])) {
                $MP3fileInfo['audiobytes'] = $MP3fileInfo['RIFF']['WAVE']['data'][0]['size'];
            }
            if (!isset($MP3fileInfo['bitrate']) && isset($MP3fileInfo['RIFF']['audio']["{$streamindex}"]['bitrate']) && isset($MP3fileInfo['audiobytes'])) {
                $MP3fileInfo['bitrate'] = $MP3fileInfo['RIFF']['audio']["{$streamindex}"]['bitrate'];
                $MP3fileInfo['playtime_seconds'] = (double) ($MP3fileInfo['audiobytes'] * 8 / $MP3fileInfo['bitrate']);
            }
            break;
        case 'AVI ':
            $MP3fileInfo['fileformat'] = 'avi';
            if (isset($MP3fileInfo['RIFF']['AVI ']['hdrl']['avih']["{$streamindex}"]['data'])) {
                $avihData = $MP3fileInfo['RIFF']['AVI ']['hdrl']['avih']["{$streamindex}"]['data'];
                $MP3fileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'] = LittleEndian2Int(substr($avihData, 0, 4));
                // frame display rate (or 0L)
                $MP3fileInfo['RIFF']['raw']['avih']['dwMaxBytesPerSec'] = LittleEndian2Int(substr($avihData, 4, 4));
                // max. transfer rate
                $MP3fileInfo['RIFF']['raw']['avih']['dwPaddingGranularity'] = LittleEndian2Int(substr($avihData, 8, 4));
                // pad to multiples of this size; normally 2K.
                $MP3fileInfo['RIFF']['raw']['avih']['dwFlags'] = LittleEndian2Int(substr($avihData, 12, 4));
                // the ever-present flags
                $MP3fileInfo['RIFF']['raw']['avih']['dwTotalFrames'] = LittleEndian2Int(substr($avihData, 16, 4));
                // # frames in file
                $MP3fileInfo['RIFF']['raw']['avih']['dwInitialFrames'] = LittleEndian2Int(substr($avihData, 20, 4));
                $MP3fileInfo['RIFF']['raw']['avih']['dwStreams'] = LittleEndian2Int(substr($avihData, 24, 4));
                $MP3fileInfo['RIFF']['raw']['avih']['dwSuggestedBufferSize'] = LittleEndian2Int(substr($avihData, 28, 4));
                $MP3fileInfo['RIFF']['raw']['avih']['dwWidth'] = LittleEndian2Int(substr($avihData, 32, 4));
                $MP3fileInfo['RIFF']['raw']['avih']['dwHeight'] = LittleEndian2Int(substr($avihData, 36, 4));
                $MP3fileInfo['RIFF']['raw']['avih']['dwScale'] = LittleEndian2Int(substr($avihData, 40, 4));
                $MP3fileInfo['RIFF']['raw']['avih']['dwRate'] = LittleEndian2Int(substr($avihData, 44, 4));
                $MP3fileInfo['RIFF']['raw']['avih']['dwStart'] = LittleEndian2Int(substr($avihData, 48, 4));
                $MP3fileInfo['RIFF']['raw']['avih']['dwLength'] = LittleEndian2Int(substr($avihData, 52, 4));
                $MP3fileInfo['RIFF']['raw']['avih']['flags']['hasindex'] = (bool) ($MP3fileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x10);
                $MP3fileInfo['RIFF']['raw']['avih']['flags']['mustuseindex'] = (bool) ($MP3fileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x20);
                $MP3fileInfo['RIFF']['raw']['avih']['flags']['interleaved'] = (bool) ($MP3fileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x100);
                $MP3fileInfo['RIFF']['raw']['avih']['flags']['trustcktype'] = (bool) ($MP3fileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x800);
                $MP3fileInfo['RIFF']['raw']['avih']['flags']['capturedfile'] = (bool) ($MP3fileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x10000);
                $MP3fileInfo['RIFF']['raw']['avih']['flags']['copyrighted'] = (bool) ($MP3fileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x20010);
                $MP3fileInfo['RIFF']['video']["{$streamindex}"]['frame_width'] = $MP3fileInfo['RIFF']['raw']['avih']['dwWidth'];
                $MP3fileInfo['RIFF']['video']["{$streamindex}"]['frame_height'] = $MP3fileInfo['RIFF']['raw']['avih']['dwHeight'];
                $MP3fileInfo['RIFF']['video']["{$streamindex}"]['frame_rate'] = round(1000000 / $MP3fileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'], 3);
                $MP3fileInfo['playtime_seconds'] = $MP3fileInfo['RIFF']['raw']['avih']['dwTotalFrames'] * ($MP3fileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'] / 1000000);
                $MP3fileInfo['bitrate'] = $MP3fileInfo['filesize'] / $MP3fileInfo['playtime_seconds'] * 8;
            }
            if (isset($MP3fileInfo['RIFF']['AVI ']['hdrl']['strl']['strh'][0]['data'])) {
                if (is_array($MP3fileInfo['RIFF']['AVI ']['hdrl']['strl']['strh'])) {
                    for ($i = 0; $i < count($MP3fileInfo['RIFF']['AVI ']['hdrl']['strl']['strh']); $i++) {
                        if (isset($MP3fileInfo['RIFF']['AVI ']['hdrl']['strl']['strh']["{$i}"]['data'])) {
                            $strhData = $MP3fileInfo['RIFF']['AVI ']['hdrl']['strl']['strh']["{$i}"]['data'];
                            $MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['fccType'] = substr($strhData, 0, 4);
                            $MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['fccHandler'] = substr($strhData, 4, 4);
                            $MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['dwFlags'] = LittleEndian2Int(substr($strhData, 8, 4));
                            // Contains AVITF_* flags
                            $MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['wPriority'] = LittleEndian2Int(substr($strhData, 12, 2));
                            $MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['wLanguage'] = LittleEndian2Int(substr($strhData, 14, 2));
                            $MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['dwInitialFrames'] = LittleEndian2Int(substr($strhData, 16, 4));
                            $MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['dwScale'] = LittleEndian2Int(substr($strhData, 20, 4));
                            $MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['dwRate'] = LittleEndian2Int(substr($strhData, 24, 4));
                            $MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['dwStart'] = LittleEndian2Int(substr($strhData, 28, 4));
                            $MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['dwLength'] = LittleEndian2Int(substr($strhData, 32, 4));
                            $MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['dwSuggestedBufferSize'] = LittleEndian2Int(substr($strhData, 36, 4));
                            $MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['dwQuality'] = LittleEndian2Int(substr($strhData, 40, 4));
                            $MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['dwSampleSize'] = LittleEndian2Int(substr($strhData, 44, 4));
                            $MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['rcFrame'] = LittleEndian2Int(substr($strhData, 48, 4));
                            if (isset($MP3fileInfo['RIFF']['AVI ']['hdrl']['strl']['strf']["{$i}"]['data'])) {
                                $strfData = $MP3fileInfo['RIFF']['AVI ']['hdrl']['strl']['strf']["{$i}"]['data'];
                                switch ($MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['fccType']) {
                                    case 'auds':
                                        if (isset($MP3fileInfo['RIFF']['audio']) && is_array($MP3fileInfo['RIFF']['audio'])) {
                                            $streamindex = count($MP3fileInfo['RIFF']['audio']);
                                        }
                                        $MP3fileInfo['RIFF']['raw']['strf']['auds']["{$streamindex}"]['wFormatTag'] = LittleEndian2Int(substr($strfData, 0, 2));
                                        $MP3fileInfo['RIFF']['raw']['strf']['auds']["{$streamindex}"]['nChannels'] = LittleEndian2Int(substr($strfData, 2, 2));
                                        $MP3fileInfo['RIFF']['raw']['strf']['auds']["{$streamindex}"]['nSamplesPerSec'] = LittleEndian2Int(substr($strfData, 4, 4));
                                        $MP3fileInfo['RIFF']['raw']['strf']['auds']["{$streamindex}"]['nAvgBytesPerSec'] = LittleEndian2Int(substr($strfData, 8, 4));
                                        $MP3fileInfo['RIFF']['raw']['strf']['auds']["{$streamindex}"]['nBlockAlign'] = LittleEndian2Int(substr($strfData, 12, 2));
                                        $MP3fileInfo['RIFF']['raw']['strf']['auds']["{$streamindex}"]['nBitsPerSample'] = LittleEndian2Int(substr($strfData, 14, 2));
                                        $MP3fileInfo['RIFF']['audio']["{$streamindex}"]['format'] = RIFFwFormatTagLookup($MP3fileInfo['RIFF']['raw']['strf']['auds']["{$streamindex}"]['wFormatTag']);
                                        $MP3fileInfo['RIFF']['audio']["{$streamindex}"]['channels'] = $MP3fileInfo['RIFF']['raw']['strf']['auds']["{$streamindex}"]['nChannels'];
                                        $MP3fileInfo['RIFF']['audio']["{$streamindex}"]['channelmode'] = $MP3fileInfo['RIFF']['audio']["{$streamindex}"]['channels'] == 1 ? 'mono' : 'stereo';
                                        $MP3fileInfo['RIFF']['audio']["{$streamindex}"]['frequency'] = $MP3fileInfo['RIFF']['raw']['strf']['auds']["{$streamindex}"]['nSamplesPerSec'];
                                        $MP3fileInfo['RIFF']['audio']["{$streamindex}"]['bitrate'] = $MP3fileInfo['RIFF']['raw']['strf']['auds']["{$streamindex}"]['nAvgBytesPerSec'] * 8;
                                        $MP3fileInfo['RIFF']['audio']["{$streamindex}"]['bitspersample'] = $MP3fileInfo['RIFF']['raw']['strf']['auds']["{$streamindex}"]['nBitsPerSample'];
                                        break;
                                    case 'vids':
                                        $MP3fileInfo['RIFF']['raw']['strf']['vids']["{$streamindex}"]['biSize'] = LittleEndian2Int(substr($strfData, 0, 4));
                                        // number of bytes required by the BITMAPINFOHEADER structure
                                        $MP3fileInfo['RIFF']['raw']['strf']['vids']["{$streamindex}"]['biWidth'] = LittleEndian2Int(substr($strfData, 4, 4));
                                        // width of the bitmap in pixels
                                        $MP3fileInfo['RIFF']['raw']['strf']['vids']["{$streamindex}"]['biHeight'] = LittleEndian2Int(substr($strfData, 8, 4));
                                        // height of the bitmap in pixels. If biHeight is positive, the bitmap is a "bottom-up" DIB and its origin is the lower left corner. If biHeight is negative, the bitmap is a "top-down" DIB and its origin is the upper left corner
                                        $MP3fileInfo['RIFF']['raw']['strf']['vids']["{$streamindex}"]['biPlanes'] = LittleEndian2Int(substr($strfData, 12, 2));
                                        // number of color planes on the target device. In most cases this value must be set to 1
                                        $MP3fileInfo['RIFF']['raw']['strf']['vids']["{$streamindex}"]['biBitCount'] = LittleEndian2Int(substr($strfData, 14, 2));
                                        // Specifies the number of bits per pixels
                                        $MP3fileInfo['RIFF']['raw']['strf']['vids']["{$streamindex}"]['fourcc'] = substr($strfData, 16, 4);
                                        //
                                        $MP3fileInfo['RIFF']['raw']['strf']['vids']["{$streamindex}"]['biSizeImage'] = LittleEndian2Int(substr($strfData, 20, 4));
                                        // size of the bitmap data section of the image (the actual pixel data, excluding BITMAPINFOHEADER and RGBQUAD structures)
                                        $MP3fileInfo['RIFF']['raw']['strf']['vids']["{$streamindex}"]['biXPelsPerMeter'] = LittleEndian2Int(substr($strfData, 24, 4));
                                        // horizontal resolution, in pixels per metre, of the target device
                                        $MP3fileInfo['RIFF']['raw']['strf']['vids']["{$streamindex}"]['biYPelsPerMeter'] = LittleEndian2Int(substr($strfData, 28, 4));
                                        // vertical resolution, in pixels per metre, of the target device
                                        $MP3fileInfo['RIFF']['raw']['strf']['vids']["{$streamindex}"]['biClrUsed'] = LittleEndian2Int(substr($strfData, 32, 4));
                                        // actual number of color indices in the color table used by the bitmap. If this value is zero, the bitmap uses the maximum number of colors corresponding to the value of the biBitCount member for the compression mode specified by biCompression
                                        $MP3fileInfo['RIFF']['raw']['strf']['vids']["{$streamindex}"]['biClrImportant'] = LittleEndian2Int(substr($strfData, 36, 4));
                                        // number of color indices that are considered important for displaying the bitmap. If this value is zero, all colors are important
                                        $MP3fileInfo['RIFF']['video']["{$streamindex}"]['codec'] = RIFFfourccLookup($MP3fileInfo['RIFF']['raw']['strh']["{$i}"]['fccHandler']);
                                        if (!$MP3fileInfo['RIFF']['video']["{$streamindex}"]['codec'] && RIFFfourccLookup($MP3fileInfo['RIFF']['raw']['strf']['vids']["{$streamindex}"]['fourcc'])) {
                                            RIFFfourccLookup($MP3fileInfo['RIFF']['raw']['strf']['vids']["{$streamindex}"]['fourcc']);
                                        }
                                        break;
                                }
                            }
                        }
                    }
                }
            }
            break;
        default:
            unset($MP3fileInfo['fileformat']);
            break;
    }
    if (isset($MP3fileInfo['RIFF']['WAVE']['INFO']) && is_array($MP3fileInfo['RIFF']['WAVE']['INFO'])) {
        $MP3fileInfo['RIFF']['title'] = trim(substr($MP3fileInfo['RIFF']['WAVE']['INFO']['DISP'][count($MP3fileInfo['RIFF']['WAVE']['INFO']['DISP']) - 1]['data'], 4));
        $MP3fileInfo['RIFF']['artist'] = trim($MP3fileInfo['RIFF']['WAVE']['INFO']['IART'][count($MP3fileInfo['RIFF']['WAVE']['INFO']['IART']) - 1]['data']);
        $MP3fileInfo['RIFF']['genre'] = trim($MP3fileInfo['RIFF']['WAVE']['INFO']['IGNR'][count($MP3fileInfo['RIFF']['WAVE']['INFO']['IGNR']) - 1]['data']);
        $MP3fileInfo['RIFF']['comment'] = trim($MP3fileInfo['RIFF']['WAVE']['INFO']['ICMT'][count($MP3fileInfo['RIFF']['WAVE']['INFO']['ICMT']) - 1]['data']);
        $MP3fileInfo['RIFF']['copyright'] = trim($MP3fileInfo['RIFF']['WAVE']['INFO']['ICOP'][count($MP3fileInfo['RIFF']['WAVE']['INFO']['ICOP']) - 1]['data']);
        $MP3fileInfo['RIFF']['engineers'] = trim($MP3fileInfo['RIFF']['WAVE']['INFO']['IENG'][count($MP3fileInfo['RIFF']['WAVE']['INFO']['IENG']) - 1]['data']);
        $MP3fileInfo['RIFF']['keywords'] = trim($MP3fileInfo['RIFF']['WAVE']['INFO']['IKEY'][count($MP3fileInfo['RIFF']['WAVE']['INFO']['IKEY']) - 1]['data']);
        $MP3fileInfo['RIFF']['originalmedium'] = trim($MP3fileInfo['RIFF']['WAVE']['INFO']['IMED'][count($MP3fileInfo['RIFF']['WAVE']['INFO']['IMED']) - 1]['data']);
        $MP3fileInfo['RIFF']['name'] = trim($MP3fileInfo['RIFF']['WAVE']['INFO']['INAM'][count($MP3fileInfo['RIFF']['WAVE']['INFO']['INAM']) - 1]['data']);
        $MP3fileInfo['RIFF']['sourcesupplier'] = trim($MP3fileInfo['RIFF']['WAVE']['INFO']['ISRC'][count($MP3fileInfo['RIFF']['WAVE']['INFO']['ISRC']) - 1]['data']);
        $MP3fileInfo['RIFF']['digitizer'] = trim($MP3fileInfo['RIFF']['WAVE']['INFO']['ITCH'][count($MP3fileInfo['RIFF']['WAVE']['INFO']['ITCH']) - 1]['data']);
        $MP3fileInfo['RIFF']['subject'] = trim($MP3fileInfo['RIFF']['WAVE']['INFO']['ISBJ'][count($MP3fileInfo['RIFF']['WAVE']['INFO']['ISBJ']) - 1]['data']);
        $MP3fileInfo['RIFF']['digitizationsource'] = trim($MP3fileInfo['RIFF']['WAVE']['INFO']['ISRF'][count($MP3fileInfo['RIFF']['WAVE']['INFO']['ISRF']) - 1]['data']);
    }
    foreach ($MP3fileInfo['RIFF'] as $key => $value) {
        if (!is_array($value) && !$value) {
            unset($MP3fileInfo['RIFF']["{$key}"]);
        }
    }
    return TRUE;
}
function getRIFFHeaderFilepointer(&$fd, &$ThisFileInfo)
{
    fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
    $RIFFheader = fread($fd, 12);
    switch (substr($RIFFheader, 0, 4)) {
        case 'RIFF':
        case 'SDSS':
            // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com)
            $ThisFileInfo['fileformat'] = 'riff';
            $ThisFileInfo['RIFF'][substr($RIFFheader, 8, 4)] = ParseRIFF($fd, $ThisFileInfo['avdataoffset'] + 12, $ThisFileInfo['avdataoffset'] + LittleEndian2Int(substr($RIFFheader, 4, 4)), $ThisFileInfo);
            break;
        default:
            $ThisFileInfo['error'] .= "\n" . 'Cannot parse RIFF (this is maybe not a RIFF / WAV / AVI file?)';
            unset($ThisFileInfo['fileformat']);
            return false;
            break;
    }
    $streamindex = 0;
    $arraykeys = array_keys($ThisFileInfo['RIFF']);
    switch ($arraykeys[0]) {
        case 'WAVE':
            $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
            $ThisFileInfo['audio']['dataformat'] = 'wav';
            if (isset($ThisFileInfo['RIFF']['WAVE']['fmt '][0]['data'])) {
                $ThisFileInfo['RIFF']['audio'][$streamindex] = RIFFparseWAVEFORMATex($ThisFileInfo['RIFF']['WAVE']['fmt '][0]['data']);
                if ($ThisFileInfo['RIFF']['audio'][$streamindex] == 0) {
                    $ThisFileInfo['error'] .= 'Corrupt RIFF file: bitrate_audio == zero';
                    return false;
                }
                $ThisFileInfo['RIFF']['raw']['fmt '] = $ThisFileInfo['RIFF']['audio'][$streamindex]['raw'];
                unset($ThisFileInfo['RIFF']['audio'][$streamindex]['raw']);
                $ThisFileInfo['audio'] = array_merge_noclobber($ThisFileInfo['audio'], $ThisFileInfo['RIFF']['audio'][$streamindex]);
                $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['RIFF']['audio'][$streamindex]['bitrate'];
                $ThisFileInfo['playtime_seconds'] = (double) (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8 / $ThisFileInfo['audio']['bitrate']);
                if (isset($ThisFileInfo['RIFF']['WAVE']['data'][0]['offset']) && isset($ThisFileInfo['RIFF']['raw']['fmt ']['wFormatTag'])) {
                    switch ($ThisFileInfo['RIFF']['raw']['fmt ']['wFormatTag']) {
                        case 85:
                            // LAME ACM
                            require_once GETID3_INCLUDEPATH . 'getid3.mp3.php';
                            getOnlyMPEGaudioInfo($fd, $ThisFileInfo, $ThisFileInfo['RIFF']['WAVE']['data'][0]['offset'], false);
                            $ThisFileInfo['audio']['dataformat'] = 'mp3';
                            if (isset($ThisFileInfo['mpeg']['audio'])) {
                                $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['mpeg']['audio']['sample_rate'];
                                $ThisFileInfo['audio']['channels'] = $ThisFileInfo['mpeg']['audio']['channels'];
                                $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['mpeg']['audio']['bitrate'] * 1000;
                                $ThisFileInfo['bitrate'] = $ThisFileInfo['audio']['bitrate'];
                                $ThisFileInfo['audio']['bitrate_mode'] = strtolower($ThisFileInfo['mpeg']['audio']['bitratemode']);
                            }
                            break;
                        default:
                            // do nothing
                            break;
                    }
                }
            }
            if (isset($ThisFileInfo['RIFF']['WAVE']['rgad'][0]['data'])) {
                require_once GETID3_INCLUDEPATH . 'getid3.rgad.php';
                $rgadData = $ThisFileInfo['RIFF']['WAVE']['rgad'][0]['data'];
                $ThisFileInfo['RIFF']['raw']['rgad']['fPeakAmplitude'] = LittleEndian2Float(substr($rgadData, 0, 4));
                $ThisFileInfo['RIFF']['raw']['rgad']['nRadioRgAdjust'] = LittleEndian2Int(substr($rgadData, 4, 2));
                $ThisFileInfo['RIFF']['raw']['rgad']['nAudiophileRgAdjust'] = LittleEndian2Int(substr($rgadData, 6, 2));
                $nRadioRgAdjustBitstring = str_pad(Dec2Bin($ThisFileInfo['RIFF']['raw']['rgad']['nRadioRgAdjust']), 16, '0', STR_PAD_LEFT);
                $nAudiophileRgAdjustBitstring = str_pad(Dec2Bin($ThisFileInfo['RIFF']['raw']['rgad']['nAudiophileRgAdjust']), 16, '0', STR_PAD_LEFT);
                $ThisFileInfo['RIFF']['raw']['rgad']['radio']['name'] = Bin2Dec(substr($nRadioRgAdjustBitstring, 0, 3));
                $ThisFileInfo['RIFF']['raw']['rgad']['radio']['originator'] = Bin2Dec(substr($nRadioRgAdjustBitstring, 3, 3));
                $ThisFileInfo['RIFF']['raw']['rgad']['radio']['signbit'] = Bin2Dec(substr($nRadioRgAdjustBitstring, 6, 1));
                $ThisFileInfo['RIFF']['raw']['rgad']['radio']['adjustment'] = Bin2Dec(substr($nRadioRgAdjustBitstring, 7, 9));
                $ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['name'] = Bin2Dec(substr($nAudiophileRgAdjustBitstring, 0, 3));
                $ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['originator'] = Bin2Dec(substr($nAudiophileRgAdjustBitstring, 3, 3));
                $ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['signbit'] = Bin2Dec(substr($nAudiophileRgAdjustBitstring, 6, 1));
                $ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['adjustment'] = Bin2Dec(substr($nAudiophileRgAdjustBitstring, 7, 9));
                $ThisFileInfo['RIFF']['rgad']['peakamplitude'] = $ThisFileInfo['RIFF']['raw']['rgad']['fPeakAmplitude'];
                if ($ThisFileInfo['RIFF']['raw']['rgad']['radio']['name'] != 0 && $ThisFileInfo['RIFF']['raw']['rgad']['radio']['originator'] != 0) {
                    $ThisFileInfo['RIFF']['rgad']['radio']['name'] = RGADnameLookup($ThisFileInfo['RIFF']['raw']['rgad']['radio']['name']);
                    $ThisFileInfo['RIFF']['rgad']['radio']['originator'] = RGADoriginatorLookup($ThisFileInfo['RIFF']['raw']['rgad']['radio']['originator']);
                    $ThisFileInfo['RIFF']['rgad']['radio']['adjustment'] = RGADadjustmentLookup($ThisFileInfo['RIFF']['raw']['rgad']['radio']['adjustment'], $ThisFileInfo['RIFF']['raw']['rgad']['radio']['signbit']);
                }
                if ($ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['name'] != 0 && $ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['originator'] != 0) {
                    $ThisFileInfo['RIFF']['rgad']['audiophile']['name'] = RGADnameLookup($ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['name']);
                    $ThisFileInfo['RIFF']['rgad']['audiophile']['originator'] = RGADoriginatorLookup($ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['originator']);
                    $ThisFileInfo['RIFF']['rgad']['audiophile']['adjustment'] = RGADadjustmentLookup($ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['adjustment'], $ThisFileInfo['RIFF']['raw']['rgad']['audiophile']['signbit']);
                }
            }
            if (isset($ThisFileInfo['RIFF']['WAVE']['fact'][0]['data'])) {
                $ThisFileInfo['RIFF']['raw']['fact']['NumberOfSamples'] = LittleEndian2Int(substr($ThisFileInfo['RIFF']['WAVE']['fact'][0]['data'], 0, 4));
                if (isset($ThisFileInfo['RIFF']['raw']['fmt ']['nSamplesPerSec']) && $ThisFileInfo['RIFF']['raw']['fmt ']['nSamplesPerSec'] > 0) {
                    $ThisFileInfo['playtime_seconds'] = (double) $ThisFileInfo['RIFF']['raw']['fact']['NumberOfSamples'] / $ThisFileInfo['RIFF']['raw']['fmt ']['nSamplesPerSec'];
                }
                if (isset($ThisFileInfo['RIFF']['raw']['fmt ']['nAvgBytesPerSec']) && $ThisFileInfo['RIFF']['raw']['fmt ']['nAvgBytesPerSec']) {
                    $ThisFileInfo['audio']['bitrate'] = CastAsInt($ThisFileInfo['RIFF']['raw']['fmt ']['nAvgBytesPerSec'] * 8);
                }
            }
            if (!isset($ThisFileInfo['audio']['bitrate']) && isset($ThisFileInfo['RIFF']['audio'][$streamindex]['bitrate'])) {
                $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['RIFF']['audio'][$streamindex]['bitrate'];
                $ThisFileInfo['playtime_seconds'] = (double) (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8 / $ThisFileInfo['audio']['bitrate']);
            }
            break;
        case 'AVI ':
            $ThisFileInfo['video']['bitrate_mode'] = 'cbr';
            $ThisFileInfo['video']['dataformat'] = 'avi';
            $ThisFileInfo['mime_type'] = 'video/avi';
            if (isset($ThisFileInfo['RIFF']['AVI ']['hdrl']['avih'][$streamindex]['data'])) {
                $avihData = $ThisFileInfo['RIFF']['AVI ']['hdrl']['avih'][$streamindex]['data'];
                $ThisFileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'] = LittleEndian2Int(substr($avihData, 0, 4));
                // frame display rate (or 0L)
                if ($ThisFileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'] == 0) {
                    $ThisFileInfo['error'] .= 'Corrupt RIFF file: avih.dwMicroSecPerFrame == zero';
                    return false;
                }
                $ThisFileInfo['RIFF']['raw']['avih']['dwMaxBytesPerSec'] = LittleEndian2Int(substr($avihData, 4, 4));
                // max. transfer rate
                $ThisFileInfo['RIFF']['raw']['avih']['dwPaddingGranularity'] = LittleEndian2Int(substr($avihData, 8, 4));
                // pad to multiples of this size; normally 2K.
                $ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] = LittleEndian2Int(substr($avihData, 12, 4));
                // the ever-present flags
                $ThisFileInfo['RIFF']['raw']['avih']['dwTotalFrames'] = LittleEndian2Int(substr($avihData, 16, 4));
                // # frames in file
                $ThisFileInfo['RIFF']['raw']['avih']['dwInitialFrames'] = LittleEndian2Int(substr($avihData, 20, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwStreams'] = LittleEndian2Int(substr($avihData, 24, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwSuggestedBufferSize'] = LittleEndian2Int(substr($avihData, 28, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwWidth'] = LittleEndian2Int(substr($avihData, 32, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwHeight'] = LittleEndian2Int(substr($avihData, 36, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwScale'] = LittleEndian2Int(substr($avihData, 40, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwRate'] = LittleEndian2Int(substr($avihData, 44, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwStart'] = LittleEndian2Int(substr($avihData, 48, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['dwLength'] = LittleEndian2Int(substr($avihData, 52, 4));
                $ThisFileInfo['RIFF']['raw']['avih']['flags']['hasindex'] = (bool) ($ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x10);
                $ThisFileInfo['RIFF']['raw']['avih']['flags']['mustuseindex'] = (bool) ($ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x20);
                $ThisFileInfo['RIFF']['raw']['avih']['flags']['interleaved'] = (bool) ($ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x100);
                $ThisFileInfo['RIFF']['raw']['avih']['flags']['trustcktype'] = (bool) ($ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x800);
                $ThisFileInfo['RIFF']['raw']['avih']['flags']['capturedfile'] = (bool) ($ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x10000);
                $ThisFileInfo['RIFF']['raw']['avih']['flags']['copyrighted'] = (bool) ($ThisFileInfo['RIFF']['raw']['avih']['dwFlags'] & 0x20010);
                $ThisFileInfo['RIFF']['video'][$streamindex]['frame_width'] = $ThisFileInfo['RIFF']['raw']['avih']['dwWidth'];
                $ThisFileInfo['RIFF']['video'][$streamindex]['frame_height'] = $ThisFileInfo['RIFF']['raw']['avih']['dwHeight'];
                $ThisFileInfo['RIFF']['video'][$streamindex]['frame_rate'] = round(1000000 / $ThisFileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'], 3);
                if (!isset($ThisFileInfo['video']['resolution_x'])) {
                    $ThisFileInfo['video']['resolution_x'] = $ThisFileInfo['RIFF']['video'][$streamindex]['frame_width'];
                }
                if (!isset($ThisFileInfo['video']['resolution_y'])) {
                    $ThisFileInfo['video']['resolution_y'] = $ThisFileInfo['RIFF']['video'][$streamindex]['frame_height'];
                }
                $ThisFileInfo['video']['frame_rate'] = $ThisFileInfo['RIFF']['video'][$streamindex]['frame_rate'];
            }
            if (isset($ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strh'][0]['data'])) {
                if (is_array($ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strh'])) {
                    for ($i = 0; $i < count($ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strh']); $i++) {
                        if (isset($ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strh'][$i]['data'])) {
                            $strhData = $ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strh'][$i]['data'];
                            $strhfccType = substr($strhData, 0, 4);
                            if (isset($ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strf'][$i]['data'])) {
                                $strfData = $ThisFileInfo['RIFF']['AVI ']['hdrl']['strl']['strf'][$i]['data'];
                                switch ($strhfccType) {
                                    case 'auds':
                                        $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
                                        $ThisFileInfo['audio']['dataformat'] = 'wav';
                                        if (isset($ThisFileInfo['RIFF']['audio']) && is_array($ThisFileInfo['RIFF']['audio'])) {
                                            $streamindex = count($ThisFileInfo['RIFF']['audio']);
                                        }
                                        $ThisFileInfo['RIFF']['audio'][$streamindex] = RIFFparseWAVEFORMATex($strfData);
                                        $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex] = $ThisFileInfo['RIFF']['audio'][$streamindex]['raw'];
                                        unset($ThisFileInfo['RIFF']['audio'][$streamindex]['raw']);
                                        $ThisFileInfo['audio'] = array_merge_noclobber($ThisFileInfo['audio'], $ThisFileInfo['RIFF']['audio'][$streamindex]);
                                        switch ($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['wFormatTag']) {
                                            case 85:
                                                $ThisFileInfo['audio']['dataformat'] = 'mp3';
                                                break;
                                            case 8192:
                                                $ThisFileInfo['audio']['dataformat'] = 'ac3';
                                                break;
                                            default:
                                                $ThisFileInfo['audio']['dataformat'] = 'wav';
                                                break;
                                        }
                                        break;
                                    case 'iavs':
                                    case 'vids':
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['fccType'] = substr($strhData, 0, 4);
                                        // same as $strhfccType;
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['fccHandler'] = substr($strhData, 4, 4);
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwFlags'] = LittleEndian2Int(substr($strhData, 8, 4));
                                        // Contains AVITF_* flags
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['wPriority'] = LittleEndian2Int(substr($strhData, 12, 2));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['wLanguage'] = LittleEndian2Int(substr($strhData, 14, 2));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwInitialFrames'] = LittleEndian2Int(substr($strhData, 16, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwScale'] = LittleEndian2Int(substr($strhData, 20, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwRate'] = LittleEndian2Int(substr($strhData, 24, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwStart'] = LittleEndian2Int(substr($strhData, 28, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwLength'] = LittleEndian2Int(substr($strhData, 32, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwSuggestedBufferSize'] = LittleEndian2Int(substr($strhData, 36, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwQuality'] = LittleEndian2Int(substr($strhData, 40, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['dwSampleSize'] = LittleEndian2Int(substr($strhData, 44, 4));
                                        $ThisFileInfo['RIFF']['raw']['strh'][$i]['rcFrame'] = LittleEndian2Int(substr($strhData, 48, 4));
                                        $ThisFileInfo['RIFF']['video'][$streamindex]['codec'] = RIFFfourccLookup($ThisFileInfo['RIFF']['raw']['strh'][$i]['fccHandler']);
                                        if (!$ThisFileInfo['RIFF']['video'][$streamindex]['codec'] && isset($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc']) && RIFFfourccLookup($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc'])) {
                                            $ThisFileInfo['RIFF']['video'][$streamindex]['codec'] = RIFFfourccLookup($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc']);
                                        }
                                        $ThisFileInfo['video']['codec'] = $ThisFileInfo['RIFF']['video'][$streamindex]['codec'];
                                        switch ($strhfccType) {
                                            case 'vids':
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biSize'] = LittleEndian2Int(substr($strfData, 0, 4));
                                                // number of bytes required by the BITMAPINFOHEADER structure
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biWidth'] = LittleEndian2Int(substr($strfData, 4, 4));
                                                // width of the bitmap in pixels
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biHeight'] = LittleEndian2Int(substr($strfData, 8, 4));
                                                // height of the bitmap in pixels. If biHeight is positive, the bitmap is a 'bottom-up' DIB and its origin is the lower left corner. If biHeight is negative, the bitmap is a 'top-down' DIB and its origin is the upper left corner
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biPlanes'] = LittleEndian2Int(substr($strfData, 12, 2));
                                                // number of color planes on the target device. In most cases this value must be set to 1
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biBitCount'] = LittleEndian2Int(substr($strfData, 14, 2));
                                                // Specifies the number of bits per pixels
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc'] = substr($strfData, 16, 4);
                                                //
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biSizeImage'] = LittleEndian2Int(substr($strfData, 20, 4));
                                                // size of the bitmap data section of the image (the actual pixel data, excluding BITMAPINFOHEADER and RGBQUAD structures)
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biXPelsPerMeter'] = LittleEndian2Int(substr($strfData, 24, 4));
                                                // horizontal resolution, in pixels per metre, of the target device
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biYPelsPerMeter'] = LittleEndian2Int(substr($strfData, 28, 4));
                                                // vertical resolution, in pixels per metre, of the target device
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biClrUsed'] = LittleEndian2Int(substr($strfData, 32, 4));
                                                // actual number of color indices in the color table used by the bitmap. If this value is zero, the bitmap uses the maximum number of colors corresponding to the value of the biBitCount member for the compression mode specified by biCompression
                                                $ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['biClrImportant'] = LittleEndian2Int(substr($strfData, 36, 4));
                                                // number of color indices that are considered important for displaying the bitmap. If this value is zero, all colors are important
                                                if ($ThisFileInfo['RIFF']['video'][$streamindex]['codec'] == 'DV') {
                                                    $ThisFileInfo['RIFF']['video'][$streamindex]['dv_type'] = 2;
                                                }
                                                break;
                                            case 'iavs':
                                                $ThisFileInfo['RIFF']['video'][$streamindex]['dv_type'] = 1;
                                                break;
                                        }
                                        break;
                                    default:
                                        $ThisFileInfo['warning'] .= "\n" . 'Unhandled fccType for stream (' . $i . '): "' . $strhfccType . '"';
                                        break;
                                }
                            }
                        }
                        if (isset($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc']) && RIFFfourccLookup($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc'])) {
                            $ThisFileInfo['RIFF']['video'][$streamindex]['codec'] = RIFFfourccLookup($ThisFileInfo['RIFF']['raw']['strf']["{$strhfccType}"][$streamindex]['fourcc']);
                            $ThisFileInfo['video']['codec'] = $ThisFileInfo['RIFF']['video'][$streamindex]['codec'];
                        }
                    }
                }
            }
            break;
        case 'CDDA':
            $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
            $ThisFileInfo['audio']['dataformat'] = 'cda';
            unset($ThisFileInfo['mime_type']);
            if (isset($ThisFileInfo['RIFF']['CDDA']['fmt '][0]['data'])) {
                $fmtData = $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['data'];
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['unknown1'] = LittleEndian2Int(substr($fmtData, 0, 2));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['track_num'] = LittleEndian2Int(substr($fmtData, 2, 2));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['disc_id'] = LittleEndian2Int(substr($fmtData, 4, 4));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['start_offset_frame'] = LittleEndian2Int(substr($fmtData, 8, 4));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['playtime_frames'] = LittleEndian2Int(substr($fmtData, 12, 4));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['unknown6'] = LittleEndian2Int(substr($fmtData, 16, 4));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['unknown7'] = LittleEndian2Int(substr($fmtData, 20, 4));
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['start_offset_seconds'] = (double) $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['start_offset_frame'] / 75;
                $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['playtime_seconds'] = (double) $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['playtime_frames'] / 75;
                $ThisFileInfo['comments']['track'] = $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['track_num'];
                $ThisFileInfo['playtime_seconds'] = $ThisFileInfo['RIFF']['CDDA']['fmt '][0]['playtime_seconds'];
                // hardcoded data for CD-audio
                $ThisFileInfo['audio']['sample_rate'] = 44100;
                $ThisFileInfo['audio']['channels'] = 2;
                $ThisFileInfo['audio']['bits_per_sample'] = 16;
                $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['audio']['sample_rate'] * $ThisFileInfo['audio']['channels'] * $ThisFileInfo['audio']['bits_per_sample'];
                $ThisFileInfo['audio']['bitrate_mode'] = 'cbr';
            }
            break;
        default:
            unset($ThisFileInfo['fileformat']);
            break;
    }
    if (isset($ThisFileInfo['RIFF']['WAVE']['DISP']) && is_array($ThisFileInfo['RIFF']['WAVE']['DISP'])) {
        $ThisFileInfo['tags'][] = 'riff';
        $ThisFileInfo['RIFF']['comments']['title'][] = trim(substr($ThisFileInfo['RIFF']['WAVE']['DISP'][count($ThisFileInfo['RIFF']['WAVE']['DISP']) - 1]['data'], 4));
    }
    if (isset($ThisFileInfo['RIFF']['WAVE']['INFO']) && is_array($ThisFileInfo['RIFF']['WAVE']['INFO'])) {
        $ThisFileInfo['tags'][] = 'riff';
        $RIFFinfoKeyLookup = array('IART' => 'artist', 'IGNR' => 'genre', 'ICMT' => 'comment', 'ICOP' => 'copyright', 'IENG' => 'engineers', 'IKEY' => 'keywords', 'IMED' => 'orignalmedium', 'INAM' => 'name', 'ISRC' => 'sourcesupplier', 'ITCH' => 'digitizer', 'ISBJ' => 'subject', 'ISRF' => 'digitizationsource');
        foreach ($RIFFinfoKeyLookup as $key => $value) {
            foreach ($ThisFileInfo['RIFF']['WAVE']['INFO']["{$key}"] as $commentid => $commentdata) {
                if (trim($commentdata['data']) != '') {
                    $ThisFileInfo['RIFF']['comments']["{$value}"][] = trim($commentdata['data']);
                }
            }
        }
    }
    if (!empty($ThisFileInfo['RIFF']['comments'])) {
        CopyFormatCommentsToRootComments($ThisFileInfo['RIFF']['comments'], $ThisFileInfo, true, true, true);
    }
    if (!isset($ThisFileInfo['playtime_seconds'])) {
        $ThisFileInfo['playtime_seconds'] = 0;
    }
    if (isset($ThisFileInfo['RIFF']['raw']['avih']['dwTotalFrames']) && isset($ThisFileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'])) {
        $ThisFileInfo['playtime_seconds'] = $ThisFileInfo['RIFF']['raw']['avih']['dwTotalFrames'] * ($ThisFileInfo['RIFF']['raw']['avih']['dwMicroSecPerFrame'] / 1000000);
    }
    if ($ThisFileInfo['playtime_seconds'] > 0) {
        if (isset($ThisFileInfo['RIFF']['audio']) && isset($ThisFileInfo['RIFF']['video'])) {
            if (!isset($ThisFileInfo['bitrate'])) {
                $ThisFileInfo['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / $ThisFileInfo['playtime_seconds'] * 8;
            }
        } elseif (isset($ThisFileInfo['RIFF']['audio']) && !isset($ThisFileInfo['RIFF']['video'])) {
            if (!isset($ThisFileInfo['audio']['bitrate'])) {
                $ThisFileInfo['audio']['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / $ThisFileInfo['playtime_seconds'] * 8;
            }
        } elseif (!isset($ThisFileInfo['RIFF']['audio']) && isset($ThisFileInfo['RIFF']['video'])) {
            if (!isset($ThisFileInfo['video']['bitrate'])) {
                $ThisFileInfo['video']['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / $ThisFileInfo['playtime_seconds'] * 8;
            }
        }
    }
    if (isset($ThisFileInfo['RIFF']['video']) && isset($ThisFileInfo['audio']['bitrate']) && $ThisFileInfo['audio']['bitrate'] > 0 && $ThisFileInfo['playtime_seconds'] > 0) {
        $ThisFileInfo['audio']['bitrate'] = 0;
        $ThisFileInfo['video']['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / $ThisFileInfo['playtime_seconds'] * 8;
        foreach ($ThisFileInfo['RIFF']['audio'] as $channelnumber => $audioinfoarray) {
            $ThisFileInfo['video']['bitrate'] -= $audioinfoarray['bitrate'];
            $ThisFileInfo['audio']['bitrate'] += $audioinfoarray['bitrate'];
        }
        if ($ThisFileInfo['video']['bitrate'] <= 0) {
            unset($ThisFileInfo['video']['bitrate']);
        }
        if ($ThisFileInfo['audio']['bitrate'] <= 0) {
            unset($ThisFileInfo['audio']['bitrate']);
        }
    }
    if (!empty($ThisFileInfo['RIFF']['raw']['fmt ']['nBitsPerSample'])) {
        $ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['RIFF']['raw']['fmt ']['nBitsPerSample'];
    }
    // Skip RIFF header
    $ThisFileInfo['avdataoffset'] += 44;
    return true;
}
function getID3v2Filepointer($fd, &$MP3fileInfo)
{
    //	Overall tag structure:
    //		+-----------------------------+
    //		|      Header (10 bytes)      |
    //		+-----------------------------+
    //		|       Extended Header       |
    //		| (variable length, OPTIONAL) |
    //		+-----------------------------+
    //		|   Frames (variable length)  |
    //		+-----------------------------+
    //		|           Padding           |
    //		| (variable length, OPTIONAL) |
    //		+-----------------------------+
    //		| Footer (10 bytes, OPTIONAL) |
    //		+-----------------------------+
    //	Header
    //		ID3v2/file identifier      "ID3"
    //		ID3v2 version              $04 00
    //		ID3v2 flags                (%ab000000 in v2.2, %abc00000 in v2.3, %abcd0000 in v2.4.x)
    //		ID3v2 size             4 * %0xxxxxxx
    rewind($fd);
    $header = fread($fd, 10);
    if (substr($header, 0, 3) == 'ID3') {
        $MP3fileInfo['id3']['id3v2']['header'] = TRUE;
        $MP3fileInfo['id3']['id3v2']['majorversion'] = ord($header[3]);
        $MP3fileInfo['id3']['id3v2']['minorversion'] = ord($header[4]);
    }
    if (isset($MP3fileInfo['id3']['id3v2']['header']) && $MP3fileInfo['id3']['id3v2']['majorversion'] <= 4) {
        // this script probably won't correctly parse ID3v2.5.x and above.
        $id3_flags = BigEndian2Bin($header[5]);
        if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 2) {
            // %ab000000 in v2.2
            $MP3fileInfo['id3']['id3v2']['flags']['unsynch'] = $id3_flags[0];
            // a - Unsynchronisation
            $MP3fileInfo['id3']['id3v2']['flags']['compression'] = $id3_flags[1];
            // b - Compression
        } else {
            if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 3) {
                // %abc00000 in v2.3
                $MP3fileInfo['id3']['id3v2']['flags']['unsynch'] = $id3_flags[0];
                // a - Unsynchronisation
                $MP3fileInfo['id3']['id3v2']['flags']['exthead'] = $id3_flags[1];
                // b - Extended header
                $MP3fileInfo['id3']['id3v2']['flags']['experim'] = $id3_flags[2];
                // c - Experimental indicator
            } else {
                if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 4) {
                    // %abcd0000 in v2.4
                    $MP3fileInfo['id3']['id3v2']['flags']['unsynch'] = $id3_flags[0];
                    // a - Unsynchronisation
                    $MP3fileInfo['id3']['id3v2']['flags']['exthead'] = $id3_flags[1];
                    // b - Extended header
                    $MP3fileInfo['id3']['id3v2']['flags']['experim'] = $id3_flags[2];
                    // c - Experimental indicator
                    $MP3fileInfo['id3']['id3v2']['flags']['isfooter'] = $id3_flags[3];
                    // d - Footer present
                }
            }
        }
        $MP3fileInfo['id3']['id3v2']['headerlength'] = BigEndian2Int(substr($header, 6, 4), 1) + ID3v2HeaderLength($MP3fileInfo['id3']['id3v2']['majorversion']);
        //	Extended Header
        if (isset($MP3fileInfo['id3']['id3v2']['flags']['exthead']) && $MP3fileInfo['id3']['id3v2']['flags']['exthead']) {
            //			Extended header size   4 * %0xxxxxxx
            //			Number of flag bytes       $01
            //			Extended Flags             $xx
            //			Where the 'Extended header size' is the size of the whole extended header, stored as a 32 bit synchsafe integer.
            $extheader = fread($fd, 4);
            $MP3fileInfo['id3']['id3v2']['extheaderlength'] = BigEndian2Int($extheader, 1);
            //			The extended flags field, with its size described by 'number of flag  bytes', is defined as:
            //				%0bcd0000
            //			b - Tag is an update
            //				Flag data length       $00
            //			c - CRC data present
            //				Flag data length       $05
            //				Total frame CRC    5 * %0xxxxxxx
            //			d - Tag restrictions
            //				Flag data length       $01
            $extheaderflagbytes = fread($fd, 1);
            $extheaderflags = fread($fd, $extheaderflagbytes);
            $id3_exthead_flags = BigEndian2Bin(substr($header, 5, 1));
            $MP3fileInfo['id3']['id3v2']['exthead_flags']['update'] = substr($id3_exthead_flags, 1, 1);
            $MP3fileInfo['id3']['id3v2']['exthead_flags']['CRC'] = substr($id3_exthead_flags, 2, 1);
            if ($MP3fileInfo['id3']['id3v2']['exthead_flags']['CRC']) {
                $extheaderrawCRC = fread($fd, 5);
                $MP3fileInfo['id3']['id3v2']['exthead_flags']['CRC'] = BigEndian2Int($extheaderrawCRC, 1);
            }
            $MP3fileInfo['id3']['id3v2']['exthead_flags']['restrictions'] = substr($id3_exthead_flags, 3, 1);
            if ($MP3fileInfo['id3']['id3v2']['exthead_flags']['restrictions']) {
                // Restrictions           %ppqrrstt
                $extheaderrawrestrictions = fread($fd, 1);
                $MP3fileInfo['id3']['id3v2']['exthead_flags']['restrictions_tagsize'] = (bindec('11000000') & ord($extheaderrawrestrictions)) >> 6;
                // p - Tag size restrictions
                $MP3fileInfo['id3']['id3v2']['exthead_flags']['restrictions_textenc'] = (bindec('00100000') & ord($extheaderrawrestrictions)) >> 5;
                // q - Text encoding restrictions
                $MP3fileInfo['id3']['id3v2']['exthead_flags']['restrictions_textsize'] = (bindec('00011000') & ord($extheaderrawrestrictions)) >> 3;
                // r - Text fields size restrictions
                $MP3fileInfo['id3']['id3v2']['exthead_flags']['restrictions_imgenc'] = (bindec('00000100') & ord($extheaderrawrestrictions)) >> 2;
                // s - Image encoding restrictions
                $MP3fileInfo['id3']['id3v2']['exthead_flags']['restrictions_imgsize'] = (bindec('00000011') & ord($extheaderrawrestrictions)) >> 0;
                // t - Image size restrictions
            }
        }
        // end extended header
        //	Frames
        //		All ID3v2 frames consists of one frame header followed by one or more
        //		fields containing the actual information. The header is always 10
        //		bytes and laid out as follows:
        //
        //		Frame ID      $xx xx xx xx  (four characters)
        //		Size      4 * %0xxxxxxx
        //		Flags         $xx xx
        $sizeofframes = $MP3fileInfo['id3']['id3v2']['headerlength'] - ID3v2HeaderLength($MP3fileInfo['id3']['id3v2']['majorversion']);
        if (isset($MP3fileInfo['id3']['id3v2']['extheaderlength'])) {
            $sizeofframes -= $MP3fileInfo['id3']['id3v2']['extheaderlength'];
        }
        if (isset($MP3fileInfo['id3']['id3v2']['flags']['isfooter']) && $MP3fileInfo['id3']['id3v2']['flags']['isfooter']) {
            $sizeofframes -= 10;
            // footer takes last 10 bytes of ID3v2 header, after frame data, before audio
        }
        if ($sizeofframes > 0) {
            $framedata = fread($fd, $sizeofframes);
            // read all frames from file into $framedata variable
            //	if entire frame data is unsynched, de-unsynch it now (ID3v2.3.x)
            if (isset($MP3fileInfo['id3']['id3v2']['flags']['unsynch']) && $MP3fileInfo['id3']['id3v2']['flags']['unsynch'] && $MP3fileInfo['id3']['id3v2']['majorversion'] <= 3) {
                $framedata = DeUnSynchronise($framedata);
            }
            //		[in ID3v2.4.0] Unsynchronisation [S:6.1] is done on frame level, instead
            //		of on tag level, making it easier to skip frames, increasing the streamability
            //		of the tag. The unsynchronisation flag in the header [S:3.1] indicates that
            //		there exists an unsynchronised frame, while the new unsynchronisation flag in
            //		the frame header [S:4.1.2] indicates unsynchronisation.
            include_once GETID3_INCLUDEPATH . 'getid3.frames.php';
            // ID3v2FrameProcessing()
            $framedataoffset = 10;
            // how many bytes into the stream - start from after the 10-byte header
            while (isset($framedata) && strlen($framedata) > 0) {
                // cycle through until no more frame data is left to parse
                if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 2) {
                    // Frame ID  $xx xx xx (three characters)
                    // Size      $xx xx xx (24-bit integer)
                    // Flags     $xx xx
                    $frame_header = substr($framedata, 0, 6);
                    // take next 6 bytes for header
                    $framedata = substr($framedata, 6);
                    // and leave the rest in $framedata
                    $frame_name = substr($frame_header, 0, 3);
                    $frame_size = BigEndian2Int(substr($frame_header, 3, 3), 0);
                    $frame_flags = '';
                    // not used for anything, just to avoid E_NOTICEs
                } else {
                    if ($MP3fileInfo['id3']['id3v2']['majorversion'] > 2) {
                        // Frame ID  $xx xx xx xx (four characters)
                        // Size      $xx xx xx xx (32-bit integer in v2.3, 28-bit synchsafe in v2.4+)
                        // Flags     $xx xx
                        $frame_header = substr($framedata, 0, 10);
                        // take next 10 bytes for header
                        $framedata = substr($framedata, 10);
                        // and leave the rest in $framedata
                        $frame_name = substr($frame_header, 0, 4);
                        if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 3) {
                            $frame_size = BigEndian2Int(substr($frame_header, 4, 4), 0);
                            // 32-bit integer
                        } else {
                            // ID3v2.4+
                            $frame_size = BigEndian2Int(substr($frame_header, 4, 4), 1);
                            // 32-bit synchsafe integer (28-bit value)
                        }
                        if ($frame_size < strlen($framedata) + 4) {
                            $nextFrameID = substr($framedata, $frame_size, 4);
                            if (IsValidID3v2FrameName($nextFrameID, $MP3fileInfo['id3']['id3v2']['majorversion'])) {
                                // next frame is OK
                            } else {
                                if ($frame_name == chr(0) . 'MP3' || $frame_name == ' MP3' || $frame_name == 'MP3e') {
                                    // MP3ext known broken frames - "ok" for the purposes of this test
                                } else {
                                    if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 4 && IsValidID3v2FrameName(substr($framedata, BigEndian2Int(substr($frame_header, 4, 4), 0), 4), 3)) {
                                        $MP3fileInfo['error'] .= "\n" . 'ID3v2 tag written as ID3v2.4, but with non-synchsafe integers (ID3v2.3 style). Older versions of Helium2 (www.helium2.com) is a known culprit of this. Tag has been parsed as ID3v2.3';
                                        $MP3fileInfo['id3']['id3v2']['majorversion'] = 3;
                                        $frame_size = BigEndian2Int(substr($frame_header, 4, 4), 0);
                                        // 32-bit integer
                                    }
                                }
                            }
                        }
                        $frame_flags = BigEndian2Bin(substr($frame_header, 8, 2));
                    }
                }
                if ($frame_name == chr(0) . chr(0) . chr(0) . chr(0)) {
                    // padding encountered
                    // $MP3fileInfo['id3']['id3v2']['padding']['start']  = $MP3fileInfo['id3']['id3v2']['headerlength'] - strlen($framedata);
                    $MP3fileInfo['id3']['id3v2']['padding']['start'] = $framedataoffset;
                    $MP3fileInfo['id3']['id3v2']['padding']['length'] = strlen($framedata);
                    $MP3fileInfo['id3']['id3v2']['padding']['valid'] = TRUE;
                    for ($i = 0; $i < $MP3fileInfo['id3']['id3v2']['padding']['length']; $i++) {
                        if (substr($framedata, $i, 1) != chr(0)) {
                            $MP3fileInfo['id3']['id3v2']['padding']['valid'] = FALSE;
                            $MP3fileInfo['id3']['id3v2']['padding']['errorpos'] = $MP3fileInfo['id3']['id3v2']['padding']['start'] + $i;
                            break;
                        }
                    }
                    break;
                    // skip rest of ID3v2 header
                }
                if ($frame_size <= strlen($framedata) && IsValidID3v2FrameName($frame_name, $MP3fileInfo['id3']['id3v2']['majorversion'])) {
                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['data'] = substr($framedata, 0, $frame_size);
                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['datalength'] = CastAsInt($frame_size);
                    $MP3fileInfo['id3']['id3v2']["{$frame_name}"]['dataoffset'] = $framedataoffset;
                    $framedata = substr($framedata, $frame_size);
                    // in getid3.frames.php - this function does all the FrameID-level parsing
                    ID3v2FrameProcessing($frame_name, $frame_flags, $MP3fileInfo);
                    $framedataoffset += $frame_size + ID3v2HeaderLength($MP3fileInfo['id3']['id3v2']['majorversion']);
                } else {
                    // invalid frame length or FrameID
                    $MP3fileInfo['error'] .= "\n" . 'error parsing "' . $frame_name . '" (' . $framedataoffset . ' bytes into the ID3v2.' . $MP3fileInfo['id3']['id3v2']['majorversion'] . ' tag).';
                    if ($frame_size > strlen($framedata)) {
                        $MP3fileInfo['error'] .= ' (ERROR: $frame_size (' . $frame_size . ') > strlen($framedata) (' . strlen($framedata) . ')).';
                    }
                    if (!IsValidID3v2FrameName($frame_name, $MP3fileInfo['id3']['id3v2']['majorversion'])) {
                        $MP3fileInfo['error'] .= ' (ERROR: !IsValidID3v2FrameName("' . str_replace(chr(0), ' ', $frame_name) . '", ' . $MP3fileInfo['id3']['id3v2']['majorversion'] . '))).';
                        if ($frame_name == chr(0) . 'MP3' || $frame_name == ' MP3' || $frame_name == 'MP3e') {
                            $MP3fileInfo['error'] .= ' [Note: this particular error has been known to happen with tags edited by "MP3ext V3.3.17(unicode)"]';
                        } else {
                            if ($frame_name == 'COM ') {
                                $MP3fileInfo['error'] .= ' [Note: this particular error has been known to happen with tags edited by "iTunes X v2.0.3"]';
                            }
                        }
                    }
                    if ($frame_size <= strlen($framedata) && IsValidID3v2FrameName(substr($framedata, $frame_size, 4), $MP3fileInfo['id3']['id3v2']['majorversion'])) {
                        // next frame is valid, just skip the current frame
                        $framedata = substr($framedata, $frame_size);
                    } else {
                        // next frame is invalid too, abort processing
                        unset($framedata);
                    }
                }
            }
        }
        //	Footer
        //	The footer is a copy of the header, but with a different identifier.
        //		ID3v2 identifier           "3DI"
        //		ID3v2 version              $04 00
        //		ID3v2 flags                %abcd0000
        //		ID3v2 size             4 * %0xxxxxxx
        if (isset($MP3fileInfo['id3']['id3v2']['flags']['isfooter']) && $MP3fileInfo['id3']['id3v2']['flags']['isfooter']) {
            $footer = fread($fd, 10);
            if (substr($footer, 0, 3) == '3DI') {
                $MP3fileInfo['id3']['id3v2']['footer'] = true;
                $MP3fileInfo['id3']['id3v2']['majorversion_footer'] = ord(substr($footer, 3, 1));
                $MP3fileInfo['id3']['id3v2']['minorversion_footer'] = ord(substr($footer, 4, 1));
            }
            if ($MP3fileInfo['id3']['id3v2']['majorversion_footer'] <= 4) {
                $id3_flags = BigEndian2Bin(substr($footer, 5, 1));
                $MP3fileInfo['id3']['id3v2']['flags']['unsynch_footer'] = substr($id3_flags, 0, 1);
                $MP3fileInfo['id3']['id3v2']['flags']['extfoot_footer'] = substr($id3_flags, 1, 1);
                $MP3fileInfo['id3']['id3v2']['flags']['experim_footer'] = substr($id3_flags, 2, 1);
                $MP3fileInfo['id3']['id3v2']['flags']['isfooter_footer'] = substr($id3_flags, 3, 1);
                $MP3fileInfo['id3']['id3v2']['footerlength'] = BigEndian2Int(substr($footer, 6, 4), 1);
            }
        }
        // end footer
        // Translate most common ID3v2 FrameIDs to easier-to-understand names
        if ($MP3fileInfo['id3']['id3v2']['majorversion'] == 2) {
            if (isset($MP3fileInfo['id3']['id3v2']['TT2'])) {
                $MP3fileInfo['id3']['id3v2']['title'] = $MP3fileInfo['id3']['id3v2']['TT2']['asciidata'];
            }
            if (isset($MP3fileInfo['id3']['id3v2']['TP1'])) {
                $MP3fileInfo['id3']['id3v2']['artist'] = $MP3fileInfo['id3']['id3v2']['TP1']['asciidata'];
            }
            if (isset($MP3fileInfo['id3']['id3v2']['TAL'])) {
                $MP3fileInfo['id3']['id3v2']['album'] = $MP3fileInfo['id3']['id3v2']['TAL']['asciidata'];
            }
            if (isset($MP3fileInfo['id3']['id3v2']['TYE'])) {
                $MP3fileInfo['id3']['id3v2']['year'] = $MP3fileInfo['id3']['id3v2']['TYE']['asciidata'];
            }
            if (isset($MP3fileInfo['id3']['id3v2']['TRK'])) {
                $MP3fileInfo['id3']['id3v2']['track'] = $MP3fileInfo['id3']['id3v2']['TRK']['asciidata'];
            }
            if (isset($MP3fileInfo['id3']['id3v2']['TCO'])) {
                $MP3fileInfo['id3']['id3v2']['genre'] = $MP3fileInfo['id3']['id3v2']['TCO']['asciidata'];
            }
            if (isset($MP3fileInfo['id3']['id3v2']['COM'][0]['asciidata'])) {
                $MP3fileInfo['id3']['id3v2']['comment'] = $MP3fileInfo['id3']['id3v2']['COM'][0]['asciidata'];
            }
        } else {
            // $MP3fileInfo['id3']['id3v2']['majorversion'] > 2
            if (isset($MP3fileInfo['id3']['id3v2']['TIT2'])) {
                $MP3fileInfo['id3']['id3v2']['title'] = $MP3fileInfo['id3']['id3v2']['TIT2']['asciidata'];
            }
            if (isset($MP3fileInfo['id3']['id3v2']['TPE1'])) {
                $MP3fileInfo['id3']['id3v2']['artist'] = $MP3fileInfo['id3']['id3v2']['TPE1']['asciidata'];
            }
            if (isset($MP3fileInfo['id3']['id3v2']['TALB'])) {
                $MP3fileInfo['id3']['id3v2']['album'] = $MP3fileInfo['id3']['id3v2']['TALB']['asciidata'];
            }
            if (isset($MP3fileInfo['id3']['id3v2']['TYER'])) {
                $MP3fileInfo['id3']['id3v2']['year'] = $MP3fileInfo['id3']['id3v2']['TYER']['asciidata'];
            }
            if (isset($MP3fileInfo['id3']['id3v2']['TRCK'])) {
                $MP3fileInfo['id3']['id3v2']['track'] = $MP3fileInfo['id3']['id3v2']['TRCK']['asciidata'];
            }
            if (isset($MP3fileInfo['id3']['id3v2']['TCON'])) {
                $MP3fileInfo['id3']['id3v2']['genre'] = $MP3fileInfo['id3']['id3v2']['TCON']['asciidata'];
            }
            if (isset($MP3fileInfo['id3']['id3v2']['COMM'][0]['asciidata'])) {
                $MP3fileInfo['id3']['id3v2']['comment'] = $MP3fileInfo['id3']['id3v2']['COMM'][0]['asciidata'];
            }
        }
        if (isset($MP3fileInfo['id3']['id3v2']['genre'])) {
            $MP3fileInfo['id3']['id3v2']['genrelist'] = ParseID3v2GenreString($MP3fileInfo['id3']['id3v2']['genre']);
            if ($MP3fileInfo['id3']['id3v2']['genrelist']['genreid'][0] !== '') {
                $MP3fileInfo['id3']['id3v2']['genreid'] = $MP3fileInfo['id3']['id3v2']['genrelist']['genreid'][0];
            }
            $MP3fileInfo['id3']['id3v2']['genre'] = $MP3fileInfo['id3']['id3v2']['genrelist']['genre'][0];
        }
        if (isset($MP3fileInfo['id3']['id3v2']['track']) && strpos($MP3fileInfo['id3']['id3v2']['track'], '/') !== FALSE) {
            $tracktotaltracks = explode('/', $MP3fileInfo['id3']['id3v2']['track']);
            $MP3fileInfo['id3']['id3v2']['track'] = $tracktotaltracks[0];
            $MP3fileInfo['id3']['id3v2']['totaltracks'] = $tracktotaltracks[1];
        }
    } else {
        // MajorVersion is > 4, or no ID3v2 header present
        if (isset($MP3fileInfo['id3']['id3v2']['header'])) {
            // MajorVersion is > 4
            $MP3fileInfo['error'] .= "\n" . 'this script only parses up to ID3v2.4.x - this tag is ID3v2.' . $MP3fileInfo['id3']['id3v2']['majorversion'] . '.' . $MP3fileInfo['id3']['id3v2']['minorversion'];
        } else {
            // no ID3v2 header present - this is fine, just don't process anything.
        }
    }
    return TRUE;
}