shithub: sox

Download patch

ref: 1c697d3f259800ec89e8b314a579d03b8832d31f
parent: 6c7a96cc8327f02ea4d526f5becb16224c7c873d
author: Ulrich Klauer <ulrich@chirlu.de>
date: Sun Sep 2 11:19:19 EDT 2012

Improve lsx_parsesamples syntax checking

Make lsx_parsesamples more predictable regarding which characters it
considers to belong to a time specification. Any sequence matching the
regex ^[0-9:.est]* is now considered the scope of lsx_parsesamples and
consumed completely. It is an error if characters out of [0-9:.est]
remain after processing. Other characters (like '@' or ',') are still
OK.

In particular, this means that input strings like "1.2e3t" and "1ts"
are now illegal. Previously, the former was interpreted as 1+0.2e3 =
1+200 = 201 seconds instead of 1200 seconds as a user reasonably might
have expected; the latter was interpreted as 1 sample due to the 's'
at the end, yet only "1" was consumed and "ts" returned for further
processing by the caller.

--- a/src/effects_i.c
+++ b/src/effects_i.c
@@ -137,26 +137,29 @@
 /*
  * lsx_parsesamples
  *
- * Parse a string for # of samples.  If string ends with a 's'
- * then the string is interpreted as a user calculated # of samples.
- * If string contains ':' or '.' or if it ends with a 't' then its
- * treated as an amount of time.  This is converted into seconds and
- * fraction of seconds and then use the sample rate to calculate
- * # of samples.
+ * Parse a string for # of samples.  If string ends with a 's' then
+ * the string is interpreted as a user-calculated # of samples.
+ * If string contains ':' or '.' but no 'e' or if it ends with a 't'
+ * then it is treated as an amount of time.  This is converted into
+ * seconds and fraction of seconds, then the sample rate is used to
+ * calculate # of samples.
+ * Parameter def specifies which interpretation should be the default
+ * for a bare number like "123".  It can either be 't' or 's'.
  * Returns NULL on error, pointer to next char to parse otherwise.
  */
 char const * lsx_parsesamples(sox_rate_t rate, const char *str0, uint64_t *samples, int def)
 {
-  int i, found_samples = 0, found_time = 0;
+  int i;
+  sox_bool found_samples = sox_false, found_time = sox_false;
   char const * end;
   char const * pos;
-  sox_bool found_colon, found_dot;
+  sox_bool found_colon, found_dot, found_e;
   char * str = (char *)str0;
 
   for (;*str == ' '; ++str);
   for (end = str; *end && strchr("0123456789:.ets", *end); ++end);
   if (end == str)
-    return NULL;
+    return NULL; /* error: empty input */
 
   pos = strchr(str, ':');
   found_colon = pos && pos < end;
@@ -164,17 +167,23 @@
   pos = strchr(str, '.');
   found_dot = pos && pos < end;
 
-  if (found_colon || found_dot || *(end-1) == 't')
-    found_time = 1;
+  pos = strchr(str, 'e');
+  found_e = pos && pos < end;
+
+  if (found_colon || (found_dot && !found_e) || *(end-1) == 't')
+    found_time = sox_true;
   else if (*(end-1) == 's')
-    found_samples = 1;
+    found_samples = sox_true;
 
   if (found_time || (def == 't' && !found_samples)) {
+    if (found_e)
+      return NULL; /* error: e notation in time */
+
     for (*samples = 0, i = 0; *str != '.' && i < 3; ++i) {
       char * last_str = str;
       long part = strtol(str, &str, 10);
       if (!i && str == last_str)
-        return NULL;
+        return NULL; /* error: empty first component */
       *samples += rate * part;
       if (i < 2) {
         if (*str != ':')
@@ -187,19 +196,23 @@
       char * last_str = str;
       double part = strtod(str, &str);
       if (str == last_str)
-        return NULL;
+        return NULL; /* error: empty fractional part */
       *samples += rate * part + .5;
     }
-    return *str == 't'? str + 1 : str;
-  }
-  {
+    if (*str == 't')
+      str++;
+  } else {
     char * last_str = str;
     double part = strtod(str, &str);
     if (str == last_str)
-      return NULL;
+      return NULL; /* error: no sample count */
     *samples = part + .5;
-    return *str == 's'? str + 1 : str;
+    if (*str == 's')
+      str++;
   }
+  if (str != end)
+    return NULL; /* error: trailing characters */
+  return str;
 }
 
 #if 0
@@ -244,7 +257,7 @@
   TEST("1.1t,", 11000, 4)
   TEST("1.1t/", 11000, 4)
   TEST("1.1t@", 11000, 4)
-  TEST("1e6t" , 10000, 1)
+  assert(!lsx_parsesamples(10000, "1e6t", &samples, 't'));
 
   TEST(".0", 0, 2)
   TEST("0.0", 0, 3)