Dr_Asik

MTFExtractor

Mar 3rd, 2012
279
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4.  
  5. namespace MTFExtractor {
  6.     struct DataEntry {
  7.         public string Path;
  8.         public int Offset;
  9.         public int Size;
  10.     }
  11.  
  12.  
  13.     class MtfExtractor {
  14.         List<string> filesToExtract;
  15.         List<DataEntry> dataEntries;
  16.         public MtfExtractor(List<string> mtfFiles) {
  17.             filesToExtract = mtfFiles;
  18.         }
  19.  
  20.         public void Execute() {
  21.             foreach (var f in filesToExtract) {
  22.                 Console.WriteLine("Processing {0}...", f);
  23.                 try {
  24.                     using (var fileStream = new FileStream(f, FileMode.Open))
  25.                     using (var binaryReader = new BinaryReader(fileStream)) {
  26.                         ProcessFile(binaryReader);
  27.                     }
  28.                 }
  29.                 catch (Exception e) {
  30.                     var errorMessage = string.Format("Error processing file {0} : {1}\n", f, e.Message);
  31.                     File.AppendAllText("log.txt", errorMessage);
  32.                     Console.WriteLine(errorMessage);
  33.                 }
  34.             }
  35.         }
  36.  
  37.         void ProcessFile(BinaryReader binaryReader) {
  38.             dataEntries = new List<DataEntry>();
  39.             int numEntries = binaryReader.ReadInt32();
  40.             Console.WriteLine("{0} entries found.", numEntries);
  41.             for (int i = 0; i < numEntries; ++i) {
  42.                 CreateEntry(binaryReader);
  43.             }
  44.  
  45.             for (int i = 0; i < numEntries; ++i) {
  46.                 ProcessEntry(dataEntries[i], binaryReader);
  47.             }
  48.         }
  49.  
  50.         void ProcessEntry(DataEntry dataEntry, BinaryReader binaryReader) {
  51.             binaryReader.BaseStream.Seek(dataEntry.Offset, SeekOrigin.Begin);
  52.             var fileInfo = new FileInfo(dataEntry.Path);
  53.             fileInfo.Directory.Create();
  54.             using (var file = File.Create(dataEntry.Path)) {
  55.                 ProcessData(binaryReader, file, dataEntry);
  56.             }
  57.         }
  58.  
  59.         void ProcessData(BinaryReader binaryReader, FileStream file, DataEntry entry) {
  60.             // Check if it's compressed or not
  61.             int idSize = 4;
  62.             var ID = binaryReader.ReadBytes(idSize);
  63.             // If it's compressed, the first two bytes are AF BE or AE BE
  64.             if (ID[1] == 0xBE && (ID[0] == 0xAF || ID[0] == 0xAE)) {
  65.                 ProcessCompressedData(binaryReader, file, entry);
  66.             }
  67.             else {
  68.                 // otherwise these bytes are part of the data, so seek back
  69.                 binaryReader.BaseStream.Seek(-idSize, SeekOrigin.Current);
  70.                 ProcessUncompressedData(binaryReader, file, entry);
  71.             }
  72.         }
  73.  
  74.         // If it's uncompressed, just copy-paste the data in the destination file.
  75.         void ProcessUncompressedData(BinaryReader binaryReader, FileStream file, DataEntry entry) {
  76.             file.Write(binaryReader.ReadBytes(entry.Size), 0, entry.Size);
  77.         }
  78.  
  79.  
  80.         // If it's compressed... argh.
  81.         // Decompression pseudo-code from http://wiki.xentax.com/index.php/Darkstone
  82.         void ProcessCompressedData(BinaryReader binaryReader, FileStream file, DataEntry entry) {
  83.             // Skip "numBlocks" and "flags", they're of no use
  84.             binaryReader.BaseStream.Seek(8, SeekOrigin.Current);
  85.             var decompressedBytes = new byte[entry.Size];
  86.             var outputIndex = 0;
  87.  
  88.             // "This is repeated until decompressed buffer reach the Decompressed File Length in MTF header."
  89.             while (outputIndex < entry.Size) {
  90.  
  91.                 // "First byte of each chunk describes what to do with next data you read."
  92.                 byte indicator = binaryReader.ReadByte();
  93.  
  94.                 // "You need to check every bit:"
  95.                 for (int j = 0; j < 8; ++j) {
  96.                     if ((indicator & (1 << j)) != 0) {
  97.                         // "If bit=1 then just copy 1 byte from compressed buffer to decompressed buffer"
  98.                         decompressedBytes[outputIndex++] = binaryReader.ReadByte();
  99.                     }
  100.                     else {
  101.                         // "If bit=0 then read 10 bits for X and 6 bits for Y" - "07 0C means X = 3 and Y = 7"
  102.                         // This is very confusing. What is really meant is:
  103.                         // Read 2 bytes, swap them (reading an Int16 in Little-Endian does the trick)
  104.                         ushort word = (ushort)binaryReader.ReadInt16();
  105.  
  106.                         // For some reason, if and only if word == 0, we end up writing past our output buffer.
  107.                         // It appears we can safely ignore all of these.
  108.                         if (word == 0) {
  109.                             break;
  110.                         }
  111.  
  112.                         byte X = (byte)(word >> 10); // The first 6 bits are then X                        
  113.                         ushort Y = (ushort)(word & 0x3FF); // And the last 10 bits are Y
  114.  
  115.                         // "copy X+3 bytes from offset Y of decompressed buffer at the end of decompressed buffer"
  116.                         for (int k = 0; k < X + 3; ++k) {
  117.                             decompressedBytes[outputIndex] = decompressedBytes[outputIndex - Y];
  118.                             ++outputIndex;
  119.                         }
  120.                     }
  121.                 }
  122.             }
  123.             file.Write(decompressedBytes, 0, decompressedBytes.Length);
  124.         }
  125.  
  126.         void CreateEntry(BinaryReader binaryReader) {
  127.             int stringLength = binaryReader.ReadInt32();
  128.             var entry = new DataEntry {
  129.                 Path = UnsafeAsciiBytesToString(binaryReader.ReadBytes(stringLength)),
  130.                 Offset = binaryReader.ReadInt32(),
  131.                 Size = binaryReader.ReadInt32()
  132.             };
  133.             dataEntries.Add(entry);
  134.         }
  135.  
  136.         string UnsafeAsciiBytesToString(byte[] buffer) {
  137.             unsafe {
  138.                 fixed (byte* pAscii = buffer) {
  139.                     return new string((sbyte*)pAscii);
  140.                 }
  141.             }
  142.         }
  143.  
  144.  
  145.         static void Main(string[] args) {
  146.             var mtfFiles = new List<string>();
  147.  
  148.             // If file specified, extract that file, otherwise extract all mtf files in current working directory
  149.             if (args.Length == 1) {
  150.                 mtfFiles.Add(args[0]);
  151.             }
  152.             else {
  153.                 foreach (var f in Directory.EnumerateFiles(Environment.CurrentDirectory)) {
  154.                     if (f.EndsWith(".MTF", StringComparison.CurrentCultureIgnoreCase)) {
  155.                         mtfFiles.Add(f);
  156.                     }
  157.                 }
  158.             }
  159.             new MtfExtractor(mtfFiles).Execute();
  160.             Console.WriteLine("All done!");
  161.         }
  162.     }
  163. }
RAW Paste Data

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×