Advertisement
Mygod

Little Inferno Resource Unpacker Source

Dec 7th, 2012
126
0
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.Drawing;
  4. using System.Drawing.Imaging;
  5. using System.IO;
  6. using System.IO.Compression;
  7. using System.Linq;
  8. using System.Text;
  9.  
  10. namespace Mygod.LittleInferno.Resource.Unpacker
  11. {
  12.     public static class Program
  13.     {
  14.         private static void Main(string[] args)
  15.         {
  16.             if (args == null || args.Length == 0)
  17.             {
  18.                 DoubleWriter.WriteLine("Drag files onto the program to start unpacking!");
  19.                 Console.ReadKey();
  20.                 return;
  21.             }
  22.             DoubleWriter.Output = new StreamWriter(File.Create("output.txt")) {AutoFlush = true};
  23.             const string directory = "EXTRACTED";
  24.             const string temp = directory + "_TEMP";
  25.             Directory.CreateDirectory(directory);
  26.             Directory.CreateDirectory(temp);
  27.             Package lastPackage = null;
  28.             foreach (var arg in args.Where(File.Exists))
  29.             {
  30.                 DoubleWriter.WriteLine("INFO: Unpacking file: {0}", arg);
  31.                 ErrorCount = WarningCount = 0;
  32.                 InformationCount = 1;
  33.                 try
  34.                 {
  35.                     (lastPackage = new Package(arg)).ExtractAll(temp);
  36.                 }
  37.                 catch (Exception exc)
  38.                 {
  39.                     DoubleWriter.WriteLine("ERROR: {0}", exc.Message);
  40.                     ErrorCount++;
  41.                 }
  42.                 DoubleWriter.WriteLine("Unpacking done. {0} error(s), {1} warning(s), {2} info(s).", ErrorCount, WarningCount, InformationCount);
  43.                 DoubleWriter.WriteLine();
  44.             }
  45.             if (lastPackage != null)
  46.             {
  47.                 DoubleWriter.WriteLine("INFO: Moving files into the correct path.");
  48.                 ErrorCount = WarningCount = 0;
  49.                 InformationCount = 1;
  50.                 var decodePosition = lastPackage.MoveFiles(directory, temp) ? directory : temp;
  51.                 DoubleWriter.WriteLine("Moving done. {0} error(s), {1} warning(s), {2} info(s).", ErrorCount, WarningCount, InformationCount);
  52.                 DoubleWriter.WriteLine();
  53.                 DoubleWriter.WriteLine("INFO: Trying to decode images.");
  54.                 ErrorCount = WarningCount = 0;
  55.                 InformationCount = 1;
  56.                 TryDecodeFiles(decodePosition);
  57.                 DoubleWriter.WriteLine("Decoding done. {0} error(s), {1} warning(s), {2} info(s).", ErrorCount, WarningCount, InformationCount);
  58.                 DoubleWriter.WriteLine();
  59.             }
  60.             DoubleWriter.Output.Close();
  61.         }
  62.  
  63.         public static void TryDecodeFiles(string directoryPath)
  64.         {
  65.             var queue = new Queue<DirectoryInfo>();
  66.             queue.Enqueue(new DirectoryInfo(directoryPath));
  67.             while (queue.Count > 0)
  68.             {
  69.                 var dir = queue.Dequeue();
  70.                 foreach (var info in dir.EnumerateFileSystemInfos())
  71.                 {
  72.                     var dirInfo = info as DirectoryInfo;
  73.                     if (dirInfo != null)
  74.                     {
  75.                         queue.Enqueue(dirInfo);
  76.                         continue;
  77.                     }
  78.                     var fileInfo = info as FileInfo;
  79.                     if (fileInfo == null) continue;
  80.                     TryDecodeImage(fileInfo);
  81.                 }
  82.             }
  83.         }
  84.  
  85.         private static void TryDecodeImage(FileInfo fileInfo)
  86.         {
  87.             RawImage image = null;
  88.             var path = fileInfo.FullName;
  89.             try
  90.             {
  91.                 if (path.ToLower().EndsWith(".raw")) return;
  92.                 using (var stream = fileInfo.OpenRead()) image = new RawImage(stream);
  93.                 fileInfo.MoveTo(path + ".raw");
  94.                 image.SaveToFile(path);
  95.             }
  96.             catch (Exception exc)
  97.             {
  98.                 DoubleWriter.WriteLine("WARNING: {0} is not an image. ({1})", path, exc.Message);
  99.                 WarningCount++;
  100.             }
  101.             finally
  102.             {
  103.                 if (image != null) image.Dispose();
  104.             }
  105.         }
  106.  
  107.         public static int ErrorCount, WarningCount, InformationCount;
  108.     }
  109.  
  110.     public class Package : IDisposable
  111.     {
  112.         public Package(string filePath)
  113.         {
  114.             path = filePath;
  115.             stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
  116.             if (!stream.CanRead || !stream.CanSeek) throw new NotSupportedException("The file stream is terrible!");
  117.             reader = new BinaryReader(stream);
  118.             PackageVersion = reader.ReadInt32();
  119.             if (PackageVersion != 1) throw new NotSupportedException("Unsupported package version: " + PackageVersion);
  120.             var count = reader.ReadInt32();
  121.             Records = new List<FileRecord>(count);
  122.             for (var i = 0; i < count; i++) Records.Add(new FileRecord(reader));
  123.         }
  124.  
  125.         private static string ReadString(BinaryReader reader)
  126.         {
  127.             var strBytes = new List<byte>();
  128.             int b;
  129.             while ((b = reader.ReadByte()) > 0) strBytes.Add((byte)b);
  130.             return Encoding.UTF8.GetString(strBytes.ToArray());
  131.         }
  132.  
  133.         public void ExtractAll(string directory)
  134.         {
  135.             foreach (var record in Records) Extract(record, Path.Combine(directory, record.ID.ToString()));
  136.         }
  137.         public void Extract(FileRecord record, string filePath)
  138.         {
  139.             int unpackedSize;
  140.             byte[] data;
  141.             lock (reader)
  142.             {
  143.                 stream.Seek(record.Offset, SeekOrigin.Begin);
  144.                 var packedSize = reader.ReadInt32();
  145.                 unpackedSize = reader.ReadInt32();
  146.                 data = reader.ReadBytes(packedSize);
  147.             }
  148.             if (record.Flags == 0)
  149.             {
  150.                 File.WriteAllBytes(filePath, data);
  151.                 DoubleWriter.WriteLine("INFO: Unpacking item #{0} done.", record.ID);
  152.                 Program.InformationCount++;
  153.                 return;
  154.             }
  155.             using (var fileStream = File.Create(filePath))
  156.             using (var memoryStream = new MemoryStream(data))
  157.             using (var deflateStream = new DeflateStream(memoryStream, CompressionMode.Decompress))
  158.             {
  159.                 memoryStream.ReadByte();
  160.                 memoryStream.ReadByte();
  161.                 try
  162.                 {
  163.                     deflateStream.CopyTo(fileStream);
  164.                     if (fileStream.Length != unpackedSize)
  165.                     {
  166.                         DoubleWriter.WriteLine("WARNING: File size does not match. (item #{0})", record.ID);
  167.                         Program.WarningCount++;
  168.                     }
  169.                     DoubleWriter.WriteLine("INFO: Unpacking item #{0} done.", record.ID);
  170.                     Program.InformationCount++;
  171.                 }
  172.                 catch (InvalidDataException)
  173.                 {
  174.                     DoubleWriter.WriteLine("ERROR: Unpacking item #{0} failed.", record.ID);
  175.                     Program.ErrorCount++;
  176.                 }
  177.             }
  178.         }
  179.         public bool MoveFiles(string directory, string temp)
  180.         {
  181.             var map = Path.Combine(temp, "3085189639");
  182.             if (!File.Exists(map))
  183.             {
  184.                 DoubleWriter.WriteLine("ERROR: Maps not found!");
  185.                 Program.ErrorCount++;
  186.                 return false;
  187.             }
  188.             using (var fileStream = new FileStream(map, FileMode.Open, FileAccess.Read, FileShare.Read))
  189.             {
  190.                 if (!fileStream.CanRead || !fileStream.CanSeek) throw new NotSupportedException("The file stream is terrible!");
  191.                 using (var mapReader = new BinaryReader(fileStream))
  192.                 {
  193.                     BinaryHeaderPointer maps = new BinaryHeaderPointer(mapReader), stringTableBytes = new BinaryHeaderPointer(mapReader);
  194.                     fileStream.Seek(maps.Offset, SeekOrigin.Begin);
  195.                     var dic = new Dictionary<uint, int>(maps.Count);
  196.                     for (var i = 0; i < maps.Count; i++) dic.Add(mapReader.ReadUInt32(), mapReader.ReadInt32());
  197.                     fileStream.Seek(stringTableBytes.Offset, SeekOrigin.Begin);
  198.                     int numStrings = mapReader.ReadInt32(), numPointers = mapReader.ReadInt32();
  199.                     var stringPointers = new List<StringPointer>(numStrings);
  200.                     for (var i = 0; i < numStrings; i++) stringPointers.Add(new StringPointer(mapReader));
  201.                     var pointerPointers = new List<LanguagePointer>(numPointers);
  202.                     for (var i = 0; i < numPointers; i++) pointerPointers.Add(new LanguagePointer(mapReader));
  203.                     var baseOffset = fileStream.Position;
  204.                     // DoubleWriter.WriteLine(pointerPointers.Min(p => p.Offset));   // for debugging purpose
  205.  
  206.                     foreach (var file in new DirectoryInfo(temp).EnumerateFiles())
  207.                     {
  208.                         try
  209.                         {
  210.                             var id = uint.Parse(file.Name);
  211.                             var stringPointer = stringPointers[dic[id]];
  212.                             var pointer = default(LanguagePointer);
  213.                             for (var i = 0; i < stringPointer.Count; i++)
  214.                             {
  215.                                 pointer = pointerPointers[stringPointer.Index + i];
  216.                                 if (pointer.LanguageID == 25966) break; // ne
  217.                             }
  218.                             if (pointer.LanguageID != 25966) throw new Exception("Language ne not found!");
  219.                             fileStream.Seek(baseOffset + pointer.Offset, SeekOrigin.Begin);
  220.                             string realPath = ReadString(mapReader), absolutePath = Path.Combine(directory, realPath);
  221.                             // ReSharper disable AssignNullToNotNullAttribute
  222.                             Directory.CreateDirectory(Path.GetDirectoryName(absolutePath));
  223.                             // ReSharper restore AssignNullToNotNullAttribute
  224.                             try
  225.                             {
  226.                                 file.MoveTo(absolutePath);
  227.                             }
  228.                             catch (IOException)
  229.                             {
  230.                                 file.CopyTo(absolutePath);  // copy it at least
  231.                                 file.Delete();
  232.                             }
  233.                             DoubleWriter.WriteLine("INFO: File moved successfully: {0}", realPath);
  234.                             Program.InformationCount++;
  235.                         }
  236.                         catch (Exception exc)
  237.                         {
  238.                             DoubleWriter.WriteLine("ERROR: ({0}) {1}", exc.GetType(), exc.Message);
  239.                             Program.ErrorCount++;
  240.                         }
  241.                     }
  242.                 }
  243.             }
  244.             return true;
  245.         }
  246.  
  247.         public void Dispose()
  248.         {
  249.             reader.Close();
  250.             stream.Close();
  251.         }
  252.  
  253.         private readonly FileStream stream;
  254.         private readonly BinaryReader reader;
  255.         private readonly string path;
  256.         public int PackageVersion;
  257.         public List<FileRecord> Records;
  258.     }
  259.  
  260.     public struct FileRecord
  261.     {
  262.         public uint ID, Flags;
  263.         public int Offset, Size;
  264.  
  265.         public FileRecord(BinaryReader reader)
  266.         {
  267.             ID = reader.ReadUInt32();
  268.             Flags = reader.ReadUInt32();
  269.             if (Flags > 1)
  270.             {
  271.                 //throw new NotSupportedException("Unsupported file record flags: " + Flags);
  272.                 DoubleWriter.WriteLine("WARNING: Unsupported file record flags value {0}. (item #{1})", Flags, ID);
  273.                 Program.WarningCount++;
  274.             }
  275.             Offset = reader.ReadInt32();
  276.             Size = reader.ReadInt32();
  277.         }
  278.     }
  279.  
  280.     public struct BinaryHeaderPointer
  281.     {
  282.         public int Count, Offset;
  283.  
  284.         public BinaryHeaderPointer(BinaryReader reader)
  285.         {
  286.             Count = reader.ReadInt32();
  287.             Offset = reader.ReadInt32();
  288.         }
  289.     }
  290.  
  291.     public struct StringPointer
  292.     {
  293.         public int Index, Count;
  294.  
  295.         public StringPointer(BinaryReader reader)
  296.         {
  297.             Index = reader.ReadInt32();
  298.             Count = reader.ReadInt32();
  299.         }
  300.     }
  301.  
  302.     public struct LanguagePointer
  303.     {
  304.         public uint LanguageID;
  305.         public int Offset;
  306.  
  307.         public LanguagePointer(BinaryReader reader)
  308.         {
  309.             LanguageID = reader.ReadUInt32();
  310.             Offset = reader.ReadInt32();
  311.         }
  312.     }
  313.  
  314.     public class RawImage : IDisposable
  315.     {
  316.         public RawImage(Stream stream)
  317.         {
  318.             using (var reader = new BinaryReader(stream))
  319.             {
  320.                 Width = reader.ReadInt32();
  321.                 Height = reader.ReadInt32();
  322.                 if (Width * Height * 4 + 12 != stream.Length) throw new Exception("Length incorrect.");
  323.                 Bitmap = new Bitmap(Width, Height, PixelFormat.Format32bppArgb);
  324.                 Type = (ImageType) reader.ReadInt32();
  325.                 switch (Type)
  326.                 {
  327.                     case ImageType.RGBA:
  328.                         for (var y = 0; y < Height; y++) for (var x = 0; x < Width; x++)
  329.                         {
  330.                             byte b = reader.ReadByte(), g = reader.ReadByte(), r = reader.ReadByte(), a = reader.ReadByte();
  331.                             Bitmap.SetPixel(x, y, Color.FromArgb(a, r, g, b));
  332.                         }
  333.                         break;
  334.                     case ImageType.Greyscale:
  335.                         for (var y = 0; y < Height; y++) for (var x = 0; x < Width; x++)
  336.                         {
  337.                             byte ca = reader.ReadByte(), cc = reader.ReadByte(), ac = reader.ReadByte(), aa = reader.ReadByte();
  338.                             Bitmap.SetPixel(x, y, Color.FromArgb((byte) (ca * aa * ac / 16581375.0), cc, cc, cc));
  339.                         }
  340.                         break;
  341.                 }
  342.             }
  343.         }
  344.  
  345.         public int Width, Height;
  346.         public ImageType Type;
  347.         public Bitmap Bitmap;
  348.  
  349.         public void SaveToFile(string filePath, ImageFormat format = null)
  350.         {
  351.             if (format == null) format = ImageFormat.Png;
  352.             var extension = '.' + format.ToString().ToLower();
  353.             if (!filePath.EndsWith(extension)) filePath += extension;
  354.             Bitmap.Save(filePath, format);
  355.         }
  356.  
  357.         public void Dispose()
  358.         {
  359.             Bitmap.Dispose();
  360.         }
  361.     }
  362.  
  363.     public enum ImageType
  364.     {
  365.         RGBA = 1, Greyscale = 8
  366.     }
  367.  
  368.     public static class DoubleWriter
  369.     {
  370.         public static StreamWriter Output;
  371.  
  372.         public static void WriteLine(string value, params object[] arg)
  373.         {
  374.             Console.WriteLine(value, arg);
  375.             if (Output != null) Output.WriteLine(value, arg);
  376.         }
  377.  
  378.         public static void WriteLine()
  379.         {
  380.             Console.WriteLine();
  381.             if (Output != null) Output.WriteLine();
  382.         }
  383.     }
  384. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement