1/*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19/**
20 * @file
21 * misc parsing utilities
22 */
23
24#include <time.h>
25
26#include "avstring.h"
27#include "avutil.h"
28#include "common.h"
29#include "eval.h"
30#include "log.h"
31#include "random_seed.h"
32#include "parseutils.h"
33
34#ifdef TEST
35
36#define av_get_random_seed av_get_random_seed_deterministic
37static uint32_t av_get_random_seed_deterministic(void);
38
39#define time(t) 1331972053
40
41#endif
42
43int av_parse_ratio(AVRational *q, const char *str, int max,
44                   int log_offset, void *log_ctx)
45{
46    char c;
47    int ret;
48
49    if (sscanf(str, "%d:%d%c", &q->num, &q->den, &c) != 2) {
50        double d;
51        ret = av_expr_parse_and_eval(&d, str, NULL, NULL,
52                                     NULL, NULL, NULL, NULL,
53                                     NULL, log_offset, log_ctx);
54        if (ret < 0)
55            return ret;
56        *q = av_d2q(d, max);
57    } else {
58        av_reduce(&q->num, &q->den, q->num, q->den, max);
59    }
60
61    return 0;
62}
63
64typedef struct {
65    const char *abbr;
66    int width, height;
67} VideoSizeAbbr;
68
69typedef struct {
70    const char *abbr;
71    AVRational rate;
72} VideoRateAbbr;
73
74static const VideoSizeAbbr video_size_abbrs[] = {
75    { "ntsc",      720, 480 },
76    { "pal",       720, 576 },
77    { "qntsc",     352, 240 }, /* VCD compliant NTSC */
78    { "qpal",      352, 288 }, /* VCD compliant PAL */
79    { "sntsc",     640, 480 }, /* square pixel NTSC */
80    { "spal",      768, 576 }, /* square pixel PAL */
81    { "film",      352, 240 },
82    { "ntsc-film", 352, 240 },
83    { "sqcif",     128,  96 },
84    { "qcif",      176, 144 },
85    { "cif",       352, 288 },
86    { "4cif",      704, 576 },
87    { "16cif",    1408,1152 },
88    { "qqvga",     160, 120 },
89    { "qvga",      320, 240 },
90    { "vga",       640, 480 },
91    { "svga",      800, 600 },
92    { "xga",      1024, 768 },
93    { "uxga",     1600,1200 },
94    { "qxga",     2048,1536 },
95    { "sxga",     1280,1024 },
96    { "qsxga",    2560,2048 },
97    { "hsxga",    5120,4096 },
98    { "wvga",      852, 480 },
99    { "wxga",     1366, 768 },
100    { "wsxga",    1600,1024 },
101    { "wuxga",    1920,1200 },
102    { "woxga",    2560,1600 },
103    { "wqsxga",   3200,2048 },
104    { "wquxga",   3840,2400 },
105    { "whsxga",   6400,4096 },
106    { "whuxga",   7680,4800 },
107    { "cga",       320, 200 },
108    { "ega",       640, 350 },
109    { "hd480",     852, 480 },
110    { "hd720",    1280, 720 },
111    { "hd1080",   1920,1080 },
112    { "2k",       2048,1080 }, /* Digital Cinema System Specification */
113    { "2kflat",   1998,1080 },
114    { "2kscope",  2048, 858 },
115    { "4k",       4096,2160 }, /* Digital Cinema System Specification */
116    { "4kflat",   3996,2160 },
117    { "4kscope",  4096,1716 },
118    { "nhd",       640,360  },
119    { "hqvga",     240,160  },
120    { "wqvga",     400,240  },
121    { "fwqvga",    432,240  },
122    { "hvga",      480,320  },
123    { "qhd",       960,540  },
124};
125
126static const VideoRateAbbr video_rate_abbrs[]= {
127    { "ntsc",      { 30000, 1001 } },
128    { "pal",       {    25,    1 } },
129    { "qntsc",     { 30000, 1001 } }, /* VCD compliant NTSC */
130    { "qpal",      {    25,    1 } }, /* VCD compliant PAL */
131    { "sntsc",     { 30000, 1001 } }, /* square pixel NTSC */
132    { "spal",      {    25,    1 } }, /* square pixel PAL */
133    { "film",      {    24,    1 } },
134    { "ntsc-film", { 24000, 1001 } },
135};
136
137int av_parse_video_size(int *width_ptr, int *height_ptr, const char *str)
138{
139    int i;
140    int n = FF_ARRAY_ELEMS(video_size_abbrs);
141    const char *p;
142    int width = 0, height = 0;
143
144    for (i = 0; i < n; i++) {
145        if (!strcmp(video_size_abbrs[i].abbr, str)) {
146            width  = video_size_abbrs[i].width;
147            height = video_size_abbrs[i].height;
148            break;
149        }
150    }
151    if (i == n) {
152        width = strtol(str, (void*)&p, 10);
153        if (*p)
154            p++;
155        height = strtol(p, (void*)&p, 10);
156
157        /* trailing extraneous data detected, like in 123x345foobar */
158        if (*p)
159            return AVERROR(EINVAL);
160    }
161    if (width <= 0 || height <= 0)
162        return AVERROR(EINVAL);
163    *width_ptr  = width;
164    *height_ptr = height;
165    return 0;
166}
167
168int av_parse_video_rate(AVRational *rate, const char *arg)
169{
170    int i, ret;
171    int n = FF_ARRAY_ELEMS(video_rate_abbrs);
172
173    /* First, we check our abbreviation table */
174    for (i = 0; i < n; ++i)
175        if (!strcmp(video_rate_abbrs[i].abbr, arg)) {
176            *rate = video_rate_abbrs[i].rate;
177            return 0;
178        }
179
180    /* Then, we try to parse it as fraction */
181    if ((ret = av_parse_ratio_quiet(rate, arg, 1001000)) < 0)
182        return ret;
183    if (rate->num <= 0 || rate->den <= 0)
184        return AVERROR(EINVAL);
185    return 0;
186}
187
188typedef struct {
189    const char *name;            ///< a string representing the name of the color
190    uint8_t     rgb_color[3];    ///< RGB values for the color
191} ColorEntry;
192
193static const ColorEntry color_table[] = {
194    { "AliceBlue",            { 0xF0, 0xF8, 0xFF } },
195    { "AntiqueWhite",         { 0xFA, 0xEB, 0xD7 } },
196    { "Aqua",                 { 0x00, 0xFF, 0xFF } },
197    { "Aquamarine",           { 0x7F, 0xFF, 0xD4 } },
198    { "Azure",                { 0xF0, 0xFF, 0xFF } },
199    { "Beige",                { 0xF5, 0xF5, 0xDC } },
200    { "Bisque",               { 0xFF, 0xE4, 0xC4 } },
201    { "Black",                { 0x00, 0x00, 0x00 } },
202    { "BlanchedAlmond",       { 0xFF, 0xEB, 0xCD } },
203    { "Blue",                 { 0x00, 0x00, 0xFF } },
204    { "BlueViolet",           { 0x8A, 0x2B, 0xE2 } },
205    { "Brown",                { 0xA5, 0x2A, 0x2A } },
206    { "BurlyWood",            { 0xDE, 0xB8, 0x87 } },
207    { "CadetBlue",            { 0x5F, 0x9E, 0xA0 } },
208    { "Chartreuse",           { 0x7F, 0xFF, 0x00 } },
209    { "Chocolate",            { 0xD2, 0x69, 0x1E } },
210    { "Coral",                { 0xFF, 0x7F, 0x50 } },
211    { "CornflowerBlue",       { 0x64, 0x95, 0xED } },
212    { "Cornsilk",             { 0xFF, 0xF8, 0xDC } },
213    { "Crimson",              { 0xDC, 0x14, 0x3C } },
214    { "Cyan",                 { 0x00, 0xFF, 0xFF } },
215    { "DarkBlue",             { 0x00, 0x00, 0x8B } },
216    { "DarkCyan",             { 0x00, 0x8B, 0x8B } },
217    { "DarkGoldenRod",        { 0xB8, 0x86, 0x0B } },
218    { "DarkGray",             { 0xA9, 0xA9, 0xA9 } },
219    { "DarkGreen",            { 0x00, 0x64, 0x00 } },
220    { "DarkKhaki",            { 0xBD, 0xB7, 0x6B } },
221    { "DarkMagenta",          { 0x8B, 0x00, 0x8B } },
222    { "DarkOliveGreen",       { 0x55, 0x6B, 0x2F } },
223    { "Darkorange",           { 0xFF, 0x8C, 0x00 } },
224    { "DarkOrchid",           { 0x99, 0x32, 0xCC } },
225    { "DarkRed",              { 0x8B, 0x00, 0x00 } },
226    { "DarkSalmon",           { 0xE9, 0x96, 0x7A } },
227    { "DarkSeaGreen",         { 0x8F, 0xBC, 0x8F } },
228    { "DarkSlateBlue",        { 0x48, 0x3D, 0x8B } },
229    { "DarkSlateGray",        { 0x2F, 0x4F, 0x4F } },
230    { "DarkTurquoise",        { 0x00, 0xCE, 0xD1 } },
231    { "DarkViolet",           { 0x94, 0x00, 0xD3 } },
232    { "DeepPink",             { 0xFF, 0x14, 0x93 } },
233    { "DeepSkyBlue",          { 0x00, 0xBF, 0xFF } },
234    { "DimGray",              { 0x69, 0x69, 0x69 } },
235    { "DodgerBlue",           { 0x1E, 0x90, 0xFF } },
236    { "FireBrick",            { 0xB2, 0x22, 0x22 } },
237    { "FloralWhite",          { 0xFF, 0xFA, 0xF0 } },
238    { "ForestGreen",          { 0x22, 0x8B, 0x22 } },
239    { "Fuchsia",              { 0xFF, 0x00, 0xFF } },
240    { "Gainsboro",            { 0xDC, 0xDC, 0xDC } },
241    { "GhostWhite",           { 0xF8, 0xF8, 0xFF } },
242    { "Gold",                 { 0xFF, 0xD7, 0x00 } },
243    { "GoldenRod",            { 0xDA, 0xA5, 0x20 } },
244    { "Gray",                 { 0x80, 0x80, 0x80 } },
245    { "Green",                { 0x00, 0x80, 0x00 } },
246    { "GreenYellow",          { 0xAD, 0xFF, 0x2F } },
247    { "HoneyDew",             { 0xF0, 0xFF, 0xF0 } },
248    { "HotPink",              { 0xFF, 0x69, 0xB4 } },
249    { "IndianRed",            { 0xCD, 0x5C, 0x5C } },
250    { "Indigo",               { 0x4B, 0x00, 0x82 } },
251    { "Ivory",                { 0xFF, 0xFF, 0xF0 } },
252    { "Khaki",                { 0xF0, 0xE6, 0x8C } },
253    { "Lavender",             { 0xE6, 0xE6, 0xFA } },
254    { "LavenderBlush",        { 0xFF, 0xF0, 0xF5 } },
255    { "LawnGreen",            { 0x7C, 0xFC, 0x00 } },
256    { "LemonChiffon",         { 0xFF, 0xFA, 0xCD } },
257    { "LightBlue",            { 0xAD, 0xD8, 0xE6 } },
258    { "LightCoral",           { 0xF0, 0x80, 0x80 } },
259    { "LightCyan",            { 0xE0, 0xFF, 0xFF } },
260    { "LightGoldenRodYellow", { 0xFA, 0xFA, 0xD2 } },
261    { "LightGreen",           { 0x90, 0xEE, 0x90 } },
262    { "LightGrey",            { 0xD3, 0xD3, 0xD3 } },
263    { "LightPink",            { 0xFF, 0xB6, 0xC1 } },
264    { "LightSalmon",          { 0xFF, 0xA0, 0x7A } },
265    { "LightSeaGreen",        { 0x20, 0xB2, 0xAA } },
266    { "LightSkyBlue",         { 0x87, 0xCE, 0xFA } },
267    { "LightSlateGray",       { 0x77, 0x88, 0x99 } },
268    { "LightSteelBlue",       { 0xB0, 0xC4, 0xDE } },
269    { "LightYellow",          { 0xFF, 0xFF, 0xE0 } },
270    { "Lime",                 { 0x00, 0xFF, 0x00 } },
271    { "LimeGreen",            { 0x32, 0xCD, 0x32 } },
272    { "Linen",                { 0xFA, 0xF0, 0xE6 } },
273    { "Magenta",              { 0xFF, 0x00, 0xFF } },
274    { "Maroon",               { 0x80, 0x00, 0x00 } },
275    { "MediumAquaMarine",     { 0x66, 0xCD, 0xAA } },
276    { "MediumBlue",           { 0x00, 0x00, 0xCD } },
277    { "MediumOrchid",         { 0xBA, 0x55, 0xD3 } },
278    { "MediumPurple",         { 0x93, 0x70, 0xD8 } },
279    { "MediumSeaGreen",       { 0x3C, 0xB3, 0x71 } },
280    { "MediumSlateBlue",      { 0x7B, 0x68, 0xEE } },
281    { "MediumSpringGreen",    { 0x00, 0xFA, 0x9A } },
282    { "MediumTurquoise",      { 0x48, 0xD1, 0xCC } },
283    { "MediumVioletRed",      { 0xC7, 0x15, 0x85 } },
284    { "MidnightBlue",         { 0x19, 0x19, 0x70 } },
285    { "MintCream",            { 0xF5, 0xFF, 0xFA } },
286    { "MistyRose",            { 0xFF, 0xE4, 0xE1 } },
287    { "Moccasin",             { 0xFF, 0xE4, 0xB5 } },
288    { "NavajoWhite",          { 0xFF, 0xDE, 0xAD } },
289    { "Navy",                 { 0x00, 0x00, 0x80 } },
290    { "OldLace",              { 0xFD, 0xF5, 0xE6 } },
291    { "Olive",                { 0x80, 0x80, 0x00 } },
292    { "OliveDrab",            { 0x6B, 0x8E, 0x23 } },
293    { "Orange",               { 0xFF, 0xA5, 0x00 } },
294    { "OrangeRed",            { 0xFF, 0x45, 0x00 } },
295    { "Orchid",               { 0xDA, 0x70, 0xD6 } },
296    { "PaleGoldenRod",        { 0xEE, 0xE8, 0xAA } },
297    { "PaleGreen",            { 0x98, 0xFB, 0x98 } },
298    { "PaleTurquoise",        { 0xAF, 0xEE, 0xEE } },
299    { "PaleVioletRed",        { 0xD8, 0x70, 0x93 } },
300    { "PapayaWhip",           { 0xFF, 0xEF, 0xD5 } },
301    { "PeachPuff",            { 0xFF, 0xDA, 0xB9 } },
302    { "Peru",                 { 0xCD, 0x85, 0x3F } },
303    { "Pink",                 { 0xFF, 0xC0, 0xCB } },
304    { "Plum",                 { 0xDD, 0xA0, 0xDD } },
305    { "PowderBlue",           { 0xB0, 0xE0, 0xE6 } },
306    { "Purple",               { 0x80, 0x00, 0x80 } },
307    { "Red",                  { 0xFF, 0x00, 0x00 } },
308    { "RosyBrown",            { 0xBC, 0x8F, 0x8F } },
309    { "RoyalBlue",            { 0x41, 0x69, 0xE1 } },
310    { "SaddleBrown",          { 0x8B, 0x45, 0x13 } },
311    { "Salmon",               { 0xFA, 0x80, 0x72 } },
312    { "SandyBrown",           { 0xF4, 0xA4, 0x60 } },
313    { "SeaGreen",             { 0x2E, 0x8B, 0x57 } },
314    { "SeaShell",             { 0xFF, 0xF5, 0xEE } },
315    { "Sienna",               { 0xA0, 0x52, 0x2D } },
316    { "Silver",               { 0xC0, 0xC0, 0xC0 } },
317    { "SkyBlue",              { 0x87, 0xCE, 0xEB } },
318    { "SlateBlue",            { 0x6A, 0x5A, 0xCD } },
319    { "SlateGray",            { 0x70, 0x80, 0x90 } },
320    { "Snow",                 { 0xFF, 0xFA, 0xFA } },
321    { "SpringGreen",          { 0x00, 0xFF, 0x7F } },
322    { "SteelBlue",            { 0x46, 0x82, 0xB4 } },
323    { "Tan",                  { 0xD2, 0xB4, 0x8C } },
324    { "Teal",                 { 0x00, 0x80, 0x80 } },
325    { "Thistle",              { 0xD8, 0xBF, 0xD8 } },
326    { "Tomato",               { 0xFF, 0x63, 0x47 } },
327    { "Turquoise",            { 0x40, 0xE0, 0xD0 } },
328    { "Violet",               { 0xEE, 0x82, 0xEE } },
329    { "Wheat",                { 0xF5, 0xDE, 0xB3 } },
330    { "White",                { 0xFF, 0xFF, 0xFF } },
331    { "WhiteSmoke",           { 0xF5, 0xF5, 0xF5 } },
332    { "Yellow",               { 0xFF, 0xFF, 0x00 } },
333    { "YellowGreen",          { 0x9A, 0xCD, 0x32 } },
334};
335
336static int color_table_compare(const void *lhs, const void *rhs)
337{
338    return av_strcasecmp(lhs, ((const ColorEntry *)rhs)->name);
339}
340
341#define ALPHA_SEP '@'
342
343int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen,
344                   void *log_ctx)
345{
346    char *tail, color_string2[128];
347    const ColorEntry *entry;
348    int len, hex_offset = 0;
349
350    if (color_string[0] == '#') {
351        hex_offset = 1;
352    } else if (!strncmp(color_string, "0x", 2))
353        hex_offset = 2;
354
355    if (slen < 0)
356        slen = strlen(color_string);
357    av_strlcpy(color_string2, color_string + hex_offset,
358               FFMIN(slen-hex_offset+1, sizeof(color_string2)));
359    if ((tail = strchr(color_string2, ALPHA_SEP)))
360        *tail++ = 0;
361    len = strlen(color_string2);
362    rgba_color[3] = 255;
363
364    if (!av_strcasecmp(color_string2, "random") || !av_strcasecmp(color_string2, "bikeshed")) {
365        int rgba = av_get_random_seed();
366        rgba_color[0] = rgba >> 24;
367        rgba_color[1] = rgba >> 16;
368        rgba_color[2] = rgba >> 8;
369        rgba_color[3] = rgba;
370    } else if (hex_offset ||
371               strspn(color_string2, "0123456789ABCDEFabcdef") == len) {
372        char *tail;
373        unsigned int rgba = strtoul(color_string2, &tail, 16);
374
375        if (*tail || (len != 6 && len != 8)) {
376            av_log(log_ctx, AV_LOG_ERROR, "Invalid 0xRRGGBB[AA] color string: '%s'\n", color_string2);
377            return AVERROR(EINVAL);
378        }
379        if (len == 8) {
380            rgba_color[3] = rgba;
381            rgba >>= 8;
382        }
383        rgba_color[0] = rgba >> 16;
384        rgba_color[1] = rgba >> 8;
385        rgba_color[2] = rgba;
386    } else {
387        entry = bsearch(color_string2,
388                        color_table,
389                        FF_ARRAY_ELEMS(color_table),
390                        sizeof(ColorEntry),
391                        color_table_compare);
392        if (!entry) {
393            av_log(log_ctx, AV_LOG_ERROR, "Cannot find color '%s'\n", color_string2);
394            return AVERROR(EINVAL);
395        }
396        memcpy(rgba_color, entry->rgb_color, 3);
397    }
398
399    if (tail) {
400        double alpha;
401        const char *alpha_string = tail;
402        if (!strncmp(alpha_string, "0x", 2)) {
403            alpha = strtoul(alpha_string, &tail, 16);
404        } else {
405            double norm_alpha = strtod(alpha_string, &tail);
406            if (norm_alpha < 0.0 || norm_alpha > 1.0)
407                alpha = 256;
408            else
409                alpha = 255 * norm_alpha;
410        }
411
412        if (tail == alpha_string || *tail || alpha > 255 || alpha < 0) {
413            av_log(log_ctx, AV_LOG_ERROR, "Invalid alpha value specifier '%s' in '%s'\n",
414                   alpha_string, color_string);
415            return AVERROR(EINVAL);
416        }
417        rgba_color[3] = alpha;
418    }
419
420    return 0;
421}
422
423const char *av_get_known_color_name(int color_idx, const uint8_t **rgbp)
424{
425    const ColorEntry *color;
426
427    if ((unsigned)color_idx >= FF_ARRAY_ELEMS(color_table))
428        return NULL;
429
430    color = &color_table[color_idx];
431    if (rgbp)
432        *rgbp = color->rgb_color;
433
434    return color->name;
435}
436
437/* get a positive number between n_min and n_max, for a maximum length
438   of len_max. Return -1 if error. */
439static int date_get_num(const char **pp,
440                        int n_min, int n_max, int len_max)
441{
442    int i, val, c;
443    const char *p;
444
445    p = *pp;
446    val = 0;
447    for(i = 0; i < len_max; i++) {
448        c = *p;
449        if (!av_isdigit(c))
450            break;
451        val = (val * 10) + c - '0';
452        p++;
453    }
454    /* no number read ? */
455    if (p == *pp)
456        return -1;
457    if (val < n_min || val > n_max)
458        return -1;
459    *pp = p;
460    return val;
461}
462
463char *av_small_strptime(const char *p, const char *fmt, struct tm *dt)
464{
465    int c, val;
466
467    for(;;) {
468        /* consume time string until a non whitespace char is found */
469        while (av_isspace(*fmt)) {
470            while (av_isspace(*p))
471                p++;
472            fmt++;
473        }
474        c = *fmt++;
475        if (c == '\0') {
476            return (char *)p;
477        } else if (c == '%') {
478            c = *fmt++;
479            switch(c) {
480            case 'H':
481            case 'J':
482                val = date_get_num(&p, 0, c == 'H' ? 23 : INT_MAX, 2);
483                if (val == -1)
484                    return NULL;
485                dt->tm_hour = val;
486                break;
487            case 'M':
488                val = date_get_num(&p, 0, 59, 2);
489                if (val == -1)
490                    return NULL;
491                dt->tm_min = val;
492                break;
493            case 'S':
494                val = date_get_num(&p, 0, 59, 2);
495                if (val == -1)
496                    return NULL;
497                dt->tm_sec = val;
498                break;
499            case 'Y':
500                val = date_get_num(&p, 0, 9999, 4);
501                if (val == -1)
502                    return NULL;
503                dt->tm_year = val - 1900;
504                break;
505            case 'm':
506                val = date_get_num(&p, 1, 12, 2);
507                if (val == -1)
508                    return NULL;
509                dt->tm_mon = val - 1;
510                break;
511            case 'd':
512                val = date_get_num(&p, 1, 31, 2);
513                if (val == -1)
514                    return NULL;
515                dt->tm_mday = val;
516                break;
517            case '%':
518                goto match;
519            default:
520                return NULL;
521            }
522        } else {
523        match:
524            if (c != *p)
525                return NULL;
526            p++;
527        }
528    }
529}
530
531time_t av_timegm(struct tm *tm)
532{
533    time_t t;
534
535    int y = tm->tm_year + 1900, m = tm->tm_mon + 1, d = tm->tm_mday;
536
537    if (m < 3) {
538        m += 12;
539        y--;
540    }
541
542    t = 86400LL *
543        (d + (153 * m - 457) / 5 + 365 * y + y / 4 - y / 100 + y / 400 - 719469);
544
545    t += 3600 * tm->tm_hour + 60 * tm->tm_min + tm->tm_sec;
546
547    return t;
548}
549
550int av_parse_time(int64_t *timeval, const char *timestr, int duration)
551{
552    const char *p, *q;
553    int64_t t;
554    time_t now;
555    struct tm dt = { 0 };
556    int today = 0, negative = 0, microseconds = 0;
557    int i;
558    static const char * const date_fmt[] = {
559        "%Y-%m-%d",
560        "%Y%m%d",
561    };
562    static const char * const time_fmt[] = {
563        "%H:%M:%S",
564        "%H%M%S",
565    };
566
567    p = timestr;
568    q = NULL;
569    *timeval = INT64_MIN;
570    if (!duration) {
571        now = time(0);
572
573        if (!av_strcasecmp(timestr, "now")) {
574            *timeval = (int64_t) now * 1000000;
575            return 0;
576        }
577
578        /* parse the year-month-day part */
579        for (i = 0; i < FF_ARRAY_ELEMS(date_fmt); i++) {
580            q = av_small_strptime(p, date_fmt[i], &dt);
581            if (q)
582                break;
583        }
584
585        /* if the year-month-day part is missing, then take the
586         * current year-month-day time */
587        if (!q) {
588            today = 1;
589            q = p;
590        }
591        p = q;
592
593        if (*p == 'T' || *p == 't' || *p == ' ')
594            p++;
595
596        /* parse the hour-minute-second part */
597        for (i = 0; i < FF_ARRAY_ELEMS(time_fmt); i++) {
598            q = av_small_strptime(p, time_fmt[i], &dt);
599            if (q)
600                break;
601        }
602    } else {
603        /* parse timestr as a duration */
604        if (p[0] == '-') {
605            negative = 1;
606            ++p;
607        }
608        /* parse timestr as HH:MM:SS */
609        q = av_small_strptime(p, "%J:%M:%S", &dt);
610        if (!q) {
611            /* parse timestr as MM:SS */
612            q = av_small_strptime(p, "%M:%S", &dt);
613            dt.tm_hour = 0;
614        }
615        if (!q) {
616            char *o;
617            /* parse timestr as S+ */
618            dt.tm_sec = strtol(p, &o, 10);
619            if (o == p) /* the parsing didn't succeed */
620                return AVERROR(EINVAL);
621            dt.tm_min = 0;
622            dt.tm_hour = 0;
623            q = o;
624        }
625    }
626
627    /* Now we have all the fields that we can get */
628    if (!q)
629        return AVERROR(EINVAL);
630
631    /* parse the .m... part */
632    if (*q == '.') {
633        int n;
634        q++;
635        for (n = 100000; n >= 1; n /= 10, q++) {
636            if (!av_isdigit(*q))
637                break;
638            microseconds += n * (*q - '0');
639        }
640        while (av_isdigit(*q))
641            q++;
642    }
643
644    if (duration) {
645        t = dt.tm_hour * 3600 + dt.tm_min * 60 + dt.tm_sec;
646    } else {
647        int is_utc = *q == 'Z' || *q == 'z';
648        q += is_utc;
649        if (today) { /* fill in today's date */
650            struct tm dt2 = is_utc ? *gmtime(&now) : *localtime(&now);
651            dt2.tm_hour = dt.tm_hour;
652            dt2.tm_min  = dt.tm_min;
653            dt2.tm_sec  = dt.tm_sec;
654            dt = dt2;
655        }
656        t = is_utc ? av_timegm(&dt) : mktime(&dt);
657    }
658
659    /* Check that we are at the end of the string */
660    if (*q)
661        return AVERROR(EINVAL);
662
663    t *= 1000000;
664    t += microseconds;
665    *timeval = negative ? -t : t;
666    return 0;
667}
668
669int av_find_info_tag(char *arg, int arg_size, const char *tag1, const char *info)
670{
671    const char *p;
672    char tag[128], *q;
673
674    p = info;
675    if (*p == '?')
676        p++;
677    for(;;) {
678        q = tag;
679        while (*p != '\0' && *p != '=' && *p != '&') {
680            if ((q - tag) < sizeof(tag) - 1)
681                *q++ = *p;
682            p++;
683        }
684        *q = '\0';
685        q = arg;
686        if (*p == '=') {
687            p++;
688            while (*p != '&' && *p != '\0') {
689                if ((q - arg) < arg_size - 1) {
690                    if (*p == '+')
691                        *q++ = ' ';
692                    else
693                        *q++ = *p;
694                }
695                p++;
696            }
697        }
698        *q = '\0';
699        if (!strcmp(tag, tag1))
700            return 1;
701        if (*p != '&')
702            break;
703        p++;
704    }
705    return 0;
706}
707
708#ifdef TEST
709
710static uint32_t randomv = MKTAG('L','A','V','U');
711
712static uint32_t av_get_random_seed_deterministic(void)
713{
714    return randomv = randomv * 1664525 + 1013904223;
715}
716
717int main(void)
718{
719    printf("Testing av_parse_video_rate()\n");
720    {
721        int i;
722        static const char *const rates[] = {
723            "-inf",
724            "inf",
725            "nan",
726            "123/0",
727            "-123 / 0",
728            "",
729            "/",
730            " 123  /  321",
731            "foo/foo",
732            "foo/1",
733            "1/foo",
734            "0/0",
735            "/0",
736            "1/",
737            "1",
738            "0",
739            "-123/123",
740            "-foo",
741            "123.23",
742            ".23",
743            "-.23",
744            "-0.234",
745            "-0.0000001",
746            "  21332.2324   ",
747            " -21332.2324   ",
748        };
749
750        for (i = 0; i < FF_ARRAY_ELEMS(rates); i++) {
751            int ret;
752            AVRational q = { 0, 0 };
753            ret = av_parse_video_rate(&q, rates[i]);
754            printf("'%s' -> %d/%d %s\n",
755                   rates[i], q.num, q.den, ret ? "ERROR" : "OK");
756        }
757    }
758
759    printf("\nTesting av_parse_color()\n");
760    {
761        int i;
762        uint8_t rgba[4];
763        static const char *const color_names[] = {
764            "bikeshed",
765            "RaNdOm",
766            "foo",
767            "red",
768            "Red ",
769            "RED",
770            "Violet",
771            "Yellow",
772            "Red",
773            "0x000000",
774            "0x0000000",
775            "0xff000000",
776            "0x3e34ff",
777            "0x3e34ffaa",
778            "0xffXXee",
779            "0xfoobar",
780            "0xffffeeeeeeee",
781            "#ff0000",
782            "#ffXX00",
783            "ff0000",
784            "ffXX00",
785            "red@foo",
786            "random@10",
787            "0xff0000@1.0",
788            "red@",
789            "red@0xfff",
790            "red@0xf",
791            "red@2",
792            "red@0.1",
793            "red@-1",
794            "red@0.5",
795            "red@1.0",
796            "red@256",
797            "red@10foo",
798            "red@-1.0",
799            "red@-0.0",
800        };
801
802        av_log_set_level(AV_LOG_DEBUG);
803
804        for (i = 0;  i < FF_ARRAY_ELEMS(color_names); i++) {
805            if (av_parse_color(rgba, color_names[i], -1, NULL) >= 0)
806                printf("%s -> R(%d) G(%d) B(%d) A(%d)\n",
807                       color_names[i], rgba[0], rgba[1], rgba[2], rgba[3]);
808            else
809                printf("%s -> error\n", color_names[i]);
810        }
811    }
812
813    printf("\nTesting av_small_strptime()\n");
814    {
815        int i;
816        struct tm tm = { 0 };
817        struct fmt_timespec_entry {
818            const char *fmt, *timespec;
819        } fmt_timespec_entries[] = {
820            { "%Y-%m-%d",                    "2012-12-21" },
821            { "%Y - %m - %d",                "2012-12-21" },
822            { "%Y-%m-%d %H:%M:%S",           "2012-12-21 20:12:21" },
823            { "  %Y - %m - %d %H : %M : %S", "   2012 - 12 -  21   20 : 12 : 21" },
824        };
825
826        av_log_set_level(AV_LOG_DEBUG);
827        for (i = 0;  i < FF_ARRAY_ELEMS(fmt_timespec_entries); i++) {
828            char *p;
829            struct fmt_timespec_entry *e = &fmt_timespec_entries[i];
830            printf("fmt:'%s' spec:'%s' -> ", e->fmt, e->timespec);
831            p = av_small_strptime(e->timespec, e->fmt, &tm);
832            if (p) {
833                printf("%04d-%02d-%2d %02d:%02d:%02d\n",
834                       1900+tm.tm_year, tm.tm_mon+1, tm.tm_mday,
835                       tm.tm_hour, tm.tm_min, tm.tm_sec);
836            } else {
837                printf("error\n");
838            }
839        }
840    }
841
842    printf("\nTesting av_parse_time()\n");
843    {
844        int i;
845        int64_t tv;
846        time_t tvi;
847        struct tm *tm;
848        static char tzstr[] = "TZ=CET-1";
849        static const char * const time_string[] = {
850            "now",
851            "12:35:46",
852            "2000-12-20 0:02:47.5z",
853            "2000-12-20T010247.6",
854        };
855        static const char * const duration_string[] = {
856            "2:34:56.79",
857            "-1:23:45.67",
858            "42.1729",
859            "-1729.42",
860            "12:34",
861        };
862
863        av_log_set_level(AV_LOG_DEBUG);
864        putenv(tzstr);
865        printf("(now is 2012-03-17 09:14:13 +0100, local time is UTC+1)\n");
866        for (i = 0;  i < FF_ARRAY_ELEMS(time_string); i++) {
867            printf("%-24s -> ", time_string[i]);
868            if (av_parse_time(&tv, time_string[i], 0)) {
869                printf("error\n");
870            } else {
871                tvi = tv / 1000000;
872                tm = gmtime(&tvi);
873                printf("%14"PRIi64".%06d = %04d-%02d-%02dT%02d:%02d:%02dZ\n",
874                       tv / 1000000, (int)(tv % 1000000),
875                       tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
876                       tm->tm_hour, tm->tm_min, tm->tm_sec);
877            }
878        }
879        for (i = 0;  i < FF_ARRAY_ELEMS(duration_string); i++) {
880            printf("%-24s -> ", duration_string[i]);
881            if (av_parse_time(&tv, duration_string[i], 1)) {
882                printf("error\n");
883            } else {
884                printf("%+21"PRIi64"\n", tv);
885            }
886        }
887    }
888
889    return 0;
890}
891
892#endif /* TEST */
893