]> git.sesse.net Git - ffmpeg/blobdiff - libavutil/parseutils.c
Merge remote-tracking branch 'qatar/master'
[ffmpeg] / libavutil / parseutils.c
index df737f68523960997741765900df7a481ab54d28..66c31e1e888862d152be19eed9435625993951bd 100644 (file)
 #include "random_seed.h"
 #include "parseutils.h"
 
+#undef time
+
+#ifdef TEST
+
+#define av_get_random_seed av_get_random_seed_deterministic
+static uint32_t av_get_random_seed_deterministic(void);
+
+#define time(t) 1331972053
+
+#endif
+
 int av_parse_ratio(AVRational *q, const char *str, int max,
                    int log_offset, void *log_ctx)
 {
@@ -383,7 +394,11 @@ int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen,
         if (!strncmp(alpha_string, "0x", 2)) {
             alpha = strtoul(alpha_string, &tail, 16);
         } else {
-            alpha = 255 * strtod(alpha_string, &tail);
+            double norm_alpha = strtod(alpha_string, &tail);
+            if (norm_alpha < 0.0 || norm_alpha > 1.0)
+                alpha = 256;
+            else
+                alpha = 255 * norm_alpha;
         }
 
         if (tail == alpha_string || *tail || alpha > 255) {
@@ -515,9 +530,11 @@ time_t av_timegm(struct tm *tm)
 
 int av_parse_time(int64_t *timeval, const char *timestr, int duration)
 {
-    const char *p;
+    const char *p, *q;
     int64_t t;
+    time_t now;
     struct tm dt = { 0 };
+    int today = 0, negative = 0, microseconds = 0;
     int i;
     static const char * const date_fmt[] = {
         "%Y-%m-%d",
@@ -527,25 +544,14 @@ int av_parse_time(int64_t *timeval, const char *timestr, int duration)
         "%H:%M:%S",
         "%H%M%S",
     };
-    const char *q;
-    int is_utc, len;
-    char lastch;
-    int negative = 0;
-
-#undef time
-    time_t now = time(0);
-
-    len = strlen(timestr);
-    if (len > 0)
-        lastch = timestr[len - 1];
-    else
-        lastch = '\0';
-    is_utc = (lastch == 'z' || lastch == 'Z');
 
     p = timestr;
     q = NULL;
+    *timeval = INT64_MIN;
     if (!duration) {
-        if (!av_strncasecmp(timestr, "now", len)) {
+        now = time(0);
+
+        if (!av_strcasecmp(timestr, "now")) {
             *timeval = (int64_t) now * 1000000;
             return 0;
         }
@@ -553,23 +559,17 @@ int av_parse_time(int64_t *timeval, const char *timestr, int duration)
         /* parse the year-month-day part */
         for (i = 0; i < FF_ARRAY_ELEMS(date_fmt); i++) {
             q = small_strptime(p, date_fmt[i], &dt);
-            if (q) {
+            if (q)
                 break;
-            }
         }
 
         /* if the year-month-day part is missing, then take the
          * current year-month-day time */
         if (!q) {
-            if (is_utc) {
-                dt = *gmtime(&now);
-            } else {
-                dt = *localtime(&now);
-            }
-            dt.tm_hour = dt.tm_min = dt.tm_sec = 0;
-        } else {
-            p = q;
+            today = 1;
+            q = p;
         }
+        p = q;
 
         if (*p == 'T' || *p == 't' || *p == ' ')
             p++;
@@ -577,9 +577,8 @@ int av_parse_time(int64_t *timeval, const char *timestr, int duration)
         /* parse the hour-minute-second part */
         for (i = 0; i < FF_ARRAY_ELEMS(time_fmt); i++) {
             q = small_strptime(p, time_fmt[i], &dt);
-            if (q) {
+            if (q)
                 break;
-            }
         }
     } else {
         /* parse timestr as a duration */
@@ -592,46 +591,49 @@ int av_parse_time(int64_t *timeval, const char *timestr, int duration)
         if (!q) {
             /* parse timestr as S+ */
             dt.tm_sec = strtol(p, (void *)&q, 10);
-            if (q == p) {
-                /* the parsing didn't succeed */
-                *timeval = INT64_MIN;
+            if (q == p) /* the parsing didn't succeed */
                 return AVERROR(EINVAL);
-            }
             dt.tm_min = 0;
             dt.tm_hour = 0;
         }
     }
 
     /* Now we have all the fields that we can get */
-    if (!q) {
-        *timeval = INT64_MIN;
+    if (!q)
         return AVERROR(EINVAL);
+
+    /* parse the .m... part */
+    if (*q == '.') {
+        int n;
+        q++;
+        for (n = 100000; n >= 1; n /= 10, q++) {
+            if (!isdigit(*q))
+                break;
+            microseconds += n * (*q - '0');
+        }
     }
 
     if (duration) {
         t = dt.tm_hour * 3600 + dt.tm_min * 60 + dt.tm_sec;
     } else {
-        dt.tm_isdst = -1;       /* unknown */
-        if (is_utc) {
-            t = av_timegm(&dt);
-        } else {
-            t = mktime(&dt);
+        int is_utc = *q == 'Z' || *q == 'z';
+        q += is_utc;
+        if (today) { /* fill in today's date */
+            struct tm dt2 = is_utc ? *gmtime(&now) : *localtime(&now);
+            dt2.tm_hour = dt.tm_hour;
+            dt2.tm_min  = dt.tm_min;
+            dt2.tm_sec  = dt.tm_sec;
+            dt = dt2;
         }
+        t = is_utc ? av_timegm(&dt) : mktime(&dt);
     }
 
-    t *= 1000000;
+    /* Check that we are at the end of the string */
+    if (*q)
+        return AVERROR(EINVAL);
 
-    /* parse the .m... part */
-    if (*q == '.') {
-        int val, n;
-        q++;
-        for (val = 0, n = 100000; n >= 1; n /= 10, q++) {
-            if (!isdigit(*q))
-                break;
-            val += n * (*q - '0');
-        }
-        t += val;
-    }
+    t *= 1000000;
+    t += microseconds;
     *timeval = negative ? -t : t;
     return 0;
 }
@@ -677,6 +679,13 @@ int av_find_info_tag(char *arg, int arg_size, const char *tag1, const char *info
 
 #ifdef TEST
 
+static uint32_t random = MKTAG('L','A','V','U');
+
+static uint32_t av_get_random_seed_deterministic(void)
+{
+    return random = random * 1664525 + 1013904223;
+}
+
 #undef printf
 
 int main(void)
@@ -715,9 +724,9 @@ int main(void)
         for (i = 0; i < FF_ARRAY_ELEMS(rates); i++) {
             int ret;
             AVRational q = (AVRational){0, 0};
-            ret = av_parse_video_rate(&q, rates[i]),
-            printf("'%s' -> %d/%d ret:%d\n",
-                   rates[i], q.num, q.den, ret);
+            ret = av_parse_video_rate(&q, rates[i]);
+            printf("'%s' -> %d/%d%s\n",
+                   rates[i], q.num, q.den, ret ? " error" : "");
         }
     }
 
@@ -774,6 +783,53 @@ int main(void)
         }
     }
 
+    printf("\nTesting av_parse_time()\n");
+    {
+        int i;
+        int64_t tv;
+        time_t tvi;
+        struct tm *tm;
+        static char tzstr[] = "TZ=CET-1";
+        const char *time_string[] = {
+            "now",
+            "12:35:46",
+            "2000-12-20 0:02:47.5z",
+            "2000-12-20T010247.6",
+        };
+        const char *duration_string[] = {
+            "2:34:56.79",
+            "-1:23:45.67",
+            "42.1729",
+            "-1729.42",
+            "12:34",
+        };
+
+        av_log_set_level(AV_LOG_DEBUG);
+        putenv(tzstr);
+        printf("(now is 2012-03-17 09:14:13 +0100, local time is UTC+1)\n");
+        for (i = 0;  i < FF_ARRAY_ELEMS(time_string); i++) {
+            printf("%-24s -> ", time_string[i]);
+            if (av_parse_time(&tv, time_string[i], 0)) {
+                printf("error\n");
+            } else {
+                tvi = tv / 1000000;
+                tm = gmtime(&tvi);
+                printf("%14"PRIi64".%06d = %04d-%02d-%02dT%02d:%02d:%02dZ\n",
+                       tv / 1000000, (int)(tv % 1000000),
+                       tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+                       tm->tm_hour, tm->tm_min, tm->tm_sec);
+            }
+        }
+        for (i = 0;  i < FF_ARRAY_ELEMS(duration_string); i++) {
+            printf("%-24s -> ", duration_string[i]);
+            if (av_parse_time(&tv, duration_string[i], 1)) {
+                printf("error\n");
+            } else {
+                printf("%+21"PRIi64"\n", tv);
+            }
+        }
+    }
+
     return 0;
 }