From dfadaa241e87e10d10f06e89debd8505f8f9381b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Thu, 13 Jun 2019 21:44:09 +0200 Subject: [PATCH] Color palette: Finish implementation Color palette can now be loaded from a resource containing hexadecimal RGB values. --- layer/color-palette.c | 108 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/layer/color-palette.c b/layer/color-palette.c index eb87eaf..f151b22 100644 --- a/layer/color-palette.c +++ b/layer/color-palette.c @@ -40,6 +40,40 @@ struct _ColorPalette { G_DEFINE_TYPE(ColorPalette, color_palette, G_TYPE_OBJECT) +/** + * @brief Return the number of non empty lines in array + * + * This function returns the number of non empty lines in an + * array. The scanning is either terminated by the given length + * or if a \0 terminator is found. + * + * @param[in] data Array to count lines in + * @param[in] length Length of \p data + * @return < 0: Error, >=0: Lines + */ +static int count_non_empty_lines_in_array(const char *data, size_t length) +{ + unsigned int idx; + int non_empty_lines; + char last_char = '\n'; + + if (!data) + return -1; + + /* Count each '\n' as a new line if it is not directly preceded by another '\n' */ + for (idx = 0; idx < length && data[idx]; idx++) { + if (data[idx] == '\n' && last_char != '\n') + non_empty_lines++; + last_char = data[idx]; + } + + /* Count the last line in case the data does not end with a '\n' */ + if (data[idx-1] != '\n') + non_empty_lines++; + + return non_empty_lines; +} + /** * @brief color_palette_fill_with_resource * @param palette @@ -49,8 +83,16 @@ G_DEFINE_TYPE(ColorPalette, color_palette, G_TYPE_OBJECT) static int color_palette_fill_with_resource(ColorPalette *palette, char *resource_name) { GBytes *data; + char line[10]; + int line_idx; + unsigned int color_idx; + int idx; const char *char_array; gsize byte_count; + int lines; + GRegex *regex; + GMatchInfo *mi; + char *match; if (!palette || !resource_name) return -1; @@ -65,9 +107,75 @@ static int color_palette_fill_with_resource(ColorPalette *palette, char *resourc if (!char_array || !byte_count) goto ret_unref; + /* Get maximum lenght of color palette, assuming all entries are valid */ + lines = count_non_empty_lines_in_array(char_array, byte_count); + + if (lines <= 0) + goto ret_unref; + + palette->color_array = (GdkRGBA *)malloc(sizeof(GdkRGBA) * (unsigned int)lines); + + /* Setup regex for hexadecimal RGB colors like 'A0CB3F' */ + regex = g_regex_new("^(?[0-9A-Fa-f][0-9A-Fa-f])(?[0-9A-Fa-f][0-9A-Fa-f])(?[0-9A-Fa-f][0-9A-Fa-f])$", 0, 0, NULL); + /* Reset line */ + line_idx = 0; + line[0] = '\0'; + /* Set color index */ + color_idx = 0; + + /* interate over lines and match */ + for (idx = 0 ; idx < byte_count; idx++) { + /* Fillup line. */ + line[line_idx] = char_array[idx]; + + + /* If end of line/string is reached, process */ + if (line[line_idx] == '\n' || line[line_idx] == '\0') { + line[line_idx] = '\0'; + + /* Match the line */ + g_regex_match(regex, line, 0, &mi); + if (g_match_info_matches(mi) && color_idx < lines) { + match = g_match_info_fetch_named(mi, "red"); + palette->color_array[color_idx].red = (double)g_ascii_strtoll(match, NULL, 16) / 255.0; + g_free(match); + match = g_match_info_fetch_named(mi, "green"); + palette->color_array[color_idx].green = (double)g_ascii_strtoll(match, NULL, 16) / 255.0; + g_free(match); + match = g_match_info_fetch_named(mi, "blue"); + palette->color_array[color_idx].blue = (double)g_ascii_strtoll(match, NULL, 16) / 255.0; + g_free(match); + + /* Only RGB supported so far. Fix alpha channel to 1.0 */ + palette->color_array[color_idx].alpha = 1.0; + + color_idx++; + } + + g_match_info_free(mi); + + /* End of string */ + if (char_array[idx] == '\0') + break; + + line_idx = 0; + continue; + } + + /* increment line index. If end is reached write all bytes to the line end + * line is longer than required for parsing. This ensures, that everything works as expected + */ + line_idx += (line_idx < sizeof(line)-1 ? 1 : 0); + } + + /* Data read; Shrink array in case of invalid lines */ + palette->color_array = realloc(palette->color_array, (size_t)color_idx * sizeof(GdkRGBA)); + palette->color_array_length = color_idx; + + g_regex_unref(regex); ret_unref: g_bytes_unref(data);