wined3d: Optimize scanning for changed state in wined3d_stateblock_capture().
[wine.git] / dlls / vbscript / vbregexp.c
blob60c99772d3dc773bd8104f0c4b23ae70e6a49f97
1 /*
2 * Copyright 2013 Piotr Caban for CodeWeavers
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.
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.
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
19 #include "vbscript.h"
20 #include "regexp.h"
21 #include "vbsregexp55.h"
22 #include "wchar.h"
24 #include "wine/debug.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
28 #define REGEXP_TID_LIST \
29 XDIID(RegExp2), \
30 XDIID(Match2), \
31 XDIID(MatchCollection2), \
32 XDIID(SubMatches)
34 typedef enum {
35 #define XDIID(iface) iface ## _tid
36 REGEXP_TID_LIST,
37 #undef XDIID
38 REGEXP_LAST_tid
39 } regexp_tid_t;
41 static REFIID tid_ids[] = {
42 #define XDIID(iface) &IID_I ## iface
43 REGEXP_TID_LIST
44 #undef XDIID
47 static ITypeLib *typelib;
48 static ITypeInfo *typeinfos[REGEXP_LAST_tid];
50 static HRESULT init_regexp_typeinfo(regexp_tid_t tid)
52 HRESULT hres;
54 if(!typelib) {
55 static const WCHAR vbscript_dll3W[] = {'v','b','s','c','r','i','p','t','.','d','l','l','\\','3',0};
56 ITypeLib *tl;
58 hres = LoadTypeLib(vbscript_dll3W, &tl);
59 if(FAILED(hres)) {
60 ERR("LoadRegTypeLib failed: %08x\n", hres);
61 return hres;
64 if(InterlockedCompareExchangePointer((void**)&typelib, tl, NULL))
65 ITypeLib_Release(tl);
68 if(!typeinfos[tid]) {
69 ITypeInfo *ti;
71 hres = ITypeLib_GetTypeInfoOfGuid(typelib, tid_ids[tid], &ti);
72 if(FAILED(hres)) {
73 ERR("GetTypeInfoOfGuid(%s) failed: %08x\n", debugstr_guid(tid_ids[tid]), hres);
74 return hres;
77 if(InterlockedCompareExchangePointer((void**)(typeinfos+tid), ti, NULL))
78 ITypeInfo_Release(ti);
81 return S_OK;
84 struct SubMatches {
85 ISubMatches ISubMatches_iface;
87 LONG ref;
89 WCHAR *match;
90 match_state_t *result;
93 typedef struct Match2 {
94 IMatch2 IMatch2_iface;
95 IMatch IMatch_iface;
97 LONG ref;
99 DWORD index;
100 SubMatches *sub_matches;
101 } Match2;
103 typedef struct MatchCollectionEnum {
104 IEnumVARIANT IEnumVARIANT_iface;
106 LONG ref;
108 IMatchCollection2 *mc;
109 LONG pos;
110 LONG count;
111 } MatchCollectionEnum;
113 typedef struct MatchCollection2 {
114 IMatchCollection2 IMatchCollection2_iface;
115 IMatchCollection IMatchCollection_iface;
117 LONG ref;
119 IMatch2 **matches;
120 DWORD count;
121 DWORD size;
122 } MatchCollection2;
124 typedef struct RegExp2 {
125 IRegExp2 IRegExp2_iface;
126 IRegExp IRegExp_iface;
128 LONG ref;
130 WCHAR *pattern;
131 regexp_t *regexp;
132 heap_pool_t pool;
133 WORD flags;
134 } RegExp2;
136 static inline SubMatches* impl_from_ISubMatches(ISubMatches *iface)
138 return CONTAINING_RECORD(iface, SubMatches, ISubMatches_iface);
141 static HRESULT WINAPI SubMatches_QueryInterface(
142 ISubMatches *iface, REFIID riid, void **ppv)
144 SubMatches *This = impl_from_ISubMatches(iface);
146 if(IsEqualGUID(riid, &IID_IUnknown)) {
147 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
148 *ppv = &This->ISubMatches_iface;
149 }else if(IsEqualGUID(riid, &IID_IDispatch)) {
150 TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
151 *ppv = &This->ISubMatches_iface;
152 }else if(IsEqualGUID(riid, &IID_ISubMatches)) {
153 TRACE("(%p)->(IID_ISubMatches %p)\n", This, ppv);
154 *ppv = &This->ISubMatches_iface;
155 }else if(IsEqualGUID(riid, &IID_IDispatchEx)) {
156 TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
157 *ppv = NULL;
158 return E_NOINTERFACE;
159 }else {
160 FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
161 *ppv = NULL;
162 return E_NOINTERFACE;
165 IUnknown_AddRef((IUnknown*)*ppv);
166 return S_OK;
169 static ULONG WINAPI SubMatches_AddRef(ISubMatches *iface)
171 SubMatches *This = impl_from_ISubMatches(iface);
172 LONG ref = InterlockedIncrement(&This->ref);
174 TRACE("(%p) ref=%d\n", This, ref);
176 return ref;
179 static ULONG WINAPI SubMatches_Release(ISubMatches *iface)
181 SubMatches *This = impl_from_ISubMatches(iface);
182 LONG ref = InterlockedDecrement(&This->ref);
184 TRACE("(%p) ref=%d\n", This, ref);
186 if(!ref) {
187 heap_free(This->match);
188 heap_free(This->result);
189 heap_free(This);
192 return ref;
195 static HRESULT WINAPI SubMatches_GetTypeInfoCount(ISubMatches *iface, UINT *pctinfo)
197 SubMatches *This = impl_from_ISubMatches(iface);
199 TRACE("(%p)->(%p)\n", This, pctinfo);
201 *pctinfo = 1;
202 return S_OK;
205 static HRESULT WINAPI SubMatches_GetTypeInfo(ISubMatches *iface,
206 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
208 SubMatches *This = impl_from_ISubMatches(iface);
209 FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
210 return E_NOTIMPL;
213 static HRESULT WINAPI SubMatches_GetIDsOfNames(ISubMatches *iface,
214 REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
216 SubMatches *This = impl_from_ISubMatches(iface);
218 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid),
219 rgszNames, cNames, lcid, rgDispId);
221 return ITypeInfo_GetIDsOfNames(typeinfos[SubMatches_tid], rgszNames, cNames, rgDispId);
224 static HRESULT WINAPI SubMatches_Invoke(ISubMatches *iface, DISPID dispIdMember,
225 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
226 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
228 SubMatches *This = impl_from_ISubMatches(iface);
230 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
231 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
233 return ITypeInfo_Invoke(typeinfos[SubMatches_tid], iface, dispIdMember, wFlags,
234 pDispParams, pVarResult, pExcepInfo, puArgErr);
237 static HRESULT WINAPI SubMatches_get_Item(ISubMatches *iface,
238 LONG index, VARIANT *pSubMatch)
240 SubMatches *This = impl_from_ISubMatches(iface);
242 TRACE("(%p)->(%d %p)\n", This, index, pSubMatch);
244 if(!pSubMatch)
245 return E_POINTER;
247 if(!This->result || index<0 || index>=This->result->paren_count)
248 return E_INVALIDARG;
250 if(This->result->parens[index].index == -1) {
251 V_VT(pSubMatch) = VT_EMPTY;
252 }else {
253 V_VT(pSubMatch) = VT_BSTR;
254 V_BSTR(pSubMatch) = SysAllocStringLen(
255 This->match+This->result->parens[index].index,
256 This->result->parens[index].length);
258 if(!V_BSTR(pSubMatch))
259 return E_OUTOFMEMORY;
262 return S_OK;
265 static HRESULT WINAPI SubMatches_get_Count(ISubMatches *iface, LONG *pCount)
267 SubMatches *This = impl_from_ISubMatches(iface);
269 TRACE("(%p)->(%p)\n", This, pCount);
271 if(!pCount)
272 return E_POINTER;
274 if(!This->result)
275 *pCount = 0;
276 else
277 *pCount = This->result->paren_count;
278 return S_OK;
281 static HRESULT WINAPI SubMatches_get__NewEnum(ISubMatches *iface, IUnknown **ppEnum)
283 SubMatches *This = impl_from_ISubMatches(iface);
284 FIXME("(%p)->(%p)\n", This, ppEnum);
285 return E_NOTIMPL;
288 static const ISubMatchesVtbl SubMatchesVtbl = {
289 SubMatches_QueryInterface,
290 SubMatches_AddRef,
291 SubMatches_Release,
292 SubMatches_GetTypeInfoCount,
293 SubMatches_GetTypeInfo,
294 SubMatches_GetIDsOfNames,
295 SubMatches_Invoke,
296 SubMatches_get_Item,
297 SubMatches_get_Count,
298 SubMatches_get__NewEnum
301 static HRESULT create_sub_matches(DWORD pos, match_state_t *result, SubMatches **sub_matches)
303 SubMatches *ret;
304 DWORD i;
305 HRESULT hres;
307 hres = init_regexp_typeinfo(SubMatches_tid);
308 if(FAILED(hres))
309 return hres;
311 ret = heap_alloc_zero(sizeof(*ret));
312 if(!ret)
313 return E_OUTOFMEMORY;
315 ret->ISubMatches_iface.lpVtbl = &SubMatchesVtbl;
317 ret->result = result;
318 if(result) {
319 ret->match = heap_alloc((result->match_len+1) * sizeof(WCHAR));
320 if(!ret->match) {
321 heap_free(ret);
322 return E_OUTOFMEMORY;
324 memcpy(ret->match, result->cp-result->match_len, result->match_len*sizeof(WCHAR));
325 ret->match[result->match_len] = 0;
327 result->cp = NULL;
328 for(i=0; i<result->paren_count; i++)
329 if(result->parens[i].index != -1)
330 result->parens[i].index -= pos;
331 }else {
332 ret->match = NULL;
335 ret->ref = 1;
336 *sub_matches = ret;
337 return hres;
340 static inline Match2* impl_from_IMatch2(IMatch2 *iface)
342 return CONTAINING_RECORD(iface, Match2, IMatch2_iface);
345 static HRESULT WINAPI Match2_QueryInterface(
346 IMatch2 *iface, REFIID riid, void **ppv)
348 Match2 *This = impl_from_IMatch2(iface);
350 if(IsEqualGUID(riid, &IID_IUnknown)) {
351 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
352 *ppv = &This->IMatch2_iface;
353 }else if(IsEqualGUID(riid, &IID_IDispatch)) {
354 TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
355 *ppv = &This->IMatch2_iface;
356 }else if(IsEqualGUID(riid, &IID_IMatch2)) {
357 TRACE("(%p)->(IID_IMatch2 %p)\n", This, ppv);
358 *ppv = &This->IMatch2_iface;
359 }else if(IsEqualGUID(riid, &IID_IMatch)) {
360 TRACE("(%p)->(IID_IMatch %p)\n", This, ppv);
361 *ppv = &This->IMatch_iface;
362 }else if(IsEqualGUID(riid, &IID_IDispatchEx)) {
363 TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
364 *ppv = NULL;
365 return E_NOINTERFACE;
366 }else {
367 FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
368 *ppv = NULL;
369 return E_NOINTERFACE;
372 IUnknown_AddRef((IUnknown*)*ppv);
373 return S_OK;
376 static ULONG WINAPI Match2_AddRef(IMatch2 *iface)
378 Match2 *This = impl_from_IMatch2(iface);
379 LONG ref = InterlockedIncrement(&This->ref);
381 TRACE("(%p) ref=%d\n", This, ref);
383 return ref;
386 static ULONG WINAPI Match2_Release(IMatch2 *iface)
388 Match2 *This = impl_from_IMatch2(iface);
389 LONG ref = InterlockedDecrement(&This->ref);
391 TRACE("(%p) ref=%d\n", This, ref);
393 if(!ref) {
394 ISubMatches_Release(&This->sub_matches->ISubMatches_iface);
395 heap_free(This);
398 return ref;
401 static HRESULT WINAPI Match2_GetTypeInfoCount(IMatch2 *iface, UINT *pctinfo)
403 Match2 *This = impl_from_IMatch2(iface);
405 TRACE("(%p)->(%p)\n", This, pctinfo);
407 *pctinfo = 1;
408 return S_OK;
411 static HRESULT WINAPI Match2_GetTypeInfo(IMatch2 *iface,
412 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
414 Match2 *This = impl_from_IMatch2(iface);
415 FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
416 return E_NOTIMPL;
419 static HRESULT WINAPI Match2_GetIDsOfNames(IMatch2 *iface,
420 REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
422 Match2 *This = impl_from_IMatch2(iface);
424 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid),
425 rgszNames, cNames, lcid, rgDispId);
427 return ITypeInfo_GetIDsOfNames(typeinfos[Match2_tid], rgszNames, cNames, rgDispId);
430 static HRESULT WINAPI Match2_Invoke(IMatch2 *iface, DISPID dispIdMember,
431 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
432 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
434 Match2 *This = impl_from_IMatch2(iface);
436 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
437 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
439 return ITypeInfo_Invoke(typeinfos[Match2_tid], iface, dispIdMember, wFlags,
440 pDispParams, pVarResult, pExcepInfo, puArgErr);
443 static HRESULT WINAPI Match2_get_Value(IMatch2 *iface, BSTR *pValue)
445 Match2 *This = impl_from_IMatch2(iface);
447 TRACE("(%p)->(%p)\n", This, pValue);
449 if(!pValue)
450 return E_POINTER;
452 if(!This->sub_matches->match) {
453 *pValue = NULL;
454 return S_OK;
457 *pValue = SysAllocString(This->sub_matches->match);
458 return *pValue ? S_OK : E_OUTOFMEMORY;
461 static HRESULT WINAPI Match2_get_FirstIndex(IMatch2 *iface, LONG *pFirstIndex)
463 Match2 *This = impl_from_IMatch2(iface);
465 TRACE("(%p)->(%p)\n", This, pFirstIndex);
467 if(!pFirstIndex)
468 return E_POINTER;
470 *pFirstIndex = This->index;
471 return S_OK;
474 static HRESULT WINAPI Match2_get_Length(IMatch2 *iface, LONG *pLength)
476 Match2 *This = impl_from_IMatch2(iface);
478 TRACE("(%p)->(%p)\n", This, pLength);
480 if(!pLength)
481 return E_POINTER;
483 if(This->sub_matches->result)
484 *pLength = This->sub_matches->result->match_len;
485 else
486 *pLength = 0;
487 return S_OK;
490 static HRESULT WINAPI Match2_get_SubMatches(IMatch2 *iface, IDispatch **ppSubMatches)
492 Match2 *This = impl_from_IMatch2(iface);
494 TRACE("(%p)->(%p)\n", This, ppSubMatches);
496 if(!ppSubMatches)
497 return E_POINTER;
499 *ppSubMatches = (IDispatch*)&This->sub_matches->ISubMatches_iface;
500 ISubMatches_AddRef(&This->sub_matches->ISubMatches_iface);
501 return S_OK;
504 static const IMatch2Vtbl Match2Vtbl = {
505 Match2_QueryInterface,
506 Match2_AddRef,
507 Match2_Release,
508 Match2_GetTypeInfoCount,
509 Match2_GetTypeInfo,
510 Match2_GetIDsOfNames,
511 Match2_Invoke,
512 Match2_get_Value,
513 Match2_get_FirstIndex,
514 Match2_get_Length,
515 Match2_get_SubMatches
518 static inline Match2 *impl_from_IMatch(IMatch *iface)
520 return CONTAINING_RECORD(iface, Match2, IMatch_iface);
523 static HRESULT WINAPI Match_QueryInterface(IMatch *iface, REFIID riid, void **ppv)
525 Match2 *This = impl_from_IMatch(iface);
526 return IMatch2_QueryInterface(&This->IMatch2_iface, riid, ppv);
529 static ULONG WINAPI Match_AddRef(IMatch *iface)
531 Match2 *This = impl_from_IMatch(iface);
532 return IMatch2_AddRef(&This->IMatch2_iface);
535 static ULONG WINAPI Match_Release(IMatch *iface)
537 Match2 *This = impl_from_IMatch(iface);
538 return IMatch2_Release(&This->IMatch2_iface);
541 static HRESULT WINAPI Match_GetTypeInfoCount(IMatch *iface, UINT *pctinfo)
543 Match2 *This = impl_from_IMatch(iface);
544 return IMatch2_GetTypeInfoCount(&This->IMatch2_iface, pctinfo);
547 static HRESULT WINAPI Match_GetTypeInfo(IMatch *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
549 Match2 *This = impl_from_IMatch(iface);
550 return IMatch2_GetTypeInfo(&This->IMatch2_iface, iTInfo, lcid, ppTInfo);
553 static HRESULT WINAPI Match_GetIDsOfNames(IMatch *iface, REFIID riid,
554 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
556 Match2 *This = impl_from_IMatch(iface);
557 return IMatch2_GetIDsOfNames(&This->IMatch2_iface, riid, rgszNames, cNames, lcid, rgDispId);
560 static HRESULT WINAPI Match_Invoke(IMatch *iface, DISPID dispIdMember,
561 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
562 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
564 Match2 *This = impl_from_IMatch(iface);
565 return IMatch2_Invoke(&This->IMatch2_iface, dispIdMember, riid, lcid,
566 wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
569 static HRESULT WINAPI Match_get_Value(IMatch *iface, BSTR *pValue)
571 Match2 *This = impl_from_IMatch(iface);
572 return IMatch2_get_Value(&This->IMatch2_iface, pValue);
575 static HRESULT WINAPI Match_get_FirstIndex(IMatch *iface, LONG *pFirstIndex)
577 Match2 *This = impl_from_IMatch(iface);
578 return IMatch2_get_FirstIndex(&This->IMatch2_iface, pFirstIndex);
581 static HRESULT WINAPI Match_get_Length(IMatch *iface, LONG *pLength)
583 Match2 *This = impl_from_IMatch(iface);
584 return IMatch2_get_Length(&This->IMatch2_iface, pLength);
587 static IMatchVtbl MatchVtbl = {
588 Match_QueryInterface,
589 Match_AddRef,
590 Match_Release,
591 Match_GetTypeInfoCount,
592 Match_GetTypeInfo,
593 Match_GetIDsOfNames,
594 Match_Invoke,
595 Match_get_Value,
596 Match_get_FirstIndex,
597 Match_get_Length
600 static HRESULT create_match2(DWORD pos, match_state_t **result, IMatch2 **match)
602 Match2 *ret;
603 HRESULT hres;
605 hres = init_regexp_typeinfo(Match2_tid);
606 if(FAILED(hres))
607 return hres;
609 ret = heap_alloc_zero(sizeof(*ret));
610 if(!ret)
611 return E_OUTOFMEMORY;
613 ret->index = pos;
614 hres = create_sub_matches(pos, result ? *result : NULL, &ret->sub_matches);
615 if(FAILED(hres)) {
616 heap_free(ret);
617 return hres;
619 if(result)
620 *result = NULL;
622 ret->IMatch2_iface.lpVtbl = &Match2Vtbl;
623 ret->IMatch_iface.lpVtbl = &MatchVtbl;
625 ret->ref = 1;
626 *match = &ret->IMatch2_iface;
627 return hres;
630 static inline MatchCollectionEnum* impl_from_IMatchCollectionEnum(IEnumVARIANT *iface)
632 return CONTAINING_RECORD(iface, MatchCollectionEnum, IEnumVARIANT_iface);
635 static HRESULT WINAPI MatchCollectionEnum_QueryInterface(
636 IEnumVARIANT *iface, REFIID riid, void **ppv)
638 MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface);
640 if(IsEqualGUID(riid, &IID_IUnknown)) {
641 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
642 *ppv = &This->IEnumVARIANT_iface;
643 }else if(IsEqualGUID(riid, &IID_IEnumVARIANT)) {
644 TRACE("(%p)->(IID_IEnumVARIANT %p)\n", This, ppv);
645 *ppv = &This->IEnumVARIANT_iface;
646 }else {
647 FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
648 *ppv = NULL;
649 return E_NOINTERFACE;
652 IUnknown_AddRef((IUnknown*)*ppv);
653 return S_OK;
656 static ULONG WINAPI MatchCollectionEnum_AddRef(IEnumVARIANT *iface)
658 MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface);
659 LONG ref = InterlockedIncrement(&This->ref);
661 TRACE("(%p) ref=%d\n", This, ref);
663 return ref;
666 static ULONG WINAPI MatchCollectionEnum_Release(IEnumVARIANT *iface)
668 MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface);
669 LONG ref = InterlockedDecrement(&This->ref);
671 TRACE("(%p) ref=%d\n", This, ref);
673 if(!ref) {
674 IMatchCollection2_Release(This->mc);
675 heap_free(This);
678 return ref;
681 static HRESULT WINAPI MatchCollectionEnum_Next(IEnumVARIANT *iface,
682 ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched)
684 MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface);
685 DWORD i;
686 HRESULT hres = S_OK;
688 TRACE("(%p)->(%u %p %p)\n", This, celt, rgVar, pCeltFetched);
690 if(This->pos>=This->count) {
691 if(pCeltFetched)
692 *pCeltFetched = 0;
693 return S_FALSE;
696 for(i=0; i<celt && This->pos+i<This->count; i++) {
697 V_VT(rgVar+i) = VT_DISPATCH;
698 hres = IMatchCollection2_get_Item(This->mc, This->pos+i, &V_DISPATCH(rgVar+i));
699 if(FAILED(hres))
700 break;
702 if(FAILED(hres)) {
703 while(i--)
704 VariantClear(rgVar+i);
705 return hres;
708 if(pCeltFetched)
709 *pCeltFetched = i;
710 This->pos += i;
711 return S_OK;
714 static HRESULT WINAPI MatchCollectionEnum_Skip(IEnumVARIANT *iface, ULONG celt)
716 MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface);
718 TRACE("(%p)->(%u)\n", This, celt);
720 if(This->pos+celt <= This->count)
721 This->pos += celt;
722 else
723 This->pos = This->count;
724 return S_OK;
727 static HRESULT WINAPI MatchCollectionEnum_Reset(IEnumVARIANT *iface)
729 MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface);
731 TRACE("(%p)\n", This);
733 This->pos = 0;
734 return S_OK;
737 static HRESULT WINAPI MatchCollectionEnum_Clone(IEnumVARIANT *iface, IEnumVARIANT **ppEnum)
739 MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface);
740 FIXME("(%p)->(%p)\n", This, ppEnum);
741 return E_NOTIMPL;
744 static const IEnumVARIANTVtbl MatchCollectionEnum_Vtbl = {
745 MatchCollectionEnum_QueryInterface,
746 MatchCollectionEnum_AddRef,
747 MatchCollectionEnum_Release,
748 MatchCollectionEnum_Next,
749 MatchCollectionEnum_Skip,
750 MatchCollectionEnum_Reset,
751 MatchCollectionEnum_Clone
754 static HRESULT create_enum_variant_mc2(IMatchCollection2 *mc, ULONG pos, IEnumVARIANT **enum_variant)
756 MatchCollectionEnum *ret;
758 ret = heap_alloc_zero(sizeof(*ret));
759 if(!ret)
760 return E_OUTOFMEMORY;
762 ret->IEnumVARIANT_iface.lpVtbl = &MatchCollectionEnum_Vtbl;
763 ret->ref = 1;
764 ret->pos = pos;
765 IMatchCollection2_get_Count(mc, &ret->count);
766 ret->mc = mc;
767 IMatchCollection2_AddRef(mc);
769 *enum_variant = &ret->IEnumVARIANT_iface;
770 return S_OK;
773 static inline MatchCollection2* impl_from_IMatchCollection2(IMatchCollection2 *iface)
775 return CONTAINING_RECORD(iface, MatchCollection2, IMatchCollection2_iface);
778 static HRESULT WINAPI MatchCollection2_QueryInterface(
779 IMatchCollection2 *iface, REFIID riid, void **ppv)
781 MatchCollection2 *This = impl_from_IMatchCollection2(iface);
783 if(IsEqualGUID(riid, &IID_IUnknown)) {
784 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
785 *ppv = &This->IMatchCollection2_iface;
786 }else if(IsEqualGUID(riid, &IID_IDispatch)) {
787 TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
788 *ppv = &This->IMatchCollection2_iface;
789 }else if(IsEqualGUID(riid, &IID_IMatchCollection2)) {
790 TRACE("(%p)->(IID_IMatchCollection2 %p)\n", This, ppv);
791 *ppv = &This->IMatchCollection2_iface;
792 }else if(IsEqualGUID(riid, &IID_IMatchCollection)) {
793 TRACE("(%p)->(IID_IMatchCollection %p)\n", This, ppv);
794 *ppv = &This->IMatchCollection_iface;
795 }else if(IsEqualGUID(riid, &IID_IDispatchEx)) {
796 TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
797 *ppv = NULL;
798 return E_NOINTERFACE;
799 }else {
800 FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
801 *ppv = NULL;
802 return E_NOINTERFACE;
805 IUnknown_AddRef((IUnknown*)*ppv);
806 return S_OK;
809 static ULONG WINAPI MatchCollection2_AddRef(IMatchCollection2 *iface)
811 MatchCollection2 *This = impl_from_IMatchCollection2(iface);
812 LONG ref = InterlockedIncrement(&This->ref);
814 TRACE("(%p) ref=%d\n", This, ref);
816 return ref;
819 static ULONG WINAPI MatchCollection2_Release(IMatchCollection2 *iface)
821 MatchCollection2 *This = impl_from_IMatchCollection2(iface);
822 LONG ref = InterlockedDecrement(&This->ref);
824 TRACE("(%p) ref=%d\n", This, ref);
826 if(!ref) {
827 DWORD i;
829 for(i=0; i<This->count; i++)
830 IMatch2_Release(This->matches[i]);
831 heap_free(This->matches);
833 heap_free(This);
836 return ref;
839 static HRESULT WINAPI MatchCollection2_GetTypeInfoCount(IMatchCollection2 *iface, UINT *pctinfo)
841 MatchCollection2 *This = impl_from_IMatchCollection2(iface);
843 TRACE("(%p)->(%p)\n", This, pctinfo);
845 *pctinfo = 1;
846 return S_OK;
849 static HRESULT WINAPI MatchCollection2_GetTypeInfo(IMatchCollection2 *iface,
850 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
852 MatchCollection2 *This = impl_from_IMatchCollection2(iface);
853 FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
854 return E_NOTIMPL;
857 static HRESULT WINAPI MatchCollection2_GetIDsOfNames(IMatchCollection2 *iface,
858 REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
860 MatchCollection2 *This = impl_from_IMatchCollection2(iface);
862 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid),
863 rgszNames, cNames, lcid, rgDispId);
865 return ITypeInfo_GetIDsOfNames(typeinfos[MatchCollection2_tid], rgszNames, cNames, rgDispId);
868 static HRESULT WINAPI MatchCollection2_Invoke(IMatchCollection2 *iface, DISPID dispIdMember,
869 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
870 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
872 MatchCollection2 *This = impl_from_IMatchCollection2(iface);
874 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
875 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
877 return ITypeInfo_Invoke(typeinfos[MatchCollection2_tid], iface, dispIdMember, wFlags,
878 pDispParams, pVarResult, pExcepInfo, puArgErr);
881 static HRESULT WINAPI MatchCollection2_get_Item(IMatchCollection2 *iface,
882 LONG index, IDispatch **ppMatch)
884 MatchCollection2 *This = impl_from_IMatchCollection2(iface);
886 TRACE("(%p)->()\n", This);
888 if(!ppMatch)
889 return E_POINTER;
891 if(index<0 || index>=This->count)
892 return E_INVALIDARG;
894 *ppMatch = (IDispatch*)This->matches[index];
895 IMatch2_AddRef(This->matches[index]);
896 return S_OK;
899 static HRESULT WINAPI MatchCollection2_get_Count(IMatchCollection2 *iface, LONG *pCount)
901 MatchCollection2 *This = impl_from_IMatchCollection2(iface);
903 TRACE("(%p)->()\n", This);
905 if(!pCount)
906 return E_POINTER;
908 *pCount = This->count;
909 return S_OK;
912 static HRESULT WINAPI MatchCollection2_get__NewEnum(IMatchCollection2 *iface, IUnknown **ppEnum)
914 MatchCollection2 *This = impl_from_IMatchCollection2(iface);
916 TRACE("(%p)->(%p)\n", This, ppEnum);
918 if(!ppEnum)
919 return E_POINTER;
921 return create_enum_variant_mc2(&This->IMatchCollection2_iface, 0, (IEnumVARIANT**)ppEnum);
924 static const IMatchCollection2Vtbl MatchCollection2Vtbl = {
925 MatchCollection2_QueryInterface,
926 MatchCollection2_AddRef,
927 MatchCollection2_Release,
928 MatchCollection2_GetTypeInfoCount,
929 MatchCollection2_GetTypeInfo,
930 MatchCollection2_GetIDsOfNames,
931 MatchCollection2_Invoke,
932 MatchCollection2_get_Item,
933 MatchCollection2_get_Count,
934 MatchCollection2_get__NewEnum
937 static inline MatchCollection2 *impl_from_IMatchCollection(IMatchCollection *iface)
939 return CONTAINING_RECORD(iface, MatchCollection2, IMatchCollection_iface);
942 static HRESULT WINAPI MatchCollection_QueryInterface(IMatchCollection *iface, REFIID riid, void **ppv)
944 MatchCollection2 *This = impl_from_IMatchCollection(iface);
945 return IMatchCollection2_QueryInterface(&This->IMatchCollection2_iface, riid, ppv);
948 static ULONG WINAPI MatchCollection_AddRef(IMatchCollection *iface)
950 MatchCollection2 *This = impl_from_IMatchCollection(iface);
951 return IMatchCollection2_AddRef(&This->IMatchCollection2_iface);
954 static ULONG WINAPI MatchCollection_Release(IMatchCollection *iface)
956 MatchCollection2 *This = impl_from_IMatchCollection(iface);
957 return IMatchCollection2_Release(&This->IMatchCollection2_iface);
960 static HRESULT WINAPI MatchCollection_GetTypeInfoCount(IMatchCollection *iface, UINT *pctinfo)
962 MatchCollection2 *This = impl_from_IMatchCollection(iface);
963 return IMatchCollection2_GetTypeInfoCount(&This->IMatchCollection2_iface, pctinfo);
966 static HRESULT WINAPI MatchCollection_GetTypeInfo(IMatchCollection *iface,
967 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
969 MatchCollection2 *This = impl_from_IMatchCollection(iface);
970 return IMatchCollection2_GetTypeInfo(&This->IMatchCollection2_iface, iTInfo, lcid, ppTInfo);
973 static HRESULT WINAPI MatchCollection_GetIDsOfNames(IMatchCollection *iface, REFIID riid,
974 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
976 MatchCollection2 *This = impl_from_IMatchCollection(iface);
977 return IMatchCollection2_GetIDsOfNames(&This->IMatchCollection2_iface,
978 riid, rgszNames, cNames, lcid, rgDispId);
981 static HRESULT WINAPI MatchCollection_Invoke(IMatchCollection *iface, DISPID dispIdMember,
982 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
983 EXCEPINFO *pExcepInfo, UINT *puArgErr)
985 MatchCollection2 *This = impl_from_IMatchCollection(iface);
986 return IMatchCollection2_Invoke(&This->IMatchCollection2_iface, dispIdMember,
987 riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
990 static HRESULT WINAPI MatchCollection_get_Item(IMatchCollection *iface, LONG index, IDispatch **ppMatch)
992 MatchCollection2 *This = impl_from_IMatchCollection(iface);
993 return IMatchCollection2_get_Item(&This->IMatchCollection2_iface, index, ppMatch);
996 static HRESULT WINAPI MatchCollection_get_Count(IMatchCollection *iface, LONG *pCount)
998 MatchCollection2 *This = impl_from_IMatchCollection(iface);
999 return IMatchCollection2_get_Count(&This->IMatchCollection2_iface, pCount);
1002 static HRESULT WINAPI MatchCollection_get__NewEnum(IMatchCollection *iface, IUnknown **ppEnum)
1004 MatchCollection2 *This = impl_from_IMatchCollection(iface);
1005 return IMatchCollection2_get__NewEnum(&This->IMatchCollection2_iface, ppEnum);
1008 static const IMatchCollectionVtbl MatchCollectionVtbl = {
1009 MatchCollection_QueryInterface,
1010 MatchCollection_AddRef,
1011 MatchCollection_Release,
1012 MatchCollection_GetTypeInfoCount,
1013 MatchCollection_GetTypeInfo,
1014 MatchCollection_GetIDsOfNames,
1015 MatchCollection_Invoke,
1016 MatchCollection_get_Item,
1017 MatchCollection_get_Count,
1018 MatchCollection_get__NewEnum
1021 static HRESULT add_match(IMatchCollection2 *iface, IMatch2 *add)
1023 MatchCollection2 *This = impl_from_IMatchCollection2(iface);
1025 TRACE("(%p)->(%p)\n", This, add);
1027 if(!This->size) {
1028 This->matches = heap_alloc(8*sizeof(IMatch*));
1029 if(!This->matches)
1030 return E_OUTOFMEMORY;
1031 This->size = 8;
1032 }else if(This->size == This->count) {
1033 IMatch2 **new_matches = heap_realloc(This->matches, 2*This->size*sizeof(IMatch*));
1034 if(!new_matches)
1035 return E_OUTOFMEMORY;
1037 This->matches = new_matches;
1038 This->size <<= 1;
1041 This->matches[This->count++] = add;
1042 IMatch2_AddRef(add);
1043 return S_OK;
1046 static HRESULT create_match_collection2(IMatchCollection2 **match_collection)
1048 MatchCollection2 *ret;
1049 HRESULT hres;
1051 hres = init_regexp_typeinfo(MatchCollection2_tid);
1052 if(FAILED(hres))
1053 return hres;
1055 ret = heap_alloc_zero(sizeof(*ret));
1056 if(!ret)
1057 return E_OUTOFMEMORY;
1059 ret->IMatchCollection2_iface.lpVtbl = &MatchCollection2Vtbl;
1060 ret->IMatchCollection_iface.lpVtbl = &MatchCollectionVtbl;
1062 ret->ref = 1;
1063 *match_collection = &ret->IMatchCollection2_iface;
1064 return S_OK;
1067 static inline RegExp2 *impl_from_IRegExp2(IRegExp2 *iface)
1069 return CONTAINING_RECORD(iface, RegExp2, IRegExp2_iface);
1072 static HRESULT WINAPI RegExp2_QueryInterface(IRegExp2 *iface, REFIID riid, void **ppv)
1074 RegExp2 *This = impl_from_IRegExp2(iface);
1076 if(IsEqualGUID(riid, &IID_IUnknown)) {
1077 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
1078 *ppv = &This->IRegExp2_iface;
1079 }else if(IsEqualGUID(riid, &IID_IDispatch)) {
1080 TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
1081 *ppv = &This->IRegExp2_iface;
1082 }else if(IsEqualGUID(riid, &IID_IRegExp2)) {
1083 TRACE("(%p)->(IID_IRegExp2 %p)\n", This, ppv);
1084 *ppv = &This->IRegExp2_iface;
1085 }else if(IsEqualGUID(riid, &IID_IRegExp)) {
1086 TRACE("(%p)->(IID_IRegExp %p)\n", This, ppv);
1087 *ppv = &This->IRegExp_iface;
1088 }else if(IsEqualGUID(riid, &IID_IDispatchEx)) {
1089 TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
1090 *ppv = NULL;
1091 return E_NOINTERFACE;
1092 }else {
1093 FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
1094 *ppv = NULL;
1095 return E_NOINTERFACE;
1098 IUnknown_AddRef((IUnknown*)*ppv);
1099 return S_OK;
1102 static ULONG WINAPI RegExp2_AddRef(IRegExp2 *iface)
1104 RegExp2 *This = impl_from_IRegExp2(iface);
1105 LONG ref = InterlockedIncrement(&This->ref);
1107 TRACE("(%p) ref=%d\n", This, ref);
1109 return ref;
1112 static ULONG WINAPI RegExp2_Release(IRegExp2 *iface)
1114 RegExp2 *This = impl_from_IRegExp2(iface);
1115 LONG ref = InterlockedDecrement(&This->ref);
1117 TRACE("(%p) ref=%d\n", This, ref);
1119 if(!ref) {
1120 heap_free(This->pattern);
1121 if(This->regexp)
1122 regexp_destroy(This->regexp);
1123 heap_pool_free(&This->pool);
1124 heap_free(This);
1127 return ref;
1130 static HRESULT WINAPI RegExp2_GetTypeInfoCount(IRegExp2 *iface, UINT *pctinfo)
1132 RegExp2 *This = impl_from_IRegExp2(iface);
1134 TRACE("(%p)->(%p)\n", This, pctinfo);
1136 *pctinfo = 1;
1137 return S_OK;
1140 static HRESULT WINAPI RegExp2_GetTypeInfo(IRegExp2 *iface,
1141 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
1143 RegExp2 *This = impl_from_IRegExp2(iface);
1144 FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1145 return E_NOTIMPL;
1148 static HRESULT WINAPI RegExp2_GetIDsOfNames(IRegExp2 *iface, REFIID riid,
1149 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
1151 RegExp2 *This = impl_from_IRegExp2(iface);
1153 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid),
1154 rgszNames, cNames, lcid, rgDispId);
1156 return ITypeInfo_GetIDsOfNames(typeinfos[RegExp2_tid], rgszNames, cNames, rgDispId);
1159 static HRESULT WINAPI RegExp2_Invoke(IRegExp2 *iface, DISPID dispIdMember,
1160 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
1161 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1163 RegExp2 *This = impl_from_IRegExp2(iface);
1165 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1166 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1168 return ITypeInfo_Invoke(typeinfos[RegExp2_tid], iface, dispIdMember, wFlags,
1169 pDispParams, pVarResult, pExcepInfo, puArgErr);
1172 static HRESULT WINAPI RegExp2_get_Pattern(IRegExp2 *iface, BSTR *pPattern)
1174 RegExp2 *This = impl_from_IRegExp2(iface);
1176 TRACE("(%p)->(%p)\n", This, pPattern);
1178 if(!pPattern)
1179 return E_POINTER;
1181 if(!This->pattern) {
1182 *pPattern = NULL;
1183 return S_OK;
1186 *pPattern = SysAllocString(This->pattern);
1187 return *pPattern ? S_OK : E_OUTOFMEMORY;
1190 static HRESULT WINAPI RegExp2_put_Pattern(IRegExp2 *iface, BSTR pattern)
1192 RegExp2 *This = impl_from_IRegExp2(iface);
1193 WCHAR *new_pattern;
1195 TRACE("(%p)->(%s)\n", This, wine_dbgstr_w(pattern));
1197 if(pattern && *pattern) {
1198 SIZE_T size = (SysStringLen(pattern)+1) * sizeof(WCHAR);
1199 new_pattern = heap_alloc(size);
1200 if(!new_pattern)
1201 return E_OUTOFMEMORY;
1202 memcpy(new_pattern, pattern, size);
1203 }else {
1204 new_pattern = NULL;
1207 heap_free(This->pattern);
1208 This->pattern = new_pattern;
1210 if(This->regexp) {
1211 regexp_destroy(This->regexp);
1212 This->regexp = NULL;
1214 return S_OK;
1217 static HRESULT WINAPI RegExp2_get_IgnoreCase(IRegExp2 *iface, VARIANT_BOOL *pIgnoreCase)
1219 RegExp2 *This = impl_from_IRegExp2(iface);
1221 TRACE("(%p)->(%p)\n", This, pIgnoreCase);
1223 if(!pIgnoreCase)
1224 return E_POINTER;
1226 *pIgnoreCase = This->flags & REG_FOLD ? VARIANT_TRUE : VARIANT_FALSE;
1227 return S_OK;
1230 static HRESULT WINAPI RegExp2_put_IgnoreCase(IRegExp2 *iface, VARIANT_BOOL ignoreCase)
1232 RegExp2 *This = impl_from_IRegExp2(iface);
1234 TRACE("(%p)->(%s)\n", This, ignoreCase ? "true" : "false");
1236 if(ignoreCase)
1237 This->flags |= REG_FOLD;
1238 else
1239 This->flags &= ~REG_FOLD;
1240 return S_OK;
1243 static HRESULT WINAPI RegExp2_get_Global(IRegExp2 *iface, VARIANT_BOOL *pGlobal)
1245 RegExp2 *This = impl_from_IRegExp2(iface);
1247 TRACE("(%p)->(%p)\n", This, pGlobal);
1249 if(!pGlobal)
1250 return E_POINTER;
1252 *pGlobal = This->flags & REG_GLOB ? VARIANT_TRUE : VARIANT_FALSE;
1253 return S_OK;
1256 static HRESULT WINAPI RegExp2_put_Global(IRegExp2 *iface, VARIANT_BOOL global)
1258 RegExp2 *This = impl_from_IRegExp2(iface);
1260 TRACE("(%p)->(%s)\n", This, global ? "true" : "false");
1262 if(global)
1263 This->flags |= REG_GLOB;
1264 else
1265 This->flags &= ~REG_GLOB;
1266 return S_OK;
1269 static HRESULT WINAPI RegExp2_get_Multiline(IRegExp2 *iface, VARIANT_BOOL *pMultiline)
1271 RegExp2 *This = impl_from_IRegExp2(iface);
1273 TRACE("(%p)->(%p)\n", This, pMultiline);
1275 if(!pMultiline)
1276 return E_POINTER;
1278 *pMultiline = This->flags & REG_MULTILINE ? VARIANT_TRUE : VARIANT_FALSE;
1279 return S_OK;
1282 static HRESULT WINAPI RegExp2_put_Multiline(IRegExp2 *iface, VARIANT_BOOL multiline)
1284 RegExp2 *This = impl_from_IRegExp2(iface);
1286 TRACE("(%p)->(%s)\n", This, multiline ? "true" : "false");
1288 if(multiline)
1289 This->flags |= REG_MULTILINE;
1290 else
1291 This->flags &= ~REG_MULTILINE;
1292 return S_OK;
1295 static HRESULT WINAPI RegExp2_Execute(IRegExp2 *iface,
1296 BSTR sourceString, IDispatch **ppMatches)
1298 RegExp2 *This = impl_from_IRegExp2(iface);
1299 match_state_t *result;
1300 const WCHAR *pos;
1301 IMatchCollection2 *match_collection;
1302 IMatch2 *add = NULL;
1303 HRESULT hres;
1305 TRACE("(%p)->(%s %p)\n", This, debugstr_w(sourceString), ppMatches);
1307 if(!This->pattern) {
1308 DWORD i, len = SysStringLen(sourceString);
1310 hres = create_match_collection2(&match_collection);
1311 if(FAILED(hres))
1312 return hres;
1314 for(i=0; i<=len; i++) {
1315 hres = create_match2(i, NULL, &add);
1316 if(FAILED(hres))
1317 break;
1319 hres = add_match(match_collection, add);
1320 if(FAILED(hres))
1321 break;
1322 IMatch2_Release(add);
1324 if(!(This->flags & REG_GLOB))
1325 break;
1328 if(FAILED(hres)) {
1329 IMatchCollection2_Release(match_collection);
1330 return hres;
1333 *ppMatches = (IDispatch*)match_collection;
1334 return S_OK;
1337 if(!This->regexp) {
1338 This->regexp = regexp_new(NULL, &This->pool, This->pattern,
1339 lstrlenW(This->pattern), This->flags, FALSE);
1340 if(!This->regexp)
1341 return E_FAIL;
1342 }else {
1343 hres = regexp_set_flags(&This->regexp, NULL, &This->pool, This->flags);
1344 if(FAILED(hres))
1345 return hres;
1348 hres = create_match_collection2(&match_collection);
1349 if(FAILED(hres))
1350 return hres;
1352 pos = sourceString;
1353 while(1) {
1354 result = alloc_match_state(This->regexp, NULL, pos);
1355 if(!result) {
1356 hres = E_OUTOFMEMORY;
1357 break;
1360 hres = regexp_execute(This->regexp, NULL, &This->pool,
1361 sourceString, SysStringLen(sourceString), result);
1362 if(hres != S_OK) {
1363 heap_free(result);
1364 break;
1366 pos = result->cp;
1368 hres = create_match2(result->cp-result->match_len-sourceString, &result, &add);
1369 heap_free(result);
1370 if(FAILED(hres))
1371 break;
1372 hres = add_match(match_collection, add);
1373 IMatch2_Release(add);
1374 if(FAILED(hres))
1375 break;
1377 if(!(This->flags & REG_GLOB))
1378 break;
1381 if(FAILED(hres)) {
1382 IMatchCollection2_Release(match_collection);
1383 return hres;
1386 *ppMatches = (IDispatch*)match_collection;
1387 return S_OK;
1390 static HRESULT WINAPI RegExp2_Test(IRegExp2 *iface, BSTR sourceString, VARIANT_BOOL *pMatch)
1392 RegExp2 *This = impl_from_IRegExp2(iface);
1393 match_state_t *result;
1394 heap_pool_t *mark;
1395 HRESULT hres;
1397 TRACE("(%p)->(%s %p)\n", This, debugstr_w(sourceString), pMatch);
1399 if(!This->pattern) {
1400 *pMatch = VARIANT_TRUE;
1401 return S_OK;
1404 if(!This->regexp) {
1405 This->regexp = regexp_new(NULL, &This->pool, This->pattern,
1406 lstrlenW(This->pattern), This->flags, FALSE);
1407 if(!This->regexp)
1408 return E_FAIL;
1409 }else {
1410 hres = regexp_set_flags(&This->regexp, NULL, &This->pool, This->flags);
1411 if(FAILED(hres))
1412 return hres;
1415 mark = heap_pool_mark(&This->pool);
1416 result = alloc_match_state(This->regexp, &This->pool, sourceString);
1417 if(!result) {
1418 heap_pool_clear(mark);
1419 return E_OUTOFMEMORY;
1422 hres = regexp_execute(This->regexp, NULL, &This->pool,
1423 sourceString, SysStringLen(sourceString), result);
1425 heap_pool_clear(mark);
1427 if(hres == S_OK) {
1428 *pMatch = VARIANT_TRUE;
1429 }else if(hres == S_FALSE) {
1430 *pMatch = VARIANT_FALSE;
1431 hres = S_OK;
1433 return hres;
1436 typedef struct {
1437 WCHAR *buf;
1438 DWORD size;
1439 DWORD len;
1440 } strbuf_t;
1442 static BOOL strbuf_ensure_size(strbuf_t *buf, unsigned len)
1444 WCHAR *new_buf;
1445 DWORD new_size;
1447 if(len <= buf->size)
1448 return TRUE;
1450 new_size = buf->size ? buf->size<<1 : 16;
1451 if(new_size < len)
1452 new_size = len;
1453 if(buf->buf)
1454 new_buf = heap_realloc(buf->buf, new_size*sizeof(WCHAR));
1455 else
1456 new_buf = heap_alloc(new_size*sizeof(WCHAR));
1457 if(!new_buf)
1458 return FALSE;
1460 buf->buf = new_buf;
1461 buf->size = new_size;
1462 return TRUE;
1465 static HRESULT strbuf_append(strbuf_t *buf, const WCHAR *str, DWORD len)
1467 if(!len)
1468 return S_OK;
1470 if(!strbuf_ensure_size(buf, buf->len+len))
1471 return E_OUTOFMEMORY;
1473 memcpy(buf->buf+buf->len, str, len*sizeof(WCHAR));
1474 buf->len += len;
1475 return S_OK;
1478 static HRESULT WINAPI RegExp2_Replace(IRegExp2 *iface, BSTR source, VARIANT replaceVar, BSTR *ret)
1480 RegExp2 *This = impl_from_IRegExp2(iface);
1481 const WCHAR *cp, *prev_cp = NULL, *ptr, *prev_ptr;
1482 size_t match_len = 0, source_len, replace_len;
1483 strbuf_t buf = { NULL, 0, 0 };
1484 match_state_t *state = NULL;
1485 heap_pool_t *mark;
1486 VARIANT strv;
1487 BSTR replace;
1488 HRESULT hres;
1490 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(source), debugstr_variant(&replaceVar), ret);
1492 if(This->pattern) {
1493 if(!This->regexp) {
1494 This->regexp = regexp_new(NULL, &This->pool, This->pattern,
1495 lstrlenW(This->pattern), This->flags, FALSE);
1496 if(!This->regexp)
1497 return E_OUTOFMEMORY;
1498 }else {
1499 hres = regexp_set_flags(&This->regexp, NULL, &This->pool, This->flags);
1500 if(FAILED(hres))
1501 return hres;
1505 V_VT(&strv) = VT_EMPTY;
1506 hres = VariantChangeType(&strv, &replaceVar, 0, VT_BSTR);
1507 if(FAILED(hres))
1508 return hres;
1509 replace = V_BSTR(&strv);
1510 replace_len = SysStringLen(replace);
1511 source_len = SysStringLen(source);
1513 mark = heap_pool_mark(&This->pool);
1514 cp = source;
1515 if(This->regexp && !(state = alloc_match_state(This->regexp, &This->pool, cp)))
1516 hres = E_OUTOFMEMORY;
1518 while(SUCCEEDED(hres)) {
1519 if(This->regexp) {
1520 prev_cp = cp;
1521 hres = regexp_execute(This->regexp, NULL, &This->pool, source, source_len, state);
1522 if(hres != S_OK) break;
1523 cp = state->cp;
1524 match_len = state->match_len;
1525 }else if(prev_cp) {
1526 if(cp == source + source_len)
1527 break;
1528 prev_cp = cp++;
1529 }else {
1530 prev_cp = cp;
1533 hres = strbuf_append(&buf, prev_cp, cp - prev_cp - match_len);
1534 if(FAILED(hres))
1535 break;
1537 prev_ptr = replace;
1538 while((ptr = wmemchr(prev_ptr, '$', replace + replace_len - prev_ptr))) {
1539 hres = strbuf_append(&buf, prev_ptr, ptr - prev_ptr);
1540 if(FAILED(hres))
1541 break;
1543 switch(ptr[1]) {
1544 case '$':
1545 hres = strbuf_append(&buf, ptr, 1);
1546 prev_ptr = ptr + 2;
1547 break;
1548 case '&':
1549 hres = strbuf_append(&buf, cp - match_len, match_len);
1550 prev_ptr = ptr + 2;
1551 break;
1552 case '`':
1553 hres = strbuf_append(&buf, source, cp - source - match_len);
1554 prev_ptr = ptr + 2;
1555 break;
1556 case '\'':
1557 hres = strbuf_append(&buf, cp, source + source_len - cp);
1558 prev_ptr = ptr + 2;
1559 break;
1560 default: {
1561 DWORD idx;
1563 if(!is_digit(ptr[1])) {
1564 hres = strbuf_append(&buf, ptr, 1);
1565 prev_ptr = ptr + 1;
1566 break;
1569 idx = ptr[1] - '0';
1570 if(is_digit(ptr[2]) && idx * 10 + (ptr[2] - '0') <= state->paren_count) {
1571 idx = idx * 10 + (ptr[2] - '0');
1572 prev_ptr = ptr + 3;
1573 }else if(idx && idx <= state->paren_count) {
1574 prev_ptr = ptr + 2;
1575 }else {
1576 hres = strbuf_append(&buf, ptr, 1);
1577 prev_ptr = ptr + 1;
1578 break;
1581 if(state->parens[idx - 1].index != -1)
1582 hres = strbuf_append(&buf, source + state->parens[idx - 1].index,
1583 state->parens[idx - 1].length);
1584 break;
1587 if(FAILED(hres))
1588 break;
1590 if(SUCCEEDED(hres))
1591 hres = strbuf_append(&buf, prev_ptr, replace + replace_len - prev_ptr);
1592 if(FAILED(hres))
1593 break;
1595 if(!(This->flags & REG_GLOB))
1596 break;
1599 if(SUCCEEDED(hres)) {
1600 hres = strbuf_append(&buf, cp, source + source_len - cp);
1601 if(SUCCEEDED(hres) && !(*ret = SysAllocStringLen(buf.buf, buf.len)))
1602 hres = E_OUTOFMEMORY;
1605 heap_pool_clear(mark);
1606 heap_free(buf.buf);
1607 SysFreeString(replace);
1608 return hres;
1611 static const IRegExp2Vtbl RegExp2Vtbl = {
1612 RegExp2_QueryInterface,
1613 RegExp2_AddRef,
1614 RegExp2_Release,
1615 RegExp2_GetTypeInfoCount,
1616 RegExp2_GetTypeInfo,
1617 RegExp2_GetIDsOfNames,
1618 RegExp2_Invoke,
1619 RegExp2_get_Pattern,
1620 RegExp2_put_Pattern,
1621 RegExp2_get_IgnoreCase,
1622 RegExp2_put_IgnoreCase,
1623 RegExp2_get_Global,
1624 RegExp2_put_Global,
1625 RegExp2_get_Multiline,
1626 RegExp2_put_Multiline,
1627 RegExp2_Execute,
1628 RegExp2_Test,
1629 RegExp2_Replace
1632 BSTR string_replace(BSTR string, BSTR find, BSTR replace, int from, int cnt)
1634 const WCHAR *ptr, *string_end;
1635 strbuf_t buf = { NULL, 0, 0 };
1636 size_t replace_len, find_len;
1637 BSTR ret = NULL;
1638 HRESULT hres = S_OK;
1640 string_end = string + SysStringLen(string);
1641 ptr = from > SysStringLen(string) ? string_end : string + from;
1643 find_len = SysStringLen(find);
1644 replace_len = SysStringLen(replace);
1645 if(!replace_len)
1646 cnt = 0;
1648 while(string_end - ptr >= find_len && cnt && find_len) {
1649 if(memcmp(ptr, find, find_len * sizeof(WCHAR))) {
1650 hres = strbuf_append(&buf, ptr, 1);
1651 if(FAILED(hres))
1652 break;
1653 ptr++;
1654 }else {
1655 hres = strbuf_append(&buf, replace, replace_len);
1656 if(FAILED(hres))
1657 break;
1658 ptr += find_len;
1659 if(cnt != -1)
1660 cnt--;
1664 if(SUCCEEDED(hres)) {
1665 hres = strbuf_append(&buf, ptr, string_end - ptr);
1666 if(SUCCEEDED(hres))
1667 ret = SysAllocStringLen(buf.buf, buf.len);
1670 heap_free(buf.buf);
1671 return ret;
1674 static inline RegExp2 *impl_from_IRegExp(IRegExp *iface)
1676 return CONTAINING_RECORD(iface, RegExp2, IRegExp_iface);
1679 static HRESULT WINAPI RegExp_QueryInterface(IRegExp *iface, REFIID riid, void **ppv)
1681 RegExp2 *This = impl_from_IRegExp(iface);
1682 return IRegExp2_QueryInterface(&This->IRegExp2_iface, riid, ppv);
1685 static ULONG WINAPI RegExp_AddRef(IRegExp *iface)
1687 RegExp2 *This = impl_from_IRegExp(iface);
1688 return IRegExp2_AddRef(&This->IRegExp2_iface);
1691 static ULONG WINAPI RegExp_Release(IRegExp *iface)
1693 RegExp2 *This = impl_from_IRegExp(iface);
1694 return IRegExp2_Release(&This->IRegExp2_iface);
1697 static HRESULT WINAPI RegExp_GetTypeInfoCount(IRegExp *iface, UINT *pctinfo)
1699 RegExp2 *This = impl_from_IRegExp(iface);
1700 return IRegExp2_GetTypeInfoCount(&This->IRegExp2_iface, pctinfo);
1703 static HRESULT WINAPI RegExp_GetTypeInfo(IRegExp *iface,
1704 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
1706 RegExp2 *This = impl_from_IRegExp(iface);
1707 return IRegExp2_GetTypeInfo(&This->IRegExp2_iface, iTInfo, lcid, ppTInfo);
1710 static HRESULT WINAPI RegExp_GetIDsOfNames(IRegExp *iface, REFIID riid,
1711 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
1713 RegExp2 *This = impl_from_IRegExp(iface);
1714 return IRegExp2_GetIDsOfNames(&This->IRegExp2_iface, riid, rgszNames, cNames, lcid, rgDispId);
1717 static HRESULT WINAPI RegExp_Invoke(IRegExp *iface, DISPID dispIdMember,
1718 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
1719 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1721 RegExp2 *This = impl_from_IRegExp(iface);
1722 return IRegExp2_Invoke(&This->IRegExp2_iface, dispIdMember, riid, lcid,
1723 wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1726 static HRESULT WINAPI RegExp_get_Pattern(IRegExp *iface, BSTR *pPattern)
1728 RegExp2 *This = impl_from_IRegExp(iface);
1729 return IRegExp2_get_Pattern(&This->IRegExp2_iface, pPattern);
1732 static HRESULT WINAPI RegExp_put_Pattern(IRegExp *iface, BSTR pPattern)
1734 RegExp2 *This = impl_from_IRegExp(iface);
1735 return IRegExp2_put_Pattern(&This->IRegExp2_iface, pPattern);
1738 static HRESULT WINAPI RegExp_get_IgnoreCase(IRegExp *iface, VARIANT_BOOL *pIgnoreCase)
1740 RegExp2 *This = impl_from_IRegExp(iface);
1741 return IRegExp2_get_IgnoreCase(&This->IRegExp2_iface, pIgnoreCase);
1744 static HRESULT WINAPI RegExp_put_IgnoreCase(IRegExp *iface, VARIANT_BOOL pIgnoreCase)
1746 RegExp2 *This = impl_from_IRegExp(iface);
1747 return IRegExp2_put_IgnoreCase(&This->IRegExp2_iface, pIgnoreCase);
1750 static HRESULT WINAPI RegExp_get_Global(IRegExp *iface, VARIANT_BOOL *pGlobal)
1752 RegExp2 *This = impl_from_IRegExp(iface);
1753 return IRegExp2_get_Global(&This->IRegExp2_iface, pGlobal);
1756 static HRESULT WINAPI RegExp_put_Global(IRegExp *iface, VARIANT_BOOL pGlobal)
1758 RegExp2 *This = impl_from_IRegExp(iface);
1759 return IRegExp2_put_Global(&This->IRegExp2_iface, pGlobal);
1762 static HRESULT WINAPI RegExp_Execute(IRegExp *iface,
1763 BSTR sourceString, IDispatch **ppMatches)
1765 RegExp2 *This = impl_from_IRegExp(iface);
1766 return IRegExp2_Execute(&This->IRegExp2_iface, sourceString, ppMatches);
1769 static HRESULT WINAPI RegExp_Test(IRegExp *iface, BSTR sourceString, VARIANT_BOOL *pMatch)
1771 RegExp2 *This = impl_from_IRegExp(iface);
1772 return IRegExp2_Test(&This->IRegExp2_iface, sourceString, pMatch);
1775 static HRESULT WINAPI RegExp_Replace(IRegExp *iface, BSTR sourceString,
1776 BSTR replaceString, BSTR *pDestString)
1778 RegExp2 *This = impl_from_IRegExp(iface);
1779 VARIANT replace;
1781 V_VT(&replace) = VT_BSTR;
1782 V_BSTR(&replace) = replaceString;
1783 return IRegExp2_Replace(&This->IRegExp2_iface, sourceString, replace, pDestString);
1786 static IRegExpVtbl RegExpVtbl = {
1787 RegExp_QueryInterface,
1788 RegExp_AddRef,
1789 RegExp_Release,
1790 RegExp_GetTypeInfoCount,
1791 RegExp_GetTypeInfo,
1792 RegExp_GetIDsOfNames,
1793 RegExp_Invoke,
1794 RegExp_get_Pattern,
1795 RegExp_put_Pattern,
1796 RegExp_get_IgnoreCase,
1797 RegExp_put_IgnoreCase,
1798 RegExp_get_Global,
1799 RegExp_put_Global,
1800 RegExp_Execute,
1801 RegExp_Test,
1802 RegExp_Replace
1805 HRESULT create_regexp(IDispatch **ret)
1807 RegExp2 *regexp;
1808 HRESULT hres;
1810 hres = init_regexp_typeinfo(RegExp2_tid);
1811 if(FAILED(hres))
1812 return hres;
1814 regexp = heap_alloc_zero(sizeof(*regexp));
1815 if(!regexp)
1816 return E_OUTOFMEMORY;
1818 regexp->IRegExp2_iface.lpVtbl = &RegExp2Vtbl;
1819 regexp->IRegExp_iface.lpVtbl = &RegExpVtbl;
1820 regexp->ref = 1;
1821 heap_pool_init(&regexp->pool);
1823 *ret = (IDispatch*)&regexp->IRegExp2_iface;
1824 return S_OK;
1827 HRESULT WINAPI VBScriptRegExpFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter, REFIID riid, void **ppv)
1829 IDispatch *regexp;
1830 HRESULT hres;
1832 TRACE("(%p %s %p)\n", pUnkOuter, debugstr_guid(riid), ppv);
1834 hres = create_regexp(&regexp);
1835 if(FAILED(hres))
1836 return hres;
1838 hres = IDispatch_QueryInterface(regexp, riid, ppv);
1839 IDispatch_Release(regexp);
1840 return hres;
1843 void release_regexp_typelib(void)
1845 DWORD i;
1847 for(i=0; i<REGEXP_LAST_tid; i++) {
1848 if(typeinfos[i])
1849 ITypeInfo_Release(typeinfos[i]);
1851 if(typelib)
1852 ITypeLib_Release(typelib);