Handle error conditions when decoding probabilities.
[FFMpeg-mirror/lagarith.git] / libavfilter / parseutils.c
blob7cafa52cb0bb3c702cea1125a3599a9d38a0458d
1 /*
2 * copyright (c) 2009 Stefano Sabatini
3 * This file is part of FFmpeg.
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.
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.
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
20 /**
21 * @file libavfilter/parseutils.c
22 * parsing utils
25 #include <strings.h>
26 #include "libavutil/avutil.h"
27 #include "libavutil/random_seed.h"
28 #include "parseutils.h"
30 #define WHITESPACES " \n\t"
32 char *av_get_token(const char **buf, const char *term)
34 char *out = av_malloc(strlen(*buf) + 1);
35 char *ret= out, *end= out;
36 const char *p = *buf;
37 p += strspn(p, WHITESPACES);
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;
51 }else{
52 *out++ = c;
56 do{
57 *out-- = 0;
58 }while(out >= end && strspn(out, WHITESPACES));
60 *buf = p;
62 return ret;
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;
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 } },
213 static int color_table_compare(const void *lhs, const void *rhs)
215 return strcasecmp(lhs, ((const ColorEntry *)rhs)->name);
218 int av_parse_color(uint8_t *rgba_color, const char *color_string, void *log_ctx)
220 if (!strcasecmp(color_string, "random") || !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);
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;
236 if (len == 10) {
237 rgba_color[3] = rgba;
238 rgba >>= 8;
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_ERROR, "Cannot find color '%s'\n", color_string);
251 return -1;
253 memcpy(rgba_color, entry->rgba_color, 4);
256 return 0;
260 * Stores the value in the field in ctx that is named like key.
261 * ctx must be an AVClass context, storing is done using AVOptions.
263 * @param buf the string to parse, buf will be updated to point at the
264 * separator just after the parsed key/value pair
265 * @param key_val_sep a 0-terminated list of characters used to
266 * separate key from value
267 * @param pairs_sep a 0-terminated list of characters used to separate
268 * two pairs from each other
269 * @return 0 if the key/value pair has been successfully parsed and
270 * set, or a negative value corresponding to an AVERROR code in case
271 * of error:
272 * AVERROR(EINVAL) if the key/value pair cannot be parsed,
273 * the error code issued by av_set_string3() if the key/value pair
274 * cannot be set
276 static int parse_key_value_pair(void *ctx, const char **buf,
277 const char *key_val_sep, const char *pairs_sep)
279 char *key = av_get_token(buf, key_val_sep);
280 char *val;
281 int ret;
283 if (*key && strspn(*buf, key_val_sep)) {
284 (*buf)++;
285 val = av_get_token(buf, pairs_sep);
286 } else {
287 av_log(ctx, AV_LOG_ERROR, "Missing key or no key/value separator found after key '%s'\n", key);
288 av_free(key);
289 return AVERROR(EINVAL);
292 av_log(ctx, AV_LOG_DEBUG, "Setting value '%s' for key '%s'\n", val, key);
294 ret = av_set_string3(ctx, key, val, 1, NULL);
296 av_free(key);
297 av_free(val);
298 return ret;
301 int av_set_options_string(void *ctx, const char *opts,
302 const char *key_val_sep, const char *pairs_sep)
304 int ret, count = 0;
306 while (*opts) {
307 if ((ret = parse_key_value_pair(ctx, &opts, key_val_sep, pairs_sep)) < 0)
308 return ret;
309 count++;
311 if (*opts)
312 opts++;
315 return count;
318 #ifdef TEST
320 #undef printf
322 typedef struct TestContext
324 const AVClass *class;
325 int num;
326 int toggle;
327 char *string;
328 int flags;
329 AVRational rational;
330 } TestContext;
332 #define OFFSET(x) offsetof(TestContext, x)
334 #define TEST_FLAG_COOL 01
335 #define TEST_FLAG_LAME 02
336 #define TEST_FLAG_MU 04
338 static const AVOption test_options[]= {
339 {"num", "set num", OFFSET(num), FF_OPT_TYPE_INT, 0, 0, 100 },
340 {"toggle", "set toggle", OFFSET(toggle), FF_OPT_TYPE_INT, 0, 0, 1 },
341 {"rational", "set rational", OFFSET(rational), FF_OPT_TYPE_RATIONAL, 0, 0, 10 },
342 {"string", "set string", OFFSET(string), FF_OPT_TYPE_STRING, 0, CHAR_MIN, CHAR_MAX },
343 {"flags", "set flags", OFFSET(flags), FF_OPT_TYPE_FLAGS, 0, 0, INT_MAX, 0, "flags" },
344 {"cool", "set cool flag ", 0, FF_OPT_TYPE_CONST, TEST_FLAG_COOL, INT_MIN, INT_MAX, 0, "flags" },
345 {"lame", "set lame flag ", 0, FF_OPT_TYPE_CONST, TEST_FLAG_LAME, INT_MIN, INT_MAX, 0, "flags" },
346 {"mu", "set mu flag ", 0, FF_OPT_TYPE_CONST, TEST_FLAG_MU, INT_MIN, INT_MAX, 0, "flags" },
347 {NULL},
350 static const char *test_get_name(void *ctx)
352 return "test";
355 static const AVClass test_class = {
356 "TestContext",
357 test_get_name,
358 test_options
361 int main(void)
363 int i;
365 const char *strings[] = {
366 "''",
368 ":",
369 "\\",
370 "'",
371 " '' :",
372 " '' '' :",
373 "foo '' :",
374 "'foo'",
375 "foo ",
376 "foo\\",
377 "foo': blah:blah",
378 "foo\\: blah:blah",
379 "foo\'",
380 "'foo : ' :blahblah",
381 "\\ :blah",
382 " foo",
383 " foo ",
384 " foo \\ ",
385 "foo ':blah",
386 " foo bar : blahblah",
387 "\\f\\o\\o",
388 "'foo : \\ \\ ' : blahblah",
389 "'\\fo\\o:': blahblah",
390 "\\'fo\\o\\:': foo ' :blahblah"
393 for (i=0; i < FF_ARRAY_ELEMS(strings); i++) {
394 const char *p= strings[i];
395 printf("|%s|", p);
396 printf(" -> |%s|", av_get_token(&p, ":"));
397 printf(" + |%s|\n", p);
400 printf("\nTesting av_parse_color()\n");
402 uint8_t rgba[4];
403 const char *color_names[] = {
404 "bikeshed",
405 "RaNdOm",
406 "foo",
407 "red",
408 "Red ",
409 "RED",
410 "Violet",
411 "Yellow",
412 "Red",
413 "0x000000",
414 "0x0000000",
415 "0x3e34ff",
416 "0x3e34ffaa",
417 "0xffXXee",
418 "0xfoobar",
419 "0xffffeeeeeeee",
422 av_log_set_level(AV_LOG_DEBUG);
424 for (int i = 0; i < FF_ARRAY_ELEMS(color_names); i++) {
425 if (av_parse_color(rgba, color_names[i], NULL) >= 0)
426 printf("%s -> R(%d) G(%d) B(%d) A(%d)\n", color_names[i], rgba[0], rgba[1], rgba[2], rgba[3]);
430 printf("\nTesting av_set_options_string()\n");
432 TestContext test_ctx;
433 const char *options[] = {
435 ":",
436 "=",
437 "foo=:",
438 ":=foo",
439 "=foo",
440 "foo=",
441 "foo",
442 "foo=val",
443 "foo==val",
444 "toggle=:",
445 "string=:",
446 "toggle=1 : foo",
447 "toggle=100",
448 "toggle==1",
449 "flags=+mu-lame : num=42: toggle=0",
450 "num=42 : string=blahblah",
451 "rational=0 : rational=1/2 : rational=1/-1",
452 "rational=-1/0",
455 test_ctx.class = &test_class;
456 av_opt_set_defaults2(&test_ctx, 0, 0);
457 test_ctx.string = av_strdup("default");
459 av_log_set_level(AV_LOG_DEBUG);
461 for (i=0; i < FF_ARRAY_ELEMS(options); i++) {
462 av_log(&test_ctx, AV_LOG_DEBUG, "Setting options string '%s'\n", options[i]);
463 if (av_set_options_string(&test_ctx, options[i], "=", ":") < 0)
464 av_log(&test_ctx, AV_LOG_ERROR, "Error setting options string: '%s'\n", options[i]);
465 printf("\n");
469 return 0;
472 #endif