private void Initialize()
        {
            Console.ForegroundColor = ConsoleColor.Cyan;
            Console.WriteLine("Loading local CASC storage...please wait");
            Console.ResetColor();

            TextWriter console = Console.Out;

            Stopwatch time = new Stopwatch();

            using ManualResetEvent resetEvent         = new ManualResetEvent(false);
            using BackgroundWorkerEx backgroundWorker = new BackgroundWorkerEx();

            backgroundWorker.DoWork += (_, e) =>
            {
                Console.SetOut(TextWriter.Null); // suppress output
                CASCConfig.ThrowOnFileNotFound         = true;
                CASCConfig.ThrowOnMissingDecryptionKey = true;
                CASCConfig config = CASCConfig.LoadLocalStorageConfig(_storagePath);
                CASCHandler = CASCHandler.OpenStorage(config, backgroundWorker);

                LocaleFlags locale = LocaleFlags.All;

                Console.SetOut(console); // enable output
                CASCHandler.Root.LoadListFile(Path.Combine(Environment.CurrentDirectory, "listfile.txt"), backgroundWorker);

                Console.SetOut(TextWriter.Null); // suppress output
                CASCFolderRoot = CASCHandler.Root.SetFlags(locale);
            };

            backgroundWorker.ProgressChanged += (_, e) =>
            {
                // main thread is blocked, so push it on another thread
                Task.Run(() => { DrawProgressBar(e.ProgressPercentage, 100, 72, '#'); });
            };

            backgroundWorker.RunWorkerCompleted += (_, e) =>
            {
                time.Stop();
                Console.SetOut(console); // enable output
                Console.Write("\r");
                DrawProgressBar(100, 100, 72, '#');

                Console.WriteLine();
                Console.WriteLine($"Finished in {time.Elapsed.TotalSeconds:0.####} seconds");
                Console.WriteLine();

                resetEvent.Set();
            };

            try
            {
                // use backgroundworker for progress reporting since it is provided by CASCLib
                // the main thread is blocked until the background process is completed
                time.Start();
                backgroundWorker.RunWorkerAsync();
                resetEvent.WaitOne();
            }
            catch (Exception ex)
            {
                resetEvent.Set();
                Console.SetOut(console);
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine();
                Console.WriteLine("Error while opening storage");
                Console.WriteLine(ex.Message);

                Console.ResetColor();
                Environment.Exit(1);
            }
        }
Esempio n. 2
0
 public void InitCasc(CASCConfig config, LocaleFlags firstInstalledLocale)
 {
     // Opens Storage
     cascHandler = CASCHandler.OpenStorage(config);
     cascHandler.Root.SetFlags(firstInstalledLocale, false);
 }
Esempio n. 3
0
        static void Main(string[] args)
        {
            // APMTool.exe "root" file flag [query]
            if (args.Length < 2)
            {
                Console.Out.WriteLine("Usage: APMTool.exe \"root directory\" op args");
                Console.Out.WriteLine("OP f: Find files in APM. args: query... query: a[APM NAME] i[INDEX HEX] t[TYPE HEX] s[SIZE LESS THAN] S[SIZE GREATER THAN] N[INDEX WITHOUT IDENTIFIER]");
                Console.Out.WriteLine("OP l: List files in package. args: query query: p[PACKAGE KEY HEX] i[CONTENT KEY HEX]");
                Console.Out.WriteLine("OP a: Output all APM names");
                Console.Out.WriteLine("OP t: Output all types");
                Console.Out.WriteLine("");
                Console.Out.WriteLine("Examples:");
                Console.Out.WriteLine("APMTool.exe overwatch l iDFEF49BEE7E66774E46DA9EEA750A552");
                Console.Out.WriteLine("APMTool.exe overwatch fa i11CE t00C");
                Console.Out.WriteLine("APMTool.exe overwatch fa i4F2");
                return;
            }
            string root = args[0];
            string flag = args[1];

            Console.Out.WriteLine("{0} v{1}", Assembly.GetExecutingAssembly().GetName().Name, OWLib.Util.GetVersion());

            OwRootHandler.LOAD_PACKAGES = true;
            CASCConfig config = null;

            // ngdp:us:pro
            // http:us:pro:us.patch.battle.net:1119
            if (root.ToLowerInvariant().Substring(0, 5) == "ngdp:")
            {
                string   cdn     = root.Substring(5, 4);
                string[] parts   = root.Substring(5).Split(':');
                string   region  = "us";
                string   product = "pro";
                if (parts.Length > 1)
                {
                    region = parts[1];
                }
                if (parts.Length > 2)
                {
                    product = parts[2];
                }
                if (cdn == "bnet")
                {
                    config = CASCConfig.LoadOnlineStorageConfig(product, region);
                }
                else
                {
                    if (cdn == "http")
                    {
                        string host = string.Join(":", parts.Skip(3));
                        config = CASCConfig.LoadOnlineStorageConfig(host, product, region, true, true, true);
                    }
                }
            }
            else
            {
                config = CASCConfig.LoadLocalStorageConfig(root, true, true);
            }

            object[] query = null;
            if (flag[0] == 'f' || flag[0] == 'C')
            {
                object[] t = new object[6] {
                    null, null, null, null, null, null
                };

                List <ulong>  id   = new List <ulong>();
                List <ulong>  type = new List <ulong>();
                List <string> apms = new List <string>();
                List <ulong>  idi  = new List <ulong>();
                for (int i = 2; i < args.Length; ++i)
                {
                    string arg = args[i];
                    try {
                        switch (arg[0])
                        {
                        case 'I':
                        case 'i':
                            id.Add(ulong.Parse(arg.Substring(1), NumberStyles.HexNumber));
                            break;

                        case 'T':
                        case 't':
                            type.Add(ulong.Parse(arg.Substring(1), NumberStyles.HexNumber));
                            break;

                        case 'n':
                        case 'N':
                            idi.Add(ulong.Parse(arg.Substring(1), NumberStyles.HexNumber));
                            break;

                        case 'a':
                            apms.Add(arg.Substring(1).ToLowerInvariant());
                            break;

                        case 's':
                        {
                            int v = int.Parse(arg.Substring(1), NumberStyles.Number);
                            if (t[2] == null)
                            {
                                t[2] = v;
                            }
                            else if (v > (int)t[2])
                            {
                                t[2] = v;
                            }
                        }
                        break;

                        case 'S':
                        {
                            int v = int.Parse(arg.Substring(1), NumberStyles.Number);
                            if (t[3] == null)
                            {
                                t[3] = v;
                            }
                            else if (v < (int)t[3])
                            {
                                t[3] = v;
                            }
                        }
                        break;
                        }
                    } finally {
                        t[0]  = id;
                        t[1]  = type;
                        t[4]  = apms;
                        t[5]  = idi;
                        query = t;
                    }
                }
            }
            else if (flag[0] == 'l')
            {
                object[] t = new object[2] {
                    null, null
                };
                List <ulong>  pkg     = new List <ulong>();
                List <string> content = new List <string>();
                for (int i = 2; i < args.Length; ++i)
                {
                    string arg = args[i];
                    try {
                        switch (arg[0])
                        {
                        case 'p':
                            pkg.Add(ulong.Parse(arg.Substring(1), NumberStyles.HexNumber));
                            break;

                        case 'P':
                            pkg.Add(ulong.Parse(arg.Substring(1), NumberStyles.Number));
                            break;

                        case 'i':
                            content.Add(arg.Substring(1).ToUpperInvariant());
                            break;
                        }
                    } finally {
                        t[0]  = pkg;
                        t[1]  = content;
                        query = t;
                    }
                }
            }
            else if (flag[0] == 'a')
            {
                config.Languages = null;
            }
            else if (flag[0] == 't')
            {
                query = new object[1] {
                    new HashSet <ulong>()
                };
            }
            else
            {
                Console.Error.WriteLine("Unsupported operand {0}", flag[0]);
                return;
            }

            CASCHandler   handler = CASCHandler.OpenStorage(config);
            OwRootHandler ow      = handler.Root as OwRootHandler;

            if (ow == null)
            {
                Console.Error.WriteLine("Not a valid Overwatch installation");
                return;
            }

            if (flag[0] == 'a')
            {
                foreach (string name in ow.APMList)
                {
                    Console.Out.WriteLine(name);
                }
                return;
            }

            foreach (APMFile apm in ow.APMFiles)
            {
                string apmName = System.IO.Path.GetFileName(apm.Name);
                if (flag[0] == 'f' && query[4] != null && ((List <string>)query[4]).Count > 0 && !((List <string>)query[4]).Contains(apmName.ToLowerInvariant()))
                {
                    continue;
                }

                if (flag[0] == 'C')
                {
                    foreach (ulong key in apm.CMFMap.Keys)
                    {
                        ulong rtype   = GUID.Type(key);
                        ulong rindex  = GUID.LongKey(key);
                        ulong rindex2 = GUID.Index(key);

                        bool check1 = ((List <ulong>)query[0]).Count == 0;
                        bool check2 = ((List <ulong>)query[1]).Count == 0;
                        bool check5 = ((List <ulong>)query[5]).Count == 0;

                        if (((List <ulong>)query[0]).Count > 0 && ((List <ulong>)query[0]).Contains(rindex)) // if index is not in i
                        {
                            check1 = true;
                        }
                        if (((List <ulong>)query[1]).Count > 0 && ((List <ulong>)query[1]).Contains(rtype)) // if type is not in t
                        {
                            check2 = true;
                        }
                        if (((List <ulong>)query[5]).Count > 0 && ((List <ulong>)query[5]).Contains(rindex2)) // if type is not in t
                        {
                            check5 = true;
                        }

                        bool check = check1 && check2 && check5;
                        if (check)
                        {
                            Console.Out.WriteLine("Found {0:X12}.{1:X3} in APM {2}", rindex, rtype, apm.Name);
                        }
                    }
                }
                else if (flag[0] == 't')
                {
                    foreach (ulong key in apm.CMFMap.Keys)
                    {
                        ((HashSet <ulong>)query[0]).Add(key >> 48);
                    }
                }

                if (flag[0] == 'C' || flag[0] == 't')
                {
                    continue;
                }

                for (long i = 0; i < apm.Packages.LongLength; ++i)
                {
                    APMPackage           package = apm.Packages[i];
                    PackageIndexRecord[] records = apm.Records[i];

                    if (flag[0] == 'l')
                    {
                        if (((List <ulong>)query[0]).Count + ((List <string>)query[1]).Count == 0)
                        {
                            return;
                        }

                        bool ret = true;
                        if (((List <ulong>)query[0]).Count > 0 && ((List <ulong>)query[0]).Contains(package.packageKey))
                        {
                            ret = false;
                        }

                        if (ret && ((List <string>)query[1]).Count > 0 && ((List <string>)query[1]).Contains(package.indexContentKey.ToHexString().ToUpperInvariant()))
                        {
                            ret = false;
                        }

                        if (ret)
                        {
                            continue;
                        }

                        ((List <ulong>)query[0]).Remove(package.packageKey);
                        ((List <string>)query[1]).Remove(package.indexContentKey.ToHexString().ToUpperInvariant());

                        Console.Out.WriteLine("Dump for package i{0} / p{1:X} in APM {2}", package.indexContentKey.ToHexString().ToUpperInvariant(), package.packageKey, apm.Name);
                    }

                    for (long j = 0; j < records.LongLength; ++j)
                    {
                        PackageIndexRecord record = records[j];

                        ulong rtype   = GUID.Type(record.Key);
                        ulong rindex  = GUID.LongKey(record.Key);
                        ulong rindex2 = GUID.Index(record.Key);

                        if (flag[0] == 'f')
                        {
                            bool check1 = ((List <ulong>)query[0]).Count == 0;
                            bool check2 = ((List <ulong>)query[1]).Count == 0;
                            bool check3 = query[2] == null;
                            bool check4 = query[3] == null;
                            bool check5 = ((List <ulong>)query[5]).Count == 0;

                            if (((List <ulong>)query[0]).Count > 0 && ((List <ulong>)query[0]).Contains(rindex)) // if index is not in i
                            {
                                check1 = true;
                            }
                            if (((List <ulong>)query[1]).Count > 0 && ((List <ulong>)query[1]).Contains(rtype)) // if type is not in t
                            {
                                check2 = true;
                            }
                            if (query[2] != null && (int)query[2] > record.Size)   // if size is less than s[lt]
                            {
                                check3 = true;
                            }
                            if (query[3] != null && (int)query[3] < record.Size)   // if size is greater than s[gt]
                            {
                                check4 = true;
                            }
                            if (((List <ulong>)query[5]).Count > 0 && ((List <ulong>)query[5]).Contains(rindex2)) // if type is not in t
                            {
                                check5 = true;
                            }
                            bool check = check1 && check2 && check3 && check4 && check5;
                            if (check)
                            {
                                Console.Out.WriteLine("Found {0:X12}.{1:X3} in package p{2:X} in APM {3}", rindex, rtype, package.packageKey, apm.Name);
                            }
                        }
                        else if (flag[0] == 'l')
                        {
                            Console.Out.WriteLine("\t{0:X12}.{1:X3} ({2} bytes) - {3:X}", rindex, rtype, record.Size, record.Key);
                        }
                    }
                }
            }
            if (flag[0] == 't')
            {
                foreach (ulong type in (HashSet <ulong>)query[0])
                {
                    byte[] be = BitConverter.GetBytes((ushort)type);
                    Array.Reverse(be);
                    Console.Out.WriteLine("{2:X4} : {0:X4} : {1:X3}", (ushort)type, GUID.Type(type << 48), BitConverter.ToUInt16(be, 0));
                }
            }
        }
Esempio n. 4
0
        static void Main(string[] args)
        {
            //byte[] keyBytes = new byte[16];

            //ArmadilloCrypt crypt = new ArmadilloCrypt(keyBytes);

            //string buildconfigfile = "9f6048f8bd01f38ec0be83f4a9fe5a10";

            //byte[] data = File.ReadAllBytes(buildconfigfile);

            //byte[] IV = buildconfigfile.Substring(16).ToByteArray();

            //unsafe
            //{
            //    fixed (byte* ptr = keyBytes)
            //    {
            //        for (ulong i = 0; i < ulong.MaxValue; i++)
            //        {
            //            for (ulong j = 0; j < ulong.MaxValue; j++)
            //            {
            //                byte[] decrypted = crypt.DecryptFile(IV, data);

            //                if (decrypted[0] == 0x23 && decrypted[1] == 0x20 && decrypted[2] == 0x42 && decrypted[3] == 0x75)
            //                {
            //                    Console.WriteLine("key found: {0} {1} ?", i, j);
            //                }

            //                *(ulong*)ptr = j;

            //                if (j % 1000000 == 0)
            //                    Console.WriteLine("{0}/{1}", j, ulong.MaxValue);
            //            }

            //            *(ulong*)(ptr + 8) = i;
            //        }
            //    }
            //}

            if (args.Length != 5)
            {
                Console.WriteLine("Invalid arguments count!");
                Console.WriteLine("Usage: CASCConsole <mode> <pattern|listfile> <destination> <localeFlags> <contentFlags>");
                return;
            }

            Console.WriteLine("Settings:");
            Console.WriteLine("    WowPath: {0}", Settings.Default.StoragePath);
            Console.WriteLine("    OnlineMode: {0}", Settings.Default.OnlineMode);

            Console.WriteLine("Loading...");

            BackgroundWorkerEx bgLoader = new BackgroundWorkerEx();

            bgLoader.ProgressChanged += BgLoader_ProgressChanged;

            //CASCConfig.LoadFlags |= LoadFlags.Install;

            CASCConfig config = Settings.Default.OnlineMode
                ? CASCConfig.LoadOnlineStorageConfig(Settings.Default.Product, "us")
                : CASCConfig.LoadLocalStorageConfig(Settings.Default.StoragePath);

            CASCHandler cascHandler = CASCHandler.OpenStorage(config, bgLoader);

            string       mode    = args[0];
            string       pattern = args[1];
            string       dest    = args[2];
            LocaleFlags  locale  = (LocaleFlags)Enum.Parse(typeof(LocaleFlags), args[3]);
            ContentFlags content = (ContentFlags)Enum.Parse(typeof(ContentFlags), args[4]);

            cascHandler.Root.LoadListFile(Path.Combine(Environment.CurrentDirectory, "listfile.txt"), bgLoader);
            CASCFolder root = cascHandler.Root.SetFlags(locale, content);

            //cascHandler.Root.MergeInstall(cascHandler.Install);

            Console.WriteLine("Loaded.");

            Console.WriteLine("Extract params:");
            Console.WriteLine("    Mode: {0}", mode);
            Console.WriteLine("    Pattern: {0}", pattern);
            Console.WriteLine("    Destination: {0}", dest);
            Console.WriteLine("    LocaleFlags: {0}", locale);
            Console.WriteLine("    ContentFlags: {0}", content);

            if (mode == "pattern")
            {
                Wildcard wildcard = new Wildcard(pattern, true, RegexOptions.IgnoreCase);

                foreach (var file in CASCFolder.GetFiles(root.Entries.Select(kv => kv.Value)))
                {
                    if (wildcard.IsMatch(file.FullName))
                    {
                        ExtractFile(cascHandler, file.FullName, dest);
                    }
                }
            }
            else if (mode == "listfile")
            {
                var names = File.ReadLines(pattern);

                foreach (var file in names)
                {
                    ExtractFile(cascHandler, file, dest);
                }
            }

            Console.WriteLine("Extracted.");
        }
Esempio n. 5
0
        //class Hashes
        //{
        //    public string[] install;
        //    public string[] encoding;
        //}

        static void Main(string[] args)
        {
            //HashSet<string> data = new HashSet<string>();
            //HashSet<string> installs = new HashSet<string>();

            //using (StreamReader sr = new StreamReader("list.txt"))
            //{
            //    string line1;

            //    while((line1 = sr.ReadLine()) != null)
            //    {
            //        data.Add(line1.Substring(19, 32));

            //        if (line1.Contains("install"))
            //        {
            //            installs.Add(line1.Substring(93, 32));
            //        }
            //    }
            //}

            ////foreach (var cfg in data)
            ////{
            ////    string url = string.Format("https://bnet.marlam.in/tpr/wow/config/{0}/{1}/{2}", cfg.Substring(0, 2), cfg.Substring(2, 2), cfg);

            ////    var stream = CDNIndexHandler.OpenFileDirect(url);

            ////    using (var fileStream = File.Create("builds\\" + cfg))
            ////    {
            ////        stream.CopyTo(fileStream);
            ////    }
            ////}

            //Dictionary<string, Hashes> data2 = new Dictionary<string, Hashes>();

            //foreach (var file in Directory.GetFiles("builds"))
            //{
            //    using(var sr = new StreamReader(file))
            //    {
            //        string line;

            //        while ((line = sr.ReadLine()) != null)
            //        {
            //            if (string.IsNullOrWhiteSpace(line) || line.StartsWith("#")) // skip empty lines and comments
            //                continue;

            //            string[] tokens = line.Split(new char[] { '=' }, 2, StringSplitOptions.RemoveEmptyEntries);

            //            if (tokens.Length != 2)
            //                throw new Exception("KeyValueConfig: tokens.Length != 2");

            //            var values = tokens[1].Trim().Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            //            var valuesList = values.ToList();

            //            if (!data2.ContainsKey(file))
            //                data2[file] = new Hashes();

            //            if (values[0] == "install")
            //            {
            //                data2[file].install = values;
            //            }

            //            if (values[0] == "encoding")
            //            {
            //                data2[file].encoding = values;
            //            }

            //            //sr.Data.Add(tokens[0].Trim(), valuesList);
            //        }
            //    }
            //}

            //Dictionary<string, string> realInstalls = new Dictionary<string, string>();

            //foreach(var kv in data2)
            //{
            //    for(int i = 6; i < kv.Value.install.Length; i++)
            //    {
            //        if (installs.Contains(kv.Value.install[i]))
            //        {
            //            //Console.WriteLine("{0} {1}", kv.Value.install[i], kv.Value.encoding[i]);

            //            realInstalls[kv.Value.install[i]] = kv.Value.encoding[i];
            //        }
            //    }
            //}

            //CASCConfig.ValidateData = false;

            //int buildIndex = 0;

            //foreach (var kvinstall in realInstalls)
            //{
            //    string url1 = string.Format("http://bnet.marlamin.com/tpr/wow/data/{0}/{1}/{2}", kvinstall.Key.Substring(0, 2), kvinstall.Key.Substring(2, 2), kvinstall.Key);

            //    BLTEStream instFile = new BLTEStream(CDNIndexHandler.OpenFileDirect(url1), new MD5Hash());

            //    InstallHandler install = new InstallHandler(new BinaryReader(instFile), null);

            //    //foreach(var ent  in install.GetEntries().Where(e => e.Name.Contains("MacOS")))
            //    //{
            //    //    Console.WriteLine(ent.Name);
            //    //}
            //    //continue;

            //    string url2 = string.Format("http://bnet.marlamin.com/tpr/wow/data/{0}/{1}/{2}", kvinstall.Value.Substring(0, 2), kvinstall.Value.Substring(2, 2), kvinstall.Value);

            //    BLTEStream encFile = new BLTEStream(CDNIndexHandler.OpenFileDirect(url2), new MD5Hash());

            //    EncodingHandler encoding = new EncodingHandler(new BinaryReader(encFile), null);

            //    string[] files = new string[] { "WowB.exe", "WowT.exe", "Wow.exe", "WowB-64.exe", "WowT-64.exe", "Wow-64.exe", "RenderService.exe", "RenderService-64.exe",
            //        @"World of Warcraft Public Test.app\Contents\MacOS\World of Warcraft",
            //        @"World of Warcraft Public Test.app\Contents\MacOS\World of Warcraft 64",
            //        @"World of Warcraft Beta.app\Contents\MacOS\World of Warcraft",
            //        @"World of Warcraft Beta.app\Contents\MacOS\World of Warcraft 64",
            //        @"World of Warcraft Retail.app\Contents\MacOS\World of Warcraft",
            //        @"World of Warcraft Retail.app\Contents\MacOS\World of Warcraft 64",
            //        @"World of Warcraft Test.app\Contents\MacOS\World of Warcraft",
            //        @"World of Warcraft.app\Contents\MacOS\World of Warcraft"
            //    };

            //    string outFolder = "build_" + buildIndex++;

            //    foreach (var file in files)
            //    {
            //        var entries = install.GetEntriesByName(file);

            //        foreach (var entry in entries)
            //        {
            //            bool ok = encoding.GetEntry(entry.MD5, out var encEntry);

            //            if (ok)
            //            {
            //                string chash = encEntry.Key.ToHexString().ToLower();

            //                Console.WriteLine("http://bnet.marlamin.com/tpr/wow/data/{0}/{1}/{2} {3}", chash.Substring(0, 2), chash.Substring(2, 2), chash, file);

            //                string url = string.Format("http://blzddist1-a.akamaihd.net/tpr/wow/data/{0}/{1}/{2}", chash.Substring(0, 2), chash.Substring(2, 2), chash);
            //                //string url = string.Format("http://bnet.marlamin.com/tpr/wow/data/{0}/{1}/{2}", chash.Substring(0, 2), chash.Substring(2, 2), chash);

            //                try
            //                {
            //                    var stream = CDNIndexHandler.OpenFileDirect(url);

            //                    BLTEStream blte3 = new BLTEStream(stream, new MD5Hash());

            //                    string outFile = Path.Combine(outFolder, chash + "_" + file);
            //                    string outDir = Path.GetDirectoryName(outFile);

            //                    if (!Directory.Exists(outDir))
            //                        Directory.CreateDirectory(outDir);

            //                    using (var fileStream = File.Create(outFile))
            //                    {
            //                        blte3.CopyTo(fileStream);
            //                    }
            //                }
            //                catch(Exception exc)
            //                {
            //                    Console.WriteLine(exc.Message);
            //                }
            //            }
            //        }
            //    }
            //}

            //ArmadilloCrypt crypt = new ArmadilloCrypt("sc1Dev");
            //ArmadilloCrypt crypt = new ArmadilloCrypt(new byte[] { 0xe2, 0x56, 0x27, 0xf6, 0xe6, 0xc6, 0xd6, 0x02, 0xc2, 0x86, 0x37, 0x46, 0x02, 0x72, 0xc6, 0x24 });
            //
            //ulong x = BitConverter.ToUInt64(crypt.Key, 0);
            //ulong y = BitConverter.ToUInt64(crypt.Key, 8);

            //var decr = crypt.DecryptFile(@"c:\Users\TOM_RUS\Downloads\e32f46c7245bfc154e43924555a5cf9f");
            //var decr = crypt.DecryptFile(@"c:\Users\TOM_RUS\Downloads\e6185c20749d6b15dfd3aaf4110f3045");

            //File.WriteAllBytes("e6185c20749d6b15dfd3aaf4110f3045_decrypted", decr);
            //;
            //byte[] keyBytes = new byte[16];

            //ArmadilloCrypt crypt = new ArmadilloCrypt(keyBytes);

            //string buildconfigfile = "9f6048f8bd01f38ec0be83f4a9fe5a10";

            //byte[] data = File.ReadAllBytes(buildconfigfile);

            //byte[] IV = buildconfigfile.Substring(16).ToByteArray();

            //unsafe
            //{
            //    fixed (byte* ptr = keyBytes)
            //    {
            //        for (ulong i = 0; i < ulong.MaxValue; i++)
            //        {
            //            for (ulong j = 0; j < ulong.MaxValue; j++)
            //            {
            //                byte[] decrypted = crypt.DecryptFile(IV, data);

            //                if (decrypted[0] == 0x23 && decrypted[1] == 0x20 && decrypted[2] == 0x42 && decrypted[3] == 0x75)
            //                {
            //                    Console.WriteLine("key found: {0} {1} ?", i, j);
            //                }

            //                *(ulong*)ptr = j;

            //                if (j % 1000000 == 0)
            //                    Console.WriteLine("{0}/{1}", j, ulong.MaxValue);
            //            }

            //            *(ulong*)(ptr + 8) = i;
            //        }
            //    }
            //}

            if (args.Length != 6)
            {
                Console.WriteLine("Invalid arguments count!");
                Console.WriteLine("Usage: CASCConsole <mode> <pattern|listfile> <destination> <localeFlags> <product> <overrideArchive>");
                return;
            }

            DateTime startTime = DateTime.Now;

            Console.WriteLine($"Started at {startTime}");

            Console.WriteLine("Settings:");
            Console.WriteLine("    WowPath: {0}", Settings.Default.StoragePath);
            Console.WriteLine("    OnlineMode: {0}", Settings.Default.OnlineMode);

            Console.WriteLine("Loading...");

            BackgroundWorkerEx bgLoader = new BackgroundWorkerEx();

            bgLoader.ProgressChanged += BgLoader_ProgressChanged;

            //CASCConfig.LoadFlags |= LoadFlags.Install;

            string      mode            = args[0];
            string      pattern         = args[1];
            string      dest            = args[2];
            LocaleFlags locale          = (LocaleFlags)Enum.Parse(typeof(LocaleFlags), args[3]);
            string      product         = args[4];
            bool        overrideArchive = bool.Parse(args[5]);

            CASCConfig.LoadFlags |= LoadFlags.Install;

            CASCConfig config = Settings.Default.OnlineMode
                ? CASCConfig.LoadOnlineStorageConfig(product, "us")
                : CASCConfig.LoadLocalStorageConfig(Settings.Default.StoragePath, product);

            CASCHandler cascHandler = CASCHandler.OpenStorage(config, bgLoader);

            cascHandler.Root.LoadListFile(Path.Combine(Environment.CurrentDirectory, "listfile.csv"), bgLoader);
            CASCFolder root = cascHandler.Root.SetFlags(locale, overrideArchive);

            cascHandler.Root.MergeInstall(cascHandler.Install);

            Console.WriteLine("Loaded.");

            Console.WriteLine("Extract params:");
            Console.WriteLine("    Mode: {0}", mode);
            Console.WriteLine("    Pattern/Listfile: {0}", pattern);
            Console.WriteLine("    Destination: {0}", dest);
            Console.WriteLine("    LocaleFlags: {0}", locale);
            Console.WriteLine("    Product: {0}", product);
            Console.WriteLine("    OverrideArchive: {0}", overrideArchive);

            if (mode == "pattern")
            {
                Wildcard wildcard = new Wildcard(pattern, true, RegexOptions.IgnoreCase);

                foreach (var file in CASCFolder.GetFiles(root.Entries.Select(kv => kv.Value)))
                {
                    if (wildcard.IsMatch(file.FullName))
                    {
                        ExtractFile(cascHandler, file.Hash, file.FullName, dest);
                    }
                }
            }
            else if (mode == "listfile")
            {
                if (cascHandler.Root is WowRootHandler wowRoot)
                {
                    char[] splitChar = new char[] { ';' };

                    var names = File.ReadLines(pattern).Select(s => s.Split(splitChar, 2)).Select(s => new { id = int.Parse(s[0]), name = s[1] });

                    foreach (var file in names)
                    {
                        ExtractFile(cascHandler, wowRoot.GetHashByFileDataId(file.id), file.name, dest);
                    }
                }
                else
                {
                    var names = File.ReadLines(pattern);

                    foreach (var file in names)
                    {
                        ExtractFile(cascHandler, 0, file, dest);
                    }
                }
            }

            Console.WriteLine("Extracted.");

            DateTime endTime = DateTime.Now;

            Console.WriteLine($"Ended at {endTime} (took {endTime - startTime})");
        }
Esempio n. 6
0
        private static void Main()
        {
            Console.OutputEncoding = Encoding.UTF8;

            Files        = new Dictionary <ulong, MD5Hash>();
            TrackedFiles = new Dictionary <ushort, HashSet <ulong> >();

            #region Tool Detection
            HashSet <Type> tools = new HashSet <Type>();
            {
                Assembly    asm   = typeof(ITool).Assembly;
                Type        t     = typeof(ITool);
                List <Type> types = asm.GetTypes().Where(tt => tt != t && t.IsAssignableFrom(tt)).ToList();
                foreach (Type tt in types)
                {
                    ToolAttribute attrib = tt.GetCustomAttribute <ToolAttribute>();
                    if (tt.IsInterface || attrib == null)
                    {
                        continue;
                    }
                    tools.Add(tt);

                    if (attrib.TrackTypes == null)
                    {
                        continue;
                    }
                    foreach (ushort type in attrib.TrackTypes)
                    {
                        if (!TrackedFiles.ContainsKey(type))
                        {
                            TrackedFiles[type] = new HashSet <ulong>();
                        }
                    }
                }
            }
            #endregion

            Flags = FlagParser.Parse <ToolFlags>(() => PrintHelp(tools));
            if (Flags == null)
            {
                return;
            }

            Logger.EXIT = !Flags.GracefulExit;

            ITool     targetTool      = null;
            ICLIFlags targetToolFlags = null;

            #region Tool Activation

            foreach (Type type in tools)
            {
                ToolAttribute attrib = type.GetCustomAttribute <ToolAttribute>();

                if (!string.Equals(attrib.Keyword, Flags.Mode, StringComparison.InvariantCultureIgnoreCase))
                {
                    continue;
                }
                targetTool = Activator.CreateInstance(type) as ITool;

                if (attrib.CustomFlags != null)
                {
                    Type flags = attrib.CustomFlags;
                    if (typeof(ICLIFlags).IsAssignableFrom(flags))
                    {
                        targetToolFlags = typeof(FlagParser).GetMethod("Parse", new Type[] { }).MakeGenericMethod(flags).Invoke(null, null) as ICLIFlags;
                    }
                }
                break;
            }

            #endregion

            if (targetTool == null)
            {
                FlagParser.Help <ToolFlags>(false);
                PrintHelp(tools);
                if (Debugger.IsAttached)
                {
                    Debugger.Break();
                }
                return;
            }

            #region Initialize CASC
            Log("{0} v{1}", Assembly.GetExecutingAssembly().GetName().Name, Util.GetVersion());
            Log("Initializing CASC...");
            Log("Set language to {0}", Flags.Language);
            CDNIndexHandler.Cache.Enabled   = Flags.UseCache;
            CDNIndexHandler.Cache.CacheData = Flags.CacheData;
            CDNIndexHandler.Cache.Validate  = Flags.ValidateCache;
            // ngdp:us:pro
            // http:us:pro:us.patch.battle.net:1119
            if (Flags.OverwatchDirectory.ToLowerInvariant().Substring(0, 5) == "ngdp:")
            {
                string   cdn     = Flags.OverwatchDirectory.Substring(5, 4);
                string[] parts   = Flags.OverwatchDirectory.Substring(5).Split(':');
                string   region  = "us";
                string   product = "pro";
                if (parts.Length > 1)
                {
                    region = parts[1];
                }
                if (parts.Length > 2)
                {
                    product = parts[2];
                }
                if (cdn == "bnet")
                {
                    Config = CASCConfig.LoadOnlineStorageConfig(product, region);
                }
                else
                {
                    if (cdn == "http")
                    {
                        string host = string.Join(":", parts.Skip(3));
                        Config = CASCConfig.LoadOnlineStorageConfig(host, product, region, true, true, true);
                    }
                }
            }
            else
            {
                Config = CASCConfig.LoadLocalStorageConfig(Flags.OverwatchDirectory, !Flags.SkipKeys, false);
            }
            Config.Languages = new HashSet <string>(new[] { Flags.Language });
            #endregion

            foreach (Dictionary <string, string> build in Config.BuildInfo)
            {
                if (!build.ContainsKey("Tags"))
                {
                    continue;
                }
                if (build["Tags"].Contains("XX?"))
                {
                    IsPTR = true;
                }
                // us ptr region is known as XX, so just look for it in the tags.
                // this should work... untested for Asia
            }

            BuildVersion = uint.Parse(Config.BuildName.Split('.').Last());

            if (Flags.SkipKeys)
            {
                Log("Disabling Key auto-detection...");
            }

            Log("Using Overwatch Version {0}", Config.BuildName);
            CASC = CASCHandler.OpenStorage(Config);
            Root = CASC.Root as OwRootHandler;
            if (Root == null)
            {
                ErrorLog("Not a valid overwatch installation");
                return;
            }

            // Fail when trying to extract data from a specified language with 2 or less files found.
            if (!Root.APMFiles.Any())
            {
                ErrorLog("Could not find the files for language {0}. Please confirm that you have that language installed, and are using the names from the target language.", Flags.Language);
                if (!Flags.GracefulExit)
                {
                    return;
                }
            }

            Log("Mapping...");
            TrackedFiles[0x90] = new HashSet <ulong>();
            IO.MapCMF();
            IO.LoadGUIDTable();
            Sound.WwiseBank.GetReady();

            #region Key Detection
            if (!Flags.SkipKeys)
            {
                Log("Adding Encryption Keys...");

                foreach (ulong key in TrackedFiles[0x90])
                {
                    if (!ValidKey(key))
                    {
                        continue;
                    }
                    using (Stream stream = IO.OpenFile(Files[key])) {
                        if (stream == null)
                        {
                            continue;
                        }

                        STUEncryptionKey encryptionKey = GetInstance <STUEncryptionKey>(key);
                        if (encryptionKey != null && !KeyService.keys.ContainsKey(encryptionKey.LongRevKey))
                        {
                            KeyService.keys.Add(encryptionKey.LongRevKey, encryptionKey.KeyValue);
                            Log("Added Encryption Key {0}, Value: {1}", encryptionKey.KeyNameProper, encryptionKey.Key);
                        }
                    }
                }
            }
            #endregion

            Log("Tooling...");
            targetTool.Parse(targetToolFlags);
            if (Debugger.IsAttached)
            {
                Debugger.Break();
            }
        }
Esempio n. 7
0
        static void Main(string[] args)
        {
            if (args.Length < 3)
            {
                Console.Out.WriteLine("Usage: PackageTool.exe [-LLang] \"overwatch_folder\" \"output_folder\" <keys...>");
                Console.Out.WriteLine("Keys must start with 'i' for content keys, 'p' for package keys, 'n' for package indexes, 't' for package indexes + indices");
                Console.Out.WriteLine("Keys must start with 'a' for specific APMs");
                Console.Out.WriteLine("If any key starts with Q it will dump all files.");
                Console.Out.WriteLine("If any key starts with D it will only output filenames to console, but not write files");
                return;
            }

            string root = args[0];

            OwRootHandler.LOAD_PACKAGES = true;
            CASCConfig config = null;

            // ngdp:us:pro
            // http:us:pro:us.patch.battle.net:1119
            if (root.ToLowerInvariant().Substring(0, 5) == "ngdp:")
            {
                string   cdn     = root.Substring(5, 4);
                string[] parts   = root.Substring(5).Split(':');
                string   region  = "us";
                string   product = "pro";
                if (parts.Length > 1)
                {
                    region = parts[1];
                }
                if (parts.Length > 2)
                {
                    product = parts[2];
                }
                if (cdn == "bnet")
                {
                    config = CASCConfig.LoadOnlineStorageConfig(product, region);
                }
                else
                {
                    if (cdn == "http")
                    {
                        string host = string.Join(":", parts.Skip(3));
                        config = CASCConfig.LoadOnlineStorageConfig(host, product, region, true, true, true);
                    }
                }
            }
            else
            {
                config = CASCConfig.LoadLocalStorageConfig(root, true, true);
            }
            if (args[0][0] == '-' && args[0][1] == 'L')
            {
                string lang = args[0].Substring(2);
                config.Languages = new HashSet <string>(new string[1] {
                    lang
                });
                args = args.Skip(1).ToArray();
            }

            string output = args[1] + Path.DirectorySeparatorChar;

            Console.Out.WriteLine("{0} v{1}", Assembly.GetExecutingAssembly().GetName().Name, OWLib.Util.GetVersion());

            HashSet <ulong>  packageKeys    = new HashSet <ulong>();
            HashSet <ulong>  packageIndices = new HashSet <ulong>();
            HashSet <ulong>  packageIndent  = new HashSet <ulong>();
            HashSet <string> contentKeys    = new HashSet <string>();
            HashSet <ulong>  dumped         = new HashSet <ulong>();
            HashSet <ulong>  fileKeys       = new HashSet <ulong>();
            HashSet <ulong>  types          = new HashSet <ulong>();
            string           apmName        = null;
            bool             dumpAll        = false;
            bool             dry            = false;

            for (int i = 2; i < args.Length; ++i)
            {
                string arg = args[i];
                switch (arg[0])
                {
                case 'q':
                case 'Q':
                    dumpAll = true;
                    break;

                case 'd':
                case 'D':
                    dry = true;
                    break;

                case 'p':
                    packageKeys.Add(ulong.Parse(arg.Substring(1), NumberStyles.HexNumber));
                    break;

                case 'P':
                    packageKeys.Add(ulong.Parse(arg.Substring(1), NumberStyles.Number));
                    break;

                case 'n':
                    packageIndices.Add(ulong.Parse(arg.Substring(1), NumberStyles.HexNumber));
                    break;

                case 'N':
                    packageIndices.Add(ulong.Parse(arg.Substring(1), NumberStyles.Number));
                    break;

                case 't':
                    packageIndent.Add(ulong.Parse(arg.Substring(1), NumberStyles.HexNumber));
                    break;

                case 'T':
                    packageIndent.Add(ulong.Parse(arg.Substring(1), NumberStyles.Number));
                    break;

                case 'a':
                case 'A':
                    apmName = arg.Substring(1).ToLowerInvariant();
                    break;

                case 'i':
                case 'I':
                    contentKeys.Add(arg.Substring(1).ToUpperInvariant());
                    break;

                case 'f':
                    fileKeys.Add(ulong.Parse(arg.Substring(1), NumberStyles.HexNumber));
                    break;

                case 'F':
                    fileKeys.Add(ulong.Parse(arg.Substring(1), NumberStyles.Number));
                    break;

                case 'M':
                    types.Add(ulong.Parse(arg.Substring(1), NumberStyles.HexNumber));
                    break;
                }
            }

            if (contentKeys.Count + packageKeys.Count + packageIndices.Count + packageIndent.Count + fileKeys.Count + types.Count == 0 && !dumpAll)
            {
                Console.Error.WriteLine("Must have at least 1 query");
                return;
            }

            CASCHandler   handler = CASCHandler.OpenStorage(config);
            OwRootHandler ow      = handler.Root as OwRootHandler;

            if (ow == null)
            {
                Console.Error.WriteLine("Not a valid Overwatch installation");
                return;
            }

            Console.Out.WriteLine("Extracting...");

            HashSet <ulong> indicesExtracted = new HashSet <ulong>();
            HashSet <ulong> CMFExtracted     = new HashSet <ulong>();

            foreach (APMFile apm in ow.APMFiles)
            {
                if (apmName != null && !Path.GetFileName(apm.Name).ToLowerInvariant().Contains(apmName))
                {
                    continue;
                }
                Console.Out.WriteLine("Iterating {0}", Path.GetFileName(apm.Name));
                HashSet <ulong> removed = new HashSet <ulong>();
                foreach (ulong key in fileKeys)
                {
                    if (apm.CMFMap.ContainsKey(key))
                    {
                        ulong  rtype  = GUID.Type(key);
                        ulong  rindex = GUID.LongKey(key);
                        string ofn    = $"{output}{Path.DirectorySeparatorChar}cmf{Path.DirectorySeparatorChar}{rtype:X3}{Path.DirectorySeparatorChar}";
                        if (!dry && !Directory.Exists(ofn))
                        {
                            Console.Out.WriteLine("Created directory {0}", ofn);
                            Directory.CreateDirectory(ofn);
                        }
                        ofn = $"{ofn}{rindex:X12}.{rtype:X3}";
                        if (!dry)
                        {
                            using (Stream outputStream = File.Open(ofn, FileMode.Create, FileAccess.Write)) {
                                EncodingEntry recordEncoding;
                                if (!handler.Encoding.GetEntry(apm.CMFMap[key].HashKey, out recordEncoding))
                                {
                                    Console.Error.WriteLine("Cannot open file {0} -- malformed CMF?", ofn);
                                    continue;
                                }

                                try {
                                    using (Stream recordStream = handler.OpenFile(recordEncoding.Key)) {
                                        CopyBytes(recordStream, outputStream, recordEncoding.Size);
                                    }
                                    Console.Out.WriteLine("Saved file {0}", ofn);
                                    removed.Add(key);
                                } catch {
                                    Console.Error.WriteLine("Cannot open file {0} -- encryption", ofn);
                                }
                            }
                        }
                    }
                }
                foreach (ulong key in removed)
                {
                    fileKeys.Remove(key);
                }
                if (types.Count > 0 || dumpAll)
                {
                    foreach (ulong key in apm.CMFMap.Keys)
                    {
                        if (types.Contains(GUID.Type(key)) || dumpAll)
                        {
                            ulong  rtype  = GUID.Type(key);
                            ulong  rindex = GUID.LongKey(key);
                            string ofn    = $"{output}{Path.DirectorySeparatorChar}cmf{Path.DirectorySeparatorChar}{rtype:X3}{Path.DirectorySeparatorChar}";
                            if (!dry && !Directory.Exists(ofn))
                            {
                                Console.Out.WriteLine("Created directory {0}", ofn);
                                Directory.CreateDirectory(ofn);
                            }
                            ofn = $"{ofn}{rindex:X12}.{rtype:X3}";
                            if (!dry)
                            {
                                using (Stream outputStream = File.Open(ofn, FileMode.Create, FileAccess.Write)) {
                                    EncodingEntry recordEncoding;
                                    if (!handler.Encoding.GetEntry(apm.CMFMap[key].HashKey, out recordEncoding))
                                    {
                                        Console.Error.WriteLine("Cannot open file {0} -- malformed CMF?", ofn);
                                        continue;
                                    }

                                    try {
                                        using (Stream recordStream = handler.OpenFile(recordEncoding.Key)) {
                                            CopyBytes(recordStream, outputStream, recordEncoding.Size);
                                        }
                                        Console.Out.WriteLine("Saved file {0}", ofn);
                                    } catch {
                                        Console.Error.WriteLine("Cannot open file {0} -- encryption", ofn);
                                    }
                                }
                            }
                        }
                    }
                }
                if (dumpAll)
                {
                    continue;
                }
                if (contentKeys.Count + packageKeys.Count + packageIndices.Count + packageIndent.Count + fileKeys.Count > 0)
                {
                    for (long i = 0; i < apm.Packages.LongLength; ++i)
                    {
                        if (contentKeys.Count + packageKeys.Count + packageIndices.Count + packageIndent.Count + fileKeys.Count == 0)
                        {
                            break;
                        }

                        APMPackage package = apm.Packages[i];

                        if (!dumpAll)
                        {
                            bool ret = true;
                            if (packageKeys.Count > 0 && packageKeys.Contains(package.packageKey))
                            {
                                ret = false;
                            }

                            if (ret && contentKeys.Count > 0 && contentKeys.Contains(package.indexContentKey.ToHexString().ToUpperInvariant()))
                            {
                                ret = false;
                            }

                            if (ret && packageIndices.Count > 0 && packageIndices.Contains(GUID.Index(package.packageKey)) && !indicesExtracted.Contains(package.packageKey))
                            {
                                ret = false;
                            }

                            if (ret && packageIndent.Count > 0 && packageIndent.Contains(GUID.LongKey(package.packageKey)))
                            {
                                ret = false;
                            }

                            if (ret)
                            {
                                continue;
                            }
                        }

                        packageKeys.Remove(package.packageKey);
                        indicesExtracted.Add(package.packageKey);
                        packageIndent.Remove(GUID.LongKey(package.packageKey));
                        contentKeys.Remove(package.indexContentKey.ToHexString().ToUpperInvariant());

                        PackageIndex         index   = apm.Indexes[i];
                        PackageIndexRecord[] records = apm.Records[i];

                        string o = null;
                        if (dumpAll)
                        {
                            o = output;
                        }
                        else
                        {
                            o = $"{output}{GUID.LongKey(package.packageKey):X12}{Path.DirectorySeparatorChar}";
                        }

                        EncodingEntry bundleEncoding;
                        bool          allowBundle = handler.Encoding.GetEntry(index.bundleContentKey, out bundleEncoding);

                        Stream bundleStream = null;
                        if (allowBundle)
                        {
                            try {
                                bundleStream = handler.OpenFile(bundleEncoding.Key);
                            } catch {
                                Console.Error.WriteLine("Cannot open bundle {0:X16} -- encryption", index.bundleKey);
                                continue;
                            }
                        }
                        foreach (PackageIndexRecord record in records)
                        {
                            if (dumpAll && !dumped.Add(record.Key))
                            {
                                continue;
                            }
                            ulong  rtype  = GUID.Type(record.Key);
                            ulong  rindex = GUID.LongKey(record.Key);
                            string ofn    = $"{o}{rtype:X3}{Path.DirectorySeparatorChar}";
                            if (!dry && !Directory.Exists(ofn))
                            {
                                Console.Out.WriteLine("Created directory {0}", ofn);
                                Directory.CreateDirectory(ofn);
                            }
                            ofn = $"{ofn}{rindex:X12}.{rtype:X3}";
                            if (!dry)
                            {
                                using (Stream outputStream = File.Open(ofn, FileMode.Create, FileAccess.Write)) {
                                    if (((ContentFlags)record.Flags & ContentFlags.Bundle) == ContentFlags.Bundle)
                                    {
                                        if (allowBundle)
                                        {
                                            bundleStream.Position = record.Offset;
                                            CopyBytes(bundleStream, outputStream, record.Size);
                                        }
                                        else
                                        {
                                            Console.Error.WriteLine("Cannot open file {0} -- can't open bundle", ofn);
                                            continue;
                                        }
                                    }
                                    else
                                    {
                                        EncodingEntry recordEncoding;
                                        if (!handler.Encoding.GetEntry(record.ContentKey, out recordEncoding))
                                        {
                                            Console.Error.WriteLine("Cannot open file {0} -- doesn't have bundle flags", ofn);
                                            continue;
                                        }

                                        try {
                                            using (Stream recordStream = handler.OpenFile(recordEncoding.Key)) {
                                                CopyBytes(recordStream, outputStream, record.Size);
                                            }
                                        } catch {
                                            Console.Error.WriteLine("Cannot open file {0} -- encryption", ofn);
                                        }
                                    }
                                }
                            }

                            Console.Out.WriteLine("Saved file {0}", ofn);
                        }

                        if (allowBundle)
                        {
                            bundleStream.Dispose();
                        }
                    }
                }
            }
        }
Esempio n. 8
0
        public static async Task <IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            [Blob("wow")] CloudBlobContainer container,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");

            string localeString = req.Query["locale"];

            string  requestBody = await new StreamReader(req.Body).ReadToEndAsync();
            dynamic data        = JsonConvert.DeserializeObject(requestBody);
            var     localeName  = localeString ?? "en-US";

            CASCConfig  config  = CASCConfig.LoadLocalStorageConfig(@"C:\Games\World of Warcraft", "wow");
            CASCHandler handler = CASCHandler.OpenStorage(config, null);

            handler.Root.LoadListFile(Path.Combine(Environment.CurrentDirectory, "listfile8x.csv"));

            var locale = WowLocales.Locales.Single(x => x.Name.Equals(localeName, StringComparison.OrdinalIgnoreCase));

            CASCFolder root = handler.Root.SetFlags(locale.Flag);

            handler.Root.MergeInstall(handler.Install);

            var dbfiles = (CASCFolder)root.Entries["dbfilesclient"];

            await container.CreateIfNotExistsAsync();

            // Apply translations to expansion / tiers
            var tiers = WowExpansion.All;
            {
                var entry = dbfiles.GetEntry("journaltier.db2");
                await using var stream = handler.OpenFile(entry.Hash);
                var reader = new WDC3Reader(stream);

                foreach (var pair in reader)
                {
                    var tier = tiers.Single(x => x.Value.TierId == pair.Key);
                    tier.Value.Name = pair.Value.GetField <string>(0);
                }
            }
            await container.GetBlockBlobReference("expansions." + localeName + ".json")
            .UploadTextAsync(JsonConvert.SerializeObject(tiers.Values, serializerSettings));

            var instanceTiers = new Dictionary <int, int>();
            {
                var entry = dbfiles.GetEntry("JournalTierXInstance.db2");
                await using var stream = handler.OpenFile(entry.Hash);
                var reader = new WDC3Reader(stream);
                foreach (var pair in reader)
                {
                    var tierId     = pair.Value.GetField <int>(0);
                    var instanceId = pair.Value.GetField <int>(1);
                    instanceTiers[instanceId] = tierId;
                }
            }

            // Get all instances
            var instances = new List <Instance>();
            {
                var entry = dbfiles.GetEntry("JournalInstance.db2");
                await using var stream = handler.OpenFile(entry.Hash);
                var reader = new WDC3Reader(stream);
                foreach (var pair in reader)
                {
                    if (!instanceTiers.ContainsKey(pair.Key))
                    {
                        continue;
                    }
                    var tierId = instanceTiers[pair.Key];

                    var instance = new Instance
                    {
                        Id                 = pair.Key,
                        Name               = pair.Value.GetField <string>(0),
                        Description        = pair.Value.GetField <string>(1),
                        MapId              = pair.Value.GetField <int>(3),
                        BackgroundImageId  = pair.Value.GetField <int>(4),
                        ButtonImageId      = pair.Value.GetField <int>(5),
                        ButtonSmallImageId = pair.Value.GetField <int>(6),
                        LoreImageId        = pair.Value.GetField <int>(7),
                        Order              = pair.Value.GetField <int>(8),
                        Flags              = pair.Value.GetField <int>(9),
                        TierId             = tierId
                    };

                    instances.Add(instance);
                }
            }

            // Save the list of all instances
            await container.GetBlockBlobReference("data/dungeons." + localeName + ".json")
            .UploadTextAsync(JsonConvert.SerializeObject(instances, serializerSettings));

            foreach (var tier in tiers.Values)
            {
                var dungeons = new List <Instance>();

                // Get details and images for each dungeon
                foreach (var instance in instances)
                {
                    // Only encounters for this tier
                    if (instance.TierId != tier.TierId)
                    {
                        continue;
                    }

                    // World instances are flagged with 0x2
                    if ((instance.Flags & 0x2) == 0x2)
                    {
                        continue;
                    }

                    // Raids have an order number, dungeons have order of 0 and sorted by name
                    if (instance.Order != 0)
                    {
                        continue;
                    }

                    dungeons.Add(instance);

                    var blobPath = "static/img/instance/" + instance.Id + "/";

                    // Get the dungeon images
                    using var loreStream = handler.OpenFile(instance.LoreImageId);
                    await container.GetBlockBlobReference(blobPath + "lg." + localeName + ".blp").UploadFromStreamAsync(loreStream);

                    using var bg = handler.OpenFile(instance.BackgroundImageId);
                    await container.GetBlockBlobReference(blobPath + "xl." + localeName + ".blp").UploadFromStreamAsync(bg);

                    using var btnLarge = handler.OpenFile(instance.ButtonImageId);
                    await container.GetBlockBlobReference(blobPath + "sm." + localeName + ".blp").UploadFromStreamAsync(btnLarge);

                    using var btnSmall = handler.OpenFile(instance.ButtonImageId);
                    await container.GetBlockBlobReference(blobPath + "xs." + localeName + ".blp").UploadFromStreamAsync(btnSmall);

                    var encounters = new List <Encounter>();

                    foreach (var encounter in dbfiles.EnumerateTable("JournalEncounter", handler))
                    {
                        var instanceId = encounter.Value.GetField <int>(3);
                        if (instanceId != instance.Id)
                        {
                            continue;
                        }

                        var journalEncounter = new Encounter
                        {
                            Id                    = encounter.Key,
                            Name                  = encounter.Value.GetField <string>(0),
                            Description           = encounter.Value.GetField <string>(1),
                            MapX                  = encounter.Value.GetField <float>(2, 0),
                            MapY                  = encounter.Value.GetField <float>(2, 1),
                            InstanceId            = instanceId,
                            EncounterId           = encounter.Value.GetField <int>(4),
                            Order                 = encounter.Value.GetField <int>(5),
                            FirstSectionId        = encounter.Value.GetField <int>(6),
                            UiMapId               = encounter.Value.GetField <int>(7),
                            MapDisplayConditionId = encounter.Value.GetField <int>(8),
                            Flags                 = encounter.Value.GetField <byte>(9),
                            Difficulty            = encounter.Value.GetField <byte>(10),
                            Sections              = new List <JournalSection>()
                        };

                        var sections = new Dictionary <int, JournalSection>();

                        foreach (var encounterSection in dbfiles.EnumerateTable("JournalEncounterSection", handler))
                        {
                            var section = new JournalSection
                            {
                                Id                    = encounterSection.Key,
                                Name                  = encounterSection.Value.GetField <string>(0),
                                Description           = encounterSection.Value.GetField <string>(1),
                                JournalEncounterId    = encounterSection.Value.GetField <ushort>(2),
                                Order                 = encounterSection.Value.GetField <byte>(3),
                                ParentSectionId       = encounterSection.Value.GetField <ushort>(4),
                                FirstChildSectionId   = encounterSection.Value.GetField <ushort>(5),
                                NextSiblingSectionId  = encounterSection.Value.GetField <ushort>(6),
                                SectionType           = encounterSection.Value.GetField <byte>(7), // 3 = overview, 1 = creature, 2 = spell
                                IconCreatureDisplayId = encounterSection.Value.GetField <uint>(8),
                                UiModelSceneId        = encounterSection.Value.GetField <int>(9),
                                SpellId               = encounterSection.Value.GetField <int>(10),
                                IconFileDataId        = encounterSection.Value.GetField <int>(11),
                                Flags                 = encounterSection.Value.GetField <ushort>(12),
                                IconFlags             = encounterSection.Value.GetField <ushort>(13), // 1=tank, 2=dps, 4=healer,
                                DifficultyMask        = encounterSection.Value.GetField <byte>(14),
                            };

                            if (section.JournalEncounterId != journalEncounter.Id)
                            {
                                continue;
                            }

                            sections[section.Id] = section;
                        }

                        journalEncounter.Sections = BuildSectionTree(sections);

                        encounters.Add(journalEncounter);
                    }

                    await container.GetBlockBlobReference("data/dungeon/" + instance.Id + "/encounters." + localeName + ".json")
                    .UploadTextAsync(JsonConvert.SerializeObject(encounters, serializerSettings));
                }

                // Save the list of dungeons for this tier
                await container.GetBlockBlobReference("data/" + tier.Id + "/dungeons." + localeName + ".json")
                .UploadTextAsync(JsonConvert.SerializeObject(dungeons, serializerSettings));
            }

            return(new OkObjectResult(tiers));
        }
Esempio n. 9
0
        static void Main(string[] args)
        {
            Console.OutputEncoding = Encoding.UTF8;

            Files        = new Dictionary <ulong, PackageRecord>();
            TrackedFiles = new Dictionary <ushort, HashSet <ulong> >();


            Flags = FlagParser.Parse <ToolFlags>();
            if (Flags == null)
            {
                return;
            }

            #region Initialize CASC
            Log("{0} v{1}", Assembly.GetExecutingAssembly().GetName().Name, Util.GetVersion());
            Log("Initializing CASC...");
            Log("Set language to {0}", Flags.Language);
            CDNIndexHandler.Cache.Enabled   = Flags.UseCache;
            CDNIndexHandler.Cache.CacheData = Flags.CacheData;
            CDNIndexHandler.Cache.Validate  = Flags.ValidateCache;
            // ngdp:us:pro
            // http:us:pro:us.patch.battle.net:1119
            if (Flags.OverwatchDirectory.ToLowerInvariant().Substring(0, 5) == "ngdp:")
            {
                string   cdn     = Flags.OverwatchDirectory.Substring(5, 4);
                string[] parts   = Flags.OverwatchDirectory.Substring(5).Split(':');
                string   region  = "us";
                string   product = "pro";
                if (parts.Length > 1)
                {
                    region = parts[1];
                }
                if (parts.Length > 2)
                {
                    product = parts[2];
                }
                if (cdn == "bnet")
                {
                    Config = CASCConfig.LoadOnlineStorageConfig(product, region);
                }
                else
                {
                    if (cdn == "http")
                    {
                        string host = string.Join(":", parts.Skip(3));
                        Config = CASCConfig.LoadOnlineStorageConfig(host, product, region, true, true, true);
                    }
                }
            }
            else
            {
                Config = CASCConfig.LoadLocalStorageConfig(Flags.OverwatchDirectory, !Flags.SkipKeys, false);
            }
            Config.Languages = new HashSet <string>(new[] { Flags.Language });
            #endregion

            BuildVersion = uint.Parse(Config.BuildName.Split('.').Last());

            if (Flags.SkipKeys)
            {
                Log("Disabling Key auto-detection...");
            }

            Log("Using Overwatch Version {0}", Config.BuildName);
            CASC = CASCHandler.OpenStorage(Config);
            Root = CASC.Root as OwRootHandler;
            if (Root == null)
            {
                ErrorLog("Not a valid overwatch installation");
                return;
            }

            if (!Root.APMFiles.Any())
            {
                ErrorLog("Could not find the files for language {0}. Please confirm that you have that language installed, and are using the names from the target language.", Flags.Language);
                if (!Flags.GracefulExit)
                {
                    return;
                }
            }

            string[] modeArgs = Flags.Positionals.Skip(2).ToArray();

            switch (Flags.Mode.ToLower())
            {
            case "extract":
                Extract(modeArgs);
                break;

            case "search":
                Search(modeArgs);
                break;

            case "search-type":
                SearchType(modeArgs);
                break;

            case "info":
                Info(modeArgs);
                break;

            case "convert":
                Convert(modeArgs);
                break;

            case "types":
                Types(modeArgs);
                break;

            default:
                Console.Out.WriteLine("Available modes: extract, search, search-type, info");
                break;
            }
        }
Esempio n. 10
0
        public static void Main(string[] args)
        {
            string       overwatchDir = args[0];
            string       mode         = args[1];
            const string language     = "enUS";

            // Usage:
            // {overwatch dir} dump  --  Dump hashes
            // {overwatch dir} compare-enc {other ver num}  --  Extract added files from encoding (requires dump from other version)
            // {overwatch dir} compare-idx {other ver num}  --  Extract added files from indices (requires dump from other version)
            // {overwatch dir} nonblte  --  Extract non-blte files
            // {overwatch dir} extract-encoding  --  Extract encoding file
            // {overwatch dir} addcmf  --  Extract all files from the cmf

            // casc setup
            Config = CASCConfig.LoadLocalStorageConfig(overwatchDir, false, false);
            Config.SpeechLanguage = Config.TextLanguage = language;
            if (mode != "allcmf" && mode != "dump-guids" && mode != "compare-guids" && mode != "dump-cmf")
            {
                Config.LoadContentManifest = false;
                Config.LoadPackageManifest = false;
            }

            CASC = CASCHandler.Open(Config);
            MapCMF(language);

            //var temp = Config.Builds[Config.ActiveBuild].KeyValue;
            BuildVersion = uint.Parse(Config.BuildVersion.Split('.').Last());

            // c:\\ow\\game\\Overwatch dump
            // "D:\Games\Overwatch Test" compare 44022

            if (mode == "dump")
            {
                Dump(args);
            }
            else if (mode == "compare-enc")
            {
                CompareEnc(args);
            }
            else if (mode == "compare-idx")
            {
                CompareIdx(args);
            }
            else if (mode == "nonblte")
            {
                DumpNonBLTE(args);
            }
            else if (mode == "extract-encoding")
            {
                ExtractEncodingFile(args);
            }
            else if (mode == "allcmf")
            {
                AllCMF(args);
            }
            else if (mode == "dump-guids")
            {
                DumpGUIDs(args);
            }
            else if (mode == "compare-guids")
            {
                CompareGUIDs(args);
            }
            else if (mode == "dump-cmf")
            {
                DumpCMF(args);
            }
            else
            {
                throw new Exception($"unknown mode: {mode}");
            }
        }
Esempio n. 11
0
        static async Task ExtractJournal(string localeName = "en-US")
        {
            CASCConfig  config  = CASCConfig.LoadLocalStorageConfig(@"C:\Games\World of Warcraft", "wow");
            CASCHandler handler = CASCHandler.OpenStorage(config, null);

            handler.Root.LoadListFile(Path.Combine(Environment.CurrentDirectory, "listfile8x.csv"));

            var locale = GetLocale(localeName);

            CASCFolder root = handler.Root.SetFlags(locale);

            handler.Root.MergeInstall(handler.Install);

            var dbfiles = (CASCFolder)root.Entries["dbfilesclient"];

            // Apply translations to expansion / tiers
            var tiers = WowExpansion.All;

            foreach (var pair in dbfiles.EnumerateTable("JournalTier", handler))
            {
                var tier = tiers.Single(x => x.Value.TierId == pair.Key);
                tier.Value.Name = pair.Value.GetField <string>(0);
            }

            var instanceTiers = new Dictionary <int, int>();

            {
                foreach (var pair in dbfiles.EnumerateTable("JournalTierXInstance", handler))
                {
                    var tierId     = pair.Value.GetField <int>(0);
                    var instanceId = pair.Value.GetField <int>(1);
                    instanceTiers[instanceId] = tierId;
                }
            }

            // All keystone dungeons
            Console.WriteLine();
            Console.WriteLine("Loading challenge dungeons...");
            var keystones = new List <MythicKeystone>();

            foreach (var pair in dbfiles.EnumerateTable("MapChallengeMode", handler))
            {
                var keystone = new MythicKeystone();
                keystone.Id    = pair.Key;
                keystone.Slug  = GetSlug(pair.Value.GetField <string>(0));
                keystone.Name  = pair.Value.GetField <string>(0);
                keystone.MapId = pair.Value.GetField <ushort>(2);
                keystone.Flags = pair.Value.GetField <byte>(3);

                // keystone.ExpansionId = pair.Value.GetField<uint>(4);
                keystone.ScenarioId = 0;


                keystone.BronzeTimer = pair.Value.GetField <ushort>(4, 0);
                keystone.SilverTimer = pair.Value.GetField <ushort>(4, 1);
                keystone.GoldTimer   = pair.Value.GetField <ushort>(4, 2);

                keystones.Add(keystone);
            }

            // Get all instances
            Console.WriteLine();
            Console.WriteLine("Loading instances...");
            var instances = (from pair in dbfiles.EnumerateTable("JournalInstance", handler)
                             where instanceTiers.ContainsKey(pair.Key)
                             select new Instance
            {
                Id = pair.Key,
                Slug = GetSlug(pair.Value.GetField <string>(0)),
                Name = pair.Value.GetField <string>(0),
                Description = pair.Value.GetField <string>(1),
                MapId = pair.Value.GetField <int>(3),
                BackgroundImageId = pair.Value.GetField <int>(4),
                ButtonImageId = pair.Value.GetField <int>(5),
                ButtonSmallImageId = pair.Value.GetField <int>(6),
                LoreImageId = pair.Value.GetField <int>(7),
                Order = pair.Value.GetField <int>(8),
                Flags = pair.Value.GetField <int>(9),
                TierId = instanceTiers[pair.Key]
            }).ToList();

            // All encounters
            Console.WriteLine();
            Console.WriteLine("Loading encounters...");
            var encounters = (from pair in dbfiles.EnumerateTable("JournalEncounter", handler)
                              select new Encounter
            {
                Id = pair.Key,
                Slug = "",
                Name = pair.Value.GetField <string>(0),
                Description = pair.Value.GetField <string>(1),
                MapX = pair.Value.GetField <float>(2, 0),
                MapY = pair.Value.GetField <float>(2, 1),
                InstanceId = pair.Value.GetField <int>(3),
                EncounterId = pair.Value.GetField <int>(4),
                Order = pair.Value.GetField <int>(5),
                FirstSectionId = pair.Value.GetField <int>(6),
                UiMapId = pair.Value.GetField <int>(7),
                MapDisplayConditionId = pair.Value.GetField <int>(8),
                Flags = pair.Value.GetField <byte>(9),
                Difficulty = pair.Value.GetField <byte>(10),
                Sections = new List <JournalSection>()
            }).ToList();

            // All sections
            Console.WriteLine();
            Console.WriteLine("Loading encounter sections...");
            var sections = (from pair in dbfiles.EnumerateTable("JournalEncounterSection", handler)
                            select new JournalSection
            {
                Id = pair.Key,
                Name = pair.Value.GetField <string>(0),
                Description = pair.Value.GetField <string>(1),
                JournalEncounterId = pair.Value.GetField <ushort>(2),
                Order = pair.Value.GetField <byte>(3),
                ParentSectionId = pair.Value.GetField <ushort>(4),
                FirstChildSectionId = pair.Value.GetField <ushort>(5),
                NextSiblingSectionId = pair.Value.GetField <ushort>(6),
                SectionType = pair.Value.GetField <byte>(7),    // 3 = overview, 1 = creature, 2 = spell
                IconCreatureDisplayId = pair.Value.GetField <uint>(8),
                UiModelSceneId = pair.Value.GetField <int>(9),
                SpellId = pair.Value.GetField <int>(10),
                IconFileDataId = pair.Value.GetField <int>(11),
                Flags = pair.Value.GetField <ushort>(12),
                IconFlags = pair.Value.GetField <ushort>(13),    // 1=tank, 2=dps, 4=healer,
                DifficultyMask = pair.Value.GetField <byte>(14),
            }).ToList();

            // Build the tree
            Console.WriteLine();
            Console.WriteLine("Building tree..");
            foreach (var instance in instances)
            {
                instance.Encounters = new List <Encounter>();

                foreach (var encounter in encounters.Where(x => x.InstanceId == instance.Id))
                {
                    encounter.Sections = BuildSectionTree(sections.Where(x => x.JournalEncounterId == encounter.Id));
                    instance.Encounters.Add(encounter);
                }
            }

            Console.WriteLine();
            Console.WriteLine("Reading in edits...");

            var existingKeystones = await ReadJson <IList <MythicKeystone> >("keystones.json");

            var existingInstances = await ReadJson <IList <Instance> >("instances.json");

            // Update keystone slugs
            foreach (var existingKeystone in existingKeystones)
            {
                var keystone = keystones.SingleOrDefault(x => x.Id == existingKeystone.Id);
                if (keystone == null)
                {
                    continue;
                }
                keystone.Slug = existingKeystone.Slug;
            }

            // Update instance and encounter slugs
            foreach (var existingInstance in existingInstances)
            {
                var instance = instances.SingleOrDefault(x => x.Id == existingInstance.Id);
                if (instance == null)
                {
                    continue;
                }
                instance.Slug = existingInstance.Slug;

                foreach (var existingEncounter in existingInstance.Encounters)
                {
                    var encounter = instance.Encounters.SingleOrDefault(x => x.Id == existingEncounter.Id);
                    if (encounter == null)
                    {
                        continue;
                    }
                    encounter.Slug = existingEncounter.Slug;
                }
            }

            Console.WriteLine();
            Console.WriteLine("Exporting..");

            await DumpJson("keystones.json", keystones);
            await DumpJson("tiers.json", tiers.Values);
            await DumpJson("instances.json", instances);

            Console.WriteLine();
            Console.WriteLine("Done.");
        }
Esempio n. 12
0
        static void Main(string[] args)
        {
            Console.ForegroundColor = ConsoleColor.Cyan;
            Console.WriteLine(@" ____                    __                      ");
            Console.WriteLine(@"/\  _`\                 /\ \                     ");
            Console.WriteLine(@"\ \ \/\_\  __  __  _____\ \ \___      __   _ __  ");
            Console.WriteLine(@" \ \ \/_/_/\ \/\ \/\ '__`\ \  _ `\  /'__`\/\`'__\");
            Console.WriteLine(@"  \ \ \L\ \ \ \_\ \ \ \L\ \ \ \ \ \/\  __/\ \ \/ ");
            Console.WriteLine(@"   \ \____/\/`____ \ \ ,__/\ \_\ \_\ \____\\ \_\ ");
            Console.WriteLine(@"    \/___/  `/___/> \ \ \/  \/_/\/_/\/____/ \/_/ ");
            Console.WriteLine(@"               /\___/\ \_\                       ");
            Console.WriteLine(@"               \/__/  \/_/    Core Data Extractor");
            Console.WriteLine("\r");

            BaseDirectory = Environment.CurrentDirectory;

            if (args.Length > 0)
            {
                BaseDirectory = Path.GetDirectoryName(args[0]);
            }

            Console.ForegroundColor = ConsoleColor.Green;

            uint localeMask = 0;

            CASCConfig config = CASCConfig.LoadLocalStorageConfig(BaseDirectory);

            string[] tagLines = config.BuildInfo[0]["Tags"].Split(' ');
            foreach (var line in tagLines)
            {
                if (!Enum.TryParse(typeof(LocaleFlags), line, out object locale))
                {
                    continue;
                }

                localeMask = localeMask | Convert.ToUInt32(locale);
            }

            installedLocalesMask = (LocaleFlags)localeMask;
            firstInstalledLocale = LocaleFlags.None;

            for (Locale i = 0; i < Locale.Total; ++i)
            {
                if (i == Locale.None)
                {
                    continue;
                }

                if (!Convert.ToBoolean(installedLocalesMask & SharedConst.WowLocaleToCascLocaleFlags[(int)i]))
                {
                    continue;
                }

                firstInstalledLocale = SharedConst.WowLocaleToCascLocaleFlags[(int)i];
                break;
            }

            if (firstInstalledLocale < LocaleFlags.None)
            {
                Console.WriteLine("No locales detected");
                Shutdown();
            }

            Console.WriteLine("Initializing CASC library...");
            CascHandler = CASCHandler.OpenStorage(config);
            CascHandler.Root.SetFlags(firstInstalledLocale, ContentFlags.None);
            Console.WriteLine("Done.");

            while (true)
            {
                PrintInstructions();
                string[] lines = Console.ReadLine().Split(' ');
                for (var i = 0; i < lines.Length; ++i)
                {
                    switch (lines[i])
                    {
                    case "maps":
                        ExtractMaps();
                        break;

                    case "vmaps":
                        ExtractVMaps();
                        break;

                    case "mmaps":
                        ExtractMMaps(lines);
                        i = lines.Length;
                        break;

                    case "all":
                        ExtractMaps();
                        ExtractVMaps();
                        //ExtractMMaps(lines);
                        break;

                    case "exit":
                        return;
                    }
                }
            }
        }
Esempio n. 13
0
        private static void Main()
        {
            AppDomain.CurrentDomain.UnhandledException += ExceptionHandler;
            Process.GetCurrentProcess().EnableRaisingEvents = true;
            AppDomain.CurrentDomain.ProcessExit += (sender, @event) => Console.ForegroundColor = ConsoleColor.Gray;
            Console.CancelKeyPress += (sender, @event) => Console.ForegroundColor = ConsoleColor.Gray;
            Console.OutputEncoding  = Encoding.UTF8;

            Files        = new Dictionary <ulong, ApplicationPackageManifest.Types.PackageRecord>();
            TrackedFiles = new Dictionary <ushort, HashSet <ulong> >();

            #region Tool Detection
            HashSet <Type> tools = new HashSet <Type>();
            {
                Assembly    asm   = typeof(ITool).Assembly;
                Type        t     = typeof(ITool);
                List <Type> types = asm.GetTypes().Where(tt => tt != t && t.IsAssignableFrom(tt)).ToList();
                foreach (Type tt in types)
                {
                    ToolAttribute attrib = tt.GetCustomAttribute <ToolAttribute>();
                    if (tt.IsInterface || attrib == null)
                    {
                        continue;
                    }
                    tools.Add(tt);

                    if (attrib.TrackTypes == null)
                    {
                        continue;
                    }
                    foreach (ushort type in attrib.TrackTypes)
                    {
                        if (!TrackedFiles.ContainsKey(type))
                        {
                            TrackedFiles[type] = new HashSet <ulong>();
                        }
                    }
                }
            }
            #endregion

            Flags = FlagParser.Parse <ToolFlags>(() => PrintHelp(tools));
            if (Flags == null)
            {
                return;
            }

            //Logger.EXIT = !Flags.GracefulExit;

            ITool     targetTool      = null;
            ICLIFlags targetToolFlags = null;

            #region Tool Activation

            foreach (Type type in tools)
            {
                ToolAttribute attrib = type.GetCustomAttribute <ToolAttribute>();

                if (!string.Equals(attrib.Keyword, Flags.Mode, StringComparison.InvariantCultureIgnoreCase))
                {
                    continue;
                }
                targetTool = Activator.CreateInstance(type) as ITool;

                if (attrib.CustomFlags != null)
                {
                    Type flags = attrib.CustomFlags;
                    if (typeof(ICLIFlags).IsAssignableFrom(flags))
                    {
                        targetToolFlags = typeof(FlagParser).GetMethod(nameof(FlagParser.Parse), new Type[] { }).MakeGenericMethod(flags).Invoke(null, null) as ICLIFlags;
                    }
                }
                break;
            }

            #endregion

            if (targetTool == null)
            {
                FlagParser.Help <ToolFlags>(false);
                PrintHelp(tools);
                if (Debugger.IsAttached)
                {
                    Debugger.Break();
                }
                return;
            }

            TankLib.Helpers.Logger.Info("Core", $"{Assembly.GetExecutingAssembly().GetName().Name} v{TankLib.Util.GetVersion(typeof(Program).Assembly)}");
            TankLib.Helpers.Logger.Info("Core", $"CommandLine: [{string.Join(", ", Environment.GetCommandLineArgs().Skip(1).Select(x => $"\"{x}\""))}]");

            #region Initialize CASC
            if (Flags.Language != null)
            {
                TankLib.Helpers.Logger.Info("CASC", $"Set language to {Flags.Language}");
            }
            if (Flags.SpeechLanguage != null)
            {
                TankLib.Helpers.Logger.Info("CASC", $"Set speech language to {Flags.SpeechLanguage}");
            }

            CASCHandler.Cache.CacheAPM     = Flags.UseCache;
            CASCHandler.Cache.CacheCDN     = Flags.UseCache;
            CASCHandler.Cache.CacheCDNData = Flags.CacheData;
            Config = CASCConfig.LoadFromString(Flags.OverwatchDirectory, Flags.SkipKeys);
            Config.SpeechLanguage = Flags.SpeechLanguage ?? Flags.Language ?? Config.SpeechLanguage;
            Config.TextLanguage   = Flags.Language ?? Config.TextLanguage;

            if (Config != null)
            {
                if (Flags.Language != null && !Config.InstallData.Settings.Languages.Select(x => x.Language).Contains(Flags.Language))
                {
                    TankLib.Helpers.Logger.Warn("Core", "Battle.Net Agent reports that language {0} is not installed.", Flags.Language);
                }

                if (Config.InstallData.Uid != "prometheus")
                {
                    TankLib.Helpers.Logger.Warn("Core", $"The branch \"{Config.InstallData.Uid}\" is not supported!. This might result in failure to load. Proceed with caution.");
                }
            }
            #endregion


            BuildVersion = uint.Parse(Config.BuildVersion.Split('.').Last());

            if (BuildVersion < 39028)
            {
                TankLib.Helpers.Logger.Error("Core", "DataTool doesn't support Overwatch versions below 1.14. Please use OverTool");
            }
            else if (BuildVersion < 39241)
            {
                TankLib.Helpers.Logger.Error("Core", "DataTool doesn't support this 1.14 release as it uses unmangeled hashes");
            }
            else if (BuildVersion < 49154)
            {
                TankLib.Helpers.Logger.Error("Core", "This version of DataTool doesn't properly support versions below 1.26. Please downgrade DataTool.");
            }

            TankLib.Helpers.Logger.Info("Core", $"Using Overwatch Version {Config.BuildVersion}");
            TankLib.Helpers.Logger.Info("CASC", "Initializing...");
            CASC = CASCHandler.Open(Config);
            Root = CASC.RootHandler;
            //if (Root== null) {
            //    ErrorLog("Not a valid overwatch installation");
            //    return;
            //}

            if (Config.InstallData != null)
            {
            }

            // Fail when trying to extract data from a specified language with 2 or less files found.
            if (!Root.APMFiles.Any())
            {
                TankLib.Helpers.Logger.Error("Core", "Unable to load APM files for language {0}. Please confirm that you have that language installed.", Flags.Language);
                return;
            }

            TankLib.Helpers.Logger.Info("Core", "Mapping storage");
            TrackedFiles[0x90] = new HashSet <ulong>();
            IO.MapCMF();
            IO.LoadGUIDTable();
            Sound.WwiseBank.GetReady();

            //foreach (KeyValuePair<ushort, HashSet<ulong>> type in TrackedFiles.OrderBy(x => x.Key)) {
            //    //Console.Out.WriteLine($"Found type: {type.Key:X4} ({type.Value.Count} files)");
            //    Console.Out.WriteLine($"Found type: {type.Key:X4}");
            //}

            #region Key Detection
            if (!Flags.SkipKeys)
            {
                TankLib.Helpers.Logger.Info("Core", "Checking ResourceKeys");

                foreach (ulong key in TrackedFiles[0x90])
                {
                    if (!ValidKey(key))
                    {
                        continue;
                    }
                    using (Stream stream = IO.OpenFile(Files[key])) {
                        if (stream == null)
                        {
                            continue;
                        }

                        STUResourceKey resourceKey = GetInstance <STUResourceKey>(key);
                        if (resourceKey == null || resourceKey.GetKeyID() == 0 || TACTKeyService.Keys.ContainsKey(resourceKey.GetReverseKeyID()))
                        {
                            continue;
                        }
                        TACTKeyService.Keys.Add(resourceKey.GetReverseKeyID(), resourceKey.m_key);
                        TankLib.Helpers.Logger.Info("Core", $"Added ResourceKey {resourceKey.GetKeyIDString()}, Value: {resourceKey.GetKeyValueString()}");
                    }
                }
            }
            #endregion

            Stopwatch stopwatch = new Stopwatch();
            TankLib.Helpers.Logger.Info("Core", "Tooling...");
            var dbPath = Flags.ScratchDBPath;
            if (Flags.Deduplicate)
            {
                TankLib.Helpers.Logger.Warn("ScratchDB", "Will attempt to deduplicate files if extracting...");
                if (!string.IsNullOrWhiteSpace(Flags.ScratchDBPath))
                {
                    TankLib.Helpers.Logger.Warn("ScratchDB", "Loading deduplication database...");
                    if (!File.Exists(dbPath))
                    {
                        dbPath = Path.Combine(Path.GetFullPath(Flags.ScratchDBPath), "Scratch.db");
                    }
                    SaveLogic.Combo.ScratchDBInstance.Load(dbPath);
                }
            }
            stopwatch.Start();
            targetTool.Parse(targetToolFlags);
            stopwatch.Stop();

            TankLib.Helpers.Logger.Success("Core", $"Execution finished in {stopwatch.Elapsed} seconds");

            if (Flags.Deduplicate && !string.IsNullOrWhiteSpace(dbPath))
            {
                TankLib.Helpers.Logger.Warn("ScratchDB", "Saving deduplication database...");
                SaveLogic.Combo.ScratchDBInstance.Save(dbPath);
            }

            if (Debugger.IsAttached)
            {
                Debugger.Break();
            }
        }