13fa58199e3c1e2a335bd21c02b002e609afdf92
[ffmpeg.git] / libavfilter / parseutils.c
1 /*
2  * copyright (c) 2009 Stefano Sabatini
3  * This file is part of FFmpeg.
4  *
5  * FFmpeg is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * FFmpeg is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with FFmpeg; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19
20 /**
21  * @file libavfilter/parseutils.c
22  * parsing utils
23  */
24
25 #include <strings.h>
26 #include "libavutil/avutil.h"
27 #include "libavutil/random_seed.h"
28 #include "parseutils.h"
29
30 #define WHITESPACES " \n\t"
31
32 char *av_get_token(const char **buf, const char *term)
33 {
34     char *out = av_malloc(strlen(*buf) + 1);
35     char *ret= out, *end= out;
36     const char *p = *buf;
37     p += strspn(p, WHITESPACES);
38
39     while(*p && !strspn(p, term)) {
40         char c = *p++;
41         if(c == '\\' && *p){
42             *out++ = *p++;
43             end= out;
44         }else if(c == '\''){
45             while(*p && *p != '\'')
46                 *out++ = *p++;
47             if(*p){
48                 p++;
49                 end= out;
50             }
51         }else{
52             *out++ = c;
53         }
54     }
55
56     do{
57         *out-- = 0;
58     }while(out >= end && strspn(out, WHITESPACES));
59
60     *buf = p;
61
62     return ret;
63 }
64
65 typedef struct {
66     const char *name;            ///< a string representing the name of the color
67     uint8_t     rgba_color[4];   ///< RGBA values for the color
68 } ColorEntry;
69
70 static ColorEntry color_table[] = {
71     { "AliceBlue",            { 0xF0, 0xF8, 0xFF } },
72     { "AntiqueWhite",         { 0xFA, 0xEB, 0xD7 } },
73     { "Aqua",                 { 0x00, 0xFF, 0xFF } },
74     { "Aquamarine",           { 0x7F, 0xFF, 0xD4 } },
75     { "Azure",                { 0xF0, 0xFF, 0xFF } },
76     { "Beige",                { 0xF5, 0xF5, 0xDC } },
77     { "Bisque",               { 0xFF, 0xE4, 0xC4 } },
78     { "Black",                { 0x00, 0x00, 0x00 } },
79     { "BlanchedAlmond",       { 0xFF, 0xEB, 0xCD } },
80     { "Blue",                 { 0x00, 0x00, 0xFF } },
81     { "BlueViolet",           { 0x8A, 0x2B, 0xE2 } },
82     { "Brown",                { 0xA5, 0x2A, 0x2A } },
83     { "BurlyWood",            { 0xDE, 0xB8, 0x87 } },
84     { "CadetBlue",            { 0x5F, 0x9E, 0xA0 } },
85     { "Chartreuse",           { 0x7F, 0xFF, 0x00 } },
86     { "Chocolate",            { 0xD2, 0x69, 0x1E } },
87     { "Coral",                { 0xFF, 0x7F, 0x50 } },
88     { "CornflowerBlue",       { 0x64, 0x95, 0xED } },
89     { "Cornsilk",             { 0xFF, 0xF8, 0xDC } },
90     { "Crimson",              { 0xDC, 0x14, 0x3C } },
91     { "Cyan",                 { 0x00, 0xFF, 0xFF } },
92     { "DarkBlue",             { 0x00, 0x00, 0x8B } },
93     { "DarkCyan",             { 0x00, 0x8B, 0x8B } },
94     { "DarkGoldenRod",        { 0xB8, 0x86, 0x0B } },
95     { "DarkGray",             { 0xA9, 0xA9, 0xA9 } },
96     { "DarkGreen",            { 0x00, 0x64, 0x00 } },
97     { "DarkKhaki",            { 0xBD, 0xB7, 0x6B } },
98     { "DarkMagenta",          { 0x8B, 0x00, 0x8B } },
99     { "DarkOliveGreen",       { 0x55, 0x6B, 0x2F } },
100     { "Darkorange",           { 0xFF, 0x8C, 0x00 } },
101     { "DarkOrchid",           { 0x99, 0x32, 0xCC } },
102     { "DarkRed",              { 0x8B, 0x00, 0x00 } },
103     { "DarkSalmon",           { 0xE9, 0x96, 0x7A } },
104     { "DarkSeaGreen",         { 0x8F, 0xBC, 0x8F } },
105     { "DarkSlateBlue",        { 0x48, 0x3D, 0x8B } },
106     { "DarkSlateGray",        { 0x2F, 0x4F, 0x4F } },
107     { "DarkTurquoise",        { 0x00, 0xCE, 0xD1 } },
108     { "DarkViolet",           { 0x94, 0x00, 0xD3 } },
109     { "DeepPink",             { 0xFF, 0x14, 0x93 } },
110     { "DeepSkyBlue",          { 0x00, 0xBF, 0xFF } },
111     { "DimGray",              { 0x69, 0x69, 0x69 } },
112     { "DodgerBlue",           { 0x1E, 0x90, 0xFF } },
113     { "FireBrick",            { 0xB2, 0x22, 0x22 } },
114     { "FloralWhite",          { 0xFF, 0xFA, 0xF0 } },
115     { "ForestGreen",          { 0x22, 0x8B, 0x22 } },
116     { "Fuchsia",              { 0xFF, 0x00, 0xFF } },
117     { "Gainsboro",            { 0xDC, 0xDC, 0xDC } },
118     { "GhostWhite",           { 0xF8, 0xF8, 0xFF } },
119     { "Gold",                 { 0xFF, 0xD7, 0x00 } },
120     { "GoldenRod",            { 0xDA, 0xA5, 0x20 } },
121     { "Gray",                 { 0x80, 0x80, 0x80 } },
122     { "Green",                { 0x00, 0x80, 0x00 } },
123     { "GreenYellow",          { 0xAD, 0xFF, 0x2F } },
124     { "HoneyDew",             { 0xF0, 0xFF, 0xF0 } },
125     { "HotPink",              { 0xFF, 0x69, 0xB4 } },
126     { "IndianRed",            { 0xCD, 0x5C, 0x5C } },
127     { "Indigo",               { 0x4B, 0x00, 0x82 } },
128     { "Ivory",                { 0xFF, 0xFF, 0xF0 } },
129     { "Khaki",                { 0xF0, 0xE6, 0x8C } },
130     { "Lavender",             { 0xE6, 0xE6, 0xFA } },
131     { "LavenderBlush",        { 0xFF, 0xF0, 0xF5 } },
132     { "LawnGreen",            { 0x7C, 0xFC, 0x00 } },
133     { "LemonChiffon",         { 0xFF, 0xFA, 0xCD } },
134     { "LightBlue",            { 0xAD, 0xD8, 0xE6 } },
135     { "LightCoral",           { 0xF0, 0x80, 0x80 } },
136     { "LightCyan",            { 0xE0, 0xFF, 0xFF } },
137     { "LightGoldenRodYellow", { 0xFA, 0xFA, 0xD2 } },
138     { "LightGrey",            { 0xD3, 0xD3, 0xD3 } },
139     { "LightGreen",           { 0x90, 0xEE, 0x90 } },
140     { "LightPink",            { 0xFF, 0xB6, 0xC1 } },
141     { "LightSalmon",          { 0xFF, 0xA0, 0x7A } },
142     { "LightSeaGreen",        { 0x20, 0xB2, 0xAA } },
143     { "LightSkyBlue",         { 0x87, 0xCE, 0xFA } },
144     { "LightSlateGray",       { 0x77, 0x88, 0x99 } },
145     { "LightSteelBlue",       { 0xB0, 0xC4, 0xDE } },
146     { "LightYellow",          { 0xFF, 0xFF, 0xE0 } },
147     { "Lime",                 { 0x00, 0xFF, 0x00 } },
148     { "LimeGreen",            { 0x32, 0xCD, 0x32 } },
149     { "Linen",                { 0xFA, 0xF0, 0xE6 } },
150     { "Magenta",              { 0xFF, 0x00, 0xFF } },
151     { "Maroon",               { 0x80, 0x00, 0x00 } },
152     { "MediumAquaMarine",     { 0x66, 0xCD, 0xAA } },
153     { "MediumBlue",           { 0x00, 0x00, 0xCD } },
154     { "MediumOrchid",         { 0xBA, 0x55, 0xD3 } },
155     { "MediumPurple",         { 0x93, 0x70, 0xD8 } },
156     { "MediumSeaGreen",       { 0x3C, 0xB3, 0x71 } },
157     { "MediumSlateBlue",      { 0x7B, 0x68, 0xEE } },
158     { "MediumSpringGreen",    { 0x00, 0xFA, 0x9A } },
159     { "MediumTurquoise",      { 0x48, 0xD1, 0xCC } },
160     { "MediumVioletRed",      { 0xC7, 0x15, 0x85 } },
161     { "MidnightBlue",         { 0x19, 0x19, 0x70 } },
162     { "MintCream",            { 0xF5, 0xFF, 0xFA } },
163     { "MistyRose",            { 0xFF, 0xE4, 0xE1 } },
164     { "Moccasin",             { 0xFF, 0xE4, 0xB5 } },
165     { "NavajoWhite",          { 0xFF, 0xDE, 0xAD } },
166     { "Navy",                 { 0x00, 0x00, 0x80 } },
167     { "OldLace",              { 0xFD, 0xF5, 0xE6 } },
168     { "Olive",                { 0x80, 0x80, 0x00 } },
169     { "OliveDrab",            { 0x6B, 0x8E, 0x23 } },
170     { "Orange",               { 0xFF, 0xA5, 0x00 } },
171     { "OrangeRed",            { 0xFF, 0x45, 0x00 } },
172     { "Orchid",               { 0xDA, 0x70, 0xD6 } },
173     { "PaleGoldenRod",        { 0xEE, 0xE8, 0xAA } },
174     { "PaleGreen",            { 0x98, 0xFB, 0x98 } },
175     { "PaleTurquoise",        { 0xAF, 0xEE, 0xEE } },
176     { "PaleVioletRed",        { 0xD8, 0x70, 0x93 } },
177     { "PapayaWhip",           { 0xFF, 0xEF, 0xD5 } },
178     { "PeachPuff",            { 0xFF, 0xDA, 0xB9 } },
179     { "Peru",                 { 0xCD, 0x85, 0x3F } },
180     { "Pink",                 { 0xFF, 0xC0, 0xCB } },
181     { "Plum",                 { 0xDD, 0xA0, 0xDD } },
182     { "PowderBlue",           { 0xB0, 0xE0, 0xE6 } },
183     { "Purple",               { 0x80, 0x00, 0x80 } },
184     { "Red",                  { 0xFF, 0x00, 0x00 } },
185     { "RosyBrown",            { 0xBC, 0x8F, 0x8F } },
186     { "RoyalBlue",            { 0x41, 0x69, 0xE1 } },
187     { "SaddleBrown",          { 0x8B, 0x45, 0x13 } },
188     { "Salmon",               { 0xFA, 0x80, 0x72 } },
189     { "SandyBrown",           { 0xF4, 0xA4, 0x60 } },
190     { "SeaGreen",             { 0x2E, 0x8B, 0x57 } },
191     { "SeaShell",             { 0xFF, 0xF5, 0xEE } },
192     { "Sienna",               { 0xA0, 0x52, 0x2D } },
193     { "Silver",               { 0xC0, 0xC0, 0xC0 } },
194     { "SkyBlue",              { 0x87, 0xCE, 0xEB } },
195     { "SlateBlue",            { 0x6A, 0x5A, 0xCD } },
196     { "SlateGray",            { 0x70, 0x80, 0x90 } },
197     { "Snow",                 { 0xFF, 0xFA, 0xFA } },
198     { "SpringGreen",          { 0x00, 0xFF, 0x7F } },
199     { "SteelBlue",            { 0x46, 0x82, 0xB4 } },
200     { "Tan",                  { 0xD2, 0xB4, 0x8C } },
201     { "Teal",                 { 0x00, 0x80, 0x80 } },
202     { "Thistle",              { 0xD8, 0xBF, 0xD8 } },
203     { "Tomato",               { 0xFF, 0x63, 0x47 } },
204     { "Turquoise",            { 0x40, 0xE0, 0xD0 } },
205     { "Violet",               { 0xEE, 0x82, 0xEE } },
206     { "Wheat",                { 0xF5, 0xDE, 0xB3 } },
207     { "White",                { 0xFF, 0xFF, 0xFF } },
208     { "WhiteSmoke",           { 0xF5, 0xF5, 0xF5 } },
209     { "Yellow",               { 0xFF, 0xFF, 0x00 } },
210     { "YellowGreen",          { 0x9A, 0xCD, 0x32 } },
211 };
212
213 static int color_table_compare(const void *lhs, const void *rhs)
214 {
215     return strcasecmp(lhs, ((const ColorEntry *)rhs)->name);
216 }
217
218 int av_parse_color(uint8_t *rgba_color, const char *color_string, void *log_ctx)
219 {
220     if (!strcasecmp(color_string, "bikeshed")) {
221         int rgba = ff_random_get_seed();
222         rgba_color[0] = rgba >> 24;
223         rgba_color[1] = rgba >> 16;
224         rgba_color[2] = rgba >> 8;
225         rgba_color[3] = rgba;
226     } else
227     if (!strncmp(color_string, "0x", 2)) {
228         char *tail;
229         int len = strlen(color_string);
230         int rgba = strtol(color_string, &tail, 16);
231
232         if (*tail || (len != 8 && len != 10)) {
233             av_log(log_ctx, AV_LOG_ERROR, "Invalid 0xRRGGBB[AA] color string: '%s'\n", color_string);
234             return -1;
235         }
236         if (len == 10) {
237             rgba_color[3] = rgba;
238             rgba >>= 8;
239         }
240         rgba_color[0] = rgba >> 16;
241         rgba_color[1] = rgba >> 8;
242         rgba_color[2] = rgba;
243     } else {
244         const ColorEntry *entry = bsearch(color_string,
245                                           color_table,
246                                           FF_ARRAY_ELEMS(color_table),
247                                           sizeof(ColorEntry),
248                                           color_table_compare);
249         if (!entry) {
250             av_log(log_ctx, AV_LOG_DEBUG, "Cannot find color '%s'\n", color_string);
251             return -1;
252         }
253         memcpy(rgba_color, entry->rgba_color, 4);
254     }
255
256     return 0;
257 }
258
259 #ifdef TEST
260
261 #undef printf
262
263 int main(void)
264 {
265     int i;
266
267     const char *strings[] = {
268         "''",
269         "",
270         ":",
271         "\\",
272         "'",
273         "    ''    :",
274         "    ''  ''  :",
275         "foo   '' :",
276         "'foo'",
277         "foo     ",
278         "foo\\",
279         "foo':  blah:blah",
280         "foo\\:  blah:blah",
281         "foo\'",
282         "'foo :  '  :blahblah",
283         "\\ :blah",
284         "     foo",
285         "      foo       ",
286         "      foo     \\ ",
287         "foo ':blah",
288         " foo   bar    :   blahblah",
289         "\\f\\o\\o",
290         "'foo : \\ \\  '   : blahblah",
291         "'\\fo\\o:': blahblah",
292         "\\'fo\\o\\:':  foo  '  :blahblah"
293     };
294
295     for (i=0; i < FF_ARRAY_ELEMS(strings); i++) {
296         const char *p= strings[i];
297         printf("|%s|", p);
298         printf(" -> |%s|", av_get_token(&p, ":"));
299         printf(" + |%s|\n", p);
300     }
301
302     printf("\nTesting av_parse_color()\n");
303     {
304         uint8_t rgba[4];
305         const char *color_names[] = {
306             "bikeshed",
307             "foo",
308             "red",
309             "Red ",
310             "RED",
311             "Violet",
312             "Yellow",
313             "Red",
314             "0x000000",
315             "0x0000000",
316             "0x3e34ff",
317             "0x3e34ffaa",
318             "0xffXXee",
319             "0xfoobar",
320             "0xffffeeeeeeee",
321         };
322
323         av_log_set_level(AV_LOG_DEBUG);
324
325         for (int i = 0;  i < FF_ARRAY_ELEMS(color_names); i++) {
326             if (av_parse_color(rgba, color_names[i], NULL) >= 0)
327                 printf("%s -> R(%d) G(%d) B(%d) A(%d)\n", color_names[i], rgba[0], rgba[1], rgba[2], rgba[3]);
328         }
329     }
330
331     return 0;
332 }
333
334 #endif