Пример #1
0
        private LoadedResourceCache GetResourceCache(PageableResource resource)
        {
            if (!resource.GetLocation(out var location))
            {
                return(null);
            }

            if (!LoadedResourceCaches.TryGetValue(location, out LoadedResourceCache cache))
            {
                var file = new FileInfo(Path.Combine(Directory.FullName, ResourceCacheNames[location]));

                if (!file.Exists && file.Name == "resources_b.dat")
                {
                    file = new FileInfo(Path.Combine(Directory.FullName, "video.dat"));
                }

                using (var stream = file.OpenRead())
                {
                    cache = new LoadedResourceCache
                    {
                        File  = file,
                        Cache = new ResourceCache(stream)
                    };
                }
            }

            return(cache);
        }
Пример #2
0
        public object Deserialize(PageableResource pageable)
        {
            switch (pageable.Resource.ResourceType)
            {
            case TagResourceTypeGen3.Animation:
                return(Deserialize <ModelAnimationTagResource>(pageable));

            case TagResourceTypeGen3.Bink:
                return(Deserialize <BinkResource>(pageable));

            case TagResourceTypeGen3.Bitmap:
            case TagResourceTypeGen3.BitmapInterleaved:
                return(Deserialize <BitmapTextureInteropResource>(pageable));

            case TagResourceTypeGen3.Collision:
                return(Deserialize <StructureBspTagResources>(pageable));

            case TagResourceTypeGen3.Pathfinding:
                return(Deserialize <StructureBspCacheFileTagResources>(pageable));

            case TagResourceTypeGen3.RenderGeometry:
                return(Deserialize <RenderGeometryApiResourceDefinition>(pageable));

            case TagResourceTypeGen3.Sound:
                return(Deserialize <SoundResourceDefinition>(pageable));

            default:
                throw new NotSupportedException(pageable.Resource.ResourceType.ToString());
            }
        }
        private ResourceCacheHaloOnline GetResourceCache(PageableResource resource, out ResourceLocation location)
        {
            if (!resource.GetLocation(out location))
            {
                return(null);
            }

            return(GetResourceCache(location));
        }
Пример #4
0
        /// <summary>
        /// Extracts raw, compressed resource data.
        /// </summary>
        /// <param name="resource">The resource.</param>
        /// <returns>The raw, compressed resource data.</returns>
        public byte[] ExtractRawResource(PageableResource resource)
        {
            if (resource == null)
            {
                throw new ArgumentNullException("resource");
            }

            var cache = GetResourceCache(resource);

            using (var stream = cache.File.OpenRead())
                return(cache.Cache.ExtractRaw(stream, resource.Page.Index, resource.Page.CompressedBlockSize));
        }
        /// <summary>
        /// Adds raw, pre-compressed resource data to a cache.
        /// </summary>
        /// <param name="resource">The resource reference to initialize.</param>
        /// <param name="data">The pre-compressed data to store.</param>
        public void AddRawResource(PageableResource resource, byte[] data)
        {
            if (resource == null)
            {
                throw new ArgumentNullException("resource");
            }

            resource.DisableChecksum();
            var cache = GetResourceCache(resource, out var location);

            using (var stream = OpenCacheReadWrite(location))
                resource.Page.Index = cache.AddRaw(stream, data);
        }
Пример #6
0
        /// <summary>
        /// Replaces a resource with raw, pre-compressed data.
        /// </summary>
        /// <param name="resource">The resource whose data should be replaced. On success, the reference will be adjusted to account for the new data.</param>
        /// <param name="data">The raw, pre-compressed data to use.</param>
        public void ReplaceRawResource(PageableResource resource, byte[] data)
        {
            if (resource == null)
            {
                throw new ArgumentNullException("resource");
            }

            resource.DisableChecksum();
            var cache = GetResourceCache(resource);

            using (var stream = cache.File.Open(FileMode.Open, FileAccess.ReadWrite))
                cache.Cache.ImportRaw(stream, resource.Page.Index, data);
        }
Пример #7
0
        /// <summary>
        /// Extracts and decompresses the data for a resource from the current cache.
        /// </summary>
        /// <param name="inStream"></param>
        /// <param name="pageable">The resource.</param>
        /// <param name="outStream">The stream to write the extracted data to.</param>
        /// <exception cref="System.ArgumentException">Thrown if the output stream is not open for writing.</exception>
        /// <exception cref="System.InvalidOperationException">Thrown if the file containing the resource has not been loaded.</exception>
        public void ExtractResource(Stream inStream, PageableResource pageable, Stream outStream)
        {
            if (pageable == null)
            {
                throw new ArgumentNullException("resource");
            }
            if (!outStream.CanWrite)
            {
                throw new ArgumentException("The output stream is not open for writing", "outStream");
            }

            var cache = GetResourceCache(pageable);

            cache.Cache.Decompress(inStream, pageable.Page.Index, pageable.Page.CompressedBlockSize, outStream);
        }
Пример #8
0
        /// <summary>
        /// Extracts and decompresses the data for a resource from the current cache.
        /// </summary>
        /// <param name="pageable">The resource.</param>
        /// <param name="outStream">The stream to write the extracted data to.</param>
        /// <exception cref="System.ArgumentException">Thrown if the output stream is not open for writing.</exception>
        /// <exception cref="System.InvalidOperationException">Thrown if the file containing the resource has not been loaded.</exception>
        public override void ExtractResource(PageableResource pageable, Stream outStream)
        {
            if (pageable == null)
            {
                throw new ArgumentNullException("resource");
            }
            if (!outStream.CanWrite)
            {
                throw new ArgumentException("The output stream is not open for writing", "outStream");
            }

            var cache = GetResourceCache(pageable);

            using (var stream = cache.File.OpenRead())
                cache.Cache.Decompress(stream, pageable.Page.Index, pageable.Page.CompressedBlockSize, outStream);
        }
Пример #9
0
        private PageableResource ConvertPageableResource(ModPackage modPack, PageableResource resource)
        {
            if (resource.Page.Index == -1)
            {
                return(resource);
            }

            var resourceStream = new MemoryStream();

            modPack.Resources.Decompress(modPack.ResourcesStream, resource.Page.Index, resource.Page.CompressedBlockSize, resourceStream);
            resourceStream.Position = 0;
            resource.ChangeLocation(ResourceLocation.ResourcesB);
            resource.Page.OldFlags &= ~OldRawPageFlags.InMods;
            CacheContext.ResourceCaches.AddResource(resource, resourceStream);

            return(resource);
        }
Пример #10
0
        private PageableResource ConvertResource(PageableResource resource, GameCacheContextHaloOnline srcCacheContext, GameCacheContextHaloOnline destCacheContext)
        {
            if (resource == null || resource.Page.Index < 0 || !resource.GetLocation(out var location))
            {
                return(null);
            }

            Console.WriteLine("- Copying resource {0} in {1}...", resource.Page.Index, location);

            var data        = srcCacheContext.ExtractRawResource(resource);
            var newLocation = FixResourceLocation(location, srcCacheContext.Version, destCacheContext.Version);

            resource.ChangeLocation(newLocation);
            destCacheContext.AddRawResource(resource, data);

            return(resource);
        }
        private TagResourceReference CreateResource <T>(T resourceDefinition, ResourceLocation location, TagResourceTypeGen3 resourceType)
        {
            var resourceReference = new TagResourceReference();
            var pageableResource  = new PageableResource();

            pageableResource.Page     = new ResourcePage();
            pageableResource.Resource = new ResourceData();
            pageableResource.ChangeLocation(location);
            pageableResource.Resource.Unknown2     = 1;
            pageableResource.Resource.ResourceType = resourceType;

            resourceReference.HaloOnlinePageableResource = pageableResource;

            var definitionStream = new MemoryStream();
            var dataStream       = new MemoryStream();

            using (var definitionWriter = new EndianWriter(definitionStream, EndianFormat.LittleEndian))
                using (var dataWriter = new EndianWriter(dataStream, EndianFormat.LittleEndian))
                {
                    var context    = new ResourceDefinitionSerializationContext(dataWriter, definitionWriter, CacheAddressType.Definition);
                    var serializer = new ResourceSerializer(Cache.Version);
                    serializer.Serialize(context, resourceDefinition);

                    var data           = dataStream.ToArray();
                    var definitionData = definitionStream.ToArray();
                    dataStream.Position = 0;

                    pageableResource.DisableChecksum();

                    dataStream.Position = 0;
                    AddResource(pageableResource, dataStream);

                    // add resource definition and fixups
                    pageableResource.Resource.DefinitionData    = definitionData;
                    pageableResource.Resource.FixupLocations    = context.FixupLocations;
                    pageableResource.Resource.DefinitionAddress = context.MainStructOffset;
                    pageableResource.Resource.InteropLocations  = context.InteropLocations;
                }
            return(resourceReference);
        }
Пример #12
0
        /// <summary>
        /// Compresses and replaces the data for a resource.
        /// </summary>
        /// <param name="resource">The resource whose data should be replaced. On success, the reference will be adjusted to account for the new data.</param>
        /// <param name="dataStream">The stream to read the new data from.</param>
        /// <exception cref="System.ArgumentException">Thrown if the input stream is not open for reading.</exception>
        public void ReplaceResource(PageableResource resource, Stream dataStream)
        {
            if (resource == null)
            {
                throw new ArgumentNullException("resource");
            }
            if (!dataStream.CanRead)
            {
                throw new ArgumentException("The input stream is not open for reading", "dataStream");
            }

            var cache = GetResourceCache(resource);

            using (var stream = cache.File.Open(FileMode.Open, FileAccess.ReadWrite))
            {
                var dataSize = (int)(dataStream.Length - dataStream.Position);
                var data     = new byte[dataSize];
                dataStream.Read(data, 0, dataSize);
                var compressedSize = cache.Cache.Compress(stream, resource.Page.Index, data);
                resource.Page.CompressedBlockSize   = compressedSize;
                resource.Page.UncompressedBlockSize = (uint)dataSize;
                resource.DisableChecksum();
            }
        }
        /// <summary>
        /// Adds a new pageable_resource to the current cache.
        /// </summary>
        /// <param name="resource">The pageable_resource to add.</param>
        /// <param name="dataStream">The stream to read the resource data from.</param>
        /// <exception cref="System.ArgumentNullException">resource</exception>
        /// <exception cref="System.ArgumentException">The input stream is not open for reading;dataStream</exception>
        public void AddResource(PageableResource resource, Stream dataStream)
        {
            if (resource == null)
            {
                throw new ArgumentNullException("resource");
            }
            if (!dataStream.CanRead)
            {
                throw new ArgumentException("The input stream is not open for reading", "dataStream");
            }

            var cache = GetResourceCache(resource, out var location);

            using (var stream = OpenCacheReadWrite(location))
            {
                var dataSize = (int)(dataStream.Length - dataStream.Position);
                var data     = new byte[dataSize];
                dataStream.Read(data, 0, dataSize);
                resource.Page.Index = cache.Add(stream, data, out uint compressedSize);
                resource.Page.CompressedBlockSize   = compressedSize;
                resource.Page.UncompressedBlockSize = (uint)dataSize;
                resource.DisableChecksum();
            }
        }
Пример #14
0
 public T Deserialize <T>(PageableResource pageable) =>
 Deserialize <T>(new ResourceSerializationContext(this, pageable));
Пример #15
0
        private void AddTags(HashSet <int> tagIndices)
        {
            using (var srcTagStream = CacheContext.OpenTagCacheRead())
            {
                var resourceIndices = new Dictionary <ResourceLocation, Dictionary <int, PageableResource> >
                {
                    [ResourceLocation.Audio]        = new Dictionary <int, PageableResource>(),
                    [ResourceLocation.Lightmaps]    = new Dictionary <int, PageableResource>(),
                    [ResourceLocation.Mods]         = new Dictionary <int, PageableResource>(),
                    [ResourceLocation.RenderModels] = new Dictionary <int, PageableResource>(),
                    [ResourceLocation.Resources]    = new Dictionary <int, PageableResource>(),
                    [ResourceLocation.ResourcesB]   = new Dictionary <int, PageableResource>(),
                    [ResourceLocation.Textures]     = new Dictionary <int, PageableResource>(),
                    [ResourceLocation.TexturesB]    = new Dictionary <int, PageableResource>()
                };

                var srcResourceCaches  = new Dictionary <ResourceLocation, ResourceCache>();
                var srcResourceStreams = new Dictionary <ResourceLocation, Stream>();

                foreach (var value in Enum.GetValues(typeof(ResourceLocation)))
                {
                    ResourceCache resourceCache = null;
                    var           location      = (ResourceLocation)value;

                    if (location == ResourceLocation.None)
                    {
                        continue;
                    }

                    try
                    {
                        resourceCache = CacheContext.GetResourceCache(location);
                    }
                    catch (FileNotFoundException)
                    {
                        continue;
                    }

                    srcResourceCaches[location]  = resourceCache;
                    srcResourceStreams[location] = CacheContext.OpenResourceCacheRead(location);
                }

                for (var tagIndex = 0; tagIndex < CacheContext.TagCache.Index.Count; tagIndex++)
                {
                    if (!tagIndices.Contains(tagIndex))
                    {
                        ModPackage.Tags.AllocateTag();
                        continue;
                    }

                    var srcTag  = CacheContext.GetTag(tagIndex);
                    var destTag = ModPackage.Tags.AllocateTag(srcTag.Group, srcTag.Name);

                    using (var tagDataStream = new MemoryStream(CacheContext.TagCache.ExtractTagRaw(srcTagStream, srcTag)))
                        using (var tagDataReader = new EndianReader(tagDataStream, leaveOpen: true))
                            using (var tagDataWriter = new EndianWriter(tagDataStream, leaveOpen: true))
                            {
                                var resourcePointerOffsets = new HashSet <uint>();

                                foreach (var resourcePointerOffset in srcTag.ResourcePointerOffsets)
                                {
                                    if (resourcePointerOffset == 0 || resourcePointerOffsets.Contains(resourcePointerOffset))
                                    {
                                        continue;
                                    }

                                    resourcePointerOffsets.Add(resourcePointerOffset);

                                    tagDataStream.Position = resourcePointerOffset;
                                    var resourcePointer = tagDataReader.ReadUInt32();

                                    if (resourcePointer == 0)
                                    {
                                        continue;
                                    }

                                    var resourceOffset = srcTag.PointerToOffset(resourcePointer);

                                    tagDataReader.BaseStream.Position = resourceOffset + 2;
                                    var locationFlags = (OldRawPageFlags)tagDataReader.ReadByte();

                                    var resourceLocation =
                                        locationFlags.HasFlag(OldRawPageFlags.InAudio) ?
                                        ResourceLocation.Audio :
                                        locationFlags.HasFlag(OldRawPageFlags.InResources) ?
                                        ResourceLocation.Resources :
                                        locationFlags.HasFlag(OldRawPageFlags.InResourcesB) ?
                                        ResourceLocation.ResourcesB :
                                        locationFlags.HasFlag(OldRawPageFlags.InTextures) ?
                                        ResourceLocation.Textures :
                                        locationFlags.HasFlag(OldRawPageFlags.InTexturesB) ?
                                        ResourceLocation.TexturesB :
                                        ResourceLocation.ResourcesB;

                                    tagDataReader.BaseStream.Position = resourceOffset + 4;
                                    var resourceIndex  = tagDataReader.ReadInt32();
                                    var compressedSize = tagDataReader.ReadUInt32();

                                    if (resourceIndex == -1)
                                    {
                                        continue;
                                    }

                                    PageableResource pageable = null;

                                    if (resourceIndices[resourceLocation].ContainsKey(resourceIndex))
                                    {
                                        pageable = resourceIndices[resourceLocation][resourceIndex];
                                    }
                                    else
                                    {
                                        var newResourceIndex = ModPackage.Resources.AddRaw(
                                            ModPackage.ResourcesStream,
                                            srcResourceCaches[resourceLocation].ExtractRaw(
                                                srcResourceStreams[resourceLocation],
                                                resourceIndex,
                                                compressedSize));

                                        pageable = resourceIndices[resourceLocation][resourceIndex] = new PageableResource
                                        {
                                            Page = new RawPage
                                            {
                                                OldFlags = OldRawPageFlags.InMods,
                                                Index    = newResourceIndex
                                            }
                                        };
                                    }

                                    tagDataReader.BaseStream.Position = resourceOffset + 2;
                                    tagDataWriter.Write((byte)pageable.Page.OldFlags);

                                    tagDataReader.BaseStream.Position = resourceOffset + 4;
                                    tagDataWriter.Write(pageable.Page.Index);
                                }

                                ModPackage.Tags.SetTagDataRaw(ModPackage.TagsStream, destTag, tagDataStream.ToArray());
                            }
                }

                ModPackage.Tags.UpdateTagOffsets(new BinaryWriter(ModPackage.TagsStream, Encoding.Default, true));
            }
        }
Пример #16
0
        private static bool ExtractResource(ScenarioStructureBsp Definition, HaloOnlineCacheContext CacheContext, IReadOnlyList <string> args)
        {
            if (args.Count < 1)
            {
                return(false);
            }

            var resourceType = "";
            var filePath     = "";
            var cachePath    = "resources.dat";

            resourceType = args[1].ToLower(); // geometry2
            filePath     = args[2];           // sc140_000_geometry2.raw

            PageableResource resource = null;

            switch (resourceType)
            {
            case "geometry":
                resource = Definition.Geometry.Resource;
                break;

            case "geometry2":
                resource = Definition.Geometry2.Resource;
                break;

            case "collisionbspresource":
                resource = Definition.CollisionBspResource;
                break;

            case "pathfindingresource":
                resource = Definition.PathfindingResource;
                break;

            default:
                Console.WriteLine($"Invalid sbsp resource type.");
                return(false);
            }

            if (resource == null || resource.Page.Index < 0 || !resource.GetLocation(out var location))
            {
                Console.WriteLine("Resource is null.");
                return(false);
            }

            try
            {
                using (var stream = File.OpenRead(CacheContext.TagCacheFile.DirectoryName + "\\" + cachePath))
                {
                    var cache = new ResourceCache(stream);
                    using (var outStream = File.Open(filePath, FileMode.Create, FileAccess.Write))
                    {
                        cache.Decompress(stream, resource.Page.Index, resource.Page.CompressedBlockSize, outStream);
                        Console.WriteLine("Wrote 0x{0:X} bytes to {1}.", outStream.Position, filePath);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed to extract resource: {0}", ex.Message);
            }

            return(true);
        }
Пример #17
0
        private PageableResource ConvertPageableResource(Stream sourceStream, Stream destStream, PageableResource resource)
        {
            if (resource.GetLocation(out var location) && location == ResourceLocation.ResourcesB)
            {
                resource.ChangeLocation(ResourceLocation.Resources);

                var resourceData = ResourcesB.ExtractRaw(sourceStream, resource.Page.Index, resource.Page.CompressedBlockSize);
                resource.Page.Index = Resources.AddRaw(destStream, resourceData);
            }

            return(resource);
        }
Пример #18
0
        private PageableResource ConvertPageableResource(ModPackageExtended sourceModPack, ModPackageExtended destModPack, PageableResource resource)
        {
            if (resource.Page.Index == -1)
            {
                return(resource);
            }

            var resourceData = sourceModPack.Resources.ExtractRaw(sourceModPack.ResourcesStream, resource.Page.Index, resource.Page.CompressedBlockSize);

            resource.Page.Index = destModPack.Resources.Add(destModPack.ResourcesStream, resourceData, out resource.Page.CompressedBlockSize);
            return(resource);
        }
Пример #19
0
        public override object Execute(List <string> args)
        {
            if (args.Count != 0)
            {
                return(false);
            }

            using (var cacheStream = CacheContext.OpenTagCacheReadWrite())
                using (var reader = new EndianReader(cacheStream))
                    using (var writer = new EndianWriter(cacheStream))
                    {
                        var retainedTags = new HashSet <int>();
                        LoadTagDependencies(CacheContext.TagCache.Index.FindFirstInGroup("cfgt").Index, ref retainedTags);

                        foreach (var scnr in CacheContext.TagCache.Index.FindAllInGroup("scnr"))
                        {
                            LoadTagDependencies(scnr.Index, ref retainedTags);
                        }

                        var resourceIndices = new Dictionary <ResourceLocation, Dictionary <int, PageableResource> >
                        {
                            [ResourceLocation.Audio]        = new Dictionary <int, PageableResource>(),
                            [ResourceLocation.Lightmaps]    = new Dictionary <int, PageableResource>(),
                            [ResourceLocation.RenderModels] = new Dictionary <int, PageableResource>(),
                            [ResourceLocation.Resources]    = new Dictionary <int, PageableResource>(),
                            [ResourceLocation.ResourcesB]   = new Dictionary <int, PageableResource>(),
                            [ResourceLocation.Textures]     = new Dictionary <int, PageableResource>(),
                            [ResourceLocation.TexturesB]    = new Dictionary <int, PageableResource>()
                        };

                        //
                        // Set up source resource caches
                        //

                        var srcResourceCaches  = new Dictionary <ResourceLocation, ResourceCache>();
                        var srcResourceStreams = new Dictionary <ResourceLocation, Stream>();

                        foreach (var value in Enum.GetValues(typeof(ResourceLocation)))
                        {
                            ResourceCache resourceCache = null;
                            var           location      = (ResourceLocation)value;

                            if (location == ResourceLocation.None)
                            {
                                continue;
                            }

                            try
                            {
                                resourceCache = CacheContext.GetResourceCache(location);
                            }
                            catch (FileNotFoundException)
                            {
                                continue;
                            }

                            srcResourceCaches[location]  = resourceCache;
                            srcResourceStreams[location] = CacheContext.OpenResourceCacheRead(location);
                        }

                        //
                        // Set up destination resource caches
                        //

                        var destDirectory       = new DirectoryInfo("new");
                        var destResourceCaches  = new Dictionary <ResourceLocation, ResourceCache>();
                        var destResourceStreams = new Dictionary <ResourceLocation, Stream>();

                        foreach (var entry in srcResourceStreams)
                        {
                            var resourceCache = CacheContext.CreateResourceCache(destDirectory, entry.Key);
                            destResourceCaches[entry.Key]  = resourceCache;
                            destResourceStreams[entry.Key] = File.Open(Path.Combine(destDirectory.FullName, CacheContext.ResourceCacheNames[entry.Key]), FileMode.Open, FileAccess.ReadWrite);
                        }

                        //
                        // Copy any used resources to the new resource caches
                        //

                        for (var i = 0; i < CacheContext.TagCache.Index.Count; i++)
                        {
                            var tag = CacheContext.TagCache.Index[i];

                            if (tag == null)
                            {
                                continue;
                            }

                            if (!retainedTags.Contains(i))
                            {
                                var tagName      = tag?.Name ?? $"0x{tag.Index:X4}";
                                var tagGroupName = CacheContext.GetString(tag.Group.Name);

                                Console.Write($"Nulling {tagName}.{tagGroupName}...");
                                CacheContext.TagCache.NullTag(cacheStream, tag);
                                Console.WriteLine("done.");

                                continue;
                            }

                            foreach (var resourcePointerOffset in tag.ResourcePointerOffsets)
                            {
                                reader.BaseStream.Position = tag.HeaderOffset + resourcePointerOffset;
                                var resourcePointer = reader.ReadUInt32();

                                if (resourcePointer == 0)
                                {
                                    continue;
                                }

                                var resourceOffset = tag.PointerToOffset(resourcePointer);

                                reader.BaseStream.Position = tag.HeaderOffset + resourceOffset + 2;
                                var locationFlags = (OldRawPageFlags)reader.ReadByte();

                                var resourceLocation =
                                    locationFlags.HasFlag(OldRawPageFlags.InAudio) ?
                                    ResourceLocation.Audio :
                                    locationFlags.HasFlag(OldRawPageFlags.InResources) ?
                                    ResourceLocation.Resources :
                                    locationFlags.HasFlag(OldRawPageFlags.InResourcesB) ?
                                    ResourceLocation.ResourcesB :
                                    locationFlags.HasFlag(OldRawPageFlags.InTextures) ?
                                    ResourceLocation.Textures :
                                    locationFlags.HasFlag(OldRawPageFlags.InTexturesB) ?
                                    ResourceLocation.TexturesB :
                                    ResourceLocation.ResourcesB;

                                reader.BaseStream.Position = tag.HeaderOffset + resourceOffset + 4;
                                var resourceIndex  = reader.ReadInt32();
                                var compressedSize = reader.ReadUInt32();

                                if (resourceIndex == -1)
                                {
                                    continue;
                                }

                                PageableResource pageable = null;

                                if (resourceIndices[resourceLocation].ContainsKey(resourceIndex))
                                {
                                    pageable = resourceIndices[resourceLocation][resourceIndex];
                                }
                                else
                                {
                                    var newResourceIndex = destResourceCaches[resourceLocation].AddRaw(
                                        destResourceStreams[resourceLocation],
                                        srcResourceCaches[resourceLocation].ExtractRaw(
                                            srcResourceStreams[resourceLocation],
                                            resourceIndex,
                                            compressedSize));

                                    pageable = resourceIndices[resourceLocation][resourceIndex] = new PageableResource
                                    {
                                        Page = new RawPage
                                        {
                                            OldFlags =
                                                resourceLocation == ResourceLocation.Audio ?
                                                OldRawPageFlags.InAudio :
                                                resourceLocation == ResourceLocation.Resources ?
                                                OldRawPageFlags.InResources :
                                                resourceLocation == ResourceLocation.Textures ?
                                                OldRawPageFlags.InTextures :
                                                resourceLocation == ResourceLocation.TexturesB ?
                                                OldRawPageFlags.InTexturesB :
                                                OldRawPageFlags.InResourcesB,
                                            Index = newResourceIndex
                                        }
                                    };
                                }

                                reader.BaseStream.Position = tag.HeaderOffset + resourceOffset + 2;
                                writer.Write((byte)pageable.Page.OldFlags);

                                reader.BaseStream.Position = tag.HeaderOffset + resourceOffset + 4;
                                writer.Write(pageable.Page.Index);
                            }
                        }

                        //
                        // Close resource streams
                        //

                        foreach (var entry in srcResourceStreams)
                        {
                            entry.Value.Close();
                        }

                        foreach (var entry in destResourceStreams)
                        {
                            entry.Value.Close();
                        }
                    }

            return(true);
        }
Пример #20
0
 /// <summary>
 /// Adds a new pageable_resource to the current cache.
 /// </summary>
 /// <param name="pageable">The <see cref="PageableResource"/> to add.</param>
 /// <param name="stream">The <see cref="Stream"/> to read the resource data from.</param>
 public abstract void AddResource(PageableResource pageable, Stream stream);
Пример #21
0
        private PageableResource ConvertBitmap(Bitmap bitmap, Dictionary <ResourceLocation, Stream> resourceStreams, int imageIndex, string tagName)
        {
            var        image      = bitmap.Images[imageIndex];
            BaseBitmap baseBitmap = BitmapConverter.ConvertGen3Bitmap(BlamCache, bitmap, imageIndex, BlamCache.Version);

            if (baseBitmap == null)
            {
                return(null);
            }

            // fix type enum
            if (baseBitmap.Type == BitmapType.Array)
            {
                baseBitmap.Type = BitmapType.Texture3D;
            }

            SetTagData(baseBitmap, image);
            var dataSize = baseBitmap.Data.Length;

            var resource = new PageableResource
            {
                Page     = new RawPage(),
                Resource = new TagResourceGen3
                {
                    ResourceFixups           = new List <TagResourceGen3.ResourceFixup>(),
                    ResourceDefinitionFixups = new List <TagResourceGen3.ResourceDefinitionFixup>(),
                    ResourceType             = TagResourceTypeGen3.Bitmap,
                    Unknown2 = 1
                }
            };

            using (var dataStream = new MemoryStream(baseBitmap.Data))
            {
                var bitmapResource = new Bitmap.BitmapResource
                {
                    Resource = resource,
                    Unknown4 = 0
                };
                var resourceContext = new ResourceSerializationContext(CacheContext, resource);

                // Create new definition
                var resourceDefinition = new BitmapTextureInteropResource
                {
                    Texture = new TagStructureReference <BitmapTextureInteropResource.BitmapDefinition>
                    {
                        Definition = new BitmapTextureInteropResource.BitmapDefinition
                        {
                            Data        = new TagData(),
                            UnknownData = new TagData(),
                        }
                    }
                };

                SetResourceDefinitionData(baseBitmap, image, resourceDefinition.Texture.Definition);

                //
                // Serialize the new resource definition
                //

                var location = bitmap.Usage == 2 ?
                               ResourceLocation.TexturesB : // bump maps
                               ResourceLocation.Textures;   // everything else

                resource.ChangeLocation(location);

                if (resource == null)
                {
                    throw new ArgumentNullException("resource");
                }

                if (!dataStream.CanRead)
                {
                    throw new ArgumentException("The input stream is not open for reading", "dataStream");
                }

                var cache = CacheContext.GetResourceCache(location);

                if (!resourceStreams.ContainsKey(location))
                {
                    resourceStreams[location] = FlagIsSet(PortingFlags.Memory) ?
                                                new MemoryStream() :
                                                (Stream)CacheContext.OpenResourceCacheReadWrite(location);

                    if (FlagIsSet(PortingFlags.Memory))
                    {
                        using (var resourceStream = CacheContext.OpenResourceCacheRead(location))
                            resourceStream.CopyTo(resourceStreams[location]);
                    }
                }

                dataSize = (int)(dataStream.Length - dataStream.Position);
                var data = new byte[dataSize];
                dataStream.Read(data, 0, dataSize);

                resource.Page.Index = cache.Add(resourceStreams[location], data, out uint compressedSize);
                resource.Page.CompressedBlockSize   = compressedSize;
                resource.Page.UncompressedBlockSize = (uint)dataSize;
                resource.DisableChecksum();

                CacheContext.Serializer.Serialize(resourceContext, resourceDefinition);
            }

            return(resource);
        }
Пример #22
0
        private void AddTags(HashSet <int> tagIndices)
        {
            // define current cache tags, names
            var modTagCache  = ModPackage.TagCaches[0];
            var modTagNames  = ModPackage.TagCacheNames[0];
            var modTagStream = ModPackage.TagCachesStreams[0];

            using (var srcTagStream = CacheContext.OpenCacheRead())
            {
                var resourceIndices = new Dictionary <ResourceLocation, Dictionary <int, PageableResource> >
                {
                    [ResourceLocation.Audio]        = new Dictionary <int, PageableResource>(),
                    [ResourceLocation.Lightmaps]    = new Dictionary <int, PageableResource>(),
                    [ResourceLocation.Mods]         = new Dictionary <int, PageableResource>(),
                    [ResourceLocation.RenderModels] = new Dictionary <int, PageableResource>(),
                    [ResourceLocation.Resources]    = new Dictionary <int, PageableResource>(),
                    [ResourceLocation.ResourcesB]   = new Dictionary <int, PageableResource>(),
                    [ResourceLocation.Textures]     = new Dictionary <int, PageableResource>(),
                    [ResourceLocation.TexturesB]    = new Dictionary <int, PageableResource>()
                };

                var srcResourceCaches  = new Dictionary <ResourceLocation, ResourceCacheHaloOnline>();
                var srcResourceStreams = new Dictionary <ResourceLocation, Stream>();

                foreach (var value in Enum.GetValues(typeof(ResourceLocation)))
                {
                    ResourceCacheHaloOnline resourceCache = null;
                    var location = (ResourceLocation)value;

                    if (location == ResourceLocation.None)
                    {
                        continue;
                    }

                    try
                    {
                        resourceCache = CacheContext.ResourceCaches.GetResourceCache(location);
                    }
                    catch (FileNotFoundException)
                    {
                        continue;
                    }

                    srcResourceCaches[location]  = resourceCache;
                    srcResourceStreams[location] = CacheContext.ResourceCaches.OpenCacheRead(location);
                }

                for (var tagIndex = 0; tagIndex < CacheContext.TagCache.Count; tagIndex++)
                {
                    var srcTag = CacheContext.TagCache.GetTag(tagIndex);

                    if (srcTag == null)
                    {
                        modTagCache.AllocateTag(new TagTool.Tags.TagGroup());
                        continue;
                    }

                    if (!tagIndices.Contains(tagIndex))
                    {
                        var emptyTag      = modTagCache.AllocateTag(srcTag.Group, srcTag.Name);
                        var cachedTagData = new CachedTagData();
                        cachedTagData.Data  = new byte[0];
                        cachedTagData.Group = emptyTag.Group;
                        modTagCache.SetTagData(modTagStream, (CachedTagHaloOnline)emptyTag, cachedTagData);
                        continue;
                    }

                    var destTag = modTagCache.AllocateTag(srcTag.Group, srcTag.Name);

                    using (var tagDataStream = new MemoryStream(CacheContext.TagCacheGenHO.ExtractTagRaw(srcTagStream, (CachedTagHaloOnline)srcTag)))
                        using (var tagDataReader = new EndianReader(tagDataStream, leaveOpen: true))
                            using (var tagDataWriter = new EndianWriter(tagDataStream, leaveOpen: true))
                            {
                                var resourcePointerOffsets = new HashSet <uint>();

                                foreach (var resourcePointerOffset in ((CachedTagHaloOnline)srcTag).ResourcePointerOffsets)
                                {
                                    if (resourcePointerOffset == 0 || resourcePointerOffsets.Contains(resourcePointerOffset))
                                    {
                                        continue;
                                    }

                                    resourcePointerOffsets.Add(resourcePointerOffset);

                                    tagDataStream.Position = resourcePointerOffset;
                                    var resourcePointer = tagDataReader.ReadUInt32();

                                    if (resourcePointer == 0)
                                    {
                                        continue;
                                    }

                                    var resourceOffset = ((CachedTagHaloOnline)srcTag).PointerToOffset(resourcePointer);

                                    tagDataReader.BaseStream.Position = resourceOffset + 2;
                                    var locationFlags = (OldRawPageFlags)tagDataReader.ReadByte();

                                    var resourceLocation =
                                        locationFlags.HasFlag(OldRawPageFlags.InAudio) ?
                                        ResourceLocation.Audio :
                                        locationFlags.HasFlag(OldRawPageFlags.InResources) ?
                                        ResourceLocation.Resources :
                                        locationFlags.HasFlag(OldRawPageFlags.InResourcesB) ?
                                        ResourceLocation.ResourcesB :
                                        locationFlags.HasFlag(OldRawPageFlags.InTextures) ?
                                        ResourceLocation.Textures :
                                        locationFlags.HasFlag(OldRawPageFlags.InTexturesB) ?
                                        ResourceLocation.TexturesB :
                                        ResourceLocation.ResourcesB;

                                    tagDataReader.BaseStream.Position = resourceOffset + 4;
                                    var resourceIndex  = tagDataReader.ReadInt32();
                                    var compressedSize = tagDataReader.ReadUInt32();

                                    if (resourceIndex == -1)
                                    {
                                        continue;
                                    }

                                    PageableResource pageable = null;

                                    if (resourceIndices[resourceLocation].ContainsKey(resourceIndex))
                                    {
                                        pageable = resourceIndices[resourceLocation][resourceIndex];
                                    }
                                    else
                                    {
                                        var newResourceIndex = ModPackage.Resources.AddRaw(
                                            ModPackage.ResourcesStream,
                                            srcResourceCaches[resourceLocation].ExtractRaw(
                                                srcResourceStreams[resourceLocation],
                                                resourceIndex,
                                                compressedSize));

                                        pageable = resourceIndices[resourceLocation][resourceIndex] = new PageableResource
                                        {
                                            Page = new ResourcePage
                                            {
                                                OldFlags = OldRawPageFlags.InMods,
                                                Index    = newResourceIndex
                                            }
                                        };
                                    }

                                    tagDataReader.BaseStream.Position = resourceOffset + 2;
                                    tagDataWriter.Write((byte)pageable.Page.OldFlags);

                                    tagDataReader.BaseStream.Position = resourceOffset + 4;
                                    tagDataWriter.Write(pageable.Page.Index);
                                }

                                modTagCache.SetTagDataRaw(modTagStream, (CachedTagHaloOnline)destTag, tagDataStream.ToArray());
                            }
                }

                foreach (var stream in srcResourceStreams.Values)
                {
                    if (stream != null)
                    {
                        stream.Dispose();
                    }
                }

                modTagCache.UpdateTagOffsets(new EndianWriter(modTagStream));
            }
        }
 public ResourceSerializationContext(GameCacheContext cacheContext, PageableResource resource)
 {
     CacheContext = cacheContext;
     Resource     = resource;
 }
Пример #24
0
 public void Serialize(PageableResource pageable, object definition) =>
 Serialize(new ResourceSerializationContext(this, pageable), definition);
Пример #25
0
        public override object Execute(List <string> args)
        {
            if (args.Count < 1 || args.Count > 5)
            {
                return(false);
            }

            bool   promptTags = false;
            bool   promptMaps = false;
            int?   fromIndex  = null;
            int?   toIndex    = null;
            string forCache   = null;

            while (args.Count != 1)
            {
                switch (args[0].ToLower())
                {
                case "prompttags":
                    promptTags = true;
                    args.RemoveRange(0, 1);
                    break;

                case "promptmaps":
                    promptMaps = true;
                    args.RemoveRange(0, 1);
                    break;

                case "from:":
                    if (CacheContext.TryGetTag(args[1], out var fromInstance) && fromInstance != null)
                    {
                        fromIndex = fromInstance.Index;
                    }
                    args.RemoveRange(0, 2);
                    break;

                case "to:":
                    if (CacheContext.TryGetTag(args[1], out var toInstance) && toInstance != null)
                    {
                        toIndex = toInstance.Index;
                    }
                    args.RemoveRange(0, 2);
                    break;

                case "forCache:":
                    forCache = args[1];
                    args.RemoveRange(0, 2);
                    break;

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

            if (!promptTags && !promptMaps && !fromIndex.HasValue && !toIndex.HasValue)
            {
                promptTags = true;
                promptMaps = true;
            }

            if (fromIndex.HasValue && !toIndex.HasValue)
            {
                toIndex = CacheContext.TagCache.Index.NonNull().Last().Index;
            }

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

            var    tagIndices = new HashSet <int>();
            var    mapFiles   = new HashSet <string>();
            string line       = null;

            if (fromIndex.HasValue && toIndex.HasValue)
            {
                foreach (var entry in Enumerable.Range(fromIndex.Value, toIndex.Value - fromIndex.Value))
                {
                    if (!tagIndices.Contains(entry) && CacheContext.GetTag(entry) != null)
                    {
                        tagIndices.Add(entry);
                    }
                }
            }

            if (promptTags)
            {
                Console.WriteLine("Please specify the tags to be used (enter an empty line to finish):");

                while ((line = Console.ReadLine().TrimStart().TrimEnd()) != "")
                {
                    if (CacheContext.TryGetTag(line, out var instance) && instance != null && !tagIndices.Contains(instance.Index))
                    {
                        tagIndices.Add(instance.Index);
                    }
                }
            }

            if (promptMaps)
            {
                Console.WriteLine("Please specify the .map files to be used (enter an empty line to finish):");

                while ((line = Console.ReadLine().TrimStart().TrimEnd()) != "")
                {
                    var mapFile = new FileInfo(line);

                    if (mapFile.Exists && mapFile.Extension == ".map" && !mapFiles.Contains(mapFile.FullName))
                    {
                        mapFiles.Add(mapFile.FullName);
                    }
                }
            }

            using (var srcTagStream = CacheContext.OpenTagCacheRead())
                using (var destTagsStream = new MemoryStream())
                    using (var destResourceStream = new MemoryStream())
                    {
                        var destTagCache      = CacheContext.CreateTagCache(destTagsStream);
                        var destResourceCache = CacheContext.CreateResourceCache(destResourceStream);

                        var resourceIndices = new Dictionary <ResourceLocation, Dictionary <int, PageableResource> >
                        {
                            [ResourceLocation.Audio]        = new Dictionary <int, PageableResource>(),
                            [ResourceLocation.Lightmaps]    = new Dictionary <int, PageableResource>(),
                            [ResourceLocation.Mods]         = new Dictionary <int, PageableResource>(),
                            [ResourceLocation.RenderModels] = new Dictionary <int, PageableResource>(),
                            [ResourceLocation.Resources]    = new Dictionary <int, PageableResource>(),
                            [ResourceLocation.ResourcesB]   = new Dictionary <int, PageableResource>(),
                            [ResourceLocation.Textures]     = new Dictionary <int, PageableResource>(),
                            [ResourceLocation.TexturesB]    = new Dictionary <int, PageableResource>()
                        };

                        var srcResourceCaches  = new Dictionary <ResourceLocation, ResourceCache>();
                        var srcResourceStreams = new Dictionary <ResourceLocation, Stream>();

                        foreach (var value in Enum.GetValues(typeof(ResourceLocation)))
                        {
                            ResourceCache resourceCache = null;
                            var           location      = (ResourceLocation)value;

                            if (location == ResourceLocation.None)
                            {
                                continue;
                            }

                            try
                            {
                                resourceCache = CacheContext.GetResourceCache(location);
                            }
                            catch (FileNotFoundException)
                            {
                                continue;
                            }

                            srcResourceCaches[location]  = resourceCache;
                            srcResourceStreams[location] = CacheContext.OpenResourceCacheRead(location);
                        }

                        for (var tagIndex = 0; tagIndex < CacheContext.TagCache.Index.Count; tagIndex++)
                        {
                            if (!tagIndices.Contains(tagIndex))
                            {
                                destTagCache.AllocateTag();
                                continue;
                            }

                            var srcTag  = CacheContext.GetTag(tagIndex);
                            var destTag = destTagCache.AllocateTag(srcTag.Group, srcTag.Name);

                            using (var tagDataStream = new MemoryStream(CacheContext.TagCache.ExtractTagRaw(srcTagStream, srcTag)))
                                using (var tagDataReader = new EndianReader(tagDataStream))
                                    using (var tagDataWriter = new EndianWriter(tagDataStream))
                                    {
                                        var resourcePointerOffsets = new HashSet <uint>();

                                        foreach (var resourcePointerOffset in srcTag.ResourcePointerOffsets)
                                        {
                                            if (resourcePointerOffset == 0 || resourcePointerOffsets.Contains(resourcePointerOffset))
                                            {
                                                continue;
                                            }

                                            resourcePointerOffsets.Add(resourcePointerOffset);

                                            tagDataStream.Position = resourcePointerOffset;
                                            var resourcePointer = tagDataReader.ReadUInt32();

                                            if (resourcePointer == 0)
                                            {
                                                continue;
                                            }

                                            var resourceOffset = srcTag.PointerToOffset(resourcePointer);

                                            tagDataReader.BaseStream.Position = resourceOffset + 2;
                                            var locationFlags = (OldRawPageFlags)tagDataReader.ReadByte();

                                            var resourceLocation =
                                                locationFlags.HasFlag(OldRawPageFlags.InAudio) ?
                                                ResourceLocation.Audio :
                                                locationFlags.HasFlag(OldRawPageFlags.InResources) ?
                                                ResourceLocation.Resources :
                                                locationFlags.HasFlag(OldRawPageFlags.InResourcesB) ?
                                                ResourceLocation.ResourcesB :
                                                locationFlags.HasFlag(OldRawPageFlags.InTextures) ?
                                                ResourceLocation.Textures :
                                                locationFlags.HasFlag(OldRawPageFlags.InTexturesB) ?
                                                ResourceLocation.TexturesB :
                                                ResourceLocation.ResourcesB;

                                            tagDataReader.BaseStream.Position = resourceOffset + 4;
                                            var resourceIndex  = tagDataReader.ReadInt32();
                                            var compressedSize = tagDataReader.ReadUInt32();

                                            if (resourceIndex == -1)
                                            {
                                                continue;
                                            }

                                            PageableResource pageable = null;

                                            if (resourceIndices[resourceLocation].ContainsKey(resourceIndex))
                                            {
                                                pageable = resourceIndices[resourceLocation][resourceIndex];
                                            }
                                            else
                                            {
                                                var newResourceIndex = destResourceCache.AddRaw(
                                                    destResourceStream,
                                                    srcResourceCaches[resourceLocation].ExtractRaw(
                                                        srcResourceStreams[resourceLocation],
                                                        resourceIndex,
                                                        compressedSize));

                                                pageable = resourceIndices[resourceLocation][resourceIndex] = new PageableResource
                                                {
                                                    Page = new RawPage
                                                    {
                                                        OldFlags = OldRawPageFlags.InMods,
                                                        Index    = newResourceIndex
                                                    }
                                                };
                                            }

                                            tagDataReader.BaseStream.Position = resourceOffset + 2;
                                            tagDataWriter.Write((byte)pageable.Page.OldFlags);

                                            tagDataReader.BaseStream.Position = resourceOffset + 4;
                                            tagDataWriter.Write(pageable.Page.Index);
                                        }

                                        destTagCache.SetTagDataRaw(destTagsStream, destTag, tagDataStream.ToArray());
                                    }
                        }

                        destTagCache.UpdateTagOffsets(new BinaryWriter(destTagsStream, Encoding.Default, true));

                        if (!packageFile.Directory.Exists)
                        {
                            packageFile.Directory.Create();
                        }

                        using (var packageStream = packageFile.Create())
                            using (var writer = new BinaryWriter(packageStream))
                            {
                                //
                                // reserve header space
                                //

                                writer.Write(new byte[48]);

                                //
                                // write tag cache
                                //

                                var tagCacheOffset = (uint)packageStream.Position;

                                destTagsStream.Position = 0;
                                StreamUtil.Copy(destTagsStream, packageStream, (int)destTagsStream.Length);
                                StreamUtil.Align(packageStream, 4);

                                //
                                // write tag names table
                                //

                                var names = new Dictionary <int, string>();

                                foreach (var entry in destTagCache.Index)
                                {
                                    if (entry != null && entry.Name != null)
                                    {
                                        names[entry.Index] = entry.Name;
                                    }
                                }

                                var tagNamesTableOffset = (uint)packageStream.Position;
                                var tagNamesTableCount  = names.Count;

                                foreach (var entry in names)
                                {
                                    writer.Write(entry.Key);

                                    var chars = new char[256];

                                    for (var i = 0; i < entry.Value.Length; i++)
                                    {
                                        chars[i] = entry.Value[i];
                                    }

                                    writer.Write(chars);
                                }

                                //
                                // write resource cache
                                //

                                var resourceCacheOffset = (uint)packageStream.Position;

                                destResourceStream.Position = 0;
                                StreamUtil.Copy(destResourceStream, packageStream, (int)destResourceStream.Length);
                                StreamUtil.Align(packageStream, 4);

                                //
                                // write map file table
                                //

                                var mapFileTableOffset = (uint)packageStream.Position;
                                var mapFileTableCount  = mapFiles.Count;

                                var mapFileInfo = new List <(uint, uint)>();
                                writer.Write(new byte[8 * mapFileTableCount]);

                                foreach (var entry in mapFiles)
                                {
                                    var mapFile = new FileInfo(entry);

                                    using (var mapFileStream = mapFile.OpenRead())
                                    {
                                        mapFileInfo.Add(((uint)packageStream.Position, (uint)mapFileStream.Length));
                                        StreamUtil.Copy(mapFileStream, packageStream, (int)mapFileStream.Length);
                                        StreamUtil.Align(packageStream, 4);
                                    }
                                }

                                packageStream.Position = mapFileTableOffset;

                                foreach (var entry in mapFileInfo)
                                {
                                    writer.Write(entry.Item1);
                                    writer.Write(entry.Item2);
                                }

                                //
                                // calculate package sha1
                                //

                                packageStream.Position = 48;
                                var packageSha1 = new SHA1Managed().ComputeHash(packageStream);

                                //
                                // update package header
                                //

                                packageStream.Position = 0;

                                writer.Write(new Tag("mod!"));
                                writer.Write(packageSha1);
                                writer.Write(tagCacheOffset);
                                writer.Write(tagNamesTableCount == 0 ? 0 : tagNamesTableOffset);
                                writer.Write(tagNamesTableCount);
                                writer.Write(resourceCacheOffset);
                                writer.Write(mapFileTableCount == 0 ? 0 : mapFileTableOffset);
                                writer.Write(mapFileTableCount);
                            }
                    }

            return(true);
        }
Пример #26
0
        public void InjectDds(TagSerializer serializer, TagDeserializer deserializer, Bitmap bitmap, int imageIndex, Stream ddsStream, ResourceLocation location = ResourceLocation.Textures)
        {
            var resource    = bitmap.Resources[imageIndex].Resource;
            var newResource = (resource == null);
            ResourceSerializationContext resourceContext;
            BitmapTextureInteropResource definition;

            if (newResource)
            {
                // Create a new resource reference
                resource = new PageableResource
                {
                    Page     = new RawPage(),
                    Resource = new TagResourceGen3
                    {
                        ResourceFixups           = new List <TagResourceGen3.ResourceFixup>(),
                        ResourceDefinitionFixups = new List <TagResourceGen3.ResourceDefinitionFixup>(),
                        ResourceType             = TagResourceTypeGen3.Bitmap,
                        Unknown2 = 1
                    }
                };

                bitmap.Resources[imageIndex].Resource = resource;
                resourceContext = new ResourceSerializationContext(CacheContext, resource);
                definition      = new BitmapTextureInteropResource
                {
                    Texture = new TagStructureReference <BitmapTextureInteropResource.BitmapDefinition>
                    {
                        Definition = new BitmapTextureInteropResource.BitmapDefinition
                        {
                            Data        = new TagData(),
                            UnknownData = new TagData(),
                        }
                    }
                };
            }
            else
            {
                // Deserialize the old definition
                resourceContext = new ResourceSerializationContext(CacheContext, resource);
                definition      = deserializer.Deserialize <BitmapTextureInteropResource>(resourceContext);
            }
            if (definition.Texture == null || definition.Texture.Definition == null)
            {
                throw new ArgumentException("Invalid bitmap definition");
            }
            var texture   = definition.Texture.Definition;
            var imageData = bitmap.Images[imageIndex];

            // Read the DDS header and modify the definition to match
            var dds      = DdsHeader.Read(ddsStream);
            var dataSize = (int)(ddsStream.Length - ddsStream.Position);

            texture.Data        = new TagData(dataSize, new CacheResourceAddress(CacheResourceAddressType.Resource, 0));
            texture.Width       = (short)dds.Width;
            texture.Height      = (short)dds.Height;
            texture.Depth       = (sbyte)Math.Max(1, dds.Depth);
            texture.MipmapCount = (sbyte)Math.Max(1, dds.MipMapCount);
            texture.Type        = BitmapDdsFormatDetection.DetectType(dds);
            texture.D3DFormat   = (int)((dds.D3D10Format != DxgiFormat.Bc5UNorm) ? dds.FourCc : DdsFourCc.FromString("ATI2"));
            texture.Format      = BitmapDdsFormatDetection.DetectFormat(dds);

            // Set flags based on the format
            switch (texture.Format)
            {
            case BitmapFormat.Dxt1:
            case BitmapFormat.Dxt3:
            case BitmapFormat.Dxt5:
            case BitmapFormat.Dxn:
                texture.Flags = BitmapFlags.Compressed;
                break;

            default:
                texture.Flags = BitmapFlags.None;
                break;
            }
            if ((texture.Width & (texture.Width - 1)) == 0 && (texture.Height & (texture.Height - 1)) == 0)
            {
                texture.Flags |= BitmapFlags.PowerOfTwoDimensions;
            }

            // If creating a new image, then add a new resource, otherwise replace the existing one
            if (newResource)
            {
                resource.ChangeLocation(location);
                CacheContext.AddResource(resource, ddsStream);
            }
            else
            {
                CacheContext.ReplaceResource(resource, ddsStream);
            }

            // Serialize the new resource definition
            serializer.Serialize(resourceContext, definition);

            // Modify the image data in the bitmap tag to match the definition
            imageData.Width       = texture.Width;
            imageData.Height      = texture.Height;
            imageData.Depth       = texture.Depth;
            imageData.Type        = texture.Type;
            imageData.Format      = texture.Format;
            imageData.Flags       = texture.Flags;
            imageData.MipmapCount = (sbyte)(texture.MipmapCount - 1);
            imageData.DataOffset  = texture.Data.Address.Offset;
            imageData.DataSize    = texture.Data.Size;
            imageData.Curve       = (BitmapImageCurve)texture.Curve;
        }
Пример #27
0
 /// <summary>
 /// Extracts and decompresses the data for a <see cref="PageableResource"/> from the current cache.
 /// </summary>
 /// <param name="resource">The <see cref="PageableResource"/> to extract.</param>
 /// <param name="stream">The <see cref="Stream"/> to write the extracted data to.</param>
 public abstract void ExtractResource(PageableResource resource, Stream stream);