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