public void LoadFileDataComplete(CASCHandler casc) { if (!casc.FileExists("DBFilesClient\\FileDataComplete.db2")) { return; } Logger.WriteLine("WowRootHandler: loading file names from FileDataComplete.db2..."); using (var s = casc.OpenFile("DBFilesClient\\FileDataComplete.db2")) { WDC1Reader fd = new WDC1Reader(s); Jenkins96 hasher = new Jenkins96(); foreach (var row in fd) { string path = row.Value.GetField <string>(0); string name = row.Value.GetField <string>(1); string fullname = path + name; ulong fileHash = hasher.ComputeHash(fullname); // skip invalid names if (!casc.FileExists(fileHash)) { //Logger.WriteLine("Invalid file name: {0}", fullname); continue; } CASCFile.Files[fileHash] = new CASCFile(fileHash, fullname); } } }
private void PreviewText(string fullName) { var stream = cascHandler.OpenFile(fullName, LocaleFlags.All); var text = new StreamReader(stream).ReadToEnd(); var form = new Form { FormBorderStyle = FormBorderStyle.SizableToolWindow }; form.Controls.Add(new TextBox { Multiline = true, ReadOnly = true, Dock = DockStyle.Fill, Text = text, ScrollBars = ScrollBars.Both }); form.Show(); }
public OwRootHandler(BinaryReader stream, BackgroundWorkerEx worker, CASCHandler casc) { worker?.ReportProgress(0, "Loading \"root\"..."); string str = Encoding.ASCII.GetString(stream.ReadBytes((int)stream.BaseStream.Length)); string[] array = str.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); List <string> APMNames = new List <string>(); for (int i = 1; i < array.Length; i++) { string[] filedata = array[i].Split('|'); string name = filedata[4]; if (Path.GetExtension(name) == ".apm" && name.Contains("RDEV")) { APMNames.Add(Path.GetFileNameWithoutExtension(name)); if (!name.Contains("L" + LanguageScan)) { continue; } // add apm file for dev purposes ulong apmNameHash = Hasher.ComputeHash(name); MD5Hash apmMD5 = filedata[0].ToByteArray().ToMD5(); _rootData[apmNameHash] = new OWRootEntry() { baseEntry = new RootEntry() { MD5 = apmMD5, LocaleFlags = LocaleFlags.All, ContentFlags = ContentFlags.None } }; CASCFile.FileNames[apmNameHash] = name; EncodingEntry apmEnc; if (!casc.Encoding.GetEntry(apmMD5, out apmEnc)) { continue; } using (Stream apmStream = casc.OpenFile(apmEnc.Key)) { apmFiles.Add(new APMFile(name, apmStream, casc)); } } worker?.ReportProgress((int)(i / (array.Length / 100f))); } APMList = APMNames.ToArray(); APMNames.Clear(); }
public IEnumerable <string> ScanFile(CASCFile file) { if (excludeFileTypes.Contains(Path.GetExtension(file.FullName).ToLower())) { yield break; } Stream fileStream = null; try { fileStream = CASC.OpenFile(file.Hash); } catch { Logger.WriteLine("Skipped {0} because of both local and CDN indices are missing.", file.FullName); yield break; } using (fileStream) { int b; int state = 1; StringBuilder sb = new StringBuilder(); // look for regex a+(da+)*\.a+ where a = IsAlphaNum() and d = IsFileDelim() // using a simple state machine while ((b = fileStream.ReadByte()) > -1) { if (state == 1 && IsAlphaNum(b) || state == 2 && IsAlphaNum(b) || state == 3 && IsAlphaNum(b)) // alpha { state = 2; sb.Append((char)b); if (sb.Length > 10) { int nextByte = fileStream.ReadByte(); if (nextByte == 0) { string foundStr = sb.ToString(); foreach (var ext in extensions) { yield return(foundStr + ext); } } if (nextByte > -1) { fileStream.Position -= 1; } } } else if (state == 2 && IsFileDelim(b)) // delimiter { state = 3; sb.Append((char)b); } else if (state == 2 && b == 46) // dot { state = 4; sb.Append((char)b); } else if (state == 4 && IsAlphaNum(b)) // extension { state = 5; sb.Append((char)b); } else if (state == 5 && IsAlphaNum(b)) // extension { sb.Append((char)b); } else if (state == 5 && !IsFileChar(b)) // accept { state = 1; if (sb.Length >= 10) { yield return(sb.ToString()); } sb.Clear(); } else { state = 1; sb.Clear(); } } } }
public async Task AnalyzeUnknownFiles(Action <int> progressCallback) { if (_casc == null) { return; } IProgress <int> progress = new Progress <int>(progressCallback); await Task.Run(() => { FileScanner scanner = new FileScanner(_casc, _root); Dictionary <uint, List <string> > idToName = new Dictionary <uint, List <string> >(); if (_casc.Config.GameType == CASCGameType.WoW) { if (_casc.FileExists("DBFilesClient\\SoundEntries.db2")) { using (Stream stream = _casc.OpenFile("DBFilesClient\\SoundEntries.db2")) { DB2Reader se = new DB2Reader(stream); foreach (var row in se) { string name = row.Value.GetField <string>(2); int type = row.Value.GetField <int>(1); bool many = row.Value.GetField <int>(4) > 0; for (int i = 3; i < 23; i++) { uint id = row.Value.GetField <uint>(i); if (!idToName.ContainsKey(id)) { idToName[id] = new List <string>(); } idToName[id].Add("unknown\\sound\\" + name + (many ? "_" + (i - 2).ToString("D2") : "") + (type == 28 ? ".mp3" : ".ogg")); } } } } if (_casc.FileExists("DBFilesClient\\SoundKit.db2") && _casc.FileExists("DBFilesClient\\SoundKitEntry.db2") && _casc.FileExists("DBFilesClient\\SoundKitName.db2")) { using (Stream skStream = _casc.OpenFile("DBFilesClient\\SoundKit.db2")) using (Stream skeStream = _casc.OpenFile("DBFilesClient\\SoundKitEntry.db2")) using (Stream sknStream = _casc.OpenFile("DBFilesClient\\SoundKitName.db2")) { WDC1Reader sk = new WDC1Reader(skStream); WDC1Reader ske = new WDC1Reader(skeStream); WDC1Reader skn = new WDC1Reader(sknStream); Dictionary <uint, List <uint> > lookup = new Dictionary <uint, List <uint> >(); foreach (var row in ske) { uint soundKitId = row.Value.GetField <uint>(0); if (!lookup.ContainsKey(soundKitId)) { lookup[soundKitId] = new List <uint>(); } lookup[soundKitId].Add(row.Value.GetField <uint>(1)); } foreach (var row in sk) { string name = skn.GetRow(row.Key).GetField <string>(0).Replace(':', '_'); int type = row.Value.GetField <byte>(6); if (!lookup.TryGetValue(row.Key, out List <uint> ske_entries)) { continue; } bool many = ske_entries.Count > 1; int i = 0; foreach (var fid in ske_entries) { if (!idToName.ContainsKey(fid)) { idToName[fid] = new List <string>(); } idToName[fid].Add("unknown\\sound\\" + name + (many ? "_" + (i + 1).ToString("D2") : "") + "_" + fid + (type == 28 ? ".mp3" : ".ogg")); i++; } } } } } CASCFolder unknownFolder = _root.GetEntry("unknown") as CASCFolder; if (unknownFolder == null) { return; } IEnumerable <CASCFile> files = CASCFolder.GetFiles(unknownFolder.Entries.Select(kv => kv.Value), null, true).ToList(); int numTotal = files.Count(); int numDone = 0; WowRootHandler wowRoot = _casc.Root as WowRootHandler; Jenkins96 Hasher = new Jenkins96(); char[] PathDelimiters = new char[] { '/', '\\' }; foreach (var unknownEntry in files) { CASCFile unknownFile = unknownEntry as CASCFile; if (idToName.TryGetValue((uint)wowRoot.GetFileDataIdByHash(unknownFile.Hash), out List <string> name)) { if (name.Count == 1) { unknownFile.FullName = name[0]; } else { unknownFolder.Entries.Remove(unknownFile.Name); foreach (var file in name) { Logger.WriteLine(file); string[] parts = file.Split(PathDelimiters); string entryName = parts[parts.Length - 1]; ulong filehash = unknownFile.Hash; CASCFile entry = new CASCFile(filehash, file); CASCFile.Files[filehash] = entry; unknownFolder.Entries[entryName] = entry; } } } else { string ext = scanner.GetFileExtension(unknownFile); unknownFile.FullName += ext; if (ext == ".m2") { using (var m2file = _casc.OpenFile(unknownFile.Hash)) using (var br = new BinaryReader(m2file)) { m2file.Position = 0x14; int nameOffs = br.ReadInt32(); m2file.Position = nameOffs + 8; // + sizeof(MD21) string m2name = br.ReadCString(); unknownFile.FullName = "unknown\\" + m2name + ".m2"; } } } progress.Report((int)(++numDone / (float)numTotal * 100)); } _casc.Root.Dump(); }); }
public void LoadFileDataComplete(CASCHandler casc) { if (!casc.FileExists("DBFilesClient\\FileDataComplete.db2")) return; Logger.WriteLine("WowRootHandler: loading file names from FileDataComplete.db2..."); using (var s = casc.OpenFile("DBFilesClient\\FileDataComplete.db2")) { DB5Reader fd = new DB5Reader(s); foreach (var row in fd) { string path = row.Value.GetField<string>(0); string name = row.Value.GetField<string>(1); string fullname = path + name; ulong fileHash = Hasher.ComputeHash(fullname); // skip invalid names if (!RootData.ContainsKey(fileHash)) { //Logger.WriteLine("Invalid file name: {0}", fullname); continue; } CASCFile.FileNames[fileHash] = fullname; } } }
public async Task AnalyzeUnknownFiles(Action <int> progressCallback) { if (_casc == null) { return; } IProgress <int> progress = new Progress <int>(progressCallback); await Task.Run(() => { FileScanner scanner = new FileScanner(_casc, _root); Dictionary <int, string> idToName = new Dictionary <int, string>(); if (_casc.Config.GameType == CASCGameType.WoW) { if (_casc.FileExists("DBFilesClient\\SoundEntries.db2")) { using (Stream stream = _casc.OpenFile("DBFilesClient\\SoundEntries.db2")) { DB2Reader se = new DB2Reader(stream); foreach (var row in se) { string name = row.Value.GetField <string>(2); int type = row.Value.GetField <int>(1); bool many = row.Value.GetField <int>(4) > 0; for (int i = 3; i < 23; i++) { idToName[row.Value.GetField <int>(i)] = "unknown\\sound\\" + name + (many ? "_" + (i - 2).ToString("D2") : "") + (type == 28 ? ".mp3" : ".ogg"); } } } } if (_casc.FileExists("DBFilesClient\\SoundKit.db2") && _casc.FileExists("DBFilesClient\\SoundKitEntry.db2")) { using (Stream skStream = _casc.OpenFile("DBFilesClient\\SoundKit.db2")) using (Stream skeStream = _casc.OpenFile("DBFilesClient\\SoundKitEntry.db2")) { DB5Reader sk = new DB5Reader(skStream); DB5Reader ske = new DB5Reader(skeStream); Dictionary <int, List <int> > lookup = new Dictionary <int, List <int> >(); foreach (var row in ske) { int soundKitId = row.Value.GetField <int>(3); if (!lookup.ContainsKey(soundKitId)) { lookup[soundKitId] = new List <int>(); } lookup[soundKitId].Add(row.Value.GetField <int>(0)); } foreach (var row in sk) { string name = row.Value.GetField <string>(0).Replace(':', '_'); int type = row.Value.GetField <byte>(12); List <int> ske_entries; if (!lookup.TryGetValue(row.Key, out ske_entries)) { continue; } bool many = ske_entries.Count > 1; int i = 0; foreach (var fid in ske_entries) { idToName[fid] = "unknown\\sound\\" + name + (many ? "_" + (i + 1).ToString("D2") : "") + (type == 28 ? ".mp3" : ".ogg"); i++; } } } } } CASCFolder unknownFolder = _root.GetEntry("unknown") as CASCFolder; if (unknownFolder == null) { return; } IEnumerable <CASCFile> files = CASCFolder.GetFiles(unknownFolder.Entries.Select(kv => kv.Value), null, true); int numTotal = files.Count(); int numDone = 0; WowRootHandler wowRoot = _casc.Root as WowRootHandler; foreach (var unknownEntry in files) { CASCFile unknownFile = unknownEntry as CASCFile; string name; if (idToName.TryGetValue(wowRoot.GetFileDataIdByHash(unknownFile.Hash), out name)) { unknownFile.FullName = name; } else { string ext = scanner.GetFileExtension(unknownFile); unknownFile.FullName += ext; if (ext == ".m2") { using (var m2file = _casc.OpenFile(unknownFile.Hash)) using (var br = new BinaryReader(m2file)) { m2file.Position = 0x138; string m2name = br.ReadCString(); unknownFile.FullName = "unknown\\" + m2name + ".m2"; } } } progress.Report((int)(++numDone / (float)numTotal * 100.0f)); } _casc.Root.Dump(); }); }
public APMFile(string name, Stream stream, CASCHandler casc) { Name = name; using (BinaryReader reader = new BinaryReader(stream)) { ulong buildVersion = reader.ReadUInt64(); uint buildNumber = reader.ReadUInt32(); uint packageCount = reader.ReadUInt32(); uint entryCount = reader.ReadUInt32(); uint unk = reader.ReadUInt32(); entries = new APMEntry[entryCount]; for (int j = 0; j < entryCount; j++) { entries[j] = reader.Read <APMEntry>(); } packages = new APMPackage[packageCount]; indexes = new PackageIndex[packageCount]; records = new PackageIndexRecord[packageCount][]; dependencies = new uint[packageCount][]; for (int j = 0; j < packages.Length; j++) { packages[j] = reader.Read <APMPackage>(); if (!casc.Encoding.GetEntry(packages[j].indexContentKey, out EncodingEntry pkgIndexEnc)) { throw new Exception("pkgIndexEnc missing"); } using (Stream pkgIndexStream = casc.OpenFile(pkgIndexEnc.Key)) using (BinaryReader pkgIndexReader = new BinaryReader(pkgIndexStream)) { indexes[j] = pkgIndexReader.Read <PackageIndex>(); pkgIndexStream.Position = indexes[j].recordsOffset; using (GZipStream recordsStream = new GZipStream(pkgIndexStream, CompressionMode.Decompress, true)) using (BinaryReader recordsReader = new BinaryReader(recordsStream)) { PackageIndexRecord[] recs = new PackageIndexRecord[indexes[j].numRecords]; for (int k = 0; k < recs.Length; k++) { recs[k] = recordsReader.Read <PackageIndexRecord>(); } records[j] = recs; } pkgIndexStream.Position = indexes[j].depsOffset; uint[] deps = new uint[indexes[j].numDeps]; for (int k = 0; k < deps.Length; k++) { deps[k] = pkgIndexReader.ReadUInt32(); } dependencies[j] = deps; } } } }
public D3RootHandler(BinaryReader stream, BackgroundWorkerEx worker, CASCHandler casc) { worker?.ReportProgress(0, "Loading \"root\"..."); byte b1 = stream.ReadByte(); byte b2 = stream.ReadByte(); byte b3 = stream.ReadByte(); byte b4 = stream.ReadByte(); int count = stream.ReadInt32(); for (int j = 0; j < count; j++) { MD5Hash md5 = stream.Read<MD5Hash>(); string name = stream.ReadCString(); var entries = new List<D3RootEntry>(); D3RootData[name] = entries; EncodingEntry enc; if (!casc.Encoding.GetEntry(md5, out enc)) continue; using (BinaryReader s = new BinaryReader(casc.OpenFile(enc.Key))) { uint magic = s.ReadUInt32(); int nEntries0 = s.ReadInt32(); for (int i = 0; i < nEntries0; i++) { entries.Add(D3RootEntry.Read(0, s)); } int nEntries1 = s.ReadInt32(); for (int i = 0; i < nEntries1; i++) { entries.Add(D3RootEntry.Read(1, s)); } int nNamedEntries = s.ReadInt32(); for (int i = 0; i < nNamedEntries; i++) { entries.Add(D3RootEntry.Read(2, s)); } } worker?.ReportProgress((int)((j + 1) / (float)(count + 2) * 100)); } // Parse CoreTOC.dat var coreTocEntry = D3RootData["Base"].Find(e => e.Name == "CoreTOC.dat"); EncodingEntry enc1; casc.Encoding.GetEntry(coreTocEntry.MD5, out enc1); using (var file = casc.OpenFile(enc1.Key)) tocParser = new CoreTOCParser(file); worker?.ReportProgress((int)((count + 1) / (float)(count + 2) * 100)); // Parse Packages.dat var pkgEntry = D3RootData["Base"].Find(e => e.Name == "Data_D3\\PC\\Misc\\Packages.dat"); EncodingEntry enc2; casc.Encoding.GetEntry(pkgEntry.MD5, out enc2); using (var file = casc.OpenFile(enc2.Key)) pkgParser = new PackagesParser(file); worker?.ReportProgress(100); }
public D3RootHandler(BinaryReader stream, BackgroundWorkerEx worker, CASCHandler casc) { worker?.ReportProgress(0, "Loading \"root\"..."); byte b1 = stream.ReadByte(); byte b2 = stream.ReadByte(); byte b3 = stream.ReadByte(); byte b4 = stream.ReadByte(); int count = stream.ReadInt32(); for (int j = 0; j < count; j++) { byte[] md5 = stream.ReadBytes(16); string name = stream.ReadCString(); var entries = new List <D3RootEntry>(); D3RootData[name] = entries; EncodingEntry enc = casc.Encoding.GetEntry(md5); using (BinaryReader s = new BinaryReader(casc.OpenFile(enc.Key))) { if (s != null) { uint magic = s.ReadUInt32(); int nEntries0 = s.ReadInt32(); for (int i = 0; i < nEntries0; i++) { entries.Add(D3RootEntry.Read(0, s)); } int nEntries1 = s.ReadInt32(); for (int i = 0; i < nEntries1; i++) { entries.Add(D3RootEntry.Read(1, s)); } int nNamedEntries = s.ReadInt32(); for (int i = 0; i < nNamedEntries; i++) { entries.Add(D3RootEntry.Read(2, s)); } } } worker?.ReportProgress((int)((j + 1) / (float)(count + 2) * 100)); } // Parse CoreTOC.dat var coreTocEntry = D3RootData["Base"].Find(e => e.Name == "CoreTOC.dat"); EncodingEntry enc1 = casc.Encoding.GetEntry(coreTocEntry.MD5); using (var file = casc.OpenFile(enc1.Key)) tocParser = new CoreTOCParser(file); worker?.ReportProgress((int)((count + 1) / (float)(count + 2) * 100)); // Parse Packages.dat var pkgEntry = D3RootData["Base"].Find(e => e.Name == "Data_D3\\PC\\Misc\\Packages.dat"); EncodingEntry enc2 = casc.Encoding.GetEntry(pkgEntry.MD5); using (var file = casc.OpenFile(enc2.Key)) pkgParser = new PackagesParser(file); worker?.ReportProgress(100); }
public APMFile(string name, Stream stream, CASCHandler casc) { Name = name; using (BinaryReader reader = new BinaryReader(stream)) { ulong buildVersion = reader.ReadUInt64(); uint buildNumber = reader.ReadUInt32(); uint packageCount = reader.ReadUInt32(); uint entryCount = reader.ReadUInt32(); uint unk = reader.ReadUInt32(); entries = new APMEntry[entryCount]; for (int j = 0; j < entryCount; j++) { entries[j] = reader.Read<APMEntry>(); } packages = new APMPackage[packageCount]; indexes = new PackageIndex[packageCount]; records = new PackageIndexRecord[packageCount][]; dependencies = new uint[packageCount][]; for (int j = 0; j < packages.Length; j++) { packages[j] = reader.Read<APMPackage>(); EncodingEntry pkgIndexEnc; if (!casc.Encoding.GetEntry(packages[j].indexContentKey, out pkgIndexEnc)) throw new Exception("pkgIndexEnc missing"); using (Stream pkgIndexStream = casc.OpenFile(pkgIndexEnc.Key)) using (BinaryReader pkgIndexReader = new BinaryReader(pkgIndexStream)) { indexes[j] = pkgIndexReader.Read<PackageIndex>(); pkgIndexStream.Position = indexes[j].recordsOffset; using (GZipStream recordsStream = new GZipStream(pkgIndexStream, CompressionMode.Decompress, true)) using (BinaryReader recordsReader = new BinaryReader(recordsStream)) { PackageIndexRecord[] recs = new PackageIndexRecord[indexes[j].numRecords]; for (int k = 0; k < recs.Length; k++) recs[k] = recordsReader.Read<PackageIndexRecord>(); records[j] = recs; } pkgIndexStream.Position = indexes[j].depsOffset; uint[] deps = new uint[indexes[j].numDeps]; for (int k = 0; k < deps.Length; k++) deps[k] = pkgIndexReader.ReadUInt32(); dependencies[j] = deps; } } } }
public OwRootHandler(BinaryReader stream, BackgroundWorkerEx worker, CASCHandler casc) { worker?.ReportProgress(0, "Loading \"root\"..."); string str = Encoding.ASCII.GetString(stream.ReadBytes((int)stream.BaseStream.Length)); string[] array = str.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); List<string> APMNames = new List<string>(); for (int i = 1; i < array.Length; i++) { string[] filedata = array[i].Split('|'); string name = filedata[4]; if (Path.GetExtension(name) == ".apm" && name.Contains("RDEV")) { APMNames.Add(Path.GetFileNameWithoutExtension(name)); if(!name.Contains("L"+LanguageScan)) { continue; } // add apm file for dev purposes ulong apmNameHash = Hasher.ComputeHash(name); MD5Hash apmMD5 = filedata[0].ToByteArray().ToMD5(); _rootData[apmNameHash] = new OWRootEntry() { baseEntry = new RootEntry() { MD5 = apmMD5, LocaleFlags = LocaleFlags.All, ContentFlags = ContentFlags.None } }; CASCFile.FileNames[apmNameHash] = name; EncodingEntry apmEnc; if (!casc.Encoding.GetEntry(apmMD5, out apmEnc)) continue; using (Stream apmStream = casc.OpenFile(apmEnc.Key)) { apmFiles.Add(new APMFile(name, apmStream, casc)); } } worker?.ReportProgress((int)(i / (array.Length / 100f))); } APMList = APMNames.ToArray(); APMNames.Clear(); }
public OWRootHandler(BinaryReader stream, BackgroundWorkerEx worker, CASCHandler casc) { worker?.ReportProgress(0, "Loading \"root\"..."); string str = Encoding.ASCII.GetString(stream.ReadBytes((int)stream.BaseStream.Length)); string[] array = str.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); // need to figure out what to do with those apm files for (int i = 1; i < array.Length; i++) { string[] filedata = array[i].Split('|'); if (Path.GetExtension(filedata[2]) == ".apm") { // add apm file for dev purposes ulong fileHash1 = Hasher.ComputeHash(filedata[2]); RootData[fileHash1] = new RootEntry() { MD5 = filedata[0].ToByteArray(), Block = RootBlock.Empty }; CASCFile.FileNames[fileHash1] = filedata[2]; // add files listed in apm file byte[] md5 = filedata[0].ToByteArray(); EncodingEntry enc = casc.Encoding.GetEntry(md5); using (BinaryReader s = new BinaryReader(casc.OpenFile(enc.Key))) { if (s != null) { // still need to figure out complete apm structure // at start of file there's a lot of data that is same in all apm files s.BaseStream.Position = 0xC; uint count = s.ReadUInt32(); s.BaseStream.Position = 0x894; // size of each entry seems to be 0x48 bytes (0x2C bytes unk data; int size; ulong unk; byte[16] md5) for (int j = 0; j < count; j++) { s.BaseStream.Position += 0x2C; // skip unknown int size = s.ReadInt32(); // size (matches size in encoding file) s.BaseStream.Position += 8; // skip unknown byte[] md5_2 = s.ReadBytes(16); EncodingEntry enc2 = casc.Encoding.GetEntry(md5_2); if (enc2 == null) { throw new Exception("enc2 == null"); } string fakeName = Path.GetFileNameWithoutExtension(filedata[2]) + "/" + md5_2.ToHexString(); ulong fileHash = Hasher.ComputeHash(fakeName); RootData[fileHash] = new RootEntry() { MD5 = md5_2, Block = RootBlock.Empty }; CASCFile.FileNames[fileHash] = fakeName; } } } } } int current = 0; Func<string, LocaleFlags> tag2locale = (s) => { LocaleFlags locale; if (Enum.TryParse(s, out locale)) return locale; return LocaleFlags.All; }; foreach (var entry in casc.Encoding.Entries) { DownloadEntry dl = casc.Download.GetEntry(entry.Value.Key); if (dl != null) { string fakeName = "unknown" + "/" + entry.Key[0].ToString("X2") + "/" + entry.Key.ToHexString(); var locales = dl.Tags.Where(tag => tag.Value.Type == 4).Select(tag => tag2locale(tag.Key)); LocaleFlags locale = LocaleFlags.None; foreach (var loc in locales) locale |= loc; ulong fileHash = Hasher.ComputeHash(fakeName); RootData.Add(fileHash, new RootEntry() { MD5 = entry.Key, Block = new RootBlock() { LocaleFlags = locale } }); CASCFile.FileNames[fileHash] = fakeName; } worker?.ReportProgress((int)(++current / (float)casc.Encoding.Count * 100)); } }
public OWRootHandler(BinaryReader stream, BackgroundWorkerEx worker, CASCHandler casc) { worker?.ReportProgress(0, "Loading \"root\"..."); string str = Encoding.ASCII.GetString(stream.ReadBytes((int)stream.BaseStream.Length)); string[] array = str.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); // need to figure out what to do with those apm files for (int i = 1; i < array.Length; i++) { string[] filedata = array[i].Split('|'); if (Path.GetExtension(filedata[2]) == ".apm") { // add apm file for dev purposes ulong fileHash1 = Hasher.ComputeHash(filedata[2]); RootData[fileHash1] = new RootEntry() { MD5 = filedata[0].ToByteArray(), Block = RootBlock.Empty }; CASCFile.FileNames[fileHash1] = filedata[2]; // add files listed in apm file byte[] md5 = filedata[0].ToByteArray(); EncodingEntry enc = casc.Encoding.GetEntry(md5); using (BinaryReader s = new BinaryReader(casc.OpenFile(enc.Key))) { if (s != null) { // still need to figure out complete apm structure // at start of file there's a lot of data that is same in all apm files s.BaseStream.Position = 0xC; uint count = s.ReadUInt32(); s.BaseStream.Position = 0x894; // size of each entry seems to be 0x48 bytes (0x2C bytes unk data; int size; ulong unk; byte[16] md5) for (int j = 0; j < count; j++) { s.BaseStream.Position += 0x2C; // skip unknown int size = s.ReadInt32(); // size (matches size in encoding file) s.BaseStream.Position += 8; // skip unknown byte[] md5_2 = s.ReadBytes(16); EncodingEntry enc2 = casc.Encoding.GetEntry(md5_2); if (enc2 == null) { throw new Exception("enc2 == null"); } string fakeName = Path.GetFileNameWithoutExtension(filedata[2]) + "/" + md5_2.ToHexString(); ulong fileHash = Hasher.ComputeHash(fakeName); RootData[fileHash] = new RootEntry() { MD5 = md5_2, Block = RootBlock.Empty }; CASCFile.FileNames[fileHash] = fakeName; } } } } } int current = 0; Func <string, LocaleFlags> tag2locale = (s) => { LocaleFlags locale; if (Enum.TryParse(s, out locale)) { return(locale); } return(LocaleFlags.All); }; foreach (var entry in casc.Encoding.Entries) { DownloadEntry dl = casc.Download.GetEntry(entry.Value.Key); if (dl != null) { string fakeName = "unknown" + "/" + entry.Key[0].ToString("X2") + "/" + entry.Key.ToHexString(); var locales = dl.Tags.Where(tag => tag.Value.Type == 4).Select(tag => tag2locale(tag.Key)); LocaleFlags locale = LocaleFlags.None; foreach (var loc in locales) { locale |= loc; } ulong fileHash = Hasher.ComputeHash(fakeName); RootData.Add(fileHash, new RootEntry() { MD5 = entry.Key, Block = new RootBlock() { LocaleFlags = locale } }); CASCFile.FileNames[fileHash] = fakeName; } worker?.ReportProgress((int)(++current / (float)casc.Encoding.Count * 100)); } }
public async Task AnalyzeUnknownFiles(Action <int> progressCallback) { if (_casc == null) { return; } IProgress <int> progress = new Progress <int>(progressCallback); await Task.Run(() => { FileScanner scanner = new FileScanner(_casc, _root); Dictionary <int, List <string> > idToName = new Dictionary <int, List <string> >(); if (_casc.Config.GameType == CASCGameType.WoW && AnalyzeSoundFiles) { if (_casc.FileExists("DBFilesClient\\SoundEntries.db2")) { using (Stream stream = _casc.OpenFile("DBFilesClient\\SoundEntries.db2")) { WDB2Reader se = new WDB2Reader(stream); foreach (var row in se) { string name = row.Value.GetField <string>(2); int type = row.Value.GetField <int>(1); bool many = row.Value.GetField <int>(4) > 0; for (int i = 3; i < 23; i++) { int id = row.Value.GetField <int>(i); if (!idToName.ContainsKey(id)) { idToName[id] = new List <string>(); } idToName[id].Add("unknown\\sound\\" + name + (many ? "_" + (i - 2).ToString("D2") : "") + (type == 28 ? ".mp3" : ".ogg")); } } } } if (_casc.FileExists(1237434 /*"DBFilesClient\\SoundKit.db2"*/) && _casc.FileExists(1237435 /*"DBFilesClient\\SoundKitEntry.db2"*/) && _casc.FileExists(1665033 /*"DBFilesClient\\SoundKitName.db2"*/)) { using (Stream skStream = _casc.OpenFile(1237434)) using (Stream skeStream = _casc.OpenFile(1237435)) using (Stream sknStream = _casc.OpenFile(1665033)) { Func <ulong, bool> keyCheckFunc = x => KeyService.GetKey(x) != null; WDC3Reader sk = new WDC3Reader(skStream, keyCheckFunc); WDC3Reader ske = new WDC3Reader(skeStream, keyCheckFunc); WDC3Reader skn = new WDC3Reader(sknStream, keyCheckFunc); Dictionary <int, List <int> > lookup = new Dictionary <int, List <int> >(); foreach (var row in ske) { int soundKitId = row.Value.GetField <int>(0); if (!lookup.ContainsKey(soundKitId)) { lookup[soundKitId] = new List <int>(); } lookup[soundKitId].Add(row.Value.GetField <int>(1)); } foreach (var row in sk) { WDC3Row sknRow = skn.GetRow(row.Key); if (sknRow != null) { string name = sknRow.GetField <string>(0).Replace(':', '_').Replace("\"", ""); int type = row.Value.GetField <byte>(6); if (!lookup.TryGetValue(row.Key, out List <int> ske_entries)) { continue; } bool many = ske_entries.Count > 1; int i = 0; foreach (var fid in ske_entries) { if (!idToName.ContainsKey(fid)) { idToName[fid] = new List <string>(); } if (AddFileDataIdToSoundFiles) { idToName[fid].Add("unknown\\sound\\" + name + (many ? "_" + (i + 1).ToString("D2") : "") + "_" + fid + (type == 28 ? ".mp3" : ".ogg")); } else { idToName[fid].Add("unknown\\sound\\" + name + (many ? "_" + (i + 1).ToString("D2") : "") + (type == 28 ? ".mp3" : ".ogg")); } i++; } } } } } } CASCFolder unknownFolder = _root.GetEntry("unknown") as CASCFolder; if (unknownFolder == null) { return; } foreach (var kv in idToName) { foreach (var fn in kv.Value) { Logger.WriteLine($"{kv.Key};{fn}"); } } IEnumerable <CASCFile> files = CASCFolder.GetFiles(unknownFolder.Entries.Select(kv => kv.Value), null, true).ToList(); int numTotal = files.Count(); int numDone = 0; WowRootHandler wowRoot = _casc.Root as WowRootHandler; Jenkins96 Hasher = new Jenkins96(); char[] PathDelimiters = new char[] { '/', '\\' }; foreach (var unknownEntry in files) { CASCFile unknownFile = unknownEntry as CASCFile; if (idToName.TryGetValue(wowRoot.GetFileDataIdByHash(unknownFile.Hash), out List <string> name)) { if (name.Count == 1) { unknownFile.FullName = name[0]; } else { unknownFolder.Entries.Remove(unknownFile.Name); foreach (var file in name) { //Logger.WriteLine(file); string[] parts = file.Split(PathDelimiters); string entryName = parts[parts.Length - 1]; ulong filehash = unknownFile.Hash; CASCFile entry = new CASCFile(filehash, file); CASCFile.Files[filehash] = entry; unknownFolder.Entries[entryName] = entry; } } } else { string ext = scanner.GetFileExtension(unknownFile); unknownFile.FullName += ext; if (ext == ".m2") { using (var m2file = _casc.OpenFile(unknownFile.Hash)) using (var br = new BinaryReader(m2file)) { m2file.Position = 0x14; int nameOffs = br.ReadInt32(); m2file.Position = nameOffs + 8; // + sizeof(MD21) string m2name = br.ReadCString(); unknownFile.FullName = "unknown\\" + m2name + ".m2"; Logger.WriteLine($"{wowRoot.GetFileDataIdByHash(unknownFile.Hash)};{unknownFile.FullName}"); //m2file.Position = 0; //while (m2file.Position != m2file.Length) //{ // int chunkType = br.ReadInt32(); // int chunkSize = br.ReadInt32(); // if (chunkType == 0x44494641) // AFID // { // int count = chunkSize / 8; // for (int i = 0; i < count; i++) // { // ushort animId = br.ReadUInt16(); // ushort subAnimId = br.ReadUInt16(); // int FileDataId = br.ReadInt32(); // if (FileDataId != 0) // Logger.WriteLine($"{FileDataId};{wowRoot.GetFileDataIdByHash(unknownFile.Hash)}\\{name}\\{name}{animId:D4}-{subAnimId:D2}.anim"); // } // break; // } // else // { // m2file.Position += chunkSize; // } //} } } } progress.Report((int)(++numDone / (float)numTotal * 100)); } _casc.Root.Dump(); }); }