public void Deserialize(Stream input)
        {
            var basePosition = input.Position;

            var magic = input.ReadValueU32(Endian.Little);

            if (magic != Signature && magic.Swap() != Signature)
            {
                throw new FormatException();
            }
            var endian = magic == Signature ? Endian.Little : Endian.Big;

            var version = input.ReadValueU32(endian);

            if (version != 4)
            {
                throw new FormatException();
            }

            var instanceCount        = input.ReadValueU32(endian);
            var instanceOffset       = input.ReadValueU32(endian);
            var typeDefinitionCount  = input.ReadValueU32(endian);
            var typeDefinitionOffset = input.ReadValueU32(endian);
            var stringHashCount      = input.ReadValueU32(endian);
            var stringHashOffset     = input.ReadValueU32(endian);
            var nameTableCount       = input.ReadValueU32(endian);
            var nameTableOffset      = input.ReadValueU32(endian);
            var totalSize            = input.ReadValueU32(endian);
            var unknown2C            = input.ReadValueU32(endian);
            var unknown30            = input.ReadValueU32(endian);
            var unknown34            = input.ReadValueU32(endian);
            var unknown38            = input.ReadValueU32(endian);
            var unknown3C            = input.ReadValueU32(endian);
            var comment = input.ReadStringZ(Encoding.ASCII);

            if (unknown2C != 0 || unknown30 != 0 || unknown34 != 0 || unknown38 != 0 || unknown3C != 0)
            {
                throw new FormatException();
            }

            if (basePosition + totalSize > input.Length)
            {
                throw new EndOfStreamException();
            }

            var rawNames = new string[nameTableCount];

            if (nameTableCount > 0)
            {
                input.Position = basePosition + nameTableOffset;
                var nameLengths = new byte[nameTableCount];
                for (uint i = 0; i < nameTableCount; i++)
                {
                    nameLengths[i] = input.ReadValueU8();
                }
                for (uint i = 0; i < nameTableCount; i++)
                {
                    rawNames[i] = input.ReadString(nameLengths[i], true, Encoding.ASCII);
                    input.Seek(1, SeekOrigin.Current);
                }
            }
            var names = new StringTable(rawNames);

            var typeDefinitions = new TypeDefinition[typeDefinitionCount];

            if (typeDefinitionCount > 0)
            {
                input.Position = basePosition + typeDefinitionOffset;
                for (uint i = 0; i < typeDefinitionCount; i++)
                {
                    typeDefinitions[i] = TypeDefinition.Read(input, endian, names);
                }
            }

            var instanceInfos = new InstanceInfo[instanceCount];

            if (instanceCount > 0)
            {
                input.Position = basePosition + instanceOffset;
                for (uint i = 0; i < instanceCount; i++)
                {
                    instanceInfos[i] = InstanceInfo.Read(input, endian, names);
                }
            }

            var stringHashInfos = new StringHashInfo[stringHashCount];

            if (stringHashCount > 0)
            {
                input.Position = basePosition + stringHashOffset;
                for (uint i = 0; i < stringHashCount; i++)
                {
                    stringHashInfos[i] = StringHashInfo.Read(input, endian);
                }
            }

            this._Endian  = endian;
            this._Comment = comment;
            this._TypeDefinitions.Clear();
            this._TypeDefinitions.AddRange(typeDefinitions);
            this._InstanceInfos.Clear();
            this._InstanceInfos.AddRange(instanceInfos);
            this._StringHashInfos.Clear();
            this._StringHashInfos.AddRange(stringHashInfos);
        }