ntdll: Buffer pagemap reads in fill_working_set_info().
[wine.git] / dlls / vbscript / vbregexp.c
blob4a56875ef14d4e8dada5ed0c498e3adec6e10ff0
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 free(This->match);
187 free(This->result);
188 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 = calloc(1, 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 = malloc((result->match_len+1) * sizeof(WCHAR));
319 if(!ret->match) {
320 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 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 = calloc(1, 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 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 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 = calloc(1, 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 free(This->matches);
832 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 = malloc(8 * sizeof(*This->matches));
1028 if(!This->matches)
1029 return E_OUTOFMEMORY;
1030 This->size = 8;
1031 }else if(This->size == This->count) {
1032 IMatch2 **new_matches = realloc(This->matches, 2 * This->size * sizeof(*This->matches));
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 = calloc(1, 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 free(This->pattern);
1120 if(This->regexp)
1121 regexp_destroy(This->regexp);
1122 heap_pool_free(&This->pool);
1123 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);
1144 TRACE("(%p)->(%u %lu %p)\n", This, iTInfo, lcid, ppTInfo);
1146 *ppTInfo = typeinfos[RegExp2_tid];
1147 ITypeInfo_AddRef(*ppTInfo);
1148 return S_OK;
1151 static HRESULT WINAPI RegExp2_GetIDsOfNames(IRegExp2 *iface, REFIID riid,
1152 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
1154 RegExp2 *This = impl_from_IRegExp2(iface);
1156 TRACE("(%p)->(%s %p %u %lu %p)\n", This, debugstr_guid(riid),
1157 rgszNames, cNames, lcid, rgDispId);
1159 return ITypeInfo_GetIDsOfNames(typeinfos[RegExp2_tid], rgszNames, cNames, rgDispId);
1162 static HRESULT WINAPI RegExp2_Invoke(IRegExp2 *iface, DISPID dispIdMember,
1163 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
1164 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1166 RegExp2 *This = impl_from_IRegExp2(iface);
1168 TRACE("(%p)->(%ld %s %ld %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1169 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1171 return ITypeInfo_Invoke(typeinfos[RegExp2_tid], iface, dispIdMember, wFlags,
1172 pDispParams, pVarResult, pExcepInfo, puArgErr);
1175 static HRESULT WINAPI RegExp2_get_Pattern(IRegExp2 *iface, BSTR *pPattern)
1177 RegExp2 *This = impl_from_IRegExp2(iface);
1179 TRACE("(%p)->(%p)\n", This, pPattern);
1181 if(!pPattern)
1182 return E_POINTER;
1184 if(!This->pattern) {
1185 *pPattern = NULL;
1186 return S_OK;
1189 *pPattern = SysAllocString(This->pattern);
1190 return *pPattern ? S_OK : E_OUTOFMEMORY;
1193 static HRESULT WINAPI RegExp2_put_Pattern(IRegExp2 *iface, BSTR pattern)
1195 RegExp2 *This = impl_from_IRegExp2(iface);
1196 WCHAR *new_pattern;
1198 TRACE("(%p)->(%s)\n", This, wine_dbgstr_w(pattern));
1200 if(pattern && *pattern) {
1201 SIZE_T size = (SysStringLen(pattern)+1) * sizeof(WCHAR);
1202 new_pattern = malloc(size);
1203 if(!new_pattern)
1204 return E_OUTOFMEMORY;
1205 memcpy(new_pattern, pattern, size);
1206 }else {
1207 new_pattern = NULL;
1210 free(This->pattern);
1211 This->pattern = new_pattern;
1213 if(This->regexp) {
1214 regexp_destroy(This->regexp);
1215 This->regexp = NULL;
1217 return S_OK;
1220 static HRESULT WINAPI RegExp2_get_IgnoreCase(IRegExp2 *iface, VARIANT_BOOL *pIgnoreCase)
1222 RegExp2 *This = impl_from_IRegExp2(iface);
1224 TRACE("(%p)->(%p)\n", This, pIgnoreCase);
1226 if(!pIgnoreCase)
1227 return E_POINTER;
1229 *pIgnoreCase = This->flags & REG_FOLD ? VARIANT_TRUE : VARIANT_FALSE;
1230 return S_OK;
1233 static HRESULT WINAPI RegExp2_put_IgnoreCase(IRegExp2 *iface, VARIANT_BOOL ignoreCase)
1235 RegExp2 *This = impl_from_IRegExp2(iface);
1237 TRACE("(%p)->(%s)\n", This, ignoreCase ? "true" : "false");
1239 if(ignoreCase)
1240 This->flags |= REG_FOLD;
1241 else
1242 This->flags &= ~REG_FOLD;
1243 return S_OK;
1246 static HRESULT WINAPI RegExp2_get_Global(IRegExp2 *iface, VARIANT_BOOL *pGlobal)
1248 RegExp2 *This = impl_from_IRegExp2(iface);
1250 TRACE("(%p)->(%p)\n", This, pGlobal);
1252 if(!pGlobal)
1253 return E_POINTER;
1255 *pGlobal = This->flags & REG_GLOB ? VARIANT_TRUE : VARIANT_FALSE;
1256 return S_OK;
1259 static HRESULT WINAPI RegExp2_put_Global(IRegExp2 *iface, VARIANT_BOOL global)
1261 RegExp2 *This = impl_from_IRegExp2(iface);
1263 TRACE("(%p)->(%s)\n", This, global ? "true" : "false");
1265 if(global)
1266 This->flags |= REG_GLOB;
1267 else
1268 This->flags &= ~REG_GLOB;
1269 return S_OK;
1272 static HRESULT WINAPI RegExp2_get_Multiline(IRegExp2 *iface, VARIANT_BOOL *pMultiline)
1274 RegExp2 *This = impl_from_IRegExp2(iface);
1276 TRACE("(%p)->(%p)\n", This, pMultiline);
1278 if(!pMultiline)
1279 return E_POINTER;
1281 *pMultiline = This->flags & REG_MULTILINE ? VARIANT_TRUE : VARIANT_FALSE;
1282 return S_OK;
1285 static HRESULT WINAPI RegExp2_put_Multiline(IRegExp2 *iface, VARIANT_BOOL multiline)
1287 RegExp2 *This = impl_from_IRegExp2(iface);
1289 TRACE("(%p)->(%s)\n", This, multiline ? "true" : "false");
1291 if(multiline)
1292 This->flags |= REG_MULTILINE;
1293 else
1294 This->flags &= ~REG_MULTILINE;
1295 return S_OK;
1298 static HRESULT WINAPI RegExp2_Execute(IRegExp2 *iface,
1299 BSTR sourceString, IDispatch **ppMatches)
1301 RegExp2 *This = impl_from_IRegExp2(iface);
1302 match_state_t *result;
1303 const WCHAR *pos;
1304 IMatchCollection2 *match_collection;
1305 IMatch2 *add = NULL;
1306 HRESULT hres;
1308 TRACE("(%p)->(%s %p)\n", This, debugstr_w(sourceString), ppMatches);
1310 if(!This->pattern) {
1311 DWORD i, len = SysStringLen(sourceString);
1313 hres = create_match_collection2(&match_collection);
1314 if(FAILED(hres))
1315 return hres;
1317 for(i=0; i<=len; i++) {
1318 hres = create_match2(i, NULL, &add);
1319 if(FAILED(hres))
1320 break;
1322 hres = add_match(match_collection, add);
1323 IMatch2_Release(add);
1324 if(FAILED(hres))
1325 break;
1327 if(!(This->flags & REG_GLOB))
1328 break;
1331 if(FAILED(hres)) {
1332 IMatchCollection2_Release(match_collection);
1333 return hres;
1336 *ppMatches = (IDispatch*)match_collection;
1337 return S_OK;
1340 if(!This->regexp) {
1341 This->regexp = regexp_new(NULL, &This->pool, This->pattern,
1342 lstrlenW(This->pattern), This->flags, FALSE);
1343 if(!This->regexp)
1344 return E_FAIL;
1345 }else {
1346 hres = regexp_set_flags(&This->regexp, NULL, &This->pool, This->flags);
1347 if(FAILED(hres))
1348 return hres;
1351 hres = create_match_collection2(&match_collection);
1352 if(FAILED(hres))
1353 return hres;
1355 pos = sourceString;
1356 while(1) {
1357 result = alloc_match_state(This->regexp, NULL, pos);
1358 if(!result) {
1359 hres = E_OUTOFMEMORY;
1360 break;
1363 hres = regexp_execute(This->regexp, NULL, &This->pool,
1364 sourceString, SysStringLen(sourceString), result);
1365 if(hres != S_OK) {
1366 free(result);
1367 break;
1369 pos = result->cp;
1371 hres = create_match2(result->cp-result->match_len-sourceString, &result, &add);
1372 free(result);
1373 if(FAILED(hres))
1374 break;
1375 hres = add_match(match_collection, add);
1376 IMatch2_Release(add);
1377 if(FAILED(hres))
1378 break;
1380 if(!(This->flags & REG_GLOB))
1381 break;
1384 if(FAILED(hres)) {
1385 IMatchCollection2_Release(match_collection);
1386 return hres;
1389 *ppMatches = (IDispatch*)match_collection;
1390 return S_OK;
1393 static HRESULT WINAPI RegExp2_Test(IRegExp2 *iface, BSTR sourceString, VARIANT_BOOL *pMatch)
1395 RegExp2 *This = impl_from_IRegExp2(iface);
1396 match_state_t *result;
1397 heap_pool_t *mark;
1398 HRESULT hres;
1400 TRACE("(%p)->(%s %p)\n", This, debugstr_w(sourceString), pMatch);
1402 if(!This->pattern) {
1403 *pMatch = VARIANT_TRUE;
1404 return S_OK;
1407 if(!This->regexp) {
1408 This->regexp = regexp_new(NULL, &This->pool, This->pattern,
1409 lstrlenW(This->pattern), This->flags, FALSE);
1410 if(!This->regexp)
1411 return E_FAIL;
1412 }else {
1413 hres = regexp_set_flags(&This->regexp, NULL, &This->pool, This->flags);
1414 if(FAILED(hres))
1415 return hres;
1418 mark = heap_pool_mark(&This->pool);
1419 result = alloc_match_state(This->regexp, &This->pool, sourceString);
1420 if(!result) {
1421 heap_pool_clear(mark);
1422 return E_OUTOFMEMORY;
1425 hres = regexp_execute(This->regexp, NULL, &This->pool,
1426 sourceString, SysStringLen(sourceString), result);
1428 heap_pool_clear(mark);
1430 if(hres == S_OK) {
1431 *pMatch = VARIANT_TRUE;
1432 }else if(hres == S_FALSE) {
1433 *pMatch = VARIANT_FALSE;
1434 hres = S_OK;
1436 return hres;
1439 typedef struct {
1440 WCHAR *buf;
1441 DWORD size;
1442 DWORD len;
1443 } strbuf_t;
1445 static BOOL strbuf_ensure_size(strbuf_t *buf, unsigned len)
1447 WCHAR *new_buf;
1448 DWORD new_size;
1450 if(len <= buf->size)
1451 return TRUE;
1453 new_size = buf->size ? buf->size<<1 : 16;
1454 if(new_size < len)
1455 new_size = len;
1456 if(buf->buf)
1457 new_buf = realloc(buf->buf, new_size*sizeof(WCHAR));
1458 else
1459 new_buf = malloc(new_size*sizeof(WCHAR));
1460 if(!new_buf)
1461 return FALSE;
1463 buf->buf = new_buf;
1464 buf->size = new_size;
1465 return TRUE;
1468 static HRESULT strbuf_append(strbuf_t *buf, const WCHAR *str, DWORD len)
1470 if(!len)
1471 return S_OK;
1473 if(!strbuf_ensure_size(buf, buf->len+len))
1474 return E_OUTOFMEMORY;
1476 memcpy(buf->buf+buf->len, str, len*sizeof(WCHAR));
1477 buf->len += len;
1478 return S_OK;
1481 static HRESULT WINAPI RegExp2_Replace(IRegExp2 *iface, BSTR source, VARIANT replaceVar, BSTR *ret)
1483 RegExp2 *This = impl_from_IRegExp2(iface);
1484 const WCHAR *cp, *prev_cp = NULL, *ptr, *prev_ptr;
1485 size_t match_len = 0, source_len, replace_len;
1486 strbuf_t buf = { NULL, 0, 0 };
1487 match_state_t *state = NULL;
1488 heap_pool_t *mark;
1489 VARIANT strv;
1490 BSTR replace;
1491 HRESULT hres;
1493 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(source), debugstr_variant(&replaceVar), ret);
1495 if(This->pattern) {
1496 if(!This->regexp) {
1497 This->regexp = regexp_new(NULL, &This->pool, This->pattern,
1498 lstrlenW(This->pattern), This->flags, FALSE);
1499 if(!This->regexp)
1500 return E_OUTOFMEMORY;
1501 }else {
1502 hres = regexp_set_flags(&This->regexp, NULL, &This->pool, This->flags);
1503 if(FAILED(hres))
1504 return hres;
1508 V_VT(&strv) = VT_EMPTY;
1509 hres = VariantChangeType(&strv, &replaceVar, 0, VT_BSTR);
1510 if(FAILED(hres))
1511 return hres;
1512 replace = V_BSTR(&strv);
1513 replace_len = SysStringLen(replace);
1514 source_len = SysStringLen(source);
1516 mark = heap_pool_mark(&This->pool);
1517 cp = source;
1518 if(This->regexp && !(state = alloc_match_state(This->regexp, &This->pool, cp)))
1519 hres = E_OUTOFMEMORY;
1521 while(SUCCEEDED(hres)) {
1522 if(This->regexp) {
1523 prev_cp = cp;
1524 hres = regexp_execute(This->regexp, NULL, &This->pool, source, source_len, state);
1525 if(hres != S_OK) break;
1526 cp = state->cp;
1527 match_len = state->match_len;
1528 }else if(prev_cp) {
1529 if(cp == source + source_len)
1530 break;
1531 prev_cp = cp++;
1532 }else {
1533 prev_cp = cp;
1536 hres = strbuf_append(&buf, prev_cp, cp - prev_cp - match_len);
1537 if(FAILED(hres))
1538 break;
1540 prev_ptr = replace;
1541 while((ptr = wmemchr(prev_ptr, '$', replace + replace_len - prev_ptr))) {
1542 hres = strbuf_append(&buf, prev_ptr, ptr - prev_ptr);
1543 if(FAILED(hres))
1544 break;
1546 switch(ptr[1]) {
1547 case '$':
1548 hres = strbuf_append(&buf, ptr, 1);
1549 prev_ptr = ptr + 2;
1550 break;
1551 case '&':
1552 hres = strbuf_append(&buf, cp - match_len, match_len);
1553 prev_ptr = ptr + 2;
1554 break;
1555 case '`':
1556 hres = strbuf_append(&buf, source, cp - source - match_len);
1557 prev_ptr = ptr + 2;
1558 break;
1559 case '\'':
1560 hres = strbuf_append(&buf, cp, source + source_len - cp);
1561 prev_ptr = ptr + 2;
1562 break;
1563 default: {
1564 DWORD idx;
1566 if(!is_digit(ptr[1])) {
1567 hres = strbuf_append(&buf, ptr, 1);
1568 prev_ptr = ptr + 1;
1569 break;
1572 idx = ptr[1] - '0';
1573 if(is_digit(ptr[2]) && idx * 10 + (ptr[2] - '0') <= state->paren_count) {
1574 idx = idx * 10 + (ptr[2] - '0');
1575 prev_ptr = ptr + 3;
1576 }else if(idx && idx <= state->paren_count) {
1577 prev_ptr = ptr + 2;
1578 }else {
1579 hres = strbuf_append(&buf, ptr, 1);
1580 prev_ptr = ptr + 1;
1581 break;
1584 if(state->parens[idx - 1].index != -1)
1585 hres = strbuf_append(&buf, source + state->parens[idx - 1].index,
1586 state->parens[idx - 1].length);
1587 break;
1590 if(FAILED(hres))
1591 break;
1593 if(SUCCEEDED(hres))
1594 hres = strbuf_append(&buf, prev_ptr, replace + replace_len - prev_ptr);
1595 if(FAILED(hres))
1596 break;
1598 if(!(This->flags & REG_GLOB))
1599 break;
1602 if(SUCCEEDED(hres)) {
1603 hres = strbuf_append(&buf, cp, source + source_len - cp);
1604 if(SUCCEEDED(hres) && !(*ret = SysAllocStringLen(buf.buf, buf.len)))
1605 hres = E_OUTOFMEMORY;
1608 heap_pool_clear(mark);
1609 free(buf.buf);
1610 SysFreeString(replace);
1611 return hres;
1614 static const IRegExp2Vtbl RegExp2Vtbl = {
1615 RegExp2_QueryInterface,
1616 RegExp2_AddRef,
1617 RegExp2_Release,
1618 RegExp2_GetTypeInfoCount,
1619 RegExp2_GetTypeInfo,
1620 RegExp2_GetIDsOfNames,
1621 RegExp2_Invoke,
1622 RegExp2_get_Pattern,
1623 RegExp2_put_Pattern,
1624 RegExp2_get_IgnoreCase,
1625 RegExp2_put_IgnoreCase,
1626 RegExp2_get_Global,
1627 RegExp2_put_Global,
1628 RegExp2_get_Multiline,
1629 RegExp2_put_Multiline,
1630 RegExp2_Execute,
1631 RegExp2_Test,
1632 RegExp2_Replace
1635 BSTR string_replace(BSTR string, BSTR find, BSTR replace, int from, int cnt, int mode)
1637 const WCHAR *ptr, *string_end;
1638 strbuf_t buf = { NULL, 0, 0 };
1639 size_t replace_len, find_len;
1640 BSTR ret = NULL;
1641 HRESULT hres = S_OK;
1642 int pos;
1644 string_end = string + SysStringLen(string);
1645 ptr = from > SysStringLen(string) ? string_end : string + from;
1647 find_len = SysStringLen(find);
1648 replace_len = SysStringLen(replace);
1650 while(string_end - ptr >= find_len && cnt && find_len) {
1651 pos = FindStringOrdinal(FIND_FROMSTART, ptr, string_end - ptr,
1652 find, find_len, mode);
1654 if(pos == -1)
1655 break;
1656 else {
1657 hres = strbuf_append(&buf, ptr, pos);
1658 if(FAILED(hres))
1659 break;
1660 hres = strbuf_append(&buf, replace, replace_len);
1661 if(FAILED(hres))
1662 break;
1664 ptr = ptr + pos + find_len;
1665 if(cnt != -1)
1666 cnt--;
1670 if(SUCCEEDED(hres)) {
1671 hres = strbuf_append(&buf, ptr, string_end - ptr);
1672 if(SUCCEEDED(hres))
1673 ret = SysAllocStringLen(buf.buf, buf.len);
1676 free(buf.buf);
1677 return ret;
1680 static inline RegExp2 *impl_from_IRegExp(IRegExp *iface)
1682 return CONTAINING_RECORD(iface, RegExp2, IRegExp_iface);
1685 static HRESULT WINAPI RegExp_QueryInterface(IRegExp *iface, REFIID riid, void **ppv)
1687 RegExp2 *This = impl_from_IRegExp(iface);
1688 return IRegExp2_QueryInterface(&This->IRegExp2_iface, riid, ppv);
1691 static ULONG WINAPI RegExp_AddRef(IRegExp *iface)
1693 RegExp2 *This = impl_from_IRegExp(iface);
1694 return IRegExp2_AddRef(&This->IRegExp2_iface);
1697 static ULONG WINAPI RegExp_Release(IRegExp *iface)
1699 RegExp2 *This = impl_from_IRegExp(iface);
1700 return IRegExp2_Release(&This->IRegExp2_iface);
1703 static HRESULT WINAPI RegExp_GetTypeInfoCount(IRegExp *iface, UINT *pctinfo)
1705 RegExp2 *This = impl_from_IRegExp(iface);
1706 return IRegExp2_GetTypeInfoCount(&This->IRegExp2_iface, pctinfo);
1709 static HRESULT WINAPI RegExp_GetTypeInfo(IRegExp *iface,
1710 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
1712 RegExp2 *This = impl_from_IRegExp(iface);
1713 return IRegExp2_GetTypeInfo(&This->IRegExp2_iface, iTInfo, lcid, ppTInfo);
1716 static HRESULT WINAPI RegExp_GetIDsOfNames(IRegExp *iface, REFIID riid,
1717 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
1719 RegExp2 *This = impl_from_IRegExp(iface);
1720 return IRegExp2_GetIDsOfNames(&This->IRegExp2_iface, riid, rgszNames, cNames, lcid, rgDispId);
1723 static HRESULT WINAPI RegExp_Invoke(IRegExp *iface, DISPID dispIdMember,
1724 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
1725 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1727 RegExp2 *This = impl_from_IRegExp(iface);
1728 return IRegExp2_Invoke(&This->IRegExp2_iface, dispIdMember, riid, lcid,
1729 wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1732 static HRESULT WINAPI RegExp_get_Pattern(IRegExp *iface, BSTR *pPattern)
1734 RegExp2 *This = impl_from_IRegExp(iface);
1735 return IRegExp2_get_Pattern(&This->IRegExp2_iface, pPattern);
1738 static HRESULT WINAPI RegExp_put_Pattern(IRegExp *iface, BSTR pPattern)
1740 RegExp2 *This = impl_from_IRegExp(iface);
1741 return IRegExp2_put_Pattern(&This->IRegExp2_iface, pPattern);
1744 static HRESULT WINAPI RegExp_get_IgnoreCase(IRegExp *iface, VARIANT_BOOL *pIgnoreCase)
1746 RegExp2 *This = impl_from_IRegExp(iface);
1747 return IRegExp2_get_IgnoreCase(&This->IRegExp2_iface, pIgnoreCase);
1750 static HRESULT WINAPI RegExp_put_IgnoreCase(IRegExp *iface, VARIANT_BOOL pIgnoreCase)
1752 RegExp2 *This = impl_from_IRegExp(iface);
1753 return IRegExp2_put_IgnoreCase(&This->IRegExp2_iface, pIgnoreCase);
1756 static HRESULT WINAPI RegExp_get_Global(IRegExp *iface, VARIANT_BOOL *pGlobal)
1758 RegExp2 *This = impl_from_IRegExp(iface);
1759 return IRegExp2_get_Global(&This->IRegExp2_iface, pGlobal);
1762 static HRESULT WINAPI RegExp_put_Global(IRegExp *iface, VARIANT_BOOL pGlobal)
1764 RegExp2 *This = impl_from_IRegExp(iface);
1765 return IRegExp2_put_Global(&This->IRegExp2_iface, pGlobal);
1768 static HRESULT WINAPI RegExp_Execute(IRegExp *iface,
1769 BSTR sourceString, IDispatch **ppMatches)
1771 RegExp2 *This = impl_from_IRegExp(iface);
1772 return IRegExp2_Execute(&This->IRegExp2_iface, sourceString, ppMatches);
1775 static HRESULT WINAPI RegExp_Test(IRegExp *iface, BSTR sourceString, VARIANT_BOOL *pMatch)
1777 RegExp2 *This = impl_from_IRegExp(iface);
1778 return IRegExp2_Test(&This->IRegExp2_iface, sourceString, pMatch);
1781 static HRESULT WINAPI RegExp_Replace(IRegExp *iface, BSTR sourceString,
1782 BSTR replaceString, BSTR *pDestString)
1784 RegExp2 *This = impl_from_IRegExp(iface);
1785 VARIANT replace;
1787 V_VT(&replace) = VT_BSTR;
1788 V_BSTR(&replace) = replaceString;
1789 return IRegExp2_Replace(&This->IRegExp2_iface, sourceString, replace, pDestString);
1792 static IRegExpVtbl RegExpVtbl = {
1793 RegExp_QueryInterface,
1794 RegExp_AddRef,
1795 RegExp_Release,
1796 RegExp_GetTypeInfoCount,
1797 RegExp_GetTypeInfo,
1798 RegExp_GetIDsOfNames,
1799 RegExp_Invoke,
1800 RegExp_get_Pattern,
1801 RegExp_put_Pattern,
1802 RegExp_get_IgnoreCase,
1803 RegExp_put_IgnoreCase,
1804 RegExp_get_Global,
1805 RegExp_put_Global,
1806 RegExp_Execute,
1807 RegExp_Test,
1808 RegExp_Replace
1811 HRESULT create_regexp(IDispatch **ret)
1813 RegExp2 *regexp;
1814 HRESULT hres;
1816 hres = init_regexp_typeinfo(RegExp2_tid);
1817 if(FAILED(hres))
1818 return hres;
1820 regexp = calloc(1, sizeof(*regexp));
1821 if(!regexp)
1822 return E_OUTOFMEMORY;
1824 regexp->IRegExp2_iface.lpVtbl = &RegExp2Vtbl;
1825 regexp->IRegExp_iface.lpVtbl = &RegExpVtbl;
1826 regexp->ref = 1;
1827 heap_pool_init(&regexp->pool);
1829 *ret = (IDispatch*)&regexp->IRegExp2_iface;
1830 return S_OK;
1833 HRESULT WINAPI VBScriptRegExpFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter, REFIID riid, void **ppv)
1835 IDispatch *regexp;
1836 HRESULT hres;
1838 TRACE("(%p %s %p)\n", pUnkOuter, debugstr_guid(riid), ppv);
1840 hres = create_regexp(&regexp);
1841 if(FAILED(hres))
1842 return hres;
1844 hres = IDispatch_QueryInterface(regexp, riid, ppv);
1845 IDispatch_Release(regexp);
1846 return hres;
1849 void release_regexp_typelib(void)
1851 DWORD i;
1853 for(i=0; i<REGEXP_LAST_tid; i++) {
1854 if(typeinfos[i])
1855 ITypeInfo_Release(typeinfos[i]);
1857 if(typelib)
1858 ITypeLib_Release(typelib);