Advertisement
_FT_

Tenchu unpacker

Apr 12th, 2014
390
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 5.66 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.IO;
  6.  
  7. namespace unTenchu
  8. {
  9.     class Program
  10.     {
  11.         static void Main(string[] args)
  12.         {
  13.             Console.WriteLine("AFS Volume 200 Unpacker");
  14.             if (args.Length == 0)
  15.             {
  16.                 Console.WriteLine("usage: untenchu inFile.vol");
  17.                 return;
  18.             }
  19.             try
  20.             {
  21.                 AFSvol200 volume = new AFSvol200(args[0]);
  22.                 foreach (string file in volume.FileList)
  23.                 {
  24.                     Console.WriteLine(file);
  25.                     EnsureDirectoryExists(new FileInfo(file).Directory);
  26.                     File.WriteAllBytes(file, volume.GetFile(file));
  27.                 }
  28.             }
  29.             catch (Exception e)
  30.             {
  31.                 Console.WriteLine(e.Message);
  32.             }
  33.         }
  34.  
  35.         public static void EnsureDirectoryExists(DirectoryInfo di)
  36.         {
  37.             if (di.Exists)
  38.                 return;
  39.  
  40.             EnsureDirectoryExists(di.Parent);
  41.             di.Create();
  42.         }
  43.     }
  44.  
  45.     class AFSvol200
  46.     {
  47.         BinaryReader br;
  48.         IndexInfo[] IndexData;
  49.         const ulong MagicA = 6866950764218238529;   // "AFS_VOL_"
  50.         const uint MagicB = 3158066;   // "200\0"
  51.  
  52.         public AFSvol200(string fi)
  53.         {
  54.             br = new BinaryReader(File.OpenRead(fi));
  55.             ulong firstRead = br.ReadUInt64();
  56.             uint secondRead = br.ReadUInt32();
  57.            
  58.             if (firstRead != MagicA)
  59.                 throw new Exception("invalid magic number");
  60.  
  61.             if (secondRead != MagicB)
  62.                 throw new Exception("invalid magic number");
  63.  
  64.             uint indicies = read32bigEndian();
  65.             uint toc_offset = read32bigEndian();
  66.             IndexData = new IndexInfo[indicies];
  67.  
  68.             br.BaseStream.Position = toc_offset;
  69.             for (int i = 0; i < indicies; i++)
  70.             {
  71.                 br.ReadUInt16();    //This is always "IX", and we don't need to know that.
  72.                 IndexData[i] = new IndexInfo();
  73.                 IndexData[i].idxType = (IndexType)read16bigEndian();
  74.                 IndexData[i].offset = read32bigEndian();
  75.                 IndexData[i].size = read32bigEndian();
  76.                 IndexData[i].sizeBackup = read32bigEndian();    //I don't know why the size is stored twice. Did they want compression?
  77.                 IndexData[i].blob = readFixedString(20);
  78.  
  79.                 while (IndexData[i].blob.EndsWith("\0"))
  80.                     IndexData[i].blob = IndexData[i].blob.Substring(0, IndexData[i].blob.Length - 1);
  81.  
  82.                 if (IndexData[i].HasMother)
  83.                     IndexData[i].mother = IndexData[IndexData[i].MotherId];
  84.             }
  85.         }
  86.  
  87.         string readFixedString(int len)
  88.         {
  89.             return Encoding.ASCII.GetString(br.ReadBytes(len));
  90.         }
  91.  
  92.         uint read32bigEndian()
  93.         {
  94.             byte[] v = br.ReadBytes(4);
  95.             byteswap(v, 0, 3);
  96.             byteswap(v, 1, 2);
  97.             return BitConverter.ToUInt32(v, 0);
  98.         }
  99.  
  100.         uint read16bigEndian()
  101.         {
  102.             byte[] v = br.ReadBytes(2);
  103.             byteswap(v, 0,1);
  104.             return BitConverter.ToUInt16(v, 0);
  105.         }
  106.         void byteswap(byte[] data, int left, int right) //I know this can be done a lot more elegant - but i'm laaaaazy :D
  107.         {
  108.             byte t = data[left];        
  109.             data[left] = data[right];
  110.             data[right] = t;
  111.         }
  112.  
  113.         public string[] FileList
  114.         {
  115.             get
  116.             {
  117.                 List<string> result = new List<string>();
  118.                
  119.                 for (int i = 0; i < IndexData.Length; i++)
  120.                     if (IndexData[i].idxType == IndexType.File)
  121.                         result.Add(IndexData[i].ToString());
  122.  
  123.                 return result.ToArray();
  124.             }
  125.         }
  126.  
  127.         public byte[] GetFile(string filename)
  128.         {
  129.             for (int i = 0; i < IndexData.Length; i++)
  130.             {
  131.                 if (IndexData[i].ToString() == filename)
  132.                 {
  133.                     br.BaseStream.Position = IndexData[i].offset;
  134.                     return br.ReadBytes((int)IndexData[i].size);
  135.                 }
  136.             }
  137.             throw new FileNotFoundException();
  138.         }
  139.     }
  140.  
  141.     enum IndexType : ushort
  142.     {
  143.         Directory = 2,
  144.         File = 1,
  145.     }
  146.  
  147.     class IndexInfo
  148.     {
  149.         public IndexType idxType;
  150.         public uint offset, size, sizeBackup;
  151.         public string blob;
  152.         public IndexInfo mother;
  153.  
  154.         public bool HasMother
  155.         {
  156.             get { return blob.Split('_').Length >= 2; }
  157.         }
  158.  
  159.         public int MotherId
  160.         {
  161.             get
  162.             {
  163.                 if (!HasMother)
  164.                     return 0;
  165.  
  166.                 string mString = blob.Split('_')[0];
  167.                 mString = mString.Substring(1, mString.Length - 1);
  168.                 return Convert.ToInt32(mString);
  169.             }
  170.         }
  171.  
  172.         public string BaseName
  173.         {
  174.             get
  175.             {
  176.                 if (HasMother)
  177.                     return blob.Split(new char[] { '_' }, 2)[1];
  178.                 else
  179.                     return blob;
  180.             }
  181.         }
  182.  
  183.         public override string ToString()
  184.         {
  185.             string rValue;
  186.            
  187.             if (HasMother)
  188.                 rValue = mother.ToString() + "\\" + BaseName;
  189.             else
  190.                 rValue = BaseName;
  191.  
  192.             return rValue.Replace(':', '_');
  193.         }
  194.     }
  195. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement