diff options
Diffstat (limited to 'src/launcherutil.c')
| -rw-r--r-- | src/launcherutil.c | 135 |
1 files changed, 130 insertions, 5 deletions
diff --git a/src/launcherutil.c b/src/launcherutil.c index 4a866f5..11d5e00 100644 --- a/src/launcherutil.c +++ b/src/launcherutil.c @@ -252,11 +252,6 @@ int l2_launcher_mkdir_parents_ex(const char *path, unsigned ignore) return 0; } -char *l2_launcher_parse_iso_time(const char *str, struct tm *ts) -{ - return strptime(str, "%FT%T%z", ts); /* TODO: replace with something portable */ -} - void l2_launcher_download_init(struct l2_dlbuf *buf) { buf->data = NULL; @@ -655,3 +650,133 @@ int l2_launcher_ftw(const char *path, int depth, l2_ftw_proc_t *proc, void *user return res; } + +int l2_launcher__parse_u64(const char *num, size_t len, uint64_t *onum) +{ + uint64_t accum = 0; + for (; len; --len, ++num) { + accum *= 10; + if (*num >= '0' && *num <= '9') { + accum += *num - '0'; + } else { + return -1; + } + } + + *onum = accum; + return 0; +} + +int l2_parse_time(const char *timestr, time_t *ocaltime) +{ +#define L2_TM_PARSE_FIELD(_tmstr, _len, _tmp, _type, _field) do { \ + if (l2_launcher__parse_u64(_tmstr, _len, &(_tmp)) < 0) return -1; \ + _field = (_type)(_tmp); \ + _tmstr += _len; \ + } while (0) + +#define L2_TM_ENSURE_CHAR(_tmstr, _ch) do { \ + if (*(_tmstr) != _ch) return -1; \ + _tmstr += 1; \ + } while (0) + +#define L2_TM_ASSERT_RANGE(_field, _min, _max) do { \ + L2_DIAG_PUSH L2_DIAG_IGNORED(-Wtype-limits) \ + if (_field < _min || _field > _max) return -1; \ + L2_DIAG_POP \ + } while (0) + + uint64_t temp; + struct tm otime; + time_t timeres; + memset(&otime, 0, sizeof(otime)); + otime.tm_isdst = -1; + +#ifndef NDEBUG + const char *origstr = timestr; +#endif + + /* full-date */ + /* date-fullyear */ + L2_TM_PARSE_FIELD(timestr, 4, temp, int, otime.tm_year); + L2_TM_ENSURE_CHAR(timestr, '-'); + otime.tm_year -= 1900; + + /* date-month */ + L2_TM_PARSE_FIELD(timestr, 2, temp, int, otime.tm_mon); + L2_TM_ASSERT_RANGE(temp, 1, 12); + --otime.tm_mon; + + L2_TM_ENSURE_CHAR(timestr, '-'); + + /* date-mday */ + L2_TM_PARSE_FIELD(timestr, 2, temp, int, otime.tm_mday); + L2_TM_ASSERT_RANGE(temp, 1, 31); + + if (*timestr != 't' && *timestr != 'T') return -1; + ++timestr; + + /* full-time */ + + /* partial-time */ + /* time-hour */ + L2_TM_PARSE_FIELD(timestr, 2, temp, int, otime.tm_hour); + L2_TM_ASSERT_RANGE(temp, 0, 23); + L2_TM_ENSURE_CHAR(timestr, ':'); + + /* time-minute */ + L2_TM_PARSE_FIELD(timestr, 2, temp, int, otime.tm_min); + L2_TM_ASSERT_RANGE(temp, 0, 59); + L2_TM_ENSURE_CHAR(timestr, ':'); + + /* time-second */ + L2_TM_PARSE_FIELD(timestr, 2, temp, int, otime.tm_sec); + L2_TM_ASSERT_RANGE(temp, 0, 60); /* for leap seconds */ + + /* ignoring time-secfrac (idc about it lol) */ + if (*timestr == '.') { + do { + ++timestr; + } while (*timestr >= '0' && *timestr <= '9'); + } + + /* time-offset */ + if (*timestr == 'Z' || *timestr == 'z') { + goto done; + } + + int tzoff_mult; + switch (*timestr) { + case '+': + tzoff_mult = 1; + break; + case '-': + tzoff_mult = -1; + break; + default: return -1; + } + + ++timestr; + + CMD_DEBUG("trying to parse timestamp %s, which has zoneoffset. " + "This is not fully supported (contains bugs 100%% guaranteed or your money back)", origstr); + + int houroff; + L2_TM_PARSE_FIELD(timestr, 2, temp, int, houroff); + L2_TM_ASSERT_RANGE(houroff, 0, 23); + L2_TM_ENSURE_CHAR(timestr, ':'); + + int minoff; + L2_TM_PARSE_FIELD(timestr, 2, temp, int, minoff); + L2_TM_ASSERT_RANGE(minoff, 0, 59); + + otime.tm_hour -= houroff * tzoff_mult; + otime.tm_min -= minoff * tzoff_mult; + +done: + timeres = mktime(&otime); + if (timeres == (time_t)-1) return -1; + *ocaltime = timeres; + + return 0; +} |
