diff --git a/MixBrowser/MixBrowser.csproj b/MixBrowser/MixBrowser.csproj
index 8ce997f6b4..4bad552aca 100644
--- a/MixBrowser/MixBrowser.csproj
+++ b/MixBrowser/MixBrowser.csproj
@@ -18,6 +18,7 @@
DEBUG;TRACE
prompt
4
+ false
pdbonly
@@ -36,6 +37,7 @@
+
diff --git a/MixBrowser/MixEntry.cs b/MixBrowser/MixEntry.cs
index 2b950c069b..34830cef95 100644
--- a/MixBrowser/MixEntry.cs
+++ b/MixBrowser/MixEntry.cs
@@ -57,5 +57,7 @@ namespace MixBrowser
uint hash = HashFilename(s);
Names.Add(hash, s);
}
+
+ public const int Size = 12;
}
}
diff --git a/MixBrowser/MixFile.cs b/MixBrowser/MixFile.cs
new file mode 100644
index 0000000000..375826a8e0
--- /dev/null
+++ b/MixBrowser/MixFile.cs
@@ -0,0 +1,146 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+
+namespace MixBrowser
+{
+ class MixFile
+ {
+ readonly string filename;
+ readonly List index;
+ readonly bool isRmix, isEncrypted;
+
+ public ICollection Content
+ {
+ get { return index.AsReadOnly(); }
+ }
+
+ public MixFile(string filename)
+ {
+ this.filename = filename;
+ using (Stream s = File.OpenRead(filename))
+ {
+ BinaryReader reader = new BinaryReader(s);
+ uint signature = reader.ReadUInt32();
+
+ isRmix = 0 == (signature & ~(uint)(MixFileFlags.Checksum | MixFileFlags.Encrypted));
+
+ if (isRmix)
+ {
+ isEncrypted = 0 != (signature & (uint)MixFileFlags.Encrypted);
+ index = ParseRaHeader(s);
+ }
+ else
+ {
+ isEncrypted = false;
+ s.Seek(0, SeekOrigin.Begin);
+ index = ParseTdHeader(s);
+ }
+ }
+ }
+
+ List ParseRaHeader(Stream s)
+ {
+ if (!isEncrypted)
+ return ParseTdHeader(s);
+
+ long headerStart = 84;
+ BinaryReader reader = new BinaryReader(s);
+ byte[] keyblock = reader.ReadBytes(80);
+ byte[] blowfishKey = MixDecrypt.MixDecrypt.BlowfishKey(keyblock);
+
+ uint[] h = ReadUints(reader, 2);
+
+ Blowfish fish = new Blowfish(blowfishKey);
+ uint[] decrypted = fish.Decrypt(h);
+
+ MemoryStream ms = new MemoryStream();
+ BinaryWriter writer = new BinaryWriter(ms);
+ foreach (uint t in decrypted)
+ writer.Write(t);
+ writer.Flush();
+
+ ms.Position = 0;
+ BinaryReader reader2 = new BinaryReader(ms);
+
+ ushort numFiles = reader.ReadUInt16();
+ uint datasize = reader.ReadUInt32();
+
+ Console.WriteLine("{0} files, {1} kb", numFiles, datasize >> 10);
+
+ s.Position = headerStart;
+ reader = new BinaryReader(s);
+
+ h = ReadUints(reader, 2 + numFiles * MixEntry.Size / 4);
+ decrypted = fish.Decrypt(h);
+
+ ms = new MemoryStream();
+ writer = new BinaryWriter(ms);
+ foreach (uint t in decrypted)
+ writer.Write(t);
+ writer.Flush();
+
+ ms.Position = 0;
+
+ return ParseTdHeader(ms);
+ }
+
+ uint[] ReadUints(BinaryReader r, int count)
+ {
+ uint[] ret = new uint[count];
+ for (int i = 0; i < ret.Length; i++)
+ ret[i] = r.ReadUInt32();
+
+ return ret;
+ }
+
+ List ParseTdHeader(Stream s)
+ {
+ List items = new List();
+
+ BinaryReader reader = new BinaryReader(s);
+ ushort numFiles = reader.ReadUInt16();
+ uint dataSize = reader.ReadUInt32();
+
+ for (int i = 0; i < numFiles; i++)
+ items.Add(new MixEntry(reader));
+
+ return items;
+ }
+
+ public Stream GetContent(uint hash)
+ {
+ foreach( MixEntry e in index )
+ if (e.Hash == hash)
+ {
+ using (Stream s = File.OpenRead(filename))
+ {
+ s.Seek(2 + 4 + (isRmix ? 4 : 0), SeekOrigin.Begin);
+ if (isEncrypted)
+ s.Seek(80, SeekOrigin.Current);
+
+ s.Seek(index.Count * MixEntry.Size + e.Offset, SeekOrigin.Current);
+ byte[] data = new byte[ e.Length ];
+ s.Read( data, 0, (int)e.Length );
+ return new MemoryStream(data);
+ }
+ }
+
+ throw new FileNotFoundException();
+ }
+
+ public Stream GetContent(string filename)
+ {
+ return GetContent(MixEntry.HashFilename(filename));
+ }
+
+ }
+
+ [Flags]
+ enum MixFileFlags : uint
+ {
+ Checksum = 0x10000,
+ Encrypted = 0x20000,
+ }
+}
diff --git a/MixBrowser/Program.cs b/MixBrowser/Program.cs
index 8194d2d8a8..af854a2ffd 100644
--- a/MixBrowser/Program.cs
+++ b/MixBrowser/Program.cs
@@ -31,58 +31,7 @@ namespace MixBrowser
return;
}
- Stream s = File.Open(fn, FileMode.Open, FileAccess.Read);
- BinaryReader reader = new BinaryReader(s);
-
- uint signature = reader.ReadUInt32();
-
- if (0 == (signature & ~(uint)(MixFileFlags.Checksum | MixFileFlags.Encrypted)))
- {
- Console.WriteLine("{0} - Red Alert MIX", Path.GetFileName(fn));
- if (0 != (signature & (uint)MixFileFlags.Checksum))
- Console.WriteLine("Checksum: YES");
- if (0 != (signature & (uint)MixFileFlags.Encrypted))
- {
- Console.WriteLine("Encrypted: YES");
-
- //get the blowfish key
- byte[] bfkey = MixDecrypt.MixDecrypt.BlowfishKey(reader.ReadBytes(80));
-
- Blowfish fish = new Blowfish(bfkey);
-
- uint[] data = { reader.ReadUInt32(), reader.ReadUInt32() };
- uint[] decrypted = fish.Decrypt(data);
-
- MemoryStream ms = new MemoryStream();
- BinaryWriter w = new BinaryWriter(ms);
- foreach (uint u in decrypted)
- w.Write(u);
- w.Flush();
- ms.Seek(0, SeekOrigin.Begin);
-
- BinaryReader reader2 = new BinaryReader(ms);
-
- ushort numfiles2 = reader2.ReadUInt16();
- uint datasize2 = reader2.ReadUInt32();
-
- Console.WriteLine("{0} files - {1} KB", numfiles2, datasize2 >> 10);
-
- return;
- }
- }
- else
- Console.WriteLine("{0} - Tiberian Dawn MIX", Path.GetFileName(fn) );
-
- s.Seek(0, SeekOrigin.Begin);
- reader = new BinaryReader(s);
-
- ushort numfiles = reader.ReadUInt16();
- uint datasize = reader.ReadUInt32();
- Console.WriteLine("{0} files - {1} KB", numfiles, datasize >> 10);
-
- List index = new List();
- for (ushort i = 0; i < numfiles; i++)
- index.Add(new MixEntry(reader));
+ MixFile file = new MixFile(fn);
if (File.Exists("files.txt"))
foreach (string filename in File.ReadAllLines("files.txt"))
@@ -90,15 +39,8 @@ namespace MixBrowser
else
Console.WriteLine("-- files.txt doesnt exist --");
- foreach (MixEntry e in index)
+ foreach (MixEntry e in file.Content)
Console.WriteLine(e);
}
}
-
- [Flags]
- enum MixFileFlags : uint
- {
- Checksum = 0x10000,
- Encrypted = 0x20000,
- }
}