Example #1
0
        private static byte[] LoadArrayBytes(Stream input, ArrayHeader array, int itemSize, bool validate)
        {
            byte[] bytes;

            if (array.Count == 0)
            {
                bytes = Array.Empty <byte>();
            }
            else
            {
                var size = array.Count * itemSize;
                if (size > int.MaxValue)
                {
                    throw new FormatException();
                }
                input.Position = array.Offset;
                bytes          = input.ReadBytes((int)size);
            }

            if (validate == true)
            {
                var actualHash = CRC32.Compute(bytes, 0, bytes.Length);
                if (actualHash != array.Hash)
                {
                    throw new FormatException($"array hash mismatch: {actualHash:X8} vs {array.Hash:X8}");
                }
            }

            return(bytes);
        }
Example #2
0
        public static CacheFile Load(Stream input, bool validate)
        {
            var         headerBytes = input.ReadBytes(FileHeader.Size + CacheHeader.Size);
            Endian      endian;
            CacheHeader header;

            using (var data = new MemoryStream(headerBytes, false))
            {
                var fileHeader = FileHeader.Read(data);
                if (fileHeader.Version != 13 || fileHeader.Unknown != 0)
                {
                    throw new FormatException();
                }

                endian = fileHeader.Endian;
                header = CacheHeader.Read(data, endian);
            }

            if (validate == true)
            {
                var deadbeefBytes = BitConverter.GetBytes(0xDEADBEEFu);
                Array.Copy(deadbeefBytes, 0, headerBytes, FileHeader.Size + CacheHeader.HashOffset, 4);

                if (CRC32.Compute(headerBytes, 0, headerBytes.Length) != header.HeaderHash)
                {
                    throw new FormatException();
                }
            }

            var stringBytes = LoadArrayBytes(input, header.StringData, 1, validate);

            string[] names, tweakDBIds, resources;
            using (var data = new MemoryStream(stringBytes, false))
            {
                names      = LoadStrings(input, header.NameStringOffsets, validate, data, endian);
                tweakDBIds = LoadStrings(input, header.TweakDBIdStringOffsets, validate, data, endian);
                resources  = LoadStrings(input, header.ResourceStringOffsets, validate, data, endian);
            }

            var definitionHeaders = LoadArray(input, header.Definitions, DefinitionHeader.Size, validate, DefinitionHeader.Read, endian);
            var definitions       = new Definition[definitionHeaders.Length];

            for (int i = 1; i < definitionHeaders.Length; i++)
            {
                definitions[i] = DefinitionFactory.Create(definitionHeaders[i].Type);
            }
            for (int i = 1; i < definitionHeaders.Length; i++)
            {
                var definitionHeader = definitionHeaders[i];
                var definition       = definitions[i];
                definition.Parent = definitions[definitionHeader.ParentIndex];
                definition.Name   = names[definitionHeader.NameIndex];
            }
            var reader = new DefinitionReader(input, endian, definitions, names, tweakDBIds, resources);

            for (int i = 1; i < definitionHeaders.Length; i++)
            {
                var definitionHeader = definitionHeaders[i];
                var definition       = definitions[i];

                input.Position = definitionHeader.DataOffset;

                definition.LoadPosition = input.Position;

                if (validate == true)
                {
                    using (var data = input.ReadToMemoryStream((int)definitionHeader.DataSize))
                    {
                        var slicedReader = new DefinitionReader(data, endian, definitions, names, tweakDBIds, resources);
                        definition.Deserialize(slicedReader);
                        if (data.Position != data.Length)
                        {
                            throw new FormatException();
                        }
                    }
                }
                else
                {
                    var expectedPosition = input.Position + definitionHeader.DataSize;
                    definition.Deserialize(reader);
                    if (input.Position != expectedPosition)
                    {
                        throw new FormatException();
                    }
                }
            }

            var instance = new CacheFile();

            instance.Unknown00 = header.Unknown00;
            instance.Unknown04 = header.Unknown04;
            instance.Unknown08 = header.Unknown08;
            instance.Unknown10 = header.Unknown10;
            instance.Definitions.AddRange(definitions.Skip(1));
            return(instance);
        }