jscript.h 12.4 KB
Newer Older
1
/*
2
 * Copyright 2008-2009 Jacek Caban for CodeWeavers
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include <stdarg.h>
#include <stdio.h>

#define COBJMACROS

#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "ole2.h"
28
#include "dispex.h"
29 30
#include "activscp.h"

31 32
#include "resource.h"

Jacek Caban's avatar
Jacek Caban committed
33
#include "wine/unicode.h"
34
#include "wine/list.h"
Jacek Caban's avatar
Jacek Caban committed
35

36 37
#define JSCRIPT_ERROR 0x800A0000

38
typedef struct _script_ctx_t script_ctx_t;
39
typedef struct _exec_ctx_t exec_ctx_t;
40
typedef struct _dispex_prop_t dispex_prop_t;
41 42 43 44 45

typedef struct {
    EXCEPINFO ei;
    VARIANT var;
} jsexcept_t;
46

47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
typedef struct {
    void **blocks;
    DWORD block_cnt;
    DWORD last_block;
    DWORD offset;
    BOOL mark;
    struct list custom_blocks;
} jsheap_t;

void jsheap_init(jsheap_t*);
void *jsheap_alloc(jsheap_t*,DWORD);
void *jsheap_grow(jsheap_t*,void*,DWORD,DWORD);
void jsheap_clear(jsheap_t*);
void jsheap_free(jsheap_t*);
jsheap_t *jsheap_mark(jsheap_t*);

63 64
typedef struct DispatchEx DispatchEx;

65 66
extern HINSTANCE jscript_hinstance;

67 68 69 70 71
#define PROPF_ARGMASK 0x00ff
#define PROPF_METHOD  0x0100
#define PROPF_ENUM    0x0200
#define PROPF_CONSTR  0x0400

72
/* NOTE: Keep in sync with names in Object.toString implementation */
73
typedef enum {
74
    JSCLASS_NONE,
75
    JSCLASS_ARRAY,
76
    JSCLASS_BOOLEAN,
77
    JSCLASS_DATE,
78
    JSCLASS_ERROR,
79
    JSCLASS_FUNCTION,
80
    JSCLASS_GLOBAL,
81
    JSCLASS_MATH,
82
    JSCLASS_NUMBER,
83
    JSCLASS_OBJECT,
84
    JSCLASS_REGEXP,
85 86
    JSCLASS_STRING,
    JSCLASS_ARGUMENTS
87 88
} jsclass_t;

89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
DispatchEx *iface_to_jsdisp(IUnknown*);

typedef struct {
    union {
        IDispatch *disp;
        IDispatchEx *dispex;
        DispatchEx *jsdisp;
    } u;
    DWORD flags;
} vdisp_t;

#define VDISP_DISPEX  0x0001
#define VDISP_JSDISP  0x0002

static inline void vdisp_release(vdisp_t *vdisp)
{
    IDispatch_Release(vdisp->u.disp);
}

static inline BOOL is_jsdisp(vdisp_t *vdisp)
{
    return (vdisp->flags & VDISP_JSDISP) != 0;
}

static inline BOOL is_dispex(vdisp_t *vdisp)
{
    return (vdisp->flags & VDISP_DISPEX) != 0;
}

static inline void set_jsdisp(vdisp_t *vdisp, DispatchEx *jsdisp)
{
    vdisp->u.jsdisp = jsdisp;
    vdisp->flags = VDISP_JSDISP | VDISP_DISPEX;
    IDispatch_AddRef(vdisp->u.disp);
}

static inline void set_disp(vdisp_t *vdisp, IDispatch *disp)
{
    IDispatchEx *dispex;
    DispatchEx *jsdisp;
    HRESULT hres;

    jsdisp = iface_to_jsdisp((IUnknown*)disp);
    if(jsdisp) {
        vdisp->u.jsdisp = jsdisp;
        vdisp->flags = VDISP_JSDISP | VDISP_DISPEX;
        return;
    }

    hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
    if(SUCCEEDED(hres)) {
        vdisp->u.dispex = dispex;
        vdisp->flags = VDISP_DISPEX;
        return;
    }

    IDispatch_AddRef(disp);
    vdisp->u.disp = disp;
    vdisp->flags = 0;
}

static inline DispatchEx *get_jsdisp(vdisp_t *vdisp)
{
    return is_jsdisp(vdisp) ? vdisp->u.jsdisp : NULL;
}

typedef HRESULT (*builtin_invoke_t)(script_ctx_t*,vdisp_t*,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*,IServiceProvider*);
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172

typedef struct {
    const WCHAR *name;
    builtin_invoke_t invoke;
    DWORD flags;
} builtin_prop_t;

typedef struct {
    jsclass_t class;
    builtin_prop_t value_prop;
    DWORD props_cnt;
    const builtin_prop_t *props;
    void (*destructor)(DispatchEx*);
    void (*on_put)(DispatchEx*,const WCHAR*);
} builtin_info_t;

struct DispatchEx {
173 174 175 176
    const IDispatchExVtbl  *lpIDispatchExVtbl;

    LONG ref;

177 178 179
    DWORD buf_size;
    DWORD prop_cnt;
    dispex_prop_t *props;
180
    script_ctx_t *ctx;
181 182 183 184 185

    DispatchEx *prototype;

    const builtin_info_t *builtin_info;
};
186 187 188

#define _IDispatchEx_(x) ((IDispatchEx*) &(x)->lpIDispatchExVtbl)

189 190 191 192 193
static inline void jsdisp_release(DispatchEx *jsdisp)
{
    IDispatchEx_Release(_IDispatchEx_(jsdisp));
}

194
HRESULT create_dispex(script_ctx_t*,const builtin_info_t*,DispatchEx*,DispatchEx**);
195
HRESULT init_dispex(DispatchEx*,script_ctx_t*,const builtin_info_t*,DispatchEx*);
196 197
HRESULT init_dispex_from_constr(DispatchEx*,script_ctx_t*,const builtin_info_t*,DispatchEx*);

198 199 200 201
HRESULT disp_call(script_ctx_t*,IDispatch*,DISPID,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*,IServiceProvider*);
HRESULT jsdisp_call_value(DispatchEx*,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*,IServiceProvider*);
HRESULT jsdisp_call(DispatchEx*,DISPID,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*,IServiceProvider*);
HRESULT jsdisp_call_name(DispatchEx*,const WCHAR*,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*,IServiceProvider*);
202
HRESULT disp_propget(script_ctx_t*,IDispatch*,DISPID,VARIANT*,jsexcept_t*,IServiceProvider*);
203
HRESULT disp_propput(script_ctx_t*,IDispatch*,DISPID,VARIANT*,jsexcept_t*,IServiceProvider*);
204
HRESULT jsdisp_propget(DispatchEx*,DISPID,VARIANT*,jsexcept_t*,IServiceProvider*);
205 206
HRESULT jsdisp_propput_name(DispatchEx*,const WCHAR*,VARIANT*,jsexcept_t*,IServiceProvider*);
HRESULT jsdisp_propput_idx(DispatchEx*,DWORD,VARIANT*,jsexcept_t*,IServiceProvider*);
207
HRESULT jsdisp_propget_name(DispatchEx*,LPCWSTR,VARIANT*,jsexcept_t*,IServiceProvider*);
208
HRESULT jsdisp_get_idx(DispatchEx*,DWORD,VARIANT*,jsexcept_t*,IServiceProvider*);
209
HRESULT jsdisp_get_id(DispatchEx*,const WCHAR*,DWORD,DISPID*);
210
HRESULT jsdisp_delete_idx(DispatchEx*,DWORD);
211

212
HRESULT create_builtin_function(script_ctx_t*,builtin_invoke_t,const WCHAR*,const builtin_info_t*,DWORD,
213
        DispatchEx*,DispatchEx**);
214
HRESULT Function_value(script_ctx_t*,vdisp_t*,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*,IServiceProvider*);
215

216
HRESULT throw_eval_error(script_ctx_t*,jsexcept_t*,UINT,const WCHAR*);
217
HRESULT throw_generic_error(script_ctx_t*,jsexcept_t*,UINT,const WCHAR*);
218 219
HRESULT throw_range_error(script_ctx_t*,jsexcept_t*,UINT,const WCHAR*);
HRESULT throw_reference_error(script_ctx_t*,jsexcept_t*,UINT,const WCHAR*);
220
HRESULT throw_regexp_error(script_ctx_t*,jsexcept_t*,UINT,const WCHAR*);
221 222 223 224
HRESULT throw_syntax_error(script_ctx_t*,jsexcept_t*,UINT,const WCHAR*);
HRESULT throw_type_error(script_ctx_t*,jsexcept_t*,UINT,const WCHAR*);
HRESULT throw_uri_error(script_ctx_t*,jsexcept_t*,UINT,const WCHAR*);

225
HRESULT create_object(script_ctx_t*,DispatchEx*,DispatchEx**);
226
HRESULT create_math(script_ctx_t*,DispatchEx**);
227
HRESULT create_array(script_ctx_t*,DWORD,DispatchEx**);
228
HRESULT create_regexp(script_ctx_t*,const WCHAR *,int,DWORD,DispatchEx**);
229
HRESULT create_regexp_var(script_ctx_t*,VARIANT*,VARIANT*,DispatchEx**);
230
HRESULT create_string(script_ctx_t*,const WCHAR*,DWORD,DispatchEx**);
231
HRESULT create_bool(script_ctx_t*,VARIANT_BOOL,DispatchEx**);
232
HRESULT create_number(script_ctx_t*,VARIANT*,DispatchEx**);
233

234 235 236 237 238 239 240
typedef enum {
    NO_HINT,
    HINT_STRING,
    HINT_NUMBER
} hint_t;

HRESULT to_primitive(script_ctx_t*,VARIANT*,jsexcept_t*,VARIANT*, hint_t);
241
HRESULT to_boolean(VARIANT*,VARIANT_BOOL*);
242
HRESULT to_number(script_ctx_t*,VARIANT*,jsexcept_t*,VARIANT*);
243
HRESULT to_integer(script_ctx_t*,VARIANT*,jsexcept_t*,VARIANT*);
244
HRESULT to_int32(script_ctx_t*,VARIANT*,jsexcept_t*,INT*);
245
HRESULT to_uint32(script_ctx_t*,VARIANT*,jsexcept_t*,DWORD*);
246
HRESULT to_string(script_ctx_t*,VARIANT*,jsexcept_t*,BSTR*);
247
HRESULT to_object(script_ctx_t*,VARIANT*,IDispatch**);
248

249 250 251
typedef struct named_item_t {
    IDispatch *disp;
    DWORD flags;
252
    LPWSTR name;
253 254 255 256

    struct named_item_t *next;
} named_item_t;

257 258 259 260
struct _script_ctx_t {
    LONG ref;

    SCRIPTSTATE state;
261
    exec_ctx_t *exec_ctx;
262
    named_item_t *named_items;
263
    IActiveScriptSite *site;
264 265
    IInternetHostSecurityManager *secmgr;
    DWORD safeopt;
266
    DWORD version;
267
    LCID lcid;
268

269 270
    jsheap_t tmp_heap;

271 272
    IDispatch *host_global;

273
    DispatchEx *global;
274
    DispatchEx *function_constr;
275
    DispatchEx *activex_constr;
276
    DispatchEx *array_constr;
277
    DispatchEx *bool_constr;
278
    DispatchEx *date_constr;
279 280 281 282
    DispatchEx *error_constr;
    DispatchEx *eval_error_constr;
    DispatchEx *range_error_constr;
    DispatchEx *reference_error_constr;
283
    DispatchEx *regexp_error_constr;
284 285 286
    DispatchEx *syntax_error_constr;
    DispatchEx *type_error_constr;
    DispatchEx *uri_error_constr;
287
    DispatchEx *number_constr;
288
    DispatchEx *object_constr;
289
    DispatchEx *regexp_constr;
290
    DispatchEx *string_constr;
291
};
292

293 294
void script_release(script_ctx_t*);

295
static inline void script_addref(script_ctx_t *ctx)
296 297 298 299
{
    ctx->ref++;
}

300
HRESULT init_global(script_ctx_t*);
301 302
HRESULT init_function_constr(script_ctx_t*,DispatchEx*);
HRESULT create_object_prototype(script_ctx_t*,DispatchEx**);
303

304
HRESULT create_activex_constr(script_ctx_t*,DispatchEx**);
305
HRESULT create_array_constr(script_ctx_t*,DispatchEx*,DispatchEx**);
306
HRESULT create_bool_constr(script_ctx_t*,DispatchEx*,DispatchEx**);
307
HRESULT create_date_constr(script_ctx_t*,DispatchEx*,DispatchEx**);
308
HRESULT init_error_constr(script_ctx_t*,DispatchEx*);
309
HRESULT create_number_constr(script_ctx_t*,DispatchEx*,DispatchEx**);
310
HRESULT create_object_constr(script_ctx_t*,DispatchEx*,DispatchEx**);
311
HRESULT create_regexp_constr(script_ctx_t*,DispatchEx*,DispatchEx**);
312
HRESULT create_string_constr(script_ctx_t*,DispatchEx*,DispatchEx**);
313

314 315
IUnknown *create_ax_site(script_ctx_t*);

316 317 318 319 320
typedef struct {
    const WCHAR *str;
    DWORD len;
} match_result_t;

321 322 323
#define REM_CHECK_GLOBAL 0x0001
#define REM_RESET_INDEX  0x0002
HRESULT regexp_match_next(script_ctx_t*,DispatchEx*,DWORD,const WCHAR*,DWORD,const WCHAR**,match_result_t**,
324
        DWORD*,DWORD*,match_result_t*);
325
HRESULT regexp_match(script_ctx_t*,DispatchEx*,const WCHAR*,DWORD,BOOL,match_result_t**,DWORD*);
326
HRESULT parse_regexp_flags(const WCHAR*,DWORD,DWORD*);
327

328 329 330 331 332 333 334 335 336 337
static inline VARIANT *get_arg(DISPPARAMS *dp, DWORD i)
{
    return dp->rgvarg + dp->cArgs-i-1;
}

static inline DWORD arg_cnt(const DISPPARAMS *dp)
{
    return dp->cArgs - dp->cNamedArgs;
}

338 339 340 341 342
static inline BOOL is_class(DispatchEx *jsdisp, jsclass_t class)
{
    return jsdisp->builtin_info->class == class;
}

343 344 345 346 347
static inline BOOL is_vclass(vdisp_t *vdisp, jsclass_t class)
{
    return is_jsdisp(vdisp) && is_class(vdisp->u.jsdisp, class);
}

348 349 350 351 352 353 354 355 356 357
static inline BOOL is_num_vt(enum VARENUM vt)
{
    return vt == VT_I4 || vt == VT_R8;
}

static inline DOUBLE num_val(const VARIANT *v)
{
    return V_VT(v) == VT_I4 ? V_I4(v) : V_R8(v);
}

358 359 360 361 362 363 364 365 366 367 368
static inline void num_set_val(VARIANT *v, DOUBLE d)
{
    if(d == (DOUBLE)(INT)d) {
        V_VT(v) = VT_I4;
        V_I4(v) = d;
    }else {
        V_VT(v) = VT_R8;
        V_R8(v) = d;
    }
}

369 370 371 372 373 374 375 376 377 378
static inline void num_set_nan(VARIANT *v)
{
    V_VT(v) = VT_R8;
#ifdef NAN
    V_R8(v) = NAN;
#else
    V_UI8(v) = (ULONGLONG)0x7ff80000<<32;
#endif
}

379
static inline DOUBLE ret_nan(void)
380 381 382 383 384 385
{
    VARIANT v;
    num_set_nan(&v);
    return V_R8(&v);
}

386 387 388 389 390 391 392 393 394 395 396 397
static inline void num_set_inf(VARIANT *v, BOOL positive)
{
    V_VT(v) = VT_R8;
#ifdef INFINITY
    V_R8(v) = positive ? INFINITY : -INFINITY;
#else
    V_UI8(v) = (ULONGLONG)0x7ff00000<<32;
    if(!positive)
        V_R8(v) = -V_R8(v);
#endif
}

398 399 400 401 402
static inline DWORD make_grfdex(script_ctx_t *ctx, DWORD flags)
{
    return (ctx->version << 28) | flags;
}

403 404
const char *debugstr_variant(const VARIANT*);

405 406
HRESULT WINAPI JScriptFactory_CreateInstance(IClassFactory*,IUnknown*,REFIID,void**);

407 408 409 410 411 412 413 414 415 416 417 418
extern LONG module_ref;

static inline void lock_module(void)
{
    InterlockedIncrement(&module_ref);
}

static inline void unlock_module(void)
{
    InterlockedDecrement(&module_ref);
}

419 420 421 422 423 424 425 426 427 428
static inline void *heap_alloc(size_t len)
{
    return HeapAlloc(GetProcessHeap(), 0, len);
}

static inline void *heap_alloc_zero(size_t len)
{
    return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
}

429 430 431 432 433
static inline void *heap_realloc(void *mem, size_t len)
{
    return HeapReAlloc(GetProcessHeap(), 0, mem, len);
}

434 435 436 437 438
static inline BOOL heap_free(void *mem)
{
    return HeapFree(GetProcessHeap(), 0, mem);
}

439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
static inline LPWSTR heap_strdupW(LPCWSTR str)
{
    LPWSTR ret = NULL;

    if(str) {
        DWORD size;

        size = (strlenW(str)+1)*sizeof(WCHAR);
        ret = heap_alloc(size);
        memcpy(ret, str, size);
    }

    return ret;
}

454
#define DEFINE_THIS(cls,ifc,iface) ((cls*)((BYTE*)(iface)-offsetof(cls,lp ## ifc ## Vtbl)))