jscript: Treat NULL disps as actual null values in html mode.
[wine.git] / dlls / jscript / enumerator.c
blob94eb9f209bc6831756f42f01c3ed1d93c415f7bf
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 heap_free(dispex);
91 static HRESULT Enumerator_atEnd(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
92 jsval_t *r)
94 EnumeratorInstance *This;
96 if (!(This = enumerator_this(vthis)))
97 return JS_E_ENUMERATOR_EXPECTED;
99 TRACE("%d\n", This->atend);
101 if (r)
102 *r = jsval_bool(This->atend);
103 return S_OK;
106 static HRESULT Enumerator_item(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
107 jsval_t *r)
109 EnumeratorInstance *This;
111 TRACE("\n");
113 if (!(This = enumerator_this(vthis)))
114 return JS_E_ENUMERATOR_EXPECTED;
116 return r ? jsval_copy(This->item, r) : S_OK;
119 static HRESULT Enumerator_moveFirst(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
120 jsval_t *r)
122 EnumeratorInstance *This;
123 HRESULT hres = S_OK;
125 TRACE("\n");
127 if (!(This = enumerator_this(vthis)))
128 return JS_E_ENUMERATOR_EXPECTED;
130 if (This->enumvar)
132 hres = IEnumVARIANT_Reset(This->enumvar);
133 if (FAILED(hres))
134 return hres;
136 This->atend = FALSE;
137 hres = enumvar_get_next_item(This, ctx);
138 if(FAILED(hres))
139 return hres;
142 if (r)
143 *r = jsval_undefined();
144 return S_OK;
147 static HRESULT Enumerator_moveNext(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
148 jsval_t *r)
150 EnumeratorInstance *This;
151 HRESULT hres = S_OK;
153 TRACE("\n");
155 if (!(This = enumerator_this(vthis)))
156 return JS_E_ENUMERATOR_EXPECTED;
158 if (This->enumvar)
160 hres = enumvar_get_next_item(This, ctx);
161 if (FAILED(hres))
162 return hres;
165 if (r)
166 *r = jsval_undefined();
167 return S_OK;
170 static const builtin_prop_t Enumerator_props[] = {
171 {L"atEnd", Enumerator_atEnd, PROPF_METHOD},
172 {L"item", Enumerator_item, PROPF_METHOD},
173 {L"moveFirst", Enumerator_moveFirst, PROPF_METHOD},
174 {L"moveNext", Enumerator_moveNext, PROPF_METHOD},
177 static const builtin_info_t Enumerator_info = {
178 JSCLASS_ENUMERATOR,
179 NULL,
180 ARRAY_SIZE(Enumerator_props),
181 Enumerator_props,
182 NULL,
183 NULL
186 static const builtin_info_t EnumeratorInst_info = {
187 JSCLASS_ENUMERATOR,
188 NULL,
190 NULL,
191 Enumerator_destructor,
192 NULL
195 static HRESULT alloc_enumerator(script_ctx_t *ctx, jsdisp_t *object_prototype, EnumeratorInstance **ret)
197 EnumeratorInstance *enumerator;
198 HRESULT hres;
200 enumerator = heap_alloc_zero(sizeof(EnumeratorInstance));
201 if(!enumerator)
202 return E_OUTOFMEMORY;
204 if(object_prototype)
205 hres = init_dispex(&enumerator->dispex, ctx, &Enumerator_info, object_prototype);
206 else
207 hres = init_dispex_from_constr(&enumerator->dispex, ctx, &EnumeratorInst_info,
208 ctx->enumerator_constr);
210 if(FAILED(hres))
212 heap_free(enumerator);
213 return hres;
216 *ret = enumerator;
217 return S_OK;
220 static HRESULT create_enumerator(script_ctx_t *ctx, jsval_t *argv, jsdisp_t **ret)
222 EnumeratorInstance *enumerator;
223 HRESULT hres;
224 IDispatch *obj;
225 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
226 IEnumVARIANT *enumvar = NULL;
228 if (argv)
230 VARIANT varresult;
232 if (!is_object_instance(*argv))
234 FIXME("I don't know how to handle this type!\n");
235 return E_NOTIMPL;
238 obj = get_object(*argv);
240 /* Try to get a IEnumVARIANT by _NewEnum */
241 VariantInit(&varresult);
242 hres = IDispatch_Invoke(obj, DISPID_NEWENUM, &IID_NULL, LOCALE_NEUTRAL,
243 DISPATCH_METHOD, &dispparams, &varresult, NULL, NULL);
244 if (FAILED(hres))
246 WARN("Enumerator: no DISPID_NEWENUM.\n");
247 return E_INVALIDARG;
250 if ((V_VT(&varresult) == VT_DISPATCH) || (V_VT(&varresult) == VT_UNKNOWN))
252 hres = IUnknown_QueryInterface(V_UNKNOWN(&varresult),
253 &IID_IEnumVARIANT, (void**)&enumvar);
255 else
257 FIXME("Enumerator: NewEnum unexpected type of varresult (%d).\n", V_VT(&varresult));
258 hres = E_INVALIDARG;
260 VariantClear(&varresult);
261 if (FAILED(hres))
262 return hres;
265 hres = alloc_enumerator(ctx, NULL, &enumerator);
266 if (FAILED(hres))
268 if (enumvar)
269 IEnumVARIANT_Release(enumvar);
270 return hres;
273 enumerator->enumvar = enumvar;
274 enumerator->atend = !enumvar;
275 hres = enumvar_get_next_item(enumerator, ctx);
276 if (FAILED(hres))
278 jsdisp_release(&enumerator->dispex);
279 return hres;
282 *ret = &enumerator->dispex;
283 return S_OK;
286 static HRESULT EnumeratorConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
287 jsval_t *r)
289 jsdisp_t *obj;
290 HRESULT hres;
292 TRACE("\n");
294 switch(flags) {
295 case DISPATCH_CONSTRUCT: {
296 if (argc > 1)
297 return JS_E_INVALIDARG;
299 hres = create_enumerator(ctx, (argc == 1) ? &argv[0] : 0, &obj);
300 if(FAILED(hres))
301 return hres;
303 *r = jsval_obj(obj);
304 break;
306 default:
307 FIXME("unimplemented flags: %x\n", flags);
308 return E_NOTIMPL;
311 return S_OK;
314 static const builtin_info_t EnumeratorConstr_info = {
315 JSCLASS_FUNCTION,
316 Function_value,
318 NULL,
319 NULL,
320 NULL
323 HRESULT create_enumerator_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
325 EnumeratorInstance *enumerator;
326 HRESULT hres;
328 hres = alloc_enumerator(ctx, object_prototype, &enumerator);
329 if(FAILED(hres))
330 return hres;
332 hres = create_builtin_constructor(ctx, EnumeratorConstr_value, L"Enumerator",
333 &EnumeratorConstr_info, PROPF_CONSTR|7, &enumerator->dispex, ret);
334 jsdisp_release(&enumerator->dispex);
336 return hres;