public void LoadEntries(DataFile file, IndexEntry indexEntry) { var blteEntry = new BinaryReader(DataFile.LoadBLTEEntry(indexEntry, file.readStream)); blteEntry.BaseStream.Position = 9; var entries = blteEntry.ReadBEUInt32(); blteEntry.BaseStream.Position += 5; var offsetEntries = blteEntry.ReadBEUInt32(); blteEntry.BaseStream.Position += offsetEntries + (entries << 5); for (var i = 0; i < entries; i++) { var keys = blteEntry.ReadUInt16(); while (keys != 0) { var encodingEntry = new EncodingEntry { Keys = new byte[keys][], Size = blteEntry.ReadBEUInt32() }; var md5 = blteEntry.ReadBytes(16); for (var j = 0; j < keys; j++) { encodingEntry.Keys[j] = blteEntry.ReadBytes(16); } this.entries.Add(md5, encodingEntry); keys = blteEntry.ReadUInt16(); } while (blteEntry.ReadByte() == 0) { ; } blteEntry.BaseStream.Position -= 1; } }
public CASCHandler(string basePath) { BasePath = basePath; lookup3 = new Lookup3(); InitConfigKeys(); // Get idx files. for (var i = 0; i <= 0xF; i++) { // Always get the last element in sequence for latest file data. var idxFile = Directory.GetFiles(BasePath + "/Data/data", $"{i :x2}*.idx").Last(); idxFiles.Add(new IndexFile(idxFile)); } // Get CDN indices. var indices = cdnConfig["archives"]; for (var i = 0; i < indices.Length; i++) { indexFiles.Add(indices[i]); idxFiles.Add(new IndexFile($"{basePath}/Data/indices/{indices[i]}.index", true, (ushort)i)); } // Get available data.### files. Parallel.ForEach(Directory.GetFiles(BasePath + "/Data/data", "data.*"), f => { var dataFile = new DataFile(File.OpenRead(f)); var index = Convert.ToUInt32(Path.GetExtension(f).Remove(0, 1)); dataFiles.TryAdd(index, dataFile); }); // Get encoding key. var encodingKey = buildConfig["encoding"][1]; if (encodingKey.Length / 2 > 16) { throw new InvalidOperationException("Encoding key too long"); } else if (encodingKey.Length / 2 < 16) { throw new InvalidOperationException("Encoding key too short"); } encodingFile = new EncodingFile(encodingKey.ToByteArray()); // Get idx file & entry which contains the encoding key (first 9 bytes) idxFiles.ForEach(idx => { var idxEntry = idx[encodingFile.Key]; if (idxEntry.Size != 0) { encodingFile.LoadEntries(dataFiles[idxEntry.Index], idxEntry); } }); // Get root key var rootKey = buildConfig["root"][0]; if (rootKey.Length / 2 > 16) { throw new InvalidOperationException("Root key too long"); } else if (rootKey.Length / 2 < 16) { throw new InvalidOperationException("Root key too short"); } rootFile = new RootFile(); idxFiles.ForEach(idx => { var encodingEntry = encodingFile[rootKey.ToByteArray()]; if (encodingEntry.Size != 0 && encodingEntry.Keys.Length > 0) { var idxEntry = idx[encodingEntry.Keys[0].Slice(0, 9)]; if (idxEntry.Size != 0) { rootFile.LoadEntries(dataFiles[idxEntry.Index], idxEntry); } } }); }
public IEnumerable <Tuple <ulong, MemoryStream> > ReadFile(Locales locales = Locales.enUS) { foreach (var entry in rootFile.Entries) { var rootEntries = rootFile[entry.Key]; for (var i = 0; i < rootEntries.Length; i++) { if ((rootEntries[i].Locales & locales) == locales) { var encodingEntry = encodingFile[rootEntries[i].MD5]; if (encodingEntry.Size != 0 && encodingEntry.Keys.Length > 0) { MemoryStream blteStream = null; for (var j = 0; j < 0x10; j++) { IndexEntry idxEntry = default(IndexEntry); foreach (var k in encodingEntry.Keys) { if ((idxEntry = idxFiles[j][k.Slice(0, 9)]).Size != 0) { var dataFile = dataFiles[idxEntry.Index]; if (dataFile == null) { throw new InvalidOperationException("Invalid data file."); } yield return(Tuple.Create(entry.Key, blteStream = DataFile.LoadBLTEEntry(idxEntry, dataFile.readStream))); } } if (idxEntry.Size != 0) { break; } } if (blteStream == null) { for (var j = 0x10; j < idxFiles.Count; j++) { IndexEntry idxEntry = default(IndexEntry); foreach (var k in encodingEntry.Keys) { if ((idxEntry = idxFiles[j][k]).Size != 0) { yield return(Tuple.Create(entry.Key, DataFile.LoadBLTEEntry(idxEntry, cdnConfig.DownloadFile(indexFiles[idxEntry.Index], idxEntry)))); } } if (idxEntry.Size != 0) { break; } } } } } } } //return null; }
public ConcurrentDictionary <ulong, MemoryStream> ReadFiles(byte[] signature, Locales locales = Locales.enUS) { var files = new ConcurrentDictionary <ulong, MemoryStream>(); foreach (var entry in rootFile.Entries) { var rootEntries = rootFile[entry.Key]; for (var i = 0; i < rootEntries.Length; i++) { if ((rootEntries[i].Locales & locales) == locales) { var encodingEntry = encodingFile[rootEntries[i].MD5]; if (encodingEntry.Size != 0 && encodingEntry.Keys.Length > 0) { for (var j = 0; j < 0x10; j++) { IndexEntry idxEntry = default(IndexEntry); foreach (var k in encodingEntry.Keys) { if ((idxEntry = idxFiles[j][k.Slice(0, 9)]).Size != 0) { var dataFile = dataFiles[idxEntry.Index]; if (dataFile == null) { throw new InvalidOperationException("Invalid data file."); } var sigBuffer = new byte[signature.Length]; var stream = DataFile.LoadBLTEEntry(idxEntry, dataFile.readStream); stream?.Read(sigBuffer, 0, sigBuffer.Length); if (sigBuffer.Compare(signature)) { files.TryAdd(entry.Key, stream); } } } if (idxEntry.Size != 0) { break; } } for (var j = 0x10; j < idxFiles.Count; j++) { IndexEntry idxEntry = default(IndexEntry); foreach (var k in encodingEntry.Keys) { if ((idxEntry = idxFiles[j][k]).Size != 0) { var sigBuffer = new byte[signature.Length]; var stream = DataFile.LoadBLTEEntry(idxEntry, cdnConfig.DownloadFile(indexFiles[idxEntry.Index], idxEntry)); stream?.Read(sigBuffer, 0, sigBuffer.Length); if (sigBuffer.Compare(signature)) { files.TryAdd(entry.Key, stream); } } } if (idxEntry.Size != 0) { break; } } } } } } return(files); }
public MemoryStream ReadFile(RootEntry[] rootEntries, Locales locales = Locales.enUS) { for (var i = 0; i < rootEntries.Length; i++) { if ((rootEntries[i].Locales & locales) == locales) { var encodingEntry = encodingFile[rootEntries[i].MD5]; if (encodingEntry.Size != 0 && encodingEntry.Keys.Length > 0) { for (var j = 0; j < 0x10; j++) { IndexEntry idxEntry = default(IndexEntry); foreach (var k in encodingEntry.Keys) { if ((idxEntry = idxFiles[j][k.Slice(0, 9)]).Size != 0) { var dataFile = dataFiles[idxEntry.Index]; if (dataFile == null) { throw new InvalidOperationException("Invalid data file."); } var ret = DataFile.LoadBLTEEntry(idxEntry, dataFile.readStream); if (ret == null) { break; } return(ret); } } if (idxEntry.Size != 0) { break; } } // CDN indices for (var j = 0x10; j < idxFiles.Count; j++) { IndexEntry idxEntry = default(IndexEntry); foreach (var k in encodingEntry.Keys) { if ((idxEntry = idxFiles[j][k]).Size != 0) { return(DataFile.LoadBLTEEntry(idxEntry, cdnConfig.DownloadFile(indexFiles[idxEntry.Index], idxEntry))); } } if (idxEntry.Size != 0) { break; } } } } } return(null); }