@@ -49886,23 +49886,28 @@ static BOOL string_skip_char(const uint8_t *sp, int *pp, int c) {
4988649886 }
4988749887}
4988849888
49889- /* skip spaces, update offset */
49890- static void string_skip_spaces(const uint8_t *sp, int *pp) {
49891- while (sp[*pp] == ' ')
49889+ /* skip spaces, update offset, return next char */
49890+ static int string_skip_spaces(const uint8_t *sp, int *pp) {
49891+ int c;
49892+ while ((c = sp[*pp]) == ' ')
4989249893 *pp += 1;
49894+ return c;
4989349895}
4989449896
4989549897/* skip dashes dots and commas */
49896- static void string_skip_separators(const uint8_t *sp, int *pp) {
49898+ static int string_skip_separators(const uint8_t *sp, int *pp) {
4989749899 int c;
49898- while ((c = sp[*pp]) == '-' || c == '.' || c == ',')
49900+ while ((c = sp[*pp]) == '-' || c == '/' || c == ' .' || c == ',')
4989949901 *pp += 1;
49902+ return c;
4990049903}
4990149904
49902- /* skip non spaces, update offset */
49903- static void string_skip_non_spaces(const uint8_t *sp, int *pp) {
49904- while (sp[*pp] != '\0' && sp[*pp] != ' ')
49905+ /* skip a word, stop on spaces, digits and separators, update offset */
49906+ static int string_skip_until(const uint8_t *sp, int *pp, const char *stoplist) {
49907+ int c;
49908+ while (!strchr(stoplist, c = sp[*pp]))
4990549909 *pp += 1;
49910+ return c;
4990649911}
4990749912
4990849913/* parse a numeric field (max_digits = 0 -> no maximum) */
@@ -49950,37 +49955,52 @@ static BOOL string_get_milliseconds(const uint8_t *sp, int *pp, int *pval) {
4995049955 return TRUE;
4995149956}
4995249957
49953- static BOOL string_get_timezone(const uint8_t *sp, int *pp, int *tzp) {
49958+ static BOOL string_get_timezone(const uint8_t *sp, int *pp, int *tzp, BOOL strict ) {
4995449959 int tz = 0, sgn, hh, mm, p = *pp;
4995549960
49956- sgn = sp[p];
49961+ sgn = sp[p++ ];
4995749962 if (sgn == '+' || sgn == '-') {
49958- p++ ;
49959- if (!string_get_digits(sp, &p, &hh, 2, 2 ))
49963+ int n = p ;
49964+ if (!string_get_digits(sp, &p, &hh, 1, 9 ))
4996049965 return FALSE;
49961- string_skip_char(sp, &p, ':'); /* optional separator */
49962- if (!string_get_digits(sp, &p, &mm, 2, 2) )
49966+ n = p - n;
49967+ if (strict && n != 2 && n != 4 )
4996349968 return FALSE;
49969+ while (n > 4) {
49970+ n -= 2;
49971+ hh /= 100;
49972+ }
49973+ if (n > 2) {
49974+ mm = hh % 100;
49975+ hh = hh / 100;
49976+ } else {
49977+ mm = 0;
49978+ if (string_skip_char(sp, &p, ':') /* optional separator */
49979+ && !string_get_digits(sp, &p, &mm, 2, 2))
49980+ return FALSE;
49981+ }
4996449982 if (hh > 23 || mm > 59)
4996549983 return FALSE;
4996649984 tz = hh * 60 + mm;
4996749985 if (sgn != '+')
4996849986 tz = -tz;
4996949987 } else
49970- if (sgn == 'Z') {
49971- p++;
49972- } else {
49988+ if (sgn != 'Z') {
4997349989 return FALSE;
4997449990 }
4997549991 *pp = p;
4997649992 *tzp = tz;
4997749993 return TRUE;
4997849994}
4997949995
49996+ static uint8_t upper_ascii(uint8_t c) {
49997+ return c >= 'a' && c <= 'z' ? c - 'a' + 'Z' : c;
49998+ }
49999+
4998050000static BOOL string_match(const uint8_t *sp, int *pp, const char *s) {
4998150001 int p = *pp;
4998250002 while (*s != '\0') {
49983- if (sp[p] != (uint8_t) *s++)
50003+ if (upper_ascii( sp[p]) != upper_ascii( *s++) )
4998450004 return FALSE;
4998550005 p++;
4998650006 }
@@ -49993,7 +50013,7 @@ static int find_abbrev(const uint8_t *sp, int p, const char *list, int count) {
4999350013
4999450014 for (n = 0; n < count; n++) {
4999550015 for (i = 0;; i++) {
49996- if (sp[p + i] != (uint8_t)month_names [n * 3 + i])
50016+ if (upper_ascii( sp[p + i]) != upper_ascii(list [n * 3 + i]) )
4999750017 break;
4999850018 if (i == 2)
4999950019 return n;
@@ -50056,8 +50076,10 @@ static BOOL js_date_parse_isostring(const uint8_t *sp, int fields[9], BOOL *is_l
5005650076 *is_local = TRUE;
5005750077 if (!string_get_digits(sp, &p, &fields[3], 2, 2) /* hour */
5005850078 || !string_skip_char(sp, &p, ':')
50059- || !string_get_digits(sp, &p, &fields[4], 2, 2)) /* minute */
50060- return FALSE;
50079+ || !string_get_digits(sp, &p, &fields[4], 2, 2)) { /* minute */
50080+ fields[3] = 100; // reject unconditionally
50081+ return TRUE;
50082+ }
5006150083 if (string_skip_char(sp, &p, ':')) {
5006250084 if (!string_get_digits(sp, &p, &fields[5], 2, 2)) /* second */
5006350085 return FALSE;
@@ -50067,7 +50089,7 @@ static BOOL js_date_parse_isostring(const uint8_t *sp, int fields[9], BOOL *is_l
5006750089 /* parse the time zone offset if present: [+-]HH:mm or [+-]HHmm */
5006850090 if (sp[p]) {
5006950091 *is_local = FALSE;
50070- if (!string_get_timezone(sp, &p, &fields[8]))
50092+ if (!string_get_timezone(sp, &p, &fields[8], TRUE ))
5007150093 return FALSE;
5007250094 }
5007350095 /* error if extraneous characters */
@@ -50092,11 +50114,10 @@ static BOOL js_date_parse_otherstring(const uint8_t *sp, int fields[9], BOOL *is
5009250114 }
5009350115 *is_local = TRUE;
5009450116
50095- while (sp[p] != '\0') {
50096- string_skip_spaces(sp, &p);
50117+ while (string_skip_spaces(sp, &p)) {
5009750118 p_start = p;
5009850119 if ((c = sp[p]) == '+' || c == '-') {
50099- if (has_time && string_get_timezone(sp, &p, &fields[8])) {
50120+ if (has_time && string_get_timezone(sp, &p, &fields[8], FALSE )) {
5010050121 *is_local = FALSE;
5010150122 } else {
5010250123 p++;
@@ -50129,7 +50150,7 @@ static BOOL js_date_parse_otherstring(const uint8_t *sp, int fields[9], BOOL *is
5012950150 has_year = TRUE;
5013050151 } else
5013150152 if (val < 1 || val > 31) {
50132- fields[0] = val + (val < 100) * 1900;
50153+ fields[0] = val + (val < 100) * 1900 + (val < 50) * 100 ;
5013350154 has_year = TRUE;
5013450155 } else {
5013550156 if (num_index == 3)
@@ -50140,19 +50161,73 @@ static BOOL js_date_parse_otherstring(const uint8_t *sp, int fields[9], BOOL *is
5014050161 } else
5014150162 if (string_get_month(sp, &p, &fields[1])) {
5014250163 has_mon = TRUE;
50164+ string_skip_until(sp, &p, "0123456789 -/(");
5014350165 } else
5014450166 if (c == 'Z') {
5014550167 *is_local = FALSE;
5014650168 p++;
5014750169 continue;
5014850170 } else
50149- if (string_match(sp, &p, "GMT") || string_match(sp, &p, "UTC")) {
50171+ if (has_time && string_match(sp, &p, "PM")) {
50172+ if (fields[3] < 12)
50173+ fields[3] += 12;
50174+ continue;
50175+ } else
50176+ if (has_time && string_match(sp, &p, "AM")) {
50177+ if (fields[3] == 12)
50178+ fields[3] -= 12;
50179+ continue;
50180+ } else
50181+ if (string_match(sp, &p, "GMT")
50182+ || string_match(sp, &p, "UTC")
50183+ || string_match(sp, &p, "UT")) {
50184+ *is_local = FALSE;
50185+ continue;
50186+ } else
50187+ if (string_match(sp, &p, "EDT")) {
50188+ fields[8] = -4 * 60;
50189+ *is_local = FALSE;
50190+ continue;
50191+ } else
50192+ if (string_match(sp, &p, "EST") || string_match(sp, &p, "CDT")) {
50193+ fields[8] = -5 * 60;
50194+ *is_local = FALSE;
50195+ continue;
50196+ } else
50197+ if (string_match(sp, &p, "CST") || string_match(sp, &p, "MDT")) {
50198+ fields[8] = -6 * 60;
50199+ *is_local = FALSE;
50200+ continue;
50201+ } else
50202+ if (string_match(sp, &p, "MST") || string_match(sp, &p, "PDT")) {
50203+ fields[8] = -7 * 60;
5015050204 *is_local = FALSE;
5015150205 continue;
50206+ } else
50207+ if (string_match(sp, &p, "PST")) {
50208+ fields[8] = -8 * 60;
50209+ *is_local = FALSE;
50210+ continue;
50211+ } else
50212+ if (c == '(') { /* skip parenthesized phrase */
50213+ int level = 0;
50214+ while ((c = sp[p]) != '\0') {
50215+ p++;
50216+ level += (c == '(');
50217+ level -= (c == ')');
50218+ if (!level)
50219+ break;
50220+ }
50221+ if (level > 0)
50222+ return FALSE;
50223+ } else
50224+ if (c == ')') {
50225+ return FALSE;
5015250226 } else {
50227+ if (has_year + has_mon + has_time + num_index)
50228+ return FALSE;
5015350229 /* skip a word */
50154- string_skip_non_spaces(sp, &p);
50155- continue;
50230+ string_skip_until(sp, &p, " -/(");
5015650231 }
5015750232 string_skip_separators(sp, &p);
5015850233 }
@@ -50176,15 +50251,15 @@ static BOOL js_date_parse_otherstring(const uint8_t *sp, int fields[9], BOOL *is
5017650251 fields[2] = num[1];
5017750252 } else
5017850253 if (has_mon) {
50179- fields[0] = num[1] + (num[1] < 100) * 1900;
50254+ fields[0] = num[1] + (num[1] < 100) * 1900 + (num[1] < 50) * 100 ;
5018050255 fields[2] = num[0];
5018150256 } else {
5018250257 fields[1] = num[0];
5018350258 fields[2] = num[1];
5018450259 }
5018550260 break;
5018650261 case 3:
50187- fields[0] = num[2] + (num[2] < 100) * 1900;
50262+ fields[0] = num[2] + (num[2] < 100) * 1900 + (num[2] < 50) * 100 ;
5018850263 fields[1] = num[0];
5018950264 fields[2] = num[1];
5019050265 break;
0 commit comments