! @brief Converts the list of flash operations to flash sectors and pages.
        
        @param self
        @param keep_unwritten If true, unwritten pages in an erased sector and unwritten
            contents of a modified page will be read from the target and added to the data to be
            programmed.

        @exception FlashFailure Could not get sector or page info for an address.

def _build_sectors_and_pages(self, keep_unwritten):
        """! @brief Converts the list of flash operations to flash sectors and pages.
        
        @param self
        @param keep_unwritten If true, unwritten pages in an erased sector and unwritten
            contents of a modified page will be read from the target and added to the data to be
            programmed.

        @exception FlashFailure Could not get sector or page info for an address.
        """
        assert len(self.flash_operation_list) > 0
        
        self.program_byte_count = 0
        
        flash_addr = self.flash_operation_list[0].addr
        sector_info = self.flash.get_sector_info(flash_addr)
        if sector_info is None:
            raise FlashFailure("Attempt to program flash at invalid address 0x%08x" % flash_addr)
        
        page_info = self.flash.get_page_info(flash_addr)
        if page_info is None:
            raise FlashFailure("Attempt to program flash at invalid address 0x%08x" % flash_addr)

        current_sector = _FlashSector(sector_info)
        self.sector_list.append(current_sector)
        current_page = _FlashPage(page_info)
        current_sector.add_page(current_page)
        self.page_list.append(current_page)
        
        for flash_operation in self.flash_operation_list:
            pos = 0
            while pos < len(flash_operation.data):
                flash_addr = flash_operation.addr + pos
                
                # Check if operation is in a different sector.
                if flash_addr >= current_sector.addr + current_sector.size:
                    sector_info = self.flash.get_sector_info(flash_addr)
                    if sector_info is None:
                        raise FlashFailure("Attempt to program flash at invalid address 0x%08x" % flash_addr)
                    current_sector = _FlashSector(sector_info)
                    self.sector_list.append(current_sector)

                # Check if operation is in a different page
                if flash_addr >= current_page.addr + current_page.size:
                    page_info = self.flash.get_page_info(flash_addr)
                    if page_info is None:
                        raise FlashFailure("Attempt to program flash at invalid address 0x%08x" % flash_addr)
                    current_page = _FlashPage(page_info)
                    current_sector.add_page(current_page)
                    self.page_list.append(current_page)

                # Fill the page gap if there is one
                page_data_end = current_page.addr + len(current_page.data)
                if flash_addr != page_data_end:
                    old_data_len = flash_addr - page_data_end
                    if keep_unwritten:
                        self._enable_read_access()
                        old_data = self.flash.target.read_memory_block8(page_data_end, old_data_len)
                    else:
                        old_data = [self.flash.region.erased_byte_value] * old_data_len
                    current_page.data.extend(old_data)
                    self.program_byte_count += old_data_len

                # Copy data to page and increment pos
                space_left_in_page = page_info.size - len(current_page.data)
                space_left_in_data = len(flash_operation.data) - pos
                amount = min(space_left_in_page, space_left_in_data)
                current_page.data.extend(flash_operation.data[pos:pos + amount])
                self.program_byte_count += amount

                #increment position
                pos += amount

        # Fill the page gap at the end if there is one
        if len(current_page.data) != current_page.size:
            page_data_end = current_page.addr + len(current_page.data)
            old_data_len = current_page.size - len(current_page.data)
            if keep_unwritten and self.flash.region.is_readable:
                self._enable_read_access()
                old_data = self.flash.target.read_memory_block8(page_data_end, old_data_len)
            else:
                old_data = [self.flash.region.erased_byte_value] * old_data_len
            current_page.data.extend(old_data)
            self.program_byte_count += old_data_len
        
        # Go back through sectors and fill any missing pages with existing data.
        if keep_unwritten and self.flash.region.is_readable:
            self._fill_unwritten_sector_pages()