mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / dlls / jscript / enumerator.c
blobdea1940669529ce449c33a070c9b823777c8cf55
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_from_vdisp(vdisp_t *vdisp)
43 return enumerator_from_jsdisp(vdisp->u.jsdisp);
46 static inline EnumeratorInstance *enumerator_this(vdisp_t *jsthis)
48 return is_vclass(jsthis, JSCLASS_ENUMERATOR) ? enumerator_from_vdisp(jsthis) : NULL;
51 static inline HRESULT enumvar_get_next_item(EnumeratorInstance *This)
53 HRESULT hres;
54 VARIANT nextitem;
56 if (This->atend)
57 return S_OK;
59 /* don't leak previous value */
60 jsval_release(This->item);
62 /* not at end ... get next item */
63 VariantInit(&nextitem);
64 hres = IEnumVARIANT_Next(This->enumvar, 1, &nextitem, NULL);
65 if (hres == S_OK)
67 hres = variant_to_jsval(&nextitem, &This->item);
68 VariantClear(&nextitem);
69 if (FAILED(hres))
71 WARN("failed to convert jsval to variant!\n");
72 This->item = jsval_undefined();
73 return hres;
76 else
78 This->item = jsval_undefined();
79 This->atend = TRUE;
82 return S_OK;
85 static void Enumerator_destructor(jsdisp_t *dispex)
87 EnumeratorInstance *This = enumerator_from_jsdisp(dispex);
89 TRACE("\n");
91 jsval_release(This->item);
92 heap_free(dispex);
95 static HRESULT Enumerator_atEnd(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
96 jsval_t *r)
98 EnumeratorInstance *This;
100 if (!(This = enumerator_this(jsthis)))
101 return JS_E_ENUMERATOR_EXPECTED;
103 TRACE("%d\n", This->atend);
105 if (r)
106 *r = jsval_bool(This->atend);
107 return S_OK;
110 static HRESULT Enumerator_item(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
111 jsval_t *r)
113 EnumeratorInstance *This;
115 TRACE("\n");
117 if (!(This = enumerator_this(jsthis)))
118 return JS_E_ENUMERATOR_EXPECTED;
120 return r ? jsval_copy(This->item, r) : S_OK;
123 static HRESULT Enumerator_moveFirst(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
124 jsval_t *r)
126 EnumeratorInstance *This;
127 HRESULT hres = S_OK;
129 TRACE("\n");
131 if (!(This = enumerator_this(jsthis)))
132 return JS_E_ENUMERATOR_EXPECTED;
134 if (This->enumvar)
136 hres = IEnumVARIANT_Reset(This->enumvar);
137 if (FAILED(hres))
138 return hres;
140 This->atend = FALSE;
141 hres = enumvar_get_next_item(This);
142 if(FAILED(hres))
143 return hres;
146 if (r)
147 *r = jsval_undefined();
148 return S_OK;
151 static HRESULT Enumerator_moveNext(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
152 jsval_t *r)
154 EnumeratorInstance *This;
155 HRESULT hres = S_OK;
157 TRACE("\n");
159 if (!(This = enumerator_this(jsthis)))
160 return JS_E_ENUMERATOR_EXPECTED;
162 if (This->enumvar)
164 hres = enumvar_get_next_item(This);
165 if (FAILED(hres))
166 return hres;
169 if (r)
170 *r = jsval_undefined();
171 return S_OK;
174 static const builtin_prop_t Enumerator_props[] = {
175 {L"atEnd", Enumerator_atEnd, PROPF_METHOD},
176 {L"item", Enumerator_item, PROPF_METHOD},
177 {L"moveFirst", Enumerator_moveFirst, PROPF_METHOD},
178 {L"moveNext", Enumerator_moveNext, PROPF_METHOD},
181 static const builtin_info_t Enumerator_info = {
182 JSCLASS_ENUMERATOR,
183 {NULL, NULL, 0},
184 ARRAY_SIZE(Enumerator_props),
185 Enumerator_props,
186 NULL,
187 NULL
190 static const builtin_info_t EnumeratorInst_info = {
191 JSCLASS_ENUMERATOR,
192 {NULL, NULL, 0, NULL},
194 NULL,
195 Enumerator_destructor,
196 NULL
199 static HRESULT alloc_enumerator(script_ctx_t *ctx, jsdisp_t *object_prototype, EnumeratorInstance **ret)
201 EnumeratorInstance *enumerator;
202 HRESULT hres;
204 enumerator = heap_alloc_zero(sizeof(EnumeratorInstance));
205 if(!enumerator)
206 return E_OUTOFMEMORY;
208 if(object_prototype)
209 hres = init_dispex(&enumerator->dispex, ctx, &Enumerator_info, object_prototype);
210 else
211 hres = init_dispex_from_constr(&enumerator->dispex, ctx, &EnumeratorInst_info,
212 ctx->enumerator_constr);
214 if(FAILED(hres))
216 heap_free(enumerator);
217 return hres;
220 *ret = enumerator;
221 return S_OK;
224 static HRESULT create_enumerator(script_ctx_t *ctx, jsval_t *argv, jsdisp_t **ret)
226 EnumeratorInstance *enumerator;
227 HRESULT hres;
228 IDispatch *obj;
229 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
230 IEnumVARIANT *enumvar = NULL;
232 if (argv)
234 VARIANT varresult;
236 if (!is_object_instance(*argv))
238 FIXME("I don't know how to handle this type!\n");
239 return E_NOTIMPL;
242 obj = get_object(*argv);
244 /* Try to get a IEnumVARIANT by _NewEnum */
245 VariantInit(&varresult);
246 hres = IDispatch_Invoke(obj, DISPID_NEWENUM, &IID_NULL, LOCALE_NEUTRAL,
247 DISPATCH_METHOD, &dispparams, &varresult, NULL, NULL);
248 if (FAILED(hres))
250 WARN("Enumerator: no DISPID_NEWENUM.\n");
251 return E_INVALIDARG;
254 if ((V_VT(&varresult) == VT_DISPATCH) || (V_VT(&varresult) == VT_UNKNOWN))
256 hres = IUnknown_QueryInterface(V_UNKNOWN(&varresult),
257 &IID_IEnumVARIANT, (void**)&enumvar);
259 else
261 FIXME("Enumerator: NewEnum unexpected type of varresult (%d).\n", V_VT(&varresult));
262 hres = E_INVALIDARG;
264 VariantClear(&varresult);
265 if (FAILED(hres))
266 return hres;
269 hres = alloc_enumerator(ctx, NULL, &enumerator);
270 if (FAILED(hres))
272 if (enumvar)
273 IEnumVARIANT_Release(enumvar);
274 return hres;
277 enumerator->enumvar = enumvar;
278 enumerator->atend = !enumvar;
279 hres = enumvar_get_next_item(enumerator);
280 if (FAILED(hres))
282 jsdisp_release(&enumerator->dispex);
283 return hres;
286 *ret = &enumerator->dispex;
287 return S_OK;
290 static HRESULT EnumeratorConstr_value(script_ctx_t *ctx, vdisp_t *vthis, WORD flags, unsigned argc, jsval_t *argv,
291 jsval_t *r)
293 jsdisp_t *obj;
294 HRESULT hres;
296 TRACE("\n");
298 switch(flags) {
299 case DISPATCH_CONSTRUCT: {
300 if (argc > 1)
301 return JS_E_INVALIDARG;
303 hres = create_enumerator(ctx, (argc == 1) ? &argv[0] : 0, &obj);
304 if(FAILED(hres))
305 return hres;
307 *r = jsval_obj(obj);
308 break;
310 default:
311 FIXME("unimplemented flags: %x\n", flags);
312 return E_NOTIMPL;
315 return S_OK;
318 static const builtin_info_t EnumeratorConstr_info = {
319 JSCLASS_FUNCTION,
320 DEFAULT_FUNCTION_VALUE,
322 NULL,
323 NULL,
324 NULL
327 HRESULT create_enumerator_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
329 EnumeratorInstance *enumerator;
330 HRESULT hres;
332 hres = alloc_enumerator(ctx, object_prototype, &enumerator);
333 if(FAILED(hres))
334 return hres;
336 hres = create_builtin_constructor(ctx, EnumeratorConstr_value, L"Enumerator",
337 &EnumeratorConstr_info, PROPF_CONSTR|7, &enumerator->dispex, ret);
338 jsdisp_release(&enumerator->dispex);
340 return hres;