/// <summary> /// Align a reader to 16 byte alignment /// </summary> /// <param name="p_Reader"></param> private void Align16(RimeReader p_Reader) { if (p_Reader.Position % 16 == 0) { return; } var s_Number = 16 - (p_Reader.Position % 16); p_Reader.ReadBytes((int)s_Number); }
/// <summary> /// Bundle constructor from BundleManifest /// </summary> /// <param name="p_Manifest">Bundle manifest</param> /// <param name="p_Reader">Opened reader to the start to the</param> /// <param name="p_Entry">Bundle Entry Information</param> public Bundle(BundleManifest p_Manifest, RimeReader p_Reader, BundleEntry p_Entry) { Entry = p_Entry; Path = p_Entry.ID; if (p_Manifest.RealManifest.EbxMode) { ParseEbxBundle(p_Manifest, p_Reader); } else { ParseDbxBundle(p_Manifest, p_Reader); } }
/// <summary> /// This function will read out a layout from an provided DbObject /// </summary> /// <param name="p_Reader">Reader opened to the position of the DbObject</param> /// <returns>DbObject contianing the layout</returns> private DbObject ParseReadLayout(RimeReader p_Reader) { var s_LayoutMagic = p_Reader.ReadUInt32(); // Check if the file is obfuscated. if (s_LayoutMagic == Loader2013_2Plugin.c_Obfuscated_0 || s_LayoutMagic == Loader2013_2Plugin.c_Obfuscated_1) { p_Reader.EnableDeobfuscation(); } else if (s_LayoutMagic == Loader2013_2Plugin.c_Signed) // Signed { p_Reader.Seek(0x228, SeekOrigin.Current); } else #if DEBUG { throw new Exception("The Layout file appears to have an invalid header or is unsupported."); } #else { return(null); } #endif return(new DbObject(p_Reader)); }
/// <summary> /// Parse a dbx bundle /// </summary> /// <param name="p_Manifest">Bundle manifest</param> /// <param name="p_Reader">Reader opened to the dbx file</param> protected void ParseDbxBundle(BundleManifest p_Manifest, RimeReader p_Reader) { throw new NotImplementedException("We currently do not support DBX-mode bundles."); }
/// <summary> /// Parses an ebx bundle /// </summary> /// <param name="p_Manifest">Bundle Manifest</param> /// <param name="p_Reader">Reader opened to the position of the bundle</param> protected void ParseEbxBundle(BundleManifest p_Manifest, RimeReader p_Reader) { // TODO: Implement VeniceBundleManifest throw new NotImplementedException(); //var s_Manifest = p_Manifest.RealManifest as VeniceBundleManifest; //// Align to 16 because of the header. //Align16(p_Reader); //var s_TextBlockReader = new RimeReader(new MemoryStream(s_Manifest.TextBlock), Endianness.BigEndian); //// Start reading entries. //for (var i = 0; i < p_Manifest.ManifestHeader.DbxCount; ++i) //{ // var s_Entry = s_Manifest.Records[i]; // // Read the name of the entry. // s_TextBlockReader.Seek(s_Entry.NameOffset, SeekOrigin.Begin); // var s_Name = s_TextBlockReader.ReadNullTerminatedString(); // // Get the SHA1 hash. // var s_Hash = s_Manifest.HashBase[i]; // // Create the EBX entry. // var s_Ebx = new EBX(s_Name, s_Hash, s_Entry, p_Reader.ReadBytes((int)s_Manifest.Records[i].PayloadSize), this); // m_EBX.Add(s_Ebx); // Align16(p_Reader); //} //// Read resource entries. //for (var i = (int)p_Manifest.ManifestHeader.DbxCount; i < p_Manifest.ManifestHeader.DbxCount + p_Manifest.ManifestHeader.ResourceCount; ++i) //{ // var s_Entry = s_Manifest.Records[i]; // // Read the name of the entry. // s_TextBlockReader.Seek(s_Entry.NameOffset, SeekOrigin.Begin); // var s_Name = s_TextBlockReader.ReadNullTerminatedString(); // // Get the SHA1 hash. // var s_Hash = s_Manifest.HashBase[i]; // // Get the Type hash. // var s_TypeHash = s_Manifest.ResourceTypeHash[(int)(i - p_Manifest.ManifestHeader.DbxCount)]; // // Get the Meta block. // var s_Meta = s_Manifest.ResourceMeta[(int)(i - p_Manifest.ManifestHeader.DbxCount)]; // // Create the Resource entry. // var s_Resource = new Resource(s_Name, s_Hash, s_TypeHash, p_Reader.ReadBytes((int)s_Manifest.Records[i].PayloadSize), s_Meta, s_Entry, this); // m_Resources.Add(s_Resource); // Align16(p_Reader); //} //// Read chunk entries. //var s_ChunkMeta = s_Manifest.ChunkMeta != null && s_Manifest.ChunkMeta["chunkMeta"] != null ? s_Manifest.ChunkMeta["chunkMeta"].Value as DbObject : null; //for (var i = 0; i < p_Manifest.ManifestHeader.ChunkCount; ++i) //{ // var s_Entry = s_Manifest.Chunks[i]; // // Get the SHA1 hash. // var s_Hash = s_Manifest.HashBase[i + (int)(p_Manifest.ManifestHeader.DbxCount + p_Manifest.ManifestHeader.ResourceCount)]; // // Get the Meta block. // var s_Meta = s_ChunkMeta != null ? s_ChunkMeta[i].Value as DbObject : null; // // Create the Chunk entry. // var s_Data = p_Reader.ReadBytes((int)(s_Manifest.Chunks[i].RangeEnd - s_Manifest.Chunks[i].RangeStart)); // var s_Chunk = new Chunk(s_Hash, s_Meta, s_Entry, s_Data, this); // m_Chunks.Add(s_Chunk); // Align16(p_Reader); //} //s_TextBlockReader.Dispose(); }
/// <summary> /// Constructor for handling Frostbite 2013.2 specific superbundles /// </summary> /// <param name="p_Reader"></param> /// <param name="p_Entry"></param> /// <param name="p_Authoritative"></param> public SuperbundleLayout(RimeReader p_Reader, SuperbundleEntry p_Entry, bool p_Authoritative) : base(p_Reader, p_Entry, p_Authoritative) { }
/// <summary> /// Helper function to mount patched bundles /// </summary> /// <param name="p_Superbundle">Superbundle to get bundles from</param> /// <param name="p_BundleEntry">The bundle entry information</param> /// <param name="p_BaseReader">The reader of the base file</param> /// <param name="p_PatchReader">The reader of the patch file</param> /// <returns>BundleBase object</returns> private BundleBase MountPatchedDeltaBundle(SuperbundleBase p_Superbundle, BundleEntry p_BundleEntry, RimeReader p_BaseReader, RimeReader p_PatchReader) { throw new NotImplementedException("Patch files for Frostbite 2013.2 not supported."); }
/// <summary> /// Helper function to mount a base bundle /// </summary> /// <param name="p_Superbundle">Superbundle to get bundles from</param> /// <param name="p_BundleEntry">The bundle entry information</param> /// <param name="p_BaseReader">The reader of the base file</param> /// <param name="p_PatchReader">The reader of the patch file</param> /// <returns>Loaded BundleBase object</returns> private BundleBase MountBundle(SuperbundleBase p_Superbundle, BundleEntry p_BundleEntry, RimeReader p_BaseReader, RimeReader p_PatchReader) { p_BaseReader.Seek(p_BundleEntry.Offset, SeekOrigin.Begin); var s_Manifest = new BundleManifest(p_BaseReader, p_BundleEntry); var s_Bundle = s_Manifest.RealManifest.Bundle; p_Superbundle.Bundles.TryAdd(p_BundleEntry.ID, s_Bundle); return(s_Bundle); }
/// <summary> /// Mounts a content addressable storage bundle /// </summary> /// <param name="p_Superbundle">Superbundle to get bundles from</param> /// <param name="p_BundleEntry">The bundle entry information</param> /// <param name="p_BaseReader">The reader of the base file</param> /// <param name="p_PatchReader">The reader of the patch file</param> /// <returns>Loaded BundleBase object</returns> private BundleBase MountCASBundle(SuperbundleBase p_Superbundle, BundleEntry p_BundleEntry, RimeReader p_BaseReader, RimeReader p_PatchReader) { p_BaseReader.Seek(p_BundleEntry.Offset, SeekOrigin.Begin); var s_Object = new DbObject(p_BaseReader, p_BundleEntry.Size); var s_Bundle = new Bundle(s_Object[0].Value as DbObject, p_BundleEntry); p_Superbundle.Bundles.TryAdd(p_BundleEntry.ID, s_Bundle); return(s_Bundle); }
/// <summary> /// This mounts all bundles that have not been mounted already /// </summary> /// <param name="p_Superbundle">Superbundle to load all bundles that are contained within</param> public override void MountBundles(SuperbundleBase p_Superbundle) { var s_Endianness = p_Superbundle.BaseLayout.Cas ? Endianness.LittleEndian : Endianness.BigEndian; RimeReader s_BaseReader; if (!FileSystem.OpenFileRead(p_Superbundle.BasePath + ".sb", out s_BaseReader, s_Endianness)) { return; } RimeReader s_PatchReader = null; if (p_Superbundle.PatchPath != null && !FileSystem.OpenFileRead(p_Superbundle.PatchPath + ".sb", out s_PatchReader, s_Endianness)) { s_BaseReader.Dispose(); return; } foreach (var s_Bundle in p_Superbundle.BundleEntries) { MessageManager.SendMessageAsync(new LogWriteMessage { LogLevel = LogsLevel.Info, Message = $"Mounting superbundle '{p_Superbundle.Name}' bundle [{s_Bundle.Key}]..." }); BundleBase s_MountedBundle; if (p_Superbundle.AuthoritativeLayout != null && s_Bundle.Value.BaseSuperbundle.Cas) { s_MountedBundle = MountPatchedCASBundle(p_Superbundle, s_Bundle.Value, s_BaseReader, s_PatchReader); } else if (s_Bundle.Value.DeltaEntry != null && s_Bundle.Value.DeltaEntry.Delta) { s_MountedBundle = MountPatchedDeltaBundle(p_Superbundle, s_Bundle.Value, s_BaseReader, s_PatchReader); } else if (s_Bundle.Value.DeltaEntry != null) { s_MountedBundle = MountPatchedBundle(p_Superbundle, s_Bundle.Value, s_BaseReader, s_PatchReader); } else if (s_Bundle.Value.BaseSuperbundle.Cas) { s_MountedBundle = MountCASBundle(p_Superbundle, s_Bundle.Value, s_BaseReader, s_PatchReader); } else { s_MountedBundle = MountBundle(p_Superbundle, s_Bundle.Value, s_BaseReader, s_PatchReader); } // VFS if (s_MountedBundle == null) { return; } MountBundleToVFS(s_MountedBundle); } s_BaseReader.Dispose(); s_PatchReader?.Dispose(); MessageManager.SendMessage(new SuperbundleBundlesMountedMessage { SuperbundleBase = p_Superbundle }); MessageManager.SendMessageAsync(new LogWriteMessage { LogLevel = LogsLevel.Info, Message = $"Finished mounting superbundle '{p_Superbundle.Name}' bundles!" }); }