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
23 #include "wine/debug.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(jscript
);
29 /* IEnumVARIANT returned by _NewEnum */
30 IEnumVARIANT
*enumvar
;
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
)
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
);
67 hres
= variant_to_jsval(&nextitem
, &This
->item
);
68 VariantClear(&nextitem
);
71 WARN("failed to convert jsval to variant!\n");
72 This
->item
= jsval_undefined();
78 This
->item
= jsval_undefined();
85 static void Enumerator_destructor(jsdisp_t
*dispex
)
87 EnumeratorInstance
*This
= enumerator_from_jsdisp(dispex
);
91 jsval_release(This
->item
);
95 static HRESULT
Enumerator_atEnd(script_ctx_t
*ctx
, vdisp_t
*jsthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
98 EnumeratorInstance
*This
;
100 if (!(This
= enumerator_this(jsthis
)))
101 return JS_E_ENUMERATOR_EXPECTED
;
103 TRACE("%d\n", This
->atend
);
106 *r
= jsval_bool(This
->atend
);
110 static HRESULT
Enumerator_item(script_ctx_t
*ctx
, vdisp_t
*jsthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
113 EnumeratorInstance
*This
;
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
,
126 EnumeratorInstance
*This
;
131 if (!(This
= enumerator_this(jsthis
)))
132 return JS_E_ENUMERATOR_EXPECTED
;
136 hres
= IEnumVARIANT_Reset(This
->enumvar
);
141 hres
= enumvar_get_next_item(This
);
147 *r
= jsval_undefined();
151 static HRESULT
Enumerator_moveNext(script_ctx_t
*ctx
, vdisp_t
*jsthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
154 EnumeratorInstance
*This
;
159 if (!(This
= enumerator_this(jsthis
)))
160 return JS_E_ENUMERATOR_EXPECTED
;
164 hres
= enumvar_get_next_item(This
);
170 *r
= jsval_undefined();
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
= {
184 ARRAY_SIZE(Enumerator_props
),
190 static const builtin_info_t EnumeratorInst_info
= {
192 {NULL
, NULL
, 0, NULL
},
195 Enumerator_destructor
,
199 static HRESULT
alloc_enumerator(script_ctx_t
*ctx
, jsdisp_t
*object_prototype
, EnumeratorInstance
**ret
)
201 EnumeratorInstance
*enumerator
;
204 enumerator
= heap_alloc_zero(sizeof(EnumeratorInstance
));
206 return E_OUTOFMEMORY
;
209 hres
= init_dispex(&enumerator
->dispex
, ctx
, &Enumerator_info
, object_prototype
);
211 hres
= init_dispex_from_constr(&enumerator
->dispex
, ctx
, &EnumeratorInst_info
,
212 ctx
->enumerator_constr
);
216 heap_free(enumerator
);
224 static HRESULT
create_enumerator(script_ctx_t
*ctx
, jsval_t
*argv
, jsdisp_t
**ret
)
226 EnumeratorInstance
*enumerator
;
229 DISPPARAMS dispparams
= {NULL
, NULL
, 0, 0};
230 IEnumVARIANT
*enumvar
= NULL
;
236 if (!is_object_instance(*argv
))
238 FIXME("I don't know how to handle this type!\n");
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
);
250 WARN("Enumerator: no DISPID_NEWENUM.\n");
254 if ((V_VT(&varresult
) == VT_DISPATCH
) || (V_VT(&varresult
) == VT_UNKNOWN
))
256 hres
= IUnknown_QueryInterface(V_UNKNOWN(&varresult
),
257 &IID_IEnumVARIANT
, (void**)&enumvar
);
261 FIXME("Enumerator: NewEnum unexpected type of varresult (%d).\n", V_VT(&varresult
));
264 VariantClear(&varresult
);
269 hres
= alloc_enumerator(ctx
, NULL
, &enumerator
);
273 IEnumVARIANT_Release(enumvar
);
277 enumerator
->enumvar
= enumvar
;
278 enumerator
->atend
= !enumvar
;
279 hres
= enumvar_get_next_item(enumerator
);
282 jsdisp_release(&enumerator
->dispex
);
286 *ret
= &enumerator
->dispex
;
290 static HRESULT
EnumeratorConstr_value(script_ctx_t
*ctx
, vdisp_t
*vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
299 case DISPATCH_CONSTRUCT
: {
301 return JS_E_INVALIDARG
;
303 hres
= create_enumerator(ctx
, (argc
== 1) ? &argv
[0] : 0, &obj
);
311 FIXME("unimplemented flags: %x\n", flags
);
318 static const builtin_info_t EnumeratorConstr_info
= {
320 DEFAULT_FUNCTION_VALUE
,
327 HRESULT
create_enumerator_constr(script_ctx_t
*ctx
, jsdisp_t
*object_prototype
, jsdisp_t
**ret
)
329 EnumeratorInstance
*enumerator
;
332 hres
= alloc_enumerator(ctx
, object_prototype
, &enumerator
);
336 hres
= create_builtin_constructor(ctx
, EnumeratorConstr_value
, L
"Enumerator",
337 &EnumeratorConstr_info
, PROPF_CONSTR
|7, &enumerator
->dispex
, ret
);
338 jsdisp_release(&enumerator
->dispex
);