From 098328822415762db2d13cecd0542e34af3f8eb0 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 31 Jul 2023 15:18:58 +0200 Subject: [PATCH] [rdtk] fix nine_patch refactor code to make it easier to read and avoid out of bound reads --- rdtk/librdtk/rdtk_nine_patch.c | 324 ++++++++++++++++++++------------- 1 file changed, 195 insertions(+), 129 deletions(-) diff --git a/rdtk/librdtk/rdtk_nine_patch.c b/rdtk/librdtk/rdtk_nine_patch.c index a78de35d7..b1e686507 100644 --- a/rdtk/librdtk/rdtk_nine_patch.c +++ b/rdtk/librdtk/rdtk_nine_patch.c @@ -213,147 +213,213 @@ int rdtk_nine_patch_draw(rdtkSurface* surface, int nXDst, int nYDst, int nWidth, return 1; } +static BOOL rdtk_nine_patch_get_scale_lr(rdtkNinePatch* ninePatch, wImage* image) +{ + WINPR_ASSERT(image); + WINPR_ASSERT(ninePatch); + + WINPR_ASSERT(image->data); + WINPR_ASSERT(image->width > 0); + + int64_t beg = -1; + int64_t end = -1; + + for (uint32_t x = 1; x < image->width - 1; x++) + { + const uint32_t* pixel = (const uint32_t*)&image->data[sizeof(uint32_t) * x]; /* (1, 0) */ + if (beg < 0) + { + if (*pixel) + beg = x; + } + else if (end < 0) + { + if (!(*pixel)) + { + end = x; + break; + } + } + } + + if ((beg <= 0) || (end <= 0)) + return FALSE; + + WINPR_ASSERT(beg <= INT32_MAX); + WINPR_ASSERT(end <= INT32_MAX); + ninePatch->scaleLeft = (int32_t)beg - 1; + ninePatch->scaleRight = (int32_t)end - 1; + ninePatch->scaleWidth = ninePatch->scaleRight - ninePatch->scaleLeft; + + return TRUE; +} + +static BOOL rdtk_nine_patch_get_scale_ht(rdtkNinePatch* ninePatch, wImage* image) +{ + WINPR_ASSERT(image); + WINPR_ASSERT(ninePatch); + + WINPR_ASSERT(image->data); + WINPR_ASSERT(image->height > 0); + WINPR_ASSERT(image->scanline > 0); + + int64_t beg = -1; + int64_t end = -1; + + for (uint32_t y = 1; y < image->height - 1; y++) + { + const uint32_t* pixel = (const uint32_t*)&image->data[image->scanline * y]; /* (1, 0) */ + if (beg < 0) + { + if (*pixel) + beg = y; + } + else if (end < 0) + { + if (!(*pixel)) + { + end = y; + break; + } + } + } + + if ((beg <= 0) || (end <= 0)) + return FALSE; + + WINPR_ASSERT(beg <= INT32_MAX); + WINPR_ASSERT(end <= INT32_MAX); + ninePatch->scaleTop = (int32_t)beg - 1; + ninePatch->scaleBottom = (int32_t)end - 1; + ninePatch->scaleHeight = ninePatch->scaleBottom - ninePatch->scaleTop; + + return TRUE; +} + +static BOOL rdtk_nine_patch_get_fill_lr(rdtkNinePatch* ninePatch, wImage* image) +{ + WINPR_ASSERT(image); + WINPR_ASSERT(ninePatch); + + WINPR_ASSERT(image->data); + WINPR_ASSERT(image->width > 0); + WINPR_ASSERT(image->height > 0); + WINPR_ASSERT(image->scanline > 0); + + int64_t beg = -1; + int64_t end = -1; + + for (uint32_t x = 1; x < image->width - 1; x++) + { + const uint32_t* pixel = (uint32_t*)&image->data[((image->height - 1) * image->scanline) + + x * sizeof(uint32_t)]; /* (1, height - 1) */ + if (beg < 0) + { + if (*pixel) + beg = x; + } + else if (end < 0) + { + if (!(*pixel)) + { + end = x; + break; + } + } + } + + if ((beg <= 0) || (end <= 0)) + return FALSE; + + WINPR_ASSERT(beg <= INT32_MAX); + WINPR_ASSERT(end <= INT32_MAX); + + ninePatch->fillLeft = (int32_t)beg - 1; + ninePatch->fillRight = (int32_t)end - 1; + ninePatch->fillWidth = ninePatch->fillRight - ninePatch->fillLeft; + + return TRUE; +} + +static BOOL rdtk_nine_patch_get_fill_ht(rdtkNinePatch* ninePatch, wImage* image) +{ + WINPR_ASSERT(image); + WINPR_ASSERT(ninePatch); + + WINPR_ASSERT(image->data); + WINPR_ASSERT(image->width > 0); + WINPR_ASSERT(image->height > 0); + WINPR_ASSERT(image->scanline > 0); + + int64_t beg = -1; + int64_t end = -1; + + for (uint32_t y = 1; y < image->height - 1; y++) + { + const uint32_t* pixel = (uint32_t*)&image->data[((image->width - 1) * sizeof(uint32_t)) + + image->scanline * y]; /* (width - 1, 1) */ + if (beg < 0) + { + if (*pixel) + beg = y; + } + else if (end < 0) + { + if (!(*pixel)) + { + end = y; + break; + } + } + } + + if ((beg <= 0) || (end <= 0)) + return FALSE; + + WINPR_ASSERT(beg <= INT32_MAX); + WINPR_ASSERT(end <= INT32_MAX); + ninePatch->scaleTop = (int32_t)beg - 1; + ninePatch->scaleBottom = (int32_t)end - 1; + ninePatch->scaleHeight = ninePatch->scaleBottom - ninePatch->scaleTop; + + return TRUE; +} + int rdtk_nine_patch_set_image(rdtkNinePatch* ninePatch, wImage* image) { - int x, y; - uint8_t* data; - int beg, end; - int scanline; - uint32_t* pixel; - int width, height; - - WINPR_ASSERT(ninePatch); WINPR_ASSERT(image); + WINPR_ASSERT(ninePatch); ninePatch->image = image; - width = image->width; - height = image->height; - scanline = image->scanline; - data = image->data; + /* parse scalable area */ - beg = end = -1; - pixel = (uint32_t*)&data[4]; /* (1, 0) */ + if (!rdtk_nine_patch_get_scale_lr(ninePatch, image)) + return -1; - for (x = 1; x < width - 1; x++) - { - if (beg < 0) - { - if (*pixel) - { - beg = x; - } - } - else if (end < 0) - { - if (!(*pixel)) - { - end = x; - break; - } - } + if (!rdtk_nine_patch_get_scale_ht(ninePatch, image)) + return -1; - pixel++; - } - - ninePatch->scaleLeft = beg - 1; - ninePatch->scaleRight = end - 1; - ninePatch->scaleWidth = ninePatch->scaleRight - ninePatch->scaleLeft; - beg = end = -1; - pixel = (uint32_t*)&data[scanline]; /* (0, 1) */ - - for (y = 1; y < height - 1; y++) - { - if (beg < 0) - { - if (*pixel) - { - beg = y; - } - } - else if (end < 0) - { - if (!(*pixel)) - { - end = y; - break; - } - } - - pixel = (uint32_t*)&((uint8_t*)pixel)[scanline]; - } - - ninePatch->scaleTop = beg - 1; - ninePatch->scaleBottom = end - 1; - ninePatch->scaleHeight = ninePatch->scaleBottom - ninePatch->scaleTop; /* parse fillable area */ - beg = end = -1; - pixel = (uint32_t*)&data[((height - 1) * scanline) + 4]; /* (1, height - 1) */ + if (!rdtk_nine_patch_get_fill_lr(ninePatch, image)) + return -1; - for (x = 1; x < width - 1; x++) - { - if (beg < 0) - { - if (*pixel) - { - beg = x; - } - } - else if (end < 0) - { - if (!(*pixel)) - { - end = x; - break; - } - } + if (!rdtk_nine_patch_get_fill_ht(ninePatch, image)) + return -1; - pixel++; - } - - ninePatch->fillLeft = beg - 1; - ninePatch->fillRight = end - 1; - ninePatch->fillWidth = ninePatch->fillRight - ninePatch->fillLeft; - beg = end = -1; - pixel = (uint32_t*)&data[((width - 1) * 4) + scanline]; /* (width - 1, 1) */ - - for (y = 1; y < height - 1; y++) - { - if (beg < 0) - { - if (*pixel) - { - beg = y; - } - } - else if (end < 0) - { - if (!(*pixel)) - { - end = y; - break; - } - } - - pixel = (uint32_t*)&((uint8_t*)pixel)[scanline]; - } - - ninePatch->fillTop = beg - 1; - ninePatch->fillBottom = end - 1; - ninePatch->fillHeight = ninePatch->fillBottom - ninePatch->fillTop; /* cut out borders from image */ - ninePatch->width = width - 2; - ninePatch->height = height - 2; - ninePatch->data = &data[scanline + 4]; /* (1, 1) */ - ninePatch->scanline = scanline; -#if 0 - printf("width: %d height: %d\n", ninePatch->width, ninePatch->height); - printf("scale: left: %d right: %d top: %d bottom: %d\n", - ninePatch->scaleLeft, ninePatch->scaleRight, - ninePatch->scaleTop, ninePatch->scaleBottom); - printf("fill: left: %d right: %d top: %d bottom: %d\n", - ninePatch->fillLeft, ninePatch->fillRight, - ninePatch->fillTop, ninePatch->fillBottom); -#endif + WINPR_ASSERT(image->width >= 2); + WINPR_ASSERT(image->height >= 2); + WINPR_ASSERT(image->scanline > 0); + WINPR_ASSERT(image->width <= INT32_MAX); + WINPR_ASSERT(image->height <= INT32_MAX); + WINPR_ASSERT(image->scanline <= INT32_MAX); + WINPR_ASSERT(image->data); + + ninePatch->width = (int32_t)image->width - 2; + ninePatch->height = (int32_t)image->height - 2; + ninePatch->data = &image->data[image->scanline + 4]; /* (1, 1) */ + ninePatch->scanline = (int32_t)image->scanline; + return 1; }