private void AddFile(string pkg, D3RootEntry e) { string name; switch (e.Type) { case 0: SNOInfo sno1 = tocParser.GetSNO(e.SNO); name = string.Format("{0}\\{1}{2}", sno1.GroupId, sno1.Name, sno1.Ext); break; case 1: SNOInfo sno2 = tocParser.GetSNO(e.SNO); name = string.Format("{0}\\{1}\\{2:D4}", sno2.GroupId, sno2.Name, e.FileIndex); string ext = pkgParser.GetExtension(name); if (ext != null) { name += ext; } else { CountUnknown++; name += ".xxx"; } break; case 2: name = e.Name; break; default: name = "Unknown"; break; } RootEntry entry = new RootEntry(); entry.MD5 = e.MD5; LocaleFlags locale; entry.Block = new RootBlock(); if (Enum.TryParse(pkg, out locale)) { entry.Block.LocaleFlags = locale; } else { entry.Block.LocaleFlags = LocaleFlags.All; } ulong fileHash = Hasher.ComputeHash(name); CASCFile.FileNames[fileHash] = name; RootData.Add(fileHash, entry); }
public S1RootHandler(BinaryReader stream, BackgroundWorkerEx worker) { worker?.ReportProgress(0, "Loading \"root\"..."); using (StreamReader sr = new StreamReader(stream.BaseStream)) { string line; while ((line = sr.ReadLine()) != null) { string[] tokens = line.Split('|'); string file; LocaleFlags locale = LocaleFlags.All; if (tokens[0].IndexOf(':') != -1) { string[] tokens2 = tokens[0].Split(':'); file = tokens2[0]; locale = (LocaleFlags)Enum.Parse(typeof(LocaleFlags), tokens2[1]); } else { file = tokens[0]; } ulong fileHash = Hasher.ComputeHash(file); RootData[fileHash] = new RootEntry() { LocaleFlags = locale, ContentFlags = ContentFlags.None, MD5 = tokens[1].ToByteArray().ToMD5() }; CASCFile.FileNames[fileHash] = file; } } worker?.ReportProgress(100); }
public WowRootHandler(BinaryReader stream, BackgroundWorkerEx worker) { worker?.ReportProgress(0, "Loading \"root\"..."); while (stream.BaseStream.Position < stream.BaseStream.Length) { int count = stream.ReadInt32(); ContentFlags contentFlags = (ContentFlags)stream.ReadUInt32(); LocaleFlags localeFlags = (LocaleFlags)stream.ReadUInt32(); if (localeFlags == LocaleFlags.None) throw new Exception("block.LocaleFlags == LocaleFlags.None"); if (contentFlags != ContentFlags.None && (contentFlags & (ContentFlags.LowViolence | ContentFlags.NoCompression | ContentFlags.F20000000)) == 0) throw new Exception("block.ContentFlags != ContentFlags.None"); RootEntry[] entries = new RootEntry[count]; int[] filedataIds = new int[count]; int fileDataIndex = 0; for (var i = 0; i < count; ++i) { entries[i].LocaleFlags = localeFlags; entries[i].ContentFlags = contentFlags; filedataIds[i] = fileDataIndex + stream.ReadInt32(); fileDataIndex = filedataIds[i] + 1; } //Console.WriteLine("Block: {0} {1} (size {2})", block.ContentFlags, block.LocaleFlags, count); for (var i = 0; i < count; ++i) { entries[i].MD5 = stream.Read<MD5Hash>(); ulong hash = stream.ReadUInt64(); RootData.Add(hash, entries[i]); //Console.WriteLine("File: {0:X8} {1:X16} {2}", entries[i].FileDataId, hash, entries[i].MD5.ToHexString()); ulong hash2; int fileDataId = filedataIds[i]; if (FileDataStore.TryGetValue(fileDataId, out hash2)) { if (hash2 == hash) { // duplicate, skipping continue; } else { Logger.WriteLine("ERROR: got miltiple hashes for filedataid {0}", fileDataId); continue; } } FileDataStore.Add(fileDataId, hash); FileDataStoreReverse.Add(hash, fileDataId); } worker?.ReportProgress((int)(stream.BaseStream.Position / (float)stream.BaseStream.Length * 100)); } }
private void AddFile(string pkg, D3RootEntry e) { string name; switch (e.Type) { case 0: SNOInfo sno1 = tocParser.GetSNO(e.SNO); name = string.Format("{0}\\{1}{2}", sno1.GroupId, sno1.Name, sno1.Ext); break; case 1: SNOInfo sno2 = tocParser.GetSNO(e.SNO); name = string.Format("{0}\\{1}\\{2:D4}", sno2.GroupId, sno2.Name, e.FileIndex); string ext = pkgParser.GetExtension(name); if (ext != null) name += ext; else { CountUnknown++; name += ".xxx"; } break; case 2: name = e.Name; break; default: name = "Unknown"; break; } RootEntry entry = new RootEntry(); entry.MD5 = e.MD5; LocaleFlags locale; if (Enum.TryParse(pkg, out locale)) entry.LocaleFlags = locale; else entry.LocaleFlags = LocaleFlags.All; ulong fileHash = Hasher.ComputeHash(name); CASCFile.FileNames[fileHash] = name; RootData.Add(fileHash, entry); }
public WowRootHandler(BinaryReader stream, BackgroundWorkerEx worker) { worker?.ReportProgress(0, "Loading \"root\"..."); while (stream.BaseStream.Position < stream.BaseStream.Length) { int count = stream.ReadInt32(); ContentFlags contentFlags = (ContentFlags)stream.ReadUInt32(); LocaleFlags localeFlags = (LocaleFlags)stream.ReadUInt32(); if (localeFlags == LocaleFlags.None) { throw new Exception("block.LocaleFlags == LocaleFlags.None"); } if (contentFlags != ContentFlags.None && (contentFlags & (ContentFlags.F00000008 | ContentFlags.F00000010 | ContentFlags.LowViolence | ContentFlags.NoCompression | ContentFlags.F20000000)) == 0) { throw new Exception("block.ContentFlags != ContentFlags.None"); } RootEntry[] entries = new RootEntry[count]; int[] filedataIds = new int[count]; int fileDataIndex = 0; for (var i = 0; i < count; ++i) { entries[i].LocaleFlags = localeFlags; entries[i].ContentFlags = contentFlags; filedataIds[i] = fileDataIndex + stream.ReadInt32(); fileDataIndex = filedataIds[i] + 1; } //Console.WriteLine("Block: {0} {1} (size {2})", block.ContentFlags, block.LocaleFlags, count); for (var i = 0; i < count; ++i) { entries[i].MD5 = stream.Read <MD5Hash>(); ulong hash = stream.ReadUInt64(); RootData.Add(hash, entries[i]); //Console.WriteLine("File: {0:X8} {1:X16} {2}", entries[i].FileDataId, hash, entries[i].MD5.ToHexString()); int fileDataId = filedataIds[i]; if (FileDataStore.TryGetValue(fileDataId, out ulong hash2)) { if (hash2 == hash) { // duplicate, skipping continue; } else { Logger.WriteLine("ERROR: got miltiple hashes for filedataid {0}", fileDataId); continue; } } FileDataStore.Add(fileDataId, hash); FileDataStoreReverse.Add(hash, fileDataId); } worker?.ReportProgress((int)(stream.BaseStream.Position / (float)stream.BaseStream.Length * 100)); } }
private CASCHandler(CASCConfig config, CDNHandler cdn, BackgroundWorker worker) { this.config = config; this.cdn = cdn; if (!config.OnlineMode) { var idxFiles = GetIdxFiles(this.config.BasePath); if (idxFiles.Count == 0) throw new FileNotFoundException("idx files missing!"); if (worker != null) worker.ReportProgress(0); int idxIndex = 0; foreach (var idx in idxFiles) { using (var fs = new FileStream(idx, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) using (var br = new BinaryReader(fs)) { int h2Len = br.ReadInt32(); int h2Check = br.ReadInt32(); byte[] h2 = br.ReadBytes(h2Len); long padPos = (8 + h2Len + 0x0F) & 0xFFFFFFF0; fs.Position = padPos; int dataLen = br.ReadInt32(); int dataCheck = br.ReadInt32(); int numBlocks = dataLen / 18; for (int i = 0; i < numBlocks; i++) { IndexEntry info = new IndexEntry(); byte[] key = br.ReadBytes(9); int indexHigh = br.ReadByte(); int indexLow = br.ReadInt32BE(); info.Index = (int)((byte)(indexHigh << 2) | ((indexLow & 0xC0000000) >> 30)); info.Offset = (indexLow & 0x3FFFFFFF); info.Size = br.ReadInt32(); // duplicate keys wtf... //IndexData[key] = info; // use last key if (!LocalIndexData.ContainsKey(key)) // use first key LocalIndexData.Add(key, info); } padPos = (dataLen + 0x0FFF) & 0xFFFFF000; fs.Position = padPos; fs.Position += numBlocks * 18; //for (int i = 0; i < numBlocks; i++) //{ // var bytes = br.ReadBytes(18); // unknown data //} if (fs.Position != fs.Position) throw new Exception("idx file under read"); } if (worker != null) worker.ReportProgress((int)((float)++idxIndex / (float)idxFiles.Count * 100)); } Logger.WriteLine("CASCHandler: loaded {0} indexes", LocalIndexData.Count); } if (worker != null) worker.ReportProgress(0); using (var fs = OpenEncodingFile()) using (var br = new BinaryReader(fs)) { br.ReadBytes(2); // EN byte b1 = br.ReadByte(); byte b2 = br.ReadByte(); byte b3 = br.ReadByte(); ushort s1 = br.ReadUInt16(); ushort s2 = br.ReadUInt16(); int numEntries = br.ReadInt32BE(); int i1 = br.ReadInt32BE(); byte b4 = br.ReadByte(); int entriesOfs = br.ReadInt32BE(); fs.Position += entriesOfs; // skip strings fs.Position += numEntries * 32; //for (int i = 0; i < numEntries; ++i) //{ // br.ReadBytes(16); // br.ReadBytes(16); //} for (int i = 0; i < numEntries; ++i) { ushort keysCount; while ((keysCount = br.ReadUInt16()) != 0) { int fileSize = br.ReadInt32BE(); byte[] md5 = br.ReadBytes(16); var entry = new EncodingEntry(); entry.Size = fileSize; for (int ki = 0; ki < keysCount; ++ki) { byte[] key = br.ReadBytes(16); entry.Keys.Add(key); } //Encodings[md5] = entry; EncodingData.Add(md5, entry); } //br.ReadBytes(28); while (br.PeekChar() == 0) fs.Position++; if (worker != null) worker.ReportProgress((int)((float)fs.Position / (float)fs.Length * 100)); } //var pos = br.BaseStream.Position; //for (int i = 0; i < i1; ++i) //{ // br.ReadBytes(16); // br.ReadBytes(16); //} Logger.WriteLine("CASCHandler: loaded {0} encoding data", EncodingData.Count); } if (worker != null) worker.ReportProgress(0); using (var fs = OpenRootFile()) using (var br = new BinaryReader(fs)) { while (fs.Position < fs.Length) { int count = br.ReadInt32(); RootBlock block = new RootBlock(); block.Unk1 = br.ReadUInt32(); block.Flags = (LocaleFlags)br.ReadUInt32(); if (block.Flags == LocaleFlags.None) throw new Exception("block.Flags == LocaleFlags.None"); RootEntry[] entries = new RootEntry[count]; for (var i = 0; i < count; ++i) { entries[i] = new RootEntry(); entries[i].Block = block; entries[i].Unk1 = br.ReadInt32(); } for (var i = 0; i < count; ++i) { entries[i].MD5 = br.ReadBytes(16); ulong hash = br.ReadUInt64(); entries[i].Hash = hash; // don't load other locales //if (block.Flags != LocaleFlags.All && (block.Flags & LocaleFlags.enUS) == 0) // continue; if (!RootData.ContainsKey(hash)) { RootData[hash] = new List<RootEntry>(); RootData[hash].Add(entries[i]); } else RootData[hash].Add(entries[i]); } if (worker != null) worker.ReportProgress((int)((float)fs.Position / (float)fs.Length * 100)); } Logger.WriteLine("CASCHandler: loaded {0} root data", RootData.Count); } if (worker != null) worker.ReportProgress(0); }
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 CASCHandler(CASCFolder root, BackgroundWorker worker) { if (!OnlineMode) { var idxFiles = GetIdxFiles(Properties.Settings.Default.WowPath); if (idxFiles.Count == 0) { throw new FileNotFoundException("idx files missing!"); } worker.ReportProgress(0); int idxIndex = 0; foreach (var idx in idxFiles) { using (var fs = new FileStream(idx, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) using (var br = new BinaryReader(fs)) { int h2Len = br.ReadInt32(); int h2Check = br.ReadInt32(); byte[] h2 = br.ReadBytes(h2Len); long padPos = (8 + h2Len + 0x0F) & 0xFFFFFFF0; fs.Position = padPos; int dataLen = br.ReadInt32(); int dataCheck = br.ReadInt32(); int numBlocks = dataLen / 18; for (int i = 0; i < numBlocks; i++) { IndexEntry info = new IndexEntry(); byte[] key = br.ReadBytes(9); int indexHigh = br.ReadByte(); int indexLow = br.ReadInt32BE(); info.Index = (int)((byte)(indexHigh << 2) | ((indexLow & 0xC0000000) >> 30)); info.Offset = (indexLow & 0x3FFFFFFF); info.Size = br.ReadInt32(); // duplicate keys wtf... //IndexData[key] = info; // use last key if (!LocalIndexData.ContainsKey(key)) // use first key { LocalIndexData.Add(key, info); } } padPos = (dataLen + 0x0FFF) & 0xFFFFF000; fs.Position = padPos; fs.Position += numBlocks * 18; //for (int i = 0; i < numBlocks; i++) //{ // var bytes = br.ReadBytes(18); // unknown data //} if (fs.Position != fs.Position) { throw new Exception("idx file under read"); } } worker.ReportProgress((int)((float)++idxIndex / (float)idxFiles.Count * 100)); } Logger.WriteLine("CASCHandler: loaded {0} indexes", LocalIndexData.Count); } worker.ReportProgress(0); using (var fs = OpenEncodingFile()) using (var br = new BinaryReader(fs)) { br.ReadBytes(2); // EN byte b1 = br.ReadByte(); byte b2 = br.ReadByte(); byte b3 = br.ReadByte(); ushort s1 = br.ReadUInt16(); ushort s2 = br.ReadUInt16(); int numEntries = br.ReadInt32BE(); int i1 = br.ReadInt32BE(); byte b4 = br.ReadByte(); int entriesOfs = br.ReadInt32BE(); fs.Position += entriesOfs; // skip strings fs.Position += numEntries * 32; //for (int i = 0; i < numEntries; ++i) //{ // br.ReadBytes(16); // br.ReadBytes(16); //} for (int i = 0; i < numEntries; ++i) { ushort keysCount; while ((keysCount = br.ReadUInt16()) != 0) { int fileSize = br.ReadInt32BE(); byte[] md5 = br.ReadBytes(16); var entry = new EncodingEntry(); entry.Size = fileSize; for (int ki = 0; ki < keysCount; ++ki) { byte[] key = br.ReadBytes(16); entry.Keys.Add(key); } //Encodings[md5] = entry; EncodingData.Add(md5, entry); } //br.ReadBytes(28); while (br.PeekChar() == 0) { fs.Position++; } worker.ReportProgress((int)((float)fs.Position / (float)fs.Length * 100)); } //var pos = br.BaseStream.Position; //for (int i = 0; i < i1; ++i) //{ // br.ReadBytes(16); // br.ReadBytes(16); //} Logger.WriteLine("CASCHandler: loaded {0} encoding data", EncodingData.Count); } worker.ReportProgress(0); using (var fs = OpenRootFile()) using (var br = new BinaryReader(fs)) { while (fs.Position < fs.Length) { int count = br.ReadInt32(); RootBlock block = new RootBlock(); block.Unk1 = br.ReadUInt32(); block.Flags = (LocaleFlags)br.ReadUInt32(); if (block.Flags == LocaleFlags.None) { throw new Exception("block.Flags == LocaleFlags.None"); } RootEntry[] entries = new RootEntry[count]; for (var i = 0; i < count; ++i) { entries[i] = new RootEntry(); entries[i].Block = block; entries[i].Unk1 = br.ReadInt32(); } for (var i = 0; i < count; ++i) { entries[i].MD5 = br.ReadBytes(16); ulong hash = br.ReadUInt64(); entries[i].Hash = hash; // don't load other locales //if (block.Flags != LocaleFlags.All && (block.Flags & LocaleFlags.enUS) == 0) // continue; if (!RootData.ContainsKey(hash)) { RootData[hash] = new List <RootEntry>(); RootData[hash].Add(entries[i]); } else { RootData[hash].Add(entries[i]); } } worker.ReportProgress((int)((float)fs.Position / (float)fs.Length * 100)); } Logger.WriteLine("CASCHandler: loaded {0} root data", RootData.Count); } worker.ReportProgress(0); if (File.Exists(listFile)) { FolderNames[Hasher.ComputeHash("root")] = "root"; using (StreamReader sr = new StreamReader(listFile)) { string file; int filesCount = 0; CASCFolder folder = root; 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; } filesCount++; string[] parts = file.Split('\\'); for (int i = 0; i < parts.Length; ++i) { bool isFile = (i == parts.Length - 1); ulong hash = isFile ? fileHash : Hasher.ComputeHash(parts[i]); ICASCEntry entry = folder.GetEntry(hash); if (entry == null) { if (isFile) { entry = new CASCFile(hash); FileNames[hash] = file; } else { entry = new CASCFolder(hash); FolderNames[hash] = parts[i]; } folder.SubEntries[hash] = entry; if (isFile) { folder = root; break; } } folder = entry as CASCFolder; } if ((filesCount % 1000) == 0) { worker.ReportProgress((int)((float)sr.BaseStream.Position / (float)sr.BaseStream.Length * 100)); } } Logger.WriteLine("CASCHandler: loaded {0} file names", FileNames.Count); } } else { throw new FileNotFoundException("list file missing!"); } }
private CASCHandler(CASCConfig config, CDNHandler cdn, BackgroundWorker worker) { this.config = config; this.cdn = cdn; if (!config.OnlineMode) { var idxFiles = GetIdxFiles(this.config.BasePath); if (idxFiles.Count == 0) { throw new FileNotFoundException("idx files missing!"); } if (worker != null) { worker.ReportProgress(0); } int idxIndex = 0; foreach (var idx in idxFiles) { using (var fs = new FileStream(idx, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) using (var br = new BinaryReader(fs)) { int h2Len = br.ReadInt32(); int h2Check = br.ReadInt32(); byte[] h2 = br.ReadBytes(h2Len); long padPos = (8 + h2Len + 0x0F) & 0xFFFFFFF0; fs.Position = padPos; int dataLen = br.ReadInt32(); int dataCheck = br.ReadInt32(); int numBlocks = dataLen / 18; for (int i = 0; i < numBlocks; i++) { IndexEntry info = new IndexEntry(); byte[] key = br.ReadBytes(9); int indexHigh = br.ReadByte(); int indexLow = br.ReadInt32BE(); info.Index = (int)((byte)(indexHigh << 2) | ((indexLow & 0xC0000000) >> 30)); info.Offset = (indexLow & 0x3FFFFFFF); info.Size = br.ReadInt32(); // duplicate keys wtf... //IndexData[key] = info; // use last key if (!LocalIndexData.ContainsKey(key)) // use first key { LocalIndexData.Add(key, info); } } padPos = (dataLen + 0x0FFF) & 0xFFFFF000; fs.Position = padPos; fs.Position += numBlocks * 18; //for (int i = 0; i < numBlocks; i++) //{ // var bytes = br.ReadBytes(18); // unknown data //} if (fs.Position != fs.Position) { throw new Exception("idx file under read"); } } if (worker != null) { worker.ReportProgress((int)((float)++idxIndex / (float)idxFiles.Count * 100)); } } Logger.WriteLine("CASCHandler: loaded {0} indexes", LocalIndexData.Count); } if (worker != null) { worker.ReportProgress(0); } using (var fs = OpenEncodingFile()) using (var br = new BinaryReader(fs)) { br.ReadBytes(2); // EN byte b1 = br.ReadByte(); byte b2 = br.ReadByte(); byte b3 = br.ReadByte(); ushort s1 = br.ReadUInt16(); ushort s2 = br.ReadUInt16(); int numEntries = br.ReadInt32BE(); int i1 = br.ReadInt32BE(); byte b4 = br.ReadByte(); int entriesOfs = br.ReadInt32BE(); fs.Position += entriesOfs; // skip strings fs.Position += numEntries * 32; //for (int i = 0; i < numEntries; ++i) //{ // br.ReadBytes(16); // br.ReadBytes(16); //} for (int i = 0; i < numEntries; ++i) { ushort keysCount; while ((keysCount = br.ReadUInt16()) != 0) { int fileSize = br.ReadInt32BE(); byte[] md5 = br.ReadBytes(16); var entry = new EncodingEntry(); entry.Size = fileSize; for (int ki = 0; ki < keysCount; ++ki) { byte[] key = br.ReadBytes(16); entry.Keys.Add(key); } //Encodings[md5] = entry; EncodingData.Add(md5, entry); } //br.ReadBytes(28); while (br.PeekChar() == 0) { fs.Position++; } if (worker != null) { worker.ReportProgress((int)((float)fs.Position / (float)fs.Length * 100)); } } //var pos = br.BaseStream.Position; //for (int i = 0; i < i1; ++i) //{ // br.ReadBytes(16); // br.ReadBytes(16); //} Logger.WriteLine("CASCHandler: loaded {0} encoding data", EncodingData.Count); } if (worker != null) { worker.ReportProgress(0); } using (var fs = OpenRootFile()) using (var br = new BinaryReader(fs)) { while (fs.Position < fs.Length) { int count = br.ReadInt32(); RootBlock block = new RootBlock(); block.Unk1 = br.ReadUInt32(); block.Flags = (LocaleFlags)br.ReadUInt32(); if (block.Flags == LocaleFlags.None) { throw new Exception("block.Flags == LocaleFlags.None"); } RootEntry[] entries = new RootEntry[count]; for (var i = 0; i < count; ++i) { entries[i] = new RootEntry(); entries[i].Block = block; entries[i].Unk1 = br.ReadInt32(); } for (var i = 0; i < count; ++i) { entries[i].MD5 = br.ReadBytes(16); ulong hash = br.ReadUInt64(); entries[i].Hash = hash; // don't load other locales //if (block.Flags != LocaleFlags.All && (block.Flags & LocaleFlags.enUS) == 0) // continue; if (!RootData.ContainsKey(hash)) { RootData[hash] = new List <RootEntry>(); RootData[hash].Add(entries[i]); } else { RootData[hash].Add(entries[i]); } } if (worker != null) { worker.ReportProgress((int)((float)fs.Position / (float)fs.Length * 100)); } } Logger.WriteLine("CASCHandler: loaded {0} root data", RootData.Count); } if (worker != null) { worker.ReportProgress(0); } }
public CASCHandler(CASCFolder root, BackgroundWorker worker) { if (!OnlineMode) { var idxFiles = GetIdxFiles(Properties.Settings.Default.WowPath); if (idxFiles.Count == 0) throw new FileNotFoundException("idx files missing!"); worker.ReportProgress(0); int idxIndex = 0; foreach (var idx in idxFiles) { using (var fs = new FileStream(idx, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) using (var br = new BinaryReader(fs)) { int h2Len = br.ReadInt32(); int h2Check = br.ReadInt32(); byte[] h2 = br.ReadBytes(h2Len); long padPos = (8 + h2Len + 0x0F) & 0xFFFFFFF0; fs.Position = padPos; int dataLen = br.ReadInt32(); int dataCheck = br.ReadInt32(); int numBlocks = dataLen / 18; for (int i = 0; i < numBlocks; i++) { IndexEntry info = new IndexEntry(); byte[] key = br.ReadBytes(9); int indexHigh = br.ReadByte(); int indexLow = br.ReadInt32BE(); info.Index = (int)((byte)(indexHigh << 2) | ((indexLow & 0xC0000000) >> 30)); info.Offset = (indexLow & 0x3FFFFFFF); info.Size = br.ReadInt32(); // duplicate keys wtf... //IndexData[key] = info; // use last key if (!LocalIndexData.ContainsKey(key)) // use first key LocalIndexData.Add(key, info); } padPos = (dataLen + 0x0FFF) & 0xFFFFF000; fs.Position = padPos; fs.Position += numBlocks * 18; //for (int i = 0; i < numBlocks; i++) //{ // var bytes = br.ReadBytes(18); // unknown data //} if (fs.Position != fs.Position) throw new Exception("idx file under read"); } worker.ReportProgress((int)((float)++idxIndex / (float)idxFiles.Count * 100)); } Logger.WriteLine("CASCHandler: loaded {0} indexes", LocalIndexData.Count); } worker.ReportProgress(0); using (var fs = OpenEncodingFile()) using (var br = new BinaryReader(fs)) { br.ReadBytes(2); // EN byte b1 = br.ReadByte(); byte b2 = br.ReadByte(); byte b3 = br.ReadByte(); ushort s1 = br.ReadUInt16(); ushort s2 = br.ReadUInt16(); int numEntries = br.ReadInt32BE(); int i1 = br.ReadInt32BE(); byte b4 = br.ReadByte(); int entriesOfs = br.ReadInt32BE(); fs.Position += entriesOfs; // skip strings fs.Position += numEntries * 32; //for (int i = 0; i < numEntries; ++i) //{ // br.ReadBytes(16); // br.ReadBytes(16); //} for (int i = 0; i < numEntries; ++i) { ushort keysCount; while ((keysCount = br.ReadUInt16()) != 0) { int fileSize = br.ReadInt32BE(); byte[] md5 = br.ReadBytes(16); var entry = new EncodingEntry(); entry.Size = fileSize; for (int ki = 0; ki < keysCount; ++ki) { byte[] key = br.ReadBytes(16); entry.Keys.Add(key); } //Encodings[md5] = entry; EncodingData.Add(md5, entry); } //br.ReadBytes(28); while (br.PeekChar() == 0) fs.Position++; worker.ReportProgress((int)((float)fs.Position / (float)fs.Length * 100)); } //var pos = br.BaseStream.Position; //for (int i = 0; i < i1; ++i) //{ // br.ReadBytes(16); // br.ReadBytes(16); //} Logger.WriteLine("CASCHandler: loaded {0} encoding data", EncodingData.Count); } worker.ReportProgress(0); using (var fs = OpenRootFile()) using (var br = new BinaryReader(fs)) { while (fs.Position < fs.Length) { int count = br.ReadInt32(); RootBlock block = new RootBlock(); block.Unk1 = br.ReadUInt32(); block.Flags = (LocaleFlags)br.ReadUInt32(); if (block.Flags == LocaleFlags.None) throw new Exception("block.Flags == LocaleFlags.None"); RootEntry[] entries = new RootEntry[count]; for (var i = 0; i < count; ++i) { entries[i] = new RootEntry(); entries[i].Block = block; entries[i].Unk1 = br.ReadInt32(); } for (var i = 0; i < count; ++i) { entries[i].MD5 = br.ReadBytes(16); ulong hash = br.ReadUInt64(); entries[i].Hash = hash; // don't load other locales //if (block.Flags != LocaleFlags.All && (block.Flags & LocaleFlags.enUS) == 0) // continue; if (!RootData.ContainsKey(hash)) { RootData[hash] = new List<RootEntry>(); RootData[hash].Add(entries[i]); } else RootData[hash].Add(entries[i]); } worker.ReportProgress((int)((float)fs.Position / (float)fs.Length * 100)); } Logger.WriteLine("CASCHandler: loaded {0} root data", RootData.Count); } worker.ReportProgress(0); if (File.Exists(listFile)) { FolderNames[Hasher.ComputeHash("root")] = "root"; using (StreamReader sr = new StreamReader(listFile)) { string file; int filesCount = 0; CASCFolder folder = root; 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; } filesCount++; string[] parts = file.Split('\\'); for (int i = 0; i < parts.Length; ++i) { bool isFile = (i == parts.Length - 1); ulong hash = isFile ? fileHash : Hasher.ComputeHash(parts[i]); ICASCEntry entry = folder.GetEntry(hash); if (entry == null) { if (isFile) { entry = new CASCFile(hash); FileNames[hash] = file; } else { entry = new CASCFolder(hash); FolderNames[hash] = parts[i]; } folder.SubEntries[hash] = entry; if (isFile) { folder = root; break; } } folder = entry as CASCFolder; } if ((filesCount % 1000) == 0) worker.ReportProgress((int)((float)sr.BaseStream.Position / (float)sr.BaseStream.Length * 100)); } Logger.WriteLine("CASCHandler: loaded {0} file names", FileNames.Count); } } else { throw new FileNotFoundException("list file missing!"); } }