xref: /reactos/dll/win32/jscript/date.c (revision 3e2d6582)
1 /*
2  * Copyright 2008 Jacek Caban for CodeWeavers
3  * Copyright 2009 Piotr Caban
4  *
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.
14  *
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 St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19 
20 #ifdef __REACTOS__
21 #include <wine/config.h>
22 #include <wine/port.h>
23 #endif
24 
25 #include <limits.h>
26 #include <math.h>
27 #include <assert.h>
28 
29 #include "jscript.h"
30 
31 #include "wine/debug.h"
32 
33 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
34 
35 /* 1601 to 1970 is 369 years plus 89 leap days */
36 #define TIME_EPOCH  ((ULONGLONG)(369 * 365 + 89) * 86400 * 1000)
37 
38 typedef struct {
39     jsdisp_t dispex;
40 
41     /* ECMA-262 3rd Edition    15.9.1.1 */
42     DOUBLE time;
43 
44     LONG bias;
45     SYSTEMTIME standardDate;
46     LONG standardBias;
47     SYSTEMTIME daylightDate;
48     LONG daylightBias;
49 } DateInstance;
50 
51 static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
52 static const WCHAR toLocaleStringW[] = {'t','o','L','o','c','a','l','e','S','t','r','i','n','g',0};
53 static const WCHAR valueOfW[] = {'v','a','l','u','e','O','f',0};
54 static const WCHAR toISOStringW[] = {'t','o','I','S','O','S','t','r','i','n','g',0};
55 static const WCHAR toUTCStringW[] = {'t','o','U','T','C','S','t','r','i','n','g',0};
56 static const WCHAR toGMTStringW[] = {'t','o','G','M','T','S','t','r','i','n','g',0};
57 static const WCHAR toDateStringW[] = {'t','o','D','a','t','e','S','t','r','i','n','g',0};
58 static const WCHAR toTimeStringW[] = {'t','o','T','i','m','e','S','t','r','i','n','g',0};
59 static const WCHAR toLocaleDateStringW[] = {'t','o','L','o','c','a','l','e','D','a','t','e','S','t','r','i','n','g',0};
60 static const WCHAR toLocaleTimeStringW[] = {'t','o','L','o','c','a','l','e','T','i','m','e','S','t','r','i','n','g',0};
61 static const WCHAR getTimeW[] = {'g','e','t','T','i','m','e',0};
62 static const WCHAR getFullYearW[] = {'g','e','t','F','u','l','l','Y','e','a','r',0};
63 static const WCHAR getUTCFullYearW[] = {'g','e','t','U','T','C','F','u','l','l','Y','e','a','r',0};
64 static const WCHAR getMonthW[] = {'g','e','t','M','o','n','t','h',0};
65 static const WCHAR getUTCMonthW[] = {'g','e','t','U','T','C','M','o','n','t','h',0};
66 static const WCHAR getDateW[] = {'g','e','t','D','a','t','e',0};
67 static const WCHAR getUTCDateW[] = {'g','e','t','U','T','C','D','a','t','e',0};
68 static const WCHAR getDayW[] = {'g','e','t','D','a','y',0};
69 static const WCHAR getUTCDayW[] = {'g','e','t','U','T','C','D','a','y',0};
70 static const WCHAR getHoursW[] = {'g','e','t','H','o','u','r','s',0};
71 static const WCHAR getUTCHoursW[] = {'g','e','t','U','T','C','H','o','u','r','s',0};
72 static const WCHAR getMinutesW[] = {'g','e','t','M','i','n','u','t','e','s',0};
73 static const WCHAR getUTCMinutesW[] = {'g','e','t','U','T','C','M','i','n','u','t','e','s',0};
74 static const WCHAR getSecondsW[] = {'g','e','t','S','e','c','o','n','d','s',0};
75 static const WCHAR getUTCSecondsW[] = {'g','e','t','U','T','C','S','e','c','o','n','d','s',0};
76 static const WCHAR getMillisecondsW[] = {'g','e','t','M','i','l','l','i','s','e','c','o','n','d','s',0};
77 static const WCHAR getUTCMillisecondsW[] = {'g','e','t','U','T','C','M','i','l','l','i','s','e','c','o','n','d','s',0};
78 static const WCHAR getTimezoneOffsetW[] = {'g','e','t','T','i','m','e','z','o','n','e','O','f','f','s','e','t',0};
79 static const WCHAR setTimeW[] = {'s','e','t','T','i','m','e',0};
80 static const WCHAR setMillisecondsW[] = {'s','e','t','M','i','l','l','i','s','e','c','o','n','d','s',0};
81 static const WCHAR setUTCMillisecondsW[] = {'s','e','t','U','T','C','M','i','l','l','i','s','e','c','o','n','d','s',0};
82 static const WCHAR setSecondsW[] = {'s','e','t','S','e','c','o','n','d','s',0};
83 static const WCHAR setUTCSecondsW[] = {'s','e','t','U','T','C','S','e','c','o','n','d','s',0};
84 static const WCHAR setMinutesW[] = {'s','e','t','M','i','n','u','t','e','s',0};
85 static const WCHAR setUTCMinutesW[] = {'s','e','t','U','T','C','M','i','n','u','t','e','s',0};
86 static const WCHAR setHoursW[] = {'s','e','t','H','o','u','r','s',0};
87 static const WCHAR setUTCHoursW[] = {'s','e','t','U','T','C','H','o','u','r','s',0};
88 static const WCHAR setDateW[] = {'s','e','t','D','a','t','e',0};
89 static const WCHAR setUTCDateW[] = {'s','e','t','U','T','C','D','a','t','e',0};
90 static const WCHAR setMonthW[] = {'s','e','t','M','o','n','t','h',0};
91 static const WCHAR setUTCMonthW[] = {'s','e','t','U','T','C','M','o','n','t','h',0};
92 static const WCHAR setFullYearW[] = {'s','e','t','F','u','l','l','Y','e','a','r',0};
93 static const WCHAR setUTCFullYearW[] = {'s','e','t','U','T','C','F','u','l','l','Y','e','a','r',0};
94 static const WCHAR getYearW[] = {'g','e','t','Y','e','a','r',0};
95 static const WCHAR setYearW[] = {'s','e','t','Y','e','a','r',0};
96 
97 static const WCHAR UTCW[] = {'U','T','C',0};
98 static const WCHAR nowW[] = {'n','o','w',0};
99 static const WCHAR parseW[] = {'p','a','r','s','e',0};
100 
date_from_jsdisp(jsdisp_t * jsdisp)101 static inline DateInstance *date_from_jsdisp(jsdisp_t *jsdisp)
102 {
103     return CONTAINING_RECORD(jsdisp, DateInstance, dispex);
104 }
105 
date_this(vdisp_t * jsthis)106 static inline DateInstance *date_this(vdisp_t *jsthis)
107 {
108     return is_vclass(jsthis, JSCLASS_DATE) ? date_from_jsdisp(jsthis->u.jsdisp) : NULL;
109 }
110 
111 /*ECMA-262 3rd Edition    15.9.1.2 */
112 #define MS_PER_DAY 86400000
113 #define MS_PER_HOUR 3600000
114 #define MS_PER_MINUTE 60000
115 
116 /* ECMA-262 3rd Edition    15.9.1.2 */
day(DOUBLE time)117 static inline DOUBLE day(DOUBLE time)
118 {
119     return floor(time / MS_PER_DAY);
120 }
121 
122 /* ECMA-262 3rd Edition    15.9.1.2 */
time_within_day(DOUBLE time)123 static inline DOUBLE time_within_day(DOUBLE time)
124 {
125     DOUBLE ret;
126 
127     ret = fmod(time, MS_PER_DAY);
128     if(ret < 0)
129         ret += MS_PER_DAY;
130 
131     return ret;
132 }
133 
134 /* ECMA-262 3rd Edition    15.9.1.3 */
days_in_year(DOUBLE year)135 static inline DOUBLE days_in_year(DOUBLE year)
136 {
137     int y;
138 
139     if(year != (int)year)
140         return NAN;
141 
142     y = year;
143     if(y%4 != 0) return 365;
144     if(y%100 != 0) return 366;
145     if(y%400 != 0) return 365;
146     return 366;
147 }
148 
149 /* ECMA-262 3rd Edition    15.9.1.3 */
day_from_year(DOUBLE year)150 static inline DOUBLE day_from_year(DOUBLE year)
151 {
152     if(year != (int)year)
153         return NAN;
154 
155     return floor(365.0*(year-1970) + floor((year-1969)/4)
156         - floor((year-1901)/100) + floor((year-1601)/400));
157 }
158 
day_from_month(int month,int in_leap_year)159 static inline int day_from_month(int month, int in_leap_year)
160 {
161     switch(month)
162     {
163         case 0:
164             return 0;
165         case 1:
166             return 31;
167         case 2:
168             return 59+in_leap_year;
169         case 3:
170             return 90+in_leap_year;
171         case 4:
172             return 120+in_leap_year;
173         case 5:
174             return 151+in_leap_year;
175         case 6:
176             return 181+in_leap_year;
177         case 7:
178             return 212+in_leap_year;
179         case 8:
180             return 243+in_leap_year;
181         case 9:
182             return 273+in_leap_year;
183         case 10:
184             return 304+in_leap_year;
185         default:
186             return 334+in_leap_year;
187     }
188 }
189 
190 /* ECMA-262 3rd Edition    15.9.1.3 */
time_from_year(DOUBLE year)191 static inline DOUBLE time_from_year(DOUBLE year)
192 {
193     return MS_PER_DAY*day_from_year(year);
194 }
195 
196 /* ECMA-262 3rd Edition    15.9.1.3 */
year_from_time(DOUBLE time)197 static inline DOUBLE year_from_time(DOUBLE time)
198 {
199     int y;
200 
201     if(isnan(time))
202         return NAN;
203 
204     y = 1970 + time/365.25/MS_PER_DAY;
205 
206     if(time_from_year(y) > time)
207         while(time_from_year(y) > time) y--;
208     else
209         while(time_from_year(y+1)<=time) y++;
210 
211     return y;
212 }
213 
214 /* ECMA-262 3rd Edition    15.9.1.3 */
in_leap_year(DOUBLE time)215 static inline int in_leap_year(DOUBLE time)
216 {
217     if(days_in_year(year_from_time(time))==366)
218         return 1;
219     return 0;
220 }
221 
222 /* ECMA-262 3rd Edition    15.9.1.4 */
day_within_year(DOUBLE time)223 static inline int day_within_year(DOUBLE time)
224 {
225     return day(time) - day_from_year(year_from_time(time));
226 }
227 
228 /* ECMA-262 3rd Edition    15.9.1.4 */
month_from_time(DOUBLE time)229 static inline DOUBLE month_from_time(DOUBLE time)
230 {
231     int ily = in_leap_year(time);
232     int dwy = day_within_year(time);
233 
234     if(isnan(time))
235         return NAN;
236 
237     if(0<=dwy && dwy<31) return 0;
238     if(dwy < 59+ily) return 1;
239     if(dwy < 90+ily) return 2;
240     if(dwy < 120+ily) return 3;
241     if(dwy < 151+ily) return 4;
242     if(dwy < 181+ily) return 5;
243     if(dwy < 212+ily) return 6;
244     if(dwy < 243+ily) return 7;
245     if(dwy < 273+ily) return 8;
246     if(dwy < 304+ily) return  9;
247     if(dwy < 334+ily) return  10;
248     return  11;
249 }
250 
251 /* ECMA-262 3rd Edition    15.9.1.5 */
date_from_time(DOUBLE time)252 static inline DOUBLE date_from_time(DOUBLE time)
253 {
254     int dwy = day_within_year(time);
255     int ily = in_leap_year(time);
256     int mft = month_from_time(time);
257 
258     if(isnan(time))
259         return NAN;
260 
261     if(mft==0) return dwy+1;
262     if(mft==1) return dwy-30;
263     if(mft==2) return dwy-58-ily;
264     if(mft==3) return dwy-89-ily;
265     if(mft==4) return dwy-119-ily;
266     if(mft==5) return dwy-150-ily;
267     if(mft==6) return dwy-180-ily;
268     if(mft==7) return dwy-211-ily;
269     if(mft==8) return dwy-242-ily;
270     if(mft==9) return dwy-272-ily;
271     if(mft==10) return dwy-303-ily;
272     return dwy-333-ily;
273 }
274 
275 /* ECMA-262 3rd Edition    15.9.1.6 */
week_day(DOUBLE time)276 static inline DOUBLE week_day(DOUBLE time)
277 {
278     DOUBLE ret;
279 
280     if(isnan(time))
281         return NAN;
282 
283     ret = fmod(day(time)+4, 7);
284     if(ret<0) ret += 7;
285 
286     return ret;
287 }
288 
convert_time(int year,SYSTEMTIME st)289 static inline DOUBLE convert_time(int year, SYSTEMTIME st)
290 {
291     DOUBLE time;
292     int set_week_day;
293 
294     if(st.wMonth == 0)
295         return NAN;
296 
297     if(st.wYear != 0)
298         year = st.wYear;
299 
300     time = time_from_year(year);
301     time += (DOUBLE)day_from_month(st.wMonth-1, in_leap_year(time)) * MS_PER_DAY;
302 
303     if(st.wYear == 0) {
304         set_week_day = st.wDayOfWeek-week_day(time);
305         if(set_week_day < 0)
306             set_week_day += 7;
307         time += set_week_day * MS_PER_DAY;
308 
309         time += (DOUBLE)(st.wDay-1) * 7 * MS_PER_DAY;
310         if(month_from_time(time) != st.wMonth-1)
311             time -= 7 * MS_PER_DAY;
312     }
313     else
314         time += st.wDay * MS_PER_DAY;
315 
316     time += st.wHour * MS_PER_HOUR;
317     time += st.wMinute * MS_PER_MINUTE;
318 
319     return time;
320 }
321 
322 /* ECMA-262 3rd Edition    15.9.1.9 */
daylight_saving_ta(DOUBLE time,DateInstance * date)323 static inline DOUBLE daylight_saving_ta(DOUBLE time, DateInstance *date)
324 {
325     int year = year_from_time(time);
326     DOUBLE standardTime, daylightTime;
327 
328     if(isnan(time))
329         return 0;
330 
331     standardTime = convert_time(year, date->standardDate);
332     daylightTime = convert_time(year, date->daylightDate);
333 
334     if(isnan(standardTime) || isnan(daylightTime))
335         return 0;
336     else if(standardTime > daylightTime) {
337         if(daylightTime <= time && time < standardTime)
338             return date->daylightBias;
339 
340         return date->standardBias;
341     }
342     else {
343         if(standardTime <= time && time < daylightTime)
344             return date->standardBias;
345 
346         return date->daylightBias;
347     }
348 }
349 
350 /* ECMA-262 3rd Edition    15.9.1.9 */
local_time(DOUBLE time,DateInstance * date)351 static inline DOUBLE local_time(DOUBLE time, DateInstance *date)
352 {
353     return time - (daylight_saving_ta(time, date)+date->bias)*MS_PER_MINUTE;
354 }
355 
356 /* ECMA-262 3rd Edition    15.9.1.9 */
utc(DOUBLE time,DateInstance * date)357 static inline DOUBLE utc(DOUBLE time, DateInstance *date)
358 {
359     time += date->bias * MS_PER_MINUTE;
360     return time + daylight_saving_ta(time, date)*MS_PER_MINUTE;
361 }
362 
363 /* ECMA-262 3rd Edition    15.9.1.10 */
hour_from_time(DOUBLE time)364 static inline DOUBLE hour_from_time(DOUBLE time)
365 {
366     DOUBLE ret;
367 
368     if(isnan(time))
369         return NAN;
370 
371     ret = fmod(floor(time/MS_PER_HOUR), 24);
372     if(ret<0) ret += 24;
373 
374     return ret;
375 }
376 
377 /* ECMA-262 3rd Edition    15.9.1.10 */
min_from_time(DOUBLE time)378 static inline DOUBLE min_from_time(DOUBLE time)
379 {
380     DOUBLE ret;
381 
382     if(isnan(time))
383         return NAN;
384 
385     ret = fmod(floor(time/MS_PER_MINUTE), 60);
386     if(ret<0) ret += 60;
387 
388     return ret;
389 }
390 
391 /* ECMA-262 3rd Edition    15.9.1.10 */
sec_from_time(DOUBLE time)392 static inline DOUBLE sec_from_time(DOUBLE time)
393 {
394     DOUBLE ret;
395 
396     if(isnan(time))
397         return NAN;
398 
399     ret = fmod(floor(time/1000), 60);
400     if(ret<0) ret += 60;
401 
402     return ret;
403 }
404 
405 /* ECMA-262 3rd Edition    15.9.1.10 */
ms_from_time(DOUBLE time)406 static inline DOUBLE ms_from_time(DOUBLE time)
407 {
408     DOUBLE ret;
409 
410     if(isnan(time))
411         return NAN;
412 
413     ret = fmod(time, 1000);
414     if(ret<0) ret += 1000;
415 
416     return ret;
417 }
418 
419 /* ECMA-262 3rd Edition    15.9.1.11 */
make_time(DOUBLE hour,DOUBLE min,DOUBLE sec,DOUBLE ms)420 static inline DOUBLE make_time(DOUBLE hour, DOUBLE min, DOUBLE sec, DOUBLE ms)
421 {
422     return hour*MS_PER_HOUR + min*MS_PER_MINUTE + sec*1000 + ms;
423 }
424 
425 /* ECMA-262 3rd Edition    15.9.1.12 */
make_day(DOUBLE year,DOUBLE month,DOUBLE day)426 static inline DOUBLE make_day(DOUBLE year, DOUBLE month, DOUBLE day)
427 {
428     DOUBLE time;
429 
430     year += floor(month/12);
431 
432     month = fmod(month, 12);
433     if(month<0) month += 12;
434 
435     time = time_from_year(year);
436 
437     day += floor(time / MS_PER_DAY);
438     day += day_from_month(month, in_leap_year(time));
439 
440     return day-1;
441 }
442 
443 /* ECMA-262 3rd Edition    15.9.1.13 */
make_date(DOUBLE day,DOUBLE time)444 static inline DOUBLE make_date(DOUBLE day, DOUBLE time)
445 {
446     return day*MS_PER_DAY + time;
447 }
448 
449 /* ECMA-262 3rd Edition    15.9.1.14 */
time_clip(DOUBLE time)450 static inline DOUBLE time_clip(DOUBLE time)
451 {
452     if(8.64e15 < time || time < -8.64e15) {
453         return NAN;
454     }
455 
456     return floor(time);
457 }
458 
date_now(void)459 static double date_now(void)
460 {
461     FILETIME ftime;
462     LONGLONG time;
463 
464     GetSystemTimeAsFileTime(&ftime);
465     time = ((LONGLONG)ftime.dwHighDateTime << 32) + ftime.dwLowDateTime;
466 
467     return time/10000 - TIME_EPOCH;
468 }
469 
create_systemtime(DOUBLE time)470 static SYSTEMTIME create_systemtime(DOUBLE time)
471 {
472     SYSTEMTIME st;
473 
474     st.wYear = year_from_time(time);
475     st.wMonth = month_from_time(time) + 1;
476     st.wDayOfWeek = week_day(time);
477     st.wDay = date_from_time(time);
478     st.wHour = hour_from_time(time);
479     st.wMinute = min_from_time(time);
480     st.wSecond = sec_from_time(time);
481     st.wMilliseconds = ms_from_time(time);
482 
483     return st;
484 }
485 
date_to_string(DOUBLE time,BOOL show_offset,int offset,jsval_t * r)486 static inline HRESULT date_to_string(DOUBLE time, BOOL show_offset, int offset, jsval_t *r)
487 {
488     static const WCHAR formatW[] = { '%','s',' ','%','s',' ','%','d',' ',
489         '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ',
490         'U','T','C','%','c','%','0','2','d','%','0','2','d',' ','%','d','%','s',0 };
491     static const WCHAR formatUTCW[] = { '%','s',' ','%','s',' ','%','d',' ',
492         '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ',
493         'U','T','C',' ','%','d','%','s',0 };
494     static const WCHAR formatNoOffsetW[] = { '%','s',' ','%','s',' ',
495         '%','d',' ','%','0','2','d',':','%','0','2','d',':',
496         '%','0','2','d',' ','%','d','%','s',0 };
497     static const WCHAR ADW[] = { 0 };
498     static const WCHAR BCW[] = { ' ','B','.','C','.',0 };
499 
500     static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1,
501         LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4,
502         LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 };
503     static const DWORD month_ids[] = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
504         LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
505         LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
506         LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
507         LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
508         LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
509 
510     BOOL formatAD = TRUE;
511     WCHAR week[64], month[64];
512     WCHAR buf[192];
513     jsstr_t *date_jsstr;
514     int year, day;
515     DWORD lcid_en;
516     WCHAR sign = '-';
517 
518     if(isnan(time)) {
519         if(r)
520             *r = jsval_string(jsstr_nan());
521         return S_OK;
522     }
523 
524     if(r) {
525         lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
526 
527         week[0] = 0;
528         GetLocaleInfoW(lcid_en, week_ids[(int)week_day(time)], week, ARRAY_SIZE(week));
529 
530         month[0] = 0;
531         GetLocaleInfoW(lcid_en, month_ids[(int)month_from_time(time)], month, ARRAY_SIZE(month));
532 
533         year = year_from_time(time);
534         if(year<0) {
535             formatAD = FALSE;
536             year = -year+1;
537         }
538 
539         day = date_from_time(time);
540 
541         if(offset < 0) {
542             sign = '+';
543             offset = -offset;
544         }
545 
546         if(!show_offset)
547             swprintf(buf, formatNoOffsetW, week, month, day,
548                     (int)hour_from_time(time), (int)min_from_time(time),
549                     (int)sec_from_time(time), year, formatAD?ADW:BCW);
550         else if(offset)
551             swprintf(buf, formatW, week, month, day,
552                     (int)hour_from_time(time), (int)min_from_time(time),
553                     (int)sec_from_time(time), sign, offset/60, offset%60,
554                     year, formatAD?ADW:BCW);
555         else
556             swprintf(buf, formatUTCW, week, month, day,
557                     (int)hour_from_time(time), (int)min_from_time(time),
558                     (int)sec_from_time(time), year, formatAD?ADW:BCW);
559 
560         date_jsstr = jsstr_alloc(buf);
561         if(!date_jsstr)
562             return E_OUTOFMEMORY;
563 
564         *r = jsval_string(date_jsstr);
565     }
566     return S_OK;
567 }
568 
569 /* ECMA-262 3rd Edition    15.9.1.2 */
dateobj_to_string(DateInstance * date,jsval_t * r)570 static HRESULT dateobj_to_string(DateInstance *date, jsval_t *r)
571 {
572     DOUBLE time;
573     int offset;
574 
575     time = local_time(date->time, date);
576     offset = date->bias +
577         daylight_saving_ta(time, date);
578 
579     return date_to_string(time, TRUE, offset, r);
580 }
581 
Date_toString(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)582 static HRESULT Date_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
583 {
584     DateInstance *date;
585 
586     TRACE("\n");
587 
588     if(!(date = date_this(jsthis)))
589         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
590 
591     return dateobj_to_string(date, r);
592 }
593 
594 /* ECMA-262 3rd Edition    15.9.1.5 */
Date_toLocaleString(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)595 static HRESULT Date_toLocaleString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
596         jsval_t *r)
597 {
598     SYSTEMTIME st;
599     DateInstance *date;
600     jsstr_t *date_str;
601     int date_len, time_len;
602 
603     TRACE("\n");
604 
605     if(!(date = date_this(jsthis)))
606         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
607 
608     if(isnan(date->time)) {
609         if(r)
610             *r = jsval_string(jsstr_nan());
611         return S_OK;
612     }
613 
614     st = create_systemtime(local_time(date->time, date));
615 
616     if(st.wYear<1601 || st.wYear>9999)
617         return dateobj_to_string(date, r);
618 
619     if(r) {
620         WCHAR *ptr;
621 
622         date_len = GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, NULL, 0);
623         time_len = GetTimeFormatW(ctx->lcid, 0, &st, NULL, NULL, 0);
624 
625         date_str = jsstr_alloc_buf(date_len+time_len-1, &ptr);
626         if(!date_str)
627             return E_OUTOFMEMORY;
628 
629         GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, ptr, date_len);
630         GetTimeFormatW(ctx->lcid, 0, &st, NULL, ptr+date_len, time_len);
631         ptr[date_len-1] = ' ';
632 
633         *r = jsval_string(date_str);
634     }
635     return S_OK;
636 }
637 
Date_toISOString(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)638 static HRESULT Date_toISOString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
639         jsval_t *r)
640 {
641     DateInstance *date;
642     WCHAR buf[64], *p = buf;
643     double year;
644 
645     static const WCHAR short_year_formatW[] = {'%','0','4','d',0};
646     static const WCHAR long_year_formatW[] = {'%','0','6','d',0};
647     static const WCHAR formatW[] = {'-','%','0','2','d','-','%','0','2','d',
648         'T','%','0','2','d',':','%','0','2','d',':','%','0','2','d','.','%','0','3','d','Z',0};
649 
650     TRACE("\n");
651 
652     if(!(date = date_this(jsthis)))
653         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
654 
655     year = year_from_time(date->time);
656     if(isnan(year) || year > 999999 || year < -999999) {
657         FIXME("year %lf should throw an exception\n", year);
658         return E_FAIL;
659     }
660 
661     if(year < 0) {
662         *p++ = '-';
663         p += swprintf(p, long_year_formatW, -(int)year);
664     }else if(year > 9999) {
665         *p++ = '+';
666         p += swprintf(p, long_year_formatW, (int)year);
667     }else {
668         p += swprintf(p, short_year_formatW, (int)year);
669     }
670 
671     swprintf(p, formatW,
672              (int)month_from_time(date->time) + 1, (int)date_from_time(date->time),
673              (int)hour_from_time(date->time), (int)min_from_time(date->time),
674              (int)sec_from_time(date->time), (int)ms_from_time(date->time));
675 
676     if(r) {
677         jsstr_t *ret;
678         if(!(ret = jsstr_alloc(buf)))
679             return E_OUTOFMEMORY;
680         *r = jsval_string(ret);
681     }
682     return S_OK;
683 }
684 
Date_valueOf(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)685 static HRESULT Date_valueOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
686         jsval_t *r)
687 {
688     DateInstance *date;
689 
690     TRACE("\n");
691 
692     if(!(date = date_this(jsthis)))
693         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
694 
695     if(r)
696         *r = jsval_number(date->time);
697     return S_OK;
698 }
699 
create_utc_string(script_ctx_t * ctx,vdisp_t * jsthis,jsval_t * r)700 static inline HRESULT create_utc_string(script_ctx_t *ctx, vdisp_t *jsthis, jsval_t *r)
701 {
702     static const WCHAR formatADW[] = { '%','s',',',' ','%','d',' ','%','s',' ','%','d',' ',
703         '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ','U','T','C',0 };
704     static const WCHAR formatBCW[] = { '%','s',',',' ','%','d',' ','%','s',' ','%','d',' ','B','.','C','.',' ',
705         '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ','U','T','C',0 };
706 
707     static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1,
708         LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4,
709         LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 };
710     static const DWORD month_ids[] = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
711         LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
712         LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
713         LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
714         LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
715         LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
716 
717     BOOL formatAD = TRUE;
718     WCHAR week[64], month[64];
719     WCHAR buf[192];
720     DateInstance *date;
721     jsstr_t *date_str;
722     int year, day;
723     DWORD lcid_en;
724 
725     if(!(date = date_this(jsthis)))
726         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
727 
728     if(isnan(date->time)) {
729         if(r)
730             *r = jsval_string(jsstr_nan());
731         return S_OK;
732     }
733 
734     if(r) {
735         lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
736 
737         week[0] = 0;
738         GetLocaleInfoW(lcid_en, week_ids[(int)week_day(date->time)], week, ARRAY_SIZE(week));
739 
740         month[0] = 0;
741         GetLocaleInfoW(lcid_en, month_ids[(int)month_from_time(date->time)], month, ARRAY_SIZE(month));
742 
743         year = year_from_time(date->time);
744         if(year<0) {
745             formatAD = FALSE;
746             year = -year+1;
747         }
748 
749         day = date_from_time(date->time);
750 
751         swprintf(buf, formatAD ? formatADW : formatBCW, week, day, month, year,
752                 (int)hour_from_time(date->time), (int)min_from_time(date->time),
753                 (int)sec_from_time(date->time));
754 
755         date_str = jsstr_alloc(buf);
756         if(!date_str)
757             return E_OUTOFMEMORY;
758 
759         *r = jsval_string(date_str);
760     }
761     return S_OK;
762 }
763 
764 /* ECMA-262 3rd Edition    15.9.5.42 */
Date_toUTCString(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)765 static HRESULT Date_toUTCString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
766         jsval_t *r)
767 {
768     TRACE("\n");
769     return create_utc_string(ctx, jsthis, r);
770 }
771 
Date_toGMTString(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)772 static HRESULT Date_toGMTString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
773         jsval_t *r)
774 {
775     TRACE("\n");
776     return create_utc_string(ctx, jsthis, r);
777 }
778 
779 /* ECMA-262 3rd Edition    15.9.5.3 */
dateobj_to_date_string(DateInstance * date,jsval_t * r)780 static HRESULT dateobj_to_date_string(DateInstance *date, jsval_t *r)
781 {
782     static const WCHAR formatADW[] = { '%','s',' ','%','s',' ','%','d',' ','%','d',0 };
783     static const WCHAR formatBCW[] = { '%','s',' ','%','s',' ','%','d',' ','%','d',' ','B','.','C','.',0 };
784 
785     static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1,
786         LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4,
787         LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 };
788     static const DWORD month_ids[] = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
789         LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
790         LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
791         LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
792         LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
793         LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
794 
795     BOOL formatAD = TRUE;
796     WCHAR week[64], month[64];
797     WCHAR buf[192];
798     jsstr_t *date_str;
799     DOUBLE time;
800     int year, day;
801     DWORD lcid_en;
802 
803     if(isnan(date->time)) {
804         if(r)
805             *r = jsval_string(jsstr_nan());
806         return S_OK;
807     }
808 
809     time = local_time(date->time, date);
810 
811     if(r) {
812         lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
813 
814         week[0] = 0;
815         GetLocaleInfoW(lcid_en, week_ids[(int)week_day(time)], week, ARRAY_SIZE(week));
816 
817         month[0] = 0;
818         GetLocaleInfoW(lcid_en, month_ids[(int)month_from_time(time)], month, ARRAY_SIZE(month));
819 
820         year = year_from_time(time);
821         if(year<0) {
822             formatAD = FALSE;
823             year = -year+1;
824         }
825 
826         day = date_from_time(time);
827 
828         swprintf(buf, formatAD ? formatADW : formatBCW, week, month, day, year);
829 
830         date_str = jsstr_alloc(buf);
831         if(!date_str)
832             return E_OUTOFMEMORY;
833 
834         *r = jsval_string(date_str);
835     }
836     return S_OK;
837 }
838 
Date_toDateString(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)839 static HRESULT Date_toDateString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
840         jsval_t *r)
841 {
842     DateInstance *date;
843 
844     if(!(date = date_this(jsthis)))
845         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
846 
847     return dateobj_to_date_string(date, r);
848 }
849 
850 /* ECMA-262 3rd Edition    15.9.5.4 */
Date_toTimeString(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)851 static HRESULT Date_toTimeString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
852         jsval_t *r)
853 {
854     static const WCHAR formatW[] = { '%','0','2','d',':','%','0','2','d',':','%','0','2','d',
855         ' ','U','T','C','%','c','%','0','2','d','%','0','2','d',0 };
856     static const WCHAR formatUTCW[] = { '%','0','2','d',':','%','0','2','d',
857         ':','%','0','2','d',' ','U','T','C',0 };
858     DateInstance *date;
859     jsstr_t *date_str;
860     WCHAR buf[32];
861     DOUBLE time;
862     WCHAR sign;
863     int offset;
864 
865     TRACE("\n");
866 
867     if(!(date = date_this(jsthis)))
868         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
869 
870     if(isnan(date->time)) {
871         if(r)
872             *r = jsval_string(jsstr_nan());
873         return S_OK;
874     }
875 
876     time = local_time(date->time, date);
877 
878     if(r) {
879         offset = date->bias +
880             daylight_saving_ta(time, date);
881 
882         if(offset < 0) {
883             sign = '+';
884             offset = -offset;
885         }
886         else sign = '-';
887 
888         if(offset)
889             swprintf(buf, formatW, (int)hour_from_time(time),
890                     (int)min_from_time(time), (int)sec_from_time(time),
891                     sign, offset/60, offset%60);
892         else
893             swprintf(buf, formatUTCW, (int)hour_from_time(time),
894                     (int)min_from_time(time), (int)sec_from_time(time));
895 
896         date_str = jsstr_alloc(buf);
897         if(!date_str)
898             return E_OUTOFMEMORY;
899 
900         *r = jsval_string(date_str);
901     }
902     return S_OK;
903 }
904 
905 /* ECMA-262 3rd Edition    15.9.5.6 */
Date_toLocaleDateString(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)906 static HRESULT Date_toLocaleDateString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
907         jsval_t *r)
908 {
909     SYSTEMTIME st;
910     DateInstance *date;
911     jsstr_t *date_str;
912     int len;
913 
914     TRACE("\n");
915 
916     if(!(date = date_this(jsthis)))
917         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
918 
919     if(isnan(date->time)) {
920         if(r)
921             *r = jsval_string(jsstr_nan());
922         return S_OK;
923     }
924 
925     st = create_systemtime(local_time(date->time, date));
926 
927     if(st.wYear<1601 || st.wYear>9999)
928         return dateobj_to_date_string(date, r);
929 
930     if(r) {
931         WCHAR *ptr;
932 
933         len = GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, NULL, 0);
934         date_str = jsstr_alloc_buf(len-1, &ptr);
935         if(!date_str)
936             return E_OUTOFMEMORY;
937         GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, ptr, len);
938 
939         *r = jsval_string(date_str);
940     }
941     return S_OK;
942 }
943 
944 /* ECMA-262 3rd Edition    15.9.5.7 */
Date_toLocaleTimeString(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)945 static HRESULT Date_toLocaleTimeString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
946         jsval_t *r)
947 {
948     SYSTEMTIME st;
949     DateInstance *date;
950     jsstr_t *date_str;
951     int len;
952 
953     TRACE("\n");
954 
955     if(!(date = date_this(jsthis)))
956         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
957 
958     if(isnan(date->time)) {
959         if(r)
960             *r = jsval_string(jsstr_nan());
961         return S_OK;
962     }
963 
964     st = create_systemtime(local_time(date->time, date));
965 
966     if(st.wYear<1601 || st.wYear>9999)
967         return Date_toTimeString(ctx, jsthis, flags, argc, argv, r);
968 
969     if(r) {
970         WCHAR *ptr;
971 
972         len = GetTimeFormatW(ctx->lcid, 0, &st, NULL, NULL, 0);
973         date_str = jsstr_alloc_buf(len-1, &ptr);
974         if(!date_str)
975             return E_OUTOFMEMORY;
976         GetTimeFormatW(ctx->lcid, 0, &st, NULL, ptr, len);
977 
978         *r = jsval_string(date_str);
979     }
980     return S_OK;
981 }
982 
983 /* ECMA-262 3rd Edition    15.9.5.9 */
Date_getTime(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)984 static HRESULT Date_getTime(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
985         jsval_t *r)
986 {
987     DateInstance *date;
988 
989     TRACE("\n");
990 
991     if(!(date = date_this(jsthis)))
992         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
993 
994     if(r)
995         *r = jsval_number(date->time);
996     return S_OK;
997 }
998 
999 /* ECMA-262 3rd Edition    15.9.5.10 */
Date_getFullYear(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1000 static HRESULT Date_getFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1001         jsval_t *r)
1002 {
1003     DateInstance *date;
1004 
1005     TRACE("\n");
1006 
1007     if(!(date = date_this(jsthis)))
1008         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1009 
1010     if(r) {
1011         DOUBLE time = local_time(date->time, date);
1012 
1013         *r = jsval_number(year_from_time(time));
1014     }
1015     return S_OK;
1016 }
1017 
1018 /* ECMA-262 3rd Edition    15.9.5.11 */
Date_getUTCFullYear(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1019 static HRESULT Date_getUTCFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1020         jsval_t *r)
1021 {
1022     DateInstance *date;
1023 
1024     TRACE("\n");
1025 
1026     if(!(date = date_this(jsthis)))
1027         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1028 
1029     if(r)
1030         *r = jsval_number(year_from_time(date->time));
1031     return S_OK;
1032 }
1033 
1034 /* ECMA-262 3rd Edition    15.9.5.12 */
Date_getMonth(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1035 static HRESULT Date_getMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1036 {
1037     DateInstance *date;
1038 
1039     TRACE("\n");
1040 
1041     if(!(date = date_this(jsthis)))
1042         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1043 
1044     if(r)
1045         *r = jsval_number(month_from_time(local_time(date->time, date)));
1046     return S_OK;
1047 }
1048 
1049 /* ECMA-262 3rd Edition    15.9.5.13 */
Date_getUTCMonth(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1050 static HRESULT Date_getUTCMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1051         jsval_t *r)
1052 {
1053     DateInstance *date;
1054 
1055     TRACE("\n");
1056 
1057     if(!(date = date_this(jsthis)))
1058         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1059 
1060     if(r)
1061         *r = jsval_number(month_from_time(date->time));
1062     return S_OK;
1063 }
1064 
1065 /* ECMA-262 3rd Edition    15.9.5.14 */
Date_getDate(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1066 static HRESULT Date_getDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1067 {
1068     DateInstance *date;
1069 
1070     TRACE("\n");
1071 
1072     if(!(date = date_this(jsthis)))
1073         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1074 
1075     if(r)
1076         *r = jsval_number(date_from_time(local_time(date->time, date)));
1077     return S_OK;
1078 }
1079 
1080 /* ECMA-262 3rd Edition    15.9.5.15 */
Date_getUTCDate(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1081 static HRESULT Date_getUTCDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1082         jsval_t *r)
1083 {
1084     DateInstance *date;
1085 
1086     TRACE("\n");
1087 
1088     if(!(date = date_this(jsthis)))
1089         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1090 
1091     if(r)
1092         *r = jsval_number(date_from_time(date->time));
1093     return S_OK;
1094 }
1095 
1096 /* ECMA-262 3rd Edition    15.9.5.16 */
Date_getDay(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1097 static HRESULT Date_getDay(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1098         jsval_t *r)
1099 {
1100     DateInstance *date;
1101 
1102     TRACE("\n");
1103 
1104     if(!(date = date_this(jsthis)))
1105         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1106 
1107     if(r)
1108         *r = jsval_number(week_day(local_time(date->time, date)));
1109     return S_OK;
1110 }
1111 
1112 /* ECMA-262 3rd Edition    15.9.5.17 */
Date_getUTCDay(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1113 static HRESULT Date_getUTCDay(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1114         jsval_t *r)
1115 {
1116     DateInstance *date;
1117 
1118     TRACE("\n");
1119 
1120     if(!(date = date_this(jsthis)))
1121         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1122 
1123     if(r)
1124         *r = jsval_number(week_day(date->time));
1125     return S_OK;
1126 }
1127 
1128 /* ECMA-262 3rd Edition    15.9.5.18 */
Date_getHours(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1129 static HRESULT Date_getHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1130         jsval_t *r)
1131 {
1132     DateInstance *date;
1133 
1134     TRACE("\n");
1135 
1136     if(!(date = date_this(jsthis)))
1137         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1138 
1139     if(r)
1140         *r = jsval_number(hour_from_time(local_time(date->time, date)));
1141     return S_OK;
1142 }
1143 
1144 /* ECMA-262 3rd Edition    15.9.5.19 */
Date_getUTCHours(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1145 static HRESULT Date_getUTCHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1146         jsval_t *r)
1147 {
1148     DateInstance *date;
1149 
1150     TRACE("\n");
1151 
1152     if(!(date = date_this(jsthis)))
1153         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1154 
1155     if(r)
1156         *r = jsval_number(hour_from_time(date->time));
1157     return S_OK;
1158 }
1159 
1160 /* ECMA-262 3rd Edition    15.9.5.20 */
Date_getMinutes(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1161 static HRESULT Date_getMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1162         jsval_t *r)
1163 {
1164     DateInstance *date;
1165 
1166     TRACE("\n");
1167 
1168     if(!(date = date_this(jsthis)))
1169         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1170 
1171     if(r)
1172         *r = jsval_number(min_from_time(local_time(date->time, date)));
1173     return S_OK;
1174 }
1175 
1176 /* ECMA-262 3rd Edition    15.9.5.21 */
Date_getUTCMinutes(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1177 static HRESULT Date_getUTCMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1178         jsval_t *r)
1179 {
1180     DateInstance *date;
1181 
1182     TRACE("\n");
1183 
1184     if(!(date = date_this(jsthis)))
1185         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1186 
1187     if(r)
1188         *r = jsval_number(min_from_time(date->time));
1189     return S_OK;
1190 }
1191 
1192 /* ECMA-262 3rd Edition    15.9.5.22 */
Date_getSeconds(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1193 static HRESULT Date_getSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1194 {
1195     DateInstance *date;
1196 
1197     TRACE("\n");
1198 
1199     if(!(date = date_this(jsthis)))
1200         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1201 
1202     if(r)
1203         *r = jsval_number(sec_from_time(local_time(date->time, date)));
1204     return S_OK;
1205 }
1206 
1207 /* ECMA-262 3rd Edition    15.9.5.23 */
Date_getUTCSeconds(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1208 static HRESULT Date_getUTCSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1209         jsval_t *r)
1210 {
1211     DateInstance *date;
1212 
1213     TRACE("\n");
1214 
1215     if(!(date = date_this(jsthis)))
1216         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1217 
1218     if(r)
1219         *r = jsval_number(sec_from_time(date->time));
1220     return S_OK;
1221 }
1222 
1223 /* ECMA-262 3rd Edition    15.9.5.24 */
Date_getMilliseconds(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1224 static HRESULT Date_getMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1225         jsval_t *r)
1226 {
1227     DateInstance *date;
1228 
1229     TRACE("\n");
1230 
1231     if(!(date = date_this(jsthis)))
1232         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1233 
1234     if(r)
1235         *r = jsval_number(ms_from_time(local_time(date->time, date)));
1236     return S_OK;
1237 }
1238 
1239 /* ECMA-262 3rd Edition    15.9.5.25 */
Date_getUTCMilliseconds(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1240 static HRESULT Date_getUTCMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1241         jsval_t *r)
1242 {
1243     DateInstance *date;
1244 
1245     TRACE("\n");
1246 
1247     if(!(date = date_this(jsthis)))
1248         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1249 
1250     if(r)
1251         *r = jsval_number(ms_from_time(date->time));
1252     return S_OK;
1253 }
1254 
1255 /* ECMA-262 3rd Edition    15.9.5.26 */
Date_getTimezoneOffset(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1256 static HRESULT Date_getTimezoneOffset(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1257         jsval_t *r)
1258 {
1259     DateInstance *date;
1260 
1261     TRACE("\n");
1262 
1263     if(!(date = date_this(jsthis)))
1264         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1265 
1266     if(r)
1267         *r = jsval_number(floor((date->time-local_time(date->time, date))/MS_PER_MINUTE));
1268     return S_OK;
1269 }
1270 
1271 /* ECMA-262 3rd Edition    15.9.5.27 */
Date_setTime(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1272 static HRESULT Date_setTime(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1273         jsval_t *r)
1274 {
1275     double n;
1276     HRESULT hres;
1277     DateInstance *date;
1278 
1279     TRACE("\n");
1280 
1281     if(!(date = date_this(jsthis)))
1282         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1283 
1284     if(!argc)
1285         return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1286 
1287     hres = to_number(ctx, argv[0], &n);
1288     if(FAILED(hres))
1289         return hres;
1290 
1291     date->time = time_clip(n);
1292 
1293     if(r)
1294         *r = jsval_number(date->time);
1295     return S_OK;
1296 }
1297 
1298 /* ECMA-262 3rd Edition    15.9.5.28 */
Date_setMilliseconds(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1299 static HRESULT Date_setMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1300         jsval_t *r)
1301 {
1302     DateInstance *date;
1303     double n, t;
1304     HRESULT hres;
1305 
1306     TRACE("\n");
1307 
1308     if(!(date = date_this(jsthis)))
1309         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1310 
1311     if(!argc)
1312         return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1313 
1314     hres = to_number(ctx, argv[0], &n);
1315     if(FAILED(hres))
1316         return hres;
1317 
1318     t = local_time(date->time, date);
1319     t = make_date(day(t), make_time(hour_from_time(t), min_from_time(t),
1320                 sec_from_time(t), n));
1321     date->time = time_clip(utc(t, date));
1322 
1323     if(r)
1324         *r = jsval_number(date->time);
1325     return S_OK;
1326 }
1327 
1328 /* ECMA-262 3rd Edition    15.9.5.29 */
Date_setUTCMilliseconds(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1329 static HRESULT Date_setUTCMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1330         jsval_t *r)
1331 {
1332     DateInstance *date;
1333     double n, t;
1334     HRESULT hres;
1335 
1336     TRACE("\n");
1337 
1338     if(!(date = date_this(jsthis)))
1339         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1340 
1341     if(!argc)
1342         return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1343 
1344     hres = to_number(ctx, argv[0], &n);
1345     if(FAILED(hres))
1346         return hres;
1347 
1348     t = date->time;
1349     t = make_date(day(t), make_time(hour_from_time(t), min_from_time(t),
1350                 sec_from_time(t), n));
1351     date->time = time_clip(t);
1352 
1353     if(r)
1354         *r = jsval_number(date->time);
1355     return S_OK;
1356 }
1357 
1358 /* ECMA-262 3rd Edition    15.9.5.30 */
Date_setSeconds(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1359 static HRESULT Date_setSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1360         jsval_t *r)
1361 {
1362     DateInstance *date;
1363     double t, sec, ms;
1364     HRESULT hres;
1365 
1366     TRACE("\n");
1367 
1368     if(!(date = date_this(jsthis)))
1369         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1370 
1371     if(!argc)
1372         return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1373 
1374     t = local_time(date->time, date);
1375 
1376     hres = to_number(ctx, argv[0], &sec);
1377     if(FAILED(hres))
1378         return hres;
1379 
1380     if(argc > 1) {
1381         hres = to_number(ctx, argv[1], &ms);
1382         if(FAILED(hres))
1383             return hres;
1384     }else {
1385         ms = ms_from_time(t);
1386     }
1387 
1388     t = make_date(day(t), make_time(hour_from_time(t),
1389                 min_from_time(t), sec, ms));
1390     date->time = time_clip(utc(t, date));
1391 
1392     if(r)
1393         *r = jsval_number(date->time);
1394     return S_OK;
1395 }
1396 
1397 /* ECMA-262 3rd Edition    15.9.5.31 */
Date_setUTCSeconds(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1398 static HRESULT Date_setUTCSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1399         jsval_t *r)
1400 {
1401     DateInstance *date;
1402     double t, sec, ms;
1403     HRESULT hres;
1404 
1405     TRACE("\n");
1406 
1407     if(!(date = date_this(jsthis)))
1408         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1409 
1410     if(!argc)
1411         return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1412 
1413     t = date->time;
1414 
1415     hres = to_number(ctx, argv[0], &sec);
1416     if(FAILED(hres))
1417         return hres;
1418 
1419     if(argc > 1) {
1420         hres = to_number(ctx, argv[1], &ms);
1421         if(FAILED(hres))
1422             return hres;
1423     }else {
1424         ms = ms_from_time(t);
1425     }
1426 
1427     t = make_date(day(t), make_time(hour_from_time(t),
1428                 min_from_time(t), sec, ms));
1429     date->time = time_clip(t);
1430 
1431     if(r)
1432         *r = jsval_number(date->time);
1433     return S_OK;
1434 }
1435 
1436 /* ECMA-262 3rd Edition    15.9.5.33 */
Date_setMinutes(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1437 static HRESULT Date_setMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1438         jsval_t *r)
1439 {
1440     DateInstance *date;
1441     double t, min, sec, ms;
1442     HRESULT hres;
1443 
1444     TRACE("\n");
1445 
1446     if(!(date = date_this(jsthis)))
1447         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1448 
1449     if(!argc)
1450         return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1451 
1452     t = local_time(date->time, date);
1453 
1454     hres = to_number(ctx, argv[0], &min);
1455     if(FAILED(hres))
1456         return hres;
1457 
1458     if(argc > 1) {
1459         hres = to_number(ctx, argv[1], &sec);
1460         if(FAILED(hres))
1461             return hres;
1462     }else {
1463         sec = sec_from_time(t);
1464     }
1465 
1466     if(argc > 2) {
1467         hres = to_number(ctx, argv[2], &ms);
1468         if(FAILED(hres))
1469             return hres;
1470     }else {
1471         ms = ms_from_time(t);
1472     }
1473 
1474     t = make_date(day(t), make_time(hour_from_time(t),
1475                 min, sec, ms));
1476     date->time = time_clip(utc(t, date));
1477 
1478     if(r)
1479         *r = jsval_number(date->time);
1480     return S_OK;
1481 }
1482 
1483 /* ECMA-262 3rd Edition    15.9.5.34 */
Date_setUTCMinutes(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1484 static HRESULT Date_setUTCMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1485         jsval_t *r)
1486 {
1487     DateInstance *date;
1488     double t, min, sec, ms;
1489     HRESULT hres;
1490 
1491     TRACE("\n");
1492 
1493     if(!(date = date_this(jsthis)))
1494         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1495 
1496     if(!argc)
1497         return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1498 
1499     t = date->time;
1500 
1501     hres = to_number(ctx, argv[0], &min);
1502     if(FAILED(hres))
1503         return hres;
1504 
1505     if(argc > 1) {
1506         hres = to_number(ctx, argv[1], &sec);
1507         if(FAILED(hres))
1508             return hres;
1509     }else {
1510         sec = sec_from_time(t);
1511     }
1512 
1513     if(argc > 2) {
1514         hres = to_number(ctx, argv[2], &ms);
1515         if(FAILED(hres))
1516             return hres;
1517     }else {
1518         ms = ms_from_time(t);
1519     }
1520 
1521     t = make_date(day(t), make_time(hour_from_time(t),
1522                 min, sec, ms));
1523     date->time = time_clip(t);
1524 
1525     if(r)
1526         *r = jsval_number(date->time);
1527     return S_OK;
1528 }
1529 
1530 /* ECMA-262 3rd Edition    15.9.5.35 */
Date_setHours(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1531 static HRESULT Date_setHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1532         jsval_t *r)
1533 {
1534     DateInstance *date;
1535     double t, hour, min, sec, ms;
1536     HRESULT hres;
1537 
1538     TRACE("\n");
1539 
1540     if(!(date = date_this(jsthis)))
1541         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1542 
1543     if(!argc)
1544         return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1545 
1546     t = local_time(date->time, date);
1547 
1548     hres = to_number(ctx, argv[0], &hour);
1549     if(FAILED(hres))
1550         return hres;
1551 
1552     if(argc > 1) {
1553         hres = to_number(ctx, argv[1], &min);
1554         if(FAILED(hres))
1555             return hres;
1556     }else {
1557         min = min_from_time(t);
1558     }
1559 
1560     if(argc > 2) {
1561         hres = to_number(ctx, argv[2], &sec);
1562         if(FAILED(hres))
1563             return hres;
1564     }else {
1565         sec = sec_from_time(t);
1566     }
1567 
1568     if(argc > 3) {
1569         hres = to_number(ctx, argv[3], &ms);
1570         if(FAILED(hres))
1571             return hres;
1572     }else {
1573         ms = ms_from_time(t);
1574     }
1575 
1576     t = make_date(day(t), make_time(hour, min, sec, ms));
1577     date->time = time_clip(utc(t, date));
1578 
1579     if(r)
1580         *r = jsval_number(date->time);
1581     return S_OK;
1582 }
1583 
1584 /* ECMA-262 3rd Edition    15.9.5.36 */
Date_setUTCHours(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1585 static HRESULT Date_setUTCHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1586         jsval_t *r)
1587 {
1588     DateInstance *date;
1589     double t, hour, min, sec, ms;
1590     HRESULT hres;
1591 
1592     TRACE("\n");
1593 
1594     if(!(date = date_this(jsthis)))
1595         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1596 
1597     if(!argc)
1598         return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1599 
1600     t = date->time;
1601 
1602     hres = to_number(ctx, argv[0], &hour);
1603     if(FAILED(hres))
1604         return hres;
1605 
1606     if(argc > 1) {
1607         hres = to_number(ctx, argv[1], &min);
1608         if(FAILED(hres))
1609             return hres;
1610     }else {
1611         min = min_from_time(t);
1612     }
1613 
1614     if(argc > 2) {
1615         hres = to_number(ctx, argv[2], &sec);
1616         if(FAILED(hres))
1617             return hres;
1618     }else {
1619         sec = sec_from_time(t);
1620     }
1621 
1622     if(argc > 3) {
1623         hres = to_number(ctx, argv[3], &ms);
1624         if(FAILED(hres))
1625             return hres;
1626     }else {
1627         ms = ms_from_time(t);
1628     }
1629 
1630     t = make_date(day(t), make_time(hour, min, sec, ms));
1631     date->time = time_clip(t);
1632 
1633     if(r)
1634         *r = jsval_number(date->time);
1635     return S_OK;
1636 }
1637 
1638 /* ECMA-262 3rd Edition    15.9.5.36 */
Date_setDate(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1639 static HRESULT Date_setDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1640         jsval_t *r)
1641 {
1642     DateInstance *date;
1643     double t, n;
1644     HRESULT hres;
1645 
1646     TRACE("\n");
1647 
1648     if(!(date = date_this(jsthis)))
1649         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1650 
1651     if(!argc)
1652         return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1653 
1654     hres = to_number(ctx, argv[0], &n);
1655     if(FAILED(hres))
1656         return hres;
1657 
1658     t = local_time(date->time, date);
1659     t = make_date(make_day(year_from_time(t), month_from_time(t), n), time_within_day(t));
1660     date->time = time_clip(utc(t, date));
1661 
1662     if(r)
1663         *r = jsval_number(date->time);
1664     return S_OK;
1665 }
1666 
1667 /* ECMA-262 3rd Edition    15.9.5.37 */
Date_setUTCDate(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1668 static HRESULT Date_setUTCDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1669         jsval_t *r)
1670 {
1671     DateInstance *date;
1672     double t, n;
1673     HRESULT hres;
1674 
1675     TRACE("\n");
1676 
1677     if(!(date = date_this(jsthis)))
1678         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1679 
1680     if(!argc)
1681         return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1682 
1683     hres = to_number(ctx, argv[0], &n);
1684     if(FAILED(hres))
1685         return hres;
1686 
1687     t = date->time;
1688     t = make_date(make_day(year_from_time(t), month_from_time(t), n), time_within_day(t));
1689     date->time = time_clip(t);
1690 
1691     if(r)
1692         *r = jsval_number(date->time);
1693     return S_OK;
1694 }
1695 
1696 /* ECMA-262 3rd Edition    15.9.5.38 */
Date_setMonth(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1697 static HRESULT Date_setMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1698         jsval_t *r)
1699 {
1700     DateInstance *date;
1701     DOUBLE t, month, ddate;
1702     HRESULT hres;
1703 
1704     TRACE("\n");
1705 
1706     if(!(date = date_this(jsthis)))
1707         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1708 
1709     if(!argc)
1710         return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1711 
1712     t = local_time(date->time, date);
1713 
1714     hres = to_number(ctx, argv[0], &month);
1715     if(FAILED(hres))
1716         return hres;
1717 
1718     if(argc > 1) {
1719         hres = to_number(ctx, argv[1], &ddate);
1720         if(FAILED(hres))
1721             return hres;
1722     }else {
1723         ddate = date_from_time(t);
1724     }
1725 
1726     t = make_date(make_day(year_from_time(t), month, ddate),
1727             time_within_day(t));
1728     date->time = time_clip(utc(t, date));
1729 
1730     if(r)
1731         *r = jsval_number(date->time);
1732     return S_OK;
1733 }
1734 
1735 /* ECMA-262 3rd Edition    15.9.5.39 */
Date_setUTCMonth(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1736 static HRESULT Date_setUTCMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1737         jsval_t *r)
1738 {
1739     DateInstance *date;
1740     double t, month, ddate;
1741     HRESULT hres;
1742 
1743     TRACE("\n");
1744 
1745     if(!(date = date_this(jsthis)))
1746         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1747 
1748     if(!argc)
1749         return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1750 
1751     t = date->time;
1752 
1753     hres = to_number(ctx, argv[0], &month);
1754     if(FAILED(hres))
1755         return hres;
1756 
1757     if(argc > 1) {
1758         hres = to_number(ctx, argv[1], &ddate);
1759         if(FAILED(hres))
1760             return hres;
1761     }else {
1762         ddate = date_from_time(t);
1763     }
1764 
1765     t = make_date(make_day(year_from_time(t), month, ddate),
1766             time_within_day(t));
1767     date->time = time_clip(t);
1768 
1769     if(r)
1770         *r = jsval_number(date->time);
1771     return S_OK;
1772 }
1773 
1774 /* ECMA-262 3rd Edition    15.9.5.40 */
Date_setFullYear(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1775 static HRESULT Date_setFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1776         jsval_t *r)
1777 {
1778     DateInstance *date;
1779     double t, year, month, ddate;
1780     HRESULT hres;
1781 
1782     TRACE("\n");
1783 
1784     if(!(date = date_this(jsthis)))
1785         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1786 
1787     if(!argc)
1788         return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1789 
1790     t = local_time(date->time, date);
1791 
1792     hres = to_number(ctx, argv[0], &year);
1793     if(FAILED(hres))
1794         return hres;
1795 
1796     if(argc > 1) {
1797         hres = to_number(ctx, argv[1], &month);
1798         if(FAILED(hres))
1799             return hres;
1800     }else {
1801         month = month_from_time(t);
1802     }
1803 
1804     if(argc > 2) {
1805         hres = to_number(ctx, argv[2], &ddate);
1806         if(FAILED(hres))
1807             return hres;
1808     }else {
1809         ddate = date_from_time(t);
1810     }
1811 
1812     t = make_date(make_day(year, month, ddate), time_within_day(t));
1813     date->time = time_clip(utc(t, date));
1814 
1815     if(r)
1816         *r = jsval_number(date->time);
1817     return S_OK;
1818 }
1819 
1820 /* ECMA-262 3rd Edition    15.9.5.41 */
Date_setUTCFullYear(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1821 static HRESULT Date_setUTCFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1822         jsval_t *r)
1823 {
1824     DateInstance *date;
1825     double t, year, month, ddate;
1826     HRESULT hres;
1827 
1828     TRACE("\n");
1829 
1830     if(!(date = date_this(jsthis)))
1831         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1832 
1833     if(!argc)
1834         return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1835 
1836     t = date->time;
1837 
1838     hres = to_number(ctx, argv[0], &year);
1839     if(FAILED(hres))
1840         return hres;
1841 
1842     if(argc > 1) {
1843         hres = to_number(ctx, argv[1], &month);
1844         if(FAILED(hres))
1845             return hres;
1846     }else {
1847         month = month_from_time(t);
1848     }
1849 
1850     if(argc > 2) {
1851         hres = to_number(ctx, argv[2], &ddate);
1852         if(FAILED(hres))
1853             return hres;
1854     }else {
1855         ddate = date_from_time(t);
1856     }
1857 
1858     t = make_date(make_day(year, month, ddate), time_within_day(t));
1859     date->time = time_clip(t);
1860 
1861     if(r)
1862         *r = jsval_number(date->time);
1863     return S_OK;
1864 }
1865 
1866 /* ECMA-262 3rd Edition    B2.4 */
Date_getYear(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1867 static HRESULT Date_getYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1868         jsval_t *r)
1869 {
1870     DateInstance *date;
1871     DOUBLE t, year;
1872 
1873     TRACE("\n");
1874 
1875     if(!(date = date_this(jsthis)))
1876         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1877 
1878     t = local_time(date->time, date);
1879     if(isnan(t)) {
1880         if(r)
1881             *r = jsval_number(NAN);
1882         return S_OK;
1883     }
1884 
1885     year = year_from_time(t);
1886     if(r)
1887         *r = jsval_number((1900<=year && year<2000)?year-1900:year);
1888     return S_OK;
1889 }
1890 
1891 /* ECMA-262 3rd Edition    B2.5 */
Date_setYear(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)1892 static HRESULT Date_setYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1893         jsval_t *r)
1894 {
1895     DateInstance *date;
1896     DOUBLE t, year;
1897     HRESULT hres;
1898 
1899     TRACE("\n");
1900 
1901     if(!(date = date_this(jsthis)))
1902         return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1903 
1904     if(!argc)
1905         return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1906 
1907     t = local_time(date->time, date);
1908 
1909     hres = to_number(ctx, argv[0], &year);
1910     if(FAILED(hres))
1911         return hres;
1912 
1913     if(isnan(year)) {
1914         date->time = year;
1915         if(r)
1916             *r = jsval_number(NAN);
1917         return S_OK;
1918     }
1919 
1920     year = year >= 0.0 ? floor(year) : -floor(-year);
1921     if(-1.0 < year && year < 100.0)
1922         year += 1900.0;
1923 
1924     date->time = time_clip(utc(make_date(make_day(year, month_from_time(t), date_from_time(t)), time_within_day(t)), date));
1925 
1926     if(r)
1927         *r = jsval_number(date->time);
1928     return S_OK;
1929 }
1930 
Date_get_value(script_ctx_t * ctx,jsdisp_t * jsthis,jsval_t * r)1931 static HRESULT Date_get_value(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
1932 {
1933     TRACE("\n");
1934 
1935     return dateobj_to_string(date_from_jsdisp(jsthis), r);
1936 }
1937 
1938 static const builtin_prop_t Date_props[] = {
1939     {getDateW,               Date_getDate,               PROPF_METHOD},
1940     {getDayW,                Date_getDay,                PROPF_METHOD},
1941     {getFullYearW,           Date_getFullYear,           PROPF_METHOD},
1942     {getHoursW,              Date_getHours,              PROPF_METHOD},
1943     {getMillisecondsW,       Date_getMilliseconds,       PROPF_METHOD},
1944     {getMinutesW,            Date_getMinutes,            PROPF_METHOD},
1945     {getMonthW,              Date_getMonth,              PROPF_METHOD},
1946     {getSecondsW,            Date_getSeconds,            PROPF_METHOD},
1947     {getTimeW,               Date_getTime,               PROPF_METHOD},
1948     {getTimezoneOffsetW,     Date_getTimezoneOffset,     PROPF_METHOD},
1949     {getUTCDateW,            Date_getUTCDate,            PROPF_METHOD},
1950     {getUTCDayW,             Date_getUTCDay,             PROPF_METHOD},
1951     {getUTCFullYearW,        Date_getUTCFullYear,        PROPF_METHOD},
1952     {getUTCHoursW,           Date_getUTCHours,           PROPF_METHOD},
1953     {getUTCMillisecondsW,    Date_getUTCMilliseconds,    PROPF_METHOD},
1954     {getUTCMinutesW,         Date_getUTCMinutes,         PROPF_METHOD},
1955     {getUTCMonthW,           Date_getUTCMonth,           PROPF_METHOD},
1956     {getUTCSecondsW,         Date_getUTCSeconds,         PROPF_METHOD},
1957     {getYearW,               Date_getYear,               PROPF_METHOD},
1958     {setDateW,               Date_setDate,               PROPF_METHOD|1},
1959     {setFullYearW,           Date_setFullYear,           PROPF_METHOD|3},
1960     {setHoursW,              Date_setHours,              PROPF_METHOD|4},
1961     {setMillisecondsW,       Date_setMilliseconds,       PROPF_METHOD|1},
1962     {setMinutesW,            Date_setMinutes,            PROPF_METHOD|3},
1963     {setMonthW,              Date_setMonth,              PROPF_METHOD|2},
1964     {setSecondsW,            Date_setSeconds,            PROPF_METHOD|2},
1965     {setTimeW,               Date_setTime,               PROPF_METHOD|1},
1966     {setUTCDateW,            Date_setUTCDate,            PROPF_METHOD|1},
1967     {setUTCFullYearW,        Date_setUTCFullYear,        PROPF_METHOD|3},
1968     {setUTCHoursW,           Date_setUTCHours,           PROPF_METHOD|4},
1969     {setUTCMillisecondsW,    Date_setUTCMilliseconds,    PROPF_METHOD|1},
1970     {setUTCMinutesW,         Date_setUTCMinutes,         PROPF_METHOD|3},
1971     {setUTCMonthW,           Date_setUTCMonth,           PROPF_METHOD|2},
1972     {setUTCSecondsW,         Date_setUTCSeconds,         PROPF_METHOD|2},
1973     {setYearW,               Date_setYear,               PROPF_METHOD|1},
1974     {toDateStringW,          Date_toDateString,          PROPF_METHOD},
1975     {toGMTStringW,           Date_toGMTString,           PROPF_METHOD},
1976     {toISOStringW,           Date_toISOString,           PROPF_METHOD|PROPF_ES5},
1977     {toLocaleDateStringW,    Date_toLocaleDateString,    PROPF_METHOD},
1978     {toLocaleStringW,        Date_toLocaleString,        PROPF_METHOD},
1979     {toLocaleTimeStringW,    Date_toLocaleTimeString,    PROPF_METHOD},
1980     {toStringW,              Date_toString,              PROPF_METHOD},
1981     {toTimeStringW,          Date_toTimeString,          PROPF_METHOD},
1982     {toUTCStringW,           Date_toUTCString,           PROPF_METHOD},
1983     {valueOfW,               Date_valueOf,               PROPF_METHOD},
1984 };
1985 
1986 static const builtin_info_t Date_info = {
1987     JSCLASS_DATE,
1988     {NULL, NULL,0, Date_get_value},
1989     ARRAY_SIZE(Date_props),
1990     Date_props,
1991     NULL,
1992     NULL
1993 };
1994 
1995 static const builtin_info_t DateInst_info = {
1996     JSCLASS_DATE,
1997     {NULL, NULL,0, Date_get_value},
1998     0, NULL,
1999     NULL,
2000     NULL
2001 };
2002 
create_date(script_ctx_t * ctx,jsdisp_t * object_prototype,DOUBLE time,jsdisp_t ** ret)2003 static HRESULT create_date(script_ctx_t *ctx, jsdisp_t *object_prototype, DOUBLE time, jsdisp_t **ret)
2004 {
2005     DateInstance *date;
2006     HRESULT hres;
2007     TIME_ZONE_INFORMATION tzi;
2008 
2009     GetTimeZoneInformation(&tzi);
2010 
2011     date = heap_alloc_zero(sizeof(DateInstance));
2012     if(!date)
2013         return E_OUTOFMEMORY;
2014 
2015     if(object_prototype)
2016         hres = init_dispex(&date->dispex, ctx, &Date_info, object_prototype);
2017     else
2018         hres = init_dispex_from_constr(&date->dispex, ctx, &DateInst_info, ctx->date_constr);
2019     if(FAILED(hres)) {
2020         heap_free(date);
2021         return hres;
2022     }
2023 
2024     date->time = time;
2025     date->bias = tzi.Bias;
2026     date->standardDate = tzi.StandardDate;
2027     date->standardBias = tzi.StandardBias;
2028     date->daylightDate = tzi.DaylightDate;
2029     date->daylightBias = tzi.DaylightBias;
2030 
2031     *ret = &date->dispex;
2032     return S_OK;
2033 }
2034 
date_parse(jsstr_t * input_str,double * ret)2035 static inline HRESULT date_parse(jsstr_t *input_str, double *ret) {
2036     static const DWORD string_ids[] = { LOCALE_SMONTHNAME12, LOCALE_SMONTHNAME11,
2037         LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME8,
2038         LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME5,
2039         LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME2,
2040         LOCALE_SMONTHNAME1, LOCALE_SDAYNAME7, LOCALE_SDAYNAME1,
2041         LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4,
2042         LOCALE_SDAYNAME5, LOCALE_SDAYNAME6 };
2043     WCHAR *strings[ARRAY_SIZE(string_ids)];
2044     WCHAR *parse;
2045     int input_len, parse_len = 0, nest_level = 0, i, size;
2046     int year = 0, month = 0, day = 0, hour = 0, min = 0, sec = 0;
2047     int ms = 0, offset = 0, hour_adjust = 0;
2048     BOOL set_year = FALSE, set_month = FALSE, set_day = FALSE, set_hour = FALSE;
2049     BOOL set_offset = FALSE, set_era = FALSE, ad = TRUE, set_am = FALSE, am = TRUE;
2050     BOOL set_hour_adjust = TRUE;
2051     TIME_ZONE_INFORMATION tzi;
2052     const WCHAR *input;
2053     DateInstance di;
2054     DWORD lcid_en;
2055 
2056     input_len = jsstr_length(input_str);
2057     input = jsstr_flatten(input_str);
2058     if(!input)
2059         return E_OUTOFMEMORY;
2060 
2061     for(i=0; i<input_len; i++) {
2062         if(input[i] == '(') nest_level++;
2063         else if(input[i] == ')') {
2064             nest_level--;
2065             if(nest_level<0) {
2066                 *ret = NAN;
2067                 return S_OK;
2068             }
2069         }
2070         else if(!nest_level) parse_len++;
2071     }
2072 
2073     parse = heap_alloc((parse_len+1)*sizeof(WCHAR));
2074     if(!parse)
2075         return E_OUTOFMEMORY;
2076     nest_level = 0;
2077     parse_len = 0;
2078     for(i=0; i<input_len; i++) {
2079         if(input[i] == '(') nest_level++;
2080         else if(input[i] == ')') nest_level--;
2081         else if(!nest_level) parse[parse_len++] = towupper(input[i]);
2082     }
2083     parse[parse_len] = 0;
2084 
2085     GetTimeZoneInformation(&tzi);
2086     di.bias = tzi.Bias;
2087     di.standardDate = tzi.StandardDate;
2088     di.standardBias = tzi.StandardBias;
2089     di.daylightDate = tzi.DaylightDate;
2090     di.daylightBias = tzi.DaylightBias;
2091 
2092     /* FIXME: Cache strings */
2093     lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
2094     for(i=0; i<ARRAY_SIZE(string_ids); i++) {
2095         size = GetLocaleInfoW(lcid_en, string_ids[i], NULL, 0);
2096         strings[i] = heap_alloc((size+1)*sizeof(WCHAR));
2097         if(!strings[i]) {
2098             i--;
2099             while(i-- >= 0)
2100                 heap_free(strings[i]);
2101             heap_free(parse);
2102             return E_OUTOFMEMORY;
2103         }
2104         GetLocaleInfoW(lcid_en, string_ids[i], strings[i], size);
2105     }
2106 
2107     for(i=0; i<parse_len;) {
2108         while(iswspace(parse[i])) i++;
2109         if(parse[i] == ',') {
2110             while(parse[i] == ',') i++;
2111             continue;
2112         }
2113 
2114         if(parse[i]>='0' && parse[i]<='9') {
2115             int tmp = wcstol(&parse[i], NULL, 10);
2116             while(parse[i]>='0' && parse[i]<='9') i++;
2117             while(iswspace(parse[i])) i++;
2118 
2119             if(parse[i] == ':') {
2120                 /* Time */
2121                 if(set_hour) break;
2122                 set_hour = TRUE;
2123 
2124                 hour = tmp;
2125 
2126                 while(parse[i] == ':') i++;
2127                 while(iswspace(parse[i])) i++;
2128                 if(parse[i]>='0' && parse[i]<='9') {
2129                     min = wcstol(&parse[i], NULL, 10);
2130                     while(parse[i]>='0' && parse[i]<='9') i++;
2131                 }
2132 
2133                 while(iswspace(parse[i])) i++;
2134                 while(parse[i] == ':') i++;
2135                 while(iswspace(parse[i])) i++;
2136                 if(parse[i]>='0' && parse[i]<='9') {
2137                     sec = wcstol(&parse[i], NULL, 10);
2138                     while(parse[i]>='0' && parse[i]<='9') i++;
2139                 }
2140             }
2141             else if(parse[i]=='-' || parse[i]=='/') {
2142                 /* Short or long date */
2143                 if(set_day || set_month || set_year) break;
2144                 set_day = TRUE;
2145                 set_month = TRUE;
2146                 set_year = TRUE;
2147 
2148                 month = tmp-1;
2149 
2150                 while(iswspace(parse[i])) i++;
2151                 while(parse[i]=='-' || parse[i]=='/') i++;
2152                 while(iswspace(parse[i])) i++;
2153                 if(parse[i]<'0' || parse[i]>'9') break;
2154                 day = wcstol(&parse[i], NULL, 10);
2155                 while(parse[i]>='0' && parse[i]<='9') i++;
2156 
2157                 while(parse[i]=='-' || parse[i]=='/') i++;
2158                 while(iswspace(parse[i])) i++;
2159                 if(parse[i]<'0' || parse[i]>'9') break;
2160                 year = wcstol(&parse[i], NULL, 10);
2161                 while(parse[i]>='0' && parse[i]<='9') i++;
2162 
2163                 if(tmp >= 70){
2164                         /* long date */
2165                         month = day - 1;
2166                         day = year;
2167                         year = tmp;
2168 		}
2169             }
2170             else if(tmp<0) break;
2171             else if(tmp<70) {
2172                 /* Day */
2173                 if(set_day) break;
2174                 set_day = TRUE;
2175                 day = tmp;
2176             }
2177             else {
2178                 /* Year */
2179                 if(set_year) break;
2180                 set_year = TRUE;
2181                 year = tmp;
2182             }
2183         }
2184         else if(parse[i]=='+' || parse[i]=='-') {
2185             /* Timezone offset */
2186             BOOL positive = TRUE;
2187 
2188             if(set_offset && set_hour_adjust) break;
2189             set_offset = TRUE;
2190             set_hour_adjust = FALSE;
2191 
2192             if(parse[i] == '-')  positive = FALSE;
2193 
2194             i++;
2195             while(iswspace(parse[i])) i++;
2196             if(parse[i]<'0' || parse[i]>'9') break;
2197             offset = wcstol(&parse[i], NULL, 10);
2198             while(parse[i]>='0' && parse[i]<='9') i++;
2199 
2200             if(offset<24) offset *= 60;
2201             else offset = (offset/100)*60 + offset%100;
2202 
2203             if(positive) offset = -offset;
2204 
2205         }
2206         else {
2207             if(parse[i]<'A' || parse[i]>'Z') break;
2208             else if(parse[i]=='B' && (parse[i+1]=='C' ||
2209                         (parse[i+1]=='.' && parse[i+2]=='C'))) {
2210                 /* AD/BC */
2211                 if(set_era) break;
2212                 set_era = TRUE;
2213                 ad = FALSE;
2214 
2215                 i++;
2216                 if(parse[i] == '.') i++;
2217                 i++;
2218                 if(parse[i] == '.') i++;
2219             }
2220             else if(parse[i]=='A' && (parse[i+1]=='D' ||
2221                         (parse[i+1]=='.' && parse[i+2]=='D'))) {
2222                 /* AD/BC */
2223                 if(set_era) break;
2224                 set_era = TRUE;
2225 
2226                 i++;
2227                 if(parse[i] == '.') i++;
2228                 i++;
2229                 if(parse[i] == '.') i++;
2230             }
2231             else if(parse[i+1]<'A' || parse[i+1]>'Z') {
2232                 /* Timezone */
2233                 if(set_offset) break;
2234                 set_offset = TRUE;
2235 
2236                 if(parse[i] <= 'I') hour_adjust = parse[i]-'A'+2;
2237                 else if(parse[i] == 'J') break;
2238                 else if(parse[i] <= 'M') hour_adjust = parse[i]-'K'+11;
2239                 else if(parse[i] <= 'Y') hour_adjust = parse[i]-'N';
2240                 else hour_adjust = 1;
2241 
2242                 i++;
2243                 if(parse[i] == '.') i++;
2244             }
2245             else if(parse[i]=='A' && parse[i+1]=='M') {
2246                 /* AM/PM */
2247                 if(set_am) break;
2248                 set_am = TRUE;
2249                 am = TRUE;
2250                 i += 2;
2251             }
2252             else if(parse[i]=='P' && parse[i+1]=='M') {
2253                 /* AM/PM */
2254                 if(set_am) break;
2255                 set_am = TRUE;
2256                 am = FALSE;
2257                 i += 2;
2258             }
2259             else if((parse[i]=='U' && parse[i+1]=='T' && parse[i+2]=='C')
2260                     || (parse[i]=='G' && parse[i+1]=='M' && parse[i+2]=='T')) {
2261                 /* Timezone */
2262                 if(set_offset) break;
2263                 set_offset = TRUE;
2264                 set_hour_adjust = FALSE;
2265 
2266                 i += 3;
2267             }
2268             else {
2269                 /* Month or garbage */
2270                 unsigned int j;
2271 
2272                 for(size=i; parse[size]>='A' && parse[size]<='Z'; size++);
2273                 size -= i;
2274 
2275                 for(j=0; j<ARRAY_SIZE(string_ids); j++)
2276                     if(!_wcsnicmp(&parse[i], strings[j], size)) break;
2277 
2278                 if(j < 12) {
2279                     if(set_month) break;
2280                     set_month = TRUE;
2281                     month = 11-j;
2282                 }
2283                 else if(j == ARRAY_SIZE(string_ids)) break;
2284 
2285                 i += size;
2286             }
2287         }
2288     }
2289 
2290     if(i == parse_len && set_year && set_month && set_day && (!set_am || hour<13)) {
2291         if(set_am) {
2292             if(hour == 12) hour = 0;
2293             if(!am) hour += 12;
2294         }
2295 
2296         if(!ad) year = -year+1;
2297         else if(year<100) year += 1900;
2298 
2299         *ret = time_clip(make_date(make_day(year, month, day),
2300                     make_time(hour+hour_adjust, min, sec, ms)) + offset*MS_PER_MINUTE);
2301 
2302         if(set_hour_adjust)
2303             *ret = utc(*ret, &di);
2304     }else {
2305         *ret = NAN;
2306     }
2307 
2308     for(i=0; i<ARRAY_SIZE(string_ids); i++)
2309         heap_free(strings[i]);
2310     heap_free(parse);
2311 
2312     return S_OK;
2313 }
2314 
DateConstr_parse(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)2315 static HRESULT DateConstr_parse(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
2316         jsval_t *r)
2317 {
2318     jsstr_t *parse_str;
2319     double n;
2320     HRESULT hres;
2321 
2322     TRACE("\n");
2323 
2324     if(!argc) {
2325         if(r)
2326             *r = jsval_number(NAN);
2327         return S_OK;
2328     }
2329 
2330     hres = to_string(ctx, argv[0], &parse_str);
2331     if(FAILED(hres))
2332         return hres;
2333 
2334     hres = date_parse(parse_str, &n);
2335     jsstr_release(parse_str);
2336     if(FAILED(hres))
2337         return hres;
2338 
2339     *r = jsval_number(n);
2340     return S_OK;
2341 }
2342 
date_utc(script_ctx_t * ctx,unsigned argc,jsval_t * argv,double * ret)2343 static HRESULT date_utc(script_ctx_t *ctx, unsigned argc, jsval_t *argv, double *ret)
2344 {
2345     double year, month, vdate, hours, minutes, seconds, ms;
2346     HRESULT hres;
2347 
2348     TRACE("\n");
2349 
2350     if(argc) {
2351         hres = to_number(ctx, argv[0], &year);
2352         if(FAILED(hres))
2353             return hres;
2354         if(0 <= year && year <= 99)
2355             year += 1900;
2356     }else {
2357         year = 1900;
2358     }
2359 
2360     if(argc>1) {
2361         hres = to_number(ctx, argv[1], &month);
2362         if(FAILED(hres))
2363             return hres;
2364     }else {
2365         month = 0;
2366     }
2367 
2368     if(argc>2) {
2369         hres = to_number(ctx, argv[2], &vdate);
2370         if(FAILED(hres))
2371             return hres;
2372     }else {
2373         vdate = 1;
2374     }
2375 
2376     if(argc>3) {
2377         hres = to_number(ctx, argv[3], &hours);
2378         if(FAILED(hres))
2379             return hres;
2380     }else {
2381         hours = 0;
2382     }
2383 
2384     if(argc>4) {
2385         hres = to_number(ctx, argv[4], &minutes);
2386         if(FAILED(hres))
2387             return hres;
2388     }else {
2389         minutes = 0;
2390     }
2391 
2392     if(argc>5) {
2393         hres = to_number(ctx, argv[5], &seconds);
2394         if(FAILED(hres))
2395             return hres;
2396     }else {
2397         seconds = 0;
2398     }
2399 
2400     if(argc>6) {
2401         hres = to_number(ctx, argv[6], &ms);
2402         if(FAILED(hres))
2403             return hres;
2404     } else {
2405         ms = 0;
2406     }
2407 
2408     *ret = time_clip(make_date(make_day(year, month, vdate),
2409             make_time(hours, minutes,seconds, ms)));
2410     return S_OK;
2411 }
2412 
DateConstr_UTC(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)2413 static HRESULT DateConstr_UTC(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
2414         jsval_t *r)
2415 {
2416     double n;
2417     HRESULT hres;
2418 
2419     TRACE("\n");
2420 
2421     hres = date_utc(ctx, argc, argv, &n);
2422     if(SUCCEEDED(hres) && r)
2423         *r = jsval_number(n);
2424     return hres;
2425 }
2426 
2427 /* ECMA-262 5.1 Edition    15.9.4.4 */
DateConstr_now(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)2428 static HRESULT DateConstr_now(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
2429 {
2430     TRACE("\n");
2431 
2432     if(r) *r = jsval_number(date_now());
2433     return S_OK;
2434 }
2435 
DateConstr_value(script_ctx_t * ctx,vdisp_t * jsthis,WORD flags,unsigned argc,jsval_t * argv,jsval_t * r)2436 static HRESULT DateConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
2437         jsval_t *r)
2438 {
2439     jsdisp_t *date;
2440     HRESULT hres;
2441 
2442     TRACE("\n");
2443 
2444     switch(flags) {
2445     case DISPATCH_CONSTRUCT:
2446         switch(argc) {
2447         /* ECMA-262 3rd Edition    15.9.3.3 */
2448         case 0:
2449             hres = create_date(ctx, NULL, date_now(), &date);
2450             if(FAILED(hres))
2451                 return hres;
2452             break;
2453 
2454         /* ECMA-262 3rd Edition    15.9.3.2 */
2455         case 1: {
2456             jsval_t prim;
2457             double n;
2458 
2459             hres = to_primitive(ctx, argv[0], &prim, NO_HINT);
2460             if(FAILED(hres))
2461                 return hres;
2462 
2463             if(is_string(prim))
2464                 hres = date_parse(get_string(prim), &n);
2465             else
2466                 hres = to_number(ctx, prim, &n);
2467 
2468             jsval_release(prim);
2469             if(FAILED(hres))
2470                 return hres;
2471 
2472             hres = create_date(ctx, NULL, time_clip(n), &date);
2473             if(FAILED(hres))
2474                 return hres;
2475             break;
2476         }
2477 
2478         /* ECMA-262 3rd Edition    15.9.3.1 */
2479         default: {
2480             double ret_date;
2481             DateInstance *di;
2482 
2483             hres = date_utc(ctx, argc, argv, &ret_date);
2484             if(FAILED(hres))
2485                 return hres;
2486 
2487             hres = create_date(ctx, NULL, ret_date, &date);
2488             if(FAILED(hres))
2489                 return hres;
2490 
2491             di = date_from_jsdisp(date);
2492             di->time = utc(di->time, di);
2493         }
2494         }
2495 
2496         *r = jsval_obj(date);
2497         return S_OK;
2498 
2499     case INVOKE_FUNC: {
2500         FILETIME system_time, local_time;
2501         LONGLONG lltime;
2502 
2503         GetSystemTimeAsFileTime(&system_time);
2504         FileTimeToLocalFileTime(&system_time, &local_time);
2505         lltime = ((LONGLONG)local_time.dwHighDateTime<<32)
2506             + local_time.dwLowDateTime;
2507 
2508         return date_to_string(lltime/10000-TIME_EPOCH, FALSE, 0, r);
2509     }
2510 
2511     default:
2512         FIXME("unimplemented flags %x\n", flags);
2513         return E_NOTIMPL;
2514     }
2515 
2516     return S_OK;
2517 }
2518 
2519 static const builtin_prop_t DateConstr_props[] = {
2520     {UTCW,    DateConstr_UTC,    PROPF_METHOD},
2521     {nowW,    DateConstr_now,    PROPF_HTML|PROPF_METHOD},
2522     {parseW,  DateConstr_parse,  PROPF_METHOD}
2523 };
2524 
2525 static const builtin_info_t DateConstr_info = {
2526     JSCLASS_FUNCTION,
2527     DEFAULT_FUNCTION_VALUE,
2528     ARRAY_SIZE(DateConstr_props),
2529     DateConstr_props,
2530     NULL,
2531     NULL
2532 };
2533 
create_date_constr(script_ctx_t * ctx,jsdisp_t * object_prototype,jsdisp_t ** ret)2534 HRESULT create_date_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
2535 {
2536     jsdisp_t *date;
2537     HRESULT hres;
2538 
2539     static const WCHAR DateW[] = {'D','a','t','e',0};
2540 
2541     hres = create_date(ctx, object_prototype, 0.0, &date);
2542     if(FAILED(hres))
2543         return hres;
2544 
2545     hres = create_builtin_constructor(ctx, DateConstr_value, DateW, &DateConstr_info,
2546             PROPF_CONSTR|7, date, ret);
2547 
2548     jsdisp_release(date);
2549     return hres;
2550 }
2551