d3drm: Just use RGBA_MAKE.
[wine] / dlls / vbscript / vbregexp.c
1 /*
2  * Copyright 2013 Piotr 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 "vbscript.h"
20 #include "regexp.h"
21 #include "vbsregexp55.h"
22
23 #include "wine/debug.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
26
27 #define REGEXP_TID_LIST \
28     XDIID(RegExp2), \
29     XDIID(Match2), \
30     XDIID(MatchCollection2), \
31     XDIID(SubMatches)
32
33 typedef enum {
34 #define XDIID(iface) iface ## _tid
35     REGEXP_TID_LIST,
36 #undef XDIID
37     REGEXP_LAST_tid
38 } regexp_tid_t;
39
40 static REFIID tid_ids[] = {
41 #define XDIID(iface) &IID_I ## iface
42     REGEXP_TID_LIST
43 #undef XDIID
44 };
45
46 static ITypeLib *typelib;
47 static ITypeInfo *typeinfos[REGEXP_LAST_tid];
48
49 static HRESULT init_regexp_typeinfo(regexp_tid_t tid)
50 {
51     HRESULT hres;
52
53     if(!typelib) {
54         static const WCHAR vbscript_dll3W[] = {'v','b','s','c','r','i','p','t','.','d','l','l','\\','3',0};
55         ITypeLib *tl;
56
57         hres = LoadTypeLib(vbscript_dll3W, &tl);
58         if(FAILED(hres)) {
59             ERR("LoadRegTypeLib failed: %08x\n", hres);
60             return hres;
61         }
62
63         if(InterlockedCompareExchangePointer((void**)&typelib, tl, NULL))
64             ITypeLib_Release(tl);
65     }
66
67     if(!typeinfos[tid]) {
68         ITypeInfo *ti;
69
70         hres = ITypeLib_GetTypeInfoOfGuid(typelib, tid_ids[tid], &ti);
71         if(FAILED(hres)) {
72             ERR("GetTypeInfoOfGuid(%s) failed: %08x\n", debugstr_guid(tid_ids[tid]), hres);
73             return hres;
74         }
75
76         if(InterlockedCompareExchangePointer((void**)(typeinfos+tid), ti, NULL))
77             ITypeInfo_Release(ti);
78     }
79
80     return S_OK;
81 }
82
83 struct SubMatches {
84     ISubMatches ISubMatches_iface;
85
86     LONG ref;
87
88     WCHAR *match;
89     match_state_t *result;
90 };
91
92 typedef struct Match2 {
93     IMatch2 IMatch2_iface;
94     IMatch IMatch_iface;
95
96     LONG ref;
97
98     DWORD index;
99     SubMatches *sub_matches;
100 } Match2;
101
102 typedef struct MatchCollectionEnum {
103     IEnumVARIANT IEnumVARIANT_iface;
104
105     LONG ref;
106
107     IMatchCollection2 *mc;
108     LONG pos;
109     LONG count;
110 } MatchCollectionEnum;
111
112 typedef struct MatchCollection2 {
113     IMatchCollection2 IMatchCollection2_iface;
114     IMatchCollection IMatchCollection_iface;
115
116     LONG ref;
117
118     IMatch2 **matches;
119     DWORD count;
120     DWORD size;
121 } MatchCollection2;
122
123 typedef struct RegExp2 {
124     IRegExp2 IRegExp2_iface;
125     IRegExp IRegExp_iface;
126
127     LONG ref;
128
129     WCHAR *pattern;
130     regexp_t *regexp;
131     heap_pool_t pool;
132     WORD flags;
133 } RegExp2;
134
135 static inline SubMatches* impl_from_ISubMatches(ISubMatches *iface)
136 {
137     return CONTAINING_RECORD(iface, SubMatches, ISubMatches_iface);
138 }
139
140 static HRESULT WINAPI SubMatches_QueryInterface(
141         ISubMatches *iface, REFIID riid, void **ppv)
142 {
143     SubMatches *This = impl_from_ISubMatches(iface);
144
145     if(IsEqualGUID(riid, &IID_IUnknown)) {
146         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
147         *ppv = &This->ISubMatches_iface;
148     }else if(IsEqualGUID(riid, &IID_IDispatch)) {
149         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
150         *ppv = &This->ISubMatches_iface;
151     }else if(IsEqualGUID(riid, &IID_ISubMatches)) {
152         TRACE("(%p)->(IID_ISubMatches %p)\n", This, ppv);
153         *ppv = &This->ISubMatches_iface;
154     }else if(IsEqualGUID(riid, &IID_IDispatchEx)) {
155         TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
156         *ppv = NULL;
157         return E_NOINTERFACE;
158     }else {
159         FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
160         *ppv = NULL;
161         return E_NOINTERFACE;
162     }
163
164     IUnknown_AddRef((IUnknown*)*ppv);
165     return S_OK;
166 }
167
168 static ULONG WINAPI SubMatches_AddRef(ISubMatches *iface)
169 {
170     SubMatches *This = impl_from_ISubMatches(iface);
171     LONG ref = InterlockedIncrement(&This->ref);
172
173     TRACE("(%p) ref=%d\n", This, ref);
174
175     return ref;
176 }
177
178 static ULONG WINAPI SubMatches_Release(ISubMatches *iface)
179 {
180     SubMatches *This = impl_from_ISubMatches(iface);
181     LONG ref = InterlockedDecrement(&This->ref);
182
183     TRACE("(%p) ref=%d\n", This, ref);
184
185     if(!ref) {
186         heap_free(This->match);
187         heap_free(This->result);
188         heap_free(This);
189     }
190
191     return ref;
192 }
193
194 static HRESULT WINAPI SubMatches_GetTypeInfoCount(ISubMatches *iface, UINT *pctinfo)
195 {
196     SubMatches *This = impl_from_ISubMatches(iface);
197
198     TRACE("(%p)->(%p)\n", This, pctinfo);
199
200     *pctinfo = 1;
201     return S_OK;
202 }
203
204 static HRESULT WINAPI SubMatches_GetTypeInfo(ISubMatches *iface,
205         UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
206 {
207     SubMatches *This = impl_from_ISubMatches(iface);
208     FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
209     return E_NOTIMPL;
210 }
211
212 static HRESULT WINAPI SubMatches_GetIDsOfNames(ISubMatches *iface,
213         REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
214 {
215     SubMatches *This = impl_from_ISubMatches(iface);
216
217     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid),
218             rgszNames, cNames, lcid, rgDispId);
219
220     return ITypeInfo_GetIDsOfNames(typeinfos[SubMatches_tid], rgszNames, cNames, rgDispId);
221 }
222
223 static HRESULT WINAPI SubMatches_Invoke(ISubMatches *iface, DISPID dispIdMember,
224         REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
225                         VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
226 {
227     SubMatches *This = impl_from_ISubMatches(iface);
228
229     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
230             lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
231
232     return ITypeInfo_Invoke(typeinfos[SubMatches_tid], iface, dispIdMember, wFlags,
233             pDispParams, pVarResult, pExcepInfo, puArgErr);
234 }
235
236 static HRESULT WINAPI SubMatches_get_Item(ISubMatches *iface,
237         LONG index, VARIANT *pSubMatch)
238 {
239     SubMatches *This = impl_from_ISubMatches(iface);
240
241     TRACE("(%p)->(%d %p)\n", This, index, pSubMatch);
242
243     if(!pSubMatch)
244         return E_POINTER;
245
246     if(!This->result || index<0 || index>=This->result->paren_count)
247         return E_INVALIDARG;
248
249     if(This->result->parens[index].index == -1) {
250         V_VT(pSubMatch) = VT_EMPTY;
251     }else {
252         V_VT(pSubMatch) = VT_BSTR;
253         V_BSTR(pSubMatch) = SysAllocStringLen(
254                 This->match+This->result->parens[index].index,
255                 This->result->parens[index].length);
256
257         if(!V_BSTR(pSubMatch))
258             return E_OUTOFMEMORY;
259     }
260
261     return S_OK;
262 }
263
264 static HRESULT WINAPI SubMatches_get_Count(ISubMatches *iface, LONG *pCount)
265 {
266     SubMatches *This = impl_from_ISubMatches(iface);
267
268     TRACE("(%p)->(%p)\n", This, pCount);
269
270     if(!pCount)
271         return E_POINTER;
272
273     if(!This->result)
274         *pCount = 0;
275     else
276         *pCount = This->result->paren_count;
277     return S_OK;
278 }
279
280 static HRESULT WINAPI SubMatches_get__NewEnum(ISubMatches *iface, IUnknown **ppEnum)
281 {
282     SubMatches *This = impl_from_ISubMatches(iface);
283     FIXME("(%p)->(%p)\n", This, ppEnum);
284     return E_NOTIMPL;
285 }
286
287 static const ISubMatchesVtbl SubMatchesVtbl = {
288     SubMatches_QueryInterface,
289     SubMatches_AddRef,
290     SubMatches_Release,
291     SubMatches_GetTypeInfoCount,
292     SubMatches_GetTypeInfo,
293     SubMatches_GetIDsOfNames,
294     SubMatches_Invoke,
295     SubMatches_get_Item,
296     SubMatches_get_Count,
297     SubMatches_get__NewEnum
298 };
299
300 static HRESULT create_sub_matches(DWORD pos, match_state_t *result, SubMatches **sub_matches)
301 {
302     SubMatches *ret;
303     DWORD i;
304     HRESULT hres;
305
306     hres = init_regexp_typeinfo(SubMatches_tid);
307     if(FAILED(hres))
308         return hres;
309
310     ret = heap_alloc_zero(sizeof(*ret));
311     if(!ret)
312         return E_OUTOFMEMORY;
313
314     ret->ISubMatches_iface.lpVtbl = &SubMatchesVtbl;
315
316     ret->result = result;
317     if(result) {
318         ret->match = heap_alloc((result->match_len+1) * sizeof(WCHAR));
319         if(!ret->match) {
320             heap_free(ret);
321             return E_OUTOFMEMORY;
322         }
323         memcpy(ret->match, result->cp-result->match_len, result->match_len*sizeof(WCHAR));
324         ret->match[result->match_len] = 0;
325
326         result->cp = NULL;
327         for(i=0; i<result->paren_count; i++)
328             if(result->parens[i].index != -1)
329                 result->parens[i].index -= pos;
330     }else {
331         ret->match = NULL;
332     }
333
334     ret->ref = 1;
335     *sub_matches = ret;
336     return hres;
337 }
338
339 static inline Match2* impl_from_IMatch2(IMatch2 *iface)
340 {
341     return CONTAINING_RECORD(iface, Match2, IMatch2_iface);
342 }
343
344 static HRESULT WINAPI Match2_QueryInterface(
345         IMatch2 *iface, REFIID riid, void **ppv)
346 {
347     Match2 *This = impl_from_IMatch2(iface);
348
349     if(IsEqualGUID(riid, &IID_IUnknown)) {
350         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
351         *ppv = &This->IMatch2_iface;
352     }else if(IsEqualGUID(riid, &IID_IDispatch)) {
353         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
354         *ppv = &This->IMatch2_iface;
355     }else if(IsEqualGUID(riid, &IID_IMatch2)) {
356         TRACE("(%p)->(IID_IMatch2 %p)\n", This, ppv);
357         *ppv = &This->IMatch2_iface;
358     }else if(IsEqualGUID(riid, &IID_IMatch)) {
359         TRACE("(%p)->(IID_IMatch %p)\n", This, ppv);
360         *ppv = &This->IMatch_iface;
361     }else if(IsEqualGUID(riid, &IID_IDispatchEx)) {
362         TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
363         *ppv = NULL;
364         return E_NOINTERFACE;
365     }else {
366         FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
367         *ppv = NULL;
368         return E_NOINTERFACE;
369     }
370
371     IUnknown_AddRef((IUnknown*)*ppv);
372     return S_OK;
373 }
374
375 static ULONG WINAPI Match2_AddRef(IMatch2 *iface)
376 {
377     Match2 *This = impl_from_IMatch2(iface);
378     LONG ref = InterlockedIncrement(&This->ref);
379
380     TRACE("(%p) ref=%d\n", This, ref);
381
382     return ref;
383 }
384
385 static ULONG WINAPI Match2_Release(IMatch2 *iface)
386 {
387     Match2 *This = impl_from_IMatch2(iface);
388     LONG ref = InterlockedDecrement(&This->ref);
389
390     TRACE("(%p) ref=%d\n", This, ref);
391
392     if(!ref) {
393         ISubMatches_Release(&This->sub_matches->ISubMatches_iface);
394         heap_free(This);
395     }
396
397     return ref;
398 }
399
400 static HRESULT WINAPI Match2_GetTypeInfoCount(IMatch2 *iface, UINT *pctinfo)
401 {
402     Match2 *This = impl_from_IMatch2(iface);
403
404     TRACE("(%p)->(%p)\n", This, pctinfo);
405
406     *pctinfo = 1;
407     return S_OK;
408 }
409
410 static HRESULT WINAPI Match2_GetTypeInfo(IMatch2 *iface,
411         UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
412 {
413     Match2 *This = impl_from_IMatch2(iface);
414     FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
415     return E_NOTIMPL;
416 }
417
418 static HRESULT WINAPI Match2_GetIDsOfNames(IMatch2 *iface,
419         REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
420 {
421     Match2 *This = impl_from_IMatch2(iface);
422
423     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid),
424             rgszNames, cNames, lcid, rgDispId);
425
426     return ITypeInfo_GetIDsOfNames(typeinfos[Match2_tid], rgszNames, cNames, rgDispId);
427 }
428
429 static HRESULT WINAPI Match2_Invoke(IMatch2 *iface, DISPID dispIdMember,
430         REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
431                 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
432 {
433     Match2 *This = impl_from_IMatch2(iface);
434
435     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
436             lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
437
438     return ITypeInfo_Invoke(typeinfos[Match2_tid], iface, dispIdMember, wFlags,
439             pDispParams, pVarResult, pExcepInfo, puArgErr);
440 }
441
442 static HRESULT WINAPI Match2_get_Value(IMatch2 *iface, BSTR *pValue)
443 {
444     Match2 *This = impl_from_IMatch2(iface);
445
446     TRACE("(%p)->(%p)\n", This, pValue);
447
448     if(!pValue)
449         return E_POINTER;
450
451     if(!This->sub_matches->match) {
452         *pValue = NULL;
453         return S_OK;
454     }
455
456     *pValue = SysAllocString(This->sub_matches->match);
457     return *pValue ? S_OK : E_OUTOFMEMORY;
458 }
459
460 static HRESULT WINAPI Match2_get_FirstIndex(IMatch2 *iface, LONG *pFirstIndex)
461 {
462     Match2 *This = impl_from_IMatch2(iface);
463
464     TRACE("(%p)->(%p)\n", This, pFirstIndex);
465
466     if(!pFirstIndex)
467         return E_POINTER;
468
469     *pFirstIndex = This->index;
470     return S_OK;
471 }
472
473 static HRESULT WINAPI Match2_get_Length(IMatch2 *iface, LONG *pLength)
474 {
475     Match2 *This = impl_from_IMatch2(iface);
476
477     TRACE("(%p)->(%p)\n", This, pLength);
478
479     if(!pLength)
480         return E_POINTER;
481
482     if(This->sub_matches->result)
483         *pLength = This->sub_matches->result->match_len;
484     else
485         *pLength = 0;
486     return S_OK;
487 }
488
489 static HRESULT WINAPI Match2_get_SubMatches(IMatch2 *iface, IDispatch **ppSubMatches)
490 {
491     Match2 *This = impl_from_IMatch2(iface);
492
493     TRACE("(%p)->(%p)\n", This, ppSubMatches);
494
495     if(!ppSubMatches)
496         return E_POINTER;
497
498     *ppSubMatches = (IDispatch*)&This->sub_matches->ISubMatches_iface;
499     ISubMatches_AddRef(&This->sub_matches->ISubMatches_iface);
500     return S_OK;
501 }
502
503 static const IMatch2Vtbl Match2Vtbl = {
504     Match2_QueryInterface,
505     Match2_AddRef,
506     Match2_Release,
507     Match2_GetTypeInfoCount,
508     Match2_GetTypeInfo,
509     Match2_GetIDsOfNames,
510     Match2_Invoke,
511     Match2_get_Value,
512     Match2_get_FirstIndex,
513     Match2_get_Length,
514     Match2_get_SubMatches
515 };
516
517 static inline Match2 *impl_from_IMatch(IMatch *iface)
518 {
519     return CONTAINING_RECORD(iface, Match2, IMatch_iface);
520 }
521
522 static HRESULT WINAPI Match_QueryInterface(IMatch *iface, REFIID riid, void **ppv)
523 {
524     Match2 *This = impl_from_IMatch(iface);
525     return IMatch2_QueryInterface(&This->IMatch2_iface, riid, ppv);
526 }
527
528 static ULONG WINAPI Match_AddRef(IMatch *iface)
529 {
530     Match2 *This = impl_from_IMatch(iface);
531     return IMatch2_AddRef(&This->IMatch2_iface);
532 }
533
534 static ULONG WINAPI Match_Release(IMatch *iface)
535 {
536     Match2 *This = impl_from_IMatch(iface);
537     return IMatch2_Release(&This->IMatch2_iface);
538 }
539
540 static HRESULT WINAPI Match_GetTypeInfoCount(IMatch *iface, UINT *pctinfo)
541 {
542     Match2 *This = impl_from_IMatch(iface);
543     return IMatch2_GetTypeInfoCount(&This->IMatch2_iface, pctinfo);
544 }
545
546 static HRESULT WINAPI Match_GetTypeInfo(IMatch *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
547 {
548     Match2 *This = impl_from_IMatch(iface);
549     return IMatch2_GetTypeInfo(&This->IMatch2_iface, iTInfo, lcid, ppTInfo);
550 }
551
552 static HRESULT WINAPI Match_GetIDsOfNames(IMatch *iface, REFIID riid,
553         LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
554 {
555     Match2 *This = impl_from_IMatch(iface);
556     return IMatch2_GetIDsOfNames(&This->IMatch2_iface, riid, rgszNames, cNames, lcid, rgDispId);
557 }
558
559 static HRESULT WINAPI Match_Invoke(IMatch *iface, DISPID dispIdMember,
560         REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
561         VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
562 {
563     Match2 *This = impl_from_IMatch(iface);
564     return IMatch2_Invoke(&This->IMatch2_iface, dispIdMember, riid, lcid,
565             wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
566 }
567
568 static HRESULT WINAPI Match_get_Value(IMatch *iface, BSTR *pValue)
569 {
570     Match2 *This = impl_from_IMatch(iface);
571     return IMatch2_get_Value(&This->IMatch2_iface, pValue);
572 }
573
574 static HRESULT WINAPI Match_get_FirstIndex(IMatch *iface, LONG *pFirstIndex)
575 {
576     Match2 *This = impl_from_IMatch(iface);
577     return IMatch2_get_FirstIndex(&This->IMatch2_iface, pFirstIndex);
578 }
579
580 static HRESULT WINAPI Match_get_Length(IMatch *iface, LONG *pLength)
581 {
582     Match2 *This = impl_from_IMatch(iface);
583     return IMatch2_get_Length(&This->IMatch2_iface, pLength);
584 }
585
586 static IMatchVtbl MatchVtbl = {
587     Match_QueryInterface,
588     Match_AddRef,
589     Match_Release,
590     Match_GetTypeInfoCount,
591     Match_GetTypeInfo,
592     Match_GetIDsOfNames,
593     Match_Invoke,
594     Match_get_Value,
595     Match_get_FirstIndex,
596     Match_get_Length
597 };
598
599 static HRESULT create_match2(DWORD pos, match_state_t **result, IMatch2 **match)
600 {
601     Match2 *ret;
602     HRESULT hres;
603
604     hres = init_regexp_typeinfo(Match2_tid);
605     if(FAILED(hres))
606         return hres;
607
608     ret = heap_alloc_zero(sizeof(*ret));
609     if(!ret)
610         return E_OUTOFMEMORY;
611
612     ret->index = pos;
613     hres = create_sub_matches(pos, result ? *result : NULL, &ret->sub_matches);
614     if(FAILED(hres)) {
615         heap_free(ret);
616         return hres;
617     }
618     if(result)
619         *result = NULL;
620
621     ret->IMatch2_iface.lpVtbl = &Match2Vtbl;
622     ret->IMatch_iface.lpVtbl = &MatchVtbl;
623
624     ret->ref = 1;
625     *match = &ret->IMatch2_iface;
626     return hres;
627 }
628
629 static inline MatchCollectionEnum* impl_from_IMatchCollectionEnum(IEnumVARIANT *iface)
630 {
631     return CONTAINING_RECORD(iface, MatchCollectionEnum, IEnumVARIANT_iface);
632 }
633
634 static HRESULT WINAPI MatchCollectionEnum_QueryInterface(
635         IEnumVARIANT *iface, REFIID riid, void **ppv)
636 {
637     MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface);
638
639     if(IsEqualGUID(riid, &IID_IUnknown)) {
640         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
641         *ppv = &This->IEnumVARIANT_iface;
642     }else if(IsEqualGUID(riid, &IID_IEnumVARIANT)) {
643         TRACE("(%p)->(IID_IEnumVARIANT %p)\n", This, ppv);
644         *ppv = &This->IEnumVARIANT_iface;
645     }else {
646         FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
647         *ppv = NULL;
648         return E_NOINTERFACE;
649     }
650
651     IUnknown_AddRef((IUnknown*)*ppv);
652     return S_OK;
653 }
654
655 static ULONG WINAPI MatchCollectionEnum_AddRef(IEnumVARIANT *iface)
656 {
657     MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface);
658     LONG ref = InterlockedIncrement(&This->ref);
659
660     TRACE("(%p) ref=%d\n", This, ref);
661
662     return ref;
663 }
664
665 static ULONG WINAPI MatchCollectionEnum_Release(IEnumVARIANT *iface)
666 {
667     MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface);
668     LONG ref = InterlockedDecrement(&This->ref);
669
670     TRACE("(%p) ref=%d\n", This, ref);
671
672     if(!ref) {
673         IMatchCollection2_Release(This->mc);
674         heap_free(This);
675     }
676
677     return ref;
678 }
679
680 static HRESULT WINAPI MatchCollectionEnum_Next(IEnumVARIANT *iface,
681         ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched)
682 {
683     MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface);
684     DWORD i;
685     HRESULT hres = S_OK;
686
687     TRACE("(%p)->(%u %p %p)\n", This, celt, rgVar, pCeltFetched);
688
689     if(This->pos>=This->count) {
690         if(pCeltFetched)
691             *pCeltFetched = 0;
692         return S_FALSE;
693     }
694
695     for(i=0; i<celt && This->pos+i<This->count; i++) {
696         V_VT(rgVar+i) = VT_DISPATCH;
697         hres = IMatchCollection2_get_Item(This->mc, This->pos+i, &V_DISPATCH(rgVar+i));
698         if(FAILED(hres))
699             break;
700     }
701     if(FAILED(hres)) {
702         while(i--)
703             VariantClear(rgVar+i);
704         return hres;
705     }
706
707     if(pCeltFetched)
708         *pCeltFetched = i;
709     This->pos += i;
710     return S_OK;
711 }
712
713 static HRESULT WINAPI MatchCollectionEnum_Skip(IEnumVARIANT *iface, ULONG celt)
714 {
715     MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface);
716
717     TRACE("(%p)->(%u)\n", This, celt);
718
719     if(This->pos+celt <= This->count)
720         This->pos += celt;
721     else
722         This->pos = This->count;
723     return S_OK;
724 }
725
726 static HRESULT WINAPI MatchCollectionEnum_Reset(IEnumVARIANT *iface)
727 {
728     MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface);
729
730     TRACE("(%p)\n", This);
731
732     This->pos = 0;
733     return S_OK;
734 }
735
736 static HRESULT WINAPI MatchCollectionEnum_Clone(IEnumVARIANT *iface, IEnumVARIANT **ppEnum)
737 {
738     MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface);
739     FIXME("(%p)->(%p)\n", This, ppEnum);
740     return E_NOTIMPL;
741 }
742
743 static const IEnumVARIANTVtbl MatchCollectionEnum_Vtbl = {
744     MatchCollectionEnum_QueryInterface,
745     MatchCollectionEnum_AddRef,
746     MatchCollectionEnum_Release,
747     MatchCollectionEnum_Next,
748     MatchCollectionEnum_Skip,
749     MatchCollectionEnum_Reset,
750     MatchCollectionEnum_Clone
751 };
752
753 static HRESULT create_enum_variant_mc2(IMatchCollection2 *mc, ULONG pos, IEnumVARIANT **enum_variant)
754 {
755     MatchCollectionEnum *ret;
756
757     ret = heap_alloc_zero(sizeof(*ret));
758     if(!ret)
759         return E_OUTOFMEMORY;
760
761     ret->IEnumVARIANT_iface.lpVtbl = &MatchCollectionEnum_Vtbl;
762     ret->ref = 1;
763     ret->pos = pos;
764     IMatchCollection2_get_Count(mc, &ret->count);
765     ret->mc = mc;
766     IMatchCollection2_AddRef(mc);
767
768     *enum_variant = &ret->IEnumVARIANT_iface;
769     return S_OK;
770 }
771
772 static inline MatchCollection2* impl_from_IMatchCollection2(IMatchCollection2 *iface)
773 {
774     return CONTAINING_RECORD(iface, MatchCollection2, IMatchCollection2_iface);
775 }
776
777 static HRESULT WINAPI MatchCollection2_QueryInterface(
778         IMatchCollection2 *iface, REFIID riid, void **ppv)
779 {
780     MatchCollection2 *This = impl_from_IMatchCollection2(iface);
781
782     if(IsEqualGUID(riid, &IID_IUnknown)) {
783         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
784         *ppv = &This->IMatchCollection2_iface;
785     }else if(IsEqualGUID(riid, &IID_IDispatch)) {
786         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
787         *ppv = &This->IMatchCollection2_iface;
788     }else if(IsEqualGUID(riid, &IID_IMatchCollection2)) {
789         TRACE("(%p)->(IID_IMatchCollection2 %p)\n", This, ppv);
790         *ppv = &This->IMatchCollection2_iface;
791     }else if(IsEqualGUID(riid, &IID_IMatchCollection)) {
792         TRACE("(%p)->(IID_IMatchCollection %p)\n", This, ppv);
793         *ppv = &This->IMatchCollection_iface;
794     }else if(IsEqualGUID(riid, &IID_IDispatchEx)) {
795         TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
796         *ppv = NULL;
797         return E_NOINTERFACE;
798     }else {
799         FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
800         *ppv = NULL;
801         return E_NOINTERFACE;
802     }
803
804     IUnknown_AddRef((IUnknown*)*ppv);
805     return S_OK;
806 }
807
808 static ULONG WINAPI MatchCollection2_AddRef(IMatchCollection2 *iface)
809 {
810     MatchCollection2 *This = impl_from_IMatchCollection2(iface);
811     LONG ref = InterlockedIncrement(&This->ref);
812
813     TRACE("(%p) ref=%d\n", This, ref);
814
815     return ref;
816 }
817
818 static ULONG WINAPI MatchCollection2_Release(IMatchCollection2 *iface)
819 {
820     MatchCollection2 *This = impl_from_IMatchCollection2(iface);
821     LONG ref = InterlockedDecrement(&This->ref);
822
823     TRACE("(%p) ref=%d\n", This, ref);
824
825     if(!ref) {
826         DWORD i;
827
828         for(i=0; i<This->count; i++)
829             IMatch2_Release(This->matches[i]);
830         heap_free(This->matches);
831
832         heap_free(This);
833     }
834
835     return ref;
836 }
837
838 static HRESULT WINAPI MatchCollection2_GetTypeInfoCount(IMatchCollection2 *iface, UINT *pctinfo)
839 {
840     MatchCollection2 *This = impl_from_IMatchCollection2(iface);
841
842     TRACE("(%p)->(%p)\n", This, pctinfo);
843
844     *pctinfo = 1;
845     return S_OK;
846 }
847
848 static HRESULT WINAPI MatchCollection2_GetTypeInfo(IMatchCollection2 *iface,
849         UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
850 {
851     MatchCollection2 *This = impl_from_IMatchCollection2(iface);
852     FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
853     return E_NOTIMPL;
854 }
855
856 static HRESULT WINAPI MatchCollection2_GetIDsOfNames(IMatchCollection2 *iface,
857         REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
858 {
859     MatchCollection2 *This = impl_from_IMatchCollection2(iface);
860
861     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid),
862             rgszNames, cNames, lcid, rgDispId);
863
864     return ITypeInfo_GetIDsOfNames(typeinfos[MatchCollection2_tid], rgszNames, cNames, rgDispId);
865 }
866
867 static HRESULT WINAPI MatchCollection2_Invoke(IMatchCollection2 *iface, DISPID dispIdMember,
868         REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
869         VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
870 {
871     MatchCollection2 *This = impl_from_IMatchCollection2(iface);
872
873     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
874             lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
875
876     return ITypeInfo_Invoke(typeinfos[MatchCollection2_tid], iface, dispIdMember, wFlags,
877             pDispParams, pVarResult, pExcepInfo, puArgErr);
878 }
879
880 static HRESULT WINAPI MatchCollection2_get_Item(IMatchCollection2 *iface,
881         LONG index, IDispatch **ppMatch)
882 {
883     MatchCollection2 *This = impl_from_IMatchCollection2(iface);
884
885     TRACE("(%p)->()\n", This);
886
887     if(!ppMatch)
888         return E_POINTER;
889
890     if(index<0 || index>=This->count)
891         return E_INVALIDARG;
892
893     *ppMatch = (IDispatch*)This->matches[index];
894     IMatch2_AddRef(This->matches[index]);
895     return S_OK;
896 }
897
898 static HRESULT WINAPI MatchCollection2_get_Count(IMatchCollection2 *iface, LONG *pCount)
899 {
900     MatchCollection2 *This = impl_from_IMatchCollection2(iface);
901
902     TRACE("(%p)->()\n", This);
903
904     if(!pCount)
905         return E_POINTER;
906
907     *pCount = This->count;
908     return S_OK;
909 }
910
911 static HRESULT WINAPI MatchCollection2_get__NewEnum(IMatchCollection2 *iface, IUnknown **ppEnum)
912 {
913     MatchCollection2 *This = impl_from_IMatchCollection2(iface);
914
915     TRACE("(%p)->(%p)\n", This, ppEnum);
916
917     if(!ppEnum)
918         return E_POINTER;
919
920     return create_enum_variant_mc2(&This->IMatchCollection2_iface, 0, (IEnumVARIANT**)ppEnum);
921 }
922
923 static const IMatchCollection2Vtbl MatchCollection2Vtbl = {
924     MatchCollection2_QueryInterface,
925     MatchCollection2_AddRef,
926     MatchCollection2_Release,
927     MatchCollection2_GetTypeInfoCount,
928     MatchCollection2_GetTypeInfo,
929     MatchCollection2_GetIDsOfNames,
930     MatchCollection2_Invoke,
931     MatchCollection2_get_Item,
932     MatchCollection2_get_Count,
933     MatchCollection2_get__NewEnum
934 };
935
936 static inline MatchCollection2 *impl_from_IMatchCollection(IMatchCollection *iface)
937 {
938     return CONTAINING_RECORD(iface, MatchCollection2, IMatchCollection_iface);
939 }
940
941 static HRESULT WINAPI MatchCollection_QueryInterface(IMatchCollection *iface, REFIID riid, void **ppv)
942 {
943     MatchCollection2 *This = impl_from_IMatchCollection(iface);
944     return IMatchCollection2_QueryInterface(&This->IMatchCollection2_iface, riid, ppv);
945 }
946
947 static ULONG WINAPI MatchCollection_AddRef(IMatchCollection *iface)
948 {
949     MatchCollection2 *This = impl_from_IMatchCollection(iface);
950     return IMatchCollection2_AddRef(&This->IMatchCollection2_iface);
951 }
952
953 static ULONG WINAPI MatchCollection_Release(IMatchCollection *iface)
954 {
955     MatchCollection2 *This = impl_from_IMatchCollection(iface);
956     return IMatchCollection2_Release(&This->IMatchCollection2_iface);
957 }
958
959 static HRESULT WINAPI MatchCollection_GetTypeInfoCount(IMatchCollection *iface, UINT *pctinfo)
960 {
961     MatchCollection2 *This = impl_from_IMatchCollection(iface);
962     return IMatchCollection2_GetTypeInfoCount(&This->IMatchCollection2_iface, pctinfo);
963 }
964
965 static HRESULT WINAPI MatchCollection_GetTypeInfo(IMatchCollection *iface,
966         UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
967 {
968     MatchCollection2 *This = impl_from_IMatchCollection(iface);
969     return IMatchCollection2_GetTypeInfo(&This->IMatchCollection2_iface, iTInfo, lcid, ppTInfo);
970 }
971
972 static HRESULT WINAPI MatchCollection_GetIDsOfNames(IMatchCollection *iface, REFIID riid,
973         LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
974 {
975     MatchCollection2 *This = impl_from_IMatchCollection(iface);
976     return IMatchCollection2_GetIDsOfNames(&This->IMatchCollection2_iface,
977             riid, rgszNames, cNames, lcid, rgDispId);
978 }
979
980 static HRESULT WINAPI MatchCollection_Invoke(IMatchCollection *iface, DISPID dispIdMember,
981         REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
982         EXCEPINFO *pExcepInfo, UINT *puArgErr)
983 {
984     MatchCollection2 *This = impl_from_IMatchCollection(iface);
985     return IMatchCollection2_Invoke(&This->IMatchCollection2_iface, dispIdMember,
986             riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
987 }
988
989 static HRESULT WINAPI MatchCollection_get_Item(IMatchCollection *iface, LONG index, IDispatch **ppMatch)
990 {
991     MatchCollection2 *This = impl_from_IMatchCollection(iface);
992     return IMatchCollection2_get_Item(&This->IMatchCollection2_iface, index, ppMatch);
993 }
994
995 static HRESULT WINAPI MatchCollection_get_Count(IMatchCollection *iface, LONG *pCount)
996 {
997     MatchCollection2 *This = impl_from_IMatchCollection(iface);
998     return IMatchCollection2_get_Count(&This->IMatchCollection2_iface, pCount);
999 }
1000
1001 static HRESULT WINAPI MatchCollection_get__NewEnum(IMatchCollection *iface, IUnknown **ppEnum)
1002 {
1003     MatchCollection2 *This = impl_from_IMatchCollection(iface);
1004     return IMatchCollection2_get__NewEnum(&This->IMatchCollection2_iface, ppEnum);
1005 }
1006
1007 static const IMatchCollectionVtbl MatchCollectionVtbl = {
1008     MatchCollection_QueryInterface,
1009     MatchCollection_AddRef,
1010     MatchCollection_Release,
1011     MatchCollection_GetTypeInfoCount,
1012     MatchCollection_GetTypeInfo,
1013     MatchCollection_GetIDsOfNames,
1014     MatchCollection_Invoke,
1015     MatchCollection_get_Item,
1016     MatchCollection_get_Count,
1017     MatchCollection_get__NewEnum
1018 };
1019
1020 static HRESULT add_match(IMatchCollection2 *iface, IMatch2 *add)
1021 {
1022     MatchCollection2 *This = impl_from_IMatchCollection2(iface);
1023
1024     TRACE("(%p)->(%p)\n", This, add);
1025
1026     if(!This->size) {
1027         This->matches = heap_alloc(8*sizeof(IMatch*));
1028         if(!This->matches)
1029             return E_OUTOFMEMORY;
1030         This->size = 8;
1031     }else if(This->size == This->count) {
1032         IMatch2 **new_matches = heap_realloc(This->matches, 2*This->size*sizeof(IMatch*));
1033         if(!new_matches)
1034             return E_OUTOFMEMORY;
1035
1036         This->matches = new_matches;
1037         This->size <<= 1;
1038     }
1039
1040     This->matches[This->count++] = add;
1041     IMatch2_AddRef(add);
1042     return S_OK;
1043 }
1044
1045 static HRESULT create_match_collection2(IMatchCollection2 **match_collection)
1046 {
1047     MatchCollection2 *ret;
1048     HRESULT hres;
1049
1050     hres = init_regexp_typeinfo(MatchCollection2_tid);
1051     if(FAILED(hres))
1052         return hres;
1053
1054     ret = heap_alloc_zero(sizeof(*ret));
1055     if(!ret)
1056         return E_OUTOFMEMORY;
1057
1058     ret->IMatchCollection2_iface.lpVtbl = &MatchCollection2Vtbl;
1059     ret->IMatchCollection_iface.lpVtbl = &MatchCollectionVtbl;
1060
1061     ret->ref = 1;
1062     *match_collection = &ret->IMatchCollection2_iface;
1063     return S_OK;
1064 }
1065
1066 static inline RegExp2 *impl_from_IRegExp2(IRegExp2 *iface)
1067 {
1068     return CONTAINING_RECORD(iface, RegExp2, IRegExp2_iface);
1069 }
1070
1071 static HRESULT WINAPI RegExp2_QueryInterface(IRegExp2 *iface, REFIID riid, void **ppv)
1072 {
1073     RegExp2 *This = impl_from_IRegExp2(iface);
1074
1075     if(IsEqualGUID(riid, &IID_IUnknown)) {
1076         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
1077         *ppv = &This->IRegExp2_iface;
1078     }else if(IsEqualGUID(riid, &IID_IDispatch)) {
1079         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
1080         *ppv = &This->IRegExp2_iface;
1081     }else if(IsEqualGUID(riid, &IID_IRegExp2)) {
1082         TRACE("(%p)->(IID_IRegExp2 %p)\n", This, ppv);
1083         *ppv = &This->IRegExp2_iface;
1084     }else if(IsEqualGUID(riid, &IID_IRegExp)) {
1085         TRACE("(%p)->(IID_IRegExp %p)\n", This, ppv);
1086         *ppv = &This->IRegExp_iface;
1087     }else if(IsEqualGUID(riid, &IID_IDispatchEx)) {
1088         TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
1089         *ppv = NULL;
1090         return E_NOINTERFACE;
1091     }else {
1092         FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
1093         *ppv = NULL;
1094         return E_NOINTERFACE;
1095     }
1096
1097     IUnknown_AddRef((IUnknown*)*ppv);
1098     return S_OK;
1099 }
1100
1101 static ULONG WINAPI RegExp2_AddRef(IRegExp2 *iface)
1102 {
1103     RegExp2 *This = impl_from_IRegExp2(iface);
1104     LONG ref = InterlockedIncrement(&This->ref);
1105
1106     TRACE("(%p) ref=%d\n", This, ref);
1107
1108     return ref;
1109 }
1110
1111 static ULONG WINAPI RegExp2_Release(IRegExp2 *iface)
1112 {
1113     RegExp2 *This = impl_from_IRegExp2(iface);
1114     LONG ref = InterlockedDecrement(&This->ref);
1115
1116     TRACE("(%p) ref=%d\n", This, ref);
1117
1118     if(!ref) {
1119         heap_free(This->pattern);
1120         if(This->regexp)
1121             regexp_destroy(This->regexp);
1122         heap_pool_free(&This->pool);
1123         heap_free(This);
1124     }
1125
1126     return ref;
1127 }
1128
1129 static HRESULT WINAPI RegExp2_GetTypeInfoCount(IRegExp2 *iface, UINT *pctinfo)
1130 {
1131     RegExp2 *This = impl_from_IRegExp2(iface);
1132
1133     TRACE("(%p)->(%p)\n", This, pctinfo);
1134
1135     *pctinfo = 1;
1136     return S_OK;
1137 }
1138
1139 static HRESULT WINAPI RegExp2_GetTypeInfo(IRegExp2 *iface,
1140         UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
1141 {
1142     RegExp2 *This = impl_from_IRegExp2(iface);
1143     FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1144     return E_NOTIMPL;
1145 }
1146
1147 static HRESULT WINAPI RegExp2_GetIDsOfNames(IRegExp2 *iface, REFIID riid,
1148         LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
1149 {
1150     RegExp2 *This = impl_from_IRegExp2(iface);
1151
1152     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid),
1153             rgszNames, cNames, lcid, rgDispId);
1154
1155     return ITypeInfo_GetIDsOfNames(typeinfos[RegExp2_tid], rgszNames, cNames, rgDispId);
1156 }
1157
1158 static HRESULT WINAPI RegExp2_Invoke(IRegExp2 *iface, DISPID dispIdMember,
1159         REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
1160         VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1161 {
1162     RegExp2 *This = impl_from_IRegExp2(iface);
1163
1164     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1165             lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1166
1167     return ITypeInfo_Invoke(typeinfos[RegExp2_tid], iface, dispIdMember, wFlags,
1168             pDispParams, pVarResult, pExcepInfo, puArgErr);
1169 }
1170
1171 static HRESULT WINAPI RegExp2_get_Pattern(IRegExp2 *iface, BSTR *pPattern)
1172 {
1173     RegExp2 *This = impl_from_IRegExp2(iface);
1174
1175     TRACE("(%p)->(%p)\n", This, pPattern);
1176
1177     if(!pPattern)
1178         return E_POINTER;
1179
1180     if(!This->pattern) {
1181         *pPattern = NULL;
1182         return S_OK;
1183     }
1184
1185     *pPattern = SysAllocString(This->pattern);
1186     return *pPattern ? S_OK : E_OUTOFMEMORY;
1187 }
1188
1189 static HRESULT WINAPI RegExp2_put_Pattern(IRegExp2 *iface, BSTR pattern)
1190 {
1191     RegExp2 *This = impl_from_IRegExp2(iface);
1192     WCHAR *p;
1193     DWORD size;
1194
1195     TRACE("(%p)->(%s)\n", This, wine_dbgstr_w(pattern));
1196
1197     if(!pattern) {
1198         heap_free(This->pattern);
1199         if(This->regexp) {
1200             regexp_destroy(This->regexp);
1201             This->regexp = NULL;
1202         }
1203         This->pattern = NULL;
1204         return S_OK;
1205     }
1206
1207     size = (SysStringLen(pattern)+1) * sizeof(WCHAR);
1208     p = heap_alloc(size);
1209     if(!p)
1210         return E_OUTOFMEMORY;
1211
1212     heap_free(This->pattern);
1213     This->pattern = p;
1214     memcpy(p, pattern, size);
1215     if(This->regexp) {
1216         regexp_destroy(This->regexp);
1217         This->regexp = NULL;
1218     }
1219     return S_OK;
1220 }
1221
1222 static HRESULT WINAPI RegExp2_get_IgnoreCase(IRegExp2 *iface, VARIANT_BOOL *pIgnoreCase)
1223 {
1224     RegExp2 *This = impl_from_IRegExp2(iface);
1225
1226     TRACE("(%p)->(%p)\n", This, pIgnoreCase);
1227
1228     if(!pIgnoreCase)
1229         return E_POINTER;
1230
1231     *pIgnoreCase = This->flags & REG_FOLD ? VARIANT_TRUE : VARIANT_FALSE;
1232     return S_OK;
1233 }
1234
1235 static HRESULT WINAPI RegExp2_put_IgnoreCase(IRegExp2 *iface, VARIANT_BOOL ignoreCase)
1236 {
1237     RegExp2 *This = impl_from_IRegExp2(iface);
1238
1239     TRACE("(%p)->(%s)\n", This, ignoreCase ? "true" : "false");
1240
1241     if(ignoreCase)
1242         This->flags |= REG_FOLD;
1243     else
1244         This->flags &= ~REG_FOLD;
1245     return S_OK;
1246 }
1247
1248 static HRESULT WINAPI RegExp2_get_Global(IRegExp2 *iface, VARIANT_BOOL *pGlobal)
1249 {
1250     RegExp2 *This = impl_from_IRegExp2(iface);
1251
1252     TRACE("(%p)->(%p)\n", This, pGlobal);
1253
1254     if(!pGlobal)
1255         return E_POINTER;
1256
1257     *pGlobal = This->flags & REG_GLOB ? VARIANT_TRUE : VARIANT_FALSE;
1258     return S_OK;
1259 }
1260
1261 static HRESULT WINAPI RegExp2_put_Global(IRegExp2 *iface, VARIANT_BOOL global)
1262 {
1263     RegExp2 *This = impl_from_IRegExp2(iface);
1264
1265     TRACE("(%p)->(%s)\n", This, global ? "true" : "false");
1266
1267     if(global)
1268         This->flags |= REG_GLOB;
1269     else
1270         This->flags &= ~REG_GLOB;
1271     return S_OK;
1272 }
1273
1274 static HRESULT WINAPI RegExp2_get_Multiline(IRegExp2 *iface, VARIANT_BOOL *pMultiline)
1275 {
1276     RegExp2 *This = impl_from_IRegExp2(iface);
1277
1278     TRACE("(%p)->(%p)\n", This, pMultiline);
1279
1280     if(!pMultiline)
1281         return E_POINTER;
1282
1283     *pMultiline = This->flags & REG_MULTILINE ? VARIANT_TRUE : VARIANT_FALSE;
1284     return S_OK;
1285 }
1286
1287 static HRESULT WINAPI RegExp2_put_Multiline(IRegExp2 *iface, VARIANT_BOOL multiline)
1288 {
1289     RegExp2 *This = impl_from_IRegExp2(iface);
1290
1291     TRACE("(%p)->(%s)\n", This, multiline ? "true" : "false");
1292
1293     if(multiline)
1294         This->flags |= REG_MULTILINE;
1295     else
1296         This->flags &= ~REG_MULTILINE;
1297     return S_OK;
1298 }
1299
1300 static HRESULT WINAPI RegExp2_Execute(IRegExp2 *iface,
1301         BSTR sourceString, IDispatch **ppMatches)
1302 {
1303     RegExp2 *This = impl_from_IRegExp2(iface);
1304     match_state_t *result;
1305     const WCHAR *pos;
1306     IMatchCollection2 *match_collection;
1307     IMatch2 *add = NULL;
1308     HRESULT hres;
1309
1310     TRACE("(%p)->(%s %p)\n", This, debugstr_w(sourceString), ppMatches);
1311
1312     if(!This->pattern) {
1313         DWORD i, len = SysStringLen(sourceString);
1314
1315         hres = create_match_collection2(&match_collection);
1316         if(FAILED(hres))
1317             return hres;
1318
1319         for(i=0; i<=len; i++) {
1320             hres = create_match2(i, NULL, &add);
1321             if(FAILED(hres))
1322                 break;
1323
1324             hres = add_match(match_collection, add);
1325             if(FAILED(hres))
1326                 break;
1327             IMatch2_Release(add);
1328
1329             if(!(This->flags & REG_GLOB))
1330                 break;
1331         }
1332
1333         if(FAILED(hres)) {
1334             IMatchCollection2_Release(match_collection);
1335             return hres;
1336         }
1337
1338         *ppMatches = (IDispatch*)match_collection;
1339         return S_OK;
1340     }
1341
1342     if(!This->regexp) {
1343         This->regexp = regexp_new(NULL, &This->pool, This->pattern,
1344                 strlenW(This->pattern), This->flags, FALSE);
1345         if(!This->regexp)
1346             return E_FAIL;
1347     }else {
1348         hres = regexp_set_flags(&This->regexp, NULL, &This->pool, This->flags);
1349         if(FAILED(hres))
1350             return hres;
1351     }
1352
1353     hres = create_match_collection2(&match_collection);
1354     if(FAILED(hres))
1355         return hres;
1356
1357     pos = sourceString;
1358     while(1) {
1359         result = alloc_match_state(This->regexp, NULL, pos);
1360         if(!result) {
1361             hres = E_OUTOFMEMORY;
1362             break;
1363         }
1364
1365         hres = regexp_execute(This->regexp, NULL, &This->pool,
1366                 sourceString, SysStringLen(sourceString), result);
1367         if(hres != S_OK) {
1368             heap_free(result);
1369             break;
1370         }
1371         pos = result->cp;
1372
1373         hres = create_match2(result->cp-result->match_len-sourceString, &result, &add);
1374         heap_free(result);
1375         if(FAILED(hres))
1376             break;
1377         hres = add_match(match_collection, add);
1378         IMatch2_Release(add);
1379         if(FAILED(hres))
1380             break;
1381
1382         if(!(This->flags & REG_GLOB))
1383             break;
1384     }
1385
1386     if(FAILED(hres)) {
1387         IMatchCollection2_Release(match_collection);
1388         return hres;
1389     }
1390
1391     *ppMatches = (IDispatch*)match_collection;
1392     return S_OK;
1393 }
1394
1395 static HRESULT WINAPI RegExp2_Test(IRegExp2 *iface, BSTR sourceString, VARIANT_BOOL *pMatch)
1396 {
1397     RegExp2 *This = impl_from_IRegExp2(iface);
1398     match_state_t *result;
1399     heap_pool_t *mark;
1400     HRESULT hres;
1401
1402     TRACE("(%p)->(%s %p)\n", This, debugstr_w(sourceString), pMatch);
1403
1404     if(!This->pattern) {
1405         *pMatch = VARIANT_TRUE;
1406         return S_OK;
1407     }
1408
1409     if(!This->regexp) {
1410         This->regexp = regexp_new(NULL, &This->pool, This->pattern,
1411                 strlenW(This->pattern), This->flags, FALSE);
1412         if(!This->regexp)
1413             return E_FAIL;
1414     }else {
1415         hres = regexp_set_flags(&This->regexp, NULL, &This->pool, This->flags);
1416         if(FAILED(hres))
1417             return hres;
1418     }
1419
1420     mark = heap_pool_mark(&This->pool);
1421     result = alloc_match_state(This->regexp, &This->pool, sourceString);
1422     if(!result) {
1423         heap_pool_clear(mark);
1424         return E_OUTOFMEMORY;
1425     }
1426
1427     hres = regexp_execute(This->regexp, NULL, &This->pool,
1428             sourceString, SysStringLen(sourceString), result);
1429
1430     heap_pool_clear(mark);
1431
1432     if(hres == S_OK) {
1433         *pMatch = VARIANT_TRUE;
1434     }else if(hres == S_FALSE) {
1435         *pMatch = VARIANT_FALSE;
1436         hres = S_OK;
1437     }
1438     return hres;
1439 }
1440
1441 static HRESULT WINAPI RegExp2_Replace(IRegExp2 *iface, BSTR sourceString,
1442         VARIANT replaceVar, BSTR *pDestString)
1443 {
1444     RegExp2 *This = impl_from_IRegExp2(iface);
1445     FIXME("(%p)->(%s %s %p)\n", This, debugstr_w(sourceString),
1446             debugstr_variant(&replaceVar), pDestString);
1447     return E_NOTIMPL;
1448 }
1449
1450 static const IRegExp2Vtbl RegExp2Vtbl = {
1451     RegExp2_QueryInterface,
1452     RegExp2_AddRef,
1453     RegExp2_Release,
1454     RegExp2_GetTypeInfoCount,
1455     RegExp2_GetTypeInfo,
1456     RegExp2_GetIDsOfNames,
1457     RegExp2_Invoke,
1458     RegExp2_get_Pattern,
1459     RegExp2_put_Pattern,
1460     RegExp2_get_IgnoreCase,
1461     RegExp2_put_IgnoreCase,
1462     RegExp2_get_Global,
1463     RegExp2_put_Global,
1464     RegExp2_get_Multiline,
1465     RegExp2_put_Multiline,
1466     RegExp2_Execute,
1467     RegExp2_Test,
1468     RegExp2_Replace
1469 };
1470
1471 static inline RegExp2 *impl_from_IRegExp(IRegExp *iface)
1472 {
1473     return CONTAINING_RECORD(iface, RegExp2, IRegExp_iface);
1474 }
1475
1476 static HRESULT WINAPI RegExp_QueryInterface(IRegExp *iface, REFIID riid, void **ppv)
1477 {
1478     RegExp2 *This = impl_from_IRegExp(iface);
1479     return IRegExp2_QueryInterface(&This->IRegExp2_iface, riid, ppv);
1480 }
1481
1482 static ULONG WINAPI RegExp_AddRef(IRegExp *iface)
1483 {
1484     RegExp2 *This = impl_from_IRegExp(iface);
1485     return IRegExp2_AddRef(&This->IRegExp2_iface);
1486 }
1487
1488 static ULONG WINAPI RegExp_Release(IRegExp *iface)
1489 {
1490     RegExp2 *This = impl_from_IRegExp(iface);
1491     return IRegExp2_Release(&This->IRegExp2_iface);
1492 }
1493
1494 static HRESULT WINAPI RegExp_GetTypeInfoCount(IRegExp *iface, UINT *pctinfo)
1495 {
1496     RegExp2 *This = impl_from_IRegExp(iface);
1497     return IRegExp2_GetTypeInfoCount(&This->IRegExp2_iface, pctinfo);
1498 }
1499
1500 static HRESULT WINAPI RegExp_GetTypeInfo(IRegExp *iface,
1501         UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
1502 {
1503     RegExp2 *This = impl_from_IRegExp(iface);
1504     return IRegExp2_GetTypeInfo(&This->IRegExp2_iface, iTInfo, lcid, ppTInfo);
1505 }
1506
1507 static HRESULT WINAPI RegExp_GetIDsOfNames(IRegExp *iface, REFIID riid,
1508         LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
1509 {
1510     RegExp2 *This = impl_from_IRegExp(iface);
1511     return IRegExp2_GetIDsOfNames(&This->IRegExp2_iface, riid, rgszNames, cNames, lcid, rgDispId);
1512 }
1513
1514 static HRESULT WINAPI RegExp_Invoke(IRegExp *iface, DISPID dispIdMember,
1515         REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
1516                 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1517 {
1518     RegExp2 *This = impl_from_IRegExp(iface);
1519     return IRegExp2_Invoke(&This->IRegExp2_iface, dispIdMember, riid, lcid,
1520             wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1521 }
1522
1523 static HRESULT WINAPI RegExp_get_Pattern(IRegExp *iface, BSTR *pPattern)
1524 {
1525     RegExp2 *This = impl_from_IRegExp(iface);
1526     return IRegExp2_get_Pattern(&This->IRegExp2_iface, pPattern);
1527 }
1528
1529 static HRESULT WINAPI RegExp_put_Pattern(IRegExp *iface, BSTR pPattern)
1530 {
1531     RegExp2 *This = impl_from_IRegExp(iface);
1532     return IRegExp2_put_Pattern(&This->IRegExp2_iface, pPattern);
1533 }
1534
1535 static HRESULT WINAPI RegExp_get_IgnoreCase(IRegExp *iface, VARIANT_BOOL *pIgnoreCase)
1536 {
1537     RegExp2 *This = impl_from_IRegExp(iface);
1538     return IRegExp2_get_IgnoreCase(&This->IRegExp2_iface, pIgnoreCase);
1539 }
1540
1541 static HRESULT WINAPI RegExp_put_IgnoreCase(IRegExp *iface, VARIANT_BOOL pIgnoreCase)
1542 {
1543     RegExp2 *This = impl_from_IRegExp(iface);
1544     return IRegExp2_put_IgnoreCase(&This->IRegExp2_iface, pIgnoreCase);
1545 }
1546
1547 static HRESULT WINAPI RegExp_get_Global(IRegExp *iface, VARIANT_BOOL *pGlobal)
1548 {
1549     RegExp2 *This = impl_from_IRegExp(iface);
1550     return IRegExp2_get_Global(&This->IRegExp2_iface, pGlobal);
1551 }
1552
1553 static HRESULT WINAPI RegExp_put_Global(IRegExp *iface, VARIANT_BOOL pGlobal)
1554 {
1555     RegExp2 *This = impl_from_IRegExp(iface);
1556     return IRegExp2_put_Global(&This->IRegExp2_iface, pGlobal);
1557 }
1558
1559 static HRESULT WINAPI RegExp_Execute(IRegExp *iface,
1560         BSTR sourceString, IDispatch **ppMatches)
1561 {
1562     RegExp2 *This = impl_from_IRegExp(iface);
1563     return IRegExp2_Execute(&This->IRegExp2_iface, sourceString, ppMatches);
1564 }
1565
1566 static HRESULT WINAPI RegExp_Test(IRegExp *iface, BSTR sourceString, VARIANT_BOOL *pMatch)
1567 {
1568     RegExp2 *This = impl_from_IRegExp(iface);
1569     return IRegExp2_Test(&This->IRegExp2_iface, sourceString, pMatch);
1570 }
1571
1572 static HRESULT WINAPI RegExp_Replace(IRegExp *iface, BSTR sourceString,
1573         BSTR replaceString, BSTR *pDestString)
1574 {
1575     RegExp2 *This = impl_from_IRegExp(iface);
1576     VARIANT replace;
1577
1578     V_VT(&replace) = VT_BSTR;
1579     V_BSTR(&replace) = replaceString;
1580     return IRegExp2_Replace(&This->IRegExp2_iface, sourceString, replace, pDestString);
1581 }
1582
1583 static IRegExpVtbl RegExpVtbl = {
1584     RegExp_QueryInterface,
1585     RegExp_AddRef,
1586     RegExp_Release,
1587     RegExp_GetTypeInfoCount,
1588     RegExp_GetTypeInfo,
1589     RegExp_GetIDsOfNames,
1590     RegExp_Invoke,
1591     RegExp_get_Pattern,
1592     RegExp_put_Pattern,
1593     RegExp_get_IgnoreCase,
1594     RegExp_put_IgnoreCase,
1595     RegExp_get_Global,
1596     RegExp_put_Global,
1597     RegExp_Execute,
1598     RegExp_Test,
1599     RegExp_Replace
1600 };
1601
1602 HRESULT WINAPI VBScriptRegExpFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter, REFIID riid, void **ppv)
1603 {
1604     RegExp2 *ret;
1605     HRESULT hres;
1606
1607     TRACE("(%p %s %p)\n", pUnkOuter, debugstr_guid(riid), ppv);
1608
1609     hres = init_regexp_typeinfo(RegExp2_tid);
1610     if(FAILED(hres))
1611         return hres;
1612
1613     ret = heap_alloc_zero(sizeof(*ret));
1614     if(!ret)
1615         return E_OUTOFMEMORY;
1616
1617     ret->IRegExp2_iface.lpVtbl = &RegExp2Vtbl;
1618     ret->IRegExp_iface.lpVtbl = &RegExpVtbl;
1619
1620     ret->ref = 1;
1621     heap_pool_init(&ret->pool);
1622
1623     hres = IRegExp2_QueryInterface(&ret->IRegExp2_iface, riid, ppv);
1624     IRegExp2_Release(&ret->IRegExp2_iface);
1625     return hres;
1626 }
1627
1628 void release_regexp_typelib(void)
1629 {
1630     DWORD i;
1631
1632     for(i=0; i<REGEXP_LAST_tid; i++) {
1633         if(typeinfos[i])
1634             ITypeInfo_Release(typeinfos[i]);
1635     }
1636     if(typelib)
1637         ITypeLib_Release(typelib);
1638 }