public DownloadHandler(BLTEStream blte) { if (CASContainer.BuildConfig["download-size"][0] != null && blte.Length != long.Parse(CASContainer.BuildConfig["download-size"][0])) { CASContainer.Settings?.Logger.LogAndThrow(Logging.LogType.Critical, "Download File is corrupt."); } using (var br = new BinaryReader(blte)) { Header = new DownloadHeader() { Header = br.ReadBytes(2), Version = br.ReadByte(), ChecksumSize = br.ReadByte(), Unknown = br.ReadByte(), NumEntries = br.ReadUInt32BE(), NumTags = br.ReadUInt16BE(), }; // entries for (int i = 0; i < Header.NumEntries; i++) { var entry = new DownloadEntry() { Unknown = Header.Version > 1 ? br.ReadByte() : (byte)0, // new V2 field Hash = new MD5Hash(br), FileSize = br.ReadUInt40BE(), Stage = br.ReadByte(), UnknownData = br.ReadBytes(4) }; Entries.Add(entry); } // tags int numMaskBytes = ((int)Header.NumEntries + 7) / 8; for (int i = 0; i < Header.NumTags; i++) { var tag = new DownloadTag() { Name = br.ReadCString(), Type = br.ReadUInt16BE(), BitMask = new BoolArray(br.ReadBytes(numMaskBytes)) }; Tags.Add(tag); } EncodingMap = blte.EncodingMap.ToArray(); endofStageIndex = new int[] // store last indice of each stage { Entries.FindLastIndex(x => x.Stage == 0), Entries.FindLastIndex(x => x.Stage == 1) }; } blte?.Dispose(); }
public InstallHandler(BLTEStream blte) { if (CASContainer.BuildConfig["install-size"][0] != null && blte.Length != long.Parse(CASContainer.BuildConfig["install-size"][0])) { CASContainer.Settings?.Logger.LogAndThrow(Logging.LogType.Critical, "Install File is corrupt."); } BinaryReader stream = new BinaryReader(blte); Header = new InstallHeader() { Magic = stream.ReadBytes(2), Version = stream.ReadByte(), HashSize = stream.ReadByte(), NumTags = stream.ReadUInt16BE(), NumEntries = stream.ReadUInt32BE() }; // tags int numMaskBytes = (int)(Header.NumEntries + 7) / 8; for (int i = 0; i < Header.NumTags; i++) { InstallTag tag = new InstallTag() { Name = stream.ReadCString(), Type = stream.ReadUInt16BE(), BitMask = new BoolArray(stream.ReadBytes(numMaskBytes)) }; // We need to remove trailing bits from the padded byte array. while (tag.BitMask.Count != Header.NumEntries) { tag.BitMask.RemoveAt(tag.BitMask.Count - 1); } Tags.Add(tag); } // entries for (int i = 0; i < Header.NumEntries; i++) { InstallEntry entry = new InstallEntry() { Name = stream.ReadCString(), CEKey = new MD5Hash(stream), Size = stream.ReadUInt32BE() }; InstallData.Add(entry); } EncodingMap = blte.EncodingMap.ToArray(); stream?.Dispose(); blte?.Dispose(); }
public static void CompareIdx(string[] args) { string otherVerNum = args[2]; HashSet <ulong> missingKeys = new HashSet <ulong>(); Directory.CreateDirectory(RawIdxDir); Directory.CreateDirectory(ConvertIdxDir); string[] otherHashes; using (StreamReader reader = new StreamReader($"{otherVerNum}.idxhashes")) { otherHashes = reader.ReadToEnd().Split('\n').Select(x => x.TrimEnd('\r')).ToArray(); } MD5Hash md5Obj = new MD5Hash(); foreach (KeyValuePair <MD5Hash, IndexEntry> indexEntry in CASC.LocalIndex.Indices) { string md5 = indexEntry.Key.ToHexString(); if (!otherHashes.Contains(md5)) { try { Stream rawStream = CASC.LocalIndex.OpenIndexInfo(indexEntry.Value, md5Obj, false); Stream stream = new BLTEStream(rawStream, md5Obj); TryConvertFile(stream, ConvertIdxDir, md5); //stream.Position = 0; //using (Stream file = File.OpenWrite(Path.Combine(RawIdxDir, md5))) { // stream.CopyTo(file); //} rawStream.Dispose(); stream.Dispose(); } catch (Exception e) { if (e is BLTEKeyException exception) { if (missingKeys.Add(exception.MissingKey)) { Console.Out.WriteLine($"Missing key: {exception.MissingKey:X16}"); } } //else { // Console.Out.WriteLine(e); //} } } } Console.Write("done"); Console.ReadLine(); }
public static void Patch(string file, string host) { CASContainer.Logger.LogInformation($"Patching {Path.GetFileName(file)}"); BLTEStream stream = OpenFile(file); if (stream == null) { return; } string outpath = Path.Combine(CASContainer.Settings.OutputPath, Helper.GetCDNPath(Path.GetFileName(file), "data")); using (var fs = new FileStream(outpath, FileMode.Create, FileAccess.Write, FileShare.Read)) using (var bw = new BinaryWriter(fs)) { stream.CopyTo(fs); stream.Position = 0; byte[] content = new byte[stream.Length]; stream.Read(content, 0, content.Length); var patches = BuildPatches(Encoding.UTF8.GetString(content), host); foreach (var patch in patches) { long offset = SearchPattern(content, patch.Key); if (offset >= 0) { fs.Position = offset; bw.Write(patch.Value); } } fs.Position = 0; fs.Flush(); } stream?.Dispose(); }
public EncodingHandler(BLTEStream blte) { if (blte.Length != long.Parse(CASContainer.BuildConfig["encoding-size"][0])) { CASContainer.Settings?.Logger.LogAndThrow(Logging.LogType.Critical, "Encoding File is corrupt."); } BinaryReader stream = new BinaryReader(blte); Header = new EncodingHeader() { Magic = stream.ReadBytes(2), Version = stream.ReadByte(), ChecksumSizeC = stream.ReadByte(), ChecksumSizeE = stream.ReadByte(), PageSizeCEKey = stream.ReadUInt16(), PageSizeEKey = stream.ReadUInt16(), PageCountCEKey = stream.ReadUInt32BE(), PageCountEKey = stream.ReadUInt32BE(), Unknown_x11 = stream.ReadByte(), ESpecBlockSize = stream.ReadUInt32BE() }; // ESpec string table ESpecStringTable.AddRange(Encoding.ASCII.GetString(stream.ReadBytes((int)Header.ESpecBlockSize)).Split('\0')); // skip CE page table lookup stream.ReadBytes((int)Header.PageCountCEKey * 32); // read CE page table data for (int i = 0; i < Header.PageCountCEKey; i++) { long start = stream.BaseStream.Position; ushort keysCount; while ((keysCount = stream.ReadUInt16()) != 0) { var entry = new EncodingCEKeyPageTable() { DecompressedSize = stream.ReadUInt32BE(), CKey = new MD5Hash(stream) }; for (int ki = 0; ki < keysCount; ki++) { entry.EKeys.Add(new MD5Hash(stream)); } CEKeys.Add(entry.CKey, entry); } if (stream.BaseStream.Position % CHUNK_SIZE != 0) { stream.BaseStream.Position += CHUNK_SIZE - ((stream.BaseStream.Position - start) % CHUNK_SIZE); } } // skip EKey page table lookup stream.ReadBytes((int)Header.PageCountEKey * 32); // read EKey page table data for (int i = 0; i < Header.PageCountEKey; i++) { long start = stream.BaseStream.Position; MD5Hash hash; while (!(hash = new MD5Hash(stream)).IsEmpty) { var entry = new EncodingEKeyPageTable() { EKey = hash, ESpecStringIndex = stream.ReadUInt32BE(), FileSize = stream.ReadUInt40BE() }; EKeys.Add(entry.EKey, entry); } if (stream.BaseStream.Position % CHUNK_SIZE != 0) { stream.BaseStream.Position += CHUNK_SIZE - ((stream.BaseStream.Position - start) % CHUNK_SIZE); } } // Encoding file ESpecStringTable stream.ReadBytes((int)(stream.BaseStream.Length - stream.BaseStream.Position)); EncodingMap = blte.EncodingMap.ToArray(); blte?.Dispose(); stream?.Dispose(); }
public DownloadHandler(BLTEStream blte) { if (CASContainer.BuildConfig["download-size"][0] != null && blte.Length != long.Parse(CASContainer.BuildConfig["download-size"][0])) { CASContainer.Settings?.Logger.LogAndThrow(Logging.LogType.Critical, "Download File is corrupt."); } using (var br = new BinaryReader(blte)) { Header = new DownloadHeader() { Header = br.ReadBytes(2), Version = br.ReadByte(), ChecksumSize = br.ReadByte(), HasChecksum = br.ReadByte(), NumEntries = br.ReadUInt32BE(), NumTags = br.ReadUInt16BE(), }; if (Header.Version >= 2) { Header.NumFlags = br.ReadByte(); } if (Header.Version >= 3) { // TODO do we have a version 3 file to test with? //Header.BasePriority = br.ReadByte(); //Header.Unknown_0D = br.ReadBytes(3); throw new NotImplementedException("Download file versions newer than 2 are not supported."); } // entries for (int i = 0; i < Header.NumEntries; i++) { var entry = new DownloadEntry() { EKey = new MD5Hash(br), FileSize = br.ReadUInt40BE(), Priority = br.ReadByte() }; if (Header.HasChecksum != 0) { entry.Checksum = br.ReadUInt32BE(); } if (Header.Version >= 2) { entry.Flags = (DownloadFlags[])(object)br.ReadBytes(Header.NumFlags); } Entries.Add(entry); } // tags int numMaskBytes = ((int)Header.NumEntries + 7) / 8; for (int i = 0; i < Header.NumTags; i++) { var tag = new DownloadTag() { Name = br.ReadCString(), Type = br.ReadUInt16BE(), BitMask = new BoolArray(br.ReadBytes(numMaskBytes)) }; // We need to remove trailing bits from the padded byte array. while (tag.BitMask.Count != Entries.Count) { tag.BitMask.RemoveAt(tag.BitMask.Count - 1); } Tags.Add(tag); } EncodingMap = blte.EncodingMap.ToArray(); endofStageIndex = new int[] // store last indice of each stage { Entries.FindLastIndex(x => x.Priority == 0), Entries.FindLastIndex(x => x.Priority == 1) }; } blte?.Dispose(); }
public EncodingHandler(BLTEStream blte) { if (blte.Length != long.Parse(CASContainer.BuildConfig["encoding-size"][0])) { CASContainer.Settings?.Logger.LogAndThrow(Logging.LogType.Critical, "Encoding File is corrupt."); } BinaryReader stream = new BinaryReader(blte); Header = new EncodingHeader() { Magic = stream.ReadBytes(2), Version = stream.ReadByte(), ChecksumSizeA = stream.ReadByte(), ChecksumSizeB = stream.ReadByte(), FlagsA = stream.ReadUInt16(), FlagsB = stream.ReadUInt16(), NumEntriesA = stream.ReadUInt32BE(), NumEntriesB = stream.ReadUInt32BE(), StringBlockSize = stream.ReadUInt40BE() }; // stringTableA LayoutStringTable.AddRange(Encoding.ASCII.GetString(stream.ReadBytes((int)Header.StringBlockSize)).Split('\0')); // skip header block A stream.ReadBytes((int)Header.NumEntriesA * 32); // encoding table entry block for (int i = 0; i < Header.NumEntriesA; i++) { long start = stream.BaseStream.Position; ushort keysCount; while ((keysCount = stream.ReadUInt16()) != 0) { EncodingEntry entry = new EncodingEntry() { DecompressedSize = stream.ReadUInt32BE(), Hash = new MD5Hash(stream) }; for (int ki = 0; ki < keysCount; ki++) { entry.Keys.Add(new MD5Hash(stream)); } Data.Add(entry.Hash, entry); } if (stream.BaseStream.Position % CHUNK_SIZE != 0) { stream.BaseStream.Position += CHUNK_SIZE - ((stream.BaseStream.Position - start) % CHUNK_SIZE); } } // skip header block B stream.ReadBytes((int)Header.NumEntriesB * 32); // layout table entry block for (int i = 0; i < Header.NumEntriesB; i++) { long start = stream.BaseStream.Position; MD5Hash hash; while (!(hash = new MD5Hash(stream)).IsEmpty) { var entry = new EncodingLayout() { Hash = hash, StringIndex = stream.ReadUInt32BE(), Size = stream.ReadUInt40BE() }; Layout.Add(entry.Hash, entry); } if (stream.BaseStream.Position % CHUNK_SIZE != 0) { stream.BaseStream.Position += CHUNK_SIZE - ((stream.BaseStream.Position - start) % CHUNK_SIZE); } } stream.ReadBytes((int)(stream.BaseStream.Length - stream.BaseStream.Position)); //EncodingStringTable EncodingMap = blte.EncodingMap.ToArray(); blte?.Dispose(); stream?.Dispose(); }