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)