static String processFileDateString(const FTPTime& fileTime) { // FIXME: Need to localize this string? String timeOfDay; if (!(fileTime.tm_hour == 0 && fileTime.tm_min == 0 && fileTime.tm_sec == 0)) { int hour = fileTime.tm_hour; ASSERT(hour >= 0 && hour < 24); if (hour < 12) { if (hour == 0) hour = 12; timeOfDay = String::format(", %i:%02i AM", hour, fileTime.tm_min); } else { hour = hour - 12; if (hour == 0) hour = 12; timeOfDay = String::format(", %i:%02i PM", hour, fileTime.tm_min); } } // If it was today or yesterday, lets just do that - but we have to compare to the current time GregorianDateTime now; now.setToCurrentLocalTime(); if (fileTime.tm_year == now.year()) { if (fileTime.tm_mon == now.month()) { if (fileTime.tm_mday == now.monthDay()) return "Today" + timeOfDay; if (fileTime.tm_mday == now.monthDay() - 1) return "Yesterday" + timeOfDay; } if (now.monthDay() == 1 && (now.month() == fileTime.tm_mon + 1 || (now.month() == 0 && fileTime.tm_mon == 11)) && wasLastDayOfMonth(fileTime.tm_year, fileTime.tm_mon, fileTime.tm_mday)) return "Yesterday" + timeOfDay; } if (fileTime.tm_year == now.year() - 1 && fileTime.tm_mon == 12 && fileTime.tm_mday == 31 && now.month() == 1 && now.monthDay() == 1) return "Yesterday" + timeOfDay; static const char* months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "???" }; int month = fileTime.tm_mon; if (month < 0 || month > 11) month = 12; String dateString; if (fileTime.tm_year > -1) dateString = String(months[month]) + " " + String::number(fileTime.tm_mday) + ", " + String::number(fileTime.tm_year); else dateString = String(months[month]) + " " + String::number(fileTime.tm_mday) + ", " + String::number(now.year()); return dateString + timeOfDay; }
static double millisecondsFromComponents(ExecState* exec, const ArgList& args, WTF::TimeType timeType) { double doubleArguments[] = { args.at(0).toNumber(exec), args.at(1).toNumber(exec), args.at(2).toNumber(exec), args.at(3).toNumber(exec), args.at(4).toNumber(exec), args.at(5).toNumber(exec), args.at(6).toNumber(exec) }; int numArgs = args.size(); if ((!std::isfinite(doubleArguments[0]) || (doubleArguments[0] > INT_MAX) || (doubleArguments[0] < INT_MIN)) || (!std::isfinite(doubleArguments[1]) || (doubleArguments[1] > INT_MAX) || (doubleArguments[1] < INT_MIN)) || (numArgs >= 3 && (!std::isfinite(doubleArguments[2]) || (doubleArguments[2] > INT_MAX) || (doubleArguments[2] < INT_MIN))) || (numArgs >= 4 && (!std::isfinite(doubleArguments[3]) || (doubleArguments[3] > INT_MAX) || (doubleArguments[3] < INT_MIN))) || (numArgs >= 5 && (!std::isfinite(doubleArguments[4]) || (doubleArguments[4] > INT_MAX) || (doubleArguments[4] < INT_MIN))) || (numArgs >= 6 && (!std::isfinite(doubleArguments[5]) || (doubleArguments[5] > INT_MAX) || (doubleArguments[5] < INT_MIN))) || (numArgs >= 7 && (!std::isfinite(doubleArguments[6]) || (doubleArguments[6] > INT_MAX) || (doubleArguments[6] < INT_MIN)))) return PNaN; GregorianDateTime t; int year = JSC::toInt32(doubleArguments[0]); t.setYear((year >= 0 && year <= 99) ? (year + 1900) : year); t.setMonth(JSC::toInt32(doubleArguments[1])); t.setMonthDay((numArgs >= 3) ? JSC::toInt32(doubleArguments[2]) : 1); t.setHour(JSC::toInt32(doubleArguments[3])); t.setMinute(JSC::toInt32(doubleArguments[4])); t.setSecond(JSC::toInt32(doubleArguments[5])); t.setIsDST(-1); double ms = (numArgs >= 7) ? doubleArguments[6] : 0; return gregorianDateTimeToMS(exec->vm(), t, ms, timeType); }
static EncodedJSValue JSC_HOST_CALL dateUTC(ExecState* exec) { double doubleArguments[7] = { exec->argument(0).toNumber(exec), exec->argument(1).toNumber(exec), exec->argument(2).toNumber(exec), exec->argument(3).toNumber(exec), exec->argument(4).toNumber(exec), exec->argument(5).toNumber(exec), exec->argument(6).toNumber(exec) }; int n = exec->argumentCount(); if (isnan(doubleArguments[0]) || isnan(doubleArguments[1]) || (n >= 3 && isnan(doubleArguments[2])) || (n >= 4 && isnan(doubleArguments[3])) || (n >= 5 && isnan(doubleArguments[4])) || (n >= 6 && isnan(doubleArguments[5])) || (n >= 7 && isnan(doubleArguments[6]))) return JSValue::encode(jsNaN()); GregorianDateTime t; int year = JSC::toInt32(doubleArguments[0]); t.setYear((year >= 0 && year <= 99) ? (year + 1900) : year); t.setMonth(JSC::toInt32(doubleArguments[1])); t.setMonthDay((n >= 3) ? JSC::toInt32(doubleArguments[2]) : 1); t.setHour(JSC::toInt32(doubleArguments[3])); t.setMinute(JSC::toInt32(doubleArguments[4])); t.setSecond(JSC::toInt32(doubleArguments[5])); double ms = (n >= 7) ? doubleArguments[6] : 0; return JSValue::encode(jsNumber(timeClip(gregorianDateTimeToMS(exec, t, ms, true)))); }
// ECMA 15.9.3 JSObject* constructDate(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args) { VM& vm = exec->vm(); int numArgs = args.size(); double value; if (numArgs == 0) // new Date() ECMA 15.9.3.3 value = jsCurrentTime(); else if (numArgs == 1) { if (args.at(0).inherits(DateInstance::info())) value = asDateInstance(args.at(0))->internalNumber(); else { JSValue primitive = args.at(0).toPrimitive(exec); if (primitive.isString()) value = parseDate(vm, primitive.getString(exec)); else value = primitive.toNumber(exec); } } else { double doubleArguments[7] = { args.at(0).toNumber(exec), args.at(1).toNumber(exec), args.at(2).toNumber(exec), args.at(3).toNumber(exec), args.at(4).toNumber(exec), args.at(5).toNumber(exec), args.at(6).toNumber(exec) }; if (!std::isfinite(doubleArguments[0]) || !std::isfinite(doubleArguments[1]) || (numArgs >= 3 && !std::isfinite(doubleArguments[2])) || (numArgs >= 4 && !std::isfinite(doubleArguments[3])) || (numArgs >= 5 && !std::isfinite(doubleArguments[4])) || (numArgs >= 6 && !std::isfinite(doubleArguments[5])) || (numArgs >= 7 && !std::isfinite(doubleArguments[6]))) value = QNaN; else { GregorianDateTime t; int year = JSC::toInt32(doubleArguments[0]); t.setYear((year >= 0 && year <= 99) ? (year + 1900) : year); t.setMonth(JSC::toInt32(doubleArguments[1])); t.setMonthDay((numArgs >= 3) ? JSC::toInt32(doubleArguments[2]) : 1); t.setHour(JSC::toInt32(doubleArguments[3])); t.setMinute(JSC::toInt32(doubleArguments[4])); t.setSecond(JSC::toInt32(doubleArguments[5])); t.setIsDST(-1); double ms = (numArgs >= 7) ? doubleArguments[6] : 0; value = gregorianDateTimeToMS(vm, t, ms, false); } } return DateInstance::create(vm, globalObject->dateStructure(), value); }
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec) { JSValue thisValue = exec->thisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); VM& vm = exec->vm(); DateInstance* thisDateObj = asDateInstance(thisValue); if (!exec->argumentCount()) { JSValue result = jsNaN(); thisDateObj->setInternalValue(vm, result); return JSValue::encode(result); } double milli = thisDateObj->internalNumber(); double ms = 0; GregorianDateTime gregorianDateTime; if (std::isnan(milli)) // Based on ECMA 262 B.2.5 (setYear) // the time must be reset to +0 if it is NaN. msToGregorianDateTime(vm, 0, true, gregorianDateTime); else { double secs = floor(milli / msPerSecond); ms = milli - secs * msPerSecond; if (const GregorianDateTime* other = thisDateObj->gregorianDateTime(exec)) gregorianDateTime.copyFrom(*other); } double year = exec->argument(0).toIntegerPreserveNaN(exec); if (!std::isfinite(year)) { JSValue result = jsNaN(); thisDateObj->setInternalValue(vm, result); return JSValue::encode(result); } gregorianDateTime.setYear(toInt32((year >= 0 && year <= 99) ? (year + 1900) : year)); JSValue result = jsNumber(gregorianDateTimeToMS(vm, gregorianDateTime, ms, false)); thisDateObj->setInternalValue(vm, result); return JSValue::encode(result); }
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(&DateInstance::info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); if (!exec->argumentCount()) { JSValue result = jsNaN(exec); thisDateObj->setInternalValue(result); return JSValue::encode(result); } double milli = thisDateObj->internalNumber(); double ms = 0; GregorianDateTime gregorianDateTime; if (isnan(milli)) // Based on ECMA 262 B.2.5 (setYear) // the time must be reset to +0 if it is NaN. msToGregorianDateTime(exec, 0, true, gregorianDateTime); else { double secs = floor(milli / msPerSecond); ms = milli - secs * msPerSecond; if (const GregorianDateTime* other = thisDateObj->gregorianDateTime(exec)) gregorianDateTime.copyFrom(*other); } bool ok = true; int32_t year = exec->argument(0).toInt32(exec, ok); if (!ok) { JSValue result = jsNaN(exec); thisDateObj->setInternalValue(result); return JSValue::encode(result); } gregorianDateTime.year = (year > 99 || year < 0) ? year - 1900 : year; JSValue result = jsNumber(exec, gregorianDateTimeToMS(exec, gregorianDateTime, ms, false)); thisDateObj->setInternalValue(result); return JSValue::encode(result); }
static EncodedJSValue setNewValueFromDateArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC) { JSValue thisValue = exec->thisValue(); if (!thisValue.inherits(DateInstance::info())) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); if (!exec->argumentCount()) { JSValue result = jsNaN(); thisDateObj->setInternalValue(exec->vm(), result); return JSValue::encode(result); } VM& vm = exec->vm(); double milli = thisDateObj->internalNumber(); double ms = 0; GregorianDateTime gregorianDateTime; if (numArgsToUse == 3 && std::isnan(milli)) msToGregorianDateTime(vm, 0, true, gregorianDateTime); else { ms = milli - floor(milli / msPerSecond) * msPerSecond; const GregorianDateTime* other = inputIsUTC ? thisDateObj->gregorianDateTimeUTC(exec) : thisDateObj->gregorianDateTime(exec); if (!other) return JSValue::encode(jsNaN()); gregorianDateTime.copyFrom(*other); } if (!fillStructuresUsingDateArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) { JSValue result = jsNaN(); thisDateObj->setInternalValue(vm, result); return JSValue::encode(result); } JSValue result = jsNumber(gregorianDateTimeToMS(vm, gregorianDateTime, ms, inputIsUTC)); thisDateObj->setInternalValue(vm, result); return JSValue::encode(result); }
void DateInstance::msToGregorianDateTime(double milli, bool outputIsUTC, GregorianDateTime& t) const { if (!m_cache) { m_cache = new Cache; m_cache->m_gregorianDateTimeCachedForMS = NaN; m_cache->m_gregorianDateTimeUTCCachedForMS = NaN; } if (outputIsUTC) { if (m_cache->m_gregorianDateTimeUTCCachedForMS != milli) { JSC::msToGregorianDateTime(milli, true, m_cache->m_cachedGregorianDateTimeUTC); m_cache->m_gregorianDateTimeUTCCachedForMS = milli; } t.copyFrom(m_cache->m_cachedGregorianDateTimeUTC); } else { if (m_cache->m_gregorianDateTimeCachedForMS != milli) { JSC::msToGregorianDateTime(milli, false, m_cache->m_cachedGregorianDateTime); m_cache->m_gregorianDateTimeCachedForMS = milli; } t.copyFrom(m_cache->m_cachedGregorianDateTime); } }
static EncodedJSValue setNewValueFromTimeArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC) { JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(&DateInstance::s_info)) return throwVMTypeError(exec); DateInstance* thisDateObj = asDateInstance(thisValue); double milli = thisDateObj->internalNumber(); if (!exec->argumentCount() || isnan(milli)) { JSValue result = jsNaN(); thisDateObj->setInternalValue(exec->globalData(), result); return JSValue::encode(result); } double secs = floor(milli / msPerSecond); double ms = milli - secs * msPerSecond; const GregorianDateTime* other = inputIsUTC ? thisDateObj->gregorianDateTimeUTC(exec) : thisDateObj->gregorianDateTime(exec); if (!other) return JSValue::encode(jsNaN()); GregorianDateTime gregorianDateTime; gregorianDateTime.copyFrom(*other); if (!fillStructuresUsingTimeArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) { JSValue result = jsNaN(); thisDateObj->setInternalValue(exec->globalData(), result); return JSValue::encode(result); } JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, inputIsUTC)); thisDateObj->setInternalValue(exec->globalData(), result); return JSValue::encode(result); }
double gregorianDateTimeToMS(VM& vm, const GregorianDateTime& t, double milliSeconds, WTF::TimeType inputTimeType) { double day = dateToDaysFrom1970(t.year(), t.month(), t.monthDay()); double ms = timeToMS(t.hour(), t.minute(), t.second(), milliSeconds); double localTimeResult = (day * WTF::msPerDay) + ms; double localToUTCTimeOffset = inputTimeType == LocalTime ? localTimeOffset(vm, localTimeResult, inputTimeType).offset : 0; return localTimeResult - localToUTCTimeOffset; }
double gregorianDateTimeToMS(ExecState* exec, const GregorianDateTime& t, double milliSeconds, bool inputIsUTC) { double day = dateToDaysFrom1970(t.year(), t.month(), t.monthDay()); double ms = timeToMS(t.hour(), t.minute(), t.second(), milliSeconds); double result = (day * WTF::msPerDay) + ms; if (!inputIsUTC) { // convert to UTC double utcOffset = getUTCOffset(exec); result -= utcOffset; result -= getDSTOffset(exec, result, utcOffset); } return result; }
// input is UTC void msToGregorianDateTime(ExecState* exec, double ms, bool outputIsUTC, GregorianDateTime& tm) { double dstOff = 0.0; double utcOff = 0.0; if (!outputIsUTC) { utcOff = getUTCOffset(exec); dstOff = getDSTOffset(exec, ms, utcOff); ms += dstOff + utcOff; } const int year = msToYear(ms); tm.setSecond(msToSeconds(ms)); tm.setMinute(msToMinutes(ms)); tm.setHour(msToHours(ms)); tm.setWeekDay(msToWeekDay(ms)); tm.setYearDay(dayInYear(ms, year)); tm.setMonthDay(dayInMonthFromDayInYear(tm.yearDay(), isLeapYear(year))); tm.setMonth(monthFromDayInYear(tm.yearDay(), isLeapYear(year))); tm.setYear(year); tm.setIsDST(dstOff != 0.0); tm.setUtcOffset(static_cast<long>((dstOff + utcOff) / WTF::msPerSecond)); }
// input is UTC void msToGregorianDateTime(VM& vm, double ms, WTF::TimeType outputTimeType, GregorianDateTime& tm) { LocalTimeOffset localTime; if (outputTimeType == WTF::LocalTime) { localTime = localTimeOffset(vm, ms); ms += localTime.offset; } const int year = msToYear(ms); tm.setSecond(msToSeconds(ms)); tm.setMinute(msToMinutes(ms)); tm.setHour(msToHours(ms)); tm.setWeekDay(msToWeekDay(ms)); tm.setYearDay(dayInYear(ms, year)); tm.setMonthDay(dayInMonthFromDayInYear(tm.yearDay(), isLeapYear(year))); tm.setMonth(monthFromDayInYear(tm.yearDay(), isLeapYear(year))); tm.setYear(year); tm.setIsDST(localTime.isDST); tm.setUtcOffset(localTime.offset / WTF::msPerSecond); }
PassRefPtr<SharedBuffer> MHTMLArchive::generateMHTMLData(Page* page) { Vector<PageSerializer::Resource> resources; PageSerializer pageSerializer(&resources); pageSerializer.serialize(page); String boundary = generateRandomBoundary(); String endOfResourceBoundary = makeString("--", boundary, "\r\n"); GregorianDateTime now; now.setToCurrentLocalTime(); String dateString = makeRFC2822DateString(now.weekDay(), now.monthDay(), now.month(), now.year(), now.hour(), now.minute(), now.second(), now.utcOffset() / 60); StringBuilder stringBuilder; stringBuilder.append("From: <Saved by WebKit>\r\n"); stringBuilder.append("Subject: "); // We replace non ASCII characters with '?' characters to match IE's behavior. stringBuilder.append(replaceNonPrintableCharacters(page->mainFrame().document()->title())); stringBuilder.append("\r\nDate: "); stringBuilder.append(dateString); stringBuilder.append("\r\nMIME-Version: 1.0\r\n"); stringBuilder.append("Content-Type: multipart/related;\r\n"); stringBuilder.append("\ttype=\""); stringBuilder.append(page->mainFrame().document()->suggestedMIMEType()); stringBuilder.append("\";\r\n"); stringBuilder.append("\tboundary=\""); stringBuilder.append(boundary); stringBuilder.append("\"\r\n\r\n"); // We use utf8() below instead of ascii() as ascii() replaces CRLFs with ?? (we still only have put ASCII characters in it). ASSERT(stringBuilder.toString().containsOnlyASCII()); CString asciiString = stringBuilder.toString().utf8(); RefPtr<SharedBuffer> mhtmlData = SharedBuffer::create(); mhtmlData->append(asciiString.data(), asciiString.length()); for (auto& resource : resources) { stringBuilder.clear(); stringBuilder.append(endOfResourceBoundary); stringBuilder.append("Content-Type: "); stringBuilder.append(resource.mimeType); const char* contentEncoding = nullptr; if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(resource.mimeType) || MIMETypeRegistry::isSupportedNonImageMIMEType(resource.mimeType)) contentEncoding = quotedPrintable; else contentEncoding = base64; stringBuilder.append("\r\nContent-Transfer-Encoding: "); stringBuilder.append(contentEncoding); stringBuilder.append("\r\nContent-Location: "); stringBuilder.append(resource.url); stringBuilder.append("\r\n\r\n"); asciiString = stringBuilder.toString().utf8(); mhtmlData->append(asciiString.data(), asciiString.length()); // FIXME: ideally we would encode the content as a stream without having to fetch it all. const char* data = resource.data->data(); size_t dataLength = resource.data->size(); Vector<char> encodedData; if (!strcmp(contentEncoding, quotedPrintable)) { quotedPrintableEncode(data, dataLength, encodedData); mhtmlData->append(encodedData.data(), encodedData.size()); mhtmlData->append("\r\n", 2); } else { ASSERT(!strcmp(contentEncoding, base64)); // We are not specifying insertLFs = true below as it would cut the lines with LFs and MHTML requires CRLFs. base64Encode(data, dataLength, encodedData); const size_t maximumLineLength = 76; size_t index = 0; size_t encodedDataLength = encodedData.size(); do { size_t lineLength = std::min(encodedDataLength - index, maximumLineLength); mhtmlData->append(encodedData.data() + index, lineLength); mhtmlData->append("\r\n", 2); index += maximumLineLength; } while (index < encodedDataLength); } } asciiString = makeString("--", boundary, "--\r\n").utf8(); mhtmlData->append(asciiString.data(), asciiString.length()); return mhtmlData.release(); }