#include <iostream>
#include <string>
#include <stdio.h>
#include <assert.h>
//#include <ctype.h>
#include <string.h>
static const struct {
const char *name;
const char *hex_string;
} named_colors[] = {
{ "AliceBlue", "#F0F8FF" },
{ "AntiqueWhite", "#FAEBD7" },
{ "Aqua", "#00FFFF" },
{ "Aquamarine", "#7FFFD4" },
{ "Azure", "#F0FFFF" },
{ "Beige", "#F5F5DC" },
{ "Bisque", "#FFE4C4" },
{ "Black", "#000000" },
{ "BlanchedAlmond", "#FFEBCD" },
{ "Blue", "#0000FF" },
{ "BlueViolet", "#8A2BE2" },
{ "Brown", "#A52A2A" },
{ "BurlyWood", "#DEB887" },
{ "CadetBlue", "#5F9EA0" },
{ "Chartreuse", "#7FFF00" },
{ "Chocolate", "#D2691E" },
{ "Coral", "#FF7F50" },
{ "CornflowerBlue", "#6495ED" },
{ "Cornsilk", "#FFF8DC" },
{ "Crimson", "#DC143C" },
{ "Cyan", "#00FFFF" },
{ "DarkBlue", "#00008B" },
{ "DarkCyan", "#008B8B" },
{ "DarkGoldenRod", "#B8860B" },
{ "DarkGray", "#A9A9A9" },
{ "DarkGreen", "#006400" },
{ "DarkKhaki", "#BDB76B" },
{ "DarkMagenta", "#8B008B" },
{ "DarkOliveGreen", "#556B2F" },
{ "DarkOrange", "#FF8C00" },
{ "DarkOrchid", "#9932CC" },
{ "DarkRed", "#8B0000" },
{ "DarkSalmon", "#E9967A" },
{ "DarkSeaGreen", "#8FBC8F" },
{ "DarkSlateBlue", "#483D8B" },
{ "DarkSlateGray", "#2F4F4F" },
{ "DarkTurquoise", "#00CED1" },
{ "DarkViolet", "#9400D3" },
{ "DeepPink", "#FF1493" },
{ "DeepSkyBlue", "#00BFFF" },
{ "DimGray", "#696969" },
{ "DodgerBlue", "#1E90FF" },
{ "FireBrick", "#B22222" },
{ "FloralWhite", "#FFFAF0" },
{ "ForestGreen", "#228B22" },
{ "Fuchsia", "#FF00FF" },
{ "Gainsboro", "#DCDCDC" },
{ "GhostWhite", "#F8F8FF" },
{ "Gold", "#FFD700" },
{ "GoldenRod", "#DAA520" },
{ "Gray", "#808080" },
{ "Green", "#008000" },
{ "GreenYellow", "#ADFF2F" },
{ "HoneyDew", "#F0FFF0" },
{ "HotPink", "#FF69B4" },
{ "IndianRed ", "#CD5C5C" },
{ "Indigo ", "#4B0082" },
{ "Ivory", "#FFFFF0" },
{ "Khaki", "#F0E68C" },
{ "Lavender", "#E6E6FA" },
{ "LavenderBlush", "#FFF0F5" },
{ "LawnGreen", "#7CFC00" },
{ "LemonChiffon", "#FFFACD" },
{ "LightBlue", "#ADD8E6" },
{ "LightCoral", "#F08080" },
{ "LightCyan", "#E0FFFF" },
{ "LightGoldenRodYellow", "#FAFAD2" },
{ "LightGray", "#D3D3D3" },
{ "LightGreen", "#90EE90" },
{ "LightPink", "#FFB6C1" },
{ "LightSalmon", "#FFA07A" },
{ "LightSeaGreen", "#20B2AA" },
{ "LightSkyBlue", "#87CEFA" },
{ "LightSlateGray", "#778899" },
{ "LightSteelBlue", "#B0C4DE" },
{ "LightYellow", "#FFFFE0" },
{ "Lime", "#00FF00" },
{ "LimeGreen", "#32CD32" },
{ "Linen", "#FAF0E6" },
{ "Magenta", "#FF00FF" },
{ "Maroon", "#800000" },
{ "MediumAquaMarine", "#66CDAA" },
{ "MediumBlue", "#0000CD" },
{ "MediumOrchid", "#BA55D3" },
{ "MediumPurple", "#9370DB" },
{ "MediumSeaGreen", "#3CB371" },
{ "MediumSlateBlue", "#7B68EE" },
{ "MediumSpringGreen", "#00FA9A" },
{ "MediumTurquoise", "#48D1CC" },
{ "MediumVioletRed", "#C71585" },
{ "MidnightBlue", "#191970" },
{ "MintCream", "#F5FFFA" },
{ "MistyRose", "#FFE4E1" },
{ "Moccasin", "#FFE4B5" },
{ "NavajoWhite", "#FFDEAD" },
{ "Navy", "#000080" },
{ "OldLace", "#FDF5E6" },
{ "Olive", "#808000" },
{ "OliveDrab", "#6B8E23" },
{ "Orange", "#FFA500" },
{ "OrangeRed", "#FF4500" },
{ "Orchid", "#DA70D6" },
{ "PaleGoldenRod", "#EEE8AA" },
{ "PaleGreen", "#98FB98" },
{ "PaleTurquoise", "#AFEEEE" },
{ "PaleVioletRed", "#DB7093" },
{ "PapayaWhip", "#FFEFD5" },
{ "PeachPuff", "#FFDAB9" },
{ "Peru", "#CD853F" },
{ "Pink", "#FFC0CB" },
{ "Plum", "#DDA0DD" },
{ "PowderBlue", "#B0E0E6" },
{ "Purple", "#800080" },
{ "Red", "#FF0000" },
{ "RosyBrown", "#BC8F8F" },
{ "RoyalBlue", "#4169E1" },
{ "SaddleBrown", "#8B4513" },
{ "Salmon", "#FA8072" },
{ "SandyBrown", "#F4A460" },
{ "SeaGreen", "#2E8B57" },
{ "SeaShell", "#FFF5EE" },
{ "Sienna", "#A0522D" },
{ "Silver", "#C0C0C0" },
{ "SkyBlue", "#87CEEB" },
{ "SlateBlue", "#6A5ACD" },
{ "SlateGray", "#708090" },
{ "Snow", "#FFFAFA" },
{ "SpringGreen", "#00FF7F" },
{ "SteelBlue", "#4682B4" },
{ "Tan", "#D2B48C" },
{ "Teal", "#008080" },
{ "Thistle", "#D8BFD8" },
{ "Tomato", "#FF6347" },
{ "Turquoise", "#40E0D0" },
{ "Violet", "#EE82EE" },
{ "Wheat", "#F5DEB3" },
{ "White", "#FFFFFF" },
{ "WhiteSmoke", "#F5F5F5" },
{ "Yellow", "#FFFF00" },
{ "YellowGreen", "#9ACD32" }
};
static inline bool hex_digit_decode(char hexdigit, unsigned char &value)
{
if(hexdigit >= '0' && hexdigit <= '9')
value = hexdigit - '0';
else if(hexdigit >= 'A' && hexdigit <= 'F')
value = hexdigit - 'A' + 10;
else if(hexdigit >= 'a' && hexdigit <= 'f')
value = hexdigit - 'a' + 10;
else
return false;
return true;
}
static bool parseHexColorString(const std::string &value, unsigned *colour)
{
unsigned char components[] = { 0x00, 0x00, 0x00, 0xff }; // R,G,B,A
if (value[0] != '#')
return false;
size_t len = value.size();
bool short_form;
if (len == 9 || len == 7) // #RRGGBBAA or #RRGGBB
short_form = false;
else if (len == 5 || len == 4) // #RGBA or #RGB
short_form = true;
else
return false;
bool success = true;
for (size_t pos = 1, cc = 0; pos < len; pos++, cc++) {
assert(cc < sizeof components / sizeof components[0]);
if (short_form) {
unsigned char d;
if (!hex_digit_decode(value[pos], d)) {
success = false;
break;
}
components[cc] = (d & 0xf) << 4 | (d & 0xf);
} else {
unsigned char d1, d2;
if (!hex_digit_decode(value[pos], d1) ||
!hex_digit_decode(value[pos+1], d2)) {
success = false;
break;
}
components[cc] = (d1 & 0xf) << 4 | (d2 & 0xf);
pos++; // skip the second digit -- it's already used
}
}
if (success) {
*colour = (components[3] << 24) | (components[0] << 16) | (components[1] << 8) | (components[2]);
}
return success;
}
static bool parseNamedColorString(const std::string &value, unsigned *colour)
{
int found_color = -1;
size_t alpha_pos = value.find('#');
std::string color_name;
std::string alpha_string;
if (alpha_pos != std::string::npos) {
color_name = value.substr(0, alpha_pos);
alpha_string = value.substr(alpha_pos + 1);
} else {
color_name = value;
alpha_string = "FF";
}
/* Not exactly efficient, but named colors (or hex strings) shouldn't be
used in time-critical areas anyway.
*/
for (size_t i = 0; i < sizeof named_colors / sizeof named_colors[0]; i++) {
// TODO: Make the comparison insensitive to case
if (color_name == named_colors[i].name) {
found_color = i;
break;
}
}
return found_color == -1
? false
: parseHexColorString(named_colors[found_color].hex_string + alpha_string, colour);
}
bool parseColor(const std::string &value, unsigned *colour)
{
bool success;
if (value[0] == '#')
success = parseHexColorString(value, colour);
else
success = parseNamedColorString(value, colour);
return success;
}
#if 0
void convert(void)
{
char buff[1024];
for (size_t i = 0; i < sizeof named_colors / sizeof named_colors[0]; i++) {
size_t j = 0;
for ( ; j < strlen(named_colors[i].name); j++) {
buff[j] = tolower(named_colors[i].name[j]);
}
buff[j] = '\0';
printf("{\"%s\",", buff);
for (j = 0; j < 22-strlen(buff); j++)
printf(" ");
printf("\"%s\" },\n", named_colors[i].hex_string);
}
}
#endif
int main(void)
{
unsigned colour;
assert(parseColor("YellowGreen", &colour) && colour == 0xFF9ACD32);
assert(parseColor("YellowGreen#87", &colour) && colour == 0x879ACD32);
assert(parseColor("RosyBrown#ba", &colour) && colour == 0xBABC8F8F);
#if 0
assert(parseColor("FF-DD-E2", &colour) == false);
assert(parseColor("#FF-DD-E2", &colour) == false);
assert(parseColor("#AABBCP", &colour) == false);
parseColor("#AABBCCDD", &colour);
assert(parseColor("#AABBCCDD", &colour) && colour == 0xddaabbcc);
assert(parseColor("#f00d", &colour) && colour == 0xddff0000);
assert(parseColor("YellowGreen", &colour));
assert(parseColor("sdsdYellowGreen", &colour) == false);
assert(parseColor("#ffffff00", &colour));
assert(parseColor("#ffffffddddddddddddddd", &colour) == false);
for (unsigned i = 0; i < 65535; i++) {
char buff[20];
sprintf(buff, "#%06x", i);
assert(parseColor(buff, &colour) && colour == (0xff000000 | i));
}
#endif
return 0;
}