mshtml: Added parsing external scripts support.
[wine] / dlls / mshtml / script.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 "config.h"
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "ole2.h"
29 #include "activscp.h"
30 #include "objsafe.h"
31
32 #include "wine/debug.h"
33
34 #include "mshtml_private.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
37
38 static const WCHAR windowW[] = {'w','i','n','d','o','w',0};
39
40 static const CLSID CLSID_JScript =
41     {0xf414c260,0x6ac0,0x11cf,{0xb6,0xd1,0x00,0xaa,0x00,0xbb,0xbb,0x58}};
42
43 typedef struct {
44     const IActiveScriptSiteVtbl               *lpIActiveScriptSiteVtbl;
45     const IActiveScriptSiteInterruptPollVtbl  *lpIActiveScriptSiteInterruptPollVtbl;
46     const IActiveScriptSiteWindowVtbl         *lpIActiveScriptSiteWindowVtbl;
47
48     LONG ref;
49
50     IActiveScript *script;
51     IActiveScriptParse *parse;
52
53     SCRIPTSTATE script_state;
54
55     HTMLDocument *doc;
56
57     GUID guid;
58     struct list entry;
59 } ScriptHost;
60
61 #define ACTSCPSITE(x)  ((IActiveScriptSite*)               &(x)->lpIActiveScriptSiteVtbl)
62 #define ACTSCPPOLL(x)  ((IActiveScriptSiteInterruptPoll*)  &(x)->lpIActiveScriptSiteInterruptPollVtbl)
63 #define ACTSCPWIN(x)   ((IActiveScriptSiteWindow*)         &(x)->lpIActiveScriptSiteWindowVtbl)
64
65 static BOOL init_script_engine(ScriptHost *script_host)
66 {
67     IActiveScriptProperty *property;
68     IObjectSafety *safety;
69     SCRIPTSTATE state;
70     DWORD supported_opts=0, enabled_opts=0;
71     HRESULT hres;
72
73     hres = IActiveScript_QueryInterface(script_host->script, &IID_IActiveScriptParse, (void**)&script_host->parse);
74     if(FAILED(hres)) {
75         WARN("Could not get IActiveScriptHost: %08x\n", hres);
76         return FALSE;
77     }
78
79     hres = IActiveScript_QueryInterface(script_host->script, &IID_IObjectSafety, (void**)&safety);
80     if(FAILED(hres)) {
81         FIXME("Could not get IObjectSafety: %08x\n", hres);
82         return FALSE;
83     }
84
85     hres = IObjectSafety_GetInterfaceSafetyOptions(safety, &IID_IActiveScriptParse, &supported_opts, &enabled_opts);
86     if(FAILED(hres)) {
87         FIXME("GetInterfaceSafetyOptions failed: %08x\n", hres);
88     }else if(!(supported_opts & INTERFACE_USES_DISPEX)) {
89         FIXME("INTERFACE_USES_DISPEX is not supported\n");
90     }else {
91         hres = IObjectSafety_SetInterfaceSafetyOptions(safety, &IID_IActiveScriptParse,
92                 INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER,
93                 INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER);
94         if(FAILED(hres))
95             FIXME("SetInterfaceSafetyOptions failed: %08x\n", hres);
96     }
97
98     IObjectSafety_Release(safety);
99     if(FAILED(hres))
100         return FALSE;
101
102     hres = IActiveScript_QueryInterface(script_host->script, &IID_IActiveScriptProperty, (void**)&property);
103     if(SUCCEEDED(hres)) {
104         VARIANT var;
105
106         V_VT(&var) = VT_BOOL;
107         V_BOOL(&var) = VARIANT_TRUE;
108         hres = IActiveScriptProperty_SetProperty(property, SCRIPTPROP_HACK_TRIDENTEVENTSINK, NULL, &var);
109         if(FAILED(hres))
110             WARN("SetProperty failed: %08x\n", hres);
111
112         IActiveScriptProperty_Release(property);
113     }else {
114         WARN("Could not get IActiveScriptProperty: %08x\n", hres);
115     }
116
117     hres = IActiveScriptParse_InitNew(script_host->parse);
118     if(FAILED(hres)) {
119         WARN("InitNew failed: %08x\n", hres);
120         return FALSE;
121     }
122
123     hres = IActiveScript_SetScriptSite(script_host->script, ACTSCPSITE(script_host));
124     if(FAILED(hres)) {
125         WARN("SetScriptSite failed: %08x\n", hres);
126         IActiveScript_Close(script_host->script);
127         return FALSE;
128     }
129
130     hres = IActiveScript_GetScriptState(script_host->script, &state);
131     if(FAILED(hres))
132         WARN("GetScriptState failed: %08x\n", hres);
133     else if(state != SCRIPTSTATE_INITIALIZED)
134         FIXME("state = %x\n", state);
135
136     hres = IActiveScript_SetScriptState(script_host->script, SCRIPTSTATE_STARTED);
137     if(FAILED(hres)) {
138         WARN("Starting script failed: %08x\n", hres);
139         return FALSE;
140     }
141
142     hres = IActiveScript_AddNamedItem(script_host->script, windowW,
143             SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|SCRIPTITEM_GLOBALMEMBERS);
144     if(FAILED(hres))
145        WARN("AddNamedItem failed: %08x\n", hres);
146
147     /* FIXME: QI for IActiveScriptParseProcedure2 and IActiveScriptParseProcedure */
148
149     return TRUE;
150 }
151
152 static void release_script_engine(ScriptHost *This)
153 {
154     if(!This->script)
155         return;
156
157     switch(This->script_state) {
158     case SCRIPTSTATE_CONNECTED:
159         IActiveScript_SetScriptState(This->script, SCRIPTSTATE_DISCONNECTED);
160
161     case SCRIPTSTATE_STARTED:
162     case SCRIPTSTATE_DISCONNECTED:
163     case SCRIPTSTATE_INITIALIZED:
164         IActiveScript_Close(This->script);
165
166     default:
167         if(This->parse) {
168             IActiveScriptParse_Release(This->parse);
169             This->parse = NULL;
170         }
171     }
172
173     IActiveScript_Release(This->script);
174     This->script = NULL;
175     This->script_state = SCRIPTSTATE_UNINITIALIZED;
176 }
177
178 void connect_scripts(HTMLDocument *doc)
179 {
180     ScriptHost *iter;
181
182     LIST_FOR_EACH_ENTRY(iter, &doc->script_hosts, ScriptHost, entry) {
183         if(iter->script_state == SCRIPTSTATE_STARTED)
184             IActiveScript_SetScriptState(iter->script, SCRIPTSTATE_CONNECTED);
185     }
186 }
187
188 #define ACTSCPSITE_THIS(iface) DEFINE_THIS(ScriptHost, IActiveScriptSite, iface)
189
190 static HRESULT WINAPI ActiveScriptSite_QueryInterface(IActiveScriptSite *iface, REFIID riid, void **ppv)
191 {
192     ScriptHost *This = ACTSCPSITE_THIS(iface);
193
194     *ppv = NULL;
195
196     if(IsEqualGUID(&IID_IUnknown, riid)) {
197         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
198         *ppv = ACTSCPSITE(This);
199     }else if(IsEqualGUID(&IID_IActiveScriptSite, riid)) {
200         TRACE("(%p)->(IID_IActiveScriptSite %p)\n", This, ppv);
201         *ppv = ACTSCPSITE(This);
202     }else if(IsEqualGUID(&IID_IActiveScriptSiteInterruptPoll, riid)) {
203         TRACE("(%p)->(IID_IActiveScriptSiteInterruprtPoll %p)\n", This, ppv);
204         *ppv = ACTSCPPOLL(This);
205     }else if(IsEqualGUID(&IID_IActiveScriptSiteWindow, riid)) {
206         TRACE("(%p)->(IID_IActiveScriptSiteWindow %p)\n", This, ppv);
207         *ppv = ACTSCPWIN(This);
208     }else {
209         FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
210         return E_NOINTERFACE;
211     }
212
213     IUnknown_AddRef((IUnknown*)*ppv);
214     return S_OK;
215 }
216
217 static ULONG WINAPI ActiveScriptSite_AddRef(IActiveScriptSite *iface)
218 {
219     ScriptHost *This = ACTSCPSITE_THIS(iface);
220     LONG ref = InterlockedIncrement(&This->ref);
221
222     TRACE("(%p) ref=%d\n", This, ref);
223
224     return ref;
225 }
226
227 static ULONG WINAPI ActiveScriptSite_Release(IActiveScriptSite *iface)
228 {
229     ScriptHost *This = ACTSCPSITE_THIS(iface);
230     LONG ref = InterlockedDecrement(&This->ref);
231
232     TRACE("(%p) ref=%d\n", This, ref);
233
234     if(!ref) {
235         release_script_engine(This);
236         if(This->doc)
237             list_remove(&This->entry);
238         heap_free(This);
239     }
240
241     return ref;
242 }
243
244 static HRESULT WINAPI ActiveScriptSite_GetLCID(IActiveScriptSite *iface, LCID *plcid)
245 {
246     ScriptHost *This = ACTSCPSITE_THIS(iface);
247
248     TRACE("(%p)->(%p)\n", This, plcid);
249
250     *plcid = GetUserDefaultLCID();
251     return S_OK;
252 }
253
254 static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface, LPCOLESTR pstrName,
255         DWORD dwReturnMask, IUnknown **ppiunkItem, ITypeInfo **ppti)
256 {
257     ScriptHost *This = ACTSCPSITE_THIS(iface);
258
259     TRACE("(%p)->(%s %x %p %p)\n", This, debugstr_w(pstrName), dwReturnMask, ppiunkItem, ppti);
260
261     if(dwReturnMask != SCRIPTINFO_IUNKNOWN) {
262         FIXME("Unsupported mask %x\n", dwReturnMask);
263         return E_NOTIMPL;
264     }
265
266     *ppiunkItem = NULL;
267
268     if(strcmpW(pstrName, windowW))
269         return DISP_E_MEMBERNOTFOUND;
270
271     if(!This->doc)
272         return E_FAIL;
273
274     /* FIXME: Return proxy object */
275     *ppiunkItem = (IUnknown*)HTMLWINDOW2(This->doc->window);
276     IUnknown_AddRef(*ppiunkItem);
277
278     return S_OK;
279 }
280
281 static HRESULT WINAPI ActiveScriptSite_GetDocVersionString(IActiveScriptSite *iface, BSTR *pbstrVersion)
282 {
283     ScriptHost *This = ACTSCPSITE_THIS(iface);
284     FIXME("(%p)->(%p)\n", This, pbstrVersion);
285     return E_NOTIMPL;
286 }
287
288 static HRESULT WINAPI ActiveScriptSite_OnScriptTerminate(IActiveScriptSite *iface,
289         const VARIANT *pvarResult, const EXCEPINFO *pexcepinfo)
290 {
291     ScriptHost *This = ACTSCPSITE_THIS(iface);
292     FIXME("(%p)->(%p %p)\n", This, pvarResult, pexcepinfo);
293     return E_NOTIMPL;
294 }
295
296 static HRESULT WINAPI ActiveScriptSite_OnStateChange(IActiveScriptSite *iface, SCRIPTSTATE ssScriptState)
297 {
298     ScriptHost *This = ACTSCPSITE_THIS(iface);
299
300     TRACE("(%p)->(%x)\n", This, ssScriptState);
301
302     This->script_state = ssScriptState;
303     return S_OK;
304 }
305
306 static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, IActiveScriptError *pscripterror)
307 {
308     ScriptHost *This = ACTSCPSITE_THIS(iface);
309     FIXME("(%p)->(%p)\n", This, pscripterror);
310     return E_NOTIMPL;
311 }
312
313 static HRESULT WINAPI ActiveScriptSite_OnEnterScript(IActiveScriptSite *iface)
314 {
315     ScriptHost *This = ACTSCPSITE_THIS(iface);
316
317     TRACE("(%p)->()\n", This);
318
319     return S_OK;
320 }
321
322 static HRESULT WINAPI ActiveScriptSite_OnLeaveScript(IActiveScriptSite *iface)
323 {
324     ScriptHost *This = ACTSCPSITE_THIS(iface);
325
326     TRACE("(%p)->()\n", This);
327
328     return S_OK;
329 }
330
331 #undef ACTSCPSITE_THIS
332
333 static const IActiveScriptSiteVtbl ActiveScriptSiteVtbl = {
334     ActiveScriptSite_QueryInterface,
335     ActiveScriptSite_AddRef,
336     ActiveScriptSite_Release,
337     ActiveScriptSite_GetLCID,
338     ActiveScriptSite_GetItemInfo,
339     ActiveScriptSite_GetDocVersionString,
340     ActiveScriptSite_OnScriptTerminate,
341     ActiveScriptSite_OnStateChange,
342     ActiveScriptSite_OnScriptError,
343     ActiveScriptSite_OnEnterScript,
344     ActiveScriptSite_OnLeaveScript
345 };
346
347 #define ACTSCPPOLL_THIS(iface) DEFINE_THIS(ScriptHost, IActiveScriptSiteInterruptPoll, iface)
348
349 static HRESULT WINAPI ActiveScriptSiteInterruptPoll_QueryInterface(IActiveScriptSiteInterruptPoll *iface,
350         REFIID riid, void **ppv)
351 {
352     ScriptHost *This = ACTSCPPOLL_THIS(iface);
353     return IActiveScriptSite_QueryInterface(ACTSCPSITE(This), riid, ppv);
354 }
355
356 static ULONG WINAPI ActiveScriptSiteInterruptPoll_AddRef(IActiveScriptSiteInterruptPoll *iface)
357 {
358     ScriptHost *This = ACTSCPPOLL_THIS(iface);
359     return IActiveScriptSite_AddRef(ACTSCPSITE(This));
360 }
361
362 static ULONG WINAPI ActiveScriptSiteInterruptPoll_Release(IActiveScriptSiteInterruptPoll *iface)
363 {
364     ScriptHost *This = ACTSCPPOLL_THIS(iface);
365     return IActiveScriptSite_Release(ACTSCPSITE(This));
366 }
367
368 static HRESULT WINAPI ActiveScriptSiteInterruptPoll_QueryContinue(IActiveScriptSiteInterruptPoll *iface)
369 {
370     ScriptHost *This = ACTSCPPOLL_THIS(iface);
371     FIXME("(%p)\n", This);
372     return E_NOTIMPL;
373 }
374
375 #undef ACTSCPPOLL_THIS
376
377 static const IActiveScriptSiteInterruptPollVtbl ActiveScriptSiteInterruptPollVtbl = {
378     ActiveScriptSiteInterruptPoll_QueryInterface,
379     ActiveScriptSiteInterruptPoll_AddRef,
380     ActiveScriptSiteInterruptPoll_Release,
381     ActiveScriptSiteInterruptPoll_QueryContinue
382 };
383
384 #define ACTSCPWIN_THIS(iface) DEFINE_THIS(ScriptHost, IActiveScriptSiteWindow, iface)
385
386 static HRESULT WINAPI ActiveScriptSiteWindow_QueryInterface(IActiveScriptSiteWindow *iface,
387         REFIID riid, void **ppv)
388 {
389     ScriptHost *This = ACTSCPWIN_THIS(iface);
390     return IActiveScriptSite_QueryInterface(ACTSCPSITE(This), riid, ppv);
391 }
392
393 static ULONG WINAPI ActiveScriptSiteWindow_AddRef(IActiveScriptSiteWindow *iface)
394 {
395     ScriptHost *This = ACTSCPWIN_THIS(iface);
396     return IActiveScriptSite_AddRef(ACTSCPSITE(This));
397 }
398
399 static ULONG WINAPI ActiveScriptSiteWindow_Release(IActiveScriptSiteWindow *iface)
400 {
401     ScriptHost *This = ACTSCPWIN_THIS(iface);
402     return IActiveScriptSite_Release(ACTSCPSITE(This));
403 }
404
405 static HRESULT WINAPI ActiveScriptSiteWindow_GetWindow(IActiveScriptSiteWindow *iface, HWND *phwnd)
406 {
407     ScriptHost *This = ACTSCPWIN_THIS(iface);
408     FIXME("(%p)->(%p)\n", This, phwnd);
409     return E_NOTIMPL;
410 }
411
412 static HRESULT WINAPI ActiveScriptSiteWindow_EnableModeless(IActiveScriptSiteWindow *iface, BOOL fEnable)
413 {
414     ScriptHost *This = ACTSCPWIN_THIS(iface);
415     FIXME("(%p)->(%x)\n", This, fEnable);
416     return E_NOTIMPL;
417 }
418
419 #undef ACTSCPWIN_THIS
420
421 static const IActiveScriptSiteWindowVtbl ActiveScriptSiteWindowVtbl = {
422     ActiveScriptSiteWindow_QueryInterface,
423     ActiveScriptSiteWindow_AddRef,
424     ActiveScriptSiteWindow_Release,
425     ActiveScriptSiteWindow_GetWindow,
426     ActiveScriptSiteWindow_EnableModeless
427 };
428
429 static ScriptHost *create_script_host(HTMLDocument *doc, GUID *guid)
430 {
431     ScriptHost *ret;
432     HRESULT hres;
433
434     ret = heap_alloc_zero(sizeof(*ret));
435     ret->lpIActiveScriptSiteVtbl               = &ActiveScriptSiteVtbl;
436     ret->lpIActiveScriptSiteInterruptPollVtbl  = &ActiveScriptSiteInterruptPollVtbl;
437     ret->lpIActiveScriptSiteWindowVtbl         = &ActiveScriptSiteWindowVtbl;
438     ret->ref = 1;
439     ret->doc = doc;
440     ret->script_state = SCRIPTSTATE_UNINITIALIZED;
441
442     ret->guid = *guid;
443     list_add_tail(&doc->script_hosts, &ret->entry);
444
445     hres = CoCreateInstance(&ret->guid, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
446             &IID_IActiveScript, (void**)&ret->script);
447     if(FAILED(hres))
448         WARN("Could not load script engine: %08x\n", hres);
449     else if(!init_script_engine(ret))
450         release_script_engine(ret);
451
452     return ret;
453 }
454
455 static void parse_text(ScriptHost *script_host, LPCWSTR text)
456 {
457     EXCEPINFO excepinfo;
458     VARIANT var;
459     HRESULT hres;
460
461     static const WCHAR script_endW[] = {'<','/','S','C','R','I','P','T','>',0};
462
463     TRACE("%s\n", debugstr_w(text));
464
465     VariantInit(&var);
466     memset(&excepinfo, 0, sizeof(excepinfo));
467     hres = IActiveScriptParse_ParseScriptText(script_host->parse, text, windowW, NULL, script_endW,
468                                               0, 0, SCRIPTTEXT_ISVISIBLE|SCRIPTTEXT_HOSTMANAGESSOURCE,
469                                               &var, &excepinfo);
470     if(FAILED(hres))
471         WARN("ParseScriptText failed: %08x\n", hres);
472
473 }
474
475 static void parse_extern_script(ScriptHost *script_host, LPCWSTR src)
476 {
477     IMoniker *mon;
478     char *buf;
479     WCHAR *text;
480     HRESULT hres;
481
482     static const WCHAR wine_schemaW[] = {'w','i','n','e',':'};
483
484     if(strlenW(src) > sizeof(wine_schemaW)/sizeof(WCHAR) && !memcmp(src, wine_schemaW, sizeof(wine_schemaW)))
485         src += sizeof(wine_schemaW)/sizeof(WCHAR);
486
487     hres = CreateURLMoniker(NULL, src, &mon);
488     if(FAILED(hres))
489         return;
490
491     hres = bind_mon_to_buffer(script_host->doc, mon, (void**)&buf);
492     IMoniker_Release(mon);
493     if(FAILED(hres))
494         return;
495
496     text = heap_strdupAtoW(buf);
497     heap_free(buf);
498
499     parse_text(script_host, text);
500
501     heap_free(text);
502 }
503
504 static void parse_inline_script(ScriptHost *script_host, nsIDOMHTMLScriptElement *nsscript)
505 {
506     const PRUnichar *text;
507     nsAString text_str;
508     nsresult nsres;
509
510     nsAString_Init(&text_str, NULL);
511
512     nsres = nsIDOMHTMLScriptElement_GetText(nsscript, &text_str);
513
514     if(NS_SUCCEEDED(nsres)) {
515         nsAString_GetData(&text_str, &text);
516         parse_text(script_host, text);
517     }else {
518         ERR("GetText failed: %08x\n", nsres);
519     }
520
521     nsAString_Finish(&text_str);
522 }
523
524 static void parse_script_elem(ScriptHost *script_host, nsIDOMHTMLScriptElement *nsscript)
525 {
526     const PRUnichar *src;
527     nsAString src_str;
528     nsresult nsres;
529
530     nsAString_Init(&src_str, NULL);
531
532     nsres = nsIDOMHTMLScriptElement_GetSrc(nsscript, &src_str);
533     nsAString_GetData(&src_str, &src);
534
535     if(NS_FAILED(nsres))
536         ERR("GetSrc failed: %08x\n", nsres);
537     else if(*src)
538         parse_extern_script(script_host, src);
539     else
540         parse_inline_script(script_host, nsscript);
541
542     nsAString_Finish(&src_str);
543 }
544
545 static BOOL get_guid_from_type(LPCWSTR type, GUID *guid)
546 {
547     const WCHAR text_javascriptW[] =
548         {'t','e','x','t','/','j','a','v','a','s','c','r','i','p','t',0};
549
550     /* FIXME: Handle more types */
551     if(!strcmpW(type, text_javascriptW)) {
552         *guid = CLSID_JScript;
553     }else {
554         FIXME("Unknown type %s\n", debugstr_w(type));
555         return FALSE;
556     }
557
558     return TRUE;
559 }
560
561 static BOOL get_guid_from_language(LPCWSTR type, GUID *guid)
562 {
563     HRESULT hres;
564
565     hres = CLSIDFromProgID(type, guid);
566     if(FAILED(hres))
567         return FALSE;
568
569     /* FIXME: Check CATID_ActiveScriptParse */
570
571     return TRUE;
572 }
573
574 static BOOL get_script_guid(nsIDOMHTMLScriptElement *nsscript, GUID *guid)
575 {
576     nsAString attr_str, val_str;
577     BOOL ret = FALSE;
578     nsresult nsres;
579
580     static const PRUnichar languageW[] = {'l','a','n','g','u','a','g','e',0};
581
582     nsAString_Init(&val_str, NULL);
583
584     nsres = nsIDOMHTMLScriptElement_GetType(nsscript, &val_str);
585     if(NS_SUCCEEDED(nsres)) {
586         const PRUnichar *type;
587
588         nsAString_GetData(&val_str, &type);
589         if(*type) {
590             ret = get_guid_from_type(type, guid);
591             nsAString_Finish(&val_str);
592             return ret;
593         }
594     }else {
595         ERR("GetType failed: %08x\n", nsres);
596     }
597
598     nsAString_Init(&attr_str, languageW);
599
600     nsres = nsIDOMHTMLScriptElement_GetAttribute(nsscript, &attr_str, &val_str);
601     if(NS_SUCCEEDED(nsres)) {
602         const PRUnichar *language;
603
604         nsAString_GetData(&val_str, &language);
605
606         if(*language) {
607             ret = get_guid_from_language(language, guid);
608         }else {
609             *guid = CLSID_JScript;
610             ret = TRUE;
611         }
612     }else {
613         ERR("GetAttribute(language) failed: %08x\n", nsres);
614     }
615
616     nsAString_Finish(&attr_str);
617     nsAString_Finish(&val_str);
618
619     return ret;
620 }
621
622 static ScriptHost *get_script_host(HTMLDocument *doc, nsIDOMHTMLScriptElement *nsscript)
623 {
624     ScriptHost *iter;
625     GUID guid;
626
627     if(!get_script_guid(nsscript, &guid)) {
628         WARN("Could not find script GUID\n");
629         return NULL;
630     }
631
632     if(IsEqualGUID(&CLSID_JScript, &guid)) {
633         FIXME("Ignoring JScript\n");
634         return NULL;
635     }
636
637     LIST_FOR_EACH_ENTRY(iter, &doc->script_hosts, ScriptHost, entry) {
638         if(IsEqualGUID(&guid, &iter->guid))
639             return iter;
640     }
641
642     return create_script_host(doc, &guid);
643 }
644
645 void doc_insert_script(HTMLDocument *doc, nsIDOMHTMLScriptElement *nsscript)
646 {
647     ScriptHost *script_host;
648
649     script_host = get_script_host(doc, nsscript);
650     if(!script_host)
651         return;
652
653     if(script_host->parse)
654         parse_script_elem(script_host, nsscript);
655 }
656
657 void release_script_hosts(HTMLDocument *doc)
658 {
659     ScriptHost *iter;
660
661     while(!list_empty(&doc->script_hosts)) {
662         iter = LIST_ENTRY(list_head(&doc->script_hosts), ScriptHost, entry);
663
664         release_script_engine(iter);
665         list_remove(&iter->entry);
666         iter->doc = NULL;
667         IActiveScript_Release(ACTSCPSITE(iter));
668     }
669 }