//! Returns true if the address filter overlaps \a region.
bool StExecutableImage::AddressFilter::matchesMemoryRegion(const MemoryRegion &region) const
{
    uint32_t firstByte = region.m_address;   // first byte occupied by this region
    uint32_t lastByte = region.endAddress(); // last used byte in this region
    return (firstByte >= m_fromAddress && firstByte <= m_toAddress) ||
           (lastByte >= m_fromAddress && lastByte <= m_toAddress);
}
//! There are several possible cases here:
//!     - No overlap at all. Nothing is done.
//!
//!     - All of the memory region is matched by the \a filter. The region is
//!         removed from #StExecutableImage::m_image and its data memory freed.
//!
//!     - The remaining portion of the region is one contiguous chunk. In this
//!         case, \a region is simply modified.
//!
//!     - The region is split in the middle by the filter. The original \a region
//!         is modified to match the first remaining chunk. And a new #StExecutableImage::MemoryRegion
//!         instance is created to hold the other leftover piece.
void StExecutableImage::cropRegionToFilter(MemoryRegion &region, const AddressFilter &filter)
{
    uint32_t firstByte = region.m_address;   // first byte occupied by this region
    uint32_t lastByte = region.endAddress(); // last used byte in this region

    // compute new address range
    uint32_t cropFrom = filter.m_fromAddress;
    if (cropFrom < firstByte)
    {
        cropFrom = firstByte;
    }

    uint32_t cropTo = filter.m_toAddress;
    if (cropTo > lastByte)
    {
        cropTo = lastByte;
    }

    // is there actually a match?
    if (cropFrom > filter.m_toAddress || cropTo < filter.m_fromAddress)
    {
        // nothing to do, so bail
        return;
    }

    printf("Deleting region 0x%08x-0x%08x\n", cropFrom, cropTo);

    // handle if the entire region is to be deleted
    if (cropFrom == firstByte && cropTo == lastByte)
    {
        delete[] region.m_data;
        region.m_data = NULL;
        m_image.remove(region);
    }

    // there is at least a little of the original region remaining
    uint32_t newLength = cropTo - cropFrom + 1;
    uint32_t leftoverLength = lastByte - cropTo;
    uint8_t *oldData = region.m_data;

    // update the region
    region.m_address = cropFrom;
    region.m_length = newLength;

    // crop data buffer for text regions
    if (region.m_type == TEXT_REGION && oldData)
    {
        region.m_data = new uint8_t[newLength];
        memcpy(region.m_data, &oldData[cropFrom - firstByte], newLength);

        // dispose of old data
        delete[] oldData;
    }

    // create a new region for any part of the original region that was past
    // the crop to address. this will happen if the filter range falls in the
    // middle of the region.
    if (leftoverLength)
    {
        MemoryRegion newRegion;
        newRegion.m_type = region.m_type;
        newRegion.m_flags = region.m_flags;
        newRegion.m_address = cropTo + 1;
        newRegion.m_length = leftoverLength;

        if (region.m_type == TEXT_REGION && oldData)
        {
            newRegion.m_data = new uint8_t[leftoverLength];
            memcpy(newRegion.m_data, &oldData[cropTo - firstByte + 1], leftoverLength);
        }

        insertOrMergeRegion(newRegion);
    }
}