mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-27 05:32:45 +00:00
4946f149b4
1. KQ4 sound 104 has an extra 0xFC (MIDI Stop command/kEndOfTrack) at the end of the resource, which causes an out-of-bounds read because the filtering loop continues after the first 0xFC and unconditionally attempts to read 2 bytes (expecting there to always be a delta value + a command, whereas in this file there is only another kEndOfTrack command). This is corrected by exiting the filtering loop when a kEndOfTrack is encountered and there is not enough data remaining in the resource to continue reading. 2. KQ5 sound 699 is truncated, which causes the parser to attempt to read past the end of the resource. This is addressed by adding bounds checks that exit the mix loop early if there is no more data available to read. This allows truncated sounds to be played as far as possible (previously, trying to read truncated resources would result in a fatal error). 3. midiMixChannels allocates an arbitrary amount of raw memory for the mixed MIDI sequence, without performing any bounds checking when writing to this memory, potentially leading to a crash or silent corruption of adjacent memory. This is mitigated by using SciSpan instead of a raw pointer for the mixed data. Fixes Trac#9727.
137 lines
3.8 KiB
C++
137 lines
3.8 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
*/
|
|
|
|
#ifndef SCI_MIDIPARSER_H
|
|
#define SCI_MIDIPARSER_H
|
|
|
|
#include "sci/resource.h"
|
|
#include "sci/sound/music.h"
|
|
#include "audio/midiparser.h"
|
|
|
|
/*
|
|
Sound drivers info: (from driver cmd0)
|
|
AdLib/SB : track 0 , voices 9 , patch 3 ah=1
|
|
ProAudioSp: track 0 , voices 9 , patch 3 ah=17
|
|
GenerlMIDI: track 7 , voices 32, patch 4 ah=1 SCI1.1
|
|
Game Blast: track 9 , voices 12, patch 101 ah=1
|
|
MT-32 : track 12, voices 32, patch 1 ah=1
|
|
PC Speaker: track 18, voices 1 , patch 0xFF ah=1
|
|
Tandy : track 19, voices 3 , patch 101 ah=1
|
|
IBM PS/1 : track 19, voices 3 , patch 101 ah=1
|
|
|
|
*/
|
|
|
|
namespace Sci {
|
|
|
|
/**
|
|
* An extended standard MIDI (SMF) parser. Sierra used an extra channel
|
|
* with special commands for extended functionality and animation syncing.
|
|
* Refer to MidiParser_SMF() in /sound/midiparser_smf.cpp for the standard
|
|
* MIDI (SMF) parser functionality that the SCI MIDI parser is based on
|
|
*/
|
|
class MidiParser_SCI : public MidiParser {
|
|
public:
|
|
MidiParser_SCI(SciVersion soundVersion, SciMusic *music);
|
|
~MidiParser_SCI();
|
|
|
|
void mainThreadBegin();
|
|
void mainThreadEnd();
|
|
|
|
bool loadMusic(SoundResource::Track *track, MusicEntry *psnd, int channelFilterMask, SciVersion soundVersion);
|
|
bool loadMusic(byte *, uint32) {
|
|
return false;
|
|
}
|
|
void sendInitCommands();
|
|
void unloadMusic();
|
|
void setMasterVolume(byte masterVolume);
|
|
void setVolume(byte volume);
|
|
void stop() {
|
|
_abortParse = true;
|
|
allNotesOff();
|
|
}
|
|
void pause() {
|
|
allNotesOff();
|
|
if (_resetOnPause)
|
|
jumpToTick(0);
|
|
}
|
|
|
|
void allNotesOff();
|
|
|
|
const SciSpan<const byte> &getMixedData() const { return *_mixedData; }
|
|
byte getSongReverb();
|
|
|
|
void sendFromScriptToDriver(uint32 midi);
|
|
void sendToDriver(uint32 midi);
|
|
void sendToDriver(byte status, byte firstOp, byte secondOp) {
|
|
sendToDriver(status | ((uint32)firstOp << 8) | ((uint32)secondOp << 16));
|
|
}
|
|
|
|
void remapChannel(int channel, int devChannel);
|
|
|
|
protected:
|
|
void parseNextEvent(EventInfo &info);
|
|
bool processEvent(const EventInfo &info, bool fireEvents = true);
|
|
void midiMixChannels();
|
|
void midiFilterChannels(int channelMask);
|
|
byte midiGetNextChannel(long ticker);
|
|
void resetStateTracking();
|
|
void trackState(uint32 midi);
|
|
void sendToDriver_raw(uint32 midi);
|
|
|
|
SciMusic *_music;
|
|
|
|
// this is set, when main thread calls us -> we send commands to queue instead to driver
|
|
bool _mainThreadCalled;
|
|
|
|
SciVersion _soundVersion;
|
|
Common::SpanOwner<SciSpan<const byte> > _mixedData;
|
|
SoundResource::Track *_track;
|
|
MusicEntry *_pSnd;
|
|
uint32 _loopTick;
|
|
byte _masterVolume; // the overall master volume (same for all tracks)
|
|
byte _volume; // the global volume of the current track
|
|
|
|
bool _resetOnPause;
|
|
|
|
bool _channelUsed[16];
|
|
int16 _channelRemap[16];
|
|
bool _channelMuted[16];
|
|
byte _channelVolume[16];
|
|
|
|
struct ChannelState {
|
|
int8 _modWheel;
|
|
int8 _pan;
|
|
int8 _patch;
|
|
int8 _note;
|
|
bool _sustain;
|
|
int16 _pitchWheel;
|
|
int8 _voices;
|
|
};
|
|
|
|
ChannelState _channelState[16];
|
|
|
|
};
|
|
|
|
} // End of namespace Sci
|
|
|
|
#endif
|