uiautomationcore: Implement UiaGetPropertyValue.
[wine.git] / dlls / vbscript / vbregexp.c
blob24ce243c6457917178db95a53a33c87e66b1cb7b
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 ITypeLib *tl;
57 hres = LoadTypeLib(L"vbscript.dll\\3", &tl);
58 if(FAILED(hres)) {
59 ERR("LoadRegTypeLib failed: %08lx\n", hres);
60 return hres;
63 if(InterlockedCompareExchangePointer((void**)&typelib, tl, NULL))
64 ITypeLib_Release(tl);
67 if(!typeinfos[tid]) {
68 ITypeInfo *ti;
70 hres = ITypeLib_GetTypeInfoOfGuid(typelib, tid_ids[tid], &ti);
71 if(FAILED(hres)) {
72 ERR("GetTypeInfoOfGuid(%s) failed: %08lx\n", debugstr_guid(tid_ids[tid]), hres);
73 return hres;
76 if(InterlockedCompareExchangePointer((void**)(typeinfos+tid), ti, NULL))
77 ITypeInfo_Release(ti);
80 return S_OK;
83 struct SubMatches {
84 ISubMatches ISubMatches_iface;
86 LONG ref;
88 WCHAR *match;
89 match_state_t *result;
92 typedef struct Match2 {
93 IMatch2 IMatch2_iface;
94 IMatch IMatch_iface;
96 LONG ref;
98 DWORD index;
99 SubMatches *sub_matches;
100 } Match2;
102 typedef struct MatchCollectionEnum {
103 IEnumVARIANT IEnumVARIANT_iface;
105 LONG ref;
107 IMatchCollection2 *mc;
108 LONG pos;
109 LONG count;
110 } MatchCollectionEnum;
112 typedef struct MatchCollection2 {
113 IMatchCollection2 IMatchCollection2_iface;
114 IMatchCollection IMatchCollection_iface;
116 LONG ref;
118 IMatch2 **matches;
119 DWORD count;
120 DWORD size;
121 } MatchCollection2;
123 typedef struct RegExp2 {
124 IRegExp2 IRegExp2_iface;
125 IRegExp IRegExp_iface;
127 LONG ref;
129 WCHAR *pattern;
130 regexp_t *regexp;
131 heap_pool_t pool;
132 WORD flags;
133 } RegExp2;
135 static inline SubMatches* impl_from_ISubMatches(ISubMatches *iface)
137 return CONTAINING_RECORD(iface, SubMatches, ISubMatches_iface);
140 static HRESULT WINAPI SubMatches_QueryInterface(
141 ISubMatches *iface, REFIID riid, void **ppv)
143 SubMatches *This = impl_from_ISubMatches(iface);
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;
164 IUnknown_AddRef((IUnknown*)*ppv);
165 return S_OK;
168 static ULONG WINAPI SubMatches_AddRef(ISubMatches *iface)
170 SubMatches *This = impl_from_ISubMatches(iface);
171 LONG ref = InterlockedIncrement(&This->ref);
173 TRACE("(%p) ref=%ld\n", This, ref);
175 return ref;
178 static ULONG WINAPI SubMatches_Release(ISubMatches *iface)
180 SubMatches *This = impl_from_ISubMatches(iface);
181 LONG ref = InterlockedDecrement(&This->ref);
183 TRACE("(%p) ref=%ld\n", This, ref);
185 if(!ref) {
186 heap_free(This->match);
187 heap_free(This->result);
188 heap_free(This);
191 return ref;
194 static HRESULT WINAPI SubMatches_GetTypeInfoCount(ISubMatches *iface, UINT *pctinfo)
196 SubMatches *This = impl_from_ISubMatches(iface);
198 TRACE("(%p)->(%p)\n", This, pctinfo);
200 *pctinfo = 1;
201 return S_OK;
204 static HRESULT WINAPI SubMatches_GetTypeInfo(ISubMatches *iface,
205 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
207 SubMatches *This = impl_from_ISubMatches(iface);
208 FIXME("(%p)->(%u %lu %p)\n", This, iTInfo, lcid, ppTInfo);
209 return E_NOTIMPL;
212 static HRESULT WINAPI SubMatches_GetIDsOfNames(ISubMatches *iface,
213 REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
215 SubMatches *This = impl_from_ISubMatches(iface);
217 TRACE("(%p)->(%s %p %u %lu %p)\n", This, debugstr_guid(riid),
218 rgszNames, cNames, lcid, rgDispId);
220 return ITypeInfo_GetIDsOfNames(typeinfos[SubMatches_tid], rgszNames, cNames, rgDispId);
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)
227 SubMatches *This = impl_from_ISubMatches(iface);
229 TRACE("(%p)->(%ld %s %ld %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
230 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
232 return ITypeInfo_Invoke(typeinfos[SubMatches_tid], iface, dispIdMember, wFlags,
233 pDispParams, pVarResult, pExcepInfo, puArgErr);
236 static HRESULT WINAPI SubMatches_get_Item(ISubMatches *iface,
237 LONG index, VARIANT *pSubMatch)
239 SubMatches *This = impl_from_ISubMatches(iface);
241 TRACE("(%p)->(%ld %p)\n", This, index, pSubMatch);
243 if(!pSubMatch)
244 return E_POINTER;
246 if(!This->result || index<0 || index>=This->result->paren_count)
247 return E_INVALIDARG;
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);
257 if(!V_BSTR(pSubMatch))
258 return E_OUTOFMEMORY;
261 return S_OK;
264 static HRESULT WINAPI SubMatches_get_Count(ISubMatches *iface, LONG *pCount)
266 SubMatches *This = impl_from_ISubMatches(iface);
268 TRACE("(%p)->(%p)\n", This, pCount);
270 if(!pCount)
271 return E_POINTER;
273 if(!This->result)
274 *pCount = 0;
275 else
276 *pCount = This->result->paren_count;
277 return S_OK;
280 static HRESULT WINAPI SubMatches_get__NewEnum(ISubMatches *iface, IUnknown **ppEnum)
282 SubMatches *This = impl_from_ISubMatches(iface);
283 FIXME("(%p)->(%p)\n", This, ppEnum);
284 return E_NOTIMPL;
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
300 static HRESULT create_sub_matches(DWORD pos, match_state_t *result, SubMatches **sub_matches)
302 SubMatches *ret;
303 DWORD i;
304 HRESULT hres;
306 hres = init_regexp_typeinfo(SubMatches_tid);
307 if(FAILED(hres))
308 return hres;
310 ret = heap_alloc_zero(sizeof(*ret));
311 if(!ret)
312 return E_OUTOFMEMORY;
314 ret->ISubMatches_iface.lpVtbl = &SubMatchesVtbl;
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;
323 memcpy(ret->match, result->cp-result->match_len, result->match_len*sizeof(WCHAR));
324 ret->match[result->match_len] = 0;
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;
334 ret->ref = 1;
335 *sub_matches = ret;
336 return hres;
339 static inline Match2* impl_from_IMatch2(IMatch2 *iface)
341 return CONTAINING_RECORD(iface, Match2, IMatch2_iface);
344 static HRESULT WINAPI Match2_QueryInterface(
345 IMatch2 *iface, REFIID riid, void **ppv)
347 Match2 *This = impl_from_IMatch2(iface);
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;
371 IUnknown_AddRef((IUnknown*)*ppv);
372 return S_OK;
375 static ULONG WINAPI Match2_AddRef(IMatch2 *iface)
377 Match2 *This = impl_from_IMatch2(iface);
378 LONG ref = InterlockedIncrement(&This->ref);
380 TRACE("(%p) ref=%ld\n", This, ref);
382 return ref;
385 static ULONG WINAPI Match2_Release(IMatch2 *iface)
387 Match2 *This = impl_from_IMatch2(iface);
388 LONG ref = InterlockedDecrement(&This->ref);
390 TRACE("(%p) ref=%ld\n", This, ref);
392 if(!ref) {
393 ISubMatches_Release(&This->sub_matches->ISubMatches_iface);
394 heap_free(This);
397 return ref;
400 static HRESULT WINAPI Match2_GetTypeInfoCount(IMatch2 *iface, UINT *pctinfo)
402 Match2 *This = impl_from_IMatch2(iface);
404 TRACE("(%p)->(%p)\n", This, pctinfo);
406 *pctinfo = 1;
407 return S_OK;
410 static HRESULT WINAPI Match2_GetTypeInfo(IMatch2 *iface,
411 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
413 Match2 *This = impl_from_IMatch2(iface);
414 FIXME("(%p)->(%u %lu %p)\n", This, iTInfo, lcid, ppTInfo);
415 return E_NOTIMPL;
418 static HRESULT WINAPI Match2_GetIDsOfNames(IMatch2 *iface,
419 REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
421 Match2 *This = impl_from_IMatch2(iface);
423 TRACE("(%p)->(%s %p %u %lu %p)\n", This, debugstr_guid(riid),
424 rgszNames, cNames, lcid, rgDispId);
426 return ITypeInfo_GetIDsOfNames(typeinfos[Match2_tid], rgszNames, cNames, rgDispId);
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)
433 Match2 *This = impl_from_IMatch2(iface);
435 TRACE("(%p)->(%ld %s %ld %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
436 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
438 return ITypeInfo_Invoke(typeinfos[Match2_tid], iface, dispIdMember, wFlags,
439 pDispParams, pVarResult, pExcepInfo, puArgErr);
442 static HRESULT WINAPI Match2_get_Value(IMatch2 *iface, BSTR *pValue)
444 Match2 *This = impl_from_IMatch2(iface);
446 TRACE("(%p)->(%p)\n", This, pValue);
448 if(!pValue)
449 return E_POINTER;
451 if(!This->sub_matches->match) {
452 *pValue = NULL;
453 return S_OK;
456 *pValue = SysAllocString(This->sub_matches->match);
457 return *pValue ? S_OK : E_OUTOFMEMORY;
460 static HRESULT WINAPI Match2_get_FirstIndex(IMatch2 *iface, LONG *pFirstIndex)
462 Match2 *This = impl_from_IMatch2(iface);
464 TRACE("(%p)->(%p)\n", This, pFirstIndex);
466 if(!pFirstIndex)
467 return E_POINTER;
469 *pFirstIndex = This->index;
470 return S_OK;
473 static HRESULT WINAPI Match2_get_Length(IMatch2 *iface, LONG *pLength)
475 Match2 *This = impl_from_IMatch2(iface);
477 TRACE("(%p)->(%p)\n", This, pLength);
479 if(!pLength)
480 return E_POINTER;
482 if(This->sub_matches->result)
483 *pLength = This->sub_matches->result->match_len;
484 else
485 *pLength = 0;
486 return S_OK;
489 static HRESULT WINAPI Match2_get_SubMatches(IMatch2 *iface, IDispatch **ppSubMatches)
491 Match2 *This = impl_from_IMatch2(iface);
493 TRACE("(%p)->(%p)\n", This, ppSubMatches);
495 if(!ppSubMatches)
496 return E_POINTER;
498 *ppSubMatches = (IDispatch*)&This->sub_matches->ISubMatches_iface;
499 ISubMatches_AddRef(&This->sub_matches->ISubMatches_iface);
500 return S_OK;
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
517 static inline Match2 *impl_from_IMatch(IMatch *iface)
519 return CONTAINING_RECORD(iface, Match2, IMatch_iface);
522 static HRESULT WINAPI Match_QueryInterface(IMatch *iface, REFIID riid, void **ppv)
524 Match2 *This = impl_from_IMatch(iface);
525 return IMatch2_QueryInterface(&This->IMatch2_iface, riid, ppv);
528 static ULONG WINAPI Match_AddRef(IMatch *iface)
530 Match2 *This = impl_from_IMatch(iface);
531 return IMatch2_AddRef(&This->IMatch2_iface);
534 static ULONG WINAPI Match_Release(IMatch *iface)
536 Match2 *This = impl_from_IMatch(iface);
537 return IMatch2_Release(&This->IMatch2_iface);
540 static HRESULT WINAPI Match_GetTypeInfoCount(IMatch *iface, UINT *pctinfo)
542 Match2 *This = impl_from_IMatch(iface);
543 return IMatch2_GetTypeInfoCount(&This->IMatch2_iface, pctinfo);
546 static HRESULT WINAPI Match_GetTypeInfo(IMatch *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
548 Match2 *This = impl_from_IMatch(iface);
549 return IMatch2_GetTypeInfo(&This->IMatch2_iface, iTInfo, lcid, ppTInfo);
552 static HRESULT WINAPI Match_GetIDsOfNames(IMatch *iface, REFIID riid,
553 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
555 Match2 *This = impl_from_IMatch(iface);
556 return IMatch2_GetIDsOfNames(&This->IMatch2_iface, riid, rgszNames, cNames, lcid, rgDispId);
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)
563 Match2 *This = impl_from_IMatch(iface);
564 return IMatch2_Invoke(&This->IMatch2_iface, dispIdMember, riid, lcid,
565 wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
568 static HRESULT WINAPI Match_get_Value(IMatch *iface, BSTR *pValue)
570 Match2 *This = impl_from_IMatch(iface);
571 return IMatch2_get_Value(&This->IMatch2_iface, pValue);
574 static HRESULT WINAPI Match_get_FirstIndex(IMatch *iface, LONG *pFirstIndex)
576 Match2 *This = impl_from_IMatch(iface);
577 return IMatch2_get_FirstIndex(&This->IMatch2_iface, pFirstIndex);
580 static HRESULT WINAPI Match_get_Length(IMatch *iface, LONG *pLength)
582 Match2 *This = impl_from_IMatch(iface);
583 return IMatch2_get_Length(&This->IMatch2_iface, pLength);
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
599 static HRESULT create_match2(DWORD pos, match_state_t **result, IMatch2 **match)
601 Match2 *ret;
602 HRESULT hres;
604 hres = init_regexp_typeinfo(Match2_tid);
605 if(FAILED(hres))
606 return hres;
608 ret = heap_alloc_zero(sizeof(*ret));
609 if(!ret)
610 return E_OUTOFMEMORY;
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;
618 if(result)
619 *result = NULL;
621 ret->IMatch2_iface.lpVtbl = &Match2Vtbl;
622 ret->IMatch_iface.lpVtbl = &MatchVtbl;
624 ret->ref = 1;
625 *match = &ret->IMatch2_iface;
626 return hres;
629 static inline MatchCollectionEnum* impl_from_IMatchCollectionEnum(IEnumVARIANT *iface)
631 return CONTAINING_RECORD(iface, MatchCollectionEnum, IEnumVARIANT_iface);
634 static HRESULT WINAPI MatchCollectionEnum_QueryInterface(
635 IEnumVARIANT *iface, REFIID riid, void **ppv)
637 MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface);
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;
651 IUnknown_AddRef((IUnknown*)*ppv);
652 return S_OK;
655 static ULONG WINAPI MatchCollectionEnum_AddRef(IEnumVARIANT *iface)
657 MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface);
658 LONG ref = InterlockedIncrement(&This->ref);
660 TRACE("(%p) ref=%ld\n", This, ref);
662 return ref;
665 static ULONG WINAPI MatchCollectionEnum_Release(IEnumVARIANT *iface)
667 MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface);
668 LONG ref = InterlockedDecrement(&This->ref);
670 TRACE("(%p) ref=%ld\n", This, ref);
672 if(!ref) {
673 IMatchCollection2_Release(This->mc);
674 heap_free(This);
677 return ref;
680 static HRESULT WINAPI MatchCollectionEnum_Next(IEnumVARIANT *iface,
681 ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched)
683 MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface);
684 DWORD i;
685 HRESULT hres = S_OK;
687 TRACE("(%p)->(%lu %p %p)\n", This, celt, rgVar, pCeltFetched);
689 if(This->pos>=This->count) {
690 if(pCeltFetched)
691 *pCeltFetched = 0;
692 return S_FALSE;
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;
701 if(FAILED(hres)) {
702 while(i--)
703 VariantClear(rgVar+i);
704 return hres;
707 if(pCeltFetched)
708 *pCeltFetched = i;
709 This->pos += i;
710 return S_OK;
713 static HRESULT WINAPI MatchCollectionEnum_Skip(IEnumVARIANT *iface, ULONG celt)
715 MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface);
717 TRACE("(%p)->(%lu)\n", This, celt);
719 if(This->pos+celt <= This->count)
720 This->pos += celt;
721 else
722 This->pos = This->count;
723 return S_OK;
726 static HRESULT WINAPI MatchCollectionEnum_Reset(IEnumVARIANT *iface)
728 MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface);
730 TRACE("(%p)\n", This);
732 This->pos = 0;
733 return S_OK;
736 static HRESULT WINAPI MatchCollectionEnum_Clone(IEnumVARIANT *iface, IEnumVARIANT **ppEnum)
738 MatchCollectionEnum *This = impl_from_IMatchCollectionEnum(iface);
739 FIXME("(%p)->(%p)\n", This, ppEnum);
740 return E_NOTIMPL;
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
753 static HRESULT create_enum_variant_mc2(IMatchCollection2 *mc, ULONG pos, IEnumVARIANT **enum_variant)
755 MatchCollectionEnum *ret;
757 ret = heap_alloc_zero(sizeof(*ret));
758 if(!ret)
759 return E_OUTOFMEMORY;
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);
768 *enum_variant = &ret->IEnumVARIANT_iface;
769 return S_OK;
772 static inline MatchCollection2* impl_from_IMatchCollection2(IMatchCollection2 *iface)
774 return CONTAINING_RECORD(iface, MatchCollection2, IMatchCollection2_iface);
777 static HRESULT WINAPI MatchCollection2_QueryInterface(
778 IMatchCollection2 *iface, REFIID riid, void **ppv)
780 MatchCollection2 *This = impl_from_IMatchCollection2(iface);
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;
804 IUnknown_AddRef((IUnknown*)*ppv);
805 return S_OK;
808 static ULONG WINAPI MatchCollection2_AddRef(IMatchCollection2 *iface)
810 MatchCollection2 *This = impl_from_IMatchCollection2(iface);
811 LONG ref = InterlockedIncrement(&This->ref);
813 TRACE("(%p) ref=%ld\n", This, ref);
815 return ref;
818 static ULONG WINAPI MatchCollection2_Release(IMatchCollection2 *iface)
820 MatchCollection2 *This = impl_from_IMatchCollection2(iface);
821 LONG ref = InterlockedDecrement(&This->ref);
823 TRACE("(%p) ref=%ld\n", This, ref);
825 if(!ref) {
826 DWORD i;
828 for(i=0; i<This->count; i++)
829 IMatch2_Release(This->matches[i]);
830 heap_free(This->matches);
832 heap_free(This);
835 return ref;
838 static HRESULT WINAPI MatchCollection2_GetTypeInfoCount(IMatchCollection2 *iface, UINT *pctinfo)
840 MatchCollection2 *This = impl_from_IMatchCollection2(iface);
842 TRACE("(%p)->(%p)\n", This, pctinfo);
844 *pctinfo = 1;
845 return S_OK;
848 static HRESULT WINAPI MatchCollection2_GetTypeInfo(IMatchCollection2 *iface,
849 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
851 MatchCollection2 *This = impl_from_IMatchCollection2(iface);
852 FIXME("(%p)->(%u %lu %p)\n", This, iTInfo, lcid, ppTInfo);
853 return E_NOTIMPL;
856 static HRESULT WINAPI MatchCollection2_GetIDsOfNames(IMatchCollection2 *iface,
857 REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
859 MatchCollection2 *This = impl_from_IMatchCollection2(iface);
861 TRACE("(%p)->(%s %p %u %lu %p)\n", This, debugstr_guid(riid),
862 rgszNames, cNames, lcid, rgDispId);
864 return ITypeInfo_GetIDsOfNames(typeinfos[MatchCollection2_tid], rgszNames, cNames, rgDispId);
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)
871 MatchCollection2 *This = impl_from_IMatchCollection2(iface);
873 TRACE("(%p)->(%ld %s %ld %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
874 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
876 return ITypeInfo_Invoke(typeinfos[MatchCollection2_tid], iface, dispIdMember, wFlags,
877 pDispParams, pVarResult, pExcepInfo, puArgErr);
880 static HRESULT WINAPI MatchCollection2_get_Item(IMatchCollection2 *iface,
881 LONG index, IDispatch **ppMatch)
883 MatchCollection2 *This = impl_from_IMatchCollection2(iface);
885 TRACE("(%p)->()\n", This);
887 if(!ppMatch)
888 return E_POINTER;
890 if(index<0 || index>=This->count)
891 return E_INVALIDARG;
893 *ppMatch = (IDispatch*)This->matches[index];
894 IMatch2_AddRef(This->matches[index]);
895 return S_OK;
898 static HRESULT WINAPI MatchCollection2_get_Count(IMatchCollection2 *iface, LONG *pCount)
900 MatchCollection2 *This = impl_from_IMatchCollection2(iface);
902 TRACE("(%p)->()\n", This);
904 if(!pCount)
905 return E_POINTER;
907 *pCount = This->count;
908 return S_OK;
911 static HRESULT WINAPI MatchCollection2_get__NewEnum(IMatchCollection2 *iface, IUnknown **ppEnum)
913 MatchCollection2 *This = impl_from_IMatchCollection2(iface);
915 TRACE("(%p)->(%p)\n", This, ppEnum);
917 if(!ppEnum)
918 return E_POINTER;
920 return create_enum_variant_mc2(&This->IMatchCollection2_iface, 0, (IEnumVARIANT**)ppEnum);
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
936 static inline MatchCollection2 *impl_from_IMatchCollection(IMatchCollection *iface)
938 return CONTAINING_RECORD(iface, MatchCollection2, IMatchCollection_iface);
941 static HRESULT WINAPI MatchCollection_QueryInterface(IMatchCollection *iface, REFIID riid, void **ppv)
943 MatchCollection2 *This = impl_from_IMatchCollection(iface);
944 return IMatchCollection2_QueryInterface(&This->IMatchCollection2_iface, riid, ppv);
947 static ULONG WINAPI MatchCollection_AddRef(IMatchCollection *iface)
949 MatchCollection2 *This = impl_from_IMatchCollection(iface);
950 return IMatchCollection2_AddRef(&This->IMatchCollection2_iface);
953 static ULONG WINAPI MatchCollection_Release(IMatchCollection *iface)
955 MatchCollection2 *This = impl_from_IMatchCollection(iface);
956 return IMatchCollection2_Release(&This->IMatchCollection2_iface);
959 static HRESULT WINAPI MatchCollection_GetTypeInfoCount(IMatchCollection *iface, UINT *pctinfo)
961 MatchCollection2 *This = impl_from_IMatchCollection(iface);
962 return IMatchCollection2_GetTypeInfoCount(&This->IMatchCollection2_iface, pctinfo);
965 static HRESULT WINAPI MatchCollection_GetTypeInfo(IMatchCollection *iface,
966 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
968 MatchCollection2 *This = impl_from_IMatchCollection(iface);
969 return IMatchCollection2_GetTypeInfo(&This->IMatchCollection2_iface, iTInfo, lcid, ppTInfo);
972 static HRESULT WINAPI MatchCollection_GetIDsOfNames(IMatchCollection *iface, REFIID riid,
973 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
975 MatchCollection2 *This = impl_from_IMatchCollection(iface);
976 return IMatchCollection2_GetIDsOfNames(&This->IMatchCollection2_iface,
977 riid, rgszNames, cNames, lcid, rgDispId);
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)
984 MatchCollection2 *This = impl_from_IMatchCollection(iface);
985 return IMatchCollection2_Invoke(&This->IMatchCollection2_iface, dispIdMember,
986 riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
989 static HRESULT WINAPI MatchCollection_get_Item(IMatchCollection *iface, LONG index, IDispatch **ppMatch)
991 MatchCollection2 *This = impl_from_IMatchCollection(iface);
992 return IMatchCollection2_get_Item(&This->IMatchCollection2_iface, index, ppMatch);
995 static HRESULT WINAPI MatchCollection_get_Count(IMatchCollection *iface, LONG *pCount)
997 MatchCollection2 *This = impl_from_IMatchCollection(iface);
998 return IMatchCollection2_get_Count(&This->IMatchCollection2_iface, pCount);
1001 static HRESULT WINAPI MatchCollection_get__NewEnum(IMatchCollection *iface, IUnknown **ppEnum)
1003 MatchCollection2 *This = impl_from_IMatchCollection(iface);
1004 return IMatchCollection2_get__NewEnum(&This->IMatchCollection2_iface, ppEnum);
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
1020 static HRESULT add_match(IMatchCollection2 *iface, IMatch2 *add)
1022 MatchCollection2 *This = impl_from_IMatchCollection2(iface);
1024 TRACE("(%p)->(%p)\n", This, add);
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;
1036 This->matches = new_matches;
1037 This->size <<= 1;
1040 This->matches[This->count++] = add;
1041 IMatch2_AddRef(add);
1042 return S_OK;
1045 static HRESULT create_match_collection2(IMatchCollection2 **match_collection)
1047 MatchCollection2 *ret;
1048 HRESULT hres;
1050 hres = init_regexp_typeinfo(MatchCollection2_tid);
1051 if(FAILED(hres))
1052 return hres;
1054 ret = heap_alloc_zero(sizeof(*ret));
1055 if(!ret)
1056 return E_OUTOFMEMORY;
1058 ret->IMatchCollection2_iface.lpVtbl = &MatchCollection2Vtbl;
1059 ret->IMatchCollection_iface.lpVtbl = &MatchCollectionVtbl;
1061 ret->ref = 1;
1062 *match_collection = &ret->IMatchCollection2_iface;
1063 return S_OK;
1066 static inline RegExp2 *impl_from_IRegExp2(IRegExp2 *iface)
1068 return CONTAINING_RECORD(iface, RegExp2, IRegExp2_iface);
1071 static HRESULT WINAPI RegExp2_QueryInterface(IRegExp2 *iface, REFIID riid, void **ppv)
1073 RegExp2 *This = impl_from_IRegExp2(iface);
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;
1097 IUnknown_AddRef((IUnknown*)*ppv);
1098 return S_OK;
1101 static ULONG WINAPI RegExp2_AddRef(IRegExp2 *iface)
1103 RegExp2 *This = impl_from_IRegExp2(iface);
1104 LONG ref = InterlockedIncrement(&This->ref);
1106 TRACE("(%p) ref=%ld\n", This, ref);
1108 return ref;
1111 static ULONG WINAPI RegExp2_Release(IRegExp2 *iface)
1113 RegExp2 *This = impl_from_IRegExp2(iface);
1114 LONG ref = InterlockedDecrement(&This->ref);
1116 TRACE("(%p) ref=%ld\n", This, ref);
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);
1126 return ref;
1129 static HRESULT WINAPI RegExp2_GetTypeInfoCount(IRegExp2 *iface, UINT *pctinfo)
1131 RegExp2 *This = impl_from_IRegExp2(iface);
1133 TRACE("(%p)->(%p)\n", This, pctinfo);
1135 *pctinfo = 1;
1136 return S_OK;
1139 static HRESULT WINAPI RegExp2_GetTypeInfo(IRegExp2 *iface,
1140 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
1142 RegExp2 *This = impl_from_IRegExp2(iface);
1143 FIXME("(%p)->(%u %lu %p)\n", This, iTInfo, lcid, ppTInfo);
1144 return E_NOTIMPL;
1147 static HRESULT WINAPI RegExp2_GetIDsOfNames(IRegExp2 *iface, REFIID riid,
1148 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
1150 RegExp2 *This = impl_from_IRegExp2(iface);
1152 TRACE("(%p)->(%s %p %u %lu %p)\n", This, debugstr_guid(riid),
1153 rgszNames, cNames, lcid, rgDispId);
1155 return ITypeInfo_GetIDsOfNames(typeinfos[RegExp2_tid], rgszNames, cNames, rgDispId);
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)
1162 RegExp2 *This = impl_from_IRegExp2(iface);
1164 TRACE("(%p)->(%ld %s %ld %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1165 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1167 return ITypeInfo_Invoke(typeinfos[RegExp2_tid], iface, dispIdMember, wFlags,
1168 pDispParams, pVarResult, pExcepInfo, puArgErr);
1171 static HRESULT WINAPI RegExp2_get_Pattern(IRegExp2 *iface, BSTR *pPattern)
1173 RegExp2 *This = impl_from_IRegExp2(iface);
1175 TRACE("(%p)->(%p)\n", This, pPattern);
1177 if(!pPattern)
1178 return E_POINTER;
1180 if(!This->pattern) {
1181 *pPattern = NULL;
1182 return S_OK;
1185 *pPattern = SysAllocString(This->pattern);
1186 return *pPattern ? S_OK : E_OUTOFMEMORY;
1189 static HRESULT WINAPI RegExp2_put_Pattern(IRegExp2 *iface, BSTR pattern)
1191 RegExp2 *This = impl_from_IRegExp2(iface);
1192 WCHAR *new_pattern;
1194 TRACE("(%p)->(%s)\n", This, wine_dbgstr_w(pattern));
1196 if(pattern && *pattern) {
1197 SIZE_T size = (SysStringLen(pattern)+1) * sizeof(WCHAR);
1198 new_pattern = heap_alloc(size);
1199 if(!new_pattern)
1200 return E_OUTOFMEMORY;
1201 memcpy(new_pattern, pattern, size);
1202 }else {
1203 new_pattern = NULL;
1206 heap_free(This->pattern);
1207 This->pattern = new_pattern;
1209 if(This->regexp) {
1210 regexp_destroy(This->regexp);
1211 This->regexp = NULL;
1213 return S_OK;
1216 static HRESULT WINAPI RegExp2_get_IgnoreCase(IRegExp2 *iface, VARIANT_BOOL *pIgnoreCase)
1218 RegExp2 *This = impl_from_IRegExp2(iface);
1220 TRACE("(%p)->(%p)\n", This, pIgnoreCase);
1222 if(!pIgnoreCase)
1223 return E_POINTER;
1225 *pIgnoreCase = This->flags & REG_FOLD ? VARIANT_TRUE : VARIANT_FALSE;
1226 return S_OK;
1229 static HRESULT WINAPI RegExp2_put_IgnoreCase(IRegExp2 *iface, VARIANT_BOOL ignoreCase)
1231 RegExp2 *This = impl_from_IRegExp2(iface);
1233 TRACE("(%p)->(%s)\n", This, ignoreCase ? "true" : "false");
1235 if(ignoreCase)
1236 This->flags |= REG_FOLD;
1237 else
1238 This->flags &= ~REG_FOLD;
1239 return S_OK;
1242 static HRESULT WINAPI RegExp2_get_Global(IRegExp2 *iface, VARIANT_BOOL *pGlobal)
1244 RegExp2 *This = impl_from_IRegExp2(iface);
1246 TRACE("(%p)->(%p)\n", This, pGlobal);
1248 if(!pGlobal)
1249 return E_POINTER;
1251 *pGlobal = This->flags & REG_GLOB ? VARIANT_TRUE : VARIANT_FALSE;
1252 return S_OK;
1255 static HRESULT WINAPI RegExp2_put_Global(IRegExp2 *iface, VARIANT_BOOL global)
1257 RegExp2 *This = impl_from_IRegExp2(iface);
1259 TRACE("(%p)->(%s)\n", This, global ? "true" : "false");
1261 if(global)
1262 This->flags |= REG_GLOB;
1263 else
1264 This->flags &= ~REG_GLOB;
1265 return S_OK;
1268 static HRESULT WINAPI RegExp2_get_Multiline(IRegExp2 *iface, VARIANT_BOOL *pMultiline)
1270 RegExp2 *This = impl_from_IRegExp2(iface);
1272 TRACE("(%p)->(%p)\n", This, pMultiline);
1274 if(!pMultiline)
1275 return E_POINTER;
1277 *pMultiline = This->flags & REG_MULTILINE ? VARIANT_TRUE : VARIANT_FALSE;
1278 return S_OK;
1281 static HRESULT WINAPI RegExp2_put_Multiline(IRegExp2 *iface, VARIANT_BOOL multiline)
1283 RegExp2 *This = impl_from_IRegExp2(iface);
1285 TRACE("(%p)->(%s)\n", This, multiline ? "true" : "false");
1287 if(multiline)
1288 This->flags |= REG_MULTILINE;
1289 else
1290 This->flags &= ~REG_MULTILINE;
1291 return S_OK;
1294 static HRESULT WINAPI RegExp2_Execute(IRegExp2 *iface,
1295 BSTR sourceString, IDispatch **ppMatches)
1297 RegExp2 *This = impl_from_IRegExp2(iface);
1298 match_state_t *result;
1299 const WCHAR *pos;
1300 IMatchCollection2 *match_collection;
1301 IMatch2 *add = NULL;
1302 HRESULT hres;
1304 TRACE("(%p)->(%s %p)\n", This, debugstr_w(sourceString), ppMatches);
1306 if(!This->pattern) {
1307 DWORD i, len = SysStringLen(sourceString);
1309 hres = create_match_collection2(&match_collection);
1310 if(FAILED(hres))
1311 return hres;
1313 for(i=0; i<=len; i++) {
1314 hres = create_match2(i, NULL, &add);
1315 if(FAILED(hres))
1316 break;
1318 hres = add_match(match_collection, add);
1319 if(FAILED(hres))
1320 break;
1321 IMatch2_Release(add);
1323 if(!(This->flags & REG_GLOB))
1324 break;
1327 if(FAILED(hres)) {
1328 IMatchCollection2_Release(match_collection);
1329 return hres;
1332 *ppMatches = (IDispatch*)match_collection;
1333 return S_OK;
1336 if(!This->regexp) {
1337 This->regexp = regexp_new(NULL, &This->pool, This->pattern,
1338 lstrlenW(This->pattern), This->flags, FALSE);
1339 if(!This->regexp)
1340 return E_FAIL;
1341 }else {
1342 hres = regexp_set_flags(&This->regexp, NULL, &This->pool, This->flags);
1343 if(FAILED(hres))
1344 return hres;
1347 hres = create_match_collection2(&match_collection);
1348 if(FAILED(hres))
1349 return hres;
1351 pos = sourceString;
1352 while(1) {
1353 result = alloc_match_state(This->regexp, NULL, pos);
1354 if(!result) {
1355 hres = E_OUTOFMEMORY;
1356 break;
1359 hres = regexp_execute(This->regexp, NULL, &This->pool,
1360 sourceString, SysStringLen(sourceString), result);
1361 if(hres != S_OK) {
1362 heap_free(result);
1363 break;
1365 pos = result->cp;
1367 hres = create_match2(result->cp-result->match_len-sourceString, &result, &add);
1368 heap_free(result);
1369 if(FAILED(hres))
1370 break;
1371 hres = add_match(match_collection, add);
1372 IMatch2_Release(add);
1373 if(FAILED(hres))
1374 break;
1376 if(!(This->flags & REG_GLOB))
1377 break;
1380 if(FAILED(hres)) {
1381 IMatchCollection2_Release(match_collection);
1382 return hres;
1385 *ppMatches = (IDispatch*)match_collection;
1386 return S_OK;
1389 static HRESULT WINAPI RegExp2_Test(IRegExp2 *iface, BSTR sourceString, VARIANT_BOOL *pMatch)
1391 RegExp2 *This = impl_from_IRegExp2(iface);
1392 match_state_t *result;
1393 heap_pool_t *mark;
1394 HRESULT hres;
1396 TRACE("(%p)->(%s %p)\n", This, debugstr_w(sourceString), pMatch);
1398 if(!This->pattern) {
1399 *pMatch = VARIANT_TRUE;
1400 return S_OK;
1403 if(!This->regexp) {
1404 This->regexp = regexp_new(NULL, &This->pool, This->pattern,
1405 lstrlenW(This->pattern), This->flags, FALSE);
1406 if(!This->regexp)
1407 return E_FAIL;
1408 }else {
1409 hres = regexp_set_flags(&This->regexp, NULL, &This->pool, This->flags);
1410 if(FAILED(hres))
1411 return hres;
1414 mark = heap_pool_mark(&This->pool);
1415 result = alloc_match_state(This->regexp, &This->pool, sourceString);
1416 if(!result) {
1417 heap_pool_clear(mark);
1418 return E_OUTOFMEMORY;
1421 hres = regexp_execute(This->regexp, NULL, &This->pool,
1422 sourceString, SysStringLen(sourceString), result);
1424 heap_pool_clear(mark);
1426 if(hres == S_OK) {
1427 *pMatch = VARIANT_TRUE;
1428 }else if(hres == S_FALSE) {
1429 *pMatch = VARIANT_FALSE;
1430 hres = S_OK;
1432 return hres;
1435 typedef struct {
1436 WCHAR *buf;
1437 DWORD size;
1438 DWORD len;
1439 } strbuf_t;
1441 static BOOL strbuf_ensure_size(strbuf_t *buf, unsigned len)
1443 WCHAR *new_buf;
1444 DWORD new_size;
1446 if(len <= buf->size)
1447 return TRUE;
1449 new_size = buf->size ? buf->size<<1 : 16;
1450 if(new_size < len)
1451 new_size = len;
1452 if(buf->buf)
1453 new_buf = heap_realloc(buf->buf, new_size*sizeof(WCHAR));
1454 else
1455 new_buf = heap_alloc(new_size*sizeof(WCHAR));
1456 if(!new_buf)
1457 return FALSE;
1459 buf->buf = new_buf;
1460 buf->size = new_size;
1461 return TRUE;
1464 static HRESULT strbuf_append(strbuf_t *buf, const WCHAR *str, DWORD len)
1466 if(!len)
1467 return S_OK;
1469 if(!strbuf_ensure_size(buf, buf->len+len))
1470 return E_OUTOFMEMORY;
1472 memcpy(buf->buf+buf->len, str, len*sizeof(WCHAR));
1473 buf->len += len;
1474 return S_OK;
1477 static HRESULT WINAPI RegExp2_Replace(IRegExp2 *iface, BSTR source, VARIANT replaceVar, BSTR *ret)
1479 RegExp2 *This = impl_from_IRegExp2(iface);
1480 const WCHAR *cp, *prev_cp = NULL, *ptr, *prev_ptr;
1481 size_t match_len = 0, source_len, replace_len;
1482 strbuf_t buf = { NULL, 0, 0 };
1483 match_state_t *state = NULL;
1484 heap_pool_t *mark;
1485 VARIANT strv;
1486 BSTR replace;
1487 HRESULT hres;
1489 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(source), debugstr_variant(&replaceVar), ret);
1491 if(This->pattern) {
1492 if(!This->regexp) {
1493 This->regexp = regexp_new(NULL, &This->pool, This->pattern,
1494 lstrlenW(This->pattern), This->flags, FALSE);
1495 if(!This->regexp)
1496 return E_OUTOFMEMORY;
1497 }else {
1498 hres = regexp_set_flags(&This->regexp, NULL, &This->pool, This->flags);
1499 if(FAILED(hres))
1500 return hres;
1504 V_VT(&strv) = VT_EMPTY;
1505 hres = VariantChangeType(&strv, &replaceVar, 0, VT_BSTR);
1506 if(FAILED(hres))
1507 return hres;
1508 replace = V_BSTR(&strv);
1509 replace_len = SysStringLen(replace);
1510 source_len = SysStringLen(source);
1512 mark = heap_pool_mark(&This->pool);
1513 cp = source;
1514 if(This->regexp && !(state = alloc_match_state(This->regexp, &This->pool, cp)))
1515 hres = E_OUTOFMEMORY;
1517 while(SUCCEEDED(hres)) {
1518 if(This->regexp) {
1519 prev_cp = cp;
1520 hres = regexp_execute(This->regexp, NULL, &This->pool, source, source_len, state);
1521 if(hres != S_OK) break;
1522 cp = state->cp;
1523 match_len = state->match_len;
1524 }else if(prev_cp) {
1525 if(cp == source + source_len)
1526 break;
1527 prev_cp = cp++;
1528 }else {
1529 prev_cp = cp;
1532 hres = strbuf_append(&buf, prev_cp, cp - prev_cp - match_len);
1533 if(FAILED(hres))
1534 break;
1536 prev_ptr = replace;
1537 while((ptr = wmemchr(prev_ptr, '$', replace + replace_len - prev_ptr))) {
1538 hres = strbuf_append(&buf, prev_ptr, ptr - prev_ptr);
1539 if(FAILED(hres))
1540 break;
1542 switch(ptr[1]) {
1543 case '$':
1544 hres = strbuf_append(&buf, ptr, 1);
1545 prev_ptr = ptr + 2;
1546 break;
1547 case '&':
1548 hres = strbuf_append(&buf, cp - match_len, match_len);
1549 prev_ptr = ptr + 2;
1550 break;
1551 case '`':
1552 hres = strbuf_append(&buf, source, cp - source - match_len);
1553 prev_ptr = ptr + 2;
1554 break;
1555 case '\'':
1556 hres = strbuf_append(&buf, cp, source + source_len - cp);
1557 prev_ptr = ptr + 2;
1558 break;
1559 default: {
1560 DWORD idx;
1562 if(!is_digit(ptr[1])) {
1563 hres = strbuf_append(&buf, ptr, 1);
1564 prev_ptr = ptr + 1;
1565 break;
1568 idx = ptr[1] - '0';
1569 if(is_digit(ptr[2]) && idx * 10 + (ptr[2] - '0') <= state->paren_count) {
1570 idx = idx * 10 + (ptr[2] - '0');
1571 prev_ptr = ptr + 3;
1572 }else if(idx && idx <= state->paren_count) {
1573 prev_ptr = ptr + 2;
1574 }else {
1575 hres = strbuf_append(&buf, ptr, 1);
1576 prev_ptr = ptr + 1;
1577 break;
1580 if(state->parens[idx - 1].index != -1)
1581 hres = strbuf_append(&buf, source + state->parens[idx - 1].index,
1582 state->parens[idx - 1].length);
1583 break;
1586 if(FAILED(hres))
1587 break;
1589 if(SUCCEEDED(hres))
1590 hres = strbuf_append(&buf, prev_ptr, replace + replace_len - prev_ptr);
1591 if(FAILED(hres))
1592 break;
1594 if(!(This->flags & REG_GLOB))
1595 break;
1598 if(SUCCEEDED(hres)) {
1599 hres = strbuf_append(&buf, cp, source + source_len - cp);
1600 if(SUCCEEDED(hres) && !(*ret = SysAllocStringLen(buf.buf, buf.len)))
1601 hres = E_OUTOFMEMORY;
1604 heap_pool_clear(mark);
1605 heap_free(buf.buf);
1606 SysFreeString(replace);
1607 return hres;
1610 static const IRegExp2Vtbl RegExp2Vtbl = {
1611 RegExp2_QueryInterface,
1612 RegExp2_AddRef,
1613 RegExp2_Release,
1614 RegExp2_GetTypeInfoCount,
1615 RegExp2_GetTypeInfo,
1616 RegExp2_GetIDsOfNames,
1617 RegExp2_Invoke,
1618 RegExp2_get_Pattern,
1619 RegExp2_put_Pattern,
1620 RegExp2_get_IgnoreCase,
1621 RegExp2_put_IgnoreCase,
1622 RegExp2_get_Global,
1623 RegExp2_put_Global,
1624 RegExp2_get_Multiline,
1625 RegExp2_put_Multiline,
1626 RegExp2_Execute,
1627 RegExp2_Test,
1628 RegExp2_Replace
1631 BSTR string_replace(BSTR string, BSTR find, BSTR replace, int from, int cnt, int mode)
1633 const WCHAR *ptr, *string_end;
1634 strbuf_t buf = { NULL, 0, 0 };
1635 size_t replace_len, find_len;
1636 BSTR ret = NULL;
1637 HRESULT hres = S_OK;
1638 int pos;
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);
1646 while(string_end - ptr >= find_len && cnt && find_len) {
1647 pos = FindStringOrdinal(FIND_FROMSTART, ptr, string_end - ptr,
1648 find, find_len, mode);
1650 if(pos == -1)
1651 break;
1652 else {
1653 hres = strbuf_append(&buf, ptr, pos);
1654 if(FAILED(hres))
1655 break;
1656 hres = strbuf_append(&buf, replace, replace_len);
1657 if(FAILED(hres))
1658 break;
1660 ptr = ptr + pos + find_len;
1661 if(cnt != -1)
1662 cnt--;
1666 if(SUCCEEDED(hres)) {
1667 hres = strbuf_append(&buf, ptr, string_end - ptr);
1668 if(SUCCEEDED(hres))
1669 ret = SysAllocStringLen(buf.buf, buf.len);
1672 heap_free(buf.buf);
1673 return ret;
1676 static inline RegExp2 *impl_from_IRegExp(IRegExp *iface)
1678 return CONTAINING_RECORD(iface, RegExp2, IRegExp_iface);
1681 static HRESULT WINAPI RegExp_QueryInterface(IRegExp *iface, REFIID riid, void **ppv)
1683 RegExp2 *This = impl_from_IRegExp(iface);
1684 return IRegExp2_QueryInterface(&This->IRegExp2_iface, riid, ppv);
1687 static ULONG WINAPI RegExp_AddRef(IRegExp *iface)
1689 RegExp2 *This = impl_from_IRegExp(iface);
1690 return IRegExp2_AddRef(&This->IRegExp2_iface);
1693 static ULONG WINAPI RegExp_Release(IRegExp *iface)
1695 RegExp2 *This = impl_from_IRegExp(iface);
1696 return IRegExp2_Release(&This->IRegExp2_iface);
1699 static HRESULT WINAPI RegExp_GetTypeInfoCount(IRegExp *iface, UINT *pctinfo)
1701 RegExp2 *This = impl_from_IRegExp(iface);
1702 return IRegExp2_GetTypeInfoCount(&This->IRegExp2_iface, pctinfo);
1705 static HRESULT WINAPI RegExp_GetTypeInfo(IRegExp *iface,
1706 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
1708 RegExp2 *This = impl_from_IRegExp(iface);
1709 return IRegExp2_GetTypeInfo(&This->IRegExp2_iface, iTInfo, lcid, ppTInfo);
1712 static HRESULT WINAPI RegExp_GetIDsOfNames(IRegExp *iface, REFIID riid,
1713 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
1715 RegExp2 *This = impl_from_IRegExp(iface);
1716 return IRegExp2_GetIDsOfNames(&This->IRegExp2_iface, riid, rgszNames, cNames, lcid, rgDispId);
1719 static HRESULT WINAPI RegExp_Invoke(IRegExp *iface, DISPID dispIdMember,
1720 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
1721 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1723 RegExp2 *This = impl_from_IRegExp(iface);
1724 return IRegExp2_Invoke(&This->IRegExp2_iface, dispIdMember, riid, lcid,
1725 wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1728 static HRESULT WINAPI RegExp_get_Pattern(IRegExp *iface, BSTR *pPattern)
1730 RegExp2 *This = impl_from_IRegExp(iface);
1731 return IRegExp2_get_Pattern(&This->IRegExp2_iface, pPattern);
1734 static HRESULT WINAPI RegExp_put_Pattern(IRegExp *iface, BSTR pPattern)
1736 RegExp2 *This = impl_from_IRegExp(iface);
1737 return IRegExp2_put_Pattern(&This->IRegExp2_iface, pPattern);
1740 static HRESULT WINAPI RegExp_get_IgnoreCase(IRegExp *iface, VARIANT_BOOL *pIgnoreCase)
1742 RegExp2 *This = impl_from_IRegExp(iface);
1743 return IRegExp2_get_IgnoreCase(&This->IRegExp2_iface, pIgnoreCase);
1746 static HRESULT WINAPI RegExp_put_IgnoreCase(IRegExp *iface, VARIANT_BOOL pIgnoreCase)
1748 RegExp2 *This = impl_from_IRegExp(iface);
1749 return IRegExp2_put_IgnoreCase(&This->IRegExp2_iface, pIgnoreCase);
1752 static HRESULT WINAPI RegExp_get_Global(IRegExp *iface, VARIANT_BOOL *pGlobal)
1754 RegExp2 *This = impl_from_IRegExp(iface);
1755 return IRegExp2_get_Global(&This->IRegExp2_iface, pGlobal);
1758 static HRESULT WINAPI RegExp_put_Global(IRegExp *iface, VARIANT_BOOL pGlobal)
1760 RegExp2 *This = impl_from_IRegExp(iface);
1761 return IRegExp2_put_Global(&This->IRegExp2_iface, pGlobal);
1764 static HRESULT WINAPI RegExp_Execute(IRegExp *iface,
1765 BSTR sourceString, IDispatch **ppMatches)
1767 RegExp2 *This = impl_from_IRegExp(iface);
1768 return IRegExp2_Execute(&This->IRegExp2_iface, sourceString, ppMatches);
1771 static HRESULT WINAPI RegExp_Test(IRegExp *iface, BSTR sourceString, VARIANT_BOOL *pMatch)
1773 RegExp2 *This = impl_from_IRegExp(iface);
1774 return IRegExp2_Test(&This->IRegExp2_iface, sourceString, pMatch);
1777 static HRESULT WINAPI RegExp_Replace(IRegExp *iface, BSTR sourceString,
1778 BSTR replaceString, BSTR *pDestString)
1780 RegExp2 *This = impl_from_IRegExp(iface);
1781 VARIANT replace;
1783 V_VT(&replace) = VT_BSTR;
1784 V_BSTR(&replace) = replaceString;
1785 return IRegExp2_Replace(&This->IRegExp2_iface, sourceString, replace, pDestString);
1788 static IRegExpVtbl RegExpVtbl = {
1789 RegExp_QueryInterface,
1790 RegExp_AddRef,
1791 RegExp_Release,
1792 RegExp_GetTypeInfoCount,
1793 RegExp_GetTypeInfo,
1794 RegExp_GetIDsOfNames,
1795 RegExp_Invoke,
1796 RegExp_get_Pattern,
1797 RegExp_put_Pattern,
1798 RegExp_get_IgnoreCase,
1799 RegExp_put_IgnoreCase,
1800 RegExp_get_Global,
1801 RegExp_put_Global,
1802 RegExp_Execute,
1803 RegExp_Test,
1804 RegExp_Replace
1807 HRESULT create_regexp(IDispatch **ret)
1809 RegExp2 *regexp;
1810 HRESULT hres;
1812 hres = init_regexp_typeinfo(RegExp2_tid);
1813 if(FAILED(hres))
1814 return hres;
1816 regexp = heap_alloc_zero(sizeof(*regexp));
1817 if(!regexp)
1818 return E_OUTOFMEMORY;
1820 regexp->IRegExp2_iface.lpVtbl = &RegExp2Vtbl;
1821 regexp->IRegExp_iface.lpVtbl = &RegExpVtbl;
1822 regexp->ref = 1;
1823 heap_pool_init(&regexp->pool);
1825 *ret = (IDispatch*)&regexp->IRegExp2_iface;
1826 return S_OK;
1829 HRESULT WINAPI VBScriptRegExpFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter, REFIID riid, void **ppv)
1831 IDispatch *regexp;
1832 HRESULT hres;
1834 TRACE("(%p %s %p)\n", pUnkOuter, debugstr_guid(riid), ppv);
1836 hres = create_regexp(&regexp);
1837 if(FAILED(hres))
1838 return hres;
1840 hres = IDispatch_QueryInterface(regexp, riid, ppv);
1841 IDispatch_Release(regexp);
1842 return hres;
1845 void release_regexp_typelib(void)
1847 DWORD i;
1849 for(i=0; i<REGEXP_LAST_tid; i++) {
1850 if(typeinfos[i])
1851 ITypeInfo_Release(typeinfos[i]);
1853 if(typelib)
1854 ITypeLib_Release(typelib);