Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
7643 views
1
#include "mupdf/pdf.h"
2
3
void *
4
pdf_new_processor(fz_context *ctx, int size)
5
{
6
return Memento_label(fz_calloc(ctx, 1, size), "pdf_processor");
7
}
8
9
void
10
pdf_drop_processor(fz_context *ctx, pdf_processor *proc)
11
{
12
if (proc && proc->drop_imp)
13
proc->drop_imp(ctx, proc);
14
fz_free(ctx, proc);
15
}
16
17
static void
18
pdf_init_csi(fz_context *ctx, pdf_csi *csi, pdf_document *doc, pdf_obj *rdb, pdf_lexbuf *buf, fz_cookie *cookie)
19
{
20
memset(csi, 0, sizeof *csi);
21
csi->doc = doc;
22
csi->rdb = rdb;
23
csi->buf = buf;
24
csi->cookie = cookie;
25
}
26
27
static void
28
pdf_clear_stack(fz_context *ctx, pdf_csi *csi)
29
{
30
int i;
31
32
pdf_drop_obj(ctx, csi->obj);
33
csi->obj = NULL;
34
35
csi->name[0] = 0;
36
csi->string_len = 0;
37
for (i = 0; i < csi->top; i++)
38
csi->stack[i] = 0;
39
40
csi->top = 0;
41
}
42
43
static pdf_font_desc *
44
load_font_or_hail_mary(fz_context *ctx, pdf_document *doc, pdf_obj *rdb, pdf_obj *font, int depth, fz_cookie *cookie)
45
{
46
pdf_font_desc *desc;
47
48
fz_try(ctx)
49
{
50
desc = pdf_load_font(ctx, doc, rdb, font, depth);
51
}
52
fz_catch(ctx)
53
{
54
if (fz_caught(ctx) == FZ_ERROR_TRYLATER && cookie && cookie->incomplete_ok)
55
{
56
desc = NULL;
57
cookie->incomplete++;
58
}
59
else
60
{
61
fz_rethrow(ctx);
62
}
63
}
64
if (desc == NULL)
65
desc = pdf_load_hail_mary_font(ctx, doc);
66
return desc;
67
}
68
69
static int
70
ocg_intents_include(fz_context *ctx, pdf_ocg_descriptor *desc, char *name)
71
{
72
int i, len;
73
74
if (strcmp(name, "All") == 0)
75
return 1;
76
77
/* In the absence of a specified intent, it's 'View' */
78
if (!desc->intent)
79
return (strcmp(name, "View") == 0);
80
81
if (pdf_is_name(ctx, desc->intent))
82
{
83
char *intent = pdf_to_name(ctx, desc->intent);
84
if (strcmp(intent, "All") == 0)
85
return 1;
86
return (strcmp(intent, name) == 0);
87
}
88
if (!pdf_is_array(ctx, desc->intent))
89
return 0;
90
91
len = pdf_array_len(ctx, desc->intent);
92
for (i=0; i < len; i++)
93
{
94
char *intent = pdf_to_name(ctx, pdf_array_get(ctx, desc->intent, i));
95
if (strcmp(intent, "All") == 0)
96
return 1;
97
if (strcmp(intent, name) == 0)
98
return 1;
99
}
100
return 0;
101
}
102
103
static int
104
pdf_is_hidden_ocg(fz_context *ctx, pdf_ocg_descriptor *desc, pdf_obj *rdb, const char *event, pdf_obj *ocg)
105
{
106
char event_state[16];
107
pdf_obj *obj, *obj2, *type;
108
109
/* Avoid infinite recursions */
110
if (pdf_obj_marked(ctx, ocg))
111
return 0;
112
113
/* If no event, everything is visible */
114
if (!event)
115
return 0;
116
117
/* If no ocg descriptor, everything is visible */
118
if (!desc)
119
return 0;
120
121
/* If we've been handed a name, look it up in the properties. */
122
if (pdf_is_name(ctx, ocg))
123
{
124
ocg = pdf_dict_get(ctx, pdf_dict_get(ctx, rdb, PDF_NAME_Properties), ocg);
125
}
126
/* If we haven't been given an ocg at all, then we're visible */
127
if (!ocg)
128
return 0;
129
130
fz_strlcpy(event_state, event, sizeof event_state);
131
fz_strlcat(event_state, "State", sizeof event_state);
132
133
type = pdf_dict_get(ctx, ocg, PDF_NAME_Type);
134
135
if (pdf_name_eq(ctx, type, PDF_NAME_OCG))
136
{
137
/* An Optional Content Group */
138
int default_value = 0;
139
int num = pdf_to_num(ctx, ocg);
140
int gen = pdf_to_gen(ctx, ocg);
141
int len = desc->len;
142
int i;
143
pdf_obj *es;
144
145
/* by default an OCG is visible, unless it's explicitly hidden */
146
for (i = 0; i < len; i++)
147
{
148
if (desc->ocgs[i].num == num && desc->ocgs[i].gen == gen)
149
{
150
default_value = desc->ocgs[i].state == 0;
151
break;
152
}
153
}
154
155
/* Check Intents; if our intent is not part of the set given
156
* by the current config, we should ignore it. */
157
obj = pdf_dict_get(ctx, ocg, PDF_NAME_Intent);
158
if (pdf_is_name(ctx, obj))
159
{
160
/* If it doesn't match, it's hidden */
161
if (ocg_intents_include(ctx, desc, pdf_to_name(ctx, obj)) == 0)
162
return 1;
163
}
164
else if (pdf_is_array(ctx, obj))
165
{
166
int match = 0;
167
len = pdf_array_len(ctx, obj);
168
for (i=0; i<len; i++) {
169
match |= ocg_intents_include(ctx, desc, pdf_to_name(ctx, pdf_array_get(ctx, obj, i)));
170
if (match)
171
break;
172
}
173
/* If we don't match any, it's hidden */
174
if (match == 0)
175
return 1;
176
}
177
else
178
{
179
/* If it doesn't match, it's hidden */
180
if (ocg_intents_include(ctx, desc, "View") == 0)
181
return 1;
182
}
183
184
/* FIXME: Currently we do a very simple check whereby we look
185
* at the Usage object (an Optional Content Usage Dictionary)
186
* and check to see if the corresponding 'event' key is on
187
* or off.
188
*
189
* Really we should only look at Usage dictionaries that
190
* correspond to entries in the AS list in the OCG config.
191
* Given that we don't handle Zoom or User, or Language
192
* dicts, this is not really a problem. */
193
obj = pdf_dict_get(ctx, ocg, PDF_NAME_Usage);
194
if (!pdf_is_dict(ctx, obj))
195
return default_value;
196
/* FIXME: Should look at Zoom (and return hidden if out of
197
* max/min range) */
198
/* FIXME: Could provide hooks to the caller to check if
199
* User is appropriate - if not return hidden. */
200
obj2 = pdf_dict_gets(ctx, obj, event);
201
es = pdf_dict_gets(ctx, obj2, event_state);
202
if (pdf_name_eq(ctx, es, PDF_NAME_OFF))
203
{
204
return 1;
205
}
206
if (pdf_name_eq(ctx, es, PDF_NAME_ON))
207
{
208
return 0;
209
}
210
return default_value;
211
}
212
else if (pdf_name_eq(ctx, type, PDF_NAME_OCMD))
213
{
214
/* An Optional Content Membership Dictionary */
215
pdf_obj *name;
216
int combine, on;
217
218
obj = pdf_dict_get(ctx, ocg, PDF_NAME_VE);
219
if (pdf_is_array(ctx, obj)) {
220
/* FIXME: Calculate visibility from array */
221
return 0;
222
}
223
name = pdf_dict_get(ctx, ocg, PDF_NAME_P);
224
/* Set combine; Bit 0 set => AND, Bit 1 set => true means
225
* Off, otherwise true means On */
226
if (pdf_name_eq(ctx, name, PDF_NAME_AllOn))
227
{
228
combine = 1;
229
}
230
else if (pdf_name_eq(ctx, name, PDF_NAME_AnyOff))
231
{
232
combine = 2;
233
}
234
else if (pdf_name_eq(ctx, name, PDF_NAME_AllOff))
235
{
236
combine = 3;
237
}
238
else /* Assume it's the default (AnyOn) */
239
{
240
combine = 0;
241
}
242
243
if (pdf_mark_obj(ctx, ocg))
244
return 0; /* Should never happen */
245
fz_try(ctx)
246
{
247
obj = pdf_dict_get(ctx, ocg, PDF_NAME_OCGs);
248
on = combine & 1;
249
if (pdf_is_array(ctx, obj)) {
250
int i, len;
251
len = pdf_array_len(ctx, obj);
252
for (i = 0; i < len; i++)
253
{
254
int hidden = pdf_is_hidden_ocg(ctx, desc, rdb, event, pdf_array_get(ctx, obj, i));
255
if ((combine & 1) == 0)
256
hidden = !hidden;
257
if (combine & 2)
258
on &= hidden;
259
else
260
on |= hidden;
261
}
262
}
263
else
264
{
265
on = pdf_is_hidden_ocg(ctx, desc, rdb, event, obj);
266
if ((combine & 1) == 0)
267
on = !on;
268
}
269
}
270
fz_always(ctx)
271
{
272
pdf_unmark_obj(ctx, ocg);
273
}
274
fz_catch(ctx)
275
{
276
fz_rethrow(ctx);
277
}
278
return !on;
279
}
280
/* No idea what sort of object this is - be visible */
281
return 0;
282
}
283
284
static fz_image *
285
parse_inline_image(fz_context *ctx, pdf_csi *csi, fz_stream *stm)
286
{
287
pdf_document *doc = csi->doc;
288
pdf_obj *rdb = csi->rdb;
289
pdf_obj *obj = NULL;
290
fz_image *img = NULL;
291
int ch, found;
292
293
fz_var(obj);
294
fz_var(img);
295
296
fz_try(ctx)
297
{
298
obj = pdf_parse_dict(ctx, doc, stm, &doc->lexbuf.base);
299
300
/* read whitespace after ID keyword */
301
ch = fz_read_byte(ctx, stm);
302
if (ch == '\r')
303
if (fz_peek_byte(ctx, stm) == '\n')
304
fz_read_byte(ctx, stm);
305
306
img = pdf_load_inline_image(ctx, doc, rdb, obj, stm);
307
308
/* find EI */
309
found = 0;
310
ch = fz_read_byte(ctx, stm);
311
do
312
{
313
while (ch != 'E' && ch != EOF)
314
ch = fz_read_byte(ctx, stm);
315
if (ch == 'E')
316
{
317
ch = fz_read_byte(ctx, stm);
318
if (ch == 'I')
319
{
320
ch = fz_peek_byte(ctx, stm);
321
if (ch == ' ' || ch <= 32 || ch == EOF || ch == '<' || ch == '/')
322
{
323
found = 1;
324
break;
325
}
326
}
327
}
328
} while (ch != EOF);
329
if (!found)
330
fz_throw(ctx, FZ_ERROR_GENERIC, "syntax error after inline image");
331
}
332
fz_catch(ctx)
333
{
334
pdf_drop_obj(ctx, obj);
335
fz_drop_image(ctx, img);
336
fz_rethrow(ctx);
337
}
338
339
return img;
340
}
341
342
static void
343
pdf_process_extgstate(fz_context *ctx, pdf_processor *proc, pdf_csi *csi, pdf_obj *dict)
344
{
345
pdf_obj *obj;
346
347
obj = pdf_dict_get(ctx, dict, PDF_NAME_LW);
348
if (pdf_is_number(ctx, obj) && proc->op_w)
349
proc->op_w(ctx, proc, pdf_to_real(ctx, obj));
350
351
obj = pdf_dict_get(ctx, dict, PDF_NAME_LC);
352
if (pdf_is_int(ctx, obj) && proc->op_J)
353
proc->op_J(ctx, proc, pdf_to_int(ctx, obj));
354
355
obj = pdf_dict_get(ctx, dict, PDF_NAME_LJ);
356
if (pdf_is_int(ctx, obj) && proc->op_j)
357
proc->op_j(ctx, proc, pdf_to_int(ctx, obj));
358
359
obj = pdf_dict_get(ctx, dict, PDF_NAME_ML);
360
if (pdf_is_number(ctx, obj) && proc->op_M)
361
proc->op_M(ctx, proc, pdf_to_real(ctx, obj));
362
363
obj = pdf_dict_get(ctx, dict, PDF_NAME_D);
364
if (pdf_is_array(ctx, obj) && proc->op_d)
365
{
366
pdf_obj *dash_array = pdf_array_get(ctx, obj, 0);
367
pdf_obj *dash_phase = pdf_array_get(ctx, obj, 1);
368
proc->op_d(ctx, proc, dash_array, pdf_to_real(ctx, dash_phase));
369
}
370
371
obj = pdf_dict_get(ctx, dict, PDF_NAME_RI);
372
if (pdf_is_name(ctx, obj) && proc->op_ri)
373
proc->op_ri(ctx, proc, pdf_to_name(ctx, obj));
374
375
obj = pdf_dict_get(ctx, dict, PDF_NAME_FL);
376
if (pdf_is_number(ctx, obj) && proc->op_i)
377
proc->op_i(ctx, proc, pdf_to_real(ctx, obj));
378
379
obj = pdf_dict_get(ctx, dict, PDF_NAME_Font);
380
if (pdf_is_array(ctx, obj) && proc->op_Tf)
381
{
382
pdf_obj *font_ref = pdf_array_get(ctx, obj, 0);
383
pdf_obj *font_size = pdf_array_get(ctx, obj, 1);
384
pdf_font_desc *font = load_font_or_hail_mary(ctx, csi->doc, csi->rdb, font_ref, 0, csi->cookie);
385
fz_try(ctx)
386
proc->op_Tf(ctx, proc, "ExtGState", font, pdf_to_real(ctx, font_size));
387
fz_always(ctx)
388
pdf_drop_font(ctx, font);
389
fz_catch(ctx)
390
fz_rethrow(ctx);
391
}
392
393
/* transfer functions */
394
395
obj = pdf_dict_get(ctx, dict, PDF_NAME_TR2);
396
if (pdf_is_name(ctx, obj))
397
if (!pdf_name_eq(ctx, obj, PDF_NAME_Identity) && !pdf_name_eq(ctx, obj, PDF_NAME_Default))
398
fz_warn(ctx, "ignoring transfer function");
399
if (!obj) /* TR is ignored in the presence of TR2 */
400
{
401
pdf_obj *tr = pdf_dict_get(ctx, dict, PDF_NAME_TR);
402
if (pdf_is_name(ctx, tr))
403
if (!pdf_name_eq(ctx, tr, PDF_NAME_Identity))
404
fz_warn(ctx, "ignoring transfer function");
405
}
406
407
/* transparency state */
408
409
obj = pdf_dict_get(ctx, dict, PDF_NAME_CA);
410
if (pdf_is_number(ctx, obj) && proc->op_gs_CA)
411
proc->op_gs_CA(ctx, proc, pdf_to_real(ctx, obj));
412
413
obj = pdf_dict_get(ctx, dict, PDF_NAME_ca);
414
if (pdf_is_number(ctx, obj) && proc->op_gs_ca)
415
proc->op_gs_ca(ctx, proc, pdf_to_real(ctx, obj));
416
417
obj = pdf_dict_get(ctx, dict, PDF_NAME_BM);
418
if (pdf_is_array(ctx, obj))
419
obj = pdf_array_get(ctx, obj, 0);
420
if (pdf_is_name(ctx, obj) && proc->op_gs_BM)
421
proc->op_gs_BM(ctx, proc, pdf_to_name(ctx, obj));
422
423
obj = pdf_dict_get(ctx, dict, PDF_NAME_SMask);
424
if (proc->op_gs_SMask)
425
{
426
if (pdf_is_dict(ctx, obj))
427
{
428
pdf_xobject *xobj;
429
pdf_obj *group, *s, *bc, *tr;
430
float softmask_bc[FZ_MAX_COLORS];
431
fz_colorspace *colorspace;
432
int k, luminosity;
433
434
fz_var(xobj);
435
436
group = pdf_dict_get(ctx, obj, PDF_NAME_G);
437
if (!group)
438
fz_throw(ctx, FZ_ERROR_GENERIC, "cannot load softmask xobject (%d %d R)", pdf_to_num(ctx, obj), pdf_to_gen(ctx, obj));
439
xobj = pdf_load_xobject(ctx, csi->doc, group);
440
441
fz_try(ctx)
442
{
443
colorspace = xobj->colorspace;
444
if (!colorspace)
445
colorspace = fz_device_gray(ctx);
446
447
for (k = 0; k < colorspace->n; k++)
448
softmask_bc[k] = 0;
449
450
bc = pdf_dict_get(ctx, obj, PDF_NAME_BC);
451
if (pdf_is_array(ctx, bc))
452
{
453
for (k = 0; k < colorspace->n; k++)
454
softmask_bc[k] = pdf_to_real(ctx, pdf_array_get(ctx, bc, k));
455
}
456
457
s = pdf_dict_get(ctx, obj, PDF_NAME_S);
458
if (pdf_name_eq(ctx, s, PDF_NAME_Luminosity))
459
luminosity = 1;
460
else
461
luminosity = 0;
462
463
tr = pdf_dict_get(ctx, obj, PDF_NAME_TR);
464
if (tr && !pdf_name_eq(ctx, tr, PDF_NAME_Identity))
465
fz_warn(ctx, "ignoring transfer function");
466
467
proc->op_gs_SMask(ctx, proc, xobj, csi->rdb, softmask_bc, luminosity);
468
}
469
fz_always(ctx)
470
{
471
pdf_drop_xobject(ctx, xobj);
472
}
473
fz_catch(ctx)
474
{
475
fz_rethrow(ctx);
476
}
477
}
478
else if (pdf_is_name(ctx, obj) && pdf_name_eq(ctx, obj, PDF_NAME_None))
479
{
480
proc->op_gs_SMask(ctx, proc, NULL, NULL, NULL, 0);
481
}
482
}
483
}
484
485
static void
486
pdf_process_Do(fz_context *ctx, pdf_processor *proc, pdf_csi *csi)
487
{
488
pdf_obj *xres, *xobj, *subtype;
489
490
xres = pdf_dict_get(ctx, csi->rdb, PDF_NAME_XObject);
491
if (!xres)
492
fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find XObject dictionary");
493
xobj = pdf_dict_gets(ctx, xres, csi->name);
494
if (!xobj)
495
fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find XObject resource '%s'", csi->name);
496
subtype = pdf_dict_get(ctx, xobj, PDF_NAME_Subtype);
497
if (pdf_name_eq(ctx, subtype, PDF_NAME_Form))
498
{
499
pdf_obj *st = pdf_dict_get(ctx, xobj, PDF_NAME_Subtype2);
500
if (st)
501
subtype = st;
502
}
503
if (!pdf_is_name(ctx, subtype))
504
fz_throw(ctx, FZ_ERROR_GENERIC, "no XObject subtype specified");
505
506
if (pdf_is_hidden_ocg(ctx, csi->doc->ocg, csi->rdb, proc->event, pdf_dict_get(ctx, xobj, PDF_NAME_OC)))
507
return;
508
509
if (pdf_name_eq(ctx, subtype, PDF_NAME_Form))
510
{
511
if (proc->op_Do_form)
512
{
513
pdf_xobject *form = pdf_load_xobject(ctx, csi->doc, xobj);
514
515
fz_try(ctx)
516
proc->op_Do_form(ctx, proc, csi->name, form, csi->rdb);
517
fz_always(ctx)
518
pdf_drop_xobject(ctx, form);
519
fz_catch(ctx)
520
fz_rethrow(ctx);
521
}
522
}
523
524
else if (pdf_name_eq(ctx, subtype, PDF_NAME_Image))
525
{
526
if (proc->op_Do_image)
527
{
528
fz_image *image = pdf_load_image(ctx, csi->doc, xobj);
529
fz_try(ctx)
530
proc->op_Do_image(ctx, proc, csi->name, image);
531
fz_always(ctx)
532
fz_drop_image(ctx, image);
533
fz_catch(ctx)
534
fz_rethrow(ctx);
535
}
536
}
537
538
else if (!strcmp(pdf_to_name(ctx, subtype), "PS"))
539
fz_warn(ctx, "ignoring XObject with subtype PS");
540
else
541
fz_warn(ctx, "ignoring XObject with unknown subtype: '%s'", pdf_to_name(ctx, subtype));
542
}
543
544
static void
545
pdf_process_CS(fz_context *ctx, pdf_processor *proc, pdf_csi *csi, int stroke)
546
{
547
if (!proc->op_CS || !proc->op_cs)
548
return;
549
550
if (!strcmp(csi->name, "Pattern"))
551
{
552
if (stroke)
553
proc->op_CS(ctx, proc, "Pattern", NULL);
554
else
555
proc->op_cs(ctx, proc, "Pattern", NULL);
556
}
557
else
558
{
559
fz_colorspace *cs;
560
561
if (!strcmp(csi->name, "DeviceGray"))
562
cs = fz_keep_colorspace(ctx, fz_device_gray(ctx));
563
else if (!strcmp(csi->name, "DeviceRGB"))
564
cs = fz_keep_colorspace(ctx, fz_device_rgb(ctx));
565
else if (!strcmp(csi->name, "DeviceCMYK"))
566
cs = fz_keep_colorspace(ctx, fz_device_cmyk(ctx));
567
else
568
{
569
pdf_obj *csres, *csobj;
570
csres = pdf_dict_get(ctx, csi->rdb, PDF_NAME_ColorSpace);
571
if (!csres)
572
fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find ColorSpace dictionary");
573
csobj = pdf_dict_gets(ctx, csres, csi->name);
574
if (!csobj)
575
fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find ColorSpace resource '%s'", csi->name);
576
cs = pdf_load_colorspace(ctx, csi->doc, csobj);
577
}
578
579
fz_try(ctx)
580
{
581
if (stroke)
582
proc->op_CS(ctx, proc, csi->name, cs);
583
else
584
proc->op_cs(ctx, proc, csi->name, cs);
585
}
586
fz_always(ctx)
587
fz_drop_colorspace(ctx, cs);
588
fz_catch(ctx)
589
fz_rethrow(ctx);
590
}
591
}
592
593
static void
594
pdf_process_SC(fz_context *ctx, pdf_processor *proc, pdf_csi *csi, int stroke)
595
{
596
if (csi->name[0])
597
{
598
pdf_obj *patres, *patobj, *type;
599
600
patres = pdf_dict_get(ctx, csi->rdb, PDF_NAME_Pattern);
601
if (!patres)
602
fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find Pattern dictionary");
603
patobj = pdf_dict_gets(ctx, patres, csi->name);
604
if (!patobj)
605
fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find Pattern resource '%s'", csi->name);
606
607
type = pdf_dict_get(ctx, patobj, PDF_NAME_PatternType);
608
609
if (pdf_to_int(ctx, type) == 1)
610
{
611
if (proc->op_SC_pattern && proc->op_sc_pattern)
612
{
613
pdf_pattern *pat = pdf_load_pattern(ctx, csi->doc, patobj);
614
fz_try(ctx)
615
{
616
if (stroke)
617
proc->op_SC_pattern(ctx, proc, csi->name, pat, csi->top, csi->stack);
618
else
619
proc->op_sc_pattern(ctx, proc, csi->name, pat, csi->top, csi->stack);
620
}
621
fz_always(ctx)
622
pdf_drop_pattern(ctx, pat);
623
fz_catch(ctx)
624
fz_rethrow(ctx);
625
}
626
}
627
628
else if (pdf_to_int(ctx, type) == 2)
629
{
630
if (proc->op_SC_shade && proc->op_sc_shade)
631
{
632
fz_shade *shade = pdf_load_shading(ctx, csi->doc, patobj);
633
fz_try(ctx)
634
{
635
if (stroke)
636
proc->op_SC_shade(ctx, proc, csi->name, shade);
637
else
638
proc->op_sc_shade(ctx, proc, csi->name, shade);
639
}
640
fz_always(ctx)
641
fz_drop_shade(ctx, shade);
642
fz_catch(ctx)
643
fz_rethrow(ctx);
644
}
645
}
646
647
else
648
{
649
fz_throw(ctx, FZ_ERROR_GENERIC, "unknown pattern type: %d", pdf_to_int(ctx, type));
650
}
651
}
652
653
else
654
{
655
if (proc->op_SC_color && proc->op_sc_color)
656
{
657
if (stroke)
658
proc->op_SC_color(ctx, proc, csi->top, csi->stack);
659
else
660
proc->op_sc_color(ctx, proc, csi->top, csi->stack);
661
}
662
}
663
}
664
665
static pdf_obj *
666
resolve_properties(fz_context *ctx, pdf_csi *csi, pdf_obj *obj)
667
{
668
if (pdf_is_name(ctx, obj))
669
return pdf_dict_get(ctx, pdf_dict_get(ctx, csi->rdb, PDF_NAME_Properties), obj);
670
else
671
return obj;
672
}
673
674
static void
675
pdf_process_BDC(fz_context *ctx, pdf_processor *proc, pdf_csi *csi, const char *name, pdf_obj *properties)
676
{
677
if (proc->op_BDC)
678
proc->op_BDC(ctx, proc, name, properties);
679
680
/* Already hidden, no need to look further */
681
if (proc->hidden > 0)
682
{
683
++proc->hidden;
684
return;
685
}
686
687
/* We only look at OC groups here */
688
if (strcmp(name, "OC"))
689
return;
690
691
/* No Properties array, or name not found, means visible. */
692
if (!properties)
693
return;
694
695
/* Wrong type of property */
696
if (!pdf_name_eq(ctx, pdf_dict_get(ctx, properties, PDF_NAME_Type), PDF_NAME_OCG))
697
return;
698
699
if (pdf_is_hidden_ocg(ctx, csi->doc->ocg, csi->rdb, proc->event, properties))
700
++proc->hidden;
701
}
702
703
static void
704
pdf_process_BMC(fz_context *ctx, pdf_processor *proc, pdf_csi *csi, const char *name)
705
{
706
if (proc->op_BMC)
707
proc->op_BMC(ctx, proc, name);
708
if (proc->hidden > 0)
709
++proc->hidden;
710
}
711
712
static void
713
pdf_process_EMC(fz_context *ctx, pdf_processor *proc, pdf_csi *csi)
714
{
715
if (proc->op_EMC)
716
proc->op_EMC(ctx, proc);
717
if (proc->hidden > 0)
718
--proc->hidden;
719
}
720
721
static void
722
pdf_process_gsave(fz_context *ctx, pdf_processor *proc, pdf_csi *csi)
723
{
724
if (proc->op_q)
725
proc->op_q(ctx, proc);
726
++csi->gstate;
727
}
728
729
static void
730
pdf_process_grestore(fz_context *ctx, pdf_processor *proc, pdf_csi *csi)
731
{
732
if (csi->gstate > 0)
733
{
734
if (proc->op_Q)
735
proc->op_Q(ctx, proc);
736
--csi->gstate;
737
}
738
}
739
740
static void
741
pdf_process_end(fz_context *ctx, pdf_processor *proc, pdf_csi *csi)
742
{
743
while (csi->gstate > 0)
744
pdf_process_grestore(ctx, proc, csi);
745
if (proc->op_END)
746
proc->op_END(ctx, proc);
747
}
748
749
#define A(a) (a)
750
#define B(a,b) (a | b << 8)
751
#define C(a,b,c) (a | b << 8 | c << 16)
752
753
static int
754
pdf_process_keyword(fz_context *ctx, pdf_processor *proc, pdf_csi *csi, fz_stream *stm, char *word)
755
{
756
float *s = csi->stack;
757
int key;
758
759
key = word[0];
760
if (word[1])
761
{
762
key |= word[1] << 8;
763
if (word[2])
764
{
765
key |= word[2] << 16;
766
if (word[3])
767
key = 0;
768
}
769
}
770
771
switch (key)
772
{
773
default:
774
if (!csi->xbalance)
775
{
776
fz_warn(ctx, "unknown keyword: '%s'", word);
777
return 1;
778
}
779
break;
780
781
/* general graphics state */
782
case A('w'): if (proc->op_w) proc->op_w(ctx, proc, s[0]); break;
783
case A('j'): if (proc->op_j) proc->op_j(ctx, proc, s[0]); break;
784
case A('J'): if (proc->op_J) proc->op_J(ctx, proc, s[0]); break;
785
case A('M'): if (proc->op_M) proc->op_M(ctx, proc, s[0]); break;
786
case A('d'): if (proc->op_d) proc->op_d(ctx, proc, csi->obj, s[0]); break;
787
case B('r','i'): if (proc->op_ri) proc->op_ri(ctx, proc, csi->name); break;
788
case A('i'): if (proc->op_i) proc->op_i(ctx, proc, s[0]); break;
789
790
case B('g','s'):
791
{
792
pdf_obj *gsres, *gsobj;
793
gsres = pdf_dict_get(ctx, csi->rdb, PDF_NAME_ExtGState);
794
if (!gsres)
795
fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find ExtGState dictionary");
796
gsobj = pdf_dict_gets(ctx, gsres, csi->name);
797
if (!gsobj)
798
fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find ExtGState resource '%s'", csi->name);
799
if (proc->op_gs_begin)
800
proc->op_gs_begin(ctx, proc, csi->name, gsobj);
801
pdf_process_extgstate(ctx, proc, csi, gsobj);
802
if (proc->op_gs_end)
803
proc->op_gs_end(ctx, proc);
804
}
805
break;
806
807
/* special graphics state */
808
case A('q'): pdf_process_gsave(ctx, proc, csi); break;
809
case A('Q'): pdf_process_grestore(ctx, proc, csi); break;
810
case B('c','m'): if (proc->op_cm) proc->op_cm(ctx, proc, s[0], s[1], s[2], s[3], s[4], s[5]); break;
811
812
/* path construction */
813
case A('m'): if (proc->op_m) proc->op_m(ctx, proc, s[0], s[1]); break;
814
case A('l'): if (proc->op_l) proc->op_l(ctx, proc, s[0], s[1]); break;
815
case A('c'): if (proc->op_c) proc->op_c(ctx, proc, s[0], s[1], s[2], s[3], s[4], s[5]); break;
816
case A('v'): if (proc->op_v) proc->op_v(ctx, proc, s[0], s[1], s[2], s[3]); break;
817
case A('y'): if (proc->op_y) proc->op_y(ctx, proc, s[0], s[1], s[2], s[3]); break;
818
case A('h'): if (proc->op_h) proc->op_h(ctx, proc); break;
819
case B('r','e'): if (proc->op_re) proc->op_re(ctx, proc, s[0], s[1], s[2], s[3]); break;
820
821
/* path painting */
822
case A('S'): if (proc->op_S) proc->op_S(ctx, proc); break;
823
case A('s'): if (proc->op_s) proc->op_s(ctx, proc); break;
824
case A('F'): if (proc->op_F) proc->op_F(ctx, proc); break;
825
case A('f'): if (proc->op_f) proc->op_f(ctx, proc); break;
826
case B('f','*'): if (proc->op_fstar) proc->op_fstar(ctx, proc); break;
827
case A('B'): if (proc->op_B) proc->op_B(ctx, proc); break;
828
case B('B','*'): if (proc->op_Bstar) proc->op_Bstar(ctx, proc); break;
829
case A('b'): if (proc->op_b) proc->op_b(ctx, proc); break;
830
case B('b','*'): if (proc->op_bstar) proc->op_bstar(ctx, proc); break;
831
case A('n'): if (proc->op_n) proc->op_n(ctx, proc); break;
832
833
/* path clipping */
834
case A('W'): if (proc->op_W) proc->op_W(ctx, proc); break;
835
case B('W','*'): if (proc->op_Wstar) proc->op_Wstar(ctx, proc); break;
836
837
/* text objects */
838
case B('B','T'): csi->in_text = 1; if (proc->op_BT) proc->op_BT(ctx, proc); break;
839
case B('E','T'): csi->in_text = 0; if (proc->op_ET) proc->op_ET(ctx, proc); break;
840
841
/* text state */
842
case B('T','c'): if (proc->op_Tc) proc->op_Tc(ctx, proc, s[0]); break;
843
case B('T','w'): if (proc->op_Tw) proc->op_Tw(ctx, proc, s[0]); break;
844
case B('T','z'): if (proc->op_Tz) proc->op_Tz(ctx, proc, s[0]); break;
845
case B('T','L'): if (proc->op_TL) proc->op_TL(ctx, proc, s[0]); break;
846
case B('T','r'): if (proc->op_Tr) proc->op_Tr(ctx, proc, s[0]); break;
847
case B('T','s'): if (proc->op_Ts) proc->op_Ts(ctx, proc, s[0]); break;
848
849
case B('T','f'):
850
if (proc->op_Tf)
851
{
852
pdf_obj *fontres, *fontobj;
853
pdf_font_desc *font;
854
fontres = pdf_dict_get(ctx, csi->rdb, PDF_NAME_Font);
855
if (!fontres)
856
fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find Font dictionary");
857
fontobj = pdf_dict_gets(ctx, fontres, csi->name);
858
if (!fontobj)
859
fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find Font resource '%s'", csi->name);
860
font = load_font_or_hail_mary(ctx, csi->doc, csi->rdb, fontobj, 0, csi->cookie);
861
fz_try(ctx)
862
proc->op_Tf(ctx, proc, csi->name, font, s[0]); break;
863
fz_always(ctx)
864
pdf_drop_font(ctx, font);
865
fz_catch(ctx)
866
fz_rethrow(ctx);
867
}
868
break;
869
870
/* text positioning */
871
case B('T','d'): if (proc->op_Td) proc->op_Td(ctx, proc, s[0], s[1]); break;
872
case B('T','D'): if (proc->op_TD) proc->op_TD(ctx, proc, s[0], s[1]); break;
873
case B('T','m'): if (proc->op_Tm) proc->op_Tm(ctx, proc, s[0], s[1], s[2], s[3], s[4], s[5]); break;
874
case B('T','*'): if (proc->op_Tstar) proc->op_Tstar(ctx, proc); break;
875
876
/* text showing */
877
case B('T','J'): if (proc->op_TJ) proc->op_TJ(ctx, proc, csi->obj); break;
878
case B('T','j'):
879
if (proc->op_Tj)
880
{
881
if (csi->string_len > 0)
882
proc->op_Tj(ctx, proc, csi->string, csi->string_len);
883
else
884
proc->op_Tj(ctx, proc, pdf_to_str_buf(ctx, csi->obj), pdf_to_str_len(ctx, csi->obj));
885
}
886
break;
887
case A('\''):
888
if (proc->op_squote)
889
{
890
if (csi->string_len > 0)
891
proc->op_squote(ctx, proc, csi->string, csi->string_len);
892
else
893
proc->op_squote(ctx, proc, pdf_to_str_buf(ctx, csi->obj), pdf_to_str_len(ctx, csi->obj));
894
}
895
break;
896
case A('"'):
897
if (proc->op_dquote)
898
{
899
if (csi->string_len > 0)
900
proc->op_dquote(ctx, proc, s[0], s[1], csi->string, csi->string_len);
901
else
902
proc->op_dquote(ctx, proc, s[0], s[1], pdf_to_str_buf(ctx, csi->obj), pdf_to_str_len(ctx, csi->obj));
903
}
904
break;
905
906
/* type 3 fonts */
907
case B('d','0'): if (proc->op_d0) proc->op_d0(ctx, proc, s[0], s[1]); break;
908
case B('d','1'): if (proc->op_d1) proc->op_d1(ctx, proc, s[0], s[1], s[2], s[3], s[4], s[5]); break;
909
910
/* color */
911
case B('C','S'): pdf_process_CS(ctx, proc, csi, 1); break;
912
case B('c','s'): pdf_process_CS(ctx, proc, csi, 0); break;
913
case B('S','C'): pdf_process_SC(ctx, proc, csi, 1); break;
914
case B('s','c'): pdf_process_SC(ctx, proc, csi, 0); break;
915
case C('S','C','N'): pdf_process_SC(ctx, proc, csi, 1); break;
916
case C('s','c','n'): pdf_process_SC(ctx, proc, csi, 0); break;
917
918
case A('G'): if (proc->op_G) proc->op_G(ctx, proc, s[0]); break;
919
case A('g'): if (proc->op_g) proc->op_g(ctx, proc, s[0]); break;
920
case B('R','G'): if (proc->op_RG) proc->op_RG(ctx, proc, s[0], s[1], s[2]); break;
921
case B('r','g'): if (proc->op_rg) proc->op_rg(ctx, proc, s[0], s[1], s[2]); break;
922
case A('K'): if (proc->op_K) proc->op_K(ctx, proc, s[0], s[1], s[2], s[3]); break;
923
case A('k'): if (proc->op_k) proc->op_k(ctx, proc, s[0], s[1], s[2], s[3]); break;
924
925
/* shadings, images, xobjects */
926
case B('B','I'):
927
{
928
fz_image *img = parse_inline_image(ctx, csi, stm);
929
fz_try(ctx)
930
{
931
if (proc->op_BI)
932
proc->op_BI(ctx, proc, img);
933
}
934
fz_always(ctx)
935
fz_drop_image(ctx, img);
936
fz_catch(ctx)
937
fz_rethrow(ctx);
938
}
939
break;
940
941
case B('s','h'):
942
if (proc->op_sh)
943
{
944
pdf_obj *shaderes, *shadeobj;
945
fz_shade *shade;
946
shaderes = pdf_dict_get(ctx, csi->rdb, PDF_NAME_Shading);
947
if (!shaderes)
948
fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find Shading dictionary");
949
shadeobj = pdf_dict_gets(ctx, shaderes, csi->name);
950
if (!shadeobj)
951
fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find Shading resource '%s'", csi->name);
952
shade = pdf_load_shading(ctx, csi->doc, shadeobj);
953
fz_try(ctx)
954
proc->op_sh(ctx, proc, csi->name, shade);
955
fz_always(ctx)
956
fz_drop_shade(ctx, shade);
957
fz_catch(ctx)
958
fz_rethrow(ctx);
959
}
960
break;
961
962
case B('D','o'): pdf_process_Do(ctx, proc, csi); break;
963
964
/* marked content */
965
case B('M','P'): if (proc->op_MP) proc->op_MP(ctx, proc, csi->name); break;
966
case B('D','P'): if (proc->op_DP) proc->op_DP(ctx, proc, csi->name, resolve_properties(ctx, csi, csi->obj)); break;
967
case C('B','M','C'): pdf_process_BMC(ctx, proc, csi, csi->name); break;
968
case C('B','D','C'): pdf_process_BDC(ctx, proc, csi, csi->name, resolve_properties(ctx, csi, csi->obj)); break;
969
case C('E','M','C'): pdf_process_EMC(ctx, proc, csi); break;
970
971
/* compatibility */
972
case B('B','X'): ++csi->xbalance; if (proc->op_BX) proc->op_BX(ctx, proc); break;
973
case B('E','X'): --csi->xbalance; if (proc->op_EX) proc->op_EX(ctx, proc); break;
974
}
975
976
return 0;
977
}
978
979
static void
980
pdf_process_stream(fz_context *ctx, pdf_processor *proc, pdf_csi *csi, fz_stream *stm)
981
{
982
pdf_document *doc = csi->doc;
983
pdf_lexbuf *buf = csi->buf;
984
fz_cookie *cookie = csi->cookie;
985
986
pdf_token tok = PDF_TOK_ERROR;
987
int in_text_array = 0;
988
int ignoring_errors = 0;
989
990
/* make sure we have a clean slate if we come here from flush_text */
991
pdf_clear_stack(ctx, csi);
992
993
fz_var(in_text_array);
994
fz_var(tok);
995
996
if (cookie)
997
{
998
cookie->progress_max = -1;
999
cookie->progress = 0;
1000
}
1001
1002
do
1003
{
1004
fz_try(ctx)
1005
{
1006
do
1007
{
1008
/* Check the cookie */
1009
if (cookie)
1010
{
1011
if (cookie->abort)
1012
{
1013
tok = PDF_TOK_EOF;
1014
break;
1015
}
1016
cookie->progress++;
1017
}
1018
1019
tok = pdf_lex(ctx, stm, buf);
1020
1021
if (in_text_array)
1022
{
1023
switch(tok)
1024
{
1025
case PDF_TOK_CLOSE_ARRAY:
1026
in_text_array = 0;
1027
break;
1028
case PDF_TOK_REAL:
1029
pdf_array_push_drop(ctx, csi->obj, pdf_new_real(ctx, doc, buf->f));
1030
break;
1031
case PDF_TOK_INT:
1032
pdf_array_push_drop(ctx, csi->obj, pdf_new_int(ctx, doc, buf->i));
1033
break;
1034
case PDF_TOK_STRING:
1035
pdf_array_push_drop(ctx, csi->obj, pdf_new_string(ctx, doc, buf->scratch, buf->len));
1036
break;
1037
case PDF_TOK_EOF:
1038
break;
1039
case PDF_TOK_KEYWORD:
1040
if (!strcmp(buf->scratch, "Tw") || !strcmp(buf->scratch, "Tc"))
1041
{
1042
int l = pdf_array_len(ctx, csi->obj);
1043
if (l > 0)
1044
{
1045
pdf_obj *o = pdf_array_get(ctx, csi->obj, l-1);
1046
if (pdf_is_number(ctx, o))
1047
{
1048
csi->stack[0] = pdf_to_real(ctx, o);
1049
pdf_array_delete(ctx, csi->obj, l-1);
1050
if (pdf_process_keyword(ctx, proc, csi, stm, buf->scratch) == 0)
1051
break;
1052
}
1053
}
1054
}
1055
/* Deliberate Fallthrough! */
1056
default:
1057
fz_throw(ctx, FZ_ERROR_GENERIC, "syntax error in array");
1058
}
1059
}
1060
else switch (tok)
1061
{
1062
case PDF_TOK_ENDSTREAM:
1063
case PDF_TOK_EOF:
1064
tok = PDF_TOK_EOF;
1065
break;
1066
1067
case PDF_TOK_OPEN_ARRAY:
1068
if (csi->obj)
1069
{
1070
pdf_drop_obj(ctx, csi->obj);
1071
csi->obj = NULL;
1072
}
1073
if (csi->in_text)
1074
{
1075
in_text_array = 1;
1076
csi->obj = pdf_new_array(ctx, doc, 4);
1077
}
1078
else
1079
{
1080
csi->obj = pdf_parse_array(ctx, doc, stm, buf);
1081
}
1082
break;
1083
1084
case PDF_TOK_OPEN_DICT:
1085
if (csi->obj)
1086
{
1087
pdf_drop_obj(ctx, csi->obj);
1088
csi->obj = NULL;
1089
}
1090
csi->obj = pdf_parse_dict(ctx, doc, stm, buf);
1091
break;
1092
1093
case PDF_TOK_NAME:
1094
if (csi->name[0])
1095
{
1096
pdf_drop_obj(ctx, csi->obj);
1097
csi->obj = NULL;
1098
csi->obj = pdf_new_name(ctx, doc, buf->scratch);
1099
}
1100
else
1101
fz_strlcpy(csi->name, buf->scratch, sizeof(csi->name));
1102
break;
1103
1104
case PDF_TOK_INT:
1105
if (csi->top < nelem(csi->stack)) {
1106
csi->stack[csi->top] = buf->i;
1107
csi->top ++;
1108
}
1109
else
1110
fz_throw(ctx, FZ_ERROR_GENERIC, "stack overflow");
1111
break;
1112
1113
case PDF_TOK_REAL:
1114
if (csi->top < nelem(csi->stack)) {
1115
csi->stack[csi->top] = buf->f;
1116
csi->top ++;
1117
}
1118
else
1119
fz_throw(ctx, FZ_ERROR_GENERIC, "stack overflow");
1120
break;
1121
1122
case PDF_TOK_STRING:
1123
if (buf->len <= sizeof(csi->string))
1124
{
1125
memcpy(csi->string, buf->scratch, buf->len);
1126
csi->string_len = buf->len;
1127
}
1128
else
1129
{
1130
if (csi->obj)
1131
{
1132
pdf_drop_obj(ctx, csi->obj);
1133
csi->obj = NULL;
1134
}
1135
csi->obj = pdf_new_string(ctx, doc, buf->scratch, buf->len);
1136
}
1137
break;
1138
1139
case PDF_TOK_KEYWORD:
1140
if (pdf_process_keyword(ctx, proc, csi, stm, buf->scratch))
1141
{
1142
tok = PDF_TOK_EOF;
1143
}
1144
pdf_clear_stack(ctx, csi);
1145
break;
1146
1147
default:
1148
fz_throw(ctx, FZ_ERROR_GENERIC, "syntax error in content stream");
1149
}
1150
}
1151
while (tok != PDF_TOK_EOF);
1152
}
1153
fz_always(ctx)
1154
{
1155
pdf_clear_stack(ctx, csi);
1156
}
1157
fz_catch(ctx)
1158
{
1159
int caught;
1160
1161
if (!cookie)
1162
{
1163
fz_rethrow_if(ctx, FZ_ERROR_TRYLATER);
1164
}
1165
else if ((caught = fz_caught(ctx)) == FZ_ERROR_TRYLATER)
1166
{
1167
if (cookie->incomplete_ok)
1168
cookie->incomplete++;
1169
else
1170
fz_rethrow(ctx);
1171
}
1172
else if (caught == FZ_ERROR_ABORT)
1173
{
1174
fz_rethrow(ctx);
1175
}
1176
else
1177
{
1178
cookie->errors++;
1179
}
1180
if (!ignoring_errors)
1181
{
1182
fz_warn(ctx, "Ignoring errors during rendering");
1183
ignoring_errors = 1;
1184
}
1185
/* If we do catch an error, then reset ourselves to a
1186
* base lexing state */
1187
in_text_array = 0;
1188
}
1189
}
1190
while (tok != PDF_TOK_EOF);
1191
}
1192
1193
void
1194
pdf_process_contents(fz_context *ctx, pdf_processor *proc, pdf_document *doc, pdf_obj *rdb, pdf_obj *stmobj, fz_cookie *cookie)
1195
{
1196
pdf_csi csi;
1197
pdf_lexbuf buf;
1198
fz_stream *stm = NULL;
1199
1200
if (!stmobj)
1201
return;
1202
1203
fz_var(stm);
1204
1205
pdf_lexbuf_init(ctx, &buf, PDF_LEXBUF_SMALL);
1206
pdf_init_csi(ctx, &csi, doc, rdb, &buf, cookie);
1207
1208
fz_try(ctx)
1209
{
1210
stm = pdf_open_contents_stream(ctx, doc, stmobj);
1211
pdf_process_stream(ctx, proc, &csi, stm);
1212
pdf_process_end(ctx, proc, &csi);
1213
}
1214
fz_always(ctx)
1215
{
1216
fz_drop_stream(ctx, stm);
1217
pdf_clear_stack(ctx, &csi);
1218
pdf_lexbuf_fin(ctx, &buf);
1219
}
1220
fz_catch(ctx)
1221
{
1222
fz_rethrow_if(ctx, FZ_ERROR_ABORT);
1223
fz_rethrow_message(ctx, "cannot parse content stream");
1224
}
1225
}
1226
1227
void
1228
pdf_process_annot(fz_context *ctx, pdf_processor *proc, pdf_document *doc, pdf_page *page, pdf_annot *annot, fz_cookie *cookie)
1229
{
1230
int flags = pdf_to_int(ctx, pdf_dict_get(ctx, annot->obj, PDF_NAME_F));
1231
1232
if (flags & (F_Invisible | F_Hidden))
1233
return;
1234
1235
if (proc->event)
1236
{
1237
if (!strcmp(proc->event, "Print") && !(flags & F_Print))
1238
return;
1239
if (!strcmp(proc->event, "View") && (flags & F_NoView))
1240
return;
1241
}
1242
1243
/* TODO: NoZoom and NoRotate */
1244
1245
/* XXX what resources, if any, to use for this check? */
1246
if (pdf_is_hidden_ocg(ctx, doc->ocg, NULL, proc->event, pdf_dict_get(ctx, annot->obj, PDF_NAME_OC)))
1247
return;
1248
1249
if (proc->op_q && proc->op_cm && proc->op_Do_form && proc->op_Q)
1250
{
1251
proc->op_q(ctx, proc);
1252
proc->op_cm(ctx, proc,
1253
annot->matrix.a, annot->matrix.b, annot->matrix.c,
1254
annot->matrix.d, annot->matrix.e, annot->matrix.f);
1255
proc->op_Do_form(ctx, proc, "Annot", annot->ap, page->resources);
1256
proc->op_Q(ctx, proc);
1257
}
1258
}
1259
1260
void
1261
pdf_process_glyph(fz_context *ctx, pdf_processor *proc, pdf_document *doc, pdf_obj *rdb, fz_buffer *contents)
1262
{
1263
pdf_csi csi;
1264
pdf_lexbuf buf;
1265
fz_stream *stm = NULL;
1266
1267
fz_var(stm);
1268
1269
if (!contents)
1270
return;
1271
1272
pdf_lexbuf_init(ctx, &buf, PDF_LEXBUF_SMALL);
1273
pdf_init_csi(ctx, &csi, doc, rdb, &buf, NULL);
1274
1275
fz_try(ctx)
1276
{
1277
fz_stream *stm = fz_open_buffer(ctx, contents);
1278
pdf_process_stream(ctx, proc, &csi, stm);
1279
pdf_process_end(ctx, proc, &csi);
1280
}
1281
fz_always(ctx)
1282
{
1283
fz_drop_stream(ctx, stm);
1284
pdf_clear_stack(ctx, &csi);
1285
pdf_lexbuf_fin(ctx, &buf);
1286
}
1287
fz_catch(ctx)
1288
{
1289
fz_rethrow_if(ctx, FZ_ERROR_ABORT);
1290
fz_rethrow_message(ctx, "cannot parse glyph content stream");
1291
}
1292
}
1293
1294