jscript: Added RegExp.test implementation.
[wine] / dlls / jscript / jscript.c
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 "jscript.h"
20 #include "engine.h"
21 #include "objsafe.h"
22
23 #include "wine/debug.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
26
27 #ifdef _WIN64
28
29 #define CTXARG_T DWORDLONG
30 #define IActiveScriptParseVtbl IActiveScriptParse64Vtbl
31 #define IActiveScriptParseProcedure2Vtbl IActiveScriptParseProcedure2_64Vtbl
32
33 #else
34
35 #define CTXARG_T DWORD
36 #define IActiveScriptParseVtbl IActiveScriptParse32Vtbl
37 #define IActiveScriptParseProcedure2Vtbl IActiveScriptParseProcedure2_32Vtbl
38
39 #endif
40
41 typedef struct {
42     const IActiveScriptVtbl                 *lpIActiveScriptVtbl;
43     const IActiveScriptParseVtbl            *lpIActiveScriptParseVtbl;
44     const IActiveScriptParseProcedure2Vtbl  *lpIActiveScriptParseProcedure2Vtbl;
45     const IActiveScriptPropertyVtbl         *lpIActiveScriptPropertyVtbl;
46     const IObjectSafetyVtbl                 *lpIObjectSafetyVtbl;
47
48     LONG ref;
49
50     DWORD safeopt;
51     script_ctx_t *ctx;
52     LONG thread_id;
53     LCID lcid;
54
55     IActiveScriptSite *site;
56
57     parser_ctx_t *queue_head;
58     parser_ctx_t *queue_tail;
59 } JScript;
60
61 #define ACTSCRIPT(x)    ((IActiveScript*) &(x)->lpIActiveScriptVtbl)
62 #define ASPARSE(x)      (&(x)->lpIActiveScriptParseVtbl)
63 #define ASPARSEPROC(x)  (&(x)->lpIActiveScriptParseProcedure2Vtbl)
64 #define ACTSCPPROP(x)   (&(x)->lpIActiveScriptPropertyVtbl)
65 #define OBJSAFETY(x)    (&(x)->lpIObjectSafetyVtbl)
66
67 void script_release(script_ctx_t *ctx)
68 {
69     if(--ctx->ref)
70         return;
71
72     jsheap_free(&ctx->tmp_heap);
73     heap_free(ctx);
74 }
75
76 static void change_state(JScript *This, SCRIPTSTATE state)
77 {
78     if(This->ctx->state == state)
79         return;
80
81     This->ctx->state = state;
82     IActiveScriptSite_OnStateChange(This->site, state);
83 }
84
85 static inline BOOL is_started(script_ctx_t *ctx)
86 {
87     return ctx->state == SCRIPTSTATE_STARTED
88         || ctx->state == SCRIPTSTATE_CONNECTED
89         || ctx->state == SCRIPTSTATE_DISCONNECTED;
90 }
91
92 static HRESULT exec_global_code(JScript *This, parser_ctx_t *parser_ctx)
93 {
94     exec_ctx_t *exec_ctx;
95     jsexcept_t jsexcept;
96     VARIANT var;
97     HRESULT hres;
98
99     hres = create_exec_ctx((IDispatch*)_IDispatchEx_(This->ctx->script_disp), This->ctx->script_disp, NULL, &exec_ctx);
100     if(FAILED(hres))
101         return hres;
102
103     IActiveScriptSite_OnEnterScript(This->site);
104
105     memset(&jsexcept, 0, sizeof(jsexcept));
106     hres = exec_source(exec_ctx, parser_ctx, parser_ctx->source, &jsexcept, &var);
107     VariantClear(&jsexcept.var);
108     exec_release(exec_ctx);
109     if(SUCCEEDED(hres))
110         VariantClear(&var);
111
112     IActiveScriptSite_OnLeaveScript(This->site);
113
114     return hres;
115 }
116
117 static void clear_script_queue(JScript *This)
118 {
119     parser_ctx_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         parser_release(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     parser_ctx_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     if(!This->ctx->script_disp) {
152         hres = create_dispex(This->ctx, NULL, NULL, &This->ctx->script_disp);
153         if(FAILED(hres))
154             return hres;
155     }
156
157     hres = init_global(This->ctx);
158     if(FAILED(hres))
159         return hres;
160
161     IActiveScriptSite_AddRef(This->site);
162     This->ctx->site = This->site;
163
164     change_state(This, SCRIPTSTATE_INITIALIZED);
165     return S_OK;
166 }
167
168 #define ACTSCRIPT_THIS(iface) DEFINE_THIS(JScript, IActiveScript, iface)
169
170 static HRESULT WINAPI JScript_QueryInterface(IActiveScript *iface, REFIID riid, void **ppv)
171 {
172     JScript *This = ACTSCRIPT_THIS(iface);
173
174     *ppv = NULL;
175
176     if(IsEqualGUID(riid, &IID_IUnknown)) {
177         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
178         *ppv = ACTSCRIPT(This);
179     }else if(IsEqualGUID(riid, &IID_IActiveScript)) {
180         TRACE("(%p)->(IID_IActiveScript %p)\n", This, ppv);
181         *ppv = ACTSCRIPT(This);
182     }else if(IsEqualGUID(riid, &IID_IActiveScriptParse)) {
183         TRACE("(%p)->(IID_IActiveScriptParse %p)\n", This, ppv);
184         *ppv = ASPARSE(This);
185     }else if(IsEqualGUID(riid, &IID_IActiveScriptParseProcedure)) {
186         TRACE("(%p)->(IID_IActiveScriptParseProcedure %p)\n", This, ppv);
187         *ppv = ASPARSEPROC(This);
188     }else if(IsEqualGUID(riid, &IID_IActiveScriptParseProcedure2)) {
189         TRACE("(%p)->(IID_IActiveScriptParseProcedure2 %p)\n", This, ppv);
190         *ppv = ASPARSEPROC(This);
191     }else if(IsEqualGUID(riid, &IID_IActiveScriptProperty)) {
192         TRACE("(%p)->(IID_IActiveScriptProperty %p)\n", This, ppv);
193         *ppv = ACTSCPPROP(This);
194     }else if(IsEqualGUID(riid, &IID_IObjectSafety)) {
195         TRACE("(%p)->(IID_IObjectSafety %p)\n", This, ppv);
196         *ppv = OBJSAFETY(This);
197     }
198
199     if(*ppv) {
200         IUnknown_AddRef((IUnknown*)*ppv);
201         return S_OK;
202     }
203
204     FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
205     return E_NOINTERFACE;
206 }
207
208 static ULONG WINAPI JScript_AddRef(IActiveScript *iface)
209 {
210     JScript *This = ACTSCRIPT_THIS(iface);
211     LONG ref = InterlockedIncrement(&This->ref);
212
213     TRACE("(%p) ref=%d\n", This, ref);
214
215     return ref;
216 }
217
218 static ULONG WINAPI JScript_Release(IActiveScript *iface)
219 {
220     JScript *This = ACTSCRIPT_THIS(iface);
221     LONG ref = InterlockedDecrement(&This->ref);
222
223     TRACE("(%p) ref=%d\n", iface, ref);
224
225     if(!ref) {
226         if(This->ctx && This->ctx->state != SCRIPTSTATE_CLOSED)
227             IActiveScript_Close(ACTSCRIPT(This));
228         if(This->ctx)
229             script_release(This->ctx);
230         heap_free(This);
231         unlock_module();
232     }
233
234     return ref;
235 }
236
237 static HRESULT WINAPI JScript_SetScriptSite(IActiveScript *iface,
238                                             IActiveScriptSite *pass)
239 {
240     JScript *This = ACTSCRIPT_THIS(iface);
241     LCID lcid;
242     HRESULT hres;
243
244     TRACE("(%p)->(%p)\n", This, pass);
245
246     if(!pass)
247         return E_POINTER;
248
249     if(This->site)
250         return E_UNEXPECTED;
251
252     if(InterlockedCompareExchange(&This->thread_id, GetCurrentThreadId(), 0))
253         return E_UNEXPECTED;
254
255     This->site = pass;
256     IActiveScriptSite_AddRef(This->site);
257
258     hres = IActiveScriptSite_GetLCID(This->site, &lcid);
259     if(hres == S_OK)
260         This->lcid = lcid;
261
262     return This->ctx ? set_ctx_site(This) : S_OK;
263 }
264
265 static HRESULT WINAPI JScript_GetScriptSite(IActiveScript *iface, REFIID riid,
266                                             void **ppvObject)
267 {
268     JScript *This = ACTSCRIPT_THIS(iface);
269     FIXME("(%p)->()\n", This);
270     return E_NOTIMPL;
271 }
272
273 static HRESULT WINAPI JScript_SetScriptState(IActiveScript *iface, SCRIPTSTATE ss)
274 {
275     JScript *This = ACTSCRIPT_THIS(iface);
276
277     TRACE("(%p)->(%d)\n", This, ss);
278
279     if(!This->ctx || GetCurrentThreadId() != This->thread_id)
280         return E_UNEXPECTED;
281
282     switch(ss) {
283     case SCRIPTSTATE_STARTED:
284     case SCRIPTSTATE_CONNECTED: /* FIXME */
285         if(This->ctx->state == SCRIPTSTATE_CLOSED)
286             return E_UNEXPECTED;
287
288         exec_queued_code(This);
289         break;
290     default:
291         FIXME("unimplemented state %d\n", ss);
292         return E_NOTIMPL;
293     }
294
295     change_state(This, ss);
296     return S_OK;
297 }
298
299 static HRESULT WINAPI JScript_GetScriptState(IActiveScript *iface, SCRIPTSTATE *pssState)
300 {
301     JScript *This = ACTSCRIPT_THIS(iface);
302
303     TRACE("(%p)->(%p)\n", This, pssState);
304
305     if(!pssState)
306         return E_POINTER;
307
308     if(!This->thread_id) {
309         *pssState = SCRIPTSTATE_UNINITIALIZED;
310         return S_OK;
311     }
312
313     if(This->thread_id != GetCurrentThreadId())
314         return E_UNEXPECTED;
315
316     *pssState = This->ctx ? This->ctx->state : SCRIPTSTATE_UNINITIALIZED;
317     return S_OK;
318 }
319
320 static HRESULT WINAPI JScript_Close(IActiveScript *iface)
321 {
322     JScript *This = ACTSCRIPT_THIS(iface);
323
324     TRACE("(%p)->()\n", This);
325
326     if(This->thread_id != GetCurrentThreadId())
327         return E_UNEXPECTED;
328
329     if(This->ctx) {
330         if(This->ctx->state == SCRIPTSTATE_CONNECTED)
331             change_state(This, SCRIPTSTATE_DISCONNECTED);
332
333         clear_script_queue(This);
334
335         if(This->ctx->state == SCRIPTSTATE_DISCONNECTED)
336             change_state(This, SCRIPTSTATE_INITIALIZED);
337
338         if(This->ctx->named_items) {
339             named_item_t *iter, *iter2;
340
341             iter = This->ctx->named_items;
342             while(iter) {
343                 iter2 = iter->next;
344
345                 if(iter->disp)
346                     IDispatch_Release(iter->disp);
347                 heap_free(iter->name);
348                 heap_free(iter);
349                 iter = iter2;
350             }
351
352             This->ctx->named_items = NULL;
353         }
354
355         if(This->ctx->site) {
356             IActiveScriptSite_Release(This->ctx->site);
357             This->ctx->site = NULL;
358         }
359
360         if (This->site)
361             change_state(This, SCRIPTSTATE_CLOSED);
362
363         if(This->ctx->script_disp) {
364             IDispatchEx_Release(_IDispatchEx_(This->ctx->script_disp));
365             This->ctx->script_disp = NULL;
366         }
367
368         if(This->ctx->global) {
369             IDispatchEx_Release(_IDispatchEx_(This->ctx->global));
370             This->ctx->global = NULL;
371         }
372     }
373
374     if(This->site) {
375         IActiveScriptSite_Release(This->site);
376         This->site = NULL;
377     }
378
379     return S_OK;
380 }
381
382 static HRESULT WINAPI JScript_AddNamedItem(IActiveScript *iface,
383                                            LPCOLESTR pstrName, DWORD dwFlags)
384 {
385     JScript *This = ACTSCRIPT_THIS(iface);
386     named_item_t *item;
387     IDispatch *disp = NULL;
388     HRESULT hres;
389
390     TRACE("(%p)->(%s %x)\n", This, debugstr_w(pstrName), dwFlags);
391
392     if(This->thread_id != GetCurrentThreadId() || !This->ctx || This->ctx->state == SCRIPTSTATE_CLOSED)
393         return E_UNEXPECTED;
394
395     if(dwFlags & SCRIPTITEM_GLOBALMEMBERS) {
396         IUnknown *unk;
397
398         hres = IActiveScriptSite_GetItemInfo(This->site, pstrName, SCRIPTINFO_IUNKNOWN, &unk, NULL);
399         if(FAILED(hres)) {
400             WARN("GetItemInfo failed: %08x\n", hres);
401             return hres;
402         }
403
404         hres = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&disp);
405         IUnknown_Release(unk);
406         if(FAILED(hres)) {
407             WARN("object does not implement IDispatch\n");
408             return hres;
409         }
410     }
411
412     item = heap_alloc(sizeof(*item));
413     if(!item) {
414         if(disp)
415             IDispatch_Release(disp);
416         return E_OUTOFMEMORY;
417     }
418
419     item->disp = disp;
420     item->flags = dwFlags;
421     item->name = heap_strdupW(pstrName);
422     if(!item->name) {
423         IDispatch_Release(disp);
424         heap_free(item);
425         return E_OUTOFMEMORY;
426     }
427
428     item->next = This->ctx->named_items;
429     This->ctx->named_items = item;
430
431     return S_OK;
432 }
433
434 static HRESULT WINAPI JScript_AddTypeLib(IActiveScript *iface, REFGUID rguidTypeLib,
435                                          DWORD dwMajor, DWORD dwMinor, DWORD dwFlags)
436 {
437     JScript *This = ACTSCRIPT_THIS(iface);
438     FIXME("(%p)->()\n", This);
439     return E_NOTIMPL;
440 }
441
442 static HRESULT WINAPI JScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR pstrItemName,
443                                                 IDispatch **ppdisp)
444 {
445     JScript *This = ACTSCRIPT_THIS(iface);
446
447     TRACE("(%p)->(%p)\n", This, ppdisp);
448
449     if(!ppdisp)
450         return E_POINTER;
451
452     if(This->thread_id != GetCurrentThreadId() || !This->ctx->script_disp) {
453         *ppdisp = NULL;
454         return E_UNEXPECTED;
455     }
456
457     *ppdisp = (IDispatch*)_IDispatchEx_(This->ctx->script_disp);
458     IDispatch_AddRef(*ppdisp);
459     return S_OK;
460 }
461
462 static HRESULT WINAPI JScript_GetCurrentScriptThreadID(IActiveScript *iface,
463                                                        SCRIPTTHREADID *pstridThread)
464 {
465     JScript *This = ACTSCRIPT_THIS(iface);
466     FIXME("(%p)->()\n", This);
467     return E_NOTIMPL;
468 }
469
470 static HRESULT WINAPI JScript_GetScriptThreadID(IActiveScript *iface,
471                                                 DWORD dwWin32ThreadId, SCRIPTTHREADID *pstidThread)
472 {
473     JScript *This = ACTSCRIPT_THIS(iface);
474     FIXME("(%p)->()\n", This);
475     return E_NOTIMPL;
476 }
477
478 static HRESULT WINAPI JScript_GetScriptThreadState(IActiveScript *iface,
479         SCRIPTTHREADID stidThread, SCRIPTTHREADSTATE *pstsState)
480 {
481     JScript *This = ACTSCRIPT_THIS(iface);
482     FIXME("(%p)->()\n", This);
483     return E_NOTIMPL;
484 }
485
486 static HRESULT WINAPI JScript_InterruptScriptThread(IActiveScript *iface,
487         SCRIPTTHREADID stidThread, const EXCEPINFO *pexcepinfo, DWORD dwFlags)
488 {
489     JScript *This = ACTSCRIPT_THIS(iface);
490     FIXME("(%p)->()\n", This);
491     return E_NOTIMPL;
492 }
493
494 static HRESULT WINAPI JScript_Clone(IActiveScript *iface, IActiveScript **ppscript)
495 {
496     JScript *This = ACTSCRIPT_THIS(iface);
497     FIXME("(%p)->()\n", This);
498     return E_NOTIMPL;
499 }
500
501 #undef ACTSCRIPT_THIS
502
503 static const IActiveScriptVtbl JScriptVtbl = {
504     JScript_QueryInterface,
505     JScript_AddRef,
506     JScript_Release,
507     JScript_SetScriptSite,
508     JScript_GetScriptSite,
509     JScript_SetScriptState,
510     JScript_GetScriptState,
511     JScript_Close,
512     JScript_AddNamedItem,
513     JScript_AddTypeLib,
514     JScript_GetScriptDispatch,
515     JScript_GetCurrentScriptThreadID,
516     JScript_GetScriptThreadID,
517     JScript_GetScriptThreadState,
518     JScript_InterruptScriptThread,
519     JScript_Clone
520 };
521
522 #define ASPARSE_THIS(iface) DEFINE_THIS(JScript, IActiveScriptParse, iface)
523
524 static HRESULT WINAPI JScriptParse_QueryInterface(IActiveScriptParse *iface, REFIID riid, void **ppv)
525 {
526     JScript *This = ASPARSE_THIS(iface);
527     return IActiveScript_QueryInterface(ACTSCRIPT(This), riid, ppv);
528 }
529
530 static ULONG WINAPI JScriptParse_AddRef(IActiveScriptParse *iface)
531 {
532     JScript *This = ASPARSE_THIS(iface);
533     return IActiveScript_AddRef(ACTSCRIPT(This));
534 }
535
536 static ULONG WINAPI JScriptParse_Release(IActiveScriptParse *iface)
537 {
538     JScript *This = ASPARSE_THIS(iface);
539     return IActiveScript_Release(ACTSCRIPT(This));
540 }
541
542 static HRESULT WINAPI JScriptParse_InitNew(IActiveScriptParse *iface)
543 {
544     JScript *This = ASPARSE_THIS(iface);
545     script_ctx_t *ctx;
546
547     TRACE("(%p)\n", This);
548
549     if(This->ctx)
550         return E_UNEXPECTED;
551
552     ctx = heap_alloc_zero(sizeof(script_ctx_t));
553     if(!ctx)
554         return E_OUTOFMEMORY;
555
556     ctx->ref = 1;
557     ctx->state = SCRIPTSTATE_UNINITIALIZED;
558     jsheap_init(&ctx->tmp_heap);
559
560     ctx = InterlockedCompareExchangePointer((void**)&This->ctx, ctx, NULL);
561     if(ctx) {
562         script_release(ctx);
563         return E_UNEXPECTED;
564     }
565
566     return This->site ? set_ctx_site(This) : S_OK;
567 }
568
569 static HRESULT WINAPI JScriptParse_AddScriptlet(IActiveScriptParse *iface,
570         LPCOLESTR pstrDefaultName, LPCOLESTR pstrCode, LPCOLESTR pstrItemName,
571         LPCOLESTR pstrSubItemName, LPCOLESTR pstrEventName, LPCOLESTR pstrDelimiter,
572         CTXARG_T dwSourceContextCookie, ULONG ulStartingLineNumber, DWORD dwFlags,
573         BSTR *pbstrName, EXCEPINFO *pexcepinfo)
574 {
575     JScript *This = ASPARSE_THIS(iface);
576     FIXME("(%p)->(%s %s %s %s %s %s %s %u %x %p %p)\n", This, debugstr_w(pstrDefaultName),
577           debugstr_w(pstrCode), debugstr_w(pstrItemName), debugstr_w(pstrSubItemName),
578           debugstr_w(pstrEventName), debugstr_w(pstrDelimiter), wine_dbgstr_longlong(dwSourceContextCookie),
579           ulStartingLineNumber, dwFlags, pbstrName, pexcepinfo);
580     return E_NOTIMPL;
581 }
582
583 static HRESULT WINAPI JScriptParse_ParseScriptText(IActiveScriptParse *iface,
584         LPCOLESTR pstrCode, LPCOLESTR pstrItemName, IUnknown *punkContext,
585         LPCOLESTR pstrDelimiter, CTXARG_T dwSourceContextCookie, ULONG ulStartingLine,
586         DWORD dwFlags, VARIANT *pvarResult, EXCEPINFO *pexcepinfo)
587 {
588     JScript *This = ASPARSE_THIS(iface);
589     parser_ctx_t *parser_ctx;
590     HRESULT hres;
591
592     TRACE("(%p)->(%s %s %p %s %s %u %x %p %p)\n", This, debugstr_w(pstrCode),
593           debugstr_w(pstrItemName), punkContext, debugstr_w(pstrDelimiter),
594           wine_dbgstr_longlong(dwSourceContextCookie), ulStartingLine, dwFlags, pvarResult, pexcepinfo);
595
596     if(This->thread_id != GetCurrentThreadId() || This->ctx->state == SCRIPTSTATE_CLOSED)
597         return E_UNEXPECTED;
598
599     hres = script_parse(This->ctx, pstrCode, pstrDelimiter, &parser_ctx);
600     if(FAILED(hres))
601         return hres;
602
603     if(!is_started(This->ctx)) {
604         if(This->queue_tail)
605             This->queue_tail = This->queue_tail->next = parser_ctx;
606         else
607             This->queue_head = This->queue_tail = parser_ctx;
608         return S_OK;
609     }
610
611     hres = exec_global_code(This, parser_ctx);
612     parser_release(parser_ctx);
613
614     return hres;
615 }
616
617 #undef ASPARSE_THIS
618
619 static const IActiveScriptParseVtbl JScriptParseVtbl = {
620     JScriptParse_QueryInterface,
621     JScriptParse_AddRef,
622     JScriptParse_Release,
623     JScriptParse_InitNew,
624     JScriptParse_AddScriptlet,
625     JScriptParse_ParseScriptText
626 };
627
628 #define ASPARSEPROC_THIS(iface) DEFINE_THIS(JScript, IActiveScriptParseProcedure2, iface)
629
630 static HRESULT WINAPI JScriptParseProcedure_QueryInterface(IActiveScriptParseProcedure2 *iface, REFIID riid, void **ppv)
631 {
632     JScript *This = ASPARSEPROC_THIS(iface);
633     return IActiveScript_QueryInterface(ACTSCRIPT(This), riid, ppv);
634 }
635
636 static ULONG WINAPI JScriptParseProcedure_AddRef(IActiveScriptParseProcedure2 *iface)
637 {
638     JScript *This = ASPARSEPROC_THIS(iface);
639     return IActiveScript_AddRef(ACTSCRIPT(This));
640 }
641
642 static ULONG WINAPI JScriptParseProcedure_Release(IActiveScriptParseProcedure2 *iface)
643 {
644     JScript *This = ASPARSEPROC_THIS(iface);
645     return IActiveScript_Release(ACTSCRIPT(This));
646 }
647
648 static HRESULT WINAPI JScriptParseProcedure_ParseProcedureText(IActiveScriptParseProcedure2 *iface,
649         LPCOLESTR pstrCode, LPCOLESTR pstrFormalParams, LPCOLESTR pstrProcedureName,
650         LPCOLESTR pstrItemName, IUnknown *punkContext, LPCOLESTR pstrDelimiter,
651         CTXARG_T dwSourceContextCookie, ULONG ulStartingLineNumber, DWORD dwFlags, IDispatch **ppdisp)
652 {
653     JScript *This = ASPARSEPROC_THIS(iface);
654     parser_ctx_t *parser_ctx;
655     DispatchEx *dispex;
656     HRESULT hres;
657
658     TRACE("(%p)->(%s %s %s %s %p %s %s %u %x %p)\n", This, debugstr_w(pstrCode), debugstr_w(pstrFormalParams),
659           debugstr_w(pstrProcedureName), debugstr_w(pstrItemName), punkContext, debugstr_w(pstrDelimiter),
660           wine_dbgstr_longlong(dwSourceContextCookie), ulStartingLineNumber, dwFlags, ppdisp);
661
662     if(This->thread_id != GetCurrentThreadId() || This->ctx->state == SCRIPTSTATE_CLOSED)
663         return E_UNEXPECTED;
664
665     hres = script_parse(This->ctx, pstrCode, pstrDelimiter, &parser_ctx);
666     if(FAILED(hres)) {
667         WARN("Parse failed %08x\n", hres);
668         return hres;
669     }
670
671     hres = create_source_function(parser_ctx, NULL, parser_ctx->source, NULL, NULL, 0, &dispex);
672     parser_release(parser_ctx);
673     if(FAILED(hres))
674         return hres;
675
676     *ppdisp = (IDispatch*)_IDispatchEx_(dispex);
677     return S_OK;
678 }
679
680 #undef ASPARSEPROC_THIS
681
682 static const IActiveScriptParseProcedure2Vtbl JScriptParseProcedureVtbl = {
683     JScriptParseProcedure_QueryInterface,
684     JScriptParseProcedure_AddRef,
685     JScriptParseProcedure_Release,
686     JScriptParseProcedure_ParseProcedureText,
687 };
688
689 #define ACTSCPPROP_THIS(iface) DEFINE_THIS(JScript, IActiveScriptProperty, iface)
690
691 static HRESULT WINAPI JScriptProperty_QueryInterface(IActiveScriptProperty *iface, REFIID riid, void **ppv)
692 {
693     JScript *This = ACTSCPPROP_THIS(iface);
694     return IActiveScript_QueryInterface(ACTSCRIPT(This), riid, ppv);
695 }
696
697 static ULONG WINAPI JScriptProperty_AddRef(IActiveScriptProperty *iface)
698 {
699     JScript *This = ACTSCPPROP_THIS(iface);
700     return IActiveScript_AddRef(ACTSCRIPT(This));
701 }
702
703 static ULONG WINAPI JScriptProperty_Release(IActiveScriptProperty *iface)
704 {
705     JScript *This = ACTSCPPROP_THIS(iface);
706     return IActiveScript_Release(ACTSCRIPT(This));
707 }
708
709 static HRESULT WINAPI JScriptProperty_GetProperty(IActiveScriptProperty *iface, DWORD dwProperty,
710         VARIANT *pvarIndex, VARIANT *pvarValue)
711 {
712     JScript *This = ACTSCPPROP_THIS(iface);
713     FIXME("(%p)->(%x %p %p)\n", This, dwProperty, pvarIndex, pvarValue);
714     return E_NOTIMPL;
715 }
716
717 static HRESULT WINAPI JScriptProperty_SetProperty(IActiveScriptProperty *iface, DWORD dwProperty,
718         VARIANT *pvarIndex, VARIANT *pvarValue)
719 {
720     JScript *This = ACTSCPPROP_THIS(iface);
721     FIXME("(%p)->(%x %p %p)\n", This, dwProperty, pvarIndex, pvarValue);
722     return E_NOTIMPL;
723 }
724
725 #undef ACTSCPPROP_THIS
726
727 static const IActiveScriptPropertyVtbl JScriptPropertyVtbl = {
728     JScriptProperty_QueryInterface,
729     JScriptProperty_AddRef,
730     JScriptProperty_Release,
731     JScriptProperty_GetProperty,
732     JScriptProperty_SetProperty
733 };
734
735 #define OBJSAFETY_THIS(iface) DEFINE_THIS(JScript, IObjectSafety, iface)
736
737 static HRESULT WINAPI JScriptSafety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
738 {
739     JScript *This = OBJSAFETY_THIS(iface);
740     return IActiveScript_QueryInterface(ACTSCRIPT(This), riid, ppv);
741 }
742
743 static ULONG WINAPI JScriptSafety_AddRef(IObjectSafety *iface)
744 {
745     JScript *This = OBJSAFETY_THIS(iface);
746     return IActiveScript_AddRef(ACTSCRIPT(This));
747 }
748
749 static ULONG WINAPI JScriptSafety_Release(IObjectSafety *iface)
750 {
751     JScript *This = OBJSAFETY_THIS(iface);
752     return IActiveScript_Release(ACTSCRIPT(This));
753 }
754
755 #define SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER)
756
757 static HRESULT WINAPI JScriptSafety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
758         DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions)
759 {
760     JScript *This = OBJSAFETY_THIS(iface);
761
762     TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), pdwSupportedOptions, pdwEnabledOptions);
763
764     if(!pdwSupportedOptions || !pdwEnabledOptions)
765         return E_POINTER;
766
767     *pdwSupportedOptions = SUPPORTED_OPTIONS;
768     *pdwEnabledOptions = This->safeopt;
769
770     return S_OK;
771 }
772
773 static HRESULT WINAPI JScriptSafety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
774         DWORD dwOptionSetMask, DWORD dwEnabledOptions)
775 {
776     JScript *This = OBJSAFETY_THIS(iface);
777
778     TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), dwOptionSetMask, dwEnabledOptions);
779
780     if(dwOptionSetMask & ~SUPPORTED_OPTIONS)
781         return E_FAIL;
782
783     This->safeopt = dwEnabledOptions & dwEnabledOptions;
784     return S_OK;
785 }
786
787 #undef OBJSAFETY_THIS
788
789 static const IObjectSafetyVtbl JScriptSafetyVtbl = {
790     JScriptSafety_QueryInterface,
791     JScriptSafety_AddRef,
792     JScriptSafety_Release,
793     JScriptSafety_GetInterfaceSafetyOptions,
794     JScriptSafety_SetInterfaceSafetyOptions
795 };
796
797 HRESULT WINAPI JScriptFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter,
798                                              REFIID riid, void **ppv)
799 {
800     JScript *ret;
801     HRESULT hres;
802
803     TRACE("(%p %s %p)\n", pUnkOuter, debugstr_guid(riid), ppv);
804
805     lock_module();
806
807     ret = heap_alloc_zero(sizeof(*ret));
808     if(!ret)
809         return E_OUTOFMEMORY;
810
811     ret->lpIActiveScriptVtbl                 = &JScriptVtbl;
812     ret->lpIActiveScriptParseVtbl            = &JScriptParseVtbl;
813     ret->lpIActiveScriptParseProcedure2Vtbl  = &JScriptParseProcedureVtbl;
814     ret->lpIActiveScriptPropertyVtbl         = &JScriptPropertyVtbl;
815     ret->lpIObjectSafetyVtbl                 = &JScriptSafetyVtbl;
816     ret->ref = 1;
817     ret->safeopt = INTERFACE_USES_DISPEX;
818
819     hres = IActiveScript_QueryInterface(ACTSCRIPT(ret), riid, ppv);
820     IActiveScript_Release(ACTSCRIPT(ret));
821     return hres;
822 }