public void Deserialize(Stream input)
        {
            this.DosHeader = input.ReadStructure <Image.DosHeader>();
            if (this.DosHeader.Magic != 0x5A4D) // MZ
            {
                throw new FormatException("dos header has bad magic");
            }

            input.Seek(this.DosHeader.NewExeOffset, SeekOrigin.Begin);
            this.NTHeaders32 = input.ReadStructure <Image.NTHeaders32>();
            if (this.NTHeaders32.Signature != 0x4550 || this.NTHeaders32.FileHeader.SizeOfOptionalHeader != 0xE0) // PE
            {
                throw new FormatException("nt header has bad signature");
            }
            else if (this.NTHeaders32.OptionalHeader.Magic != 0x10B) // IMAGE_NT_OPTIONAL_HDR32_MAGIC
            {
                throw new FormatException("optional header has bad magic");
            }

            this.Directories = new List <Image.DataDirectory>();
            for (int i = 0; i < this.NTHeaders32.OptionalHeader.NumberOfRvaAndSizes; i++)
            {
                this.Directories.Add(input.ReadStructure <Image.DataDirectory>());
            }

            this.Sections = new List <Image.SectionHeader>();
            for (int i = 0; i < this.NTHeaders32.FileHeader.NumberOfSections; i++)
            {
                this.Sections.Add(input.ReadStructure <Image.SectionHeader>());
            }

            this.Exports     = new Dictionary <UInt32, UInt32>();
            this.ExportNames = new Dictionary <string, UInt32>();

            if (
                this.Directories.Count >= 1 &&
                this.Directories[0].VirtualAddress != 0 &&
                this.Directories[0].Size != 0)
            {
                var fileOffset = this.GetFileOffset(this.Directories[0].VirtualAddress, true);

                input.Seek(fileOffset, SeekOrigin.Begin);
                Image.ExportDirectory exportDirectory = input.ReadStructure <Image.ExportDirectory>();

                if (exportDirectory.NumberOfNames > 0)
                {
                    var nameOffsets = new UInt32[exportDirectory.NumberOfNames];
                    var names       = new string[exportDirectory.NumberOfNames];
                    var ordinals    = new UInt16[exportDirectory.NumberOfNames];

                    input.Seek(this.GetFileOffset(exportDirectory.AddressOfNames, true), SeekOrigin.Begin);
                    for (uint i = 0; i < exportDirectory.NumberOfNames; i++)
                    {
                        nameOffsets[i] = input.ReadValueU32();
                    }

                    input.Seek(this.GetFileOffset(exportDirectory.AddressOfNameOrdinals, true), SeekOrigin.Begin);
                    for (uint i = 0; i < exportDirectory.NumberOfNames; i++)
                    {
                        ordinals[i] = input.ReadValueU16();
                    }

                    for (uint i = 0; i < exportDirectory.NumberOfNames; i++)
                    {
                        input.Seek(this.GetFileOffset(nameOffsets[i], true), SeekOrigin.Begin);
                        var name = input.ReadStringZ(Encoding.ASCII);
                        this.ExportNames.Add(name, exportDirectory.Base + ordinals[i]);
                    }
                }

                if (exportDirectory.NumberOfFunctions > 0)
                {
                    input.Seek(this.GetFileOffset(exportDirectory.AddressOfFunctions, true), SeekOrigin.Begin);

                    for (uint i = 0; i < exportDirectory.NumberOfFunctions; i++)
                    {
                        var address = input.ReadValueU32();
                        if (address == 0)
                        {
                            continue;
                        }

                        this.Exports.Add(exportDirectory.Base + i, address);
                    }
                }
            }
        }
        public void Deserialize(Stream input)
        {
            this.DosHeader = input.ReadStructure<Image.DosHeader>();
            if (this.DosHeader.Magic != 0x5A4D) // MZ
            {
                throw new FormatException("dos header has bad magic");
            }

            input.Seek(this.DosHeader.NewExeOffset, SeekOrigin.Begin);
            this.NTHeaders32 = input.ReadStructure<Image.NTHeaders32>();
            if (this.NTHeaders32.Signature != 0x4550 || this.NTHeaders32.FileHeader.SizeOfOptionalHeader != 0xE0) // PE
            {
                throw new FormatException("nt header has bad signature");
            }
            else if (this.NTHeaders32.OptionalHeader.Magic != 0x10B) // IMAGE_NT_OPTIONAL_HDR32_MAGIC
            {
                throw new FormatException("optional header has bad magic");
            }

            this.Directories = new List<Image.DataDirectory>();
            for (int i = 0; i < this.NTHeaders32.OptionalHeader.NumberOfRvaAndSizes; i++)
            {
                this.Directories.Add(input.ReadStructure<Image.DataDirectory>());
            }

            this.Sections = new List<Image.SectionHeader>();
            for (int i = 0; i < this.NTHeaders32.FileHeader.NumberOfSections; i++)
            {
                this.Sections.Add(input.ReadStructure<Image.SectionHeader>());
            }

            this.Exports = new Dictionary<UInt32, UInt32>();
            this.ExportNames = new Dictionary<string, UInt32>();

            if (
                this.Directories.Count >= 1 &&
                this.Directories[0].VirtualAddress != 0 &&
                this.Directories[0].Size != 0)
            {
                var fileOffset = this.GetFileOffset(this.Directories[0].VirtualAddress, true);

                input.Seek(fileOffset, SeekOrigin.Begin);
                Image.ExportDirectory exportDirectory = input.ReadStructure<Image.ExportDirectory>();

                if (exportDirectory.NumberOfNames > 0)
                {
                    var nameOffsets = new UInt32[exportDirectory.NumberOfNames];
                    var names = new string[exportDirectory.NumberOfNames];
                    var ordinals = new UInt16[exportDirectory.NumberOfNames];

                    input.Seek(this.GetFileOffset(exportDirectory.AddressOfNames, true), SeekOrigin.Begin);
                    for (uint i = 0; i < exportDirectory.NumberOfNames; i++)
                    {
                        nameOffsets[i] = input.ReadValueU32();
                    }

                    input.Seek(this.GetFileOffset(exportDirectory.AddressOfNameOrdinals, true), SeekOrigin.Begin);
                    for (uint i = 0; i < exportDirectory.NumberOfNames; i++)
                    {
                        ordinals[i] = input.ReadValueU16();
                    }

                    for (uint i = 0; i < exportDirectory.NumberOfNames; i++)
                    {
                        input.Seek(this.GetFileOffset(nameOffsets[i], true), SeekOrigin.Begin);
                        var name = input.ReadStringZ(Encoding.ASCII);
                        this.ExportNames.Add(name, exportDirectory.Base + ordinals[i]);
                    }
                }

                if (exportDirectory.NumberOfFunctions > 0)
                {
                    input.Seek(this.GetFileOffset(exportDirectory.AddressOfFunctions, true), SeekOrigin.Begin);

                    for (uint i = 0; i < exportDirectory.NumberOfFunctions; i++)
                    {
                        var address = input.ReadValueU32();
                        if (address == 0)
                        {
                            continue;
                        }

                        this.Exports.Add(exportDirectory.Base + i, address);
                    }
                }
            }
        }