Merge pull request #3240 from pchote/mixfile-streams

Be explicit about MixFile stream positions.
This commit is contained in:
Matthias Mailänder
2013-05-10 04:12:08 -07:00

View File

@@ -50,40 +50,48 @@ namespace OpenRA.FileFormats
s = FileSystem.Open(filename);
// Detect format type
s.Seek(0, SeekOrigin.Begin);
var reader = new BinaryReader(s);
var isCncMix = reader.ReadUInt16() != 0;
var isEncrypted = false;
// The C&C mix format doesn't contain any flags or encryption
if (isCncMix)
s.Seek(0, SeekOrigin.Begin);
else
var isEncrypted = false;
if (!isCncMix)
isEncrypted = (reader.ReadUInt16() & 0x2) != 0;
var header = isEncrypted ? DecryptHeader(s) : s;
index = ParseHeader(header).ToDictionaryWithConflictLog(x => x.Hash,
"{0} ({1} format, Encrypted: {2})".F(filename, (isCncMix ? "C&C" : "RA/TS/RA2"), isEncrypted),
List<PackageEntry> entries;
if (isEncrypted)
{
long unused;
entries = ParseHeader(DecryptHeader(s, 4, out dataStart), 0, out unused);
}
else
entries = ParseHeader(s, isCncMix ? 0 : 4, out dataStart);
index = entries.ToDictionaryWithConflictLog(x => x.Hash,
"{0} ({1} format, Encrypted: {2}, DataStart: {3})".F(filename, (isCncMix ? "C&C" : "RA/TS/RA2"), isEncrypted, dataStart),
null, x => "(offs={0}, len={1})".F(x.Offset, x.Length)
);
dataStart = s.Position;
}
List<PackageEntry> ParseHeader(Stream s)
List<PackageEntry> ParseHeader(Stream s, long offset, out long headerEnd)
{
var items = new List<PackageEntry>();
s.Seek(offset, SeekOrigin.Begin);
var reader = new BinaryReader(s);
var numFiles = reader.ReadUInt16();
/*uint dataSize = */reader.ReadUInt32();
var items = new List<PackageEntry>();
for (var i = 0; i < numFiles; i++)
items.Add(new PackageEntry(reader));
headerEnd = offset + 6 + numFiles*PackageEntry.Size;
return items;
}
MemoryStream DecryptHeader(Stream s)
MemoryStream DecryptHeader(Stream s, long offset, out long headerEnd)
{
s.Seek(offset, SeekOrigin.Begin);
var reader = new BinaryReader(s);
// Decrypt blowfish key
@@ -92,13 +100,14 @@ namespace OpenRA.FileFormats
var fish = new Blowfish(blowfishKey);
// Decrypt first block to work out the header length
var headerStart = s.Position;
var ms = Decrypt(ReadBlocks(s, headerStart, 1), fish);
var ms = Decrypt(ReadBlocks(s, offset + 80, 1), fish);
var numFiles = new BinaryReader(ms).ReadUInt16();
// Decrypt the full header - round bytes up to a full block
var blockCount = (13 + numFiles*PackageEntry.Size)/8;
return Decrypt(ReadBlocks(s, headerStart, blockCount), fish);
headerEnd = offset + 80 + blockCount*8;
return Decrypt(ReadBlocks(s, offset + 80, blockCount), fish);
}
static MemoryStream Decrypt(uint[] h, Blowfish fish)