Subversion Repositories Kolibri OS

Rev

Rev 4680 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4680 right-hear 1
#include "fitz.h"
2
 
3
typedef enum fz_objkind_e
4
{
5
	FZ_NULL,
6
	FZ_BOOL,
7
	FZ_INT,
8
	FZ_REAL,
9
	FZ_STRING,
10
	FZ_NAME,
11
	FZ_ARRAY,
12
	FZ_DICT,
13
	FZ_INDIRECT
14
} fz_objkind;
15
 
16
struct keyval
17
{
18
	fz_obj *k;
19
	fz_obj *v;
20
};
21
 
22
struct fz_obj_s
23
{
24
	int refs;
25
	fz_objkind kind;
26
	union
27
	{
28
		int b;
29
		int i;
30
		float f;
31
		struct {
32
			unsigned short len;
33
			char buf[1];
34
		} s;
35
		char n[1];
36
		struct {
37
			int len;
38
			int cap;
39
			fz_obj **items;
40
		} a;
41
		struct {
42
			char sorted;
43
			int len;
44
			int cap;
45
			struct keyval *items;
46
		} d;
47
		struct {
48
			int num;
49
			int gen;
50
			struct pdf_xref_s *xref;
51
		} r;
52
	} u;
53
};
54
 
55
static fz_obj *fz_resolve_indirect_null(fz_obj *ref)
56
{
57
	return ref;
58
}
59
 
60
fz_obj* (*fz_resolve_indirect)(fz_obj*) = fz_resolve_indirect_null;
61
 
62
fz_obj *
63
fz_new_null(void)
64
{
65
	fz_obj *obj = fz_malloc(sizeof(fz_obj));
66
	obj->refs = 1;
67
	obj->kind = FZ_NULL;
68
	return obj;
69
}
70
 
71
fz_obj *
72
fz_new_bool(int b)
73
{
74
	fz_obj *obj = fz_malloc(sizeof(fz_obj));
75
	obj->refs = 1;
76
	obj->kind = FZ_BOOL;
77
	obj->u.b = b;
78
	return obj;
79
}
80
 
81
fz_obj *
82
fz_new_int(int i)
83
{
84
	fz_obj *obj = fz_malloc(sizeof(fz_obj));
85
	obj->refs = 1;
86
	obj->kind = FZ_INT;
87
	obj->u.i = i;
88
	return obj;
89
}
90
 
91
fz_obj *
92
fz_new_real(float f)
93
{
94
	fz_obj *obj = fz_malloc(sizeof(fz_obj));
95
	obj->refs = 1;
96
	obj->kind = FZ_REAL;
97
	obj->u.f = f;
98
	return obj;
99
}
100
 
101
fz_obj *
102
fz_new_string(char *str, int len)
103
{
104
	fz_obj *obj = fz_malloc(offsetof(fz_obj, u.s.buf) + len + 1);
105
	obj->refs = 1;
106
	obj->kind = FZ_STRING;
107
	obj->u.s.len = len;
108
	memcpy(obj->u.s.buf, str, len);
109
	obj->u.s.buf[len] = '\0';
110
	return obj;
111
}
112
 
113
fz_obj *
114
fz_new_name(char *str)
115
{
116
	fz_obj *obj = fz_malloc(offsetof(fz_obj, u.n) + strlen(str) + 1);
117
	obj->refs = 1;
118
	obj->kind = FZ_NAME;
119
	strcpy(obj->u.n, str);
120
	return obj;
121
}
122
 
123
fz_obj *
124
fz_new_indirect(int num, int gen, void *xref)
125
{
126
	fz_obj *obj = fz_malloc(sizeof(fz_obj));
127
	obj->refs = 1;
128
	obj->kind = FZ_INDIRECT;
129
	obj->u.r.num = num;
130
	obj->u.r.gen = gen;
131
	obj->u.r.xref = xref;
132
	return obj;
133
}
134
 
135
fz_obj *
136
fz_keep_obj(fz_obj *obj)
137
{
138
	assert(obj != NULL);
139
	obj->refs ++;
140
	return obj;
141
}
142
 
143
int fz_is_indirect(fz_obj *obj)
144
{
145
	return obj ? obj->kind == FZ_INDIRECT : 0;
146
}
147
 
148
int fz_is_null(fz_obj *obj)
149
{
150
	obj = fz_resolve_indirect(obj);
151
	return obj ? obj->kind == FZ_NULL : 0;
152
}
153
 
154
int fz_is_bool(fz_obj *obj)
155
{
156
	obj = fz_resolve_indirect(obj);
157
	return obj ? obj->kind == FZ_BOOL : 0;
158
}
159
 
160
int fz_is_int(fz_obj *obj)
161
{
162
	obj = fz_resolve_indirect(obj);
163
	return obj ? obj->kind == FZ_INT : 0;
164
}
165
 
166
int fz_is_real(fz_obj *obj)
167
{
168
	obj = fz_resolve_indirect(obj);
169
	return obj ? obj->kind == FZ_REAL : 0;
170
}
171
 
172
int fz_is_string(fz_obj *obj)
173
{
174
	obj = fz_resolve_indirect(obj);
175
	return obj ? obj->kind == FZ_STRING : 0;
176
}
177
 
178
int fz_is_name(fz_obj *obj)
179
{
180
	obj = fz_resolve_indirect(obj);
181
	return obj ? obj->kind == FZ_NAME : 0;
182
}
183
 
184
int fz_is_array(fz_obj *obj)
185
{
186
	obj = fz_resolve_indirect(obj);
187
	return obj ? obj->kind == FZ_ARRAY : 0;
188
}
189
 
190
int fz_is_dict(fz_obj *obj)
191
{
192
	obj = fz_resolve_indirect(obj);
193
	return obj ? obj->kind == FZ_DICT : 0;
194
}
195
 
196
int fz_to_bool(fz_obj *obj)
197
{
198
	obj = fz_resolve_indirect(obj);
199
	if (fz_is_bool(obj))
200
		return obj->u.b;
201
	return 0;
202
}
203
 
204
int fz_to_int(fz_obj *obj)
205
{
206
	obj = fz_resolve_indirect(obj);
207
	if (fz_is_int(obj))
208
		return obj->u.i;
209
	if (fz_is_real(obj))
210
		return obj->u.f;
211
	return 0;
212
}
213
 
214
float fz_to_real(fz_obj *obj)
215
{
216
	obj = fz_resolve_indirect(obj);
217
	if (fz_is_real(obj))
218
		return obj->u.f;
219
	if (fz_is_int(obj))
220
		return obj->u.i;
221
	return 0;
222
}
223
 
224
char *fz_to_name(fz_obj *obj)
225
{
226
	obj = fz_resolve_indirect(obj);
227
	if (fz_is_name(obj))
228
		return obj->u.n;
229
	return "";
230
}
231
 
232
char *fz_to_str_buf(fz_obj *obj)
233
{
234
	obj = fz_resolve_indirect(obj);
235
	if (fz_is_string(obj))
236
		return obj->u.s.buf;
237
	return "";
238
}
239
 
240
int fz_to_str_len(fz_obj *obj)
241
{
242
	obj = fz_resolve_indirect(obj);
243
	if (fz_is_string(obj))
244
		return obj->u.s.len;
245
	return 0;
246
}
247
 
248
/* for use by pdf_crypt_obj_imp to decrypt AES string in place */
249
void fz_set_str_len(fz_obj *obj, int newlen)
250
{
251
	obj = fz_resolve_indirect(obj);
252
	if (fz_is_string(obj))
253
		if (newlen < obj->u.s.len)
254
			obj->u.s.len = newlen;
255
}
256
 
257
int fz_to_num(fz_obj *obj)
258
{
259
	if (fz_is_indirect(obj))
260
		return obj->u.r.num;
261
	return 0;
262
}
263
 
264
int fz_to_gen(fz_obj *obj)
265
{
266
	if (fz_is_indirect(obj))
267
		return obj->u.r.gen;
268
	return 0;
269
}
270
 
271
void *fz_get_indirect_xref(fz_obj *obj)
272
{
273
	if (fz_is_indirect(obj))
274
		return obj->u.r.xref;
275
	return NULL;
276
}
277
 
278
int
279
fz_objcmp(fz_obj *a, fz_obj *b)
280
{
281
	int i;
282
 
283
	if (a == b)
284
		return 0;
285
 
286
	if (!a || !b)
287
		return 1;
288
 
289
	if (a->kind != b->kind)
290
		return 1;
291
 
292
	switch (a->kind)
293
	{
294
	case FZ_NULL:
295
		return 0;
296
 
297
	case FZ_BOOL:
298
		return a->u.b - b->u.b;
299
 
300
	case FZ_INT:
301
		return a->u.i - b->u.i;
302
 
303
	case FZ_REAL:
304
		if (a->u.f < b->u.f)
305
			return -1;
306
		if (a->u.f > b->u.f)
307
			return 1;
308
		return 0;
309
 
310
	case FZ_STRING:
311
		if (a->u.s.len < b->u.s.len)
312
		{
313
			if (memcmp(a->u.s.buf, b->u.s.buf, a->u.s.len) <= 0)
314
				return -1;
315
			return 1;
316
		}
317
		if (a->u.s.len > b->u.s.len)
318
		{
319
			if (memcmp(a->u.s.buf, b->u.s.buf, b->u.s.len) >= 0)
320
				return 1;
321
			return -1;
322
		}
323
		return memcmp(a->u.s.buf, b->u.s.buf, a->u.s.len);
324
 
325
	case FZ_NAME:
326
		return strcmp(a->u.n, b->u.n);
327
 
328
	case FZ_INDIRECT:
329
		if (a->u.r.num == b->u.r.num)
330
			return a->u.r.gen - b->u.r.gen;
331
		return a->u.r.num - b->u.r.num;
332
 
333
	case FZ_ARRAY:
334
		if (a->u.a.len != b->u.a.len)
335
			return a->u.a.len - b->u.a.len;
336
		for (i = 0; i < a->u.a.len; i++)
337
			if (fz_objcmp(a->u.a.items[i], b->u.a.items[i]))
338
				return 1;
339
		return 0;
340
 
341
	case FZ_DICT:
342
		if (a->u.d.len != b->u.d.len)
343
			return a->u.d.len - b->u.d.len;
344
		for (i = 0; i < a->u.d.len; i++)
345
		{
346
			if (fz_objcmp(a->u.d.items[i].k, b->u.d.items[i].k))
347
				return 1;
348
			if (fz_objcmp(a->u.d.items[i].v, b->u.d.items[i].v))
349
				return 1;
350
		}
351
		return 0;
352
 
353
	}
354
	return 1;
355
}
356
 
357
static char *
358
fz_objkindstr(fz_obj *obj)
359
{
360
	if (obj == NULL)
361
		return "";
362
	switch (obj->kind)
363
	{
364
	case FZ_NULL: return "null";
365
	case FZ_BOOL: return "boolean";
366
	case FZ_INT: return "integer";
367
	case FZ_REAL: return "real";
368
	case FZ_STRING: return "string";
369
	case FZ_NAME: return "name";
370
	case FZ_ARRAY: return "array";
371
	case FZ_DICT: return "dictionary";
372
	case FZ_INDIRECT: return "reference";
373
	}
374
	return "";
375
}
376
 
377
fz_obj *
378
fz_new_array(int initialcap)
379
{
380
	fz_obj *obj;
381
	int i;
382
 
383
	obj = fz_malloc(sizeof(fz_obj));
384
	obj->refs = 1;
385
	obj->kind = FZ_ARRAY;
386
 
387
	obj->u.a.len = 0;
388
	obj->u.a.cap = initialcap > 1 ? initialcap : 6;
389
 
390
	obj->u.a.items = fz_calloc(obj->u.a.cap, sizeof(fz_obj*));
391
	for (i = 0; i < obj->u.a.cap; i++)
392
		obj->u.a.items[i] = NULL;
393
 
394
	return obj;
395
}
396
 
397
fz_obj *
398
fz_copy_array(fz_obj *obj)
399
{
400
	fz_obj *new;
401
	int i;
402
 
403
	if (fz_is_indirect(obj) || !fz_is_array(obj))
404
		fz_warn("assert: not an array (%s)", fz_objkindstr(obj));
405
 
406
	new = fz_new_array(fz_array_len(obj));
407
	for (i = 0; i < fz_array_len(obj); i++)
408
		fz_array_push(new, fz_array_get(obj, i));
409
 
410
	return new;
411
}
412
 
413
int
414
fz_array_len(fz_obj *obj)
415
{
416
	obj = fz_resolve_indirect(obj);
417
	if (!fz_is_array(obj))
418
		return 0;
419
	return obj->u.a.len;
420
}
421
 
422
fz_obj *
423
fz_array_get(fz_obj *obj, int i)
424
{
425
	obj = fz_resolve_indirect(obj);
426
 
427
	if (!fz_is_array(obj))
428
		return NULL;
429
 
430
	if (i < 0 || i >= obj->u.a.len)
431
		return NULL;
432
 
433
	return obj->u.a.items[i];
434
}
435
 
436
void
437
fz_array_put(fz_obj *obj, int i, fz_obj *item)
438
{
439
	obj = fz_resolve_indirect(obj);
440
 
441
	if (!fz_is_array(obj))
442
		fz_warn("assert: not an array (%s)", fz_objkindstr(obj));
443
	else if (i < 0)
444
		fz_warn("assert: index %d < 0", i);
445
	else if (i >= obj->u.a.len)
446
		fz_warn("assert: index %d > length %d", i, obj->u.a.len);
447
	else
448
	{
449
		if (obj->u.a.items[i])
450
			fz_drop_obj(obj->u.a.items[i]);
451
		obj->u.a.items[i] = fz_keep_obj(item);
452
	}
453
}
454
 
455
void
456
fz_array_push(fz_obj *obj, fz_obj *item)
457
{
458
	obj = fz_resolve_indirect(obj);
459
 
460
	if (!fz_is_array(obj))
461
		fz_warn("assert: not an array (%s)", fz_objkindstr(obj));
462
	else
463
	{
464
		if (obj->u.a.len + 1 > obj->u.a.cap)
465
		{
466
			int i;
467
			obj->u.a.cap = (obj->u.a.cap * 3) / 2;
468
			obj->u.a.items = fz_realloc(obj->u.a.items, obj->u.a.cap, sizeof(fz_obj*));
469
			for (i = obj->u.a.len ; i < obj->u.a.cap; i++)
470
				obj->u.a.items[i] = NULL;
471
		}
472
		obj->u.a.items[obj->u.a.len] = fz_keep_obj(item);
473
		obj->u.a.len++;
474
	}
475
}
476
 
477
void
478
fz_array_insert(fz_obj *obj, fz_obj *item)
479
{
480
	obj = fz_resolve_indirect(obj);
481
 
482
	if (!fz_is_array(obj))
483
		fz_warn("assert: not an array (%s)", fz_objkindstr(obj));
484
	else
485
	{
486
		if (obj->u.a.len + 1 > obj->u.a.cap)
487
		{
488
			int i;
489
			obj->u.a.cap = (obj->u.a.cap * 3) / 2;
490
			obj->u.a.items = fz_realloc(obj->u.a.items, obj->u.a.cap, sizeof(fz_obj*));
491
			for (i = obj->u.a.len ; i < obj->u.a.cap; i++)
492
				obj->u.a.items[i] = NULL;
493
		}
494
		memmove(obj->u.a.items + 1, obj->u.a.items, obj->u.a.len * sizeof(fz_obj*));
495
		obj->u.a.items[0] = fz_keep_obj(item);
496
		obj->u.a.len++;
497
	}
498
}
499
 
500
/* dicts may only have names as keys! */
501
 
502
static int keyvalcmp(const void *ap, const void *bp)
503
{
504
	const struct keyval *a = ap;
505
	const struct keyval *b = bp;
506
	return strcmp(fz_to_name(a->k), fz_to_name(b->k));
507
}
508
 
509
fz_obj *
510
fz_new_dict(int initialcap)
511
{
512
	fz_obj *obj;
513
	int i;
514
 
515
	obj = fz_malloc(sizeof(fz_obj));
516
	obj->refs = 1;
517
	obj->kind = FZ_DICT;
518
 
519
	obj->u.d.sorted = 1;
520
	obj->u.d.len = 0;
521
	obj->u.d.cap = initialcap > 1 ? initialcap : 10;
522
 
523
	obj->u.d.items = fz_calloc(obj->u.d.cap, sizeof(struct keyval));
524
	for (i = 0; i < obj->u.d.cap; i++)
525
	{
526
		obj->u.d.items[i].k = NULL;
527
		obj->u.d.items[i].v = NULL;
528
	}
529
 
530
	return obj;
531
}
532
 
533
fz_obj *
534
fz_copy_dict(fz_obj *obj)
535
{
536
	fz_obj *new;
537
	int i;
538
 
539
	if (fz_is_indirect(obj) || !fz_is_dict(obj))
540
		fz_throw("assert: not a dict (%s)", fz_objkindstr(obj));
541
 
542
	new = fz_new_dict(fz_dict_len(obj));
543
	for (i = 0; i < fz_dict_len(obj); i++)
544
		fz_dict_put(new, fz_dict_get_key(obj, i), fz_dict_get_val(obj, i));
545
 
546
	return new;
547
}
548
 
549
int
550
fz_dict_len(fz_obj *obj)
551
{
552
	obj = fz_resolve_indirect(obj);
553
	if (!fz_is_dict(obj))
554
		return 0;
555
	return obj->u.d.len;
556
}
557
 
558
fz_obj *
559
fz_dict_get_key(fz_obj *obj, int i)
560
{
561
	obj = fz_resolve_indirect(obj);
562
 
563
	if (!fz_is_dict(obj))
564
		return NULL;
565
 
566
	if (i < 0 || i >= obj->u.d.len)
567
		return NULL;
568
 
569
	return obj->u.d.items[i].k;
570
}
571
 
572
fz_obj *
573
fz_dict_get_val(fz_obj *obj, int i)
574
{
575
	obj = fz_resolve_indirect(obj);
576
 
577
	if (!fz_is_dict(obj))
578
		return NULL;
579
 
580
	if (i < 0 || i >= obj->u.d.len)
581
		return NULL;
582
 
583
	return obj->u.d.items[i].v;
584
}
585
 
586
static int
587
fz_dict_finds(fz_obj *obj, char *key)
588
{
589
	if (obj->u.d.sorted)
590
	{
591
		int l = 0;
592
		int r = obj->u.d.len - 1;
593
		while (l <= r)
594
		{
595
			int m = (l + r) >> 1;
596
			int c = -strcmp(fz_to_name(obj->u.d.items[m].k), key);
597
			if (c < 0)
598
				r = m - 1;
599
			else if (c > 0)
600
				l = m + 1;
601
			else
602
				return m;
603
		}
604
	}
605
 
606
	else
607
	{
608
		int i;
609
		for (i = 0; i < obj->u.d.len; i++)
610
			if (strcmp(fz_to_name(obj->u.d.items[i].k), key) == 0)
611
				return i;
612
	}
613
 
614
	return -1;
615
}
616
 
617
fz_obj *
618
fz_dict_gets(fz_obj *obj, char *key)
619
{
620
	int i;
621
 
622
	obj = fz_resolve_indirect(obj);
623
 
624
	if (!fz_is_dict(obj))
625
		return NULL;
626
 
627
	i = fz_dict_finds(obj, key);
628
	if (i >= 0)
629
		return obj->u.d.items[i].v;
630
 
631
	return NULL;
632
}
633
 
634
fz_obj *
635
fz_dict_get(fz_obj *obj, fz_obj *key)
636
{
637
	if (fz_is_name(key))
638
		return fz_dict_gets(obj, fz_to_name(key));
639
	return NULL;
640
}
641
 
642
fz_obj *
643
fz_dict_getsa(fz_obj *obj, char *key, char *abbrev)
644
{
645
	fz_obj *v;
646
	v = fz_dict_gets(obj, key);
647
	if (v)
648
		return v;
649
	return fz_dict_gets(obj, abbrev);
650
}
651
 
652
void
653
fz_dict_put(fz_obj *obj, fz_obj *key, fz_obj *val)
654
{
655
	char *s;
656
	int i;
657
 
658
	obj = fz_resolve_indirect(obj);
659
 
660
	if (!fz_is_dict(obj))
661
	{
662
		fz_warn("assert: not a dict (%s)", fz_objkindstr(obj));
663
		return;
664
	}
665
 
666
	if (fz_is_name(key))
667
		s = fz_to_name(key);
668
	else
669
	{
670
		fz_warn("assert: key is not a name (%s)", fz_objkindstr(obj));
671
		return;
672
	}
673
 
674
	if (!val)
675
	{
676
		fz_warn("assert: val does not exist for key (%s)", s);
677
		return;
678
	}
679
 
680
	i = fz_dict_finds(obj, s);
681
	if (i >= 0)
682
	{
683
		fz_drop_obj(obj->u.d.items[i].v);
684
		obj->u.d.items[i].v = fz_keep_obj(val);
685
		return;
686
	}
687
 
688
	if (obj->u.d.len + 1 > obj->u.d.cap)
689
	{
690
		obj->u.d.cap = (obj->u.d.cap * 3) / 2;
691
		obj->u.d.items = fz_realloc(obj->u.d.items, obj->u.d.cap, sizeof(struct keyval));
692
		for (i = obj->u.d.len; i < obj->u.d.cap; i++)
693
		{
694
			obj->u.d.items[i].k = NULL;
695
			obj->u.d.items[i].v = NULL;
696
		}
697
	}
698
 
699
	/* borked! */
700
	if (obj->u.d.len)
701
		if (strcmp(fz_to_name(obj->u.d.items[obj->u.d.len - 1].k), s) > 0)
702
			obj->u.d.sorted = 0;
703
 
704
	obj->u.d.items[obj->u.d.len].k = fz_keep_obj(key);
705
	obj->u.d.items[obj->u.d.len].v = fz_keep_obj(val);
706
	obj->u.d.len ++;
707
}
708
 
709
void
710
fz_dict_puts(fz_obj *obj, char *key, fz_obj *val)
711
{
712
	fz_obj *keyobj = fz_new_name(key);
713
	fz_dict_put(obj, keyobj, val);
714
	fz_drop_obj(keyobj);
715
}
716
 
717
void
718
fz_dict_dels(fz_obj *obj, char *key)
719
{
720
	obj = fz_resolve_indirect(obj);
721
 
722
	if (!fz_is_dict(obj))
723
		fz_warn("assert: not a dict (%s)", fz_objkindstr(obj));
724
	else
725
	{
726
		int i = fz_dict_finds(obj, key);
727
		if (i >= 0)
728
		{
729
			fz_drop_obj(obj->u.d.items[i].k);
730
			fz_drop_obj(obj->u.d.items[i].v);
731
			obj->u.d.sorted = 0;
732
			obj->u.d.items[i] = obj->u.d.items[obj->u.d.len-1];
733
			obj->u.d.len --;
734
		}
735
	}
736
}
737
 
738
void
739
fz_dict_del(fz_obj *obj, fz_obj *key)
740
{
741
	if (fz_is_name(key))
742
		fz_dict_dels(obj, fz_to_name(key));
743
	else
744
		fz_warn("assert: key is not a name (%s)", fz_objkindstr(obj));
745
}
746
 
747
void
748
fz_sort_dict(fz_obj *obj)
749
{
750
	obj = fz_resolve_indirect(obj);
751
	if (!fz_is_dict(obj))
752
		return;
753
	if (!obj->u.d.sorted)
754
	{
755
		qsort(obj->u.d.items, obj->u.d.len, sizeof(struct keyval), keyvalcmp);
756
		obj->u.d.sorted = 1;
757
	}
758
}
759
 
760
static void
761
fz_free_array(fz_obj *obj)
762
{
763
	int i;
764
 
765
	for (i = 0; i < obj->u.a.len; i++)
766
		if (obj->u.a.items[i])
767
			fz_drop_obj(obj->u.a.items[i]);
768
 
769
	fz_free(obj->u.a.items);
770
	fz_free(obj);
771
}
772
 
773
static void
774
fz_free_dict(fz_obj *obj)
775
{
776
	int i;
777
 
778
	for (i = 0; i < obj->u.d.len; i++) {
779
		if (obj->u.d.items[i].k)
780
			fz_drop_obj(obj->u.d.items[i].k);
781
		if (obj->u.d.items[i].v)
782
			fz_drop_obj(obj->u.d.items[i].v);
783
	}
784
 
785
	fz_free(obj->u.d.items);
786
	fz_free(obj);
787
}
788
 
789
void
790
fz_drop_obj(fz_obj *obj)
791
{
792
	assert(obj != NULL);
793
	if (--obj->refs == 0)
794
	{
795
		if (obj->kind == FZ_ARRAY)
796
			fz_free_array(obj);
797
		else if (obj->kind == FZ_DICT)
798
			fz_free_dict(obj);
799
		else
800
			fz_free(obj);
801
	}
802
}