protected override bool ReadFile(BinaryReader r) { source = r; var length = (int)r.BaseStream.Length; this.FileLength = (uint)length; if (length < 10) { ParseError("File length too short to contain file header."); return false; } var fileBytes = r.ReadBytes((int)length); UInt32 flags = BitConverter.ToUInt32(fileBytes, 0); if ((flags & 0x0000FFFF) != 0) { var s = new ArraySegment<byte>(fileBytes, 0, 6); if (!Header.ReadFile(s)) { ParseError("Failed to read file header (old style)."); return false; } var headLen = Header.FileCount * 12; if (length < (6 + headLen)) { ParseError("File length too short to contain entry headers."); return false; } HeadLength = (uint)(6 + headLen); headerBytes = new byte[HeadLength]; Buffer.BlockCopy(fileBytes, 0, headerBytes, 0, (int)HeadLength); } else { if ((flags & (uint)MIXFlags.HasChecksum) != 0) { Flags |= MIXFlags.HasChecksum; } if ((flags & (uint)MIXFlags.HasEncryption) != 0) { Flags |= MIXFlags.HasEncryption; } if (Flags.HasFlag(MIXFlags.HasEncryption)) { // uh oh var key80 = fileBytes.Skip(4).Take(80).ToArray(); var key56 = new byte[56]; MIX_Magic.get_blowfish_key(key80, ref key56); var bf = new Blowfish(key56); var header = fileBytes.Skip(84).Take(8).ToArray(); bf.Decipher(header, 8); var s = new ArraySegment<byte>(header, 0, 6); if (!Header.ReadFile(s)) { ParseError("Failed to read file header (encrypted style, yo)."); return false; } var hSize = Header.FileCount * 12 + 6; hSize += 8 - (hSize % 8); var blockCount = hSize >> 3; HeadLength = (uint)(84 + hSize); if (length < (84 + hSize)) { ParseError("File length too short to contain entry headers."); return false; } var decoded = new byte[hSize]; Buffer.BlockCopy(header, 0, decoded, 0, 8); --blockCount; var encoded = new byte[blockCount * 8]; Buffer.BlockCopy(fileBytes, 92, encoded, 0, blockCount * 8); for (var i = 0; i < blockCount; ++i) { bf.Decipher(encoded, 8, i * 8); } Buffer.BlockCopy(encoded, 0, decoded, 8, blockCount * 8); headerBytes = decoded; } else { var s = new ArraySegment<byte>(fileBytes, 4, 6); if (!Header.ReadFile(s)) { ParseError("Failed to read file header (new style)."); return false; } var headLen = Header.FileCount * 12; if (length < (10 + headLen)) { ParseError("File length too short to contain entry headers."); return false; } HeadLength = (uint)(10 + headLen); headerBytes = new byte[HeadLength - 4]; Buffer.BlockCopy(fileBytes, 4, headerBytes, 0, (int)HeadLength - 4); } } if (!ReadEntryHeaders()) { ParseError("Failed to read entry headers."); return false; } ParseLMD(); return true; }
protected override bool ReadFile(BinaryReader r) { source = r; var length = (int)r.BaseStream.Length; this.FileLength = (uint)length; if (length < 10) { ParseError("File length too short to contain file header."); return(false); } var fileBytes = r.ReadBytes((int)length); UInt32 flags = BitConverter.ToUInt32(fileBytes, 0); if ((flags & 0x0000FFFF) != 0) { var s = new ArraySegment <byte>(fileBytes, 0, 6); if (!Header.ReadFile(s)) { ParseError("Failed to read file header (old style)."); return(false); } var headLen = Header.FileCount * 12; if (length < (6 + headLen)) { ParseError("File length too short to contain entry headers."); return(false); } HeadLength = (uint)(6 + headLen); headerBytes = new byte[HeadLength]; Buffer.BlockCopy(fileBytes, 0, headerBytes, 0, (int)HeadLength); } else { if ((flags & (uint)MIXFlags.HasChecksum) != 0) { Flags |= MIXFlags.HasChecksum; } if ((flags & (uint)MIXFlags.HasEncryption) != 0) { Flags |= MIXFlags.HasEncryption; } if (Flags.HasFlag(MIXFlags.HasEncryption)) { // uh oh var key80 = fileBytes.Skip(4).Take(80).ToArray(); var key56 = new byte[56]; MIX_Magic.get_blowfish_key(key80, ref key56); var bf = new Blowfish(key56); var header = fileBytes.Skip(84).Take(8).ToArray(); bf.Decipher(header, 8); var s = new ArraySegment <byte>(header, 0, 6); if (!Header.ReadFile(s)) { ParseError("Failed to read file header (encrypted style, yo)."); return(false); } var hSize = Header.FileCount * 12 + 6; hSize += 8 - (hSize % 8); var blockCount = hSize >> 3; HeadLength = (uint)(84 + hSize); if (length < (84 + hSize)) { ParseError("File length too short to contain entry headers."); return(false); } var decoded = new byte[hSize]; Buffer.BlockCopy(header, 0, decoded, 0, 8); --blockCount; var encoded = new byte[blockCount * 8]; Buffer.BlockCopy(fileBytes, 92, encoded, 0, blockCount * 8); for (var i = 0; i < blockCount; ++i) { bf.Decipher(encoded, 8, i * 8); } Buffer.BlockCopy(encoded, 0, decoded, 8, blockCount * 8); headerBytes = decoded; } else { var s = new ArraySegment <byte>(fileBytes, 4, 6); if (!Header.ReadFile(s)) { ParseError("Failed to read file header (new style)."); return(false); } var headLen = Header.FileCount * 12; if (length < (10 + headLen)) { ParseError("File length too short to contain entry headers."); return(false); } HeadLength = (uint)(10 + headLen); headerBytes = new byte[HeadLength - 4]; Buffer.BlockCopy(fileBytes, 4, headerBytes, 0, (int)HeadLength - 4); } } if (!ReadEntryHeaders()) { ParseError("Failed to read entry headers."); return(false); } ParseLMD(); return(true); }