[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Gnash-commit] gnash/server/asobj Date.cpp
From: |
Martin Guy |
Subject: |
[Gnash-commit] gnash/server/asobj Date.cpp |
Date: |
Tue, 27 Feb 2007 22:45:51 +0000 |
CVSROOT: /sources/gnash
Module name: gnash
Changes by: Martin Guy <martinwguy> 07/02/27 22:45:51
Modified files:
server/asobj : Date.cpp
Log message:
Implement Date.UTC(). It is not yet initialised properly
(Date.UTC() still gives undefined)
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/Date.cpp?cvsroot=gnash&r1=1.25&r2=1.26
Patches:
Index: Date.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/Date.cpp,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -b -r1.25 -r1.26
--- Date.cpp 25 Feb 2007 16:38:10 -0000 1.25
+++ Date.cpp 27 Feb 2007 22:45:51 -0000 1.26
@@ -49,6 +49,21 @@
// It changes to/from daylight saving time according to its own rules.
// We use the operating system's localtime routines.
//
+// For portability it may be useful to convert this to use libboost's
+// date_time stuff http://www.boost.org/doc/html/date_time.html but the
+// mapping between Flash's perverse behaviour and date_time's coherent
+// behaviour.
+// Plus:
+// * OS portability is done by libboost, not here;
+// * extends correct date handling from POSIX to 1 Jan 1400 - 31 Dec 9999
+// Minus:
+// * it doesn't handle fractions of milliseconds (and who cares?);
+// * using it to implement this class's methods is more tricky,
+// including the need to handle all boundary cases and exceptions
+// explicitly (e.g. mapping of 38 Nov to 8 Dec, mapping negative
+// month/day-of-month/hours/min/secs/millisecs into the previous
+// year/month/day/hour/min/sec and so on).
+//
// To probe FlashPlayer functionality put something like:
// class Test {
// }
@@ -114,7 +129,7 @@
//
// Currently, without this, setting times in UTC to a moment when DST is active
// gets the hour and datestamp wrong, and changing the date into/out of a
-// DST period without adjusts the UTC time of day (it shouldn't).
+// DST period changes the UTC time of day (it shouldn't).
#define USE_UTCCONV 1
#if USE_UTCCONV
@@ -179,7 +194,8 @@
// To do this we set tm_isdst to the correct value for that moment in time
// by doing an initial conversion of the time to find out is_dst for that
// moment without DST, then do the real conversion.
-// This may get things wrong around the hour when the clocks go back or forth.
+// This may still get things wrong around the hour when the clocks go back
+// or forth.
static time_t
_mktime(struct tm *tmp)
{
@@ -234,7 +250,9 @@
static void date_tostring(const fn_call& fn);
static void date_valueof(const fn_call& fn);
+// Static AS methods
static void date_utc(const fn_call& fn);
+
static as_object* getDateInterface();
static void attachDateInterface(as_object& o);
static void attachDateStaticInterface(as_object& o);
@@ -285,7 +303,7 @@
attachDateStaticInterface(as_object& o)
{
// This should *only* be available when SWF version is > 6
- // Are you sure? the references say it's in from v5 -martin
+ // Are you sure? The online reference say it's in from v5 -martin
o.init_member("UTC", &date_utc);
}
@@ -402,7 +420,7 @@
if (utcsecs == -1) {
// mktime could not represent the time
log_error("Date() failed to initialise from arguments");
- date->value = 0;
+ date->value = 0; // or undefined?
} else {
date->value = (double)utcsecs * 1000.0 + millisecs;
}
@@ -619,17 +637,19 @@
// Convert Unix time structure and the remaining milliseconds to
// Flash datestamp.
-static void
-local_tm_msec_to_date(struct tm &tm, double &msec, date_as_object* &date)
+static double
+local_tm_msec_to_date(struct tm &tm, double &msec)
{
time_t t = _mktime(&tm);
// Reconstruct the time value and put the milliseconds back in.
- // If mktime fails to reconstruct the date, change nothing.
if (t == (time_t)(-1)) {
+ // If mktime fails to reconstruct the date, return bogus value;
+ // Not sure when/how this can happen. Values outside POSIX time?
log_error("Failed to set a date.\n");
+ return(NAN);
} else {
- date->value = t * 1000.0 + msec;
+ return(t * 1000.0 + msec);
}
}
@@ -650,27 +670,26 @@
#endif
}
-// TODO:
// Until we find the correct algorithm, we can use mktime which, by
// experiment, seems to flip timezone at midnight, not at 2 in the morning,
// so we use that to do year/month/day and put the unadjusted hours/mins/secs
// in by hand. It's probably not right but it'll do for the moment.
-static void
-utc_tm_msec_to_date(struct tm &tm, double &msec, date_as_object* &date)
+static double
+utc_tm_msec_to_date(struct tm &tm, double &msec)
{
#if USE_UTCCONV
- date->value = mkutctime(&tm, msec);
+ return (mkutctime(&tm, msec)); // The better algorithm :)
#else
time_t t = mktime(&tm);
if (t == (time_t)(-1)) {
- log_error("utc_tm_msec_to_date failed to convert back to Date");
+ log_error("utc_tm_msec_to_date failed to convert a date");
} else {
// Knock out the H:M:S part of t and replace with UTC time-of-day
t = t - (t % 86400) + tm.tm_sec + 60 * (tm.tm_min + 60 *
tm.tm_hour);
}
- date->value = t * 1000.0 + msec;
+ return (t * 1000.0 + msec);
#endif
}
@@ -681,9 +700,9 @@
tm_msec_to_date(struct tm &tm, double &msec, date_as_object* &date, bool utc)
{
if (utc)
- utc_tm_msec_to_date(tm, msec, date);
+ date->value = utc_tm_msec_to_date(tm, msec);
else
- local_tm_msec_to_date(tm, msec, date);
+ date->value = local_tm_msec_to_date(tm, msec);
}
static void
@@ -1087,13 +1106,114 @@
// Convert a UTC date/time specification to number of milliseconds since
// 1 Jan 1970 00:00 UTC.
//
-// year is a Gregorian year; unspecified arguments default to 0 except for
-// day-of-month, which defaults to 1.
+// unspecified optional arguments default to 0 except for day-of-month,
+// which defaults to 1.
+//
+// year is a Gregorian year; special values 0 to 99 mean 1900 to 1999 so it is
+// impossible to specify the year 55 AD using this interface.
+//
+// Any fractional part in the number of milliseconds is ignored (truncated)
+//
+// If 0 or 1 argument are passed, the result is the "undefined" value.
+//
+// This probably doesn't handle exceptional cases such as NaNs and infinities
+// the same as the commercial player. What that does is:
+// - if any argument is NaN, the result is NaN
+// - if one or more arguments are +Infinity, the result is +Infinity
+// - if one or more arguments are -Infinity, the result is -Infinity
+// - if both +Infinity and -Infinity are present in the args, result is NaN.
+
+static double rogue_date_args(const fn_call& fn); // Forward decl
static void date_utc(const fn_call& fn) {
- date_as_object* date = ensure_date_object(fn.this_ptr);
- UNUSED(date);
- log_msg("Date.UTC is unimplemented\n");
+ struct tm tm; // Date structure for values down to seconds
+ double millisecs; // and the miliseconds component.
+ double result; // Resulting Flash timestamp
+
+ if (fn.nargs < 2) {
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror("Date.UTC needs one argument");
+ )
+ fn.result->set_undefined();
+ return;
+ }
+
+ // Check for presence of NaNs and Infinities in the arguments
+ // and return the appropriate value if so.
+ if ( (result = rogue_date_args(fn)) != 0.0) {
+ fn.result->set_double(result);
+ return;
+ }
+
+ // Preset default values
+ // Year and month are always given explicitly
+ tm.tm_mday = 1;
+ tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+ tm.tm_isdst = 0; // Not used by our UTCTIME code.
+ millisecs = 0;
+ switch (fn.nargs) {
+ default: // More than 7
+ IF_VERBOSE_ASCODING_ERRORS(
+ log_aserror("Date.UTC was called with more than 7 arguments");
+ )
+ case 7:
+ // millisecs is double, but fractions of millisecs are ignored.
+ millisecs = (int) fn.arg(6).to_number();
+ case 6:
+ tm.tm_sec = (int) fn.arg(5).to_number();
+ case 5:
+ tm.tm_min = (int) fn.arg(4).to_number();
+ case 4:
+ tm.tm_hour = (int) fn.arg(3).to_number();
+ case 3:
+ tm.tm_mday = (int) fn.arg(2).to_number();
+ case 2: // these last two are always performed
+ tm.tm_mon = (int) fn.arg(1).to_number();
+ {
+ int y = (int) fn.arg(0).to_number();
+ if (y < 100 && y >= 0) y += 1900;
+ // y is now the Gregorian year number
+ tm.tm_year = y - 1900;
+ }
+ }
+
+ result = utc_tm_msec_to_date(tm, millisecs);
+ fn.result->set_double(result);
+}
+
+// Auxillary function checks for Infinities and NaN in a function's args and
+// returns 0.0 if there are none,
+static double
+rogue_date_args(const fn_call& fn) {
+ int plusinf_present = 0;
+ int minusinf_present = 0;
+ double infinity; // The kind of infinity we found
+
+ for (int i = 0; i < fn.nargs; i++) {
+ double arg = fn.arg(i).to_number();
+
+ if (isnan(arg)) return(NAN);
+
+ if (isinf(arg)) {
+ if (arg > 0) { // Plus infinity
+ plusinf_present = 1;
+ } else { // Minus infinity
+ minusinf_present = 1;
+ }
+ // Remember the kind of infinity we found
+ infinity = arg;
+ }
+ }
+ // If both kinds of infinity were present in the args,
+ // the result is NaN.
+ if (plusinf_present && minusinf_present) return(NAN);
+
+ // If only one kind of infinity was in the args, return that.
+ if (plusinf_present || minusinf_present) return(infinity);
+
+ // Otherwise indicate that the function arguments contained
+ // no rogue values
+ return(0.0);
}
/// \brief Date.valueOf() returns the number of milliseconds since midnight
- [Gnash-commit] gnash/server/asobj Date.cpp, Martin Guy, 2007/02/01
- [Gnash-commit] gnash/server/asobj Date.cpp, Martin Guy, 2007/02/02
- [Gnash-commit] gnash/server/asobj Date.cpp, Martin Guy, 2007/02/06
- [Gnash-commit] gnash/server/asobj Date.cpp, Martin Guy, 2007/02/07
- [Gnash-commit] gnash/server/asobj Date.cpp, Martin Guy, 2007/02/07
- [Gnash-commit] gnash/server/asobj Date.cpp, Martin Guy, 2007/02/11
- [Gnash-commit] gnash/server/asobj Date.cpp, Martin Guy, 2007/02/17
- [Gnash-commit] gnash/server/asobj Date.cpp,
Martin Guy <=
- [Gnash-commit] gnash/server/asobj Date.cpp, Markus Gothe, 2007/02/27
- [Gnash-commit] gnash/server/asobj Date.cpp, Martin Guy, 2007/02/28
- [Gnash-commit] gnash/server/asobj Date.cpp, Martin Guy, 2007/02/28