private const uint WDB2FmtSig = 0x32424457; // WDB2 public WDB2Writer(WDB2Reader reader, IDictionary <int, T> storage, Stream stream) : base(reader) { WDB2RowSerializer <T> serializer = new WDB2RowSerializer <T>(this); serializer.Serialize(storage); RecordsCount = storage.Count; using (var writer = new BinaryWriter(stream)) { writer.Write(WDB2FmtSig); writer.Write(RecordsCount); writer.Write(FieldsCount); writer.Write(RecordSize); writer.Write(StringTableSize); writer.Write(reader.TableHash); writer.Write(reader.Build); writer.Write((uint)DateTimeOffset.UtcNow.ToUnixTimeSeconds()); if (storage.Count == 0) { return; } // Extended header if (reader.Build > 12880) { if (reader.MaxIndex == 0) { writer.Write(0); writer.Write(0); writer.Write(reader.LayoutHash); writer.Write(0); // CopyTableSize } else { WriteIndices(writer, serializer, reader.LayoutHash); } } foreach (var record in serializer.Records) { record.Value.CopyTo(writer.BaseStream); } foreach (var str in StringTable) { writer.WriteCString(str.Key); } } }
public Storage(Stream stream) { DB2Reader reader; using (stream) using (var bin = new BinaryReader(stream)) { var identifier = new string(bin.ReadChars(4)); stream.Position = 0; switch (identifier) { case "WDC3": reader = new WDC3Reader(stream); break; case "WDC2": case "1SLC": reader = new WDC2Reader(stream); break; case "WDC1": reader = new WDC1Reader(stream); break; case "WDB6": reader = new WDB6Reader(stream); break; case "WDB5": reader = new WDB5Reader(stream); break; case "WDB4": reader = new WDB4Reader(stream); break; case "WDB3": reader = new WDB3Reader(stream); break; case "WDB2": reader = new WDB2Reader(stream); break; case "WDBC": reader = new WDBCReader(stream); break; default: throw new Exception("DB type " + identifier + " is not supported!"); } } FieldInfo[] fields = typeof(T).GetFields(); FieldCache <T>[] fieldCache = new FieldCache <T> [fields.Length]; for (int i = 0; i < fields.Length; ++i) { bool indexMapAttribute = reader.Flags.HasFlagExt(DB2Flags.Index) ? Attribute.IsDefined(fields[i], typeof(IndexAttribute)) : false; fieldCache[i] = new FieldCache <T>(fields[i], indexMapAttribute); } Parallel.ForEach(reader.AsEnumerable(), new ParallelOptions() { MaxDegreeOfParallelism = 1 }, row => { T entry = new T(); row.Value.GetFields(fieldCache, entry); lock (this) Add(row.Value.Id, entry); }); }
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("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")) { WDC3Reader sk = new WDC3Reader(skStream); WDC3Reader ske = new WDC3Reader(skeStream); WDC3Reader skn = new WDC3Reader(sknStream); 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) { string name = skn.GetRow(row.Key).GetField <string>(0).Replace(':', '_'); //string name = row.Value.GetField<string>(0).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; } 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"; } } } progress.Report((int)(++numDone / (float)numTotal * 100)); } _casc.Root.Dump(); }); }