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_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
)
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
);
63 hres
= variant_to_jsval(ctx
, &nextitem
, &This
->item
);
64 VariantClear(&nextitem
);
67 WARN("failed to convert jsval to variant!\n");
68 This
->item
= jsval_undefined();
74 This
->item
= jsval_undefined();
81 static void Enumerator_destructor(jsdisp_t
*dispex
)
83 EnumeratorInstance
*This
= enumerator_from_jsdisp(dispex
);
88 IEnumVARIANT_Release(This
->enumvar
);
89 jsval_release(This
->item
);
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
,
101 EnumeratorInstance
*This
;
103 if (!(This
= enumerator_this(vthis
)))
104 return JS_E_ENUMERATOR_EXPECTED
;
106 TRACE("%d\n", This
->atend
);
109 *r
= jsval_bool(This
->atend
);
113 static HRESULT
Enumerator_item(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
116 EnumeratorInstance
*This
;
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
,
129 EnumeratorInstance
*This
;
134 if (!(This
= enumerator_this(vthis
)))
135 return JS_E_ENUMERATOR_EXPECTED
;
139 hres
= IEnumVARIANT_Reset(This
->enumvar
);
144 hres
= enumvar_get_next_item(This
, ctx
);
150 *r
= jsval_undefined();
154 static HRESULT
Enumerator_moveNext(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
157 EnumeratorInstance
*This
;
162 if (!(This
= enumerator_this(vthis
)))
163 return JS_E_ENUMERATOR_EXPECTED
;
167 hres
= enumvar_get_next_item(This
, ctx
);
173 *r
= jsval_undefined();
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
= {
187 ARRAY_SIZE(Enumerator_props
),
193 static const builtin_info_t EnumeratorInst_info
= {
198 Enumerator_destructor
,
203 Enumerator_gc_traverse
206 static HRESULT
alloc_enumerator(script_ctx_t
*ctx
, jsdisp_t
*object_prototype
, EnumeratorInstance
**ret
)
208 EnumeratorInstance
*enumerator
;
211 enumerator
= calloc(1, sizeof(EnumeratorInstance
));
213 return E_OUTOFMEMORY
;
216 hres
= init_dispex(&enumerator
->dispex
, ctx
, &Enumerator_info
, object_prototype
);
218 hres
= init_dispex_from_constr(&enumerator
->dispex
, ctx
, &EnumeratorInst_info
,
219 ctx
->enumerator_constr
);
231 static HRESULT
create_enumerator(script_ctx_t
*ctx
, jsval_t
*argv
, jsdisp_t
**ret
)
233 EnumeratorInstance
*enumerator
;
236 DISPPARAMS dispparams
= {NULL
, NULL
, 0, 0};
237 IEnumVARIANT
*enumvar
= NULL
;
243 if (!is_object_instance(*argv
))
245 FIXME("I don't know how to handle this type!\n");
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
);
257 WARN("Enumerator: no DISPID_NEWENUM.\n");
261 if ((V_VT(&varresult
) == VT_DISPATCH
) || (V_VT(&varresult
) == VT_UNKNOWN
))
263 hres
= IUnknown_QueryInterface(V_UNKNOWN(&varresult
),
264 &IID_IEnumVARIANT
, (void**)&enumvar
);
268 FIXME("Enumerator: NewEnum unexpected type of varresult (%d).\n", V_VT(&varresult
));
271 VariantClear(&varresult
);
276 hres
= alloc_enumerator(ctx
, NULL
, &enumerator
);
280 IEnumVARIANT_Release(enumvar
);
284 enumerator
->enumvar
= enumvar
;
285 enumerator
->atend
= !enumvar
;
286 hres
= enumvar_get_next_item(enumerator
, ctx
);
289 jsdisp_release(&enumerator
->dispex
);
293 *ret
= &enumerator
->dispex
;
297 static HRESULT
EnumeratorConstr_value(script_ctx_t
*ctx
, jsval_t vthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
306 case DISPATCH_CONSTRUCT
: {
308 return JS_E_INVALIDARG
;
310 hres
= create_enumerator(ctx
, (argc
== 1) ? &argv
[0] : 0, &obj
);
314 if(r
) *r
= jsval_obj(obj
);
315 else jsdisp_release(obj
);
319 FIXME("unimplemented flags: %x\n", flags
);
326 static const builtin_info_t EnumeratorConstr_info
= {
335 HRESULT
create_enumerator_constr(script_ctx_t
*ctx
, jsdisp_t
*object_prototype
, jsdisp_t
**ret
)
337 EnumeratorInstance
*enumerator
;
340 hres
= alloc_enumerator(ctx
, object_prototype
, &enumerator
);
344 hres
= create_builtin_constructor(ctx
, EnumeratorConstr_value
, L
"Enumerator",
345 &EnumeratorConstr_info
, PROPF_CONSTR
|7, &enumerator
->dispex
, ret
);
346 jsdisp_release(&enumerator
->dispex
);