From ede1f7ff6f9509a18037534fbbe90942773e7597 Mon Sep 17 00:00:00 2001 From: Damjan Adamic Date: Sun, 16 Nov 2014 19:56:04 +0100 Subject: [PATCH] Fixed bmpLoad(): * added gtests * fixed various memory leaks * fixed wrong display of images with width < 8 * fixed wrong display of images with odd width and/or height --- radio/src/bmp.cpp | 27 ++++--- radio/src/lua.cpp | 2 +- radio/src/opentx.h | 3 +- radio/src/targets/simu/simpgmspace.cpp | 5 +- radio/src/tests/1b_39x32.bmp | Bin 0 -> 318 bytes radio/src/tests/1b_6x32.bmp | Bin 0 -> 190 bytes radio/src/tests/4b_31x31.bmp | Bin 0 -> 614 bytes radio/src/tests/4b_7x32.bmp | Bin 0 -> 242 bytes radio/src/tests/lcd.cpp | 71 ++++++++++++++++++ .../tests/lcd_bmpLoadAndDisplay_212x64.png | Bin 0 -> 1342 bytes 10 files changed, 94 insertions(+), 14 deletions(-) create mode 100644 radio/src/tests/1b_39x32.bmp create mode 100644 radio/src/tests/1b_6x32.bmp create mode 100644 radio/src/tests/4b_31x31.bmp create mode 100644 radio/src/tests/4b_7x32.bmp create mode 100644 radio/src/tests/lcd_bmpLoadAndDisplay_212x64.png diff --git a/radio/src/bmp.cpp b/radio/src/bmp.cpp index a20e07ab6..ffbe8efc8 100644 --- a/radio/src/bmp.cpp +++ b/radio/src/bmp.cpp @@ -44,7 +44,9 @@ const pm_char * bmpLoad(uint8_t *bmp, const char *filename, const unsigned int w uint8_t bmpBuf[LCD_W]; /* maximum with LCD_W */ uint8_t *buf = &bmpBuf[0]; - assert(width <= LCD_W); + if (width > LCD_W) { + return STR_INCOMPATIBLE; + } FRESULT result = f_open(&bmpFile, filename, FA_OPEN_EXISTING | FA_READ); if (result != FR_OK) { @@ -70,7 +72,7 @@ const pm_char * bmpLoad(uint8_t *bmp, const char *filename, const unsigned int w uint32_t fsize = *((uint32_t *)&buf[2]); uint32_t hsize = *((uint32_t *)&buf[10]); /* header size */ - uint32_t len = limit((uint32_t)0, (uint32_t)(hsize-14), (uint32_t)32); + uint32_t len = limit((uint32_t)4, (uint32_t)(hsize-14), (uint32_t)32); result = f_read(&bmpFile, buf, len, &read); if (result != FR_OK || read != len) { f_close(&bmpFile); @@ -152,16 +154,16 @@ const pm_char * bmpLoad(uint8_t *bmp, const char *filename, const unsigned int w *dest++ = w; *dest++ = h; - memset(dest, 0, w*((h+7)/8)*4); + memset(dest, 0, BITMAP_BUFFER_SIZE(w, h) - 2); - uint32_t n; + uint32_t rowSize; switch (depth) { case 1: - n = w/8; + rowSize = ((w+31)/32)*4; for (uint32_t i=0; i=0; i--) { - result = f_read(&bmpFile, buf, ((w+7)/8)*4, &read); - if (result != FR_OK || read != ((w+7)/8)*4) { + result = f_read(&bmpFile, buf, rowSize, &read); + if (result != FR_OK || read != rowSize) { f_close(&bmpFile); return SDCARD_ERROR(result); } - for (uint32_t j=0; j<(w+1)/2; j++) { + for (uint32_t j=0; j> 4) & 0x0F] << 4; *dst |= val ^ 0xF0; + if ((j+1)*2 >= w) break; val = palette[buf[j] & 0x0F] << 4; *(dst+1) |= val ^ 0xF0; } else { uint8_t val = palette[(buf[j] >> 4) & 0x0F]; *dst |= val ^ 0x0F; + if ((j+1)*2 >= w) break; val = palette[buf[j] & 0x0F]; *(dst+1) |= val ^ 0x0F; } diff --git a/radio/src/lua.cpp b/radio/src/lua.cpp index c74987ac1..8890e6392 100644 --- a/radio/src/lua.cpp +++ b/radio/src/lua.cpp @@ -450,7 +450,7 @@ static int luaLcdDrawPixmap(lua_State *L) int x = luaL_checkinteger(L, 1); int y = luaL_checkinteger(L, 2); const char * filename = luaL_checkstring(L, 3); - uint8_t bitmap[2+LCD_W/2*LCD_H/2]; // width max is LCD_W/2 pixels for saving stack and avoid a malloc here + uint8_t bitmap[BITMAP_BUFFER_SIZE(LCD_W/2, LCD_H)]; // width max is LCD_W/2 pixels for saving stack and avoid a malloc here const pm_char * error = bmpLoad(bitmap, filename, LCD_W/2, LCD_H); if (!error) { lcd_bmp(x, y, bitmap); diff --git a/radio/src/opentx.h b/radio/src/opentx.h index 44b85645e..f16de4763 100644 --- a/radio/src/opentx.h +++ b/radio/src/opentx.h @@ -439,9 +439,10 @@ enum PotType { #endif #if defined(PCBTARANIS) + #define BITMAP_BUFFER_SIZE(width, height) (2 + width * ((height+7)/8)*4) #define MODEL_BITMAP_WIDTH 64 #define MODEL_BITMAP_HEIGHT 32 - #define MODEL_BITMAP_SIZE (2+4*(MODEL_BITMAP_WIDTH*MODEL_BITMAP_HEIGHT/8)) + #define MODEL_BITMAP_SIZE BITMAP_BUFFER_SIZE(MODEL_BITMAP_WIDTH, MODEL_BITMAP_HEIGHT) extern uint8_t modelBitmap[MODEL_BITMAP_SIZE]; void loadModelBitmap(char *name, uint8_t *bitmap); #define LOAD_MODEL_BITMAP() loadModelBitmap(g_model.header.bitmap, modelBitmap) diff --git a/radio/src/targets/simu/simpgmspace.cpp b/radio/src/targets/simu/simpgmspace.cpp index a8758c0fc..b5e3648c3 100644 --- a/radio/src/targets/simu/simpgmspace.cpp +++ b/radio/src/targets/simu/simpgmspace.cpp @@ -520,7 +520,10 @@ FRESULT f_open (FIL * fil, const TCHAR *name, BYTE flag) FRESULT f_read (FIL* fil, void* data, UINT size, UINT* read) { - if (fil && fil->fs) *read = fread(data, 1, size, (FILE*)fil->fs); + if (fil && fil->fs) { + *read = fread(data, 1, size, (FILE*)fil->fs); + // TRACE("fread(%p) %u, %u", fil->fs, size, *read); + } return FR_OK; } diff --git a/radio/src/tests/1b_39x32.bmp b/radio/src/tests/1b_39x32.bmp new file mode 100644 index 0000000000000000000000000000000000000000..1730b7bd5ff75d28c982b806c5a5181090cd0e05 GIT binary patch literal 318 zcmZ{eyA1*{5JYFWz@axXp>ZsppUK(E!^dJk%*I%*$#`14{m|Nm sXy5jX#s4ytkZqpZmov%jIFsCt1UNk!Gw@C%{W4OLDj>5Hoh|;v3R&hP;s5{u literal 0 HcmV?d00001 diff --git a/radio/src/tests/1b_6x32.bmp b/radio/src/tests/1b_6x32.bmp new file mode 100644 index 0000000000000000000000000000000000000000..f130b9986dced34e21f1819991886d48bab36b6e GIT binary patch literal 190 zcmZ?r-Nyg{c0fu4h}nQx0f-ra5Cj^4*a#>I!c0Im2!p`?|Np^s1(1Z{KS1^mApQcx nZ-Dp?5bpru5+wc}AiD;LL25x5rWYR#RK{Qc#UM6FEeHSr;LI0^ literal 0 HcmV?d00001 diff --git a/radio/src/tests/4b_31x31.bmp b/radio/src/tests/4b_31x31.bmp new file mode 100644 index 0000000000000000000000000000000000000000..f4fe798af7ead302191329132871c874be155300 GIT binary patch literal 614 zcmZ?rO=DsJgEAng0mSl9%*en37XQG=z+hwt!2&=L5C#E3K|uy3B_#%9V`Byv7Z--m z&`^f7v^0kD@^Xfbjt+*IGiNfaTD6K{_wL;cXU?2qxO?|5!@GCy82neEy_wJz5oABFM#l$ zM5hWWDdlXhXaMv7Mf^X^z#wc^(E*YF_x}ICCIQxtjxvZmNYURUvGVfN0Em7dxuc`J zazRZ DIh3*p literal 0 HcmV?d00001 diff --git a/radio/src/tests/4b_7x32.bmp b/radio/src/tests/4b_7x32.bmp new file mode 100644 index 0000000000000000000000000000000000000000..5de76c4b69b258a547c90ad26a0f1bbaa3a6a1cd GIT binary patch literal 242 zcmY+;Jqp5L3=k+dm#!}E-`Wc}bnpmnf`!^M$Oj!n zcn2>~Q!9vpCqINhR_hnK*lC%mffCh2Uo)^*i)Ck|eX9+}ap1ZxJkLWA1c;&taU3H_ z5~OL0EX$DRIm)s`UDqIqrfKvt3Www$-GyI5T0{DVmWDo!C5^9i|EcX<%rjG2-Yfdb cD$37O`=eBkt=tY{xo)O%nVh9KQS>i)1NGr)v;Y7A literal 0 HcmV?d00001 diff --git a/radio/src/tests/lcd.cpp b/radio/src/tests/lcd.cpp index 884f2cf5a..47131b578 100644 --- a/radio/src/tests/lcd.cpp +++ b/radio/src/tests/lcd.cpp @@ -296,3 +296,74 @@ TEST(Lcd, lcd_vlineStip) } #endif +template class TestBuffer +{ +private: + uint8_t * buf; + uint32_t size; +public: + TestBuffer(uint32_t size) : buf(0), size(size) { + buf = new uint8_t[size + padding * 2]; + memset(buf, 0xA5, padding); + memset(buf+padding, 0x00, size); + memset(buf+padding+size, 0x5A, padding); + }; + ~TestBuffer() { if (buf) delete[] buf; }; + uint8_t * buffer() { return buf + padding; }; + void leakCheck() const { + uint8_t paddingCompareBuf[padding]; + memset(paddingCompareBuf, 0xA5, padding); + if (memcmp(buf, paddingCompareBuf, padding) != 0) { + ADD_FAILURE() << "buffer leaked low"; + }; + memset(paddingCompareBuf, 0x5A, padding); + if (memcmp(buf+padding+size, paddingCompareBuf, padding) != 0) { + ADD_FAILURE() << "buffer leaked high"; + } + }; +}; + +#if defined(PCBTARANIS) +TEST(Lcd, lcd_bmpLoadAndDisplay) +{ + lcd_clear(); + // Test proper BMP files, they should display correctly + { + TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(7, 32)); + EXPECT_EQ(bmpLoad(bitmap.buffer(), "./tests/4b_7x32.bmp", 7, 32), (char *)0); + bitmap.leakCheck(); + lcd_bmp(10, 2, bitmap.buffer()); + } + { + TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(6, 32)); + EXPECT_EQ(bmpLoad(bitmap.buffer(), "./tests/1b_6x32.bmp", 6, 32), (char *)0); + bitmap.leakCheck(); + lcd_bmp(20, 2, bitmap.buffer()); + } + { + TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(31, 31)); + EXPECT_EQ(bmpLoad(bitmap.buffer(), "./tests/4b_31x31.bmp", 31, 31), (char *)0); + bitmap.leakCheck(); + lcd_bmp(30, 2, bitmap.buffer()); + } + { + TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(39, 32)); + EXPECT_EQ(bmpLoad(bitmap.buffer(), "./tests/1b_39x32.bmp", 39, 32), (char *)0); + bitmap.leakCheck(); + lcd_bmp(70, 2, bitmap.buffer()); + } + EXPECT_TRUE(checkScreenshot("lcd_bmpLoadAndDisplay")); + + // Test various bad BMP files, they should not display + { + TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(LCD_W+1, 32)); + EXPECT_EQ(bmpLoad(bitmap.buffer(), "", LCD_W+1, 32), STR_INCOMPATIBLE) << "to wide"; + bitmap.leakCheck(); + } + { + TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(10, 10)); + EXPECT_EQ(bmpLoad(bitmap.buffer(), "./tests/1b_39x32.bmp", 10, 10), STR_INCOMPATIBLE) << "to small buffer"; + bitmap.leakCheck(); + } +} +#endif diff --git a/radio/src/tests/lcd_bmpLoadAndDisplay_212x64.png b/radio/src/tests/lcd_bmpLoadAndDisplay_212x64.png new file mode 100644 index 0000000000000000000000000000000000000000..70fab5d38c6f3e15879900c384e79395892ad40e GIT binary patch literal 1342 zcmb_c{X5eM0H3pER*Nn)FHbnSEDP!JMAkGGHibqnBGDrCG;br(SKjWJ*`ej7LrY^k z<(l2Roz&EM&aj#D_K;zmmtpN_vy-iIyZ_;S_AF8751(i0@LlOvJQ?sS*#vP79W0uXV|ARyEvW$C?G5NBi*|o6(dMmR;70fM6t(DLG}-? zrtnZjRF(r_wDnqn8{M?VNsFDdtZaW6L}{CgD=Zt~{o-D%LQl+x6!f5kcO(Zp%s9_; z=$rbSk#qbUm)?kpQwK}%j1^uUg;Pdj`9nXBnxL|{-)_wPbr~@k`G}aoJW)M}AiZLT zx~)k|i3QxR!Df$!-|ERn6=U;r2cjdT7=L6XV?n zl@P3P{yc!0kc)7wmr?P@OkPG+HH1~{dnktL+MF-d4I4~YC3LcZssPB4&s>_h?dB^t zxH7E5G=Dx_BFgY{tzE_4GqGYPq%mM-`gfZ26J)K>{Hqvu9 z!=EgcyEVrf_PEekL>|k*DGi(Pp{Nxgy?uRuggZt|nBAycQz%~UVQUuOX|>wblp~j( zsnA|ld()Yf4QsS|zGOg2(3a9q(eIDgTw7X+`%xo$v#)pZb{m0lqeH^J^@8Fl_K;2U zP(q%&?96$8Z~|+Xv{J^x0aX~u}r**AKg@` zjt^1Dmiv;#=A?GAXE7ymZEeQm#nB9o6LoAlgmP2cVFoC$Ex_iEXq||$=<&*&d(T7l zB4iPl_)<8sc%f>4m?`Px(LVJ>W2L&b97tJ~b^{_(FBE`VAQ3S1);9p}1?A zAI(m>C(`~J0ngcF+n}ucWh$UXCG=HD>-Y$_uEY|JqqJaHteQFg)!eXE==}H2iXR)x zm&s)RWPV||fOZS62QN0g2C1c(gWN=$PtF(YKs%ZwiIMTR^<(*%;XQQKlH(}mOSA;` zq!_%lP+8CDF3nfCf#MC4F;RQ^4Cs2>*~e_GU3M+%_htic5v4{5eWf1h^#2%sI=~9A Vw}#O!OzIvGgg+CA<9J8q{tGKvmk0m= literal 0 HcmV?d00001