include: Use proper dllimports for propsys functions.
[wine.git] / dlls / jscript / enumerator.c
blobd962c65d229723f96939e5a20035a10c16c32e0f
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 if(This->enumvar)
88 IEnumVARIANT_Release(This->enumvar);
89 jsval_release(This->item);
90 free(dispex);
93 static HRESULT Enumerator_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, jsdisp_t *dispex)
95 return gc_process_linked_val(gc_ctx, op, dispex, &enumerator_from_jsdisp(dispex)->item);
98 static HRESULT Enumerator_atEnd(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
99 jsval_t *r)
101 EnumeratorInstance *This;
103 if (!(This = enumerator_this(vthis)))
104 return JS_E_ENUMERATOR_EXPECTED;
106 TRACE("%d\n", This->atend);
108 if (r)
109 *r = jsval_bool(This->atend);
110 return S_OK;
113 static HRESULT Enumerator_item(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
114 jsval_t *r)
116 EnumeratorInstance *This;
118 TRACE("\n");
120 if (!(This = enumerator_this(vthis)))
121 return JS_E_ENUMERATOR_EXPECTED;
123 return r ? jsval_copy(This->item, r) : S_OK;
126 static HRESULT Enumerator_moveFirst(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
127 jsval_t *r)
129 EnumeratorInstance *This;
130 HRESULT hres = S_OK;
132 TRACE("\n");
134 if (!(This = enumerator_this(vthis)))
135 return JS_E_ENUMERATOR_EXPECTED;
137 if (This->enumvar)
139 hres = IEnumVARIANT_Reset(This->enumvar);
140 if (FAILED(hres))
141 return hres;
143 This->atend = FALSE;
144 hres = enumvar_get_next_item(This, ctx);
145 if(FAILED(hres))
146 return hres;
149 if (r)
150 *r = jsval_undefined();
151 return S_OK;
154 static HRESULT Enumerator_moveNext(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
155 jsval_t *r)
157 EnumeratorInstance *This;
158 HRESULT hres = S_OK;
160 TRACE("\n");
162 if (!(This = enumerator_this(vthis)))
163 return JS_E_ENUMERATOR_EXPECTED;
165 if (This->enumvar)
167 hres = enumvar_get_next_item(This, ctx);
168 if (FAILED(hres))
169 return hres;
172 if (r)
173 *r = jsval_undefined();
174 return S_OK;
177 static const builtin_prop_t Enumerator_props[] = {
178 {L"atEnd", Enumerator_atEnd, PROPF_METHOD},
179 {L"item", Enumerator_item, PROPF_METHOD},
180 {L"moveFirst", Enumerator_moveFirst, PROPF_METHOD},
181 {L"moveNext", Enumerator_moveNext, PROPF_METHOD},
184 static const builtin_info_t Enumerator_info = {
185 JSCLASS_ENUMERATOR,
186 NULL,
187 ARRAY_SIZE(Enumerator_props),
188 Enumerator_props,
189 NULL,
190 NULL
193 static const builtin_info_t EnumeratorInst_info = {
194 JSCLASS_ENUMERATOR,
195 NULL,
197 NULL,
198 Enumerator_destructor,
199 NULL,
200 NULL,
201 NULL,
202 NULL,
203 Enumerator_gc_traverse
206 static HRESULT alloc_enumerator(script_ctx_t *ctx, jsdisp_t *object_prototype, EnumeratorInstance **ret)
208 EnumeratorInstance *enumerator;
209 HRESULT hres;
211 enumerator = calloc(1, sizeof(EnumeratorInstance));
212 if(!enumerator)
213 return E_OUTOFMEMORY;
215 if(object_prototype)
216 hres = init_dispex(&enumerator->dispex, ctx, &Enumerator_info, object_prototype);
217 else
218 hres = init_dispex_from_constr(&enumerator->dispex, ctx, &EnumeratorInst_info,
219 ctx->enumerator_constr);
221 if(FAILED(hres))
223 free(enumerator);
224 return hres;
227 *ret = enumerator;
228 return S_OK;
231 static HRESULT create_enumerator(script_ctx_t *ctx, jsval_t *argv, jsdisp_t **ret)
233 EnumeratorInstance *enumerator;
234 HRESULT hres;
235 IDispatch *obj;
236 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
237 IEnumVARIANT *enumvar = NULL;
239 if (argv)
241 VARIANT varresult;
243 if (!is_object_instance(*argv))
245 FIXME("I don't know how to handle this type!\n");
246 return E_NOTIMPL;
249 obj = get_object(*argv);
251 /* Try to get a IEnumVARIANT by _NewEnum */
252 VariantInit(&varresult);
253 hres = IDispatch_Invoke(obj, DISPID_NEWENUM, &IID_NULL, LOCALE_NEUTRAL,
254 DISPATCH_METHOD, &dispparams, &varresult, NULL, NULL);
255 if (FAILED(hres))
257 WARN("Enumerator: no DISPID_NEWENUM.\n");
258 return E_INVALIDARG;
261 if ((V_VT(&varresult) == VT_DISPATCH) || (V_VT(&varresult) == VT_UNKNOWN))
263 hres = IUnknown_QueryInterface(V_UNKNOWN(&varresult),
264 &IID_IEnumVARIANT, (void**)&enumvar);
266 else
268 FIXME("Enumerator: NewEnum unexpected type of varresult (%d).\n", V_VT(&varresult));
269 hres = E_INVALIDARG;
271 VariantClear(&varresult);
272 if (FAILED(hres))
273 return hres;
276 hres = alloc_enumerator(ctx, NULL, &enumerator);
277 if (FAILED(hres))
279 if (enumvar)
280 IEnumVARIANT_Release(enumvar);
281 return hres;
284 enumerator->enumvar = enumvar;
285 enumerator->atend = !enumvar;
286 hres = enumvar_get_next_item(enumerator, ctx);
287 if (FAILED(hres))
289 jsdisp_release(&enumerator->dispex);
290 return hres;
293 *ret = &enumerator->dispex;
294 return S_OK;
297 static HRESULT EnumeratorConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
298 jsval_t *r)
300 jsdisp_t *obj;
301 HRESULT hres;
303 TRACE("\n");
305 switch(flags) {
306 case DISPATCH_CONSTRUCT: {
307 if (argc > 1)
308 return JS_E_INVALIDARG;
310 hres = create_enumerator(ctx, (argc == 1) ? &argv[0] : 0, &obj);
311 if(FAILED(hres))
312 return hres;
314 if(r) *r = jsval_obj(obj);
315 else jsdisp_release(obj);
316 break;
318 default:
319 FIXME("unimplemented flags: %x\n", flags);
320 return E_NOTIMPL;
323 return S_OK;
326 static const builtin_info_t EnumeratorConstr_info = {
327 JSCLASS_FUNCTION,
328 Function_value,
330 NULL,
331 NULL,
332 NULL
335 HRESULT create_enumerator_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
337 EnumeratorInstance *enumerator;
338 HRESULT hres;
340 hres = alloc_enumerator(ctx, object_prototype, &enumerator);
341 if(FAILED(hres))
342 return hres;
344 hres = create_builtin_constructor(ctx, EnumeratorConstr_value, L"Enumerator",
345 &EnumeratorConstr_info, PROPF_CONSTR|7, &enumerator->dispex, ret);
346 jsdisp_release(&enumerator->dispex);
348 return hres;