internal TI.Definition LoadResources(CacheFileGen3 c, cache_file_resource_gestalt_group owner, cache_file_resource_layout_table cache_layout, bool mega_hack) { if (Reference.Datum == DatumIndex.Null) return null; // this is a null entry if (loadedResources != null) return loadedResources; // data already loaded, return var rdf = c.GetCacheFileResourceDefinitionFactory(); // pre-process cache for resource loading cache_layout.BuildInteropData(); owner.BuildInteropData(); int resource_stream_definition_size = BlockSize.Value; // sound resource case hack bool use_sound_resource_hack = false; if (resource_stream_definition_size == 0) { Debug.Assert.If(ResourceType.Value == owner.resource_index_sound_resource_definition); resource_stream_definition_size = sound_resource_definition.kSizeOf; use_sound_resource_hack = true; } int resource_stream_size_required = resource_stream_definition_size; // base address to use on cache fixups, cache data will be appended // later on uint cache_required_base_address = 0, cache_optional_base_address = 0; byte[] resource_stream_data; #region create resource buffer {// Get our page segment data so we can build our resource buffer for loading int seg_index = SegmentIndex.Value; cache_file_resource_layout_table.page_segment_block page_segment = cache_layout.PageSegments[seg_index]; int required_size = page_segment.GetRequiredSize(); int optional_size = page_segment.GetOptionalSize(); cache_required_base_address = (uint)resource_stream_size_required; if (required_size > 0) resource_stream_size_required += required_size; if (optional_size > 0) // optional isn't always used so don't set the base address if it isn't { cache_optional_base_address = (uint)resource_stream_size_required; resource_stream_size_required += optional_size; } // get our definition data buffer resource_stream_data = new byte[resource_stream_size_required]; if (use_sound_resource_hack) // sound_resources don't occupy space in the resource-definition-data, so we have to create faux def data { int data_size = 0; if (required_size > 0) data_size += required_size; if (optional_size > 0) data_size += optional_size; if (data_size > 0) rdf.InsertDataSizeIntoFauxDefinitionData(resource_stream_data, (uint)data_size); } else Array.Copy(owner.ResourceDefinitionData.Value, BlockOffset.Value, resource_stream_data, 0, resource_stream_definition_size); { // get cache data and append it byte[] page_data = cache_layout.Pages[page_segment.RequiredPageIndex.Value].GetSegmentData(c, cache_layout, page_segment.RequiredSegmentOffset.Value); Array.Copy(page_data, 0, resource_stream_data, (int)cache_required_base_address, required_size); if (page_segment.OptionalPageIndex.Value >=0 && cache_optional_base_address > 0) { page_data = cache_layout.Pages[page_segment.OptionalPageIndex.Value].GetSegmentData(c, cache_layout, page_segment.OptionalSegmentOffset.Value); Array.Copy(page_data, 0, resource_stream_data, (int)cache_optional_base_address, optional_size); } } } #endregion Util.OptionalValue optv = new Util.OptionalValue((byte)resource_fixup_type.Count); #region perform fixups using (var ms = new System.IO.MemoryStream(resource_stream_data, true)) { foreach (resource_fixup_block def in ResourceFixups) { uint address = (uint)def.Address.Value; uint address_offset = optv.GetValue(address); ms.Seek(def.BlockOffset.Value, System.IO.SeekOrigin.Begin); resource_fixup_type rft = (resource_fixup_type)optv.GetOption(address); switch (rft) { case resource_fixup_type.Data: break; case resource_fixup_type.CacheRequired: address_offset += cache_required_base_address; break; case resource_fixup_type.CacheOptional: address_offset += cache_optional_base_address; break; default: throw new Debug.Exceptions.UnreachableException(); } IO.ByteSwap.SwapUDWordAndWrite(address_offset, ms); // hack identifier for StructReference fields when the definition is at offset '0' // as that f***s with the init code //if (address_offset == 0) IO.ByteSwap.SwapUDWordAndWrite(1, ms); } // foreach (resource_definition_fixup_block def in ResourceDefinitionFixups) // { // } } #endregion #region create and stream definition using (var s = new IO.EndianReader(resource_stream_data, IO.EndianState.Big, null)) { int res_type = ResourceType.Value; if (res_type == owner.resource_index_render_geometry_api_resource_definition) loadedResources = rdf.GenerateRenderGeometryApiResource(); else if (res_type == owner.resource_index_bitmap_texture_interop_resource) loadedResources = rdf.GenerateBitmapTextureInteropResource(); else if (res_type == owner.resource_index_model_animation_tag_resource) loadedResources = rdf.GenerateModelAnimationTagResource(); // TODO: haven't quite figured this one out yet. Currently using hacked up code (see [use_sound_resource_hack]) else if (res_type == owner.resource_index_sound_resource_definition) loadedResources = rdf.GenerateSoundResourceResource(); else if (res_type == owner.resource_index_bitmap_texture_interleaved_interop_resource) loadedResources = rdf.GenerateBitmapTextureInterleavedInteropResource(); else if (res_type == owner.resource_index_structure_bsp_tag_resources) loadedResources = rdf.GenerateStructureBspTagResource(); // TODO: haven't figured this one out yet else if (res_type == owner.resource_index_structure_bsp_cache_file_tag_resources) loadedResources = rdf.GenerateStructureBspCacheFileTagResource(); else throw new Debug.Exceptions.UnreachableException(); s.Seek(optv.GetValue((uint)DefinitionOffset.Value)); IO.ITagStream ts = new resource_tag_stream(c, Reference.Datum, s); ts.Flags.Add( IO.ITagStreamFlags.UseStreamPositions | IO.ITagStreamFlags.DontStreamStringData | IO.ITagStreamFlags.DontStreamFieldSetHeader | IO.ITagStreamFlags.DontPostprocess); if (mega_hack) ts.Flags.Add(IO.ITagStreamFlags.Halo3VertexBufferMegaHack); loadedResources.Read(ts); } #endregion return loadedResources; }
internal TI.Definition LoadResources(CacheFileGen3 c, cache_file_resource_gestalt_group owner, cache_file_resource_layout_table cache_layout, bool mega_hack) { if (Reference.Datum == DatumIndex.Null) { return(null); // this is a null entry } if (loadedResources != null) { return(loadedResources); // data already loaded, return } var rdf = c.GetCacheFileResourceDefinitionFactory(); // pre-process cache for resource loading cache_layout.BuildInteropData(); owner.BuildInteropData(); int resource_stream_definition_size = BlockSize.Value; // sound resource case hack bool use_sound_resource_hack = false; if (resource_stream_definition_size == 0) { Debug.Assert.If(ResourceType.Value == owner.resource_index_sound_resource_definition); resource_stream_definition_size = sound_resource_definition.kSizeOf; use_sound_resource_hack = true; } int resource_stream_size_required = resource_stream_definition_size; // base address to use on cache fixups, cache data will be appended // later on uint cache_required_base_address = 0, cache_optional_base_address = 0; byte[] resource_stream_data; #region create resource buffer { // Get our page segment data so we can build our resource buffer for loading int seg_index = SegmentIndex.Value; cache_file_resource_layout_table.page_segment_block page_segment = cache_layout.PageSegments[seg_index]; int required_size = page_segment.GetRequiredSize(); int optional_size = page_segment.GetOptionalSize(); cache_required_base_address = (uint)resource_stream_size_required; if (required_size > 0) { resource_stream_size_required += required_size; } if (optional_size > 0) // optional isn't always used so don't set the base address if it isn't { cache_optional_base_address = (uint)resource_stream_size_required; resource_stream_size_required += optional_size; } // get our definition data buffer resource_stream_data = new byte[resource_stream_size_required]; if (use_sound_resource_hack) // sound_resources don't occupy space in the resource-definition-data, so we have to create faux def data { int data_size = 0; if (required_size > 0) { data_size += required_size; } if (optional_size > 0) { data_size += optional_size; } if (data_size > 0) { rdf.InsertDataSizeIntoFauxDefinitionData(resource_stream_data, (uint)data_size); } } else { Array.Copy(owner.ResourceDefinitionData.Value, BlockOffset.Value, resource_stream_data, 0, resource_stream_definition_size); } { // get cache data and append it byte[] page_data = cache_layout.Pages[page_segment.RequiredPageIndex.Value].GetSegmentData(c, cache_layout, page_segment.RequiredSegmentOffset.Value); Array.Copy(page_data, 0, resource_stream_data, (int)cache_required_base_address, required_size); if (page_segment.OptionalPageIndex.Value >= 0 && cache_optional_base_address > 0) { page_data = cache_layout.Pages[page_segment.OptionalPageIndex.Value].GetSegmentData(c, cache_layout, page_segment.OptionalSegmentOffset.Value); Array.Copy(page_data, 0, resource_stream_data, (int)cache_optional_base_address, optional_size); } } } #endregion Util.OptionalValue optv = new Util.OptionalValue((byte)resource_fixup_type.Count); #region perform fixups using (var ms = new System.IO.MemoryStream(resource_stream_data, true)) { foreach (resource_fixup_block def in ResourceFixups) { uint address = (uint)def.Address.Value; uint address_offset = optv.GetValue(address); ms.Seek(def.BlockOffset.Value, System.IO.SeekOrigin.Begin); resource_fixup_type rft = (resource_fixup_type)optv.GetOption(address); switch (rft) { case resource_fixup_type.Data: break; case resource_fixup_type.CacheRequired: address_offset += cache_required_base_address; break; case resource_fixup_type.CacheOptional: address_offset += cache_optional_base_address; break; default: throw new Debug.Exceptions.UnreachableException(); } IO.ByteSwap.SwapUDWordAndWrite(address_offset, ms); // hack identifier for StructReference fields when the definition is at offset '0' // as that f***s with the init code //if (address_offset == 0) IO.ByteSwap.SwapUDWordAndWrite(1, ms); } // foreach (resource_definition_fixup_block def in ResourceDefinitionFixups) // { // } } #endregion #region create and stream definition using (var s = new IO.EndianReader(resource_stream_data, IO.EndianState.Big, null)) { int res_type = ResourceType.Value; if (res_type == owner.resource_index_render_geometry_api_resource_definition) { loadedResources = rdf.GenerateRenderGeometryApiResource(); } else if (res_type == owner.resource_index_bitmap_texture_interop_resource) { loadedResources = rdf.GenerateBitmapTextureInteropResource(); } else if (res_type == owner.resource_index_model_animation_tag_resource) { loadedResources = rdf.GenerateModelAnimationTagResource(); } // TODO: haven't quite figured this one out yet. Currently using hacked up code (see [use_sound_resource_hack]) else if (res_type == owner.resource_index_sound_resource_definition) { loadedResources = rdf.GenerateSoundResourceResource(); } else if (res_type == owner.resource_index_bitmap_texture_interleaved_interop_resource) { loadedResources = rdf.GenerateBitmapTextureInterleavedInteropResource(); } else if (res_type == owner.resource_index_structure_bsp_tag_resources) { loadedResources = rdf.GenerateStructureBspTagResource(); } // TODO: haven't figured this one out yet else if (res_type == owner.resource_index_structure_bsp_cache_file_tag_resources) { loadedResources = rdf.GenerateStructureBspCacheFileTagResource(); } else { throw new Debug.Exceptions.UnreachableException(); } s.Seek(optv.GetValue((uint)DefinitionOffset.Value)); IO.ITagStream ts = new resource_tag_stream(c, Reference.Datum, s); ts.Flags.Add( IO.ITagStreamFlags.UseStreamPositions | IO.ITagStreamFlags.DontStreamStringData | IO.ITagStreamFlags.DontStreamFieldSetHeader | IO.ITagStreamFlags.DontPostprocess); if (mega_hack) { ts.Flags.Add(IO.ITagStreamFlags.Halo3VertexBufferMegaHack); } loadedResources.Read(ts); } #endregion return(loadedResources); }