private void ParseIndex(Stream stream, int i) { using (var br = new BinaryReader(stream)) { stream.Seek(-12, SeekOrigin.End); int count = br.ReadInt32(); stream.Seek(0, SeekOrigin.Begin); if (count * (16 + 4 + 4) > stream.Length) throw new Exception("ParseIndex failed"); for (int j = 0; j < count; ++j) { byte[] key = br.ReadBytes(16); if (key.IsZeroed()) // wtf? key = br.ReadBytes(16); if (key.IsZeroed()) // wtf? throw new Exception("key.IsZeroed()"); IndexEntry entry = new IndexEntry(); entry.Index = i; entry.Size = br.ReadInt32BE(); entry.Offset = br.ReadInt32BE(); CDNIndexData.Add(key, entry); } } }
protected Stream OpenFileOnlineInternal(IndexEntry idxInfo, MD5Hash key) { if (idxInfo != null) { Stream s = CDNIndex.OpenDataFile(idxInfo); return new BLTEStream(s, key); } else { Stream s = CDNIndex.OpenDataFileDirect(key); return new BLTEStream(s, key); } }
private void ParseIndex(string idx) { 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); byte indexHigh = br.ReadByte(); int indexLow = br.ReadInt32BE(); info.Index = (indexHigh << 2 | (byte)((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.Length) // throw new Exception("idx file under read"); } }
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); }
private unsafe void ParseIndex(string idx) { 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; //byte[] buf = new byte[8]; for (int i = 0; i < numBlocks; i++) { IndexEntry info = new IndexEntry(); byte[] keyBytes = br.ReadBytes(9); Array.Resize(ref keyBytes, 16); MD5Hash key; fixed (byte *ptr = keyBytes) key = *(MD5Hash*)ptr; byte indexHigh = br.ReadByte(); int indexLow = br.ReadInt32BE(); info.Index = (indexHigh << 2 | (byte)((indexLow & 0xC0000000) >> 30)); info.Offset = (indexLow & 0x3FFFFFFF); //for (int j = 3; j < 8; j++) // buf[7 - j] = br.ReadByte(); //long val = BitConverter.ToInt64(buf, 0); //info.Index = (int)(val / 0x40000000); //info.Offset = (int)(val % 0x40000000); 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.Length) // throw new Exception("idx file under read"); } }
public Stream OpenDataFile(IndexEntry entry) { var archive = config.Archives[entry.Index]; string file = config.CDNPath + "/data/" + archive.Substring(0, 2) + "/" + archive.Substring(2, 2) + "/" + archive; string url = "http://" + config.CDNHost + "/" + file; Stream stream = Cache.OpenFile(file, url, true); if (stream != null) { stream.Position = entry.Offset; MemoryStream ms = new MemoryStream(entry.Size); stream.CopyBytes(ms, entry.Size); ms.Position = 0; return ms; } //using (HttpClient client = new HttpClient()) //{ // client.DefaultRequestHeaders.Range = new RangeHeaderValue(entry.Offset, entry.Offset + entry.Size - 1); // var resp = client.GetStreamAsync(url).Result; // MemoryStream ms = new MemoryStream(entry.Size); // resp.CopyBytes(ms, entry.Size); // ms.Position = 0; // return ms; //} HttpWebRequest req = WebRequest.CreateHttp(url); //req.Headers[HttpRequestHeader.Range] = string.Format("bytes={0}-{1}", entry.Offset, entry.Offset + entry.Size - 1); req.AddRange(entry.Offset, entry.Offset + entry.Size - 1); using (HttpWebResponse resp = (HttpWebResponse)req.GetResponseAsync().Result) { MemoryStream ms = new MemoryStream(entry.Size); resp.GetResponseStream().CopyBytes(ms, entry.Size); ms.Position = 0; return ms; } }
public Stream OpenDataFile(IndexEntry entry) { var archive = CASCConfig.Archives[entry.Index]; string file = CASCConfig.CDNPath + "/data/" + archive.Substring(0, 2) + "/" + archive.Substring(2, 2) + "/" + archive; string url = "http://" + CASCConfig.CDNHost + "/" + file; Stream stream = Cache.OpenFile(file, url, true); if (stream != null) { stream.Position = entry.Offset; MemoryStream ms = new MemoryStream(entry.Size); stream.CopyBytes(ms, entry.Size); ms.Position = 0; return ms; } HttpWebRequest req = WebRequest.CreateHttp(url); req.AddRange(entry.Offset, entry.Offset + entry.Size - 1); using (HttpWebResponse resp = (HttpWebResponse)req.GetResponse()) { MemoryStream ms = new MemoryStream(entry.Size); resp.GetResponseStream().CopyBytes(ms, entry.Size); ms.Position = 0; return ms; } }
protected Stream GetLocalDataStreamInternal(IndexEntry idxInfo, MD5Hash key) { if (idxInfo == null) throw new Exception("local index missing"); Stream dataStream = GetDataStream(idxInfo.Index); dataStream.Position = idxInfo.Offset; using (BinaryReader reader = new BinaryReader(dataStream, Encoding.ASCII, true)) { byte[] md5 = reader.ReadBytes(16); Array.Reverse(md5); if (!key.EqualsTo(md5)) throw new Exception("local data corrupted"); int size = reader.ReadInt32(); if (size != idxInfo.Size) throw new Exception("local data corrupted"); //byte[] unkData1 = reader.ReadBytes(2); //byte[] unkData2 = reader.ReadBytes(8); dataStream.Position += 10; byte[] data = reader.ReadBytes(idxInfo.Size - 30); return new MemoryStream(data); } }
protected void ExtractFileOnlineInternal(IndexEntry idxInfo, MD5Hash key, string path, string name) { if (idxInfo != null) { using (Stream s = CDNIndex.OpenDataFile(idxInfo)) using (BLTEStream blte = new BLTEStream(s, key)) { blte.ExtractToFile(path, name); } } else { using (Stream s = CDNIndex.OpenDataFileDirect(key)) using (BLTEStream blte = new BLTEStream(s, key)) { blte.ExtractToFile(path, name); } } }
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!"); } }