예제 #1
0
        /// <summary>
        /// Decode the volume resource map.
        /// </summary>
        /// <param name="data">Resource map data.</param>
        /// <param name="startOffset">Start offset in resource map data.</param>
        /// <param name="length">Length of resource map data (in bytes).</param>
        /// <param name="resourceMapEntries">Resource map entry collection to add decoded entries to.</param>
        internal static void ReadResourceMap(byte[] data, int startOffset, int length, VolumeResourceMapEntryCollection resourceMapEntries)
        {
            int count = length / 3;

            if (count > 255)
            {
                // There can't be more than 255 resources for a particular type of resource
                // If the resource map is longer than that, it is probably padded with junk
                count = 255;
            }

            for (int index = 0; index < count; index++)
            {
                int dataOffset = startOffset + (index * 3);

                byte b0 = data[dataOffset + 0];
                byte b1 = data[dataOffset + 1];
                byte b2 = data[dataOffset + 2];

                // [0][1][2] = volume file number and position in that volume file
                // [0] = 76543210   [1] = 76543210   [2] = 76543210
                // [0] = VVVVPPPP   [1] = PPPPPPPP   [2] = PPPPPPPP

                // When all three bytes are 0xff it means the resource doesn't exist
                if (!(b0 == 0xff && b1 == 0xff && b2 == 0xff))
                {
                    int volume    = (b0 & 0xf0) >> 4;
                    int resOffset = ((b0 & 0x0f) * 0x10000) + (b1 * 0x100) + b2;

                    var entry = new VolumeResourceMapEntry((byte)index, (byte)volume, resOffset);
                    resourceMapEntries.Add(entry);
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Extract the resource from the volume.
        /// </summary>
        /// <param name="container">Game container.</param>
        /// <param name="fileName">Volume file name.</param>
        /// <param name="dirEntry">Resource map entry for the resource to extract.</param>
        /// <param name="wasCompressed">Resource was compressed in the volume, so it was decompressed.</param>
        /// <returns>Binary data for the resource.  This is always uncompressed.  If the data is compressed in the volume, the volume decoder must decompress it.</returns>
        byte[] IVolumeDecoder.ExtractResource(IGameContainer container, string fileName, VolumeResourceMapEntry dirEntry, out bool wasCompressed)
        {
            if (container == null)
            {
                throw new ArgumentNullException(nameof(container));
            }

            if (fileName == null)
            {
                throw new ArgumentNullException(nameof(fileName));
            }

            if (fileName.Length == 0)
            {
                throw new ArgumentException(Errors.FilePathEmpty, nameof(fileName));
            }

            if (dirEntry == null)
            {
                throw new ArgumentNullException(nameof(dirEntry));
            }

            byte[] volumeData = container.Read(fileName);

            if (dirEntry.Offset >= volumeData.Length)
            {
                throw new VolumeDecoderInvalidResourceOffsetException();
            }

            return(VolumeDecoderV3.ExtractResource(volumeData, dirEntry.Offset, out wasCompressed));
        }