xref: /reactos/dll/win32/jscript/jscript.c (revision 40462c92)
1 /*
2  * Copyright 2008 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 
19 #include <assert.h>
20 
21 #include "jscript.h"
22 #include "engine.h"
23 #include "objsafe.h"
24 
25 #include "wine/debug.h"
26 
27 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
28 
29 #ifdef _WIN64
30 
31 #define CTXARG_T DWORDLONG
32 #define IActiveScriptParseVtbl IActiveScriptParse64Vtbl
33 #define IActiveScriptParseProcedure2Vtbl IActiveScriptParseProcedure2_64Vtbl
34 
35 #else
36 
37 #define CTXARG_T DWORD
38 #define IActiveScriptParseVtbl IActiveScriptParse32Vtbl
39 #define IActiveScriptParseProcedure2Vtbl IActiveScriptParseProcedure2_32Vtbl
40 
41 #endif
42 
43 typedef struct {
44     IActiveScript                IActiveScript_iface;
45     IActiveScriptParse           IActiveScriptParse_iface;
46     IActiveScriptParseProcedure2 IActiveScriptParseProcedure2_iface;
47     IActiveScriptProperty        IActiveScriptProperty_iface;
48     IObjectSafety                IObjectSafety_iface;
49     IVariantChangeType           IVariantChangeType_iface;
50 
51     LONG ref;
52 
53     DWORD safeopt;
54     script_ctx_t *ctx;
55     LONG thread_id;
56     LCID lcid;
57     DWORD version;
58     BOOL html_mode;
59     BOOL is_encode;
60 
61     IActiveScriptSite *site;
62 
63     bytecode_t *queue_head;
64     bytecode_t *queue_tail;
65 } JScript;
66 
67 void script_release(script_ctx_t *ctx)
68 {
69     if(--ctx->ref)
70         return;
71 
72     jsval_release(ctx->acc);
73     clear_ei(ctx);
74     if(ctx->cc)
75         release_cc(ctx->cc);
76     heap_pool_free(&ctx->tmp_heap);
77     if(ctx->last_match)
78         jsstr_release(ctx->last_match);
79     assert(!ctx->stack_top);
80     heap_free(ctx->stack);
81 
82     ctx->jscaller->ctx = NULL;
83     IServiceProvider_Release(&ctx->jscaller->IServiceProvider_iface);
84 
85     heap_free(ctx);
86 }
87 
88 static void change_state(JScript *This, SCRIPTSTATE state)
89 {
90     if(This->ctx->state == state)
91         return;
92 
93     This->ctx->state = state;
94     if(This->site)
95         IActiveScriptSite_OnStateChange(This->site, state);
96 }
97 
98 static inline BOOL is_started(script_ctx_t *ctx)
99 {
100     return ctx->state == SCRIPTSTATE_STARTED
101         || ctx->state == SCRIPTSTATE_CONNECTED
102         || ctx->state == SCRIPTSTATE_DISCONNECTED;
103 }
104 
105 static HRESULT exec_global_code(JScript *This, bytecode_t *code)
106 {
107     HRESULT hres;
108 
109     IActiveScriptSite_OnEnterScript(This->site);
110 
111     clear_ei(This->ctx);
112     hres = exec_source(This->ctx, EXEC_GLOBAL, code, &code->global_code, NULL, NULL, NULL, This->ctx->global, 0, NULL, NULL);
113 
114     IActiveScriptSite_OnLeaveScript(This->site);
115     return hres;
116 }
117 
118 static void clear_script_queue(JScript *This)
119 {
120     bytecode_t *iter, *iter2;
121 
122     if(!This->queue_head)
123         return;
124 
125     iter = This->queue_head;
126     while(iter) {
127         iter2 = iter->next;
128         iter->next = NULL;
129         release_bytecode(iter);
130         iter = iter2;
131     }
132 
133     This->queue_head = This->queue_tail = NULL;
134 }
135 
136 static void exec_queued_code(JScript *This)
137 {
138     bytecode_t *iter;
139 
140     for(iter = This->queue_head; iter; iter = iter->next)
141         exec_global_code(This, iter);
142 
143     clear_script_queue(This);
144 }
145 
146 static HRESULT set_ctx_site(JScript *This)
147 {
148     HRESULT hres;
149 
150     This->ctx->lcid = This->lcid;
151 
152     hres = init_global(This->ctx);
153     if(FAILED(hres))
154         return hres;
155 
156     IActiveScriptSite_AddRef(This->site);
157     This->ctx->site = This->site;
158 
159     change_state(This, SCRIPTSTATE_INITIALIZED);
160     return S_OK;
161 }
162 
163 static void decrease_state(JScript *This, SCRIPTSTATE state)
164 {
165     if(This->ctx) {
166         switch(This->ctx->state) {
167         case SCRIPTSTATE_CONNECTED:
168             change_state(This, SCRIPTSTATE_DISCONNECTED);
169             if(state == SCRIPTSTATE_DISCONNECTED)
170                 return;
171             /* FALLTHROUGH */
172         case SCRIPTSTATE_STARTED:
173         case SCRIPTSTATE_DISCONNECTED:
174             clear_script_queue(This);
175 
176             if(This->ctx->state == SCRIPTSTATE_DISCONNECTED)
177                 change_state(This, SCRIPTSTATE_INITIALIZED);
178             if(state == SCRIPTSTATE_INITIALIZED)
179                 return;
180             /* FALLTHROUGH */
181         case SCRIPTSTATE_INITIALIZED:
182             if(This->ctx->host_global) {
183                 IDispatch_Release(This->ctx->host_global);
184                 This->ctx->host_global = NULL;
185             }
186 
187             if(This->ctx->named_items) {
188                 named_item_t *iter, *iter2;
189 
190                 iter = This->ctx->named_items;
191                 while(iter) {
192                     iter2 = iter->next;
193 
194                     if(iter->disp)
195                         IDispatch_Release(iter->disp);
196                     heap_free(iter->name);
197                     heap_free(iter);
198                     iter = iter2;
199                 }
200 
201                 This->ctx->named_items = NULL;
202             }
203 
204             if(This->ctx->secmgr) {
205                 IInternetHostSecurityManager_Release(This->ctx->secmgr);
206                 This->ctx->secmgr = NULL;
207             }
208 
209             if(This->ctx->site) {
210                 IActiveScriptSite_Release(This->ctx->site);
211                 This->ctx->site = NULL;
212             }
213 
214             if(This->ctx->global) {
215                 jsdisp_release(This->ctx->global);
216                 This->ctx->global = NULL;
217             }
218             /* FALLTHROUGH */
219         case SCRIPTSTATE_UNINITIALIZED:
220             change_state(This, state);
221             break;
222         default:
223             assert(0);
224         }
225 
226         change_state(This, state);
227     }else if(state == SCRIPTSTATE_UNINITIALIZED) {
228         if(This->site)
229             IActiveScriptSite_OnStateChange(This->site, state);
230     }else {
231         FIXME("NULL ctx\n");
232     }
233 
234     if(state == SCRIPTSTATE_UNINITIALIZED)
235         This->thread_id = 0;
236 
237     if(This->site) {
238         IActiveScriptSite_Release(This->site);
239         This->site = NULL;
240     }
241 }
242 
243 typedef struct {
244     IServiceProvider IServiceProvider_iface;
245 
246     LONG ref;
247 
248     IServiceProvider *sp;
249 } AXSite;
250 
251 static inline AXSite *impl_from_IServiceProvider(IServiceProvider *iface)
252 {
253     return CONTAINING_RECORD(iface, AXSite, IServiceProvider_iface);
254 }
255 
256 static HRESULT WINAPI AXSite_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
257 {
258     AXSite *This = impl_from_IServiceProvider(iface);
259 
260     if(IsEqualGUID(&IID_IUnknown, riid)) {
261         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
262         *ppv = &This->IServiceProvider_iface;
263     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
264         TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
265         *ppv = &This->IServiceProvider_iface;
266     }else {
267         TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
268         *ppv = NULL;
269         return E_NOINTERFACE;
270     }
271 
272     IUnknown_AddRef((IUnknown*)*ppv);
273     return S_OK;
274 }
275 
276 static ULONG WINAPI AXSite_AddRef(IServiceProvider *iface)
277 {
278     AXSite *This = impl_from_IServiceProvider(iface);
279     LONG ref = InterlockedIncrement(&This->ref);
280 
281     TRACE("(%p) ref=%d\n", This, ref);
282 
283     return ref;
284 }
285 
286 static ULONG WINAPI AXSite_Release(IServiceProvider *iface)
287 {
288     AXSite *This = impl_from_IServiceProvider(iface);
289     LONG ref = InterlockedDecrement(&This->ref);
290 
291     TRACE("(%p) ref=%d\n", This, ref);
292 
293     if(!ref)
294     {
295         if(This->sp)
296             IServiceProvider_Release(This->sp);
297 
298         heap_free(This);
299     }
300 
301     return ref;
302 }
303 
304 static HRESULT WINAPI AXSite_QueryService(IServiceProvider *iface,
305         REFGUID guidService, REFIID riid, void **ppv)
306 {
307     AXSite *This = impl_from_IServiceProvider(iface);
308 
309     TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
310 
311     if(!This->sp)
312         return E_NOINTERFACE;
313 
314     return IServiceProvider_QueryService(This->sp, guidService, riid, ppv);
315 }
316 
317 static IServiceProviderVtbl AXSiteVtbl = {
318     AXSite_QueryInterface,
319     AXSite_AddRef,
320     AXSite_Release,
321     AXSite_QueryService
322 };
323 
324 IUnknown *create_ax_site(script_ctx_t *ctx)
325 {
326     IServiceProvider *sp = NULL;
327     AXSite *ret;
328     HRESULT hres;
329 
330     hres = IActiveScriptSite_QueryInterface(ctx->site, &IID_IServiceProvider, (void**)&sp);
331     if(FAILED(hres)) {
332         TRACE("Could not get IServiceProvider iface: %08x\n", hres);
333     }
334 
335     ret = heap_alloc(sizeof(AXSite));
336     if(!ret) {
337         IServiceProvider_Release(sp);
338         return NULL;
339     }
340 
341     ret->IServiceProvider_iface.lpVtbl = &AXSiteVtbl;
342     ret->ref = 1;
343     ret->sp = sp;
344 
345     return (IUnknown*)&ret->IServiceProvider_iface;
346 }
347 
348 static inline JScript *impl_from_IActiveScript(IActiveScript *iface)
349 {
350     return CONTAINING_RECORD(iface, JScript, IActiveScript_iface);
351 }
352 
353 static HRESULT WINAPI JScript_QueryInterface(IActiveScript *iface, REFIID riid, void **ppv)
354 {
355     JScript *This = impl_from_IActiveScript(iface);
356 
357     *ppv = NULL;
358 
359     if(IsEqualGUID(riid, &IID_IUnknown)) {
360         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
361         *ppv = &This->IActiveScript_iface;
362     }else if(IsEqualGUID(riid, &IID_IActiveScript)) {
363         TRACE("(%p)->(IID_IActiveScript %p)\n", This, ppv);
364         *ppv = &This->IActiveScript_iface;
365     }else if(IsEqualGUID(riid, &IID_IActiveScriptParse)) {
366         TRACE("(%p)->(IID_IActiveScriptParse %p)\n", This, ppv);
367         *ppv = &This->IActiveScriptParse_iface;
368     }else if(IsEqualGUID(riid, &IID_IActiveScriptParseProcedure)) {
369         TRACE("(%p)->(IID_IActiveScriptParseProcedure %p)\n", This, ppv);
370         *ppv = &This->IActiveScriptParseProcedure2_iface;
371     }else if(IsEqualGUID(riid, &IID_IActiveScriptParseProcedure2)) {
372         TRACE("(%p)->(IID_IActiveScriptParseProcedure2 %p)\n", This, ppv);
373         *ppv = &This->IActiveScriptParseProcedure2_iface;
374     }else if(IsEqualGUID(riid, &IID_IActiveScriptProperty)) {
375         TRACE("(%p)->(IID_IActiveScriptProperty %p)\n", This, ppv);
376         *ppv = &This->IActiveScriptProperty_iface;
377     }else if(IsEqualGUID(riid, &IID_IObjectSafety)) {
378         TRACE("(%p)->(IID_IObjectSafety %p)\n", This, ppv);
379         *ppv = &This->IObjectSafety_iface;
380     }else if(IsEqualGUID(riid, &IID_IVariantChangeType)) {
381         TRACE("(%p)->(IID_IVariantChangeType %p)\n", This, ppv);
382         *ppv = &This->IVariantChangeType_iface;
383     }
384 
385     if(*ppv) {
386         IUnknown_AddRef((IUnknown*)*ppv);
387         return S_OK;
388     }
389 
390     FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
391     return E_NOINTERFACE;
392 }
393 
394 static ULONG WINAPI JScript_AddRef(IActiveScript *iface)
395 {
396     JScript *This = impl_from_IActiveScript(iface);
397     LONG ref = InterlockedIncrement(&This->ref);
398 
399     TRACE("(%p) ref=%d\n", This, ref);
400 
401     return ref;
402 }
403 
404 static ULONG WINAPI JScript_Release(IActiveScript *iface)
405 {
406     JScript *This = impl_from_IActiveScript(iface);
407     LONG ref = InterlockedDecrement(&This->ref);
408 
409     TRACE("(%p) ref=%d\n", iface, ref);
410 
411     if(!ref) {
412         if(This->ctx && This->ctx->state != SCRIPTSTATE_CLOSED)
413             IActiveScript_Close(&This->IActiveScript_iface);
414         if(This->ctx) {
415             This->ctx->active_script = NULL;
416             script_release(This->ctx);
417         }
418         heap_free(This);
419         unlock_module();
420     }
421 
422     return ref;
423 }
424 
425 static HRESULT WINAPI JScript_SetScriptSite(IActiveScript *iface,
426                                             IActiveScriptSite *pass)
427 {
428     JScript *This = impl_from_IActiveScript(iface);
429     LCID lcid;
430     HRESULT hres;
431 
432     TRACE("(%p)->(%p)\n", This, pass);
433 
434     if(!pass)
435         return E_POINTER;
436 
437     if(This->site)
438         return E_UNEXPECTED;
439 
440     if(InterlockedCompareExchange(&This->thread_id, GetCurrentThreadId(), 0))
441         return E_UNEXPECTED;
442 
443     This->site = pass;
444     IActiveScriptSite_AddRef(This->site);
445 
446     hres = IActiveScriptSite_GetLCID(This->site, &lcid);
447     if(hres == S_OK)
448         This->lcid = lcid;
449 
450     return This->ctx ? set_ctx_site(This) : S_OK;
451 }
452 
453 static HRESULT WINAPI JScript_GetScriptSite(IActiveScript *iface, REFIID riid,
454                                             void **ppvObject)
455 {
456     JScript *This = impl_from_IActiveScript(iface);
457     FIXME("(%p)->()\n", This);
458     return E_NOTIMPL;
459 }
460 
461 static HRESULT WINAPI JScript_SetScriptState(IActiveScript *iface, SCRIPTSTATE ss)
462 {
463     JScript *This = impl_from_IActiveScript(iface);
464 
465     TRACE("(%p)->(%d)\n", This, ss);
466 
467     if(This->thread_id && GetCurrentThreadId() != This->thread_id)
468         return E_UNEXPECTED;
469 
470     if(ss == SCRIPTSTATE_UNINITIALIZED) {
471         if(This->ctx && This->ctx->state == SCRIPTSTATE_CLOSED)
472             return E_UNEXPECTED;
473 
474         decrease_state(This, SCRIPTSTATE_UNINITIALIZED);
475         return S_OK;
476     }
477 
478     if(!This->ctx)
479         return E_UNEXPECTED;
480 
481     switch(ss) {
482     case SCRIPTSTATE_STARTED:
483     case SCRIPTSTATE_CONNECTED: /* FIXME */
484         if(This->ctx->state == SCRIPTSTATE_CLOSED)
485             return E_UNEXPECTED;
486 
487         exec_queued_code(This);
488         break;
489     case SCRIPTSTATE_INITIALIZED:
490         FIXME("unimplemented SCRIPTSTATE_INITIALIZED\n");
491         return S_OK;
492     default:
493         FIXME("unimplemented state %d\n", ss);
494         return E_NOTIMPL;
495     }
496 
497     change_state(This, ss);
498     return S_OK;
499 }
500 
501 static HRESULT WINAPI JScript_GetScriptState(IActiveScript *iface, SCRIPTSTATE *pssState)
502 {
503     JScript *This = impl_from_IActiveScript(iface);
504 
505     TRACE("(%p)->(%p)\n", This, pssState);
506 
507     if(!pssState)
508         return E_POINTER;
509 
510     if(This->thread_id && This->thread_id != GetCurrentThreadId())
511         return E_UNEXPECTED;
512 
513     *pssState = This->ctx ? This->ctx->state : SCRIPTSTATE_UNINITIALIZED;
514     return S_OK;
515 }
516 
517 static HRESULT WINAPI JScript_Close(IActiveScript *iface)
518 {
519     JScript *This = impl_from_IActiveScript(iface);
520 
521     TRACE("(%p)->()\n", This);
522 
523     if(This->thread_id && This->thread_id != GetCurrentThreadId())
524         return E_UNEXPECTED;
525 
526     decrease_state(This, SCRIPTSTATE_CLOSED);
527     return S_OK;
528 }
529 
530 static HRESULT WINAPI JScript_AddNamedItem(IActiveScript *iface,
531                                            LPCOLESTR pstrName, DWORD dwFlags)
532 {
533     JScript *This = impl_from_IActiveScript(iface);
534     named_item_t *item;
535     IDispatch *disp = NULL;
536     HRESULT hres;
537 
538     TRACE("(%p)->(%s %x)\n", This, debugstr_w(pstrName), dwFlags);
539 
540     if(This->thread_id != GetCurrentThreadId() || !This->ctx || This->ctx->state == SCRIPTSTATE_CLOSED)
541         return E_UNEXPECTED;
542 
543     if(dwFlags & SCRIPTITEM_GLOBALMEMBERS) {
544         IUnknown *unk;
545 
546         hres = IActiveScriptSite_GetItemInfo(This->site, pstrName, SCRIPTINFO_IUNKNOWN, &unk, NULL);
547         if(FAILED(hres)) {
548             WARN("GetItemInfo failed: %08x\n", hres);
549             return hres;
550         }
551 
552         hres = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&disp);
553         IUnknown_Release(unk);
554         if(FAILED(hres)) {
555             WARN("object does not implement IDispatch\n");
556             return hres;
557         }
558 
559         if(This->ctx->host_global)
560             IDispatch_Release(This->ctx->host_global);
561         IDispatch_AddRef(disp);
562         This->ctx->host_global = disp;
563     }
564 
565     item = heap_alloc(sizeof(*item));
566     if(!item) {
567         if(disp)
568             IDispatch_Release(disp);
569         return E_OUTOFMEMORY;
570     }
571 
572     item->disp = disp;
573     item->flags = dwFlags;
574     item->name = heap_strdupW(pstrName);
575     if(!item->name) {
576         if(disp)
577             IDispatch_Release(disp);
578         heap_free(item);
579         return E_OUTOFMEMORY;
580     }
581 
582     item->next = This->ctx->named_items;
583     This->ctx->named_items = item;
584 
585     return S_OK;
586 }
587 
588 static HRESULT WINAPI JScript_AddTypeLib(IActiveScript *iface, REFGUID rguidTypeLib,
589                                          DWORD dwMajor, DWORD dwMinor, DWORD dwFlags)
590 {
591     JScript *This = impl_from_IActiveScript(iface);
592     FIXME("(%p)->()\n", This);
593     return E_NOTIMPL;
594 }
595 
596 static HRESULT WINAPI JScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR pstrItemName,
597                                                 IDispatch **ppdisp)
598 {
599     JScript *This = impl_from_IActiveScript(iface);
600 
601     TRACE("(%p)->(%p)\n", This, ppdisp);
602 
603     if(!ppdisp)
604         return E_POINTER;
605 
606     if(This->thread_id != GetCurrentThreadId() || !This->ctx->global) {
607         *ppdisp = NULL;
608         return E_UNEXPECTED;
609     }
610 
611     *ppdisp = to_disp(This->ctx->global);
612     IDispatch_AddRef(*ppdisp);
613     return S_OK;
614 }
615 
616 static HRESULT WINAPI JScript_GetCurrentScriptThreadID(IActiveScript *iface,
617                                                        SCRIPTTHREADID *pstridThread)
618 {
619     JScript *This = impl_from_IActiveScript(iface);
620     FIXME("(%p)->()\n", This);
621     return E_NOTIMPL;
622 }
623 
624 static HRESULT WINAPI JScript_GetScriptThreadID(IActiveScript *iface,
625                                                 DWORD dwWin32ThreadId, SCRIPTTHREADID *pstidThread)
626 {
627     JScript *This = impl_from_IActiveScript(iface);
628     FIXME("(%p)->()\n", This);
629     return E_NOTIMPL;
630 }
631 
632 static HRESULT WINAPI JScript_GetScriptThreadState(IActiveScript *iface,
633         SCRIPTTHREADID stidThread, SCRIPTTHREADSTATE *pstsState)
634 {
635     JScript *This = impl_from_IActiveScript(iface);
636     FIXME("(%p)->()\n", This);
637     return E_NOTIMPL;
638 }
639 
640 static HRESULT WINAPI JScript_InterruptScriptThread(IActiveScript *iface,
641         SCRIPTTHREADID stidThread, const EXCEPINFO *pexcepinfo, DWORD dwFlags)
642 {
643     JScript *This = impl_from_IActiveScript(iface);
644     FIXME("(%p)->()\n", This);
645     return E_NOTIMPL;
646 }
647 
648 static HRESULT WINAPI JScript_Clone(IActiveScript *iface, IActiveScript **ppscript)
649 {
650     JScript *This = impl_from_IActiveScript(iface);
651     FIXME("(%p)->()\n", This);
652     return E_NOTIMPL;
653 }
654 
655 static const IActiveScriptVtbl JScriptVtbl = {
656     JScript_QueryInterface,
657     JScript_AddRef,
658     JScript_Release,
659     JScript_SetScriptSite,
660     JScript_GetScriptSite,
661     JScript_SetScriptState,
662     JScript_GetScriptState,
663     JScript_Close,
664     JScript_AddNamedItem,
665     JScript_AddTypeLib,
666     JScript_GetScriptDispatch,
667     JScript_GetCurrentScriptThreadID,
668     JScript_GetScriptThreadID,
669     JScript_GetScriptThreadState,
670     JScript_InterruptScriptThread,
671     JScript_Clone
672 };
673 
674 static inline JScript *impl_from_IActiveScriptParse(IActiveScriptParse *iface)
675 {
676     return CONTAINING_RECORD(iface, JScript, IActiveScriptParse_iface);
677 }
678 
679 static HRESULT WINAPI JScriptParse_QueryInterface(IActiveScriptParse *iface, REFIID riid, void **ppv)
680 {
681     JScript *This = impl_from_IActiveScriptParse(iface);
682     return IActiveScript_QueryInterface(&This->IActiveScript_iface, riid, ppv);
683 }
684 
685 static ULONG WINAPI JScriptParse_AddRef(IActiveScriptParse *iface)
686 {
687     JScript *This = impl_from_IActiveScriptParse(iface);
688     return IActiveScript_AddRef(&This->IActiveScript_iface);
689 }
690 
691 static ULONG WINAPI JScriptParse_Release(IActiveScriptParse *iface)
692 {
693     JScript *This = impl_from_IActiveScriptParse(iface);
694     return IActiveScript_Release(&This->IActiveScript_iface);
695 }
696 
697 static HRESULT WINAPI JScriptParse_InitNew(IActiveScriptParse *iface)
698 {
699     JScript *This = impl_from_IActiveScriptParse(iface);
700     script_ctx_t *ctx;
701     HRESULT hres;
702 
703     TRACE("(%p)\n", This);
704 
705     if(This->ctx)
706         return E_UNEXPECTED;
707 
708     ctx = heap_alloc_zero(sizeof(script_ctx_t));
709     if(!ctx)
710         return E_OUTOFMEMORY;
711 
712     ctx->ref = 1;
713     ctx->state = SCRIPTSTATE_UNINITIALIZED;
714     ctx->active_script = &This->IActiveScript_iface;
715     ctx->safeopt = This->safeopt;
716     ctx->version = This->version;
717     ctx->html_mode = This->html_mode;
718     ctx->ei.val = jsval_undefined();
719     ctx->acc = jsval_undefined();
720     heap_pool_init(&ctx->tmp_heap);
721 
722     hres = create_jscaller(ctx);
723     if(FAILED(hres)) {
724         heap_free(ctx);
725         return hres;
726     }
727 
728     ctx->last_match = jsstr_empty();
729 
730     ctx = InterlockedCompareExchangePointer((void**)&This->ctx, ctx, NULL);
731     if(ctx) {
732         script_release(ctx);
733         return E_UNEXPECTED;
734     }
735 
736     return This->site ? set_ctx_site(This) : S_OK;
737 }
738 
739 static HRESULT WINAPI JScriptParse_AddScriptlet(IActiveScriptParse *iface,
740         LPCOLESTR pstrDefaultName, LPCOLESTR pstrCode, LPCOLESTR pstrItemName,
741         LPCOLESTR pstrSubItemName, LPCOLESTR pstrEventName, LPCOLESTR pstrDelimiter,
742         CTXARG_T dwSourceContextCookie, ULONG ulStartingLineNumber, DWORD dwFlags,
743         BSTR *pbstrName, EXCEPINFO *pexcepinfo)
744 {
745     JScript *This = impl_from_IActiveScriptParse(iface);
746     FIXME("(%p)->(%s %s %s %s %s %s %s %u %x %p %p)\n", This, debugstr_w(pstrDefaultName),
747           debugstr_w(pstrCode), debugstr_w(pstrItemName), debugstr_w(pstrSubItemName),
748           debugstr_w(pstrEventName), debugstr_w(pstrDelimiter), wine_dbgstr_longlong(dwSourceContextCookie),
749           ulStartingLineNumber, dwFlags, pbstrName, pexcepinfo);
750     return E_NOTIMPL;
751 }
752 
753 static HRESULT WINAPI JScriptParse_ParseScriptText(IActiveScriptParse *iface,
754         LPCOLESTR pstrCode, LPCOLESTR pstrItemName, IUnknown *punkContext,
755         LPCOLESTR pstrDelimiter, CTXARG_T dwSourceContextCookie, ULONG ulStartingLine,
756         DWORD dwFlags, VARIANT *pvarResult, EXCEPINFO *pexcepinfo)
757 {
758     JScript *This = impl_from_IActiveScriptParse(iface);
759     bytecode_t *code;
760     HRESULT hres;
761 
762     TRACE("(%p)->(%s %s %p %s %s %u %x %p %p)\n", This, debugstr_w(pstrCode),
763           debugstr_w(pstrItemName), punkContext, debugstr_w(pstrDelimiter),
764           wine_dbgstr_longlong(dwSourceContextCookie), ulStartingLine, dwFlags, pvarResult, pexcepinfo);
765 
766     if(This->thread_id != GetCurrentThreadId() || This->ctx->state == SCRIPTSTATE_CLOSED)
767         return E_UNEXPECTED;
768 
769     hres = compile_script(This->ctx, pstrCode, NULL, pstrDelimiter, (dwFlags & SCRIPTTEXT_ISEXPRESSION) != 0,
770             This->is_encode, &code);
771     if(FAILED(hres))
772         return hres;
773 
774     if(dwFlags & SCRIPTTEXT_ISEXPRESSION) {
775         jsval_t r;
776 
777         IActiveScriptSite_OnEnterScript(This->site);
778 
779         clear_ei(This->ctx);
780         hres = exec_source(This->ctx, EXEC_GLOBAL, code, &code->global_code, NULL, NULL, NULL, This->ctx->global, 0, NULL, &r);
781         if(SUCCEEDED(hres)) {
782             if(pvarResult)
783                 hres = jsval_to_variant(r, pvarResult);
784             jsval_release(r);
785         }
786 
787         IActiveScriptSite_OnLeaveScript(This->site);
788         return hres;
789     }
790 
791     /*
792      * Although pvarResult is not really used without SCRIPTTEXT_ISEXPRESSION flag, if it's not NULL,
793      * script is executed immediately, even if it's not in started state yet.
794      */
795     if(!pvarResult && !is_started(This->ctx)) {
796         if(This->queue_tail)
797             This->queue_tail = This->queue_tail->next = code;
798         else
799             This->queue_head = This->queue_tail = code;
800         return S_OK;
801     }
802 
803     hres = exec_global_code(This, code);
804     release_bytecode(code);
805     if(FAILED(hres))
806         return hres;
807 
808     if(pvarResult)
809         V_VT(pvarResult) = VT_EMPTY;
810     return S_OK;
811 }
812 
813 static const IActiveScriptParseVtbl JScriptParseVtbl = {
814     JScriptParse_QueryInterface,
815     JScriptParse_AddRef,
816     JScriptParse_Release,
817     JScriptParse_InitNew,
818     JScriptParse_AddScriptlet,
819     JScriptParse_ParseScriptText
820 };
821 
822 static inline JScript *impl_from_IActiveScriptParseProcedure2(IActiveScriptParseProcedure2 *iface)
823 {
824     return CONTAINING_RECORD(iface, JScript, IActiveScriptParseProcedure2_iface);
825 }
826 
827 static HRESULT WINAPI JScriptParseProcedure_QueryInterface(IActiveScriptParseProcedure2 *iface, REFIID riid, void **ppv)
828 {
829     JScript *This = impl_from_IActiveScriptParseProcedure2(iface);
830     return IActiveScript_QueryInterface(&This->IActiveScript_iface, riid, ppv);
831 }
832 
833 static ULONG WINAPI JScriptParseProcedure_AddRef(IActiveScriptParseProcedure2 *iface)
834 {
835     JScript *This = impl_from_IActiveScriptParseProcedure2(iface);
836     return IActiveScript_AddRef(&This->IActiveScript_iface);
837 }
838 
839 static ULONG WINAPI JScriptParseProcedure_Release(IActiveScriptParseProcedure2 *iface)
840 {
841     JScript *This = impl_from_IActiveScriptParseProcedure2(iface);
842     return IActiveScript_Release(&This->IActiveScript_iface);
843 }
844 
845 static HRESULT WINAPI JScriptParseProcedure_ParseProcedureText(IActiveScriptParseProcedure2 *iface,
846         LPCOLESTR pstrCode, LPCOLESTR pstrFormalParams, LPCOLESTR pstrProcedureName,
847         LPCOLESTR pstrItemName, IUnknown *punkContext, LPCOLESTR pstrDelimiter,
848         CTXARG_T dwSourceContextCookie, ULONG ulStartingLineNumber, DWORD dwFlags, IDispatch **ppdisp)
849 {
850     JScript *This = impl_from_IActiveScriptParseProcedure2(iface);
851     bytecode_t *code;
852     jsdisp_t *dispex;
853     HRESULT hres;
854 
855     TRACE("(%p)->(%s %s %s %s %p %s %s %u %x %p)\n", This, debugstr_w(pstrCode), debugstr_w(pstrFormalParams),
856           debugstr_w(pstrProcedureName), debugstr_w(pstrItemName), punkContext, debugstr_w(pstrDelimiter),
857           wine_dbgstr_longlong(dwSourceContextCookie), ulStartingLineNumber, dwFlags, ppdisp);
858 
859     if(This->thread_id != GetCurrentThreadId() || This->ctx->state == SCRIPTSTATE_CLOSED)
860         return E_UNEXPECTED;
861 
862     hres = compile_script(This->ctx, pstrCode, pstrFormalParams, pstrDelimiter, FALSE, This->is_encode, &code);
863     if(FAILED(hres)) {
864         WARN("Parse failed %08x\n", hres);
865         return hres;
866     }
867 
868     hres = create_source_function(This->ctx, code, &code->global_code, NULL,  &dispex);
869     release_bytecode(code);
870     if(FAILED(hres))
871         return hres;
872 
873     *ppdisp = to_disp(dispex);
874     return S_OK;
875 }
876 
877 static const IActiveScriptParseProcedure2Vtbl JScriptParseProcedureVtbl = {
878     JScriptParseProcedure_QueryInterface,
879     JScriptParseProcedure_AddRef,
880     JScriptParseProcedure_Release,
881     JScriptParseProcedure_ParseProcedureText,
882 };
883 
884 static inline JScript *impl_from_IActiveScriptProperty(IActiveScriptProperty *iface)
885 {
886     return CONTAINING_RECORD(iface, JScript, IActiveScriptProperty_iface);
887 }
888 
889 static HRESULT WINAPI JScriptProperty_QueryInterface(IActiveScriptProperty *iface, REFIID riid, void **ppv)
890 {
891     JScript *This = impl_from_IActiveScriptProperty(iface);
892     return IActiveScript_QueryInterface(&This->IActiveScript_iface, riid, ppv);
893 }
894 
895 static ULONG WINAPI JScriptProperty_AddRef(IActiveScriptProperty *iface)
896 {
897     JScript *This = impl_from_IActiveScriptProperty(iface);
898     return IActiveScript_AddRef(&This->IActiveScript_iface);
899 }
900 
901 static ULONG WINAPI JScriptProperty_Release(IActiveScriptProperty *iface)
902 {
903     JScript *This = impl_from_IActiveScriptProperty(iface);
904     return IActiveScript_Release(&This->IActiveScript_iface);
905 }
906 
907 static HRESULT WINAPI JScriptProperty_GetProperty(IActiveScriptProperty *iface, DWORD dwProperty,
908         VARIANT *pvarIndex, VARIANT *pvarValue)
909 {
910     JScript *This = impl_from_IActiveScriptProperty(iface);
911     FIXME("(%p)->(%x %p %p)\n", This, dwProperty, pvarIndex, pvarValue);
912     return E_NOTIMPL;
913 }
914 
915 static HRESULT WINAPI JScriptProperty_SetProperty(IActiveScriptProperty *iface, DWORD dwProperty,
916         VARIANT *pvarIndex, VARIANT *pvarValue)
917 {
918     JScript *This = impl_from_IActiveScriptProperty(iface);
919 
920     TRACE("(%p)->(%x %s %s)\n", This, dwProperty, debugstr_variant(pvarIndex), debugstr_variant(pvarValue));
921 
922     if(pvarIndex)
923         FIXME("unsupported pvarIndex\n");
924 
925     switch(dwProperty) {
926     case SCRIPTPROP_INVOKEVERSIONING:
927         if(V_VT(pvarValue) != VT_I4 || V_I4(pvarValue) < 0
928            || (V_I4(pvarValue) > 15 && !(V_I4(pvarValue) & SCRIPTLANGUAGEVERSION_HTML))) {
929             WARN("invalid value %s\n", debugstr_variant(pvarValue));
930             return E_INVALIDARG;
931         }
932 
933         This->version = V_I4(pvarValue) & 0x1ff;
934         This->html_mode = (V_I4(pvarValue) & SCRIPTLANGUAGEVERSION_HTML) != 0;
935         break;
936     default:
937         FIXME("Unimplemented property %x\n", dwProperty);
938         return E_NOTIMPL;
939     }
940 
941     return S_OK;
942 }
943 
944 static const IActiveScriptPropertyVtbl JScriptPropertyVtbl = {
945     JScriptProperty_QueryInterface,
946     JScriptProperty_AddRef,
947     JScriptProperty_Release,
948     JScriptProperty_GetProperty,
949     JScriptProperty_SetProperty
950 };
951 
952 static inline JScript *impl_from_IObjectSafety(IObjectSafety *iface)
953 {
954     return CONTAINING_RECORD(iface, JScript, IObjectSafety_iface);
955 }
956 
957 static HRESULT WINAPI JScriptSafety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
958 {
959     JScript *This = impl_from_IObjectSafety(iface);
960     return IActiveScript_QueryInterface(&This->IActiveScript_iface, riid, ppv);
961 }
962 
963 static ULONG WINAPI JScriptSafety_AddRef(IObjectSafety *iface)
964 {
965     JScript *This = impl_from_IObjectSafety(iface);
966     return IActiveScript_AddRef(&This->IActiveScript_iface);
967 }
968 
969 static ULONG WINAPI JScriptSafety_Release(IObjectSafety *iface)
970 {
971     JScript *This = impl_from_IObjectSafety(iface);
972     return IActiveScript_Release(&This->IActiveScript_iface);
973 }
974 
975 #define SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER)
976 
977 static HRESULT WINAPI JScriptSafety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
978         DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions)
979 {
980     JScript *This = impl_from_IObjectSafety(iface);
981 
982     TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), pdwSupportedOptions, pdwEnabledOptions);
983 
984     if(!pdwSupportedOptions || !pdwEnabledOptions)
985         return E_POINTER;
986 
987     *pdwSupportedOptions = SUPPORTED_OPTIONS;
988     *pdwEnabledOptions = This->safeopt;
989 
990     return S_OK;
991 }
992 
993 static HRESULT WINAPI JScriptSafety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
994         DWORD dwOptionSetMask, DWORD dwEnabledOptions)
995 {
996     JScript *This = impl_from_IObjectSafety(iface);
997 
998     TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), dwOptionSetMask, dwEnabledOptions);
999 
1000     if(dwOptionSetMask & ~SUPPORTED_OPTIONS)
1001         return E_FAIL;
1002 
1003     This->safeopt = (dwEnabledOptions & dwOptionSetMask) | (This->safeopt & ~dwOptionSetMask) | INTERFACE_USES_DISPEX;
1004     return S_OK;
1005 }
1006 
1007 static const IObjectSafetyVtbl JScriptSafetyVtbl = {
1008     JScriptSafety_QueryInterface,
1009     JScriptSafety_AddRef,
1010     JScriptSafety_Release,
1011     JScriptSafety_GetInterfaceSafetyOptions,
1012     JScriptSafety_SetInterfaceSafetyOptions
1013 };
1014 
1015 static inline JScript *impl_from_IVariantChangeType(IVariantChangeType *iface)
1016 {
1017     return CONTAINING_RECORD(iface, JScript, IVariantChangeType_iface);
1018 }
1019 
1020 static HRESULT WINAPI VariantChangeType_QueryInterface(IVariantChangeType *iface, REFIID riid, void **ppv)
1021 {
1022     JScript *This = impl_from_IVariantChangeType(iface);
1023     return IActiveScript_QueryInterface(&This->IActiveScript_iface, riid, ppv);
1024 }
1025 
1026 static ULONG WINAPI VariantChangeType_AddRef(IVariantChangeType *iface)
1027 {
1028     JScript *This = impl_from_IVariantChangeType(iface);
1029     return IActiveScript_AddRef(&This->IActiveScript_iface);
1030 }
1031 
1032 static ULONG WINAPI VariantChangeType_Release(IVariantChangeType *iface)
1033 {
1034     JScript *This = impl_from_IVariantChangeType(iface);
1035     return IActiveScript_Release(&This->IActiveScript_iface);
1036 }
1037 
1038 static HRESULT WINAPI VariantChangeType_ChangeType(IVariantChangeType *iface, VARIANT *dst, VARIANT *src, LCID lcid, VARTYPE vt)
1039 {
1040     JScript *This = impl_from_IVariantChangeType(iface);
1041     VARIANT res;
1042     HRESULT hres;
1043 
1044     TRACE("(%p)->(%p %p%s %x %d)\n", This, dst, src, debugstr_variant(src), lcid, vt);
1045 
1046     if(!This->ctx) {
1047         FIXME("Object uninitialized\n");
1048         return E_UNEXPECTED;
1049     }
1050 
1051     hres = variant_change_type(This->ctx, &res, src, vt);
1052     if(FAILED(hres))
1053         return hres;
1054 
1055     hres = VariantClear(dst);
1056     if(FAILED(hres)) {
1057         VariantClear(&res);
1058         return hres;
1059     }
1060 
1061     *dst = res;
1062     return S_OK;
1063 }
1064 
1065 static const IVariantChangeTypeVtbl VariantChangeTypeVtbl = {
1066     VariantChangeType_QueryInterface,
1067     VariantChangeType_AddRef,
1068     VariantChangeType_Release,
1069     VariantChangeType_ChangeType
1070 };
1071 
1072 HRESULT create_jscript_object(BOOL is_encode, REFIID riid, void **ppv)
1073 {
1074     JScript *ret;
1075     HRESULT hres;
1076 
1077     ret = heap_alloc_zero(sizeof(*ret));
1078     if(!ret)
1079         return E_OUTOFMEMORY;
1080 
1081     lock_module();
1082 
1083     ret->IActiveScript_iface.lpVtbl = &JScriptVtbl;
1084     ret->IActiveScriptParse_iface.lpVtbl = &JScriptParseVtbl;
1085     ret->IActiveScriptParseProcedure2_iface.lpVtbl = &JScriptParseProcedureVtbl;
1086     ret->IActiveScriptProperty_iface.lpVtbl = &JScriptPropertyVtbl;
1087     ret->IObjectSafety_iface.lpVtbl = &JScriptSafetyVtbl;
1088     ret->IVariantChangeType_iface.lpVtbl = &VariantChangeTypeVtbl;
1089     ret->ref = 1;
1090     ret->safeopt = INTERFACE_USES_DISPEX;
1091     ret->is_encode = is_encode;
1092 
1093     hres = IActiveScript_QueryInterface(&ret->IActiveScript_iface, riid, ppv);
1094     IActiveScript_Release(&ret->IActiveScript_iface);
1095     return hres;
1096 }
1097