Merge pull request #10482 from Mailaender/ra2-wav

Fixed crashes with Red Alert 2 wav files
This commit is contained in:
Paul Chote
2016-01-15 23:05:13 +00:00
5 changed files with 40 additions and 32 deletions

View File

@@ -125,12 +125,12 @@ namespace OpenRA.FileFormats
sampleRate = s.ReadUInt16(); sampleRate = s.ReadUInt16();
var dataSize = s.ReadInt32(); var dataSize = s.ReadInt32();
var outputSize = s.ReadInt32(); var outputSize = s.ReadInt32();
var readFlag = s.ReadByte();
var readFormat = s.ReadByte();
var readFlag = s.ReadByte();
if (!Enum.IsDefined(typeof(SoundFlags), readFlag)) if (!Enum.IsDefined(typeof(SoundFlags), readFlag))
return false; return false;
var readFormat = s.ReadByte();
if (!Enum.IsDefined(typeof(SoundFormat), readFormat)) if (!Enum.IsDefined(typeof(SoundFormat), readFormat))
return false; return false;
@@ -170,6 +170,7 @@ namespace OpenRA.FileFormats
out int sampleRate) out int sampleRate)
{ {
channels = sampleBits = sampleRate = 0; channels = sampleBits = sampleRate = 0;
var position = stream.Position;
try try
{ {
@@ -182,11 +183,15 @@ namespace OpenRA.FileFormats
// If not, it will simply return false so we know we can't use it. If it is, it will start // If not, it will simply return false so we know we can't use it. If it is, it will start
// parsing the data without any further failsafes, which means that it will crash on corrupted files // parsing the data without any further failsafes, which means that it will crash on corrupted files
// (that end prematurely or otherwise don't conform to the specifications despite the headers being OK). // (that end prematurely or otherwise don't conform to the specifications despite the headers being OK).
Log.Write("debug", "Failed to parse AUD file {0}. Error message:".F(fileName)); Log.Write("sound", "Failed to parse AUD file {0}. Error message:".F(fileName));
Log.Write("debug", e.ToString()); Log.Write("sound", e.ToString());
rawData = null; rawData = null;
return false; return false;
} }
finally
{
stream.Position = position;
}
channels = 1; channels = 1;
sampleBits = 16; sampleBits = 16;

View File

@@ -19,6 +19,8 @@ namespace OpenRA.FileFormats
{ {
bool ISoundLoader.TryParseSound(Stream stream, string fileName, out byte[] rawData, out int channels, out int sampleBits, out int sampleRate) bool ISoundLoader.TryParseSound(Stream stream, string fileName, out byte[] rawData, out int channels, out int sampleBits, out int sampleRate)
{ {
var position = stream.Position;
try try
{ {
var vocStream = new VocStream(stream); var vocStream = new VocStream(stream);
@@ -33,6 +35,10 @@ namespace OpenRA.FileFormats
channels = sampleBits = sampleRate = 0; channels = sampleBits = sampleRate = 0;
return false; return false;
} }
finally
{
stream.Position = position;
}
return true; return true;
} }

View File

@@ -43,7 +43,6 @@ namespace OpenRA.FileFormats
Format = s.ReadASCII(4); Format = s.ReadASCII(4);
if (Format != "WAVE") if (Format != "WAVE")
return false; return false;
while (s.Position < s.Length) while (s.Position < s.Length)
{ {
if ((s.Position & 1) == 1) if ((s.Position & 1) == 1)
@@ -57,8 +56,8 @@ namespace OpenRA.FileFormats
AudioFormat = s.ReadInt16(); AudioFormat = s.ReadInt16();
Type = (WaveType)AudioFormat; Type = (WaveType)AudioFormat;
if (Type != WaveType.Pcm && Type != WaveType.ImaAdpcm) if (!Enum.IsDefined(typeof(WaveType), Type))
throw new NotSupportedException("Compression type is not supported."); throw new NotSupportedException("Compression type {0} is not supported.".F(AudioFormat));
Channels = s.ReadInt16(); Channels = s.ReadInt16();
SampleRate = s.ReadInt32(); SampleRate = s.ReadInt32();
@@ -69,24 +68,17 @@ namespace OpenRA.FileFormats
s.ReadBytes(FmtChunkSize - 16); s.ReadBytes(FmtChunkSize - 16);
break; break;
case "fact": case "fact":
{ var chunkSize = s.ReadInt32();
var chunkSize = s.ReadInt32(); UncompressedSize = s.ReadInt32();
UncompressedSize = s.ReadInt32(); s.ReadBytes(chunkSize - 4);
s.ReadBytes(chunkSize - 4);
}
break; break;
case "data": case "data":
DataSize = s.ReadInt32(); DataSize = s.ReadInt32();
RawOutput = s.ReadBytes(DataSize); RawOutput = s.ReadBytes(DataSize);
break; break;
default: default:
// Ignore unknown chunks var unknownChunkSize = s.ReadInt32();
{ s.ReadBytes(unknownChunkSize);
var chunkSize = s.ReadInt32();
s.ReadBytes(chunkSize);
}
break; break;
} }
} }
@@ -189,6 +181,7 @@ namespace OpenRA.FileFormats
{ {
rawData = null; rawData = null;
channels = sampleBits = sampleRate = 0; channels = sampleBits = sampleRate = 0;
var position = stream.Position;
try try
{ {
@@ -201,10 +194,14 @@ namespace OpenRA.FileFormats
// If not, it will simply return false so we know we can't use it. If it is, it will start // If not, it will simply return false so we know we can't use it. If it is, it will start
// parsing the data without any further failsafes, which means that it will crash on corrupted files // parsing the data without any further failsafes, which means that it will crash on corrupted files
// (that end prematurely or otherwise don't conform to the specifications despite the headers being OK). // (that end prematurely or otherwise don't conform to the specifications despite the headers being OK).
Log.Write("debug", "Failed to parse WAV file {0}. Error message:".F(fileName)); Log.Write("sound", "Failed to parse WAV file {0}. Error message:".F(fileName));
Log.Write("debug", e.ToString()); Log.Write("sound", e.ToString());
return false; return false;
} }
finally
{
stream.Position = position;
}
rawData = RawOutput; rawData = RawOutput;
channels = Channels; channels = Channels;

View File

@@ -18,6 +18,7 @@ namespace OpenRA.Primitives
public Stream Stream2 { get; set; } public Stream Stream2 { get; set; }
long VirtualLength { get; set; } long VirtualLength { get; set; }
long position;
public MergedStream(Stream stream1, Stream stream2) public MergedStream(Stream stream1, Stream stream2)
{ {
@@ -35,8 +36,6 @@ namespace OpenRA.Primitives
public override long Seek(long offset, SeekOrigin origin) public override long Seek(long offset, SeekOrigin origin)
{ {
var position = Position;
switch (origin) switch (origin)
{ {
case SeekOrigin.Begin: case SeekOrigin.Begin:
@@ -52,9 +51,9 @@ namespace OpenRA.Primitives
} }
if (position >= Stream1.Length) if (position >= Stream1.Length)
Position = Stream1.Length + Stream2.Seek(offset - Stream1.Length, SeekOrigin.Begin); position = Stream1.Length + Stream2.Seek(offset - Stream1.Length, SeekOrigin.Begin);
else else
Position = Stream1.Seek(offset, SeekOrigin.Begin); position = Stream1.Seek(offset, SeekOrigin.Begin);
return position; return position;
} }
@@ -68,7 +67,7 @@ namespace OpenRA.Primitives
{ {
int bytesRead; int bytesRead;
if (Position >= Stream1.Length) if (position >= Stream1.Length)
bytesRead = Stream2.Read(buffer, offset, count); bytesRead = Stream2.Read(buffer, offset, count);
else if (count > Stream1.Length) else if (count > Stream1.Length)
{ {
@@ -78,14 +77,14 @@ namespace OpenRA.Primitives
else else
bytesRead = Stream1.Read(buffer, offset, count); bytesRead = Stream1.Read(buffer, offset, count);
Position += bytesRead; position += bytesRead;
return bytesRead; return bytesRead;
} }
public override void Write(byte[] buffer, int offset, int count) public override void Write(byte[] buffer, int offset, int count)
{ {
if (Position >= Stream1.Length) if (position >= Stream1.Length)
Stream2.Write(buffer, offset - (int)Stream1.Length, count); Stream2.Write(buffer, offset - (int)Stream1.Length, count);
else else
Stream1.Write(buffer, offset, count); Stream1.Write(buffer, offset, count);
@@ -111,6 +110,10 @@ namespace OpenRA.Primitives
get { return VirtualLength; } get { return VirtualLength; }
} }
public override long Position { get; set; } public override long Position
{
get { return position; }
set { Seek(value, SeekOrigin.Begin); }
}
} }
} }

View File

@@ -63,11 +63,8 @@ namespace OpenRA
int sampleBits; int sampleBits;
int sampleRate; int sampleRate;
foreach (var loader in Game.ModData.SoundLoaders) foreach (var loader in Game.ModData.SoundLoaders)
{
stream.Position = 0;
if (loader.TryParseSound(stream, filename, out rawData, out channels, out sampleBits, out sampleRate)) if (loader.TryParseSound(stream, filename, out rawData, out channels, out sampleBits, out sampleRate))
return soundEngine.AddSoundSourceFromMemory(rawData, channels, sampleBits, sampleRate); return soundEngine.AddSoundSourceFromMemory(rawData, channels, sampleBits, sampleRate);
}
throw new InvalidDataException(filename + " is not a valid sound file!"); throw new InvalidDataException(filename + " is not a valid sound file!");
} }