public TI.Definition LoadResources(DatumIndex resource, CacheFileGen3 c, cache_file_resource_layout_table cache_layout, bool mega_hack)
        {
            if (resource == DatumIndex.Null || c == null || cache_layout == null ||
                resource.Index < 0 || resource.Index > TagResources.Count)
            {
                return(null);
            }

            return(TagResources[resource.Index].LoadResources(c, this, cache_layout, mega_hack));
        }
Exemplo n.º 2
0
			internal byte[] GetSegmentData(CacheFileGen3 cf, cache_file_resource_layout_table owner, int segment_offset)
			{
				if (PageData == null)
				{
					#region shared cache handling
					if (SharedCache.Value != -1) return null;
					if (SharedCache.Value > -1) // above stmt disables this code for now
					{
						shared_cache_block scb = owner.SharedCaches[SharedCache.Value];
						bool is_internal;
						var scf = Program.GetManager(cf.EngineVersion).GetCacheFileFromLocation(cf.EngineVersion, scb.CachePath.Value, out is_internal) 
							as CacheFileGen3;
						if (!is_internal) cf = scf;
						// if it says its internal, the shared cache file wasn't loaded
						else throw new Debug.Exceptions.UnreachableException();
					}
					#endregion

					// If the page is valid, figure out the decompression size
					int size = BlockSizeUncompressed.Value;
					if (size <= 0) return null;

					#region Perform codec operations
					uint base_offset = (uint)(cf.Header as CacheHeaderGen3).Interop[Blam.CacheSectionType.Resource].CacheOffset;
					uint offset = base_offset + (uint)BlockOffset.Value;
					cf.InputStream.Seek(offset);
					if (CompressionCodec.Value != -1)
					{
						// TODO: we would need to test the GUID here if\when bungie adds
						// more compression codecs. Since deflation and no-codec are the 
						// only things they do use, we can just assume for now.
						using (var deflate = new System.IO.Compression.DeflateStream(cf.InputStream.BaseStream, System.IO.Compression.CompressionMode.Decompress, true))
						{
							PageData = new byte[size];
							deflate.Read(PageData, 0, PageData.Length);
						}
					}
					// No codec used, plain data
					else PageData = cf.InputStream.ReadBytes(size);
					#endregion
				}

				int segment_size = GetSegmentSize(segment_offset);
				if (segment_size == -1) return null; // offset was either invalid or sizes haven't been post-processed

				byte[] segment_data = new byte[segment_size];
				// Extract the segment data from the page
				Array.Copy(PageData, segment_offset, segment_data, 0, segment_data.Length);

				return segment_data;
			}
            public static void OutputResources(string dir, CacheFileGen3 cf, TI.Block <pages_block> block)
            {
                uint   offset;
                int    size;
                uint   base_offset = (uint)(cf.Header as CacheHeaderGen3).Interop[CacheSectionType.Resource].CacheOffset;
                string path        = string.Format(@"{0}\\{1}_resources\\", dir, cf.Header.Name);

                if (!System.IO.Directory.Exists(path))
                {
                    System.IO.Directory.CreateDirectory(path);
                }

                int x = -1;

                foreach (pages_block def in block)
                {
                    x++;
                    if (def.SharedCache.Value != -1)
                    {
                        continue;
                    }
                    size = def.BlockSizeUncompressed.Value;
                    if (size <= 0)
                    {
                        continue;
                    }

                    offset = base_offset + (uint)def.BlockOffset.Value;
                    cf.InputStream.Seek(offset);
                    byte[] data;
                    if (def.CompressionCodec.Value != -1)
                    {
                        using (var deflate = new System.IO.Compression.DeflateStream(cf.InputStream.BaseStream, System.IO.Compression.CompressionMode.Decompress, true))
                        {
                            data = new byte[size];
                            deflate.Read(data, 0, data.Length);
                        }
                    }
                    else
                    {
                        data = cf.InputStream.ReadBytes(size);
                    }

                    using (var fs = new FileStream(string.Format("{0}\\{1:X8}.bin", path, x), System.IO.FileMode.Create, System.IO.FileAccess.Write))
                    {
                        fs.Write(data, 0, data.Length);
                    }
                }
            }
Exemplo n.º 4
0
		public static void OutputResources(string dir, CacheFileGen3 cf, cache_file_resource_layout_table def)
		{
			pages_block.OutputResources(dir, cf, def.Pages);
		}
Exemplo n.º 5
0
			public static void OutputResources(string dir, CacheFileGen3 cf, TI.Block<pages_block> block)
			{
				uint offset;
				int size;
				uint base_offset = (uint)(cf.Header as CacheHeaderGen3).Interop[CacheSectionType.Resource].CacheOffset;
				string path = string.Format(@"{0}\\{1}_resources\\", dir, cf.Header.Name);
				if (!System.IO.Directory.Exists(path))
					System.IO.Directory.CreateDirectory(path);

				int x = -1;
				foreach (pages_block def in block)
				{
					x++;
					if (def.SharedCache.Value != -1) continue;
					size = def.BlockSizeUncompressed.Value;
					if (size <= 0) continue;

					offset = base_offset + (uint)def.BlockOffset.Value;
					cf.InputStream.Seek(offset);
					byte[] data;
					if (def.CompressionCodec.Value != -1)
					{
						using (var deflate = new System.IO.Compression.DeflateStream(cf.InputStream.BaseStream, System.IO.Compression.CompressionMode.Decompress, true))
						{
							data = new byte[size];
							deflate.Read(data, 0, data.Length);
						}
					}
					else
						data = cf.InputStream.ReadBytes(size);

					using(var fs = new FileStream(string.Format("{0}\\{1:X8}.bin", path, x), System.IO.FileMode.Create, System.IO.FileAccess.Write))
					{
						fs.Write(data, 0, data.Length);
					}
				}
			}
 public static void OutputResources(string dir, CacheFileGen3 cf, cache_file_resource_layout_table def)
 {
     pages_block.OutputResources(dir, cf, def.Pages);
 }
Exemplo n.º 7
0
        public override object Execute(List <string> args)
        {
            if (args.Count < 1)
            {
                return(false);
            }

            var memory = false;

            while (args.Count > 1)
            {
                switch (args[0].ToLower())
                {
                case "memory":
                    memory = true;
                    break;

                default:
                    throw new FormatException(args[0]);
                }

                args.RemoveAt(0);
            }

            var blamCacheFile = new FileInfo(args[0]);

            if (!blamCacheFile.Exists)
            {
                Console.WriteLine($"CacheFile {blamCacheFile.FullName} does not exist");
                return(true);
            }

            Console.Write("Loading blam cache file...");

            CacheFile blamCache = null;

            using (var cacheStream = new FileStream(blamCacheFile.FullName, FileMode.Open, FileAccess.Read))
            {
                var reader = new EndianReader(cacheStream, EndianFormat.BigEndian);

                var head = reader.ReadInt32();

                if (head == 1684104552)
                {
                    reader.Format = EndianFormat.LittleEndian;
                }

                var v = reader.ReadInt32();

                switch (v)
                {
                case 8:     // Gen2
                    reader.SeekTo(36);
                    switch (reader.ReadInt32())
                    {
                    case 0:         // Halo 2 Xbox
                        reader.SeekTo(288);
                        break;

                    case -1:         // Halo 2 Vista
                        reader.SeekTo(300);
                        break;
                    }
                    break;

                default:     // Gen3+
                    reader.SeekTo(284);
                    break;
                }

                var version = CacheVersionDetection.GetFromBuildName(reader.ReadString(32));

                switch (version)
                {
                case CacheVersion.Halo2Xbox:
                case CacheVersion.Halo2Vista:
                    if (blamCacheFile.Name != "mainmenu.map")
                    {
                        new CacheFileGen2(CacheContext, new FileInfo(Path.Combine(blamCacheFile.Directory.FullName, "mainmenu.map")), version, memory);
                    }
                    if (blamCacheFile.Name != "shared.map")
                    {
                        new CacheFileGen2(CacheContext, new FileInfo(Path.Combine(blamCacheFile.Directory.FullName, "shared.map")), version, memory);
                    }
                    if (blamCacheFile.Name != "single_player_shared.map")
                    {
                        new CacheFileGen2(CacheContext, new FileInfo(Path.Combine(blamCacheFile.Directory.FullName, "single_player_shared.map")), version, memory);
                    }
                    blamCache = new CacheFileGen2(CacheContext, blamCacheFile, version, memory);
                    break;

                case CacheVersion.Halo3Retail:
                case CacheVersion.Halo3ODST:
                case CacheVersion.HaloReach:
                    blamCache = new CacheFileGen3(CacheContext, blamCacheFile, version, memory);
                    break;

                default:     // Same question here as above.
                    throw new NotSupportedException(CacheVersionDetection.GetBuildName(version));
                }
            }

            ContextStack.Push(PortingContextFactory.Create(ContextStack, CacheContext, blamCache));

            Console.WriteLine("done.");

            return(true);
        }
Exemplo n.º 8
0
		public TI.Definition LoadResources(DatumIndex resource, CacheFileGen3 c, cache_file_resource_layout_table cache_layout, bool mega_hack)
		{
			if (resource == DatumIndex.Null || c == null || cache_layout == null ||
				resource.Index < 0 || resource.Index > TagResources.Count)
				return null;

			return TagResources[resource.Index].LoadResources(c, this, cache_layout, mega_hack);
		}
Exemplo n.º 9
0
		public TI.Definition LoadResources(DatumIndex resource, CacheFileGen3 c, cache_file_resource_layout_table cache_layout)
		{
			return LoadResources(resource, c, cache_layout, false);
		}
Exemplo n.º 10
0
			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;
			}
Exemplo n.º 11
0
				public resource_tag_stream(CacheFileGen3 c, DatumIndex tag, IO.EndianReader s)
				{ cache = c; tag_datum = tag; InputStream = s; }
            internal byte[] GetSegmentData(CacheFileGen3 cf, cache_file_resource_layout_table owner, int segment_offset)
            {
                if (PageData == null)
                {
                    #region shared cache handling
                    if (SharedCache.Value != -1)
                    {
                        return(null);
                    }
                    if (SharedCache.Value > -1)                     // above stmt disables this code for now
                    {
                        shared_cache_block scb = owner.SharedCaches[SharedCache.Value];
                        bool is_internal;
                        var  scf = Program.GetManager(cf.EngineVersion).GetCacheFileFromLocation(cf.EngineVersion, scb.CachePath.Value, out is_internal)
                                   as CacheFileGen3;
                        if (!is_internal)
                        {
                            cf = scf;
                        }
                        // if it says its internal, the shared cache file wasn't loaded
                        else
                        {
                            throw new Debug.Exceptions.UnreachableException();
                        }
                    }
                    #endregion

                    // If the page is valid, figure out the decompression size
                    int size = BlockSizeUncompressed.Value;
                    if (size <= 0)
                    {
                        return(null);
                    }

                    #region Perform codec operations
                    uint base_offset = (uint)(cf.Header as CacheHeaderGen3).Interop[Blam.CacheSectionType.Resource].CacheOffset;
                    uint offset      = base_offset + (uint)BlockOffset.Value;
                    cf.InputStream.Seek(offset);
                    if (CompressionCodec.Value != -1)
                    {
                        // TODO: we would need to test the GUID here if\when bungie adds
                        // more compression codecs. Since deflation and no-codec are the
                        // only things they do use, we can just assume for now.
                        using (var deflate = new System.IO.Compression.DeflateStream(cf.InputStream.BaseStream, System.IO.Compression.CompressionMode.Decompress, true))
                        {
                            PageData = new byte[size];
                            deflate.Read(PageData, 0, PageData.Length);
                        }
                    }
                    // No codec used, plain data
                    else
                    {
                        PageData = cf.InputStream.ReadBytes(size);
                    }
                    #endregion
                }

                int segment_size = GetSegmentSize(segment_offset);
                if (segment_size == -1)
                {
                    return(null);                                    // offset was either invalid or sizes haven't been post-processed
                }
                byte[] segment_data = new byte[segment_size];
                // Extract the segment data from the page
                Array.Copy(PageData, segment_offset, segment_data, 0, segment_data.Length);

                return(segment_data);
            }
 public TI.Definition LoadResources(DatumIndex resource, CacheFileGen3 c, cache_file_resource_layout_table cache_layout)
 {
     return(LoadResources(resource, c, cache_layout, false));
 }
            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);
            }
 public resource_tag_stream(CacheFileGen3 c, DatumIndex tag, IO.EndianReader s)
 {
     cache = c; tag_datum = tag; InputStream = s;
 }