: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
$RIFFchunk['amvh']['us_per_frame'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 12, 4));
$RIFFchunk['amvh']['reserved28'] = substr($AMVheader, 16, 28); // null? reserved?
$RIFFchunk['amvh']['resolution_x'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 44, 4));
$RIFFchunk['amvh']['resolution_y'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 48, 4));
$RIFFchunk['amvh']['frame_rate_int'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 52, 4));
$RIFFchunk['amvh']['reserved0'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 56, 4)); // 1? reserved?
$RIFFchunk['amvh']['reserved1'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 60, 4)); // 0? reserved?
$RIFFchunk['amvh']['runtime_sec'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 64, 1));
$RIFFchunk['amvh']['runtime_min'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 65, 1));
$RIFFchunk['amvh']['runtime_hrs'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 66, 2));
$info['video']['frame_rate'] = 1000000 / $RIFFchunk['amvh']['us_per_frame'];
$info['video']['resolution_x'] = $RIFFchunk['amvh']['resolution_x'];
$info['video']['resolution_y'] = $RIFFchunk['amvh']['resolution_y'];
$info['playtime_seconds'] = ($RIFFchunk['amvh']['runtime_hrs'] * 3600) + ($RIFFchunk['amvh']['runtime_min'] * 60) + $RIFFchunk['amvh']['runtime_sec'];
// the rest is all hardcoded(?) and does not appear to be useful until you get to audio info at offset 256, even then everything is probably hardcoded
if (substr($AMVheader, 68, 20) != 'LIST'."\x00\x00\x00\x00".'strlstrh'."\x38\x00\x00\x00") {
throw new Exception('expecting "LIST<0x00000000>strlstrh<0x38000000>" at offset '.($startoffset + 68).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader, 68, 20)).'"');
// followed by 56 bytes of null: substr($AMVheader, 88, 56) -> 144
if (substr($AMVheader, 144, 8) != 'strf'."\x24\x00\x00\x00") {
throw new Exception('expecting "strf<0x24000000>" at offset '.($startoffset + 144).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader, 144, 8)).'"');
// followed by 36 bytes of null: substr($AMVheader, 144, 36) -> 180
if (substr($AMVheader, 188, 20) != 'LIST'."\x00\x00\x00\x00".'strlstrh'."\x30\x00\x00\x00") {
throw new Exception('expecting "LIST<0x00000000>strlstrh<0x30000000>" at offset '.($startoffset + 188).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader, 188, 20)).'"');
// followed by 48 bytes of null: substr($AMVheader, 208, 48) -> 256
if (substr($AMVheader, 256, 8) != 'strf'."\x14\x00\x00\x00") {
throw new Exception('expecting "strf<0x14000000>" at offset '.($startoffset + 256).', found "'.getid3_lib::PrintHexBytes(substr($AMVheader, 256, 8)).'"');
// followed by 20 bytes of a modified WAVEFORMATEX:
// WORD wFormatTag; //(Fixme: this is equal to PCM's 0x01 format code)
// WORD nChannels; //(Fixme: this is always 1)
// DWORD nSamplesPerSec; //(Fixme: for all known sample files this is equal to 22050)
// DWORD nAvgBytesPerSec; //(Fixme: for all known sample files this is equal to 44100)
// WORD nBlockAlign; //(Fixme: this seems to be 2 in AMV files, is this correct ?)
// WORD wBitsPerSample; //(Fixme: this seems to be 16 in AMV files instead of the expected 4)
// WORD cbSize; //(Fixme: this seems to be 0 in AMV files)
$RIFFchunk['strf']['wformattag'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 264, 2));
$RIFFchunk['strf']['nchannels'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 266, 2));
$RIFFchunk['strf']['nsamplespersec'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 268, 4));
$RIFFchunk['strf']['navgbytespersec'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 272, 4));
$RIFFchunk['strf']['nblockalign'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 276, 2));
$RIFFchunk['strf']['wbitspersample'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 278, 2));
$RIFFchunk['strf']['cbsize'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 280, 2));
$RIFFchunk['strf']['reserved'] = getid3_lib::LittleEndian2Int(substr($AMVheader, 282, 2));
$info['audio']['lossless'] = false;
$info['audio']['sample_rate'] = $RIFFchunk['strf']['nsamplespersec'];
$info['audio']['channels'] = $RIFFchunk['strf']['nchannels'];
$info['audio']['bits_per_sample'] = $RIFFchunk['strf']['wbitspersample'];
$info['audio']['bitrate'] = $info['audio']['sample_rate'] * $info['audio']['channels'] * $info['audio']['bits_per_sample'];
$info['audio']['bitrate_mode'] = 'cbr';
} catch (getid3_exception $e) {
if ($e->getCode() == 10) {
$this->warning('RIFFAMV parser: '.$e->getMessage());
* @param int $startoffset
* @throws getid3_exception
public function ParseRIFF($startoffset, $maxoffset) {
$info = &$this->getid3->info;
$FoundAllChunksWeNeed = false;
$LISTchunkMaxOffset = null;
$AC3syncwordBytes = pack('n', getid3_ac3::syncword); // 0x0B77 -> "\x0B\x77"
$this->fseek($startoffset);
$maxoffset = min($maxoffset, $info['avdataend']);
while ($this->ftell() < $maxoffset) {
$chunknamesize = $this->fread(8);
//$chunkname = substr($chunknamesize, 0, 4);
$chunkname = str_replace("\x00", '_', substr($chunknamesize, 0, 4)); // note: chunk names of 4 null bytes do appear to be legal (has been observed inside INFO and PRMI chunks, for example), but makes traversing array keys more difficult
$chunksize = $this->EitherEndian2Int(substr($chunknamesize, 4, 4));
//if (strlen(trim($chunkname, "\x00")) < 4) {
if (strlen($chunkname) < 4) {
$this->error('Expecting chunk name at offset '.($this->ftell() - 8).' but found nothing. Aborting RIFF parsing.');
if (($chunksize == 0) && ($chunkname != 'JUNK')) {
$this->warning('Chunk ('.$chunkname.') size at offset '.($this->ftell() - 4).' is zero. Aborting RIFF parsing.');
if (($chunksize % 2) != 0) {
// all structures are packed on word boundaries
$listname = $this->fread(4);
if (preg_match('#^(movi|rec )$#i', $listname)) {
$RIFFchunk[$listname]['offset'] = $this->ftell() - 4;
$RIFFchunk[$listname]['size'] = $chunksize;
if (!$FoundAllChunksWeNeed) {
$WhereWeWere = $this->ftell();
$AudioChunkHeader = $this->fread(12);
$AudioChunkStreamNum = substr($AudioChunkHeader, 0, 2);
$AudioChunkStreamType = substr($AudioChunkHeader, 2, 2);
$AudioChunkSize = getid3_lib::LittleEndian2Int(substr($AudioChunkHeader, 4, 4));
if ($AudioChunkStreamType == 'wb') {
$FirstFourBytes = substr($AudioChunkHeader, 8, 4);
if (preg_match('/^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]/s', $FirstFourBytes)) {
if (getid3_mp3::MPEGaudioHeaderBytesValid($FirstFourBytes)) {
$getid3_temp = new getID3();
$getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
$getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
$getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize;
$getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__);
$getid3_mp3->getOnlyMPEGaudioInfo($getid3_temp->info['avdataoffset'], false);
if (isset($getid3_temp->info['mpeg']['audio'])) {
$info['mpeg']['audio'] = $getid3_temp->info['mpeg']['audio'];
$info['audio'] = $getid3_temp->info['audio'];
$info['audio']['dataformat'] = 'mp'.$info['mpeg']['audio']['layer'];
$info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate'];
$info['audio']['channels'] = $info['mpeg']['audio']['channels'];
$info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate'];
$info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
//$info['bitrate'] = $info['audio']['bitrate'];
unset($getid3_temp, $getid3_mp3);
} elseif (strpos($FirstFourBytes, $AC3syncwordBytes) === 0) {
$getid3_temp = new getID3();
$getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
$getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
$getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize;
$getid3_ac3 = new getid3_ac3($getid3_temp);
if (empty($getid3_temp->info['error'])) {
$info['audio'] = $getid3_temp->info['audio'];
$info['ac3'] = $getid3_temp->info['ac3'];
if (!empty($getid3_temp->info['warning'])) {
foreach ($getid3_temp->info['warning'] as $key => $value) {
unset($getid3_temp, $getid3_ac3);
$FoundAllChunksWeNeed = true;
$this->fseek($WhereWeWere);
$this->fseek($chunksize - 4, SEEK_CUR);
if (!isset($RIFFchunk[$listname])) {
$RIFFchunk[$listname] = array();
$LISTchunkParent = $listname;
$LISTchunkMaxOffset = $this->ftell() - 4 + $chunksize;
if ($parsedChunk = $this->ParseRIFF($this->ftell(), $LISTchunkMaxOffset)) {
$RIFFchunk[$listname] = array_merge_recursive($RIFFchunk[$listname], $parsedChunk);
if (preg_match('#^[0-9]{2}(wb|pc|dc|db)$#', $chunkname)) {
$this->fseek($chunksize, SEEK_CUR);
if (isset($RIFFchunk[$chunkname]) && is_array($RIFFchunk[$chunkname])) {
$thisindex = count($RIFFchunk[$chunkname]);
$RIFFchunk[$chunkname][$thisindex]['offset'] = $this->ftell() - 8;
$RIFFchunk[$chunkname][$thisindex]['size'] = $chunksize;
$info['avdataoffset'] = $this->ftell();
$info['avdataend'] = $info['avdataoffset'] + $chunksize;
$testData = $this->fread(36);
if (preg_match('/^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]/s', substr($testData, 0, 4))) {
if (getid3_mp3::MPEGaudioHeaderBytesValid(substr($testData, 0, 4))) {
$getid3_temp = new getID3();
$getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
$getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
$getid3_temp->info['avdataend'] = $info['avdataend'];
$getid3_mp3 = new getid3_mp3($getid3_temp, __CLASS__);
$getid3_mp3->getOnlyMPEGaudioInfo($info['avdataoffset'], false);
if (empty($getid3_temp->info['error'])) {
$info['audio'] = $getid3_temp->info['audio'];
$info['mpeg'] = $getid3_temp->info['mpeg'];
unset($getid3_temp, $getid3_mp3);
} elseif (($isRegularAC3 = (substr($testData, 0, 2) == $AC3syncwordBytes)) || substr($testData, 8, 2) == strrev($AC3syncwordBytes)) {
// This is probably AC-3 data
$getid3_temp = new getID3();
$getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
$getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
$getid3_temp->info['avdataend'] = $info['avdataend'];
$getid3_ac3 = new getid3_ac3($getid3_temp);
// AC-3 content, but not encoded in same format as normal AC-3 file
// For one thing, byte order is swapped
for ($i = 0; $i < 28; $i += 2) {
$ac3_data .= substr($testData, 8 + $i + 1, 1);
$ac3_data .= substr($testData, 8 + $i + 0, 1);
$getid3_ac3->getid3->info['avdataoffset'] = 0;
$getid3_ac3->getid3->info['avdataend'] = strlen($ac3_data);
$getid3_ac3->AnalyzeString($ac3_data);
if (empty($getid3_temp->info['error'])) {
$info['audio'] = $getid3_temp->info['audio'];
$info['ac3'] = $getid3_temp->info['ac3'];
if (!empty($getid3_temp->info['warning'])) {
foreach ($getid3_temp->info['warning'] as $newerror) {
$this->warning('getid3_ac3() says: ['.$newerror.']');
unset($getid3_temp, $getid3_ac3);
} elseif (preg_match('/^('.implode('|', array_map('preg_quote', getid3_dts::$syncwords)).')/', $testData)) {
// This is probably DTS data
$getid3_temp = new getID3();
$getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
$getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
$getid3_dts = new getid3_dts($getid3_temp);
if (empty($getid3_temp->info['error'])) {
$info['audio'] = $getid3_temp->info['audio'];
$info['dts'] = $getid3_temp->info['dts'];
$info['playtime_seconds'] = $getid3_temp->info['playtime_seconds']; // may not match RIFF calculations since DTS-WAV often used 14/16 bit-word packing
if (!empty($getid3_temp->info['warning'])) {
foreach ($getid3_temp->info['warning'] as $newerror) {
$this->warning('getid3_dts() says: ['.$newerror.']');
unset($getid3_temp, $getid3_dts);
} elseif (substr($testData, 0, 4) == 'wvpk') {
$info['wavpack']['offset'] = $info['avdataoffset'];
$info['wavpack']['size'] = getid3_lib::LittleEndian2Int(substr($testData, 4, 4));
$this->parseWavPackHeader(substr($testData, 8, 28));
// This is some other kind of data (quite possibly just PCM)
// do nothing special, just skip it
$nextoffset = $info['avdataend'];
$this->fseek($nextoffset);
// should be: never read data in
// but some programs write their version strings in a JUNK chunk (e.g. VirtualDub, AVIdemux, etc)
if ($chunksize < 1048576) {
$RIFFchunk[$chunkname][$thisindex]['data'] = $this->fread($chunksize);
if ($chunkname == 'JUNK') {
if (preg_match('#^([\\x20-\\x7F]+)#', $RIFFchunk[$chunkname][$thisindex]['data'], $matches)) {
// only keep text characters [chr(32)-chr(127)]
$info['riff']['comments']['junk'][] = trim($matches[1]);
// but if nothing there, ignore
// remove the key in either case
unset($RIFFchunk[$chunkname][$thisindex]['data']);
$this->warning('Chunk "'.$chunkname.'" at offset '.$this->ftell().' is unexpectedly larger than 1MB (claims to be '.number_format($chunksize).' bytes), skipping data');
$this->fseek($chunksize, SEEK_CUR);
// $info['divxtag']['comments'] = self::ParseDIVXTAG($this->fread($chunksize));
// https://cmsdk.com/node-js/adding-scot-chunk-to-wav-file.html
$RIFFchunk[$chunkname][$thisindex]['data'] = $this->fread($chunksize);
$RIFFchunk[$chunkname][$thisindex]['parsed']['alter'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 0, 1);
$RIFFchunk[$chunkname][$thisindex]['parsed']['attrib'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 1, 1);
$RIFFchunk[$chunkname][$thisindex]['parsed']['artnum'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 2, 2));
$RIFFchunk[$chunkname][$thisindex]['parsed']['title'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 4, 43); // "name" in other documentation
$RIFFchunk[$chunkname][$thisindex]['parsed']['copy'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 47, 4);
$RIFFchunk[$chunkname][$thisindex]['parsed']['padd'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 51, 1);
$RIFFchunk[$chunkname][$thisindex]['parsed']['asclen'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 52, 5);
$RIFFchunk[$chunkname][$thisindex]['parsed']['startseconds'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 57, 2));
$RIFFchunk[$chunkname][$thisindex]['parsed']['starthundredths'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 59, 2));
$RIFFchunk[$chunkname][$thisindex]['parsed']['endseconds'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 61, 2));
$RIFFchunk[$chunkname][$thisindex]['parsed']['endhundreths'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 63, 2));
$RIFFchunk[$chunkname][$thisindex]['parsed']['sdate'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 65, 6);
$RIFFchunk[$chunkname][$thisindex]['parsed']['kdate'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 71, 6);
$RIFFchunk[$chunkname][$thisindex]['parsed']['start_hr'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 77, 1);
$RIFFchunk[$chunkname][$thisindex]['parsed']['kill_hr'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 78, 1);
$RIFFchunk[$chunkname][$thisindex]['parsed']['digital'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 79, 1);
$RIFFchunk[$chunkname][$thisindex]['parsed']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 80, 2));
$RIFFchunk[$chunkname][$thisindex]['parsed']['stereo'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 82, 1);
$RIFFchunk[$chunkname][$thisindex]['parsed']['compress'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 83, 1);
$RIFFchunk[$chunkname][$thisindex]['parsed']['eomstrt'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 84, 4));
$RIFFchunk[$chunkname][$thisindex]['parsed']['eomlen'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 88, 2));
$RIFFchunk[$chunkname][$thisindex]['parsed']['attrib2'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 90, 4));
$RIFFchunk[$chunkname][$thisindex]['parsed']['future1'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 94, 12);
$RIFFchunk[$chunkname][$thisindex]['parsed']['catfontcolor'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 106, 4));
$RIFFchunk[$chunkname][$thisindex]['parsed']['catcolor'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 110, 4));
$RIFFchunk[$chunkname][$thisindex]['parsed']['segeompos'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 114, 4));
$RIFFchunk[$chunkname][$thisindex]['parsed']['vt_startsecs'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 118, 2));
$RIFFchunk[$chunkname][$thisindex]['parsed']['vt_starthunds'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 120, 2));
$RIFFchunk[$chunkname][$thisindex]['parsed']['priorcat'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 122, 3);
$RIFFchunk[$chunkname][$thisindex]['parsed']['priorcopy'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 125, 4);
$RIFFchunk[$chunkname][$thisindex]['parsed']['priorpadd'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 129, 1);
$RIFFchunk[$chunkname][$thisindex]['parsed']['postcat'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 130, 3);
$RIFFchunk[$chunkname][$thisindex]['parsed']['postcopy'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 133, 4);
$RIFFchunk[$chunkname][$thisindex]['parsed']['postpadd'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 137, 1);
$RIFFchunk[$chunkname][$thisindex]['parsed']['hrcanplay'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 138, 21);
$RIFFchunk[$chunkname][$thisindex]['parsed']['future2'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 159, 108);
$RIFFchunk[$chunkname][$thisindex]['parsed']['artist'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 267, 34);
$RIFFchunk[$chunkname][$thisindex]['parsed']['comment'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 301, 34); // "trivia" in other documentation
$RIFFchunk[$chunkname][$thisindex]['parsed']['intro'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 335, 2);
$RIFFchunk[$chunkname][$thisindex]['parsed']['end'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 337, 1);
$RIFFchunk[$chunkname][$thisindex]['parsed']['year'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 338, 4);
$RIFFchunk[$chunkname][$thisindex]['parsed']['obsolete2'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 342, 1);
$RIFFchunk[$chunkname][$thisindex]['parsed']['rec_hr'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 343, 1);
$RIFFchunk[$chunkname][$thisindex]['parsed']['rdate'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 344, 6);
$RIFFchunk[$chunkname][$thisindex]['parsed']['mpeg_bitrate'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 350, 2));
$RIFFchunk[$chunkname][$thisindex]['parsed']['pitch'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 352, 2));
$RIFFchunk[$chunkname][$thisindex]['parsed']['playlevel'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 354, 2));
$RIFFchunk[$chunkname][$thisindex]['parsed']['lenvalid'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 356, 1);
$RIFFchunk[$chunkname][$thisindex]['parsed']['filelength'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 357, 4));
$RIFFchunk[$chunkname][$thisindex]['parsed']['newplaylevel'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 361, 2));
$RIFFchunk[$chunkname][$thisindex]['parsed']['chopsize'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 363, 4));
$RIFFchunk[$chunkname][$thisindex]['parsed']['vteomovr'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 367, 4));
$RIFFchunk[$chunkname][$thisindex]['parsed']['desiredlen'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 371, 4));
$RIFFchunk[$chunkname][$thisindex]['parsed']['triggers'] = getid3_lib::LittleEndian2Int(substr($RIFFchunk[$chunkname][$thisindex]['data'], 375, 4));
$RIFFchunk[$chunkname][$thisindex]['parsed']['fillout'] = substr($RIFFchunk[$chunkname][$thisindex]['data'], 379, 33);
foreach (array('title', 'artist', 'comment') as $key) {
if (trim($RIFFchunk[$chunkname][$thisindex]['parsed'][$key])) {
$info['riff']['comments'][$key] = array($RIFFchunk[$chunkname][$thisindex]['parsed'][$key]);
if ($RIFFchunk[$chunkname][$thisindex]['parsed']['filelength'] && !empty($info['filesize']) && ($RIFFchunk[$chunkname][$thisindex]['parsed']['filelength'] != $info['filesize'])) {
$this->warning('RIFF.WAVE.scot.filelength ('.$RIFFchunk[$chunkname][$thisindex]['parsed']['filelength'].') different from actual filesize ('.$info['filesize'].')');
if (!empty($LISTchunkParent) && isset($LISTchunkMaxOffset) && (($RIFFchunk[$chunkname][$thisindex]['offset'] + $RIFFchunk[$chunkname][$thisindex]['size']) <= $LISTchunkMaxOffset)) {
$RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['offset'] = $RIFFchunk[$chunkname][$thisindex]['offset'];
$RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['size'] = $RIFFchunk[$chunkname][$thisindex]['size'];
unset($RIFFchunk[$chunkname][$thisindex]['offset']);
unset($RIFFchunk[$chunkname][$thisindex]['size']);
if (isset($RIFFchunk[$chunkname][$thisindex]) && empty($RIFFchunk[$chunkname][$thisindex])) {
unset($RIFFchunk[$chunkname][$thisindex]);
if (count($RIFFchunk[$chunkname]) === 0) {
unset($RIFFchunk[$chunkname]);
$RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['data'] = $this->fread($chunksize);
} elseif ($chunksize < 2048) {
// only read data in if smaller than 2kB
$RIFFchunk[$chunkname][$thisindex]['data'] = $this->fread($chunksize);
$this->fseek($chunksize, SEEK_CUR);
} catch (getid3_exception $e) {
if ($e->getCode() == 10) {
$this->warning('RIFF parser: '.$e->getMessage());
return !empty($RIFFchunk) ? $RIFFchunk : false;
* @param string $RIFFdata
public function ParseRIFFdata(&$RIFFdata) {
$info = &$this->getid3->info;
$tempfile = tempnam(GETID3_TEMP_DIR, 'getID3');
$fp_temp = fopen($tempfile, 'wb');
$RIFFdataLength = strlen($RIFFdata);
$NewLengthString = getid3_lib::LittleEndian2String($RIFFdataLength, 4);
for ($i = 0; $i < 4; $i++) {
$RIFFdata[($i + 4)] = $NewLengthString[$i];
fwrite($fp_temp, $RIFFdata);
$getid3_temp = new getID3();
$getid3_temp->openfile($tempfile);
$getid3_temp->info['filesize'] = $RIFFdataLength;
$getid3_temp->info['filenamepath'] = $info['filenamepath'];
$getid3_temp->info['tags'] = $info['tags'];
$getid3_temp->info['warning'] = $info['warning'];
$getid3_temp->info['error'] = $info['error'];
$getid3_temp->info['comments'] = $info['comments'];
$getid3_temp->info['audio'] = (isset($info['audio']) ? $info['audio'] : array());
$getid3_temp->info['video'] = (isset($info['video']) ? $info['video'] : array());
$getid3_riff = new getid3_riff($getid3_temp);
$info['riff'] = $getid3_temp->info['riff'];
$info['warning'] = $getid3_temp->info['warning'];
$info['error'] = $getid3_temp->info['error'];
$info['tags'] = $getid3_temp->info['tags'];
$info['comments'] = $getid3_temp->info['comments'];
unset($getid3_riff, $getid3_temp);
* @param array $RIFFinfoArray
* @param array $CommentsTargetArray
public static function parseComments(&$RIFFinfoArray, &$CommentsTargetArray) {
$RIFFinfoKeyLookup = array(
'IARL'=>'archivallocation',
'ICDS'=>'costumedesigner',
'ICMS'=>'commissionedby',