VMProtect/runtime/CFGregorianDateCreate.hpp

304 lines
7.1 KiB
C++

/* Arrays of asctime-date day and month strs, rfc1123-date day and month strs, and rfc850-date day and month strs. */
static const char* kDayStrs[] = {
"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday",
"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
static const char* kMonthStrs[] = {
"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December",
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
/* NOTE that these are ordered this way on purpose. */
static const char* kUSTimeZones[] = {"PST", "PDT", "MST", "MDT", "CST", "CDT", "EST", "EDT"};
/* extern */ const UInt8*
_CFGregorianDateCreateWithBytes(CFAllocatorRef alloc, const UInt8* bytes, CFIndex length, CFGregorianDate* date, CFTimeZoneRef* tz) {
UInt8 buffer[256]; /* Any dates longer than this are not understood. */
length = (length == 256) ? 255 : length;
memmove(buffer, bytes, length);
buffer[length] = '\0'; /* Guarantees every compare will fail if trying to index off the end. */
memset(date, 0, sizeof(date[0]));
if (tz) *tz = NULL;
do {
size_t i;
CFIndex scan = 0;
UInt8 c = buffer[scan];
/* Skip leading whitespace */
while (isspace(c))
c = buffer[++scan];
/* Check to see if there is a weekday up front. */
if (!isdigit(c)) {
for (i = 0; i < (sizeof(kDayStrs) / sizeof(kDayStrs[0])); i++) {
if (!memcmp(kDayStrs[i], &buffer[scan], strlen(kDayStrs[i])))
break;
}
if (i >=(sizeof(kDayStrs) / sizeof(kDayStrs[0])))
break;
scan += strlen(kDayStrs[i]);
c = buffer[scan];
while (isspace(c) || c == ',')
c = buffer[++scan];
}
/* check for asctime where month comes first */
if (!isdigit(c)) {
for (i = 0; i < (sizeof(kMonthStrs) / sizeof(kMonthStrs[0])); i++) {
if (!memcmp(kMonthStrs[i], &buffer[scan], strlen(kMonthStrs[i])))
break;
}
if (i >= (sizeof(kMonthStrs) / sizeof(kMonthStrs[0])))
break;
date->month = (i % 12) + 1;
scan += strlen(kMonthStrs[i]);
c = buffer[scan];
while (isspace(c))
c = buffer[++scan];
if (!isdigit(c))
break;
}
/* Read the day of month */
for (i = 0; isdigit(c) && (i < 2); i++) {
date->day *= 10;
date->day += c - '0';
c = buffer[++scan];
}
while (isspace(c) || c == '-')
c = buffer[++scan];
/* Not asctime so now comes the month. */
if (date->month == 0) {
if (isdigit(c)) {
for (i = 0; isdigit(c) && (i < 2); i++) {
date->month *= 10;
date->month += c - '0';
c = buffer[++scan];
}
}
else {
for (i = 0; i < (sizeof(kMonthStrs) / sizeof(kMonthStrs[0])); i++) {
if (!memcmp(kMonthStrs[i], &buffer[scan], strlen(kMonthStrs[i])))
break;
}
if (i >= (sizeof(kMonthStrs) / sizeof(kMonthStrs[0])))
break;
date->month = (i % 12) + 1;
scan += strlen(kMonthStrs[i]);
c = buffer[scan];
}
while (isspace(c) || c == '-')
c = buffer[++scan];
/* Read the year */
for (i = 0; isdigit(c) && (i < 4); i++) {
date->year *= 10;
date->year += c - '0';
c = buffer[++scan];
}
while (isspace(c))
c = buffer[++scan];
}
/* Read the hours */
for (i = 0; isdigit(c) && (i < 2); i++) {
date->hour *= 10;
date->hour += c - '0';
c = buffer[++scan];
}
if (c != ':')
break;
c = buffer[++scan];
/* Read the minutes */
for (i = 0; isdigit(c) && (i < 2); i++) {
date->minute *= 10;
date->minute += c - '0';
c = buffer[++scan];
}
if (c == ':') {
c = buffer[++scan];
/* Read the seconds */
for (i = 0; isdigit(c) && (i < 2); i++) {
date->second *= 10;
date->second += c - '0';
c = buffer[++scan];
}
c = buffer[++scan];
}
/* If haven't read the year yet, now is the time. */
if (date->year == 0) {
while (isspace(c))
c = buffer[++scan];
/* Read the year */
for (i = 0; isdigit(c) && (i < 4); i++) {
date->year *= 10;
date->year += c - '0';
c = buffer[++scan];
}
}
if (date->year && date->year < 100) {
if (date->year < 70)
date->year += 2000; /* My CC is still using 2-digit years! */
else
date->year += 1900; /* Bad 2 byte clients */
}
while (isspace(c))
c = buffer[++scan];
if (c && tz) {
/* If it has absolute offset, read the hours and minutes. */
if ((c == '+') || (c == '-')) {
char sign = c;
CFTimeInterval minutes = 0, offset = 0;
c = buffer[++scan];
/* Read the hours */
for (i = 0; isdigit(c) && (i < 2); i++) {
offset *= 10;
offset += c - '0';
c = buffer[++scan];
}
/* Read the minutes */
for (i = 0; isdigit(c) && (i < 2); i++) {
minutes *= 10;
minutes += c - '0';
c = buffer[++scan];
}
offset *= 60;
offset += minutes;
if (sign == '-') offset *= -60;
else offset *= 60;
*tz = CFTimeZoneCreateWithTimeIntervalFromGMT(alloc, offset);
}
/* If it's not GMT/UT time, need to parse the alpha offset. */
else if (!strncmp((const char*)(&buffer[scan]), "UT", 2)) {
*tz = CFTimeZoneCreateWithTimeIntervalFromGMT(alloc, 0);
scan += 2;
}
else if (!strncmp((const char*)(&buffer[scan]), "GMT", 3)) {
*tz = CFTimeZoneCreateWithTimeIntervalFromGMT(alloc, 0);
scan += 3;
}
else if (isalpha(c)) {
UInt8 next = buffer[scan + 1];
/* Check for military time. */
if ((c != 'J') && (!next || isspace(next) || (next == '*'))) {
if (c == 'Z')
*tz = CFTimeZoneCreateWithTimeIntervalFromGMT(alloc, 0);
else {
CFTimeInterval offset = (c < 'N') ? (c - 'A' + 1) : ('M' - c);
offset *= 60;
if (next == '*') {
scan++;
offset = (offset < 0) ? offset - 30 : offset + 30;
}
offset *= 60;
*tz = CFTimeZoneCreateWithTimeIntervalFromGMT(alloc, 0);
}
}
else {
for (i = 0; i < (sizeof(kUSTimeZones) / sizeof(kUSTimeZones[0])); i++) {
if (!memcmp(kUSTimeZones[i], &buffer[scan], strlen(kUSTimeZones[i]))) {
*tz = CFTimeZoneCreateWithTimeIntervalFromGMT(alloc, (-8 + (i >> 2) + (i & 0x1)) * 3600);
scan += strlen(kUSTimeZones[i]);
break;
}
}
}
}
}
if (!CFGregorianDateIsValid(*date, kCFGregorianAllUnits))
break;
return bytes + scan;
} while (1);
memset(date, 0, sizeof(date[0]));
if (tz) {
if (*tz) CFRelease(*tz);
*tz = NULL;
}
return bytes;
}
/* extern */ CFIndex
_CFGregorianDateCreateWithString(CFAllocatorRef alloc, CFStringRef str, CFGregorianDate* date, CFTimeZoneRef* tz) {
UInt8 buffer[256]; /* Any dates longer than this are not understood. */
CFIndex length = CFStringGetLength(str);
CFIndex result = 0;
CFStringGetBytes(str, CFRangeMake(0, length), kCFStringEncodingASCII, 0, FALSE, buffer, sizeof(buffer), &length);
if (length)
result = _CFGregorianDateCreateWithBytes(alloc, buffer, length, date, tz) - buffer;
else {
memset(date, 0, sizeof(date[0]));
if (tz) *tz = NULL;
}
return result;
}