From 531e3b786131132372a589f9e19566167edeee97 Mon Sep 17 00:00:00 2001 From: RoosterDragon Date: Sat, 31 May 2014 18:00:42 +0100 Subject: [PATCH] Fixes to StreamExts. - Almost all calls to Stream.Read were broken. These have been patched to all go through ReadBytes which itself has been fixed to function correctly. The key thing to note is that Stream.Read is very much allowed to return less than the requested number of bytes. If this happens and you're not checking the return result, you'll be working with partially initialized arrays and really bad stuff happens when you do that. - Call CopyTo rather than copying between streams manually. - Peek and ReadUInt8 have been changed to avoid a pointless array allocation which is significant overhead for such simple calls. --- OpenRA.Game/FileFormats/ShpReader.cs | 5 +- OpenRA.Game/FileFormats/ShpTSReader.cs | 3 +- OpenRA.Game/FileSystem/D2kSoundResources.cs | 5 +- OpenRA.Game/FileSystem/GlobalFileSystem.cs | 3 +- .../FileSystem/InstallShieldPackage.cs | 3 +- OpenRA.Game/FileSystem/MixFile.cs | 3 +- OpenRA.Game/FileSystem/Pak.cs | 3 +- OpenRA.Game/FileSystem/ZipFile.cs | 6 +- OpenRA.Game/InstallUtils.cs | 7 +-- OpenRA.Game/StreamExts.cs | 55 +++++++++---------- 10 files changed, 36 insertions(+), 57 deletions(-) diff --git a/OpenRA.Game/FileFormats/ShpReader.cs b/OpenRA.Game/FileFormats/ShpReader.cs index 22e2443d18..1c80d9092b 100644 --- a/OpenRA.Game/FileFormats/ShpReader.cs +++ b/OpenRA.Game/FileFormats/ShpReader.cs @@ -105,10 +105,7 @@ namespace OpenRA.FileFormats // Actually, far too big. There's no length field with the correct length though :( var compressedLength = (int)(stream.Length - stream.Position); - var compressedBytes = new byte[compressedLength]; - stream.Read(compressedBytes, 0, compressedLength); - - return compressedBytes; + return stream.ReadBytes(compressedLength); } void Decompress(Stream stream, ImageHeader h) diff --git a/OpenRA.Game/FileFormats/ShpTSReader.cs b/OpenRA.Game/FileFormats/ShpTSReader.cs index ea10a4e209..2b1704711b 100644 --- a/OpenRA.Game/FileFormats/ShpTSReader.cs +++ b/OpenRA.Game/FileFormats/ShpTSReader.cs @@ -81,7 +81,8 @@ namespace OpenRA.FileFormats for (var j = 0; j < f.Size.Height; j++) { var length = stream.ReadUInt16() - 2; - stream.Read(f.Data, f.Size.Width * j, length); + var offset = f.Size.Width * j; + stream.ReadBytes(f.Data, offset, length); } } diff --git a/OpenRA.Game/FileSystem/D2kSoundResources.cs b/OpenRA.Game/FileSystem/D2kSoundResources.cs index e5912f12b2..9a58bf1b87 100644 --- a/OpenRA.Game/FileSystem/D2kSoundResources.cs +++ b/OpenRA.Game/FileSystem/D2kSoundResources.cs @@ -56,10 +56,7 @@ namespace OpenRA.FileSystem return null; s.Seek(e.Offset, SeekOrigin.Begin); - var data = new byte[e.Length]; - s.Read(data, 0, (int)e.Length); - - return new MemoryStream(data); + return new MemoryStream(s.ReadBytes((int)e.Length)); } public Stream GetContent(string filename) diff --git a/OpenRA.Game/FileSystem/GlobalFileSystem.cs b/OpenRA.Game/FileSystem/GlobalFileSystem.cs index 45ca6af2bf..03d1ed7764 100644 --- a/OpenRA.Game/FileSystem/GlobalFileSystem.cs +++ b/OpenRA.Game/FileSystem/GlobalFileSystem.cs @@ -230,8 +230,7 @@ namespace OpenRA.FileSystem if (Exists(filename)) using (var s = Open(filename)) { - var buf = new byte[s.Length]; - s.Read(buf, 0, buf.Length); + var buf = s.ReadBytes((int)s.Length); a = Assembly.Load(buf); assemblyCache.Add(filename, a); return a; diff --git a/OpenRA.Game/FileSystem/InstallShieldPackage.cs b/OpenRA.Game/FileSystem/InstallShieldPackage.cs index eea52cabe0..fdb4fde287 100644 --- a/OpenRA.Game/FileSystem/InstallShieldPackage.cs +++ b/OpenRA.Game/FileSystem/InstallShieldPackage.cs @@ -103,8 +103,7 @@ namespace OpenRA.FileSystem return null; s.Seek(dataStart + e.Offset, SeekOrigin.Begin); - var data = new byte[e.Length]; - s.Read(data, 0, (int)e.Length); + var data = s.ReadBytes((int)e.Length); return new MemoryStream(Blast.Decompress(data)); } diff --git a/OpenRA.Game/FileSystem/MixFile.cs b/OpenRA.Game/FileSystem/MixFile.cs index e71ea82b88..f28d17b2b9 100644 --- a/OpenRA.Game/FileSystem/MixFile.cs +++ b/OpenRA.Game/FileSystem/MixFile.cs @@ -157,8 +157,7 @@ namespace OpenRA.FileSystem return null; s.Seek(dataStart + e.Offset, SeekOrigin.Begin); - var data = new byte[e.Length]; - s.Read(data, 0, (int)e.Length); + var data = s.ReadBytes((int)e.Length); return new MemoryStream(data); } diff --git a/OpenRA.Game/FileSystem/Pak.cs b/OpenRA.Game/FileSystem/Pak.cs index a105ee99dc..e3a6dc709f 100644 --- a/OpenRA.Game/FileSystem/Pak.cs +++ b/OpenRA.Game/FileSystem/Pak.cs @@ -59,8 +59,7 @@ namespace OpenRA.FileSystem return null; stream.Seek(entry.Offset, SeekOrigin.Begin); - var data = new byte[entry.Length]; - stream.Read(data, 0, (int)entry.Length); + var data = stream.ReadBytes((int)entry.Length); return new MemoryStream(data); } diff --git a/OpenRA.Game/FileSystem/ZipFile.cs b/OpenRA.Game/FileSystem/ZipFile.cs index 8859ba2a53..c7705a0949 100644 --- a/OpenRA.Game/FileSystem/ZipFile.cs +++ b/OpenRA.Game/FileSystem/ZipFile.cs @@ -60,11 +60,7 @@ namespace OpenRA.FileSystem using (var z = pkg.GetInputStream(pkg.GetEntry(filename))) { var ms = new MemoryStream(); - int bufSize = 2048; - byte[] buf = new byte[bufSize]; - while ((bufSize = z.Read(buf, 0, buf.Length)) > 0) - ms.Write(buf, 0, bufSize); - + z.CopyTo(ms); ms.Seek(0, SeekOrigin.Begin); return ms; } diff --git a/OpenRA.Game/InstallUtils.cs b/OpenRA.Game/InstallUtils.cs index b6e14afffa..5e098e54f3 100644 --- a/OpenRA.Game/InstallUtils.cs +++ b/OpenRA.Game/InstallUtils.cs @@ -122,12 +122,7 @@ namespace OpenRA extracted.Add(path); using (var f = File.Create(path)) - { - int bufSize = 2048; - byte[] buf = new byte[bufSize]; - while ((bufSize = z.Read(buf, 0, buf.Length)) > 0) - f.Write(buf, 0, bufSize); - } + z.CopyTo(f); } z.Close(); diff --git a/OpenRA.Game/StreamExts.cs b/OpenRA.Game/StreamExts.cs index 2317476a3a..33c465b981 100755 --- a/OpenRA.Game/StreamExts.cs +++ b/OpenRA.Game/StreamExts.cs @@ -21,27 +21,38 @@ namespace OpenRA { if (count < 0) throw new ArgumentOutOfRangeException("count", "Non-negative number required."); + var buffer = new byte[count]; + s.ReadBytes(buffer, 0, count); + return buffer; + } - var buf = new byte[count]; - if (s.Read(buf, 0, count) < count) - throw new EndOfStreamException(); - - return buf; + public static void ReadBytes(this Stream s, byte[] buffer, int offset, int count) + { + while (count > 0) + { + int bytesRead; + if ((bytesRead = s.Read(buffer, offset, count)) == 0) + throw new EndOfStreamException(); + offset += bytesRead; + count -= bytesRead; + } } public static int Peek(this Stream s) { - var buf = new byte[1]; - if (s.Read(buf, 0, 1) == 0) + var b = s.ReadByte(); + if (b == -1) return -1; - - s.Seek(s.Position - 1, SeekOrigin.Begin); - return buf[0]; + s.Seek(-1, SeekOrigin.Current); + return (byte)b; } public static byte ReadUInt8(this Stream s) { - return s.ReadBytes(1)[0]; + var b = s.ReadByte(); + if (b == -1) + throw new EndOfStreamException(); + return (byte)b; } public static ushort ReadUInt16(this Stream s) @@ -87,19 +98,9 @@ namespace OpenRA public static string ReadASCIIZ(this Stream s) { var bytes = new List(); - var buf = new byte[1]; - - for (;;) - { - if (s.Read(buf, 0, 1) < 1) - throw new EndOfStreamException(); - - if (buf[0] == 0) - break; - - bytes.Add(buf[0]); - } - + byte b; + while ((b = s.ReadUInt8()) != 0) + bytes.Add(b); return new string(Encoding.ASCII.GetChars(bytes.ToArray())); } @@ -113,11 +114,7 @@ namespace OpenRA public static byte[] ReadAllBytes(this Stream s) { using (s) - { - var data = new byte[s.Length - s.Position]; - s.Read(data, 0, data.Length); - return data; - } + return s.ReadBytes((int)(s.Length - s.Position)); } public static void Write(this Stream s, byte[] data)