Advertisement
Mygod

Little Inferno Resource Unpacker Source

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