comparison mupdf-source/thirdparty/mujs/jsobject.c @ 2:b50eed0cc0ef upstream

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