*/
/**
- * @file libavfilter/parseutils.c
+ * @file
* parsing utils
*/
#include <strings.h>
#include "libavutil/avutil.h"
+#include "libavutil/avstring.h"
#include "libavutil/random_seed.h"
#include "parseutils.h"
-#define WHITESPACES " \n\t"
-
-char *av_get_token(const char **buf, const char *term)
-{
- char *out = av_malloc(strlen(*buf) + 1);
- char *ret= out, *end= out;
- const char *p = *buf;
- p += strspn(p, WHITESPACES);
-
- while(*p && !strspn(p, term)) {
- char c = *p++;
- if(c == '\\' && *p){
- *out++ = *p++;
- end= out;
- }else if(c == '\''){
- while(*p && *p != '\'')
- *out++ = *p++;
- if(*p){
- p++;
- end= out;
- }
- }else{
- *out++ = c;
- }
- }
-
- do{
- *out-- = 0;
- }while(out >= end && strspn(out, WHITESPACES));
-
- *buf = p;
-
- return ret;
-}
-
typedef struct {
const char *name; ///< a string representing the name of the color
- uint8_t rgba_color[4]; ///< RGBA values for the color
+ uint8_t rgb_color[3]; ///< RGB values for the color
} ColorEntry;
static ColorEntry color_table[] = {
return strcasecmp(lhs, ((const ColorEntry *)rhs)->name);
}
+#define ALPHA_SEP '@'
+
int av_parse_color(uint8_t *rgba_color, const char *color_string, void *log_ctx)
{
- if (!strcasecmp(color_string, "random") || !strcasecmp(color_string, "bikeshed")) {
- int rgba = ff_random_get_seed();
+ char *tail, color_string2[128];
+ const ColorEntry *entry;
+ av_strlcpy(color_string2, color_string, sizeof(color_string2));
+ if ((tail = strchr(color_string2, ALPHA_SEP)))
+ *tail++ = 0;
+ rgba_color[3] = 255;
+
+ if (!strcasecmp(color_string2, "random") || !strcasecmp(color_string2, "bikeshed")) {
+ int rgba = av_get_random_seed();
rgba_color[0] = rgba >> 24;
rgba_color[1] = rgba >> 16;
rgba_color[2] = rgba >> 8;
rgba_color[3] = rgba;
- } else
- if (!strncmp(color_string, "0x", 2)) {
+ } else if (!strncmp(color_string2, "0x", 2)) {
char *tail;
- int len = strlen(color_string);
- int rgba = strtol(color_string, &tail, 16);
+ int len = strlen(color_string2);
+ unsigned int rgba = strtoul(color_string2, &tail, 16);
if (*tail || (len != 8 && len != 10)) {
- av_log(log_ctx, AV_LOG_ERROR, "Invalid 0xRRGGBB[AA] color string: '%s'\n", color_string);
- return -1;
+ av_log(log_ctx, AV_LOG_ERROR, "Invalid 0xRRGGBB[AA] color string: '%s'\n", color_string2);
+ return AVERROR(EINVAL);
}
if (len == 10) {
rgba_color[3] = rgba;
rgba_color[1] = rgba >> 8;
rgba_color[2] = rgba;
} else {
- const ColorEntry *entry = bsearch(color_string,
- color_table,
- FF_ARRAY_ELEMS(color_table),
- sizeof(ColorEntry),
- color_table_compare);
+ entry = bsearch(color_string2,
+ color_table,
+ FF_ARRAY_ELEMS(color_table),
+ sizeof(ColorEntry),
+ color_table_compare);
if (!entry) {
- av_log(log_ctx, AV_LOG_ERROR, "Cannot find color '%s'\n", color_string);
- return -1;
+ av_log(log_ctx, AV_LOG_ERROR, "Cannot find color '%s'\n", color_string2);
+ return AVERROR(EINVAL);
}
- memcpy(rgba_color, entry->rgba_color, 4);
+ memcpy(rgba_color, entry->rgb_color, 3);
}
- return 0;
-}
-
-/**
- * Stores the value in the field in ctx that is named like key.
- * ctx must be an AVClass context, storing is done using AVOptions.
- *
- * @param buf the string to parse, buf will be updated to point at the
- * separator just after the parsed key/value pair
- * @param key_val_sep a 0-terminated list of characters used to
- * separate key from value
- * @param pairs_sep a 0-terminated list of characters used to separate
- * two pairs from each other
- * @return 0 if the key/value pair has been successfully parsed and
- * set, or a negative value corresponding to an AVERROR code in case
- * of error:
- * AVERROR(EINVAL) if the key/value pair cannot be parsed,
- * the error code issued by av_set_string3() if the key/value pair
- * cannot be set
- */
-static int parse_key_value_pair(void *ctx, const char **buf,
- const char *key_val_sep, const char *pairs_sep)
-{
- char *key = av_get_token(buf, key_val_sep);
- char *val;
- int ret;
-
- if (*key && strspn(*buf, key_val_sep)) {
- (*buf)++;
- val = av_get_token(buf, pairs_sep);
- } else {
- av_log(ctx, AV_LOG_ERROR, "Missing key or no key/value separator found after key '%s'\n", key);
- av_free(key);
- return AVERROR(EINVAL);
- }
-
- av_log(ctx, AV_LOG_DEBUG, "Setting value '%s' for key '%s'\n", val, key);
-
- ret = av_set_string3(ctx, key, val, 1, NULL);
-
- av_free(key);
- av_free(val);
- return ret;
-}
-
-int av_set_options_string(void *ctx, const char *opts,
- const char *key_val_sep, const char *pairs_sep)
-{
- int ret, count = 0;
-
- while (*opts) {
- if ((ret = parse_key_value_pair(ctx, &opts, key_val_sep, pairs_sep)) < 0)
- return ret;
- count++;
+ if (tail) {
+ unsigned long int alpha;
+ const char *alpha_string = tail;
+ if (!strncmp(alpha_string, "0x", 2)) {
+ alpha = strtoul(alpha_string, &tail, 16);
+ } else {
+ alpha = strtoul(alpha_string, &tail, 10);
+ if (*tail) {
+ double d = strtod(alpha_string, &tail);
+ alpha = d * 255;
+ }
+ }
- if (*opts)
- opts++;
+ if (tail == alpha_string || *tail || alpha > 255) {
+ av_log(log_ctx, AV_LOG_ERROR, "Invalid alpha value specifier '%s' in '%s'\n",
+ alpha_string, color_string);
+ return AVERROR(EINVAL);
+ }
+ rgba_color[3] = alpha;
}
- return count;
+ return 0;
}
#ifdef TEST
#undef printf
-typedef struct TestContext
-{
- const AVClass *class;
- int num;
- int toggle;
- char *string;
- int flags;
- AVRational rational;
-} TestContext;
-
-#define OFFSET(x) offsetof(TestContext, x)
-
-#define TEST_FLAG_COOL 01
-#define TEST_FLAG_LAME 02
-#define TEST_FLAG_MU 04
-
-static const AVOption test_options[]= {
-{"num", "set num", OFFSET(num), FF_OPT_TYPE_INT, 0, 0, 100 },
-{"toggle", "set toggle", OFFSET(toggle), FF_OPT_TYPE_INT, 0, 0, 1 },
-{"rational", "set rational", OFFSET(rational), FF_OPT_TYPE_RATIONAL, 0, 0, 10 },
-{"string", "set string", OFFSET(string), FF_OPT_TYPE_STRING, 0, CHAR_MIN, CHAR_MAX },
-{"flags", "set flags", OFFSET(flags), FF_OPT_TYPE_FLAGS, 0, 0, INT_MAX, 0, "flags" },
-{"cool", "set cool flag ", 0, FF_OPT_TYPE_CONST, TEST_FLAG_COOL, INT_MIN, INT_MAX, 0, "flags" },
-{"lame", "set lame flag ", 0, FF_OPT_TYPE_CONST, TEST_FLAG_LAME, INT_MIN, INT_MAX, 0, "flags" },
-{"mu", "set mu flag ", 0, FF_OPT_TYPE_CONST, TEST_FLAG_MU, INT_MIN, INT_MAX, 0, "flags" },
-{NULL},
-};
-
-static const char *test_get_name(void *ctx)
-{
- return "test";
-}
-
-static const AVClass test_class = {
- "TestContext",
- test_get_name,
- test_options
-};
-
int main(void)
{
int i;
- const char *strings[] = {
- "''",
- "",
- ":",
- "\\",
- "'",
- " '' :",
- " '' '' :",
- "foo '' :",
- "'foo'",
- "foo ",
- "foo\\",
- "foo': blah:blah",
- "foo\\: blah:blah",
- "foo\'",
- "'foo : ' :blahblah",
- "\\ :blah",
- " foo",
- " foo ",
- " foo \\ ",
- "foo ':blah",
- " foo bar : blahblah",
- "\\f\\o\\o",
- "'foo : \\ \\ ' : blahblah",
- "'\\fo\\o:': blahblah",
- "\\'fo\\o\\:': foo ' :blahblah"
- };
-
- for (i=0; i < FF_ARRAY_ELEMS(strings); i++) {
- const char *p= strings[i];
- printf("|%s|", p);
- printf(" -> |%s|", av_get_token(&p, ":"));
- printf(" + |%s|\n", p);
- }
-
printf("\nTesting av_parse_color()\n");
{
uint8_t rgba[4];
"Red",
"0x000000",
"0x0000000",
+ "0xff000000",
"0x3e34ff",
"0x3e34ffaa",
"0xffXXee",
"0xfoobar",
"0xffffeeeeeeee",
+ "red@foo",
+ "random@10",
+ "0xff0000@1.0",
+ "red@",
+ "red@0xfff",
+ "red@0xf",
+ "red@2",
+ "red@0.1",
+ "red@-1",
+ "red@0.5",
+ "red@1.0",
+ "red@256",
+ "red@10foo",
+ "red@-1.0",
+ "red@-0.0",
};
av_log_set_level(AV_LOG_DEBUG);
}
}
- printf("\nTesting av_set_options_string()\n");
- {
- TestContext test_ctx;
- const char *options[] = {
- "",
- ":",
- "=",
- "foo=:",
- ":=foo",
- "=foo",
- "foo=",
- "foo",
- "foo=val",
- "foo==val",
- "toggle=:",
- "string=:",
- "toggle=1 : foo",
- "toggle=100",
- "toggle==1",
- "flags=+mu-lame : num=42: toggle=0",
- "num=42 : string=blahblah",
- "rational=0 : rational=1/2 : rational=1/-1",
- "rational=-1/0",
- };
-
- test_ctx.class = &test_class;
- av_opt_set_defaults2(&test_ctx, 0, 0);
- test_ctx.string = av_strdup("default");
-
- av_log_set_level(AV_LOG_DEBUG);
-
- for (i=0; i < FF_ARRAY_ELEMS(options); i++) {
- av_log(&test_ctx, AV_LOG_DEBUG, "Setting options string '%s'\n", options[i]);
- if (av_set_options_string(&test_ctx, options[i], "=", ":") < 0)
- av_log(&test_ctx, AV_LOG_ERROR, "Error setting options string: '%s'\n", options[i]);
- printf("\n");
- }
- }
-
return 0;
}