/// <summary>
        /// Remove a specific address
        /// </summary>
        /// <param name="address">Address to remove</param>
        /// <returns>True if removed with success, else false</returns>
        public bool DeleteRelocation(uint address)
        {
            List<Reloc> relocs;

            // search if 4K address exists
            if (!pages.TryGetValue((address & 0xFFFFF000) - imageBase, out relocs))
                return false;

            ushort offset = (ushort)(address & 0x0FFF);

            // search if offset exists
            foreach (Reloc reloc in relocs)
            {
                if (reloc.offset == offset && reloc.type != BASE_RELOCATION_TYPE.ABSOLUTE)
                {
                    relocs.Remove(reloc);
                    virtualSize -= 2;

                    if (relocs.Count % 2 != 0) // align in 32bits
                    {
                        bool isAlignDeleted = false;

                        foreach (Reloc item in relocs) // search if align already exists
                        {
                            if (item.offset == 0 && item.type == BASE_RELOCATION_TYPE.ABSOLUTE)
                            {
                                relocs.Remove(item);
                                isAlignDeleted = true;
                                virtualSize -= 2;
                                break;
                            }
                        }

                        if (!isAlignDeleted) // if no align reloc found, add it
                        {
                            Reloc item = new Reloc();
                            item.offset = 0;
                            item.type = BASE_RELOCATION_TYPE.ABSOLUTE;

                            relocs.Add(item);
                            virtualSize += 2;
                        }
                    }

                    if (relocs.Count == 0) // remove page if nothing offset
                    {
                        pages.Remove((address & 0xFFFFF000) - imageBase);
                        virtualSize -= 8;
                    }

                    IsNotSaved = true;
                    return true;
                }
            }

            return false;
        }
        /// <summary>
        /// Open the file specified into the <paramref name="path"/>, read the relocation section
        /// and load it.
        /// </summary>
        /// <param name="path"></param>
        public Relocations(string path)
        {
            if (!File.Exists(path))
                throw new FileNotFoundException();

            this.path = path;
            this.IsNotSaved = false;

            BinaryReader br = new BinaryReader(new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read));

            if (br.ReadInt16() != 0x5A4D) // MZ signature
            {
                br.Close();
                throw new InvalidOperationException("MZ");
            }

            br.BaseStream.Seek(0x3C, SeekOrigin.Begin); // go to ptr to COFF File Header
            br.BaseStream.Seek(br.ReadInt32(), SeekOrigin.Begin); // go to COFF File Header

            if (br.ReadInt32() != 0x00004550) // PE\0\0
            {
                br.Close();
                throw new InvalidOperationException("PE");
            }

            br.ReadUInt16(); // machine ID. Ignored
            uint numbersOfSections = br.ReadUInt16();

            br.BaseStream.Seek(20 - 4, SeekOrigin.Current); // go to magic number (PE or PE+ = x86 or x64)

            if (br.ReadInt16() != 0x010B)
            {
                br.Close();
                throw new InvalidOperationException("X86");
            }

            br.BaseStream.Seek(26, SeekOrigin.Current); // go to ImageBase
            imageBase = br.ReadUInt32();
            br.BaseStream.Seek(64 + 40, SeekOrigin.Current); // go to Data Directories -> Base Relocation Table

            virtualAddress = br.ReadUInt32();
            addressVirtualSize = br.BaseStream.Position;
            virtualSize = br.ReadUInt32();

            br.BaseStream.Seek(80, SeekOrigin.Current); // jump to Section Table

            // find the RAW address/size
            RawAddress = 0;
            RawSize = 0;

            for (int i = 0; i < numbersOfSections; i++)
            {
                br.BaseStream.Seek(12, SeekOrigin.Current);

                if (br.ReadUInt32() == virtualAddress)
                {
                    RawSize = br.ReadUInt32();
                    RawAddress = br.ReadUInt32();
                    break;
                }

                br.BaseStream.Seek(24, SeekOrigin.Current); // place the pointer to the next section
            }

            if (RawAddress == 0x00 || RawSize == 0x00)
            {
                br.Close();
                throw new InvalidOperationException("RAW");
            }

            // reading relocation section
            br.BaseStream.Seek(RawAddress, SeekOrigin.Begin);

            pages = new SortedDictionary<uint, List<Reloc>>();

            while (br.BaseStream.Position < RawAddress + virtualSize) // 4K block loop
            {
                uint address = br.ReadUInt32();
                uint size = br.ReadUInt32();
                uint count = (size - 8) / 2;

                List<Reloc> relocs = new List<Reloc>();

                for (int i = 0; i < count; i++) // offsets loop
                {
                    ushort data = br.ReadUInt16();
                    BASE_RELOCATION_TYPE type = (BASE_RELOCATION_TYPE)((data & 0xF000) >> 12);
                    ushort offset = (ushort)(data & 0x0FFF);

                    Reloc reloc = new Reloc();
                    reloc.offset = offset;
                    reloc.type = type;

                    relocs.Add(reloc);
                }

                pages.Add(address, relocs);
            }

            br.Close();
        }
        /// <summary>
        /// Add a relocation address
        /// </summary>
        /// <param name="address">Address to add</param>
        /// <param name="type">Type of relocation</param>
        /// <returns>-1 if duplicated, 0 if not added, 1 if added a page and 2 if added only in reloc of page</returns>
        public int AddRelocation(uint address, BASE_RELOCATION_TYPE type)
        {
            if (address < imageBase)
                return 0;

            uint page = (address & 0xFFFFF000) - imageBase;
            ushort offset = (ushort)(address & 0x00000FFF);

            if (!pages.ContainsKey(page)) // create a new page if doesn't exists
            {
                if (RawSize - virtualSize < 12)
                    return 0;

                List<Reloc> relocs = new List<Reloc>();

                Reloc reloc = new Reloc();
                reloc.offset = offset;
                reloc.type = type;
                relocs.Add(reloc);

                reloc = new Reloc();
                reloc.offset = 0;
                reloc.type = BASE_RELOCATION_TYPE.ABSOLUTE;
                relocs.Add(reloc);

                pages.Add(page, relocs);

                virtualSize += 12;

                IsNotSaved = true;
                return 1;
            }
            else // just added the offset
            {
                List<Reloc> relocs;

                if (!pages.TryGetValue(page, out relocs))
                    return 0;

                foreach (Reloc item in relocs) // search if address already present
                {
                    if (item.offset == offset && item.type != BASE_RELOCATION_TYPE.ABSOLUTE)
                        return -1;
                }

                if (relocs.Count % 2 == 0) // align in 32bits
                {
                    bool isAlignDeleted = false;

                    foreach (Reloc item in relocs) // search if align already exists
                    {
                        if (item.offset == 0 && item.type == BASE_RELOCATION_TYPE.ABSOLUTE)
                        {
                            relocs.Remove(item);
                            isAlignDeleted = true;
                            virtualSize -= 2;
                            break;
                        }
                    }

                    if (!isAlignDeleted) // if no align reloc found, add it
                    {
                        if (RawSize - virtualSize < 4)
                            return 0;

                        Reloc item = new Reloc();
                        item.offset = 0;
                        item.type = BASE_RELOCATION_TYPE.ABSOLUTE;

                        relocs.Add(item);
                        virtualSize += 2;
                    }
                }

                Reloc reloc = new Reloc();
                reloc.offset = offset;
                reloc.type = type;

                relocs.Add(reloc);

                virtualSize += 2;

                IsNotSaved = true;
                return 2;
            }
        }