Coverage Report

Created: 2025-01-28 06:17

/src/mupdf/thirdparty/mujs/jsobject.c
Line
Count
Source (jump to first uncovered line)
1
#include "jsi.h"
2
3
static void jsB_new_Object(js_State *J)
4
0
{
5
0
  if (js_isundefined(J, 1) || js_isnull(J, 1))
6
0
    js_newobject(J);
7
0
  else
8
0
    js_pushobject(J, js_toobject(J, 1));
9
0
}
10
11
static void jsB_Object(js_State *J)
12
0
{
13
0
  if (js_isundefined(J, 1) || js_isnull(J, 1))
14
0
    js_newobject(J);
15
0
  else
16
0
    js_pushobject(J, js_toobject(J, 1));
17
0
}
18
19
static void Op_toString(js_State *J)
20
0
{
21
0
  if (js_isundefined(J, 0))
22
0
    js_pushliteral(J, "[object Undefined]");
23
0
  else if (js_isnull(J, 0))
24
0
    js_pushliteral(J, "[object Null]");
25
0
  else {
26
0
    js_Object *self = js_toobject(J, 0);
27
0
    switch (self->type) {
28
0
    case JS_COBJECT: js_pushliteral(J, "[object Object]"); break;
29
0
    case JS_CARRAY: js_pushliteral(J, "[object Array]"); break;
30
0
    case JS_CFUNCTION: js_pushliteral(J, "[object Function]"); break;
31
0
    case JS_CSCRIPT: js_pushliteral(J, "[object Function]"); break;
32
0
    case JS_CCFUNCTION: js_pushliteral(J, "[object Function]"); break;
33
0
    case JS_CERROR: js_pushliteral(J, "[object Error]"); break;
34
0
    case JS_CBOOLEAN: js_pushliteral(J, "[object Boolean]"); break;
35
0
    case JS_CNUMBER: js_pushliteral(J, "[object Number]"); break;
36
0
    case JS_CSTRING: js_pushliteral(J, "[object String]"); break;
37
0
    case JS_CREGEXP: js_pushliteral(J, "[object RegExp]"); break;
38
0
    case JS_CDATE: js_pushliteral(J, "[object Date]"); break;
39
0
    case JS_CMATH: js_pushliteral(J, "[object Math]"); break;
40
0
    case JS_CJSON: js_pushliteral(J, "[object JSON]"); break;
41
0
    case JS_CARGUMENTS: js_pushliteral(J, "[object Arguments]"); break;
42
0
    case JS_CITERATOR: js_pushliteral(J, "[object Iterator]"); break;
43
0
    case JS_CUSERDATA:
44
0
      js_pushliteral(J, "[object ");
45
0
      js_pushliteral(J, self->u.user.tag);
46
0
      js_concat(J);
47
0
      js_pushliteral(J, "]");
48
0
      js_concat(J);
49
0
      break;
50
0
    }
51
0
  }
52
0
}
53
54
static void Op_valueOf(js_State *J)
55
0
{
56
0
  js_copy(J, 0);
57
0
}
58
59
static void Op_hasOwnProperty(js_State *J)
60
0
{
61
0
  js_Object *self = js_toobject(J, 0);
62
0
  const char *name = js_tostring(J, 1);
63
0
  js_Property *ref;
64
0
  int k;
65
66
0
  if (self->type == JS_CSTRING) {
67
0
    if (js_isarrayindex(J, name, &k) && k >= 0 && k < self->u.s.length) {
68
0
      js_pushboolean(J, 1);
69
0
      return;
70
0
    }
71
0
  }
72
73
0
  if (self->type == JS_CARRAY && self->u.a.simple) {
74
0
    if (js_isarrayindex(J, name, &k) && k >= 0 && k < self->u.a.flat_length) {
75
0
      js_pushboolean(J, 1);
76
0
      return;
77
0
    }
78
0
  }
79
80
0
  ref = jsV_getownproperty(J, self, name);
81
0
  js_pushboolean(J, ref != NULL);
82
0
}
83
84
static void Op_isPrototypeOf(js_State *J)
85
0
{
86
0
  js_Object *self = js_toobject(J, 0);
87
0
  if (js_isobject(J, 1)) {
88
0
    js_Object *V = js_toobject(J, 1);
89
0
    do {
90
0
      V = V->prototype;
91
0
      if (V == self) {
92
0
        js_pushboolean(J, 1);
93
0
        return;
94
0
      }
95
0
    } while (V);
96
0
  }
97
0
  js_pushboolean(J, 0);
98
0
}
99
100
static void Op_propertyIsEnumerable(js_State *J)
101
0
{
102
0
  js_Object *self = js_toobject(J, 0);
103
0
  const char *name = js_tostring(J, 1);
104
0
  js_Property *ref = jsV_getownproperty(J, self, name);
105
0
  js_pushboolean(J, ref && !(ref->atts & JS_DONTENUM));
106
0
}
107
108
static void O_getPrototypeOf(js_State *J)
109
0
{
110
0
  js_Object *obj;
111
0
  if (!js_isobject(J, 1))
112
0
    js_typeerror(J, "not an object");
113
0
  obj = js_toobject(J, 1);
114
0
  if (obj->prototype)
115
0
    js_pushobject(J, obj->prototype);
116
0
  else
117
0
    js_pushnull(J);
118
0
}
119
120
static void O_getOwnPropertyDescriptor(js_State *J)
121
0
{
122
0
  js_Object *obj;
123
0
  js_Property *ref;
124
0
  if (!js_isobject(J, 1))
125
0
    js_typeerror(J, "not an object");
126
0
  obj = js_toobject(J, 1);
127
0
  ref = jsV_getproperty(J, obj, js_tostring(J, 2));
128
0
  if (!ref) {
129
    // TODO: builtin properties (string and array index and length, regexp flags, etc)
130
0
    js_pushundefined(J);
131
0
  } else {
132
0
    js_newobject(J);
133
0
    if (!ref->getter && !ref->setter) {
134
0
      js_pushvalue(J, ref->value);
135
0
      js_defproperty(J, -2, "value", 0);
136
0
      js_pushboolean(J, !(ref->atts & JS_READONLY));
137
0
      js_defproperty(J, -2, "writable", 0);
138
0
    } else {
139
0
      if (ref->getter)
140
0
        js_pushobject(J, ref->getter);
141
0
      else
142
0
        js_pushundefined(J);
143
0
      js_defproperty(J, -2, "get", 0);
144
0
      if (ref->setter)
145
0
        js_pushobject(J, ref->setter);
146
0
      else
147
0
        js_pushundefined(J);
148
0
      js_defproperty(J, -2, "set", 0);
149
0
    }
150
0
    js_pushboolean(J, !(ref->atts & JS_DONTENUM));
151
0
    js_defproperty(J, -2, "enumerable", 0);
152
0
    js_pushboolean(J, !(ref->atts & JS_DONTCONF));
153
0
    js_defproperty(J, -2, "configurable", 0);
154
0
  }
155
0
}
156
157
static int O_getOwnPropertyNames_walk(js_State *J, js_Property *ref, int i)
158
0
{
159
0
  if (ref->left->level)
160
0
    i = O_getOwnPropertyNames_walk(J, ref->left, i);
161
0
  js_pushstring(J, ref->name);
162
0
  js_setindex(J, -2, i++);
163
0
  if (ref->right->level)
164
0
    i = O_getOwnPropertyNames_walk(J, ref->right, i);
165
0
  return i;
166
0
}
167
168
static void O_getOwnPropertyNames(js_State *J)
169
0
{
170
0
  js_Object *obj;
171
0
  char name[32];
172
0
  int k;
173
0
  int i;
174
175
0
  if (!js_isobject(J, 1))
176
0
    js_typeerror(J, "not an object");
177
0
  obj = js_toobject(J, 1);
178
179
0
  js_newarray(J);
180
181
0
  if (obj->properties->level)
182
0
    i = O_getOwnPropertyNames_walk(J, obj->properties, 0);
183
0
  else
184
0
    i = 0;
185
186
0
  if (obj->type == JS_CARRAY) {
187
0
    js_pushliteral(J, "length");
188
0
    js_setindex(J, -2, i++);
189
0
    if (obj->u.a.simple) {
190
0
      for (k = 0; k < obj->u.a.flat_length; ++k) {
191
0
        js_itoa(name, k);
192
0
        js_pushstring(J, name);
193
0
        js_setindex(J, -2, i++);
194
0
      }
195
0
    }
196
0
  }
197
198
0
  if (obj->type == JS_CSTRING) {
199
0
    js_pushliteral(J, "length");
200
0
    js_setindex(J, -2, i++);
201
0
    for (k = 0; k < obj->u.s.length; ++k) {
202
0
      js_itoa(name, k);
203
0
      js_pushstring(J, name);
204
0
      js_setindex(J, -2, i++);
205
0
    }
206
0
  }
207
208
0
  if (obj->type == JS_CREGEXP) {
209
0
    js_pushliteral(J, "source");
210
0
    js_setindex(J, -2, i++);
211
0
    js_pushliteral(J, "global");
212
0
    js_setindex(J, -2, i++);
213
0
    js_pushliteral(J, "ignoreCase");
214
0
    js_setindex(J, -2, i++);
215
0
    js_pushliteral(J, "multiline");
216
0
    js_setindex(J, -2, i++);
217
0
    js_pushliteral(J, "lastIndex");
218
0
    js_setindex(J, -2, i++);
219
0
  }
220
0
}
221
222
static void ToPropertyDescriptor(js_State *J, js_Object *obj, const char *name, js_Object *desc)
223
0
{
224
0
  int haswritable = 0;
225
0
  int hasvalue = 0;
226
0
  int enumerable = 0;
227
0
  int configurable = 0;
228
0
  int writable = 0;
229
0
  int atts = 0;
230
231
0
  js_pushobject(J, obj);
232
0
  js_pushobject(J, desc);
233
234
0
  if (js_hasproperty(J, -1, "writable")) {
235
0
    haswritable = 1;
236
0
    writable = js_toboolean(J, -1);
237
0
    js_pop(J, 1);
238
0
  }
239
0
  if (js_hasproperty(J, -1, "enumerable")) {
240
0
    enumerable = js_toboolean(J, -1);
241
0
    js_pop(J, 1);
242
0
  }
243
0
  if (js_hasproperty(J, -1, "configurable")) {
244
0
    configurable = js_toboolean(J, -1);
245
0
    js_pop(J, 1);
246
0
  }
247
0
  if (js_hasproperty(J, -1, "value")) {
248
0
    hasvalue = 1;
249
0
    js_defproperty(J, -3, name, 0);
250
0
  }
251
252
0
  if (!writable) atts |= JS_READONLY;
253
0
  if (!enumerable) atts |= JS_DONTENUM;
254
0
  if (!configurable) atts |= JS_DONTCONF;
255
256
0
  if (js_hasproperty(J, -1, "get")) {
257
0
    if (haswritable || hasvalue)
258
0
      js_typeerror(J, "value/writable and get/set attributes are exclusive");
259
0
  } else {
260
0
    js_pushundefined(J);
261
0
  }
262
263
0
  if (js_hasproperty(J, -2, "set")) {
264
0
    if (haswritable || hasvalue)
265
0
      js_typeerror(J, "value/writable and get/set attributes are exclusive");
266
0
  } else {
267
0
    js_pushundefined(J);
268
0
  }
269
270
0
  js_defaccessor(J, -4, name, atts);
271
272
0
  js_pop(J, 2);
273
0
}
274
275
static void O_defineProperty(js_State *J)
276
0
{
277
0
  if (!js_isobject(J, 1)) js_typeerror(J, "not an object");
278
0
  if (!js_isobject(J, 3)) js_typeerror(J, "not an object");
279
0
  ToPropertyDescriptor(J, js_toobject(J, 1), js_tostring(J, 2), js_toobject(J, 3));
280
0
  js_copy(J, 1);
281
0
}
282
283
static void O_defineProperties_walk(js_State *J, js_Property *ref)
284
0
{
285
0
  if (ref->left->level)
286
0
    O_defineProperties_walk(J, ref->left);
287
0
  if (!(ref->atts & JS_DONTENUM)) {
288
0
    js_pushvalue(J, ref->value);
289
0
    ToPropertyDescriptor(J, js_toobject(J, 1), ref->name, js_toobject(J, -1));
290
0
    js_pop(J, 1);
291
0
  }
292
0
  if (ref->right->level)
293
0
    O_defineProperties_walk(J, ref->right);
294
0
}
295
296
static void O_defineProperties(js_State *J)
297
0
{
298
0
  js_Object *props;
299
300
0
  if (!js_isobject(J, 1)) js_typeerror(J, "not an object");
301
0
  if (!js_isobject(J, 2)) js_typeerror(J, "not an object");
302
303
0
  props = js_toobject(J, 2);
304
0
  if (props->properties->level)
305
0
    O_defineProperties_walk(J, props->properties);
306
307
0
  js_copy(J, 1);
308
0
}
309
310
static void O_create_walk(js_State *J, js_Object *obj, js_Property *ref)
311
0
{
312
0
  if (ref->left->level)
313
0
    O_create_walk(J, obj, ref->left);
314
0
  if (!(ref->atts & JS_DONTENUM)) {
315
0
    if (ref->value.t.type != JS_TOBJECT)
316
0
      js_typeerror(J, "not an object");
317
0
    ToPropertyDescriptor(J, obj, ref->name, ref->value.u.object);
318
0
  }
319
0
  if (ref->right->level)
320
0
    O_create_walk(J, obj, ref->right);
321
0
}
322
323
static void O_create(js_State *J)
324
0
{
325
0
  js_Object *obj;
326
0
  js_Object *proto;
327
0
  js_Object *props;
328
329
0
  if (js_isobject(J, 1))
330
0
    proto = js_toobject(J, 1);
331
0
  else if (js_isnull(J, 1))
332
0
    proto = NULL;
333
0
  else
334
0
    js_typeerror(J, "not an object or null");
335
336
0
  obj = jsV_newobject(J, JS_COBJECT, proto);
337
0
  js_pushobject(J, obj);
338
339
0
  if (js_isdefined(J, 2)) {
340
0
    if (!js_isobject(J, 2))
341
0
      js_typeerror(J, "not an object");
342
0
    props = js_toobject(J, 2);
343
0
    if (props->properties->level)
344
0
      O_create_walk(J, obj, props->properties);
345
0
  }
346
0
}
347
348
static int O_keys_walk(js_State *J, js_Property *ref, int i)
349
0
{
350
0
  if (ref->left->level)
351
0
    i = O_keys_walk(J, ref->left, i);
352
0
  if (!(ref->atts & JS_DONTENUM)) {
353
0
    js_pushstring(J, ref->name);
354
0
    js_setindex(J, -2, i++);
355
0
  }
356
0
  if (ref->right->level)
357
0
    i = O_keys_walk(J, ref->right, i);
358
0
  return i;
359
0
}
360
361
static void O_keys(js_State *J)
362
0
{
363
0
  js_Object *obj;
364
0
  char name[32];
365
0
  int i, k;
366
367
0
  if (!js_isobject(J, 1))
368
0
    js_typeerror(J, "not an object");
369
0
  obj = js_toobject(J, 1);
370
371
0
  js_newarray(J);
372
373
0
  if (obj->properties->level)
374
0
    i = O_keys_walk(J, obj->properties, 0);
375
0
  else
376
0
    i = 0;
377
378
0
  if (obj->type == JS_CSTRING) {
379
0
    for (k = 0; k < obj->u.s.length; ++k) {
380
0
      js_itoa(name, k);
381
0
      js_pushstring(J, name);
382
0
      js_setindex(J, -2, i++);
383
0
    }
384
0
  }
385
386
0
  if (obj->type == JS_CARRAY && obj->u.a.simple) {
387
0
    for (k = 0; k < obj->u.a.flat_length; ++k) {
388
0
      js_itoa(name, k);
389
0
      js_pushstring(J, name);
390
0
      js_setindex(J, -2, i++);
391
0
    }
392
0
  }
393
0
}
394
395
static void O_preventExtensions(js_State *J)
396
0
{
397
0
  js_Object *obj;
398
0
  if (!js_isobject(J, 1))
399
0
    js_typeerror(J, "not an object");
400
0
  obj = js_toobject(J, 1);
401
0
  jsR_unflattenarray(J, obj);
402
0
  obj->extensible = 0;
403
0
  js_copy(J, 1);
404
0
}
405
406
static void O_isExtensible(js_State *J)
407
0
{
408
0
  if (!js_isobject(J, 1))
409
0
    js_typeerror(J, "not an object");
410
0
  js_pushboolean(J, js_toobject(J, 1)->extensible);
411
0
}
412
413
static void O_seal_walk(js_State *J, js_Property *ref)
414
0
{
415
0
  if (ref->left->level)
416
0
    O_seal_walk(J, ref->left);
417
0
  ref->atts |= JS_DONTCONF;
418
0
  if (ref->right->level)
419
0
    O_seal_walk(J, ref->right);
420
0
}
421
422
static void O_seal(js_State *J)
423
0
{
424
0
  js_Object *obj;
425
426
0
  if (!js_isobject(J, 1))
427
0
    js_typeerror(J, "not an object");
428
429
0
  obj = js_toobject(J, 1);
430
0
  jsR_unflattenarray(J, obj);
431
0
  obj->extensible = 0;
432
433
0
  if (obj->properties->level)
434
0
    O_seal_walk(J, obj->properties);
435
436
0
  js_copy(J, 1);
437
0
}
438
439
static int O_isSealed_walk(js_State *J, js_Property *ref)
440
0
{
441
0
  if (ref->left->level)
442
0
    if (!O_isSealed_walk(J, ref->left))
443
0
      return 0;
444
0
  if (!(ref->atts & JS_DONTCONF))
445
0
    return 0;
446
0
  if (ref->right->level)
447
0
    if (!O_isSealed_walk(J, ref->right))
448
0
      return 0;
449
0
  return 1;
450
0
}
451
452
static void O_isSealed(js_State *J)
453
0
{
454
0
  js_Object *obj;
455
456
0
  if (!js_isobject(J, 1))
457
0
    js_typeerror(J, "not an object");
458
459
0
  obj = js_toobject(J, 1);
460
0
  if (obj->extensible) {
461
0
    js_pushboolean(J, 0);
462
0
    return;
463
0
  }
464
465
0
  if (obj->properties->level)
466
0
    js_pushboolean(J, O_isSealed_walk(J, obj->properties));
467
0
  else
468
0
    js_pushboolean(J, 1);
469
0
}
470
471
static void O_freeze_walk(js_State *J, js_Property *ref)
472
0
{
473
0
  if (ref->left->level)
474
0
    O_freeze_walk(J, ref->left);
475
0
  ref->atts |= JS_READONLY | JS_DONTCONF;
476
0
  if (ref->right->level)
477
0
    O_freeze_walk(J, ref->right);
478
0
}
479
480
static void O_freeze(js_State *J)
481
0
{
482
0
  js_Object *obj;
483
484
0
  if (!js_isobject(J, 1))
485
0
    js_typeerror(J, "not an object");
486
487
0
  obj = js_toobject(J, 1);
488
0
  jsR_unflattenarray(J, obj);
489
0
  obj->extensible = 0;
490
491
0
  if (obj->properties->level)
492
0
    O_freeze_walk(J, obj->properties);
493
494
0
  js_copy(J, 1);
495
0
}
496
497
static int O_isFrozen_walk(js_State *J, js_Property *ref)
498
0
{
499
0
  if (ref->left->level)
500
0
    if (!O_isFrozen_walk(J, ref->left))
501
0
      return 0;
502
0
  if (!(ref->atts & JS_READONLY))
503
0
    return 0;
504
0
  if (!(ref->atts & JS_DONTCONF))
505
0
    return 0;
506
0
  if (ref->right->level)
507
0
    if (!O_isFrozen_walk(J, ref->right))
508
0
      return 0;
509
0
  return 1;
510
0
}
511
512
static void O_isFrozen(js_State *J)
513
0
{
514
0
  js_Object *obj;
515
516
0
  if (!js_isobject(J, 1))
517
0
    js_typeerror(J, "not an object");
518
519
0
  obj = js_toobject(J, 1);
520
521
0
  if (obj->properties->level) {
522
0
    if (!O_isFrozen_walk(J, obj->properties)) {
523
0
      js_pushboolean(J, 0);
524
0
      return;
525
0
    }
526
0
  }
527
528
0
  js_pushboolean(J, !obj->extensible);
529
0
}
530
531
void jsB_initobject(js_State *J)
532
0
{
533
0
  js_pushobject(J, J->Object_prototype);
534
0
  {
535
0
    jsB_propf(J, "Object.prototype.toString", Op_toString, 0);
536
0
    jsB_propf(J, "Object.prototype.toLocaleString", Op_toString, 0);
537
0
    jsB_propf(J, "Object.prototype.valueOf", Op_valueOf, 0);
538
0
    jsB_propf(J, "Object.prototype.hasOwnProperty", Op_hasOwnProperty, 1);
539
0
    jsB_propf(J, "Object.prototype.isPrototypeOf", Op_isPrototypeOf, 1);
540
0
    jsB_propf(J, "Object.prototype.propertyIsEnumerable", Op_propertyIsEnumerable, 1);
541
0
  }
542
0
  js_newcconstructor(J, jsB_Object, jsB_new_Object, "Object", 1);
543
0
  {
544
    /* ES5 */
545
0
    jsB_propf(J, "Object.getPrototypeOf", O_getPrototypeOf, 1);
546
0
    jsB_propf(J, "Object.getOwnPropertyDescriptor", O_getOwnPropertyDescriptor, 2);
547
0
    jsB_propf(J, "Object.getOwnPropertyNames", O_getOwnPropertyNames, 1);
548
0
    jsB_propf(J, "Object.create", O_create, 2);
549
0
    jsB_propf(J, "Object.defineProperty", O_defineProperty, 3);
550
0
    jsB_propf(J, "Object.defineProperties", O_defineProperties, 2);
551
0
    jsB_propf(J, "Object.seal", O_seal, 1);
552
0
    jsB_propf(J, "Object.freeze", O_freeze, 1);
553
0
    jsB_propf(J, "Object.preventExtensions", O_preventExtensions, 1);
554
0
    jsB_propf(J, "Object.isSealed", O_isSealed, 1);
555
0
    jsB_propf(J, "Object.isFrozen", O_isFrozen, 1);
556
0
    jsB_propf(J, "Object.isExtensible", O_isExtensible, 1);
557
0
    jsB_propf(J, "Object.keys", O_keys, 1);
558
0
  }
559
0
  js_defglobal(J, "Object", JS_DONTENUM);
560
0
}