public CASCHandlerBase(CASCConfig config, BackgroundWorkerEx worker) { Config = config; Logger.WriteLine("CASCHandlerBase: loading CDN indices..."); using (var _ = new PerfCounter("CDNIndexHandler.Initialize()")) { CDNIndex = CDNIndexHandler.Initialize(config, worker); } Logger.WriteLine("CASCHandlerBase: loaded {0} CDN indexes", CDNIndex.Count); if (!config.OnlineMode) { CDNCache.Enabled = false; Logger.WriteLine("CASCHandlerBase: loading local indices..."); using (var _ = new PerfCounter("LocalIndexHandler.Initialize()")) { LocalIndex = LocalIndexHandler.Initialize(config, worker); } Logger.WriteLine("CASCHandlerBase: loaded {0} local indexes", LocalIndex.Count); } }
private static CASCHandler Open(BackgroundWorkerEx worker, CASCConfig config) { using (var _ = new PerfCounter("new CASCHandler()")) { return(new CASCHandler(config, worker)); } }
private bool LoadPreHashedListFile(string pathbin, string pathtext, BackgroundWorkerEx worker = null) { using (var _ = new PerfCounter("WowRootHandler::LoadPreHashedListFile()")) { worker?.ReportProgress(0, "Loading \"listfile\"..."); if (!File.Exists(pathbin)) { return(false); } var timebin = File.GetLastWriteTime(pathbin); var timetext = File.GetLastWriteTime(pathtext); if (timebin != timetext) // text has been modified, recreate crehashed file { return(false); } Logger.WriteLine("WowRootHandler: loading file names..."); using (var fs = new FileStream(pathbin, FileMode.Open)) using (var br = new BinaryReader(fs)) { int numFolders = br.ReadInt32(); for (int i = 0; i < numFolders; i++) { string dirName = br.ReadString(); Logger.WriteLine(dirName); int numFiles = br.ReadInt32(); for (int j = 0; j < numFiles; j++) { ulong fileHash = br.ReadUInt64(); string fileName = br.ReadString(); string fileNameFull = dirName != String.Empty ? dirName + "\\" + fileName : fileName; // skip invalid names if (!RootData.ContainsKey(fileHash)) { Logger.WriteLine("Invalid file name: {0}", fileNameFull); continue; } CASCFile.Files[fileHash] = new CASCFile(fileHash, fileNameFull); } worker?.ReportProgress((int)(fs.Position / (float)fs.Length * 100)); } Logger.WriteLine("WowRootHandler: loaded {0} valid file names", CASCFile.Files.Count); } } return(true); }
private static CASCHandlerLite Open(LocaleFlags locale, BackgroundWorkerEx worker, CASCConfig config) { using (var _ = new PerfCounter("new CASCHandlerLite()")) { return(new CASCHandlerLite(config, locale, worker)); } }
private CASCHandlerLite(CASCConfig config, LocaleFlags locale, BackgroundWorkerEx worker) : base(config, worker) { if (config.GameType != CASCGameType.WoW) { throw new Exception("Unsupported game " + config.BuildUID); } Logger.WriteLine("CASCHandlerLite: loading encoding data..."); EncodingHandler EncodingHandler; using (var _ = new PerfCounter("new EncodingHandler()")) { using (var fs = OpenEncodingFile(this)) EncodingHandler = new EncodingHandler(fs, worker); } Logger.WriteLine("CASCHandlerLite: loaded {0} encoding data", EncodingHandler.Count); Logger.WriteLine("CASCHandlerLite: loading root data..."); WowRootHandler RootHandler; using (var _ = new PerfCounter("new RootHandler()")) { using (var fs = OpenRootFile(EncodingHandler, this)) RootHandler = new WowRootHandler(fs, worker); } Logger.WriteLine("CASCHandlerLite: loaded {0} root data", RootHandler.Count); RootHandler.SetFlags(locale, false, false); RootEntry rootEntry; foreach (var entry in RootHandler.GetAllEntries()) { rootEntry = entry.Value; if ((rootEntry.LocaleFlags == locale || (rootEntry.LocaleFlags & locale) != LocaleFlags.None) && (rootEntry.ContentFlags & ContentFlags.Alternate) == ContentFlags.None) { if (EncodingHandler.GetEntry(rootEntry.cKey, out EncodingEntry enc)) { if (!HashToEKey.ContainsKey(entry.Key)) { HashToEKey.Add(entry.Key, enc.Keys[0]); FileDataIdToHash.Add(RootHandler.GetFileDataIdByHash(entry.Key), entry.Key); } } } } RootHandler.Clear(); RootHandler = null; EncodingHandler.Clear(); EncodingHandler = null; GC.Collect(); Logger.WriteLine("CASCHandlerLite: loaded {0} files", HashToEKey.Count); }
public CASCFolder SetFlags(LocaleFlags locale, bool overrideArchive = false, bool createTree = true) { using (var _ = new PerfCounter(GetType().Name + "::SetFlags()")) { Locale = locale; OverrideArchive = overrideArchive; if (createTree) { Root = CreateStorageTree(); } return(Root); } }
public CASCFolder SetFlags(LocaleFlags locale, ContentFlags content, bool createTree = true) { using (var _ = new PerfCounter(GetType().Name + "::SetFlags()")) { Locale = locale; Content = content; if (createTree) { Root = CreateStorageTree(); } return(Root); } }
private CASCHandler(CASCConfig config, BackgroundWorkerEx worker) : base(config, worker) { Logger.WriteLine("CASCHandler: loading encoding data..."); using (var _ = new PerfCounter("new EncodingHandler()")) { using (var fs = OpenEncodingFile(this)) EncodingHandler = new EncodingHandler(fs, worker); } Logger.WriteLine("CASCHandler: loaded {0} encoding data", EncodingHandler.Count); if ((CASCConfig.LoadFlags & LoadFlags.Download) != 0) { Logger.WriteLine("CASCHandler: loading download data..."); using (var _ = new PerfCounter("new DownloadHandler()")) { using (var fs = OpenDownloadFile(EncodingHandler, this)) DownloadHandler = new DownloadHandler(fs, worker); } Logger.WriteLine("CASCHandler: loaded {0} download data", EncodingHandler.Count); } Logger.WriteLine("CASCHandler: loading root data..."); using (var _ = new PerfCounter("new RootHandler()")) { using (var fs = OpenRootFile(EncodingHandler, this)) { if (config.GameType == CASCGameType.S2 || config.GameType == CASCGameType.HotS) { RootHandler = new MNDXRootHandler(fs, worker); } else if (config.GameType == CASCGameType.D3) { RootHandler = new D3RootHandler(fs, worker, this); } else if (config.GameType == CASCGameType.WoW) { RootHandler = new WowRootHandler(fs, worker); } else if (config.GameType == CASCGameType.Agent || config.GameType == CASCGameType.Bna || config.GameType == CASCGameType.Client) { RootHandler = new AgentRootHandler(fs, worker); } else if (config.GameType == CASCGameType.S1) { RootHandler = new S1RootHandler(fs, worker); } else if (config.GameType == CASCGameType.WC3) { RootHandler = new WC3RootHandler(fs, worker); } else if (config.GameType == CASCGameType.Hearthstone) { RootHandler = new HSRootHandler(fs, worker); } else if (config.GameType == CASCGameType.Overwatch) { RootHandler = new OwRootHandler(fs, worker, this); } else if (config.GameType == CASCGameType.Destiny2) { RootHandler = new Destiny2RootHandler(fs, worker); } else { using (var ufs = new FileStream("unk_root", FileMode.Create)) fs.BaseStream.CopyTo(ufs); throw new Exception("Unsupported game " + config.BuildUID); } } } Logger.WriteLine("CASCHandler: loaded {0} root data", RootHandler.Count); if ((CASCConfig.LoadFlags & LoadFlags.Install) != 0) { Logger.WriteLine("CASCHandler: loading install data..."); using (var _ = new PerfCounter("new InstallHandler()")) { using (var fs = OpenInstallFile(EncodingHandler, this)) InstallHandler = new InstallHandler(fs, worker); InstallHandler.Print(); } Logger.WriteLine("CASCHandler: loaded {0} install data", InstallHandler.Count); } }
public override void LoadListFile(string path, BackgroundWorkerEx worker = null) { //CASCFile.Files.Clear(); using (var _ = new PerfCounter("WowRootHandler::LoadListFile()")) { worker?.ReportProgress(0, "Loading \"listfile\"..."); if (!File.Exists(path)) { Logger.WriteLine("WowRootHandler: list file missing!"); return; } bool isCsv = Path.GetExtension(path) == ".csv"; Logger.WriteLine($"WowRootHandler: loading listfile {path}..."); using (var fs2 = File.Open(path, FileMode.Open)) using (var sr = new StreamReader(fs2)) { string line; char[] splitChar = isCsv ? new char[] { ';' } : new char[] { ' ' }; while ((line = sr.ReadLine()) != null) { string[] tokens = line.Split(splitChar, 2); if (tokens.Length != 2) { Logger.WriteLine($"Invalid line in listfile: {line}"); continue; } if (!int.TryParse(tokens[0], out int fileDataId)) { Logger.WriteLine($"Invalid line in listfile: {line}"); continue; } // skip invalid names if (!RootData.ContainsKey(fileDataId)) { Logger.WriteLine($"Invalid fileDataId in listfile: {line}"); continue; } string file = tokens[1]; ulong fileHash = FileDataStore[fileDataId]; if (!CASCFile.Files.ContainsKey(fileHash)) { CASCFile.Files.Add(fileHash, new CASCFile(fileHash, file)); } else { Logger.WriteLine($"Duplicate fileDataId {fileDataId} detected: {line}"); } worker?.ReportProgress((int)(sr.BaseStream.Position / (float)sr.BaseStream.Length * 100)); } } Logger.WriteLine($"WowRootHandler: loaded {CASCFile.Files.Count} valid file names"); } }
public override void LoadListFile(string path, BackgroundWorkerEx worker = null) { CASCFile.Files.Clear(); if (LoadPreHashedListFile("listfile.bin", path, worker)) { return; } using (var _ = new PerfCounter("WowRootHandler::LoadListFile()")) { worker?.ReportProgress(0, "Loading \"listfile\"..."); if (!File.Exists(path)) { Logger.WriteLine("WowRootHandler: list file missing!"); return; } Logger.WriteLine("WowRootHandler: loading file names..."); Dictionary <string, Dictionary <ulong, string> > dirData = new Dictionary <string, Dictionary <ulong, string> >(StringComparer.OrdinalIgnoreCase) { [""] = new Dictionary <ulong, string>() }; using (var fs = new FileStream("listfile.bin", FileMode.Create)) using (var bw = new BinaryWriter(fs)) using (var fs2 = File.Open(path, FileMode.Open)) using (var sr = new StreamReader(fs2)) { string file; while ((file = sr.ReadLine()) != null) { ulong fileHash = Hasher.ComputeHash(file); // skip invalid names if (!RootData.ContainsKey(fileHash)) { Logger.WriteLine("Invalid file name: {0}", file); continue; } CASCFile.Files[fileHash] = new CASCFile(fileHash, file); int dirSepIndex = file.LastIndexOf('\\'); if (dirSepIndex >= 0) { string key = file.Substring(0, dirSepIndex); if (!dirData.ContainsKey(key)) { dirData[key] = new Dictionary <ulong, string>(); } dirData[key][fileHash] = file.Substring(dirSepIndex + 1); } else { dirData[""][fileHash] = file; } worker?.ReportProgress((int)(sr.BaseStream.Position / (float)sr.BaseStream.Length * 100)); } bw.Write(dirData.Count); // count of dirs foreach (var dir in dirData) { bw.Write(dir.Key); // dir name Logger.WriteLine(dir.Key); bw.Write(dirData[dir.Key].Count); // count of files in dir foreach (var fh in dirData[dir.Key]) { bw.Write(fh.Key); // file name hash bw.Write(fh.Value); // file name (without dir name) } } Logger.WriteLine("WowRootHandler: loaded {0} valid file names", CASCFile.Files.Count); } File.SetLastWriteTime("listfile.bin", File.GetLastWriteTime(path)); } }
private CASCHandlerLite(CASCConfig config, LocaleFlags locale, BackgroundWorkerEx worker) : base(config, worker) { if (config.GameType != CASCGameType.WoW) { throw new Exception("Unsupported game " + config.BuildUID); } Logger.WriteLine("CASCHandlerLite: loading encoding data..."); EncodingHandler EncodingHandler; using (var _ = new PerfCounter("new EncodingHandler()")) { using (var fs = OpenEncodingFile(this)) EncodingHandler = new EncodingHandler(fs, worker); } Logger.WriteLine("CASCHandlerLite: loaded {0} encoding data", EncodingHandler.Count); Logger.WriteLine("CASCHandlerLite: loading root data..."); WowRootHandler RootHandler; using (var _ = new PerfCounter("new RootHandler()")) { using (var fs = OpenRootFile(EncodingHandler, this)) RootHandler = new WowRootHandler(fs, worker); } Logger.WriteLine("CASCHandlerLite: loaded {0} root data", RootHandler.Count); RootHandler.SetFlags(locale, ContentFlags.None, false); CDNIndexData = new Dictionary <MD5Hash, IndexEntry>(comparer); if (LocalIndex != null) { LocalIndexData = new Dictionary <MD5Hash, IndexEntry>(comparer); } RootEntry rootEntry; foreach (var entry in RootHandler.GetAllEntries()) { rootEntry = entry.Value; if ((rootEntry.LocaleFlags == locale || (rootEntry.LocaleFlags & locale) != LocaleFlags.None) && (rootEntry.ContentFlags & ContentFlags.LowViolence) == ContentFlags.None) { if (EncodingHandler.GetEntry(rootEntry.MD5, out EncodingEntry enc)) { if (!HashToKey.ContainsKey(entry.Key)) { HashToKey.Add(entry.Key, enc.Key); FileDataIdToHash.Add(RootHandler.GetFileDataIdByHash(entry.Key), entry.Key); if (LocalIndex != null) { IndexEntry iLocal = LocalIndex.GetIndexInfo(enc.Key); if (iLocal != null && !LocalIndexData.ContainsKey(enc.Key)) { LocalIndexData.Add(enc.Key, iLocal); } } IndexEntry iCDN = CDNIndex.GetIndexInfo(enc.Key); if (iCDN != null && !CDNIndexData.ContainsKey(enc.Key)) { CDNIndexData.Add(enc.Key, iCDN); } } } } } CDNIndex.Clear(); //CDNIndex = null; LocalIndex?.Clear(); LocalIndex = null; RootHandler.Clear(); RootHandler = null; EncodingHandler.Clear(); EncodingHandler = null; GC.Collect(); Logger.WriteLine("CASCHandlerLite: loaded {0} files", HashToKey.Count); }
private CASCHandler(CASCConfig config, BackgroundWorkerEx worker) : base(config, worker) { Logger.WriteLine("CASCHandler: loading encoding data..."); using (var _ = new PerfCounter("new EncodingHandler()")) { using (var fs = OpenEncodingFile(this)) EncodingHandler = new EncodingHandler(fs, worker); } Logger.WriteLine("CASCHandler: loaded {0} encoding data", EncodingHandler.Count); if ((CASCConfig.LoadFlags & LoadFlags.Download) != 0) { Logger.WriteLine("CASCHandler: loading download data..."); using (var _ = new PerfCounter("new DownloadHandler()")) { using (var fs = OpenDownloadFile(EncodingHandler, this)) DownloadHandler = new DownloadHandler(fs, worker); } Logger.WriteLine("CASCHandler: loaded {0} download data", EncodingHandler.Count); } KeyService.LoadKeys(); Logger.WriteLine("CASCHandler: loading root data..."); using (var _ = new PerfCounter("new RootHandler()")) { if (config.IsVfsRoot) { RootHandler = new TVFSRootHandler(worker, this); } else { using (var fs = OpenRootFile(EncodingHandler, this)) { RootHandlerBase UnknownRootHandler() { using (var ufs = new FileStream("unk_root", FileMode.Create)) fs.BaseStream.CopyTo(ufs); throw new Exception("Unsupported game " + config.BuildProduct); } RootHandler = config.GameType switch { CASCGameType.S2 => new MNDXRootHandler(fs, worker), CASCGameType.HotS => new MNDXRootHandler(fs, worker), CASCGameType.D3 => new D3RootHandler(fs, worker, this), CASCGameType.WoW => new WowRootHandler(fs, worker), CASCGameType.S1 => new S1RootHandler(fs, worker), CASCGameType.Agent => new DummyRootHandler(fs, worker), CASCGameType.Bna => new DummyRootHandler(fs, worker), CASCGameType.Client => new DummyRootHandler(fs, worker), CASCGameType.Hearthstone => new DummyRootHandler(fs, worker), CASCGameType.Destiny2 => new DummyRootHandler(fs, worker), CASCGameType.Wlby => new DummyRootHandler(fs, worker), CASCGameType.Rtro => new DummyRootHandler(fs, worker), _ => UnknownRootHandler() }; } } } Logger.WriteLine("CASCHandler: loaded {0} root data", RootHandler.Count); if ((CASCConfig.LoadFlags & LoadFlags.Install) != 0) { Logger.WriteLine("CASCHandler: loading install data..."); using (var _ = new PerfCounter("new InstallHandler()")) { using (var fs = OpenInstallFile(EncodingHandler, this)) InstallHandler = new InstallHandler(fs, worker); //InstallHandler.Print(); } Logger.WriteLine("CASCHandler: loaded {0} install data", InstallHandler.Count); } }