windows.applicationmodel/tests: Use PathRemoveFileSpecW() instead of PathCchRemoveFil...
[wine.git] / dlls / jscript / enumerator.c
blobd724d0685c9e032e79624852259c98700b9114e1
1 /*
2 * Copyright 2019 Andreas Maier
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 <assert.h>
21 #include "jscript.h"
23 #include "wine/debug.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
27 typedef struct {
28 jsdisp_t dispex;
29 /* IEnumVARIANT returned by _NewEnum */
30 IEnumVARIANT *enumvar;
31 /* current item */
32 jsval_t item;
33 BOOL atend;
34 } EnumeratorInstance;
36 static inline EnumeratorInstance *enumerator_from_jsdisp(jsdisp_t *jsdisp)
38 return CONTAINING_RECORD(jsdisp, EnumeratorInstance, dispex);
41 static inline EnumeratorInstance *enumerator_this(jsval_t vthis)
43 jsdisp_t *jsdisp = is_object_instance(vthis) ? to_jsdisp(get_object(vthis)) : NULL;
44 return (jsdisp && is_class(jsdisp, JSCLASS_ENUMERATOR)) ? enumerator_from_jsdisp(jsdisp) : NULL;
47 static inline HRESULT enumvar_get_next_item(EnumeratorInstance *This, script_ctx_t *ctx)
49 HRESULT hres;
50 VARIANT nextitem;
52 if (This->atend)
53 return S_OK;
55 /* don't leak previous value */
56 jsval_release(This->item);
58 /* not at end ... get next item */
59 VariantInit(&nextitem);
60 hres = IEnumVARIANT_Next(This->enumvar, 1, &nextitem, NULL);
61 if (hres == S_OK)
63 hres = variant_to_jsval(ctx, &nextitem, &This->item);
64 VariantClear(&nextitem);
65 if (FAILED(hres))
67 WARN("failed to convert jsval to variant!\n");
68 This->item = jsval_undefined();
69 return hres;
72 else
74 This->item = jsval_undefined();
75 This->atend = TRUE;
78 return S_OK;
81 static void Enumerator_destructor(jsdisp_t *dispex)
83 EnumeratorInstance *This = enumerator_from_jsdisp(dispex);
85 TRACE("\n");
87 jsval_release(This->item);
88 free(dispex);
91 static HRESULT Enumerator_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, jsdisp_t *dispex)
93 return gc_process_linked_val(gc_ctx, op, dispex, &enumerator_from_jsdisp(dispex)->item);
96 static HRESULT Enumerator_atEnd(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
97 jsval_t *r)
99 EnumeratorInstance *This;
101 if (!(This = enumerator_this(vthis)))
102 return JS_E_ENUMERATOR_EXPECTED;
104 TRACE("%d\n", This->atend);
106 if (r)
107 *r = jsval_bool(This->atend);
108 return S_OK;
111 static HRESULT Enumerator_item(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
112 jsval_t *r)
114 EnumeratorInstance *This;
116 TRACE("\n");
118 if (!(This = enumerator_this(vthis)))
119 return JS_E_ENUMERATOR_EXPECTED;
121 return r ? jsval_copy(This->item, r) : S_OK;
124 static HRESULT Enumerator_moveFirst(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
125 jsval_t *r)
127 EnumeratorInstance *This;
128 HRESULT hres = S_OK;
130 TRACE("\n");
132 if (!(This = enumerator_this(vthis)))
133 return JS_E_ENUMERATOR_EXPECTED;
135 if (This->enumvar)
137 hres = IEnumVARIANT_Reset(This->enumvar);
138 if (FAILED(hres))
139 return hres;
141 This->atend = FALSE;
142 hres = enumvar_get_next_item(This, ctx);
143 if(FAILED(hres))
144 return hres;
147 if (r)
148 *r = jsval_undefined();
149 return S_OK;
152 static HRESULT Enumerator_moveNext(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
153 jsval_t *r)
155 EnumeratorInstance *This;
156 HRESULT hres = S_OK;
158 TRACE("\n");
160 if (!(This = enumerator_this(vthis)))
161 return JS_E_ENUMERATOR_EXPECTED;
163 if (This->enumvar)
165 hres = enumvar_get_next_item(This, ctx);
166 if (FAILED(hres))
167 return hres;
170 if (r)
171 *r = jsval_undefined();
172 return S_OK;
175 static const builtin_prop_t Enumerator_props[] = {
176 {L"atEnd", Enumerator_atEnd, PROPF_METHOD},
177 {L"item", Enumerator_item, PROPF_METHOD},
178 {L"moveFirst", Enumerator_moveFirst, PROPF_METHOD},
179 {L"moveNext", Enumerator_moveNext, PROPF_METHOD},
182 static const builtin_info_t Enumerator_info = {
183 JSCLASS_ENUMERATOR,
184 NULL,
185 ARRAY_SIZE(Enumerator_props),
186 Enumerator_props,
187 NULL,
188 NULL
191 static const builtin_info_t EnumeratorInst_info = {
192 JSCLASS_ENUMERATOR,
193 NULL,
195 NULL,
196 Enumerator_destructor,
197 NULL,
198 NULL,
199 NULL,
200 NULL,
201 Enumerator_gc_traverse
204 static HRESULT alloc_enumerator(script_ctx_t *ctx, jsdisp_t *object_prototype, EnumeratorInstance **ret)
206 EnumeratorInstance *enumerator;
207 HRESULT hres;
209 enumerator = calloc(1, sizeof(EnumeratorInstance));
210 if(!enumerator)
211 return E_OUTOFMEMORY;
213 if(object_prototype)
214 hres = init_dispex(&enumerator->dispex, ctx, &Enumerator_info, object_prototype);
215 else
216 hres = init_dispex_from_constr(&enumerator->dispex, ctx, &EnumeratorInst_info,
217 ctx->enumerator_constr);
219 if(FAILED(hres))
221 free(enumerator);
222 return hres;
225 *ret = enumerator;
226 return S_OK;
229 static HRESULT create_enumerator(script_ctx_t *ctx, jsval_t *argv, jsdisp_t **ret)
231 EnumeratorInstance *enumerator;
232 HRESULT hres;
233 IDispatch *obj;
234 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
235 IEnumVARIANT *enumvar = NULL;
237 if (argv)
239 VARIANT varresult;
241 if (!is_object_instance(*argv))
243 FIXME("I don't know how to handle this type!\n");
244 return E_NOTIMPL;
247 obj = get_object(*argv);
249 /* Try to get a IEnumVARIANT by _NewEnum */
250 VariantInit(&varresult);
251 hres = IDispatch_Invoke(obj, DISPID_NEWENUM, &IID_NULL, LOCALE_NEUTRAL,
252 DISPATCH_METHOD, &dispparams, &varresult, NULL, NULL);
253 if (FAILED(hres))
255 WARN("Enumerator: no DISPID_NEWENUM.\n");
256 return E_INVALIDARG;
259 if ((V_VT(&varresult) == VT_DISPATCH) || (V_VT(&varresult) == VT_UNKNOWN))
261 hres = IUnknown_QueryInterface(V_UNKNOWN(&varresult),
262 &IID_IEnumVARIANT, (void**)&enumvar);
264 else
266 FIXME("Enumerator: NewEnum unexpected type of varresult (%d).\n", V_VT(&varresult));
267 hres = E_INVALIDARG;
269 VariantClear(&varresult);
270 if (FAILED(hres))
271 return hres;
274 hres = alloc_enumerator(ctx, NULL, &enumerator);
275 if (FAILED(hres))
277 if (enumvar)
278 IEnumVARIANT_Release(enumvar);
279 return hres;
282 enumerator->enumvar = enumvar;
283 enumerator->atend = !enumvar;
284 hres = enumvar_get_next_item(enumerator, ctx);
285 if (FAILED(hres))
287 jsdisp_release(&enumerator->dispex);
288 return hres;
291 *ret = &enumerator->dispex;
292 return S_OK;
295 static HRESULT EnumeratorConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
296 jsval_t *r)
298 jsdisp_t *obj;
299 HRESULT hres;
301 TRACE("\n");
303 switch(flags) {
304 case DISPATCH_CONSTRUCT: {
305 if (argc > 1)
306 return JS_E_INVALIDARG;
308 hres = create_enumerator(ctx, (argc == 1) ? &argv[0] : 0, &obj);
309 if(FAILED(hres))
310 return hres;
312 if(r) *r = jsval_obj(obj);
313 else jsdisp_release(obj);
314 break;
316 default:
317 FIXME("unimplemented flags: %x\n", flags);
318 return E_NOTIMPL;
321 return S_OK;
324 static const builtin_info_t EnumeratorConstr_info = {
325 JSCLASS_FUNCTION,
326 Function_value,
328 NULL,
329 NULL,
330 NULL
333 HRESULT create_enumerator_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
335 EnumeratorInstance *enumerator;
336 HRESULT hres;
338 hres = alloc_enumerator(ctx, object_prototype, &enumerator);
339 if(FAILED(hres))
340 return hres;
342 hres = create_builtin_constructor(ctx, EnumeratorConstr_value, L"Enumerator",
343 &EnumeratorConstr_info, PROPF_CONSTR|7, &enumerator->dispex, ret);
344 jsdisp_release(&enumerator->dispex);
346 return hres;