[2.0.x] Buffer overflow and scroll fix, UTF8 cleanup (#10844)

This commit is contained in:
Eduardo José Tagle
2018-05-26 01:32:37 -03:00
committed by Scott Lahteine
parent 235facd545
commit 6f330f397e
17 changed files with 413 additions and 671 deletions

View File

@ -33,7 +33,7 @@ FORCE_INLINE void _draw_centered_temp(const int16_t temp, const uint8_t x, const
const char * const str = itostr3(temp);
lcd_moveto(x - (str[0] != ' ' ? 0 : str[1] != ' ' ? 1 : 2) * DOG_CHAR_WIDTH / 2, y);
lcd_put_u8str(str);
lcd_put_u8str_rom(PSTR(LCD_STR_DEGREE " "));
lcd_put_u8str_P(PSTR(LCD_STR_DEGREE " "));
}
#ifndef HEAT_INDICATOR_X
@ -113,7 +113,7 @@ FORCE_INLINE void _draw_axis_value(const AxisEnum axis, const char *value, const
else {
#if DISABLED(HOME_AFTER_DEACTIVATE) && DISABLED(DISABLE_REDUCED_ACCURACY_WARNING)
if (!axis_known_position[axis])
lcd_put_u8str_rom(axis == Z_AXIS ? PSTR(" ") : PSTR(" "));
lcd_put_u8str_P(axis == Z_AXIS ? PSTR(" ") : PSTR(" "));
else
#endif
lcd_put_u8str(value);
@ -124,36 +124,77 @@ FORCE_INLINE void _draw_axis_value(const AxisEnum axis, const char *value, const
inline void lcd_implementation_status_message(const bool blink) {
#if ENABLED(STATUS_MESSAGE_SCROLLING)
static bool last_blink = false;
const uint8_t slen = utf8_strlen(lcd_status_message);
const char *stat = lcd_status_message + status_scroll_pos;
if (slen <= LCD_WIDTH)
lcd_put_u8str(stat); // The string isn't scrolling
// Get the UTF8 character count of the string
uint8_t slen = utf8_strlen(lcd_status_message);
// If the string fits into the LCD, just print it and do not scroll it
if (slen <= LCD_WIDTH) {
// The string isn't scrolling and may not fill the screen
lcd_put_u8str(lcd_status_message);
// Fill the rest with spaces
while (slen < LCD_WIDTH) {
lcd_put_wchar(' ');
++slen;
}
}
else {
if (status_scroll_pos <= slen - LCD_WIDTH)
lcd_put_u8str(stat); // The string fills the screen
// String is larger than the available space in screen.
// Get a pointer to the next valid UTF8 character
const char *stat = lcd_status_message + status_scroll_offset;
// Get the string remaining length
const uint8_t rlen = utf8_strlen(stat);
// If we have enough characters to display
if (rlen >= LCD_WIDTH) {
// The remaining string fills the screen - Print it
lcd_put_u8str_max(stat, LCD_PIXEL_WIDTH);
}
else {
uint8_t chars = LCD_WIDTH;
if (status_scroll_pos < slen) { // First string still visible
lcd_put_u8str(stat); // The string leaves space
chars -= slen - status_scroll_pos; // Amount of space left
}
lcd_put_wchar('.'); // Always at 1+ spaces left, draw a dot
if (--chars) {
if (status_scroll_pos < slen + 1) // Draw a second dot if there's space
--chars, lcd_put_wchar('.');
if (chars) lcd_put_u8str_max(lcd_status_message, chars); // Print a second copy of the message
// The remaining string does not completely fill the screen
lcd_put_u8str_max(stat, LCD_PIXEL_WIDTH); // The string leaves space
uint8_t chars = LCD_WIDTH - rlen; // Amount of space left in characters
lcd_put_wchar('.'); // Always at 1+ spaces left, draw a dot
if (--chars) { // Draw a second dot if there's space
lcd_put_wchar('.');
if (--chars) {
// Print a second copy of the message
lcd_put_u8str_max(lcd_status_message, LCD_PIXEL_WIDTH - ((rlen+2) * DOG_CHAR_WIDTH));
}
}
}
if (last_blink != blink) {
last_blink = blink;
// Skip any non-printing bytes
if (status_scroll_pos < slen) while (!PRINTABLE(lcd_status_message[status_scroll_pos])) status_scroll_pos++;
if (++status_scroll_pos >= slen + 2) status_scroll_pos = 0;
// Adjust by complete UTF8 characters
if (status_scroll_offset < slen) {
status_scroll_offset++;
while (!START_OF_UTF8_CHAR(lcd_status_message[status_scroll_offset]))
status_scroll_offset++;
}
else
status_scroll_offset = 0;
}
}
#else
UNUSED(blink);
lcd_put_u8str(lcd_status_message);
// Get the UTF8 character count of the string
uint8_t slen = utf8_strlen(lcd_status_message);
// Just print the string to the LCD
lcd_put_u8str_max(lcd_status_message, LCD_PIXEL_WIDTH);
// Fill the rest with spaces if there are missing spaces
while (slen < LCD_WIDTH) {
lcd_put_wchar(' ');
++slen;
}
#endif
}
@ -417,7 +458,7 @@ static void lcd_implementation_status_screen() {
lcd_put_wchar('%');
lcd_setFont(FONT_MENU);
lcd_moveto(47, 50);
lcd_put_wchar(LCD_STR_FILAM_DIA[0]); // lcd_put_u8str_rom(PSTR(LCD_STR_FILAM_DIA));
lcd_put_wchar(LCD_STR_FILAM_DIA[0]); // lcd_put_u8str_P(PSTR(LCD_STR_FILAM_DIA));
lcd_moveto(93, 50);
lcd_put_wchar(LCD_STR_FILAM_MUL[0]);
#endif
@ -437,10 +478,10 @@ static void lcd_implementation_status_screen() {
lcd_implementation_status_message(blink);
}
else {
lcd_put_u8str_rom(PSTR(LCD_STR_FILAM_DIA));
lcd_put_u8str_P(PSTR(LCD_STR_FILAM_DIA));
lcd_put_wchar(':');
lcd_put_u8str(wstring);
lcd_put_u8str_rom(PSTR(" " LCD_STR_FILAM_MUL));
lcd_put_u8str_P(PSTR(" " LCD_STR_FILAM_MUL));
lcd_put_wchar(':');
lcd_put_u8str(mstring);
lcd_put_wchar('%');

View File

@ -615,36 +615,71 @@ void ST7920_Lite_Status_Screen::draw_feedrate_percentage(const uint8_t percentag
void ST7920_Lite_Status_Screen::draw_status_message(const char *str) {
set_ddram_address(DDRAM_LINE_4);
begin_data();
const uint8_t lcd_len = 16;
#if ENABLED(STATUS_MESSAGE_SCROLLING)
const uint8_t lcd_len = 16;
const uint8_t padding = 2;
uint8_t str_len = strlen(str);
// Trim whitespace at the end of the str, as for some reason
// messages like "Card Inserted" are padded with many spaces
while (str_len && str[str_len - 1] == ' ') str_len--;
uint8_t slen = utf8_strlen(str);
if (str_len <= lcd_len) {
// It all fits on the LCD without scrolling
// If the string fits into the LCD, just print it and do not scroll it
if (slen <= lcd_len) {
// The string isn't scrolling and may not fill the screen
write_str(str);
// Fill the rest with spaces
while (slen < lcd_len) {
write_byte(' ');
++slen;
}
}
else {
// Print the message repeatedly until covering the LCD
uint8_t c = status_scroll_pos;
for (uint8_t n = 0; n < lcd_len; n++) {
write_byte(c < str_len ? str[c] : ' ');
c++;
c %= str_len + padding; // Wrap around
// String is larger than the available space in screen.
// Get a pointer to the next valid UTF8 character
const char *stat = str + status_scroll_offset;
// Get the string remaining length
const uint8_t rlen = utf8_strlen(stat);
// If we have enough characters to display
if (rlen >= lcd_len) {
// The remaining string fills the screen - Print it
write_str(stat, lcd_len);
}
else {
// The remaining string does not completely fill the screen
write_str(stat); // The string leaves space
uint8_t chars = lcd_len - rlen; // Amount of space left in characters
write_byte('.'); // Always at 1+ spaces left, draw a dot
if (--chars) { // Draw a second dot if there's space
write_byte('.');
if (--chars)
write_str(str, chars); // Print a second copy of the message
}
}
// Scroll the message
if (status_scroll_pos == str_len + padding)
status_scroll_pos = 0;
// Adjust by complete UTF8 characters
if (status_scroll_offset < slen) {
status_scroll_offset++;
while (!START_OF_UTF8_CHAR(str[status_scroll_offset]))
status_scroll_offset++;
}
else
status_scroll_pos++;
status_scroll_offset = 0;
}
#else
write_str(str, 16);
// Get the UTF8 character count of the string
uint8_t slen = utf8_strlen(str);
// Just print the string to the LCD
write_str(str, lcd_len);
// Fill the rest with spaces if there are missing spaces
while (slen < lcd_len) {
write_byte(' ');
++slen;
}
#endif
}
@ -792,7 +827,7 @@ void ST7920_Lite_Status_Screen::update_status_or_position(bool forceUpdate) {
*/
if (forceUpdate || status_changed()) {
#if ENABLED(STATUS_MESSAGE_SCROLLING)
status_scroll_pos = 0;
status_scroll_offset = 0;
#endif
#if STATUS_EXPIRE_SECONDS
countdown = lcd_status_message[0] ? STATUS_EXPIRE_SECONDS : 0;