Beispiel #1
0
        public void Dispose()
        {
            if (!this.IsDirty)
            {
                this.stream?.Dispose();

                return;
            }

            var strings = this.entries.Select(entry => new[] { entry.Folder, entry.File }).SelectMany(s => s).Distinct().ToArray();

            using var stream = new MemoryStream();
            using var writer = new BinaryWriter(stream);

            // Header

            writer.Write(Idx.MagicHeader);
            writer.Write(Idx.Version);
            writer.Write(this.entries.Count());

            // Strings

            writer.Write(Idx.MagicSector);
            writer.Write(strings.Length);
            writer.Write(strings.Sum(s => s.Length + 1));

            foreach (var s in strings)
            {
                writer.Write(Encoding.ASCII.GetBytes(s));
                writer.Write((byte)0x00);
            }

            // StringInfos

            writer.Write(Idx.MagicSector);

            foreach (var s in strings)
            {
                writer.Write((short)s.Length);
                writer.Write(Idx.Hash(s));
            }

            // FileInfos

            writer.Write(Idx.MagicSector);

            foreach (var entry in this.entries)
            {
                entry.Write(writer, strings);
            }

            // Save the file.

            var data = stream.GetBuffer().Take((int)stream.Position).ToArray();

            Encryption.Encrypt(data);

            this.stream.Position = 0;
            this.stream.Write(data);
            this.stream.SetLength(data.Length);

            this.stream?.Dispose();
        }
Beispiel #2
0
        private void Read()
        {
            this.stream.Position = 0;

            var data = new byte[this.stream.Length];

            this.stream.Read(data);
            Encryption.Decrypt(data);

            using var stream = new MemoryStream(data);
            using var reader = new BinaryReader(stream);

            // Header

            if (!reader.ReadChars(4).SequenceEqual(Idx.MagicHeader))
            {
                throw new Exception("IDX.Header: Wrong identifier!");
            }

            if (reader.ReadInt32() != Idx.Version)
            {
                throw new Exception("IDX.header: Wrong version!");
            }

            var numFiles = reader.ReadInt32();

            // Strings

            if (!reader.ReadChars(4).SequenceEqual(Idx.MagicSector))
            {
                throw new Exception("IDX.Strings: Wrong identifier!");
            }

            var numStrings = reader.ReadInt32();
            var dataLength = reader.ReadInt32();

            var position = stream.Position;

            var strings = new string[numStrings];

            for (var i = 0; i < numStrings; i++)
            {
                var characters = new List <char>();

                while (true)
                {
                    var character = reader.ReadChar();

                    if (character == 0x00)
                    {
                        strings[i] = new string(characters.ToArray());

                        break;
                    }

                    characters.Add(character);
                }
            }

            if (stream.Position != position + dataLength)
            {
                throw new Exception("IDX.Strings: Wrong dataLength!");
            }

            // StringInfos

            if (!reader.ReadChars(4).SequenceEqual(Idx.MagicSector))
            {
                throw new Exception("IDX.StringInfos: Wrong identifier!");
            }

            for (var i = 0; i < numStrings; i++)
            {
                if (reader.ReadInt16() != strings[i].Length)
                {
                    throw new Exception("IDX.StringInfos: Wrong length!");
                }

                if (reader.ReadInt32() != Idx.Hash(strings[i]))
                {
                    throw new Exception("IDX.StringInfos: Wrong hash!");
                }
            }

            // FileInfos

            if (!reader.ReadChars(4).SequenceEqual(Idx.MagicSector))
            {
                throw new Exception("IDX.FileInfos: Wrong identifier!");
            }

            for (var i = 0; i < numFiles; i++)
            {
                // TODO some containers have duplicate paths. verify the load order and store only the valid one.
                this.entries.Add(new IdxEntry(reader, strings));
            }

            // TODO happens when a new patch is applied. Launching the game once will fix the idx file. We should support this too.
            if (stream.Position < stream.Length)
            {
                throw new Exception("IDX: Data at the end!");
            }
        }