add blend mode tests
[swfdec.git] / swfdec / swfdec_as_date.c
blob2e896197521a107394cad0561a013824148f7d24
1 /* Swfdec
2 * Copyright (C) 2007-2008 Benjamin Otte <otte@gnome.org>
3 * 2007 Pekka Lampila <pekka.lampila@iki.fi>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301 USA
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
25 #include <stdlib.h>
26 #include <string.h>
27 #include <math.h>
29 #include "swfdec_as_date.h"
30 #include "swfdec_as_context.h"
31 #include "swfdec_as_frame_internal.h"
32 #include "swfdec_as_function.h"
33 #include "swfdec_as_object.h"
34 #include "swfdec_as_strings.h"
35 #include "swfdec_as_internal.h"
36 #include "swfdec_as_native_function.h"
37 #include "swfdec_system.h"
38 #include "swfdec_player_internal.h"
39 #include "swfdec_debug.h"
41 G_DEFINE_TYPE (SwfdecAsDate, swfdec_as_date, SWFDEC_TYPE_AS_RELAY)
44 * Class functions
47 static void
48 swfdec_as_date_class_init (SwfdecAsDateClass *klass)
52 static void
53 swfdec_as_date_init (SwfdecAsDate *date)
57 /*** Helper functions ***/
59 /* Kind of replacement for gmtime_r, timegm that works the way Flash works */
61 #define MILLISECONDS_PER_SECOND 1000
62 #define SECONDS_PER_MINUTE 60
63 #define MINUTES_PER_HOUR 60
64 #define HOURS_PER_DAY 24
65 #define MONTHS_PER_YEAR 12
67 #define MILLISECONDS_PER_MINUTE 60000
68 #define MILLISECONDS_PER_HOUR 3600000
69 #define MILLISECONDS_PER_DAY 86400000
71 static const int month_offsets[2][13] = {
72 // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec Total
73 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
74 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
77 typedef struct {
78 int milliseconds;
79 int seconds;
80 int minutes;
81 int hours;
82 int day_of_month;
83 int month;
84 int year;
86 int day_of_week;
87 } BrokenTime;
89 static int
90 swfdec_as_date_days_in_year (int year)
92 if (year % 4) {
93 return 365;
94 } else if (year % 100) {
95 return 366;
96 } else if (year % 400) {
97 return 365;
98 } else {
99 return 366;
103 #define IS_LEAP(year) (swfdec_as_date_days_in_year ((year)) == 366)
105 static double
106 swfdec_as_date_days_since_utc_for_year (double year)
108 return floor (
109 365 * (year - 1970) +
110 floor (((year - 1969) / 4.0f)) -
111 floor (((year - 1901) / 100.0f)) +
112 floor (((year - 1601) / 400.0f))
116 static double
117 swfdec_as_date_days_from_utc_to_year (double days)
119 double low, high, pivot;
121 low = floor ((days >= 0 ? days / 366.0 : days / 365.0)) + 1970;
122 high = ceil ((days >= 0 ? days / 365.0 : days / 366.0)) + 1970;
124 while (low < high) {
125 pivot = floor ((low + high) / 2.0);
127 if (swfdec_as_date_days_since_utc_for_year (pivot) <= days) {
128 if (swfdec_as_date_days_since_utc_for_year (pivot + 1) > days) {
129 high = low = pivot;
130 } else {
131 low = pivot + 1;
133 } else {
134 high = pivot - 1;
138 return low;
141 static void
142 swfdec_as_date_milliseconds_to_brokentime (double milliseconds,
143 BrokenTime *brokentime)
145 double remaining;
146 double year;
148 g_assert (brokentime != NULL);
150 /* special case: hours are calculated from different value */
151 if (isfinite (milliseconds)) {
152 remaining = floor (milliseconds + 0.5);
153 } else {
154 remaining = 0;
157 remaining = floor (remaining / MILLISECONDS_PER_HOUR);
158 brokentime->hours = fmod (remaining, HOURS_PER_DAY);
160 /* hours done, on with the rest */
161 if (isfinite (milliseconds)) {
162 remaining = milliseconds;
163 } else {
164 remaining = 0;
167 brokentime->milliseconds = fmod (remaining, MILLISECONDS_PER_SECOND);
168 remaining = floor (remaining / MILLISECONDS_PER_SECOND);
170 brokentime->seconds = fmod (remaining, SECONDS_PER_MINUTE);
171 remaining = floor (remaining / SECONDS_PER_MINUTE);
173 brokentime->minutes = fmod (remaining, MINUTES_PER_HOUR);
174 remaining = floor (remaining / MINUTES_PER_HOUR);
175 remaining = floor (remaining / HOURS_PER_DAY);
177 if (milliseconds < 0) {
178 if (brokentime->milliseconds < 0)
179 brokentime->milliseconds += MILLISECONDS_PER_SECOND;
180 if (brokentime->seconds < 0)
181 brokentime->seconds += SECONDS_PER_MINUTE;
182 if (brokentime->minutes < 0)
183 brokentime->minutes += MINUTES_PER_HOUR;
184 if (brokentime->hours < 0)
185 brokentime->hours += HOURS_PER_DAY;
188 // now remaining == days since 1970
190 if (isfinite (milliseconds)) {
191 brokentime->day_of_week = fmod ((remaining + 4), 7);
192 if (brokentime->day_of_week < 0)
193 brokentime->day_of_week += 7;
194 } else {
195 // special case
196 brokentime->day_of_week = 0;
199 year = swfdec_as_date_days_from_utc_to_year (remaining);
200 brokentime->year = year - 1900;
202 remaining -= swfdec_as_date_days_since_utc_for_year (year);
203 g_assert (remaining >= 0 && remaining <= 365);
205 brokentime->month = 0;
206 while (month_offsets[IS_LEAP (year)][brokentime->month + 1] <= remaining)
207 brokentime->month++;
209 brokentime->day_of_month =
210 remaining - month_offsets[IS_LEAP (year)][brokentime->month] + 1;
213 static double
214 swfdec_as_date_brokentime_to_milliseconds (const BrokenTime *brokentime)
216 double milliseconds;
217 int month, year;
219 year = 1900 + brokentime->year;
221 milliseconds = brokentime->milliseconds;
222 milliseconds += brokentime->seconds * MILLISECONDS_PER_SECOND;
223 milliseconds += brokentime->minutes * MILLISECONDS_PER_MINUTE;
224 milliseconds += brokentime->hours * MILLISECONDS_PER_HOUR;
225 milliseconds += (double)(brokentime->day_of_month - 1) * MILLISECONDS_PER_DAY;
227 milliseconds +=
228 swfdec_as_date_days_since_utc_for_year (year) * MILLISECONDS_PER_DAY;
230 for (month = brokentime->month; month < 0; month += MONTHS_PER_YEAR) {
231 milliseconds -=
232 (double)month_offsets[IS_LEAP (--year)][MONTHS_PER_YEAR] * MILLISECONDS_PER_DAY;
235 for (month = month; month >= MONTHS_PER_YEAR; month -= MONTHS_PER_YEAR) {
236 milliseconds +=
237 (double)month_offsets[IS_LEAP (year++)][MONTHS_PER_YEAR] * MILLISECONDS_PER_DAY;
240 milliseconds += (double)month_offsets[IS_LEAP (year)][month] * MILLISECONDS_PER_DAY;
242 return milliseconds;
245 /* Wrappers for swfdec_as_value_to_number because we need both double and int
246 * often, and need to generate the right valueOf etc. */
248 // returns TRUE if d is not Infinite or NAN
249 static gboolean
250 swfdec_as_date_value_to_number_and_integer_floor (SwfdecAsContext *context,
251 const SwfdecAsValue *value, double *d, int *num)
253 *d = swfdec_as_value_to_number (context, *value);
254 if (!isfinite (*d)) {
255 *num = 0;
256 return FALSE;
259 *num = floor (*d);
260 return TRUE;
263 // returns TRUE if d is not Infinite or NAN
264 static gboolean
265 swfdec_as_date_value_to_number_and_integer (SwfdecAsContext *context,
266 const SwfdecAsValue *value, double *d, int *num)
268 g_assert (d != NULL);
269 g_assert (num != NULL);
271 // undefined == NAN here, even in version < 7
272 if (SWFDEC_AS_VALUE_IS_UNDEFINED (*value)) {
273 *d = NAN;
274 } else {
275 *d = swfdec_as_value_to_number (context, *value);
277 if (!isfinite (*d)) {
278 *num = 0;
279 return FALSE;
282 if (*d < 0) {
283 *num = - (guint) fmod (-*d, 4294967296);
284 } else {
285 *num = (guint) fmod (*d, 4294967296);
287 return TRUE;
290 /* The functions to query/modify the current time */
292 // returns TRUE with Infinite and -Infinite, because those values should be
293 // handles like 0 that is returned by below functions
294 static gboolean
295 swfdec_as_date_is_valid (const SwfdecAsDate *date)
297 return !isnan (date->milliseconds);
300 static void
301 swfdec_as_date_set_invalid (SwfdecAsDate *date)
303 date->milliseconds = NAN;
306 static double
307 swfdec_as_date_get_milliseconds_utc (const SwfdecAsDate *date)
309 g_assert (swfdec_as_date_is_valid (date));
311 if (isfinite (date->milliseconds)) {
312 return date->milliseconds;
313 } else {
314 return 0;
318 static void
319 swfdec_as_date_set_milliseconds_utc (SwfdecAsDate *date, double milliseconds)
321 date->milliseconds = milliseconds;
324 /*static double
325 swfdec_as_date_get_milliseconds_local (const SwfdecAsDate *date)
327 g_assert (swfdec_as_date_is_valid (date));
329 if (isfinite (date->milliseconds)) {
330 return date->milliseconds + (double) date->utc_offset * 60 * 1000;
331 } else {
332 return 0;
336 static void
337 swfdec_as_date_set_milliseconds_local (SwfdecAsDate *date, double milliseconds)
339 date->milliseconds =
340 milliseconds - (double) date->utc_offset * 60 * 1000;
343 static void
344 swfdec_as_date_get_brokentime_utc (const SwfdecAsDate *date,
345 BrokenTime *brokentime)
347 g_assert (swfdec_as_date_is_valid (date));
349 swfdec_as_date_milliseconds_to_brokentime (date->milliseconds, brokentime);
352 static void
353 swfdec_as_date_set_brokentime_utc (SwfdecAsDate *date, BrokenTime *brokentime)
355 date->milliseconds = swfdec_as_date_brokentime_to_milliseconds (brokentime);
358 static void
359 swfdec_as_date_get_brokentime_local (const SwfdecAsDate *date,
360 BrokenTime *brokentime)
362 g_assert (swfdec_as_date_is_valid (date));
364 swfdec_as_date_milliseconds_to_brokentime (
365 date->milliseconds + date->utc_offset * 60 * 1000, brokentime);
368 static void
369 swfdec_as_date_set_brokentime_local (SwfdecAsDate *date, BrokenTime *brokentime)
371 date->milliseconds = swfdec_as_date_brokentime_to_milliseconds (brokentime) -
372 date->utc_offset * 60 * 1000;
375 /* set and get function helpers */
377 typedef enum {
378 FIELD_MILLISECONDS,
379 FIELD_SECONDS,
380 FIELD_MINUTES,
381 FIELD_HOURS,
382 FIELD_WEEK_DAYS,
383 FIELD_MONTH_DAYS,
384 FIELD_MONTHS,
385 FIELD_YEAR,
386 FIELD_FULL_YEAR
387 } field_t;
389 static int field_offsets[] = {
390 G_STRUCT_OFFSET (BrokenTime, milliseconds),
391 G_STRUCT_OFFSET (BrokenTime, seconds),
392 G_STRUCT_OFFSET (BrokenTime, minutes),
393 G_STRUCT_OFFSET (BrokenTime, hours),
394 G_STRUCT_OFFSET (BrokenTime, day_of_week),
395 G_STRUCT_OFFSET (BrokenTime, day_of_month),
396 G_STRUCT_OFFSET (BrokenTime, month),
397 G_STRUCT_OFFSET (BrokenTime, year),
398 G_STRUCT_OFFSET (BrokenTime, year)
401 static int
402 swfdec_as_date_get_brokentime_value (SwfdecAsDate *date, gboolean utc,
403 int field_offset)
405 BrokenTime brokentime;
407 if (utc) {
408 swfdec_as_date_get_brokentime_utc (date, &brokentime);
409 } else {
410 swfdec_as_date_get_brokentime_local (date, &brokentime);
413 return G_STRUCT_MEMBER (int, &brokentime, field_offset);
416 static void
417 swfdec_as_date_set_brokentime_value (SwfdecAsDate *date, gboolean utc,
418 int field_offset, SwfdecAsContext *cx, int number)
420 BrokenTime brokentime;
422 if (utc) {
423 swfdec_as_date_get_brokentime_utc (date, &brokentime);
424 } else {
425 swfdec_as_date_get_brokentime_local (date, &brokentime);
428 G_STRUCT_MEMBER (int, &brokentime, field_offset) = number;
430 if (utc) {
431 swfdec_as_date_set_brokentime_utc (date, &brokentime);
432 } else {
433 swfdec_as_date_set_brokentime_local (date, &brokentime);
437 static void
438 swfdec_as_date_set_field (SwfdecAsContext *cx, SwfdecAsObject *object,
439 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret, field_t field,
440 gboolean utc)
442 SwfdecAsDate *date;
444 SWFDEC_AS_CHECK (SWFDEC_TYPE_AS_DATE, &date, "");
446 if (!swfdec_as_date_is_valid (date))
447 swfdec_as_value_to_number (cx, argv[0]); // calls valueOf
449 if (swfdec_as_date_is_valid (date) && argc > 0)
451 gboolean set;
452 double milliseconds;
453 double d;
454 int number;
456 set = TRUE;
457 swfdec_as_date_value_to_number_and_integer (cx, &argv[0], &d, &number);
459 switch (field) {
460 case FIELD_MONTHS:
461 if (!isfinite (d)) {
462 if (!isnan (d)) {
463 swfdec_as_date_set_brokentime_value (date, utc,
464 field_offsets[FIELD_YEAR], cx, 0 - 1900);
466 swfdec_as_date_set_brokentime_value (date, utc, field_offsets[field],
467 cx, 0);
468 set = FALSE;
470 break;
471 case FIELD_YEAR:
472 // NOTE: Test against double, not the integer
473 if (d >= 0 && d < 100)
474 number += 1900;
475 // fall trough
476 case FIELD_FULL_YEAR:
477 number -= 1900;
478 if (!isfinite (d)) {
479 swfdec_as_date_set_brokentime_value (date, utc, field_offsets[field],
480 cx, 0 - 1900);
481 set = FALSE;
483 break;
484 case FIELD_MILLISECONDS:
485 case FIELD_SECONDS:
486 case FIELD_MINUTES:
487 case FIELD_HOURS:
488 case FIELD_WEEK_DAYS:
489 case FIELD_MONTH_DAYS:
490 if (!isfinite (d)) {
491 swfdec_as_date_set_invalid (date);
492 set = FALSE;
494 break;
495 default:
496 g_assert_not_reached ();
499 if (set) {
500 swfdec_as_date_set_brokentime_value (date, utc, field_offsets[field], cx,
501 number);
504 if (swfdec_as_date_is_valid (date)) {
505 milliseconds = swfdec_as_date_get_milliseconds_utc (date);
506 if (milliseconds < -8.64e15 || milliseconds > 8.64e15)
507 swfdec_as_date_set_invalid (date);
511 *ret = swfdec_as_value_from_number (cx, date->milliseconds);
514 static void
515 swfdec_as_date_get_field (SwfdecAsContext *cx, SwfdecAsObject *object,
516 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret, field_t field,
517 gboolean utc)
519 SwfdecAsDate *date;
520 int number;
522 SWFDEC_AS_CHECK (SWFDEC_TYPE_AS_DATE, &date, "");
524 if (!swfdec_as_date_is_valid (date)) {
525 *ret = swfdec_as_value_from_number (cx, NAN);
526 return;
529 number = swfdec_as_date_get_brokentime_value (date, utc,
530 field_offsets[field]);
532 if (field == FIELD_FULL_YEAR)
533 number += 1900;
535 *ret = swfdec_as_value_from_integer (cx, number);
538 /*** AS CODE ***/
540 SWFDEC_AS_NATIVE (103, 19, swfdec_as_date_toString)
541 void
542 swfdec_as_date_toString (SwfdecAsContext *cx, SwfdecAsObject *object,
543 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
545 static const char *weekday_names[] =
546 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
547 static const char *month_names[] =
548 { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
549 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
550 SwfdecAsDate *date;
551 BrokenTime brokentime;
552 char *result;
554 SWFDEC_AS_CHECK (SWFDEC_TYPE_AS_DATE, &date, "");
556 if (!swfdec_as_date_is_valid (date)) {
557 SWFDEC_AS_VALUE_SET_STRING (ret, SWFDEC_AS_STR_Invalid_Date);
558 return;
561 swfdec_as_date_get_brokentime_local (date, &brokentime);
563 result = g_strdup_printf ("%s %s %i %02i:%02i:%02i GMT%+03i%02i %i",
564 weekday_names[brokentime.day_of_week % 7],
565 month_names[brokentime.month % 12],
566 brokentime.day_of_month,
567 brokentime.hours, brokentime.minutes, brokentime.seconds,
568 date->utc_offset / 60, ABS (date->utc_offset % 60),
569 1900 + brokentime.year);
571 SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_context_give_string (cx, result));
574 SWFDEC_AS_NATIVE (103, 16, swfdec_as_date_getTime)
575 void
576 swfdec_as_date_getTime (SwfdecAsContext *cx, SwfdecAsObject *object,
577 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
579 SwfdecAsDate *date;
581 SWFDEC_AS_CHECK (SWFDEC_TYPE_AS_DATE, &date, "");
583 *ret = swfdec_as_value_from_number (cx, date->milliseconds);
586 SWFDEC_AS_NATIVE (103, 18, swfdec_as_date_getTimezoneOffset)
587 void
588 swfdec_as_date_getTimezoneOffset (SwfdecAsContext *cx, SwfdecAsObject *object,
589 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
591 SwfdecAsDate *date;
593 SWFDEC_AS_CHECK (SWFDEC_TYPE_AS_DATE, &date, "");
595 // reverse of utc_offset
596 *ret = swfdec_as_value_from_number (cx, -(date->utc_offset));
599 // get* functions
601 SWFDEC_AS_NATIVE (103, 8, swfdec_as_date_getMilliseconds)
602 void
603 swfdec_as_date_getMilliseconds (SwfdecAsContext *cx, SwfdecAsObject *object,
604 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
606 swfdec_as_date_get_field (cx, object, argc, argv, ret, FIELD_MILLISECONDS,
607 FALSE);
610 SWFDEC_AS_NATIVE (103, 128 + 8, swfdec_as_date_getUTCMilliseconds)
611 void
612 swfdec_as_date_getUTCMilliseconds (SwfdecAsContext *cx, SwfdecAsObject *object,
613 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
615 swfdec_as_date_get_field (cx, object, argc, argv, ret, FIELD_MILLISECONDS,
616 TRUE);
619 SWFDEC_AS_NATIVE (103, 7, swfdec_as_date_getSeconds)
620 void
621 swfdec_as_date_getSeconds (SwfdecAsContext *cx, SwfdecAsObject *object,
622 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
624 swfdec_as_date_get_field (cx, object, argc, argv, ret, FIELD_SECONDS, FALSE);
627 SWFDEC_AS_NATIVE (103, 128 + 7, swfdec_as_date_getUTCSeconds)
628 void
629 swfdec_as_date_getUTCSeconds (SwfdecAsContext *cx, SwfdecAsObject *object,
630 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
632 swfdec_as_date_get_field (cx, object, argc, argv, ret, FIELD_SECONDS, TRUE);
635 SWFDEC_AS_NATIVE (103, 6, swfdec_as_date_getMinutes)
636 void
637 swfdec_as_date_getMinutes (SwfdecAsContext *cx, SwfdecAsObject *object,
638 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
640 swfdec_as_date_get_field (cx, object, argc, argv, ret, FIELD_MINUTES, FALSE);
643 SWFDEC_AS_NATIVE (103, 128 + 6, swfdec_as_date_getUTCMinutes)
644 void
645 swfdec_as_date_getUTCMinutes (SwfdecAsContext *cx, SwfdecAsObject *object,
646 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
648 swfdec_as_date_get_field (cx, object, argc, argv, ret, FIELD_MINUTES, TRUE);
651 SWFDEC_AS_NATIVE (103, 5, swfdec_as_date_getHours)
652 void
653 swfdec_as_date_getHours (SwfdecAsContext *cx, SwfdecAsObject *object,
654 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
656 swfdec_as_date_get_field (cx, object, argc, argv, ret, FIELD_HOURS, FALSE);
659 SWFDEC_AS_NATIVE (103, 128 + 5, swfdec_as_date_getUTCHours)
660 void
661 swfdec_as_date_getUTCHours (SwfdecAsContext *cx, SwfdecAsObject *object,
662 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
664 swfdec_as_date_get_field (cx, object, argc, argv, ret, FIELD_HOURS, TRUE);
667 SWFDEC_AS_NATIVE (103, 4, swfdec_as_date_getDay)
668 void
669 swfdec_as_date_getDay (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc,
670 SwfdecAsValue *argv, SwfdecAsValue *ret)
672 swfdec_as_date_get_field (cx, object, argc, argv, ret, FIELD_WEEK_DAYS,
673 FALSE);
676 SWFDEC_AS_NATIVE (103, 128 + 4, swfdec_as_date_getUTCDay)
677 void
678 swfdec_as_date_getUTCDay (SwfdecAsContext *cx, SwfdecAsObject *object,
679 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
681 swfdec_as_date_get_field (cx, object, argc, argv, ret, FIELD_WEEK_DAYS,
682 TRUE);
685 SWFDEC_AS_NATIVE (103, 3, swfdec_as_date_getDate)
686 void
687 swfdec_as_date_getDate (SwfdecAsContext *cx, SwfdecAsObject *object,
688 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
690 swfdec_as_date_get_field (cx, object, argc, argv, ret, FIELD_MONTH_DAYS,
691 FALSE);
694 SWFDEC_AS_NATIVE (103, 128 + 3, swfdec_as_date_getUTCDate)
695 void
696 swfdec_as_date_getUTCDate (SwfdecAsContext *cx, SwfdecAsObject *object,
697 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
699 swfdec_as_date_get_field (cx, object, argc, argv, ret, FIELD_MONTH_DAYS,
700 TRUE);
703 SWFDEC_AS_NATIVE (103, 2, swfdec_as_date_getMonth)
704 void
705 swfdec_as_date_getMonth (SwfdecAsContext *cx, SwfdecAsObject *object,
706 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
708 swfdec_as_date_get_field (cx, object, argc, argv, ret, FIELD_MONTHS, FALSE);
711 SWFDEC_AS_NATIVE (103, 128 + 2, swfdec_as_date_getUTCMonth)
712 void
713 swfdec_as_date_getUTCMonth (SwfdecAsContext *cx, SwfdecAsObject *object,
714 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
716 swfdec_as_date_get_field (cx, object, argc, argv, ret, FIELD_MONTHS, TRUE);
719 SWFDEC_AS_NATIVE (103, 1, swfdec_as_date_getYear)
720 void
721 swfdec_as_date_getYear (SwfdecAsContext *cx, SwfdecAsObject *object,
722 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
724 swfdec_as_date_get_field (cx, object, argc, argv, ret, FIELD_YEAR, FALSE);
727 SWFDEC_AS_NATIVE (103, 128 + 1, swfdec_as_date_getUTCYear)
728 void
729 swfdec_as_date_getUTCYear (SwfdecAsContext *cx, SwfdecAsObject *object,
730 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
732 swfdec_as_date_get_field (cx, object, argc, argv, ret, FIELD_YEAR, TRUE);
735 SWFDEC_AS_NATIVE (103, 0, swfdec_as_date_getFullYear)
736 void
737 swfdec_as_date_getFullYear (SwfdecAsContext *cx, SwfdecAsObject *object,
738 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
740 swfdec_as_date_get_field (cx, object, argc, argv, ret, FIELD_FULL_YEAR,
741 FALSE);
744 SWFDEC_AS_NATIVE (103, 128 + 0, swfdec_as_date_getUTCFullYear)
745 void
746 swfdec_as_date_getUTCFullYear (SwfdecAsContext *cx, SwfdecAsObject *object,
747 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
749 swfdec_as_date_get_field (cx, object, argc, argv, ret, FIELD_FULL_YEAR,
750 TRUE);
753 // set* functions
755 SWFDEC_AS_NATIVE (103, 17, swfdec_as_date_setTime)
756 void
757 swfdec_as_date_setTime (SwfdecAsContext *cx, SwfdecAsObject *object,
758 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
760 SwfdecAsDate *date;
761 double d;
763 SWFDEC_AS_CHECK (SWFDEC_TYPE_AS_DATE, &date, "");
765 if (argc > 0 &&
766 (cx->version > 6 || !SWFDEC_AS_VALUE_IS_UNDEFINED (argv[0]))) {
767 d = swfdec_as_value_to_number (cx, argv[0]);
768 } else {
769 d = NAN;
771 if (isfinite (d)) {
772 swfdec_as_date_set_milliseconds_utc (date, trunc (d));
773 } else {
774 swfdec_as_date_set_milliseconds_utc (date, NAN);
777 *ret = swfdec_as_value_from_number (cx, date->milliseconds);
780 SWFDEC_AS_NATIVE (103, 15, swfdec_as_date_setMilliseconds)
781 void
782 swfdec_as_date_setMilliseconds (SwfdecAsContext *cx, SwfdecAsObject *object,
783 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
785 swfdec_as_date_set_field (cx, object, argc, argv, ret, FIELD_MILLISECONDS,
786 FALSE);
789 SWFDEC_AS_NATIVE (103, 128 + 15, swfdec_as_date_setUTCMilliseconds)
790 void
791 swfdec_as_date_setUTCMilliseconds (SwfdecAsContext *cx, SwfdecAsObject *object,
792 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
794 swfdec_as_date_set_field (cx, object, argc, argv, ret, FIELD_MILLISECONDS,
795 TRUE);
798 SWFDEC_AS_NATIVE (103, 14, swfdec_as_date_setSeconds)
799 void
800 swfdec_as_date_setSeconds (SwfdecAsContext *cx, SwfdecAsObject *object,
801 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
803 swfdec_as_date_set_field (cx, object, argc, argv, ret, FIELD_SECONDS, FALSE);
805 if (argc > 1)
806 swfdec_as_date_setMilliseconds (cx, object, argc - 1, argv + 1, ret);
809 SWFDEC_AS_NATIVE (103, 128 + 14, swfdec_as_date_setUTCSeconds)
810 void
811 swfdec_as_date_setUTCSeconds (SwfdecAsContext *cx, SwfdecAsObject *object,
812 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
814 swfdec_as_date_set_field (cx, object, argc, argv, ret, FIELD_SECONDS, TRUE);
816 if (argc > 1)
817 swfdec_as_date_setUTCMilliseconds (cx, object, argc - 1, argv + 1, ret);
820 SWFDEC_AS_NATIVE (103, 13, swfdec_as_date_setMinutes)
821 void
822 swfdec_as_date_setMinutes (SwfdecAsContext *cx, SwfdecAsObject *object,
823 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
825 swfdec_as_date_set_field (cx, object, argc, argv, ret, FIELD_MINUTES, FALSE);
827 if (argc > 1)
828 swfdec_as_date_setSeconds (cx, object, argc - 1, argv + 1, ret);
831 SWFDEC_AS_NATIVE (103, 128 + 13, swfdec_as_date_setUTCMinutes)
832 void
833 swfdec_as_date_setUTCMinutes (SwfdecAsContext *cx, SwfdecAsObject *object,
834 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
836 swfdec_as_date_set_field (cx, object, argc, argv, ret, FIELD_MINUTES, TRUE);
838 if (argc > 1)
839 swfdec_as_date_setUTCSeconds (cx, object, argc - 1, argv + 1, ret);
842 SWFDEC_AS_NATIVE (103, 12, swfdec_as_date_setHours)
843 void
844 swfdec_as_date_setHours (SwfdecAsContext *cx, SwfdecAsObject *object,
845 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
847 swfdec_as_date_set_field (cx, object, argc, argv, ret, FIELD_HOURS, FALSE);
849 if (argc > 1)
850 swfdec_as_date_setMinutes (cx, object, argc - 1, argv + 1, ret);
853 SWFDEC_AS_NATIVE (103, 128 + 12, swfdec_as_date_setUTCHours)
854 void
855 swfdec_as_date_setUTCHours (SwfdecAsContext *cx, SwfdecAsObject *object,
856 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
858 swfdec_as_date_set_field (cx, object, argc, argv, ret, FIELD_HOURS, TRUE);
860 if (argc > 1)
861 swfdec_as_date_setUTCMinutes (cx, object, argc - 1, argv + 1, ret);
864 SWFDEC_AS_NATIVE (103, 11, swfdec_as_date_setDate)
865 void
866 swfdec_as_date_setDate (SwfdecAsContext *cx, SwfdecAsObject *object,
867 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
869 swfdec_as_date_set_field (cx, object, argc, argv, ret, FIELD_MONTH_DAYS,
870 FALSE);
873 SWFDEC_AS_NATIVE (103, 128 + 11, swfdec_as_date_setUTCDate)
874 void
875 swfdec_as_date_setUTCDate (SwfdecAsContext *cx, SwfdecAsObject *object,
876 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
878 swfdec_as_date_set_field (cx, object, argc, argv, ret, FIELD_MONTH_DAYS,
879 TRUE);
882 SWFDEC_AS_NATIVE (103, 10, swfdec_as_date_setMonth)
883 void
884 swfdec_as_date_setMonth (SwfdecAsContext *cx, SwfdecAsObject *object,
885 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
887 swfdec_as_date_set_field (cx, object, argc, argv, ret, FIELD_MONTHS, FALSE);
889 if (argc > 1)
890 swfdec_as_date_setDate (cx, object, argc - 1, argv + 1, ret);
893 SWFDEC_AS_NATIVE (103, 128 + 10, swfdec_as_date_setUTCMonth)
894 void
895 swfdec_as_date_setUTCMonth (SwfdecAsContext *cx, SwfdecAsObject *object,
896 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
898 swfdec_as_date_set_field (cx, object, argc, argv, ret, FIELD_MONTHS, TRUE);
900 if (argc > 1)
901 swfdec_as_date_setUTCDate (cx, object, argc - 1, argv + 1, ret);
904 SWFDEC_AS_NATIVE (103, 20, swfdec_as_date_setYear)
905 void
906 swfdec_as_date_setYear (SwfdecAsContext *cx, SwfdecAsObject *object,
907 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
909 swfdec_as_date_set_field (cx, object, argc, argv, ret, FIELD_YEAR, FALSE);
911 if (argc > 1)
912 swfdec_as_date_setMonth (cx, object, argc - 1, argv + 1, ret);
915 SWFDEC_AS_NATIVE (103, 9, swfdec_as_date_setFullYear)
916 void
917 swfdec_as_date_setFullYear (SwfdecAsContext *cx, SwfdecAsObject *object,
918 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
920 swfdec_as_date_set_field (cx, object, argc, argv, ret, FIELD_FULL_YEAR,
921 FALSE);
923 if (argc > 1)
924 swfdec_as_date_setMonth (cx, object, argc - 1, argv + 1, ret);
927 SWFDEC_AS_NATIVE (103, 128 + 9, swfdec_as_date_setUTCFullYear)
928 void
929 swfdec_as_date_setUTCFullYear (SwfdecAsContext *cx, SwfdecAsObject *object,
930 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
932 swfdec_as_date_set_field (cx, object, argc, argv, ret, FIELD_FULL_YEAR,
933 TRUE);
935 if (argc > 1)
936 swfdec_as_date_setUTCMonth (cx, object, argc - 1, argv + 1, ret);
939 // Static methods
941 SWFDEC_AS_NATIVE (103, 257, swfdec_as_date_UTC)
942 void
943 swfdec_as_date_UTC (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc,
944 SwfdecAsValue *argv, SwfdecAsValue *ret)
946 guint i;
947 int year, num;
948 double d;
949 BrokenTime brokentime;
951 // special case: ignore undefined and everything after it
952 for (i = 0; i < argc; i++) {
953 if (SWFDEC_AS_VALUE_IS_UNDEFINED (argv[i])) {
954 argc = i;
955 break;
959 memset (&brokentime, 0, sizeof (brokentime));
961 if (argc > 0) {
962 if (swfdec_as_date_value_to_number_and_integer_floor (cx, &argv[0], &d,
963 &num)) {
964 year = num;
965 } else {
966 // special case: if year is not finite set it to -1900
967 year = -1900;
969 } else {
970 return;
973 // if we don't got atleast two values, return undefined
974 // do it only here, so valueOf first arg is called
975 if (argc < 2)
976 return;
978 if (swfdec_as_date_value_to_number_and_integer (cx, &argv[1], &d,
979 &num)) {
980 brokentime.month = num;
981 } else {
982 // special case: if month is not finite set year to -1900
983 year = -1900;
984 brokentime.month = 0;
987 if (argc > 2) {
988 if (swfdec_as_date_value_to_number_and_integer (cx, &argv[2], &d,
989 &num)) {
990 brokentime.day_of_month = num;
991 } else {
992 *ret = swfdec_as_value_from_number (cx, d);
993 return;
995 } else {
996 brokentime.day_of_month = 1;
999 if (argc > 3) {
1000 if (swfdec_as_date_value_to_number_and_integer (cx, &argv[3], &d,
1001 &num)) {
1002 brokentime.hours = num;
1003 } else {
1004 *ret = swfdec_as_value_from_number (cx, d);
1005 return;
1009 if (argc > 4) {
1010 if (swfdec_as_date_value_to_number_and_integer (cx, &argv[4], &d,
1011 &num)) {
1012 brokentime.minutes = num;
1013 } else {
1014 *ret = swfdec_as_value_from_number (cx, d);
1015 return;
1019 if (argc > 5) {
1020 if (swfdec_as_date_value_to_number_and_integer (cx, &argv[5], &d,
1021 &num)) {
1022 brokentime.seconds = num;
1023 } else {
1024 *ret = swfdec_as_value_from_number (cx, d);
1025 return;
1029 if (year >= 100) {
1030 brokentime.year = year - 1900;
1031 } else {
1032 brokentime.year = year;
1035 if (argc > 6) {
1036 if (swfdec_as_date_value_to_number_and_integer (cx, &argv[6], &d,
1037 &num)) {
1038 brokentime.milliseconds = num;
1039 } else {
1040 *ret = swfdec_as_value_from_number (cx, d);
1041 return;
1045 *ret = swfdec_as_value_from_number (cx,
1046 swfdec_as_date_brokentime_to_milliseconds (&brokentime));
1049 // Constructor
1051 SWFDEC_AS_NATIVE (103, 256, swfdec_as_date_construct)
1052 void
1053 swfdec_as_date_construct (SwfdecAsContext *cx, SwfdecAsObject *object,
1054 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
1056 guint i;
1057 SwfdecAsDate *date;
1059 if (!swfdec_as_context_is_constructing (cx)) {
1060 object = swfdec_as_object_new_empty (cx);
1061 swfdec_as_object_set_constructor_by_name (object, SWFDEC_AS_STR_Date, NULL);
1064 date = g_object_new (SWFDEC_TYPE_AS_DATE, "context", cx, NULL);
1065 swfdec_as_object_set_relay (object, SWFDEC_AS_RELAY (date));
1067 /* FIXME: find a general solution here */
1068 if (SWFDEC_IS_PLAYER (swfdec_gc_object_get_context (date))) {
1069 date->utc_offset =
1070 SWFDEC_PLAYER (swfdec_gc_object_get_context (date))->priv->system->utc_offset;
1073 // don't accept arguments when not constructing
1074 if (!cx->frame->construct)
1075 argc = 0;
1077 // special case: ignore undefined and everything after it
1078 for (i = 0; i < argc; i++) {
1079 if (SWFDEC_AS_VALUE_IS_UNDEFINED (argv[i])) {
1080 argc = i;
1081 break;
1085 if (argc == 0) // current time, local
1087 GTimeVal tv;
1089 swfdec_as_context_get_time (cx, &tv);
1090 /* Use millisecond granularity here. Otherwise the value returned by
1091 * getTime() or toString() has a decimal point which breaks Flash files.
1093 swfdec_as_date_set_milliseconds_utc (date,
1094 tv.tv_sec * 1000.0 + tv.tv_usec / 1000);
1096 else if (argc == 1) // milliseconds from epoch, local
1098 // need to save directly to keep fractions of a milliseconds
1099 date->milliseconds = swfdec_as_value_to_number (cx, argv[0]);
1101 else // year, month etc. local
1103 int year, num;
1104 double d;
1105 BrokenTime brokentime;
1107 date->milliseconds = 0;
1109 memset (&brokentime, 0, sizeof (brokentime));
1111 i = 0;
1113 if (argc > i) {
1114 if (swfdec_as_date_value_to_number_and_integer_floor (cx, &argv[i++], &d,
1115 &num)) {
1116 year = num;
1117 } else {
1118 // special case: if year is not finite set it to -1900
1119 year = -1900;
1121 } else {
1122 year = -1900;
1125 if (argc > i) {
1126 if (swfdec_as_date_value_to_number_and_integer (cx, &argv[i++], &d,
1127 &num)) {
1128 brokentime.month = num;
1129 } else {
1130 // special case: if month is not finite set year to -1900
1131 year = -1900;
1132 brokentime.month = 0;
1136 if (argc > i) {
1137 if (swfdec_as_date_value_to_number_and_integer (cx, &argv[i++], &d,
1138 &num)) {
1139 brokentime.day_of_month = num;
1140 } else {
1141 date->milliseconds += d;
1143 } else {
1144 brokentime.day_of_month = 1;
1147 if (argc > i) {
1148 if (swfdec_as_date_value_to_number_and_integer (cx, &argv[i++], &d,
1149 &num)) {
1150 brokentime.hours = num;
1151 } else {
1152 date->milliseconds += d;
1156 if (argc > i) {
1157 if (swfdec_as_date_value_to_number_and_integer (cx, &argv[i++], &d,
1158 &num)) {
1159 brokentime.minutes = num;
1160 } else {
1161 date->milliseconds += d;
1165 if (argc > i) {
1166 if (swfdec_as_date_value_to_number_and_integer (cx, &argv[i++], &d,
1167 &num)) {
1168 brokentime.seconds = num;
1169 } else {
1170 date->milliseconds += d;
1174 if (year >= 100) {
1175 brokentime.year = year - 1900;
1176 } else {
1177 brokentime.year = year;
1180 if (argc > i) {
1181 if (swfdec_as_date_value_to_number_and_integer (cx, &argv[i++], &d,
1182 &num)) {
1183 brokentime.milliseconds += num;
1184 } else {
1185 date->milliseconds += d;
1189 if (date->milliseconds == 0) {
1190 swfdec_as_date_set_milliseconds_local (date,
1191 swfdec_as_date_brokentime_to_milliseconds (&brokentime));
1195 SWFDEC_AS_VALUE_SET_OBJECT (ret, object);