private void LoadPackage(int i, ClientHandler client, ContentManifestFile cmf) { var entry = m_packageEntries[i]; using (Stream packageStream = cmf.OpenFile(client, entry.m_packageGUID) !) using (BinaryReader packageReader = new BinaryReader(packageStream)) { var package = packageReader.Read <PackageHeader>(); m_packages[i] = package; if (package.m_recordCount == 0) { m_packageRecords[i] = new PackageRecord[0]; return; } if (package.m_bundleCount > 0) { packageStream.Position = package.m_offsetBundles; m_packageBundles[i] = packageReader.ReadArray <ulong>((int)package.m_bundleCount); } packageStream.Position = package.m_offsetRecords; using (GZipStream decompressedStream = new GZipStream(packageStream, CompressionMode.Decompress)) using (BinaryReader decompressedReader = new BinaryReader(decompressedStream)) { m_packageRecords[i] = decompressedReader.ReadArray <PackageRecord>((int)package.m_recordCount); } } }
private Dictionary <ulong, uint> CreateOffsetCache(ContentManifestFile cmf, ulong bundleGuid) { using (Stream bundleStream = cmf.OpenFile(_client, bundleGuid)) { Memory <byte> buf = new byte[(int)bundleStream.Length]; bundleStream.Read(buf); lock (_bundleCache) { _bundleCache[bundleGuid] = buf; } bundleStream.Position = 0; Bundle bundle = new Bundle(bundleStream); return(bundle.Entries.ToDictionary(x => x.GUID, x => x.Offset)); } }
private bool VerifyEntries(ContentManifestFile cmf) { for (var i = 0; i < m_header.m_entryCount; i++) { var a = m_entries[i]; var b = cmf.m_entries[i]; if (a.m_hashA != b.m_hashA) { return(false); } // todo: HashB is always 0 in APM. what does this mean? } return(true); }
private bool VerifyEntries(ContentManifestFile cmf) { for (int i = 0; i < Header.EntryCount; i++) { Entry a = Entries[i]; Entry b = cmf.Entries[i]; if (a.HashA != b.HashA) { return(false); } // todo: HashB is always 0 in APM. what does this mean? } return(true); }
private void RegisterCMFAssets(ContentManifestFile contentManifestFile, int fakePackageIdx) { if (contentManifestFile == null) { return; } Parallel.For(0, contentManifestFile.m_hashList.Length, new ParallelOptions { MaxDegreeOfParallelism = 4 }, j => { var cmfAsset = contentManifestFile.m_hashList[j]; if (m_assets.ContainsKey(cmfAsset.GUID)) { return; } m_assets[cmfAsset.GUID] = new Asset(fakePackageIdx, j); }); }
public ProductHandler_Tank(ClientHandler client, Stream stream) { m_client = client; var clientArgs = client.CreateArgs.HandlerArgs as ClientCreateArgs_Tank ?? new ClientCreateArgs_Tank(); using (BinaryReader reader = new BinaryReader(stream)) { string str = Encoding.ASCII.GetString(reader.ReadBytes((int)stream.Length)); string[] array = str.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); if (ROOT_FILE_FIELD_ORDER_CHECK != array[0]) { throw new InvalidDataException($"ProductHandler_Tank: Root file field list mismatch ({array[0]})"); } m_rootFiles = new RootFile[array.Length - 1]; for (int i = 1; i < array.Length; i++) { m_rootFiles[i - 1] = new RootFile(array[i].Split('|')); } } if (!clientArgs.LoadManifest) { return; } int totalAssetCount = 0; foreach (RootFile rootFile in m_rootFiles.Reverse()) // cmf first, then apm { string extension = Path.GetExtension(rootFile.FileName); if (extension != ".cmf" && extension != ".apm" && extension != ".trg") { continue; } var manifestName = Path.GetFileNameWithoutExtension(rootFile.FileName); var manifestFileName = Path.GetFileName(rootFile.FileName); if (!manifestName.Contains(clientArgs.ManifestRegion ?? REGION_DEV)) { continue; // is a CN (china) CMF. todo: support this } var locale = GetManifestLocale(manifestName); // ReSharper disable once ConvertIfStatementToSwitchStatement if (extension == ".cmf") { bool speech = manifestName.Contains(SPEECH_MANIFEST_NAME); bool text = manifestName.Contains(TEXT_MANIFEST_NAME); if (speech) { if (locale != client.CreateArgs.SpeechLanguage) { continue; } } else if (locale != null) { // text or old root/text combo if (locale != client.CreateArgs.TextLanguage) { continue; } } ContentManifestFile cmf; //using (Stream file = File.OpenWrite($"{manifestName}.cmf")) { // cmfStream.CopyTo(file); //} try { using (Stream cmfStream = client.OpenCKey(rootFile.MD5)) cmf = new ContentManifestFile(client, cmfStream, manifestFileName); } catch (CryptographicException) { Logger.Error("CASC", OutdatedTACTLibErrorMessage); if (Debugger.IsAttached) { Debugger.Break(); } throw; } if (speech) { m_speechContentManifest = cmf; } else if (text) { m_textContentManifest = cmf; } else { m_rootContentManifest = cmf; } totalAssetCount += cmf.m_header.m_dataCount; } else if (extension == ".apm") { if (locale != client.CreateArgs.TextLanguage) { continue; } using (Stream apmStream = client.OpenCKey(rootFile.MD5)) m_packageManifest = new ApplicationPackageManifest(client, this, apmStream, manifestName); } else if (extension == ".trg") { try { using (Stream trgStream = client.OpenCKey(rootFile.MD5)) { //using (Stream file = File.OpenWrite($"{manifestName}.trg")) { // trgStream.CopyTo(file); //} m_resourceGraph = new ResourceGraph(client, trgStream, manifestFileName); } } catch (CryptographicException) { Logger.Error("CASC", OutdatedTACTLibErrorMessage); if (Debugger.IsAttached) { Debugger.Break(); } throw; } } } m_usingResourceGraph = m_rootContentManifest.m_header.m_buildVersion >= VERSION_148_PTR; m_assets = new ConcurrentDictionary <ulong, Asset>(Environment.ProcessorCount + 2, totalAssetCount); if (!m_usingResourceGraph) { for (int i = 0; i < m_packageManifest.m_header.m_packageCount; i++) { var records = m_packageManifest.m_packageRecords[i]; for (int j = 0; j < records.Length; j++) { var record = records[j]; //Console.Out.WriteLine($"{record.GUID:X8} {record.Unknown1} {record.Unknown2} {Manifests[0].ContentManifest.Exists(record.GUID)} {Manifests[1].ContentManifest.Exists(record.GUID)}"); if (m_assets.ContainsKey(record.m_GUID)) { continue; } m_assets[record.m_GUID] = new Asset(i, j); } } } RegisterCMFAssets(m_rootContentManifest, PACKAGE_IDX_FAKE_ROOT_CMF); RegisterCMFAssets(m_textContentManifest, PACKAGE_IDX_FAKE_TEXT_CMF); RegisterCMFAssets(m_speechContentManifest, PACKAGE_IDX_FAKE_SPEECH_CMF); if (m_usingResourceGraph) { m_hackedLookedUpBundles = new HashSet <ulong>(); m_hackedBundleLookup = new Dictionary <ulong, ulong>(); DoBundleLookupHack(); } }
public ProductHandler_Tank(ClientHandler client, Stream stream) { _client = client; var clientArgs = client.CreateArgs.HandlerArgs as ClientCreateArgs_Tank ?? new ClientCreateArgs_Tank(); using (BinaryReader reader = new BinaryReader(stream)) { string str = Encoding.ASCII.GetString(reader.ReadBytes((int)stream.Length)); string[] array = str.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); if (FieldOrderCheck != array[0]) { throw new InvalidDataException($"ProductHandler_Tank: Root file field list mismatch ({array[0]})"); } RootFiles = new RootFile[array.Length - 1]; for (int i = 1; i < array.Length; i++) { RootFiles[i - 1] = new RootFile(array[i].Split('|')); } } if (!clientArgs.LoadManifest) { return; } int totalAssetCount = 0; foreach (RootFile rootFile in RootFiles.Reverse()) // cmf first, then apm { string extension = Path.GetExtension(rootFile.FileName); if (extension != ".cmf" && extension != ".apm") { continue; } string manifestName = Path.GetFileNameWithoutExtension(rootFile.FileName); if (manifestName == null) { throw new InvalidDataException(); } if (!manifestName.Contains(RegionDev)) { continue; // is a CN (china?) CMF. todo: support this } var locale = GetManifestLocale(manifestName); // ReSharper disable once ConvertIfStatementToSwitchStatement if (extension == ".cmf") { bool speech = manifestName.Contains(SpeechManifestName); if (speech) { if (locale != client.CreateArgs.SpeechLanguage) { continue; } } else { if (locale != client.CreateArgs.TextLanguage) { continue; } } ContentManifestFile cmf; using (Stream cmfStream = client.OpenCKey(rootFile.MD5)) { try { cmf = new ContentManifestFile(client, cmfStream, $"{manifestName}.cmf"); } catch (CryptographicException) { Logger.Error("CASC", "Fatal - CMF decryption failed. Please update TACTLib."); if (Debugger.IsAttached) { Debugger.Break(); } throw; } } if (speech) { SpeechContentManifest = cmf; } else { MainContentManifest = cmf; } totalAssetCount += cmf.Header.DataCount; } else if (extension == ".apm") { if (locale != client.CreateArgs.TextLanguage) { continue; } using (Stream apmStream = client.OpenCKey(rootFile.MD5)) { PackageManifest = new ApplicationPackageManifest(client, this, apmStream, manifestName); } } } Assets = new ConcurrentDictionary <ulong, Asset>(Environment.ProcessorCount + 2, totalAssetCount); for (int i = 0; i < PackageManifest.Header.PackageCount; i++) { var records = PackageManifest.Records[i]; for (int j = 0; j < records.Length; j++) { var record = records[j]; //Console.Out.WriteLine($"{record.GUID:X8} {record.Unknown1} {record.Unknown2} {Manifests[0].ContentManifest.Exists(record.GUID)} {Manifests[1].ContentManifest.Exists(record.GUID)}"); if (Assets.ContainsKey(record.GUID)) { continue; } Assets[record.GUID] = new Asset(i, j); } } for (int i = 0; i < 2; i++) { ContentManifestFile contentManifestFile; int cmfId = -(i + 1); if (cmfId == -1) { contentManifestFile = MainContentManifest; } else if (cmfId == -2) { contentManifestFile = SpeechContentManifest; } else { throw new Exception("wat"); } // main = -1 // speech = -2 Parallel.For(0, contentManifestFile.HashList.Length, new ParallelOptions { MaxDegreeOfParallelism = 4 }, j => { var cmfAsset = contentManifestFile.HashList[j]; if (Assets.ContainsKey(cmfAsset.GUID)) { return; } Assets[cmfAsset.GUID] = new Asset(cmfId, j); }); } }