Coverage Report

Created: 2024-07-05 06:13

/src/mupdf/source/pdf/pdf-op-buffer.c
Line
Count
Source (jump to first uncovered line)
1
// Copyright (C) 2004-2024 Artifex Software, Inc.
2
//
3
// This file is part of MuPDF.
4
//
5
// MuPDF is free software: you can redistribute it and/or modify it under the
6
// terms of the GNU Affero General Public License as published by the Free
7
// Software Foundation, either version 3 of the License, or (at your option)
8
// any later version.
9
//
10
// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
11
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12
// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13
// details.
14
//
15
// You should have received a copy of the GNU Affero General Public License
16
// along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
17
//
18
// Alternative licensing terms are available from the licensor.
19
// For commercial licensing, see <https://www.artifex.com/> or contact
20
// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
21
// CA 94129, USA, for further information.
22
23
#include "mupdf/fitz.h"
24
#include "mupdf/pdf.h"
25
26
typedef struct resources_stack
27
{
28
  struct resources_stack *next;
29
  pdf_obj *res;
30
} resources_stack;
31
32
typedef struct
33
{
34
  pdf_processor super;
35
  fz_output *out;
36
  int ahxencode;
37
  int extgstate;
38
  int newlines;
39
  int balance;
40
  pdf_obj *res;
41
  pdf_obj *last_res;
42
  resources_stack *rstack;
43
  int sep;
44
} pdf_output_processor;
45
46
/* general graphics state */
47
48
static void
49
post_op(fz_context *ctx, pdf_output_processor *proc)
50
0
{
51
0
  if (proc->newlines)
52
0
  {
53
0
    fz_write_byte(ctx, proc->out, '\n');
54
0
    proc->sep = 0;
55
0
  }
56
0
  else
57
0
    proc->sep = 1;
58
0
}
59
60
static void
61
pdf_out_w(fz_context *ctx, pdf_processor *proc_, float linewidth)
62
0
{
63
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
64
65
0
  if (proc->extgstate != 0)
66
0
    return;
67
68
0
  if (proc->sep)
69
0
    fz_write_byte(ctx, proc->out, ' ');
70
0
  fz_write_printf(ctx, proc->out, "%g w", linewidth);
71
0
  post_op(ctx, proc);
72
0
}
73
74
static void
75
pdf_out_j(fz_context *ctx, pdf_processor *proc_, int linejoin)
76
0
{
77
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
78
79
0
  if (proc->extgstate != 0)
80
0
    return;
81
82
0
  if (proc->sep)
83
0
    fz_write_byte(ctx, proc->out, ' ');
84
0
  fz_write_printf(ctx, proc->out, "%d j", linejoin);
85
0
  post_op(ctx, proc);
86
0
}
87
88
static void
89
pdf_out_J(fz_context *ctx, pdf_processor *proc_, int linecap)
90
0
{
91
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
92
93
0
  if (proc->extgstate != 0)
94
0
    return;
95
96
0
  if (proc->sep)
97
0
    fz_write_byte(ctx, proc->out, ' ');
98
0
  fz_write_printf(ctx, proc->out, "%d J", linecap);
99
0
  post_op(ctx, proc);
100
0
}
101
102
static void
103
pdf_out_M(fz_context *ctx, pdf_processor *proc_, float a)
104
0
{
105
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
106
107
0
  if (proc->extgstate != 0)
108
0
    return;
109
110
0
  if (proc->sep)
111
0
    fz_write_byte(ctx, proc->out, ' ');
112
0
  fz_write_printf(ctx, proc->out, "%g M", a);
113
0
  post_op(ctx, proc);
114
0
}
115
116
static void
117
pdf_out_d(fz_context *ctx, pdf_processor *proc_, pdf_obj *array, float phase)
118
0
{
119
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
120
0
  int ahx = proc->ahxencode;
121
122
0
  if (proc->extgstate != 0)
123
0
    return;
124
125
0
  pdf_print_encrypted_obj(ctx, proc->out, array, 1, ahx, NULL, 0, 0, &proc->sep);
126
0
  if (proc->sep)
127
0
    fz_write_byte(ctx, proc->out, ' ');
128
0
  fz_write_printf(ctx, proc->out, "%g d", phase);
129
0
  post_op(ctx, proc);
130
0
}
131
132
static void
133
pdf_out_ri(fz_context *ctx, pdf_processor *proc_, const char *intent)
134
0
{
135
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
136
137
0
  if (proc->extgstate != 0)
138
0
    return;
139
140
0
  if (proc->sep)
141
0
    fz_write_byte(ctx, proc->out, ' ');
142
0
  fz_write_printf(ctx, proc->out, "%n ri", intent);
143
0
  post_op(ctx, proc);
144
0
}
145
146
static void
147
pdf_out_i(fz_context *ctx, pdf_processor *proc_, float flatness)
148
0
{
149
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
150
151
0
  if (proc->extgstate != 0)
152
0
    return;
153
154
0
  if (proc->sep)
155
0
    fz_write_byte(ctx, proc->out, ' ');
156
0
  fz_write_printf(ctx, proc->out, "%g i", flatness);
157
0
  post_op(ctx, proc);
158
0
}
159
160
static void
161
pdf_out_gs_begin(fz_context *ctx, pdf_processor *proc_, const char *name, pdf_obj *extgstate)
162
0
{
163
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
164
165
0
  proc->extgstate = 1;
166
167
0
  fz_write_printf(ctx, proc->out, "%n gs", name);
168
0
  post_op(ctx, proc);
169
0
}
170
171
static void
172
pdf_out_gs_end(fz_context *ctx, pdf_processor *proc)
173
0
{
174
0
  ((pdf_output_processor*)proc)->extgstate = 0;
175
0
}
176
177
/* special graphics state */
178
179
static void
180
pdf_out_q(fz_context *ctx, pdf_processor *proc_)
181
0
{
182
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
183
184
0
  proc->balance++;
185
186
0
  if (proc->sep)
187
0
    fz_write_byte(ctx, proc->out, ' ');
188
0
  fz_write_string(ctx, proc->out, "q");
189
0
  post_op(ctx, proc);
190
0
}
191
192
static void
193
pdf_out_Q(fz_context *ctx, pdf_processor *proc_)
194
0
{
195
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
196
197
0
  proc->balance--;
198
0
  if (proc->balance < 0)
199
0
    fz_warn(ctx, "gstate underflow (too many Q operators)");
200
201
0
  if (proc->sep)
202
0
    fz_write_byte(ctx, proc->out, ' ');
203
0
  fz_write_string(ctx, proc->out, "Q");
204
0
  post_op(ctx, proc);
205
0
}
206
207
static void
208
pdf_out_cm(fz_context *ctx, pdf_processor *proc_, float a, float b, float c, float d, float e, float f)
209
0
{
210
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
211
212
0
  if (proc->sep)
213
0
    fz_write_byte(ctx, proc->out, ' ');
214
0
  fz_write_printf(ctx, proc->out, "%g %g %g %g %g %g cm", a, b, c, d, e, f);
215
0
  post_op(ctx, proc);
216
0
}
217
218
/* path construction */
219
220
static void
221
pdf_out_m(fz_context *ctx, pdf_processor *proc_, float x, float y)
222
0
{
223
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
224
225
0
  if (proc->sep)
226
0
    fz_write_byte(ctx, proc->out, ' ');
227
0
  fz_write_printf(ctx, proc->out, "%g %g m", x, y);
228
0
  post_op(ctx, proc);
229
0
}
230
231
static void
232
pdf_out_l(fz_context *ctx, pdf_processor *proc_, float x, float y)
233
0
{
234
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
235
236
0
  if (proc->sep)
237
0
    fz_write_byte(ctx, proc->out, ' ');
238
0
  fz_write_printf(ctx, proc->out, "%g %g l", x, y);
239
0
  post_op(ctx, proc);
240
0
}
241
242
static void
243
pdf_out_c(fz_context *ctx, pdf_processor *proc_, float x1, float y1, float x2, float y2, float x3, float y3)
244
0
{
245
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
246
247
0
  if (proc->sep)
248
0
    fz_write_byte(ctx, proc->out, ' ');
249
0
  fz_write_printf(ctx, proc->out, "%g %g %g %g %g %g c", x1, y1, x2, y2, x3, y3);
250
0
  post_op(ctx, proc);
251
0
}
252
253
static void
254
pdf_out_v(fz_context *ctx, pdf_processor *proc_, float x2, float y2, float x3, float y3)
255
0
{
256
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
257
258
0
  if (proc->sep)
259
0
    fz_write_byte(ctx, proc->out, ' ');
260
0
  fz_write_printf(ctx, proc->out, "%g %g %g %g v", x2, y2, x3, y3);
261
0
  post_op(ctx, proc);
262
0
}
263
264
static void
265
pdf_out_y(fz_context *ctx, pdf_processor *proc_, float x1, float y1, float x3, float y3)
266
0
{
267
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
268
269
0
  if (proc->sep)
270
0
    fz_write_byte(ctx, proc->out, ' ');
271
0
  fz_write_printf(ctx, proc->out, "%g %g %g %g y", x1, y1, x3, y3);
272
0
  post_op(ctx, proc);
273
0
}
274
275
static void
276
pdf_out_h(fz_context *ctx, pdf_processor *proc_)
277
0
{
278
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
279
280
0
  if (proc->sep)
281
0
    fz_write_byte(ctx, proc->out, ' ');
282
0
  fz_write_string(ctx, proc->out, "h");
283
0
  post_op(ctx, proc);
284
0
}
285
286
static void
287
pdf_out_re(fz_context *ctx, pdf_processor *proc_, float x, float y, float w, float h)
288
0
{
289
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
290
291
0
  if (proc->sep)
292
0
    fz_write_byte(ctx, proc->out, ' ');
293
0
  fz_write_printf(ctx, proc->out, "%g %g %g %g re", x, y, w, h);
294
0
  post_op(ctx, proc);
295
0
}
296
297
/* path painting */
298
299
static void
300
pdf_out_S(fz_context *ctx, pdf_processor *proc_)
301
0
{
302
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
303
304
0
  if (proc->sep)
305
0
    fz_write_byte(ctx, proc->out, ' ');
306
0
  fz_write_string(ctx, proc->out, "S");
307
0
  post_op(ctx, proc);
308
0
}
309
310
static void
311
pdf_out_s(fz_context *ctx, pdf_processor *proc_)
312
0
{
313
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
314
315
0
  if (proc->sep)
316
0
    fz_write_byte(ctx, proc->out, ' ');
317
0
  fz_write_string(ctx, proc->out, "s");
318
0
  post_op(ctx, proc);
319
0
}
320
321
static void
322
pdf_out_F(fz_context *ctx, pdf_processor *proc_)
323
0
{
324
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
325
326
0
  if (proc->sep)
327
0
    fz_write_byte(ctx, proc->out, ' ');
328
0
  fz_write_string(ctx, proc->out, "F");
329
0
  post_op(ctx, proc);
330
0
}
331
332
static void
333
pdf_out_f(fz_context *ctx, pdf_processor *proc_)
334
0
{
335
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
336
337
0
  if (proc->sep)
338
0
    fz_write_byte(ctx, proc->out, ' ');
339
0
  fz_write_string(ctx, proc->out, "f");
340
0
  post_op(ctx, proc);
341
0
}
342
343
static void
344
pdf_out_fstar(fz_context *ctx, pdf_processor *proc_)
345
0
{
346
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
347
348
0
  if (proc->sep)
349
0
    fz_write_byte(ctx, proc->out, ' ');
350
0
  fz_write_string(ctx, proc->out, "f*");
351
0
  post_op(ctx, proc);
352
0
}
353
354
static void
355
pdf_out_B(fz_context *ctx, pdf_processor *proc_)
356
0
{
357
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
358
359
0
  if (proc->sep)
360
0
    fz_write_byte(ctx, proc->out, ' ');
361
0
  fz_write_string(ctx, proc->out, "B");
362
0
  post_op(ctx, proc);
363
0
}
364
365
static void
366
pdf_out_Bstar(fz_context *ctx, pdf_processor *proc_)
367
0
{
368
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
369
370
0
  if (proc->sep)
371
0
    fz_write_byte(ctx, proc->out, ' ');
372
0
  fz_write_string(ctx, proc->out, "B*");
373
0
  post_op(ctx, proc);
374
0
}
375
376
static void
377
pdf_out_b(fz_context *ctx, pdf_processor *proc_)
378
0
{
379
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
380
381
0
  if (proc->sep)
382
0
    fz_write_byte(ctx, proc->out, ' ');
383
0
  fz_write_string(ctx, proc->out, "b");
384
0
  post_op(ctx, proc);
385
0
}
386
387
static void
388
pdf_out_bstar(fz_context *ctx, pdf_processor *proc_)
389
0
{
390
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
391
392
0
  if (proc->sep)
393
0
    fz_write_byte(ctx, proc->out, ' ');
394
0
  fz_write_string(ctx, proc->out, "b*");
395
0
  post_op(ctx, proc);
396
0
}
397
398
static void
399
pdf_out_n(fz_context *ctx, pdf_processor *proc_)
400
0
{
401
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
402
403
0
  if (proc->sep)
404
0
    fz_write_byte(ctx, proc->out, ' ');
405
0
  fz_write_string(ctx, proc->out, "n");
406
0
  post_op(ctx, proc);
407
0
}
408
409
/* clipping paths */
410
411
static void
412
pdf_out_W(fz_context *ctx, pdf_processor *proc_)
413
0
{
414
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
415
416
0
  if (proc->sep)
417
0
    fz_write_byte(ctx, proc->out, ' ');
418
0
  fz_write_string(ctx, proc->out, "W");
419
0
  post_op(ctx, proc);
420
0
}
421
422
static void
423
pdf_out_Wstar(fz_context *ctx, pdf_processor *proc_)
424
0
{
425
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
426
427
0
  if (proc->sep)
428
0
    fz_write_byte(ctx, proc->out, ' ');
429
0
  fz_write_string(ctx, proc->out, "W*");
430
0
  post_op(ctx, proc);
431
0
}
432
433
/* text objects */
434
435
static void
436
pdf_out_BT(fz_context *ctx, pdf_processor *proc_)
437
0
{
438
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
439
440
0
  if (proc->sep)
441
0
    fz_write_byte(ctx, proc->out, ' ');
442
0
  fz_write_string(ctx, proc->out, "BT");
443
0
  post_op(ctx, proc);
444
0
}
445
446
static void
447
pdf_out_ET(fz_context *ctx, pdf_processor *proc_)
448
0
{
449
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
450
451
0
  if (proc->sep)
452
0
    fz_write_byte(ctx, proc->out, ' ');
453
0
  fz_write_string(ctx, proc->out, "ET");
454
0
  post_op(ctx, proc);
455
0
}
456
457
/* text state */
458
459
static void
460
pdf_out_Tc(fz_context *ctx, pdf_processor *proc_, float charspace)
461
0
{
462
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
463
464
0
  if (proc->sep)
465
0
    fz_write_byte(ctx, proc->out, ' ');
466
0
  fz_write_printf(ctx, proc->out, "%g Tc", charspace);
467
0
  post_op(ctx, proc);
468
0
}
469
470
static void
471
pdf_out_Tw(fz_context *ctx, pdf_processor *proc_, float wordspace)
472
0
{
473
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
474
475
0
  if (proc->sep)
476
0
    fz_write_byte(ctx, proc->out, ' ');
477
0
  fz_write_printf(ctx, proc->out, "%g Tw", wordspace);
478
0
  post_op(ctx, proc);
479
0
}
480
481
static void
482
pdf_out_Tz(fz_context *ctx, pdf_processor *proc_, float scale)
483
0
{
484
  /* scale is exactly as read from the file. */
485
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
486
487
0
  if (proc->sep)
488
0
    fz_write_byte(ctx, proc->out, ' ');
489
0
  fz_write_printf(ctx, proc->out, "%g Tz", scale);
490
0
  post_op(ctx, proc);
491
0
}
492
493
static void
494
pdf_out_TL(fz_context *ctx, pdf_processor *proc_, float leading)
495
0
{
496
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
497
498
0
  if (proc->sep)
499
0
    fz_write_byte(ctx, proc->out, ' ');
500
0
  fz_write_printf(ctx, proc->out, "%g TL", leading);
501
0
  post_op(ctx, proc);
502
0
}
503
504
static void
505
pdf_out_Tf(fz_context *ctx, pdf_processor *proc_, const char *name, pdf_font_desc *font, float size)
506
0
{
507
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
508
509
0
  if (proc->extgstate != 0)
510
0
    return;
511
512
0
  fz_write_printf(ctx, proc->out, "%n %g Tf", name, size);
513
0
  post_op(ctx, proc);
514
0
}
515
516
static void
517
pdf_out_Tr(fz_context *ctx, pdf_processor *proc_, int render)
518
0
{
519
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
520
521
0
  if (proc->sep)
522
0
    fz_write_byte(ctx, proc->out, ' ');
523
0
  fz_write_printf(ctx, proc->out, "%d Tr", render);
524
0
  post_op(ctx, proc);
525
0
}
526
527
static void
528
pdf_out_Ts(fz_context *ctx, pdf_processor *proc_, float rise)
529
0
{
530
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
531
532
0
  if (proc->sep)
533
0
    fz_write_byte(ctx, proc->out, ' ');
534
0
  fz_write_printf(ctx, proc->out, "%g Ts", rise);
535
0
  post_op(ctx, proc);
536
0
}
537
538
/* text positioning */
539
540
static void
541
pdf_out_Td(fz_context *ctx, pdf_processor *proc_, float tx, float ty)
542
0
{
543
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
544
545
0
  if (proc->sep)
546
0
    fz_write_byte(ctx, proc->out, ' ');
547
0
  fz_write_printf(ctx, proc->out, "%g %g Td", tx, ty);
548
0
  post_op(ctx, proc);
549
0
}
550
551
static void
552
pdf_out_TD(fz_context *ctx, pdf_processor *proc_, float tx, float ty)
553
0
{
554
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
555
556
0
  if (proc->sep)
557
0
    fz_write_byte(ctx, proc->out, ' ');
558
0
  fz_write_printf(ctx, proc->out, "%g %g TD", tx, ty);
559
0
  post_op(ctx, proc);
560
0
}
561
562
static void
563
pdf_out_Tm(fz_context *ctx, pdf_processor *proc_, float a, float b, float c, float d, float e, float f)
564
0
{
565
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
566
567
0
  if (proc->sep)
568
0
    fz_write_byte(ctx, proc->out, ' ');
569
0
  fz_write_printf(ctx, proc->out, "%g %g %g %g %g %g Tm", a, b, c, d, e, f);
570
0
  post_op(ctx, proc);
571
0
}
572
573
static void
574
pdf_out_Tstar(fz_context *ctx, pdf_processor *proc_)
575
0
{
576
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
577
578
0
  if (proc->sep)
579
0
    fz_write_byte(ctx, proc->out, ' ');
580
0
  fz_write_string(ctx, proc->out, "T*");
581
0
  post_op(ctx, proc);
582
0
}
583
584
/* text showing */
585
586
static void
587
fz_write_pdf_string(fz_context *ctx, fz_output *out, const unsigned char *str, size_t len)
588
0
{
589
0
  size_t i;
590
591
0
  for (i = 0; i < len; ++i)
592
0
    if (str[i] < 32 || str[i] >= 127)
593
0
      break;
594
595
0
  if (i < len)
596
0
  {
597
0
    fz_write_byte(ctx, out, '<');
598
0
    for (i = 0; i < len; ++i)
599
0
    {
600
0
      unsigned char c = str[i];
601
0
      fz_write_byte(ctx, out, "0123456789abcdef"[(c>>4)&15]);
602
0
      fz_write_byte(ctx, out, "0123456789abcdef"[(c)&15]);
603
0
    }
604
0
    fz_write_byte(ctx, out, '>');
605
0
  }
606
0
  else
607
0
  {
608
0
    fz_write_byte(ctx, out, '(');
609
0
    for (i = 0; i < len; ++i)
610
0
    {
611
0
      unsigned char c = str[i];
612
0
      if (c == '(' || c == ')' || c == '\\')
613
0
        fz_write_byte(ctx, out, '\\');
614
0
      fz_write_byte(ctx, out, c);
615
0
    }
616
0
    fz_write_byte(ctx, out, ')');
617
0
  }
618
0
}
619
620
static void
621
pdf_out_TJ(fz_context *ctx, pdf_processor *proc_, pdf_obj *array)
622
0
{
623
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
624
0
  int ahx = proc->ahxencode;
625
626
0
  pdf_print_encrypted_obj(ctx, proc->out, array, 1, ahx, NULL, 0, 0, &proc->sep);
627
0
  if (proc->sep)
628
0
    fz_write_byte(ctx, proc->out, ' ');
629
0
  fz_write_string(ctx, proc->out, "TJ");
630
0
  post_op(ctx, proc);
631
0
}
632
633
static void
634
pdf_out_Tj(fz_context *ctx, pdf_processor *proc_, char *str, size_t len)
635
0
{
636
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
637
638
0
  fz_write_pdf_string(ctx, proc->out, (const unsigned char *)str, len);
639
0
  fz_write_string(ctx, proc->out, "Tj");
640
0
  post_op(ctx, proc);
641
0
}
642
643
static void
644
pdf_out_squote(fz_context *ctx, pdf_processor *proc_, char *str, size_t len)
645
0
{
646
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
647
648
0
  fz_write_pdf_string(ctx, proc->out, (const unsigned char *)str, len);
649
0
  fz_write_string(ctx, proc->out, "'");
650
0
  post_op(ctx, proc);
651
0
}
652
653
static void
654
pdf_out_dquote(fz_context *ctx, pdf_processor *proc_, float aw, float ac, char *str, size_t len)
655
0
{
656
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
657
658
0
  if (proc->sep)
659
0
    fz_write_byte(ctx, proc->out, ' ');
660
0
  fz_write_printf(ctx, proc->out, "%g %g ", aw, ac);
661
0
  fz_write_pdf_string(ctx, proc->out, (const unsigned char *)str, len);
662
0
  fz_write_string(ctx, proc->out, "\"");
663
0
  post_op(ctx, proc);
664
0
}
665
666
/* type 3 fonts */
667
668
static void
669
pdf_out_d0(fz_context *ctx, pdf_processor *proc_, float wx, float wy)
670
0
{
671
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
672
673
0
  if (proc->sep)
674
0
    fz_write_byte(ctx, proc->out, ' ');
675
0
  fz_write_printf(ctx, proc->out, "%g %g d0", wx, wy);
676
0
  post_op(ctx, proc);
677
0
}
678
679
static void
680
pdf_out_d1(fz_context *ctx, pdf_processor *proc_, float wx, float wy, float llx, float lly, float urx, float ury)
681
0
{
682
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
683
684
0
  if (proc->sep)
685
0
    fz_write_byte(ctx, proc->out, ' ');
686
0
  fz_write_printf(ctx, proc->out, "%g %g %g %g %g %g d1", wx, wy, llx, lly, urx, ury);
687
0
  post_op(ctx, proc);
688
0
}
689
690
/* color */
691
692
static void
693
pdf_out_CS(fz_context *ctx, pdf_processor *proc_, const char *name, fz_colorspace *cs)
694
0
{
695
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
696
697
0
  fz_write_printf(ctx, proc->out, "%n CS", name);
698
0
  post_op(ctx, proc);
699
0
}
700
701
static void
702
pdf_out_cs(fz_context *ctx, pdf_processor *proc_, const char *name, fz_colorspace *cs)
703
0
{
704
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
705
706
0
  fz_write_printf(ctx, proc->out, "%n cs", name);
707
0
  post_op(ctx, proc);
708
0
}
709
710
static void
711
pdf_out_SC_pattern(fz_context *ctx, pdf_processor *proc_, const char *name, pdf_pattern *pat, int n, float *color)
712
0
{
713
0
  int i;
714
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
715
716
0
  if (proc->sep)
717
0
    fz_write_byte(ctx, proc->out, ' ');
718
0
  for (i = 0; i < n; ++i)
719
0
    fz_write_printf(ctx, proc->out, "%g ", color[i]);
720
0
  fz_write_printf(ctx, proc->out, "%n SCN", name);
721
0
  post_op(ctx, proc);
722
0
}
723
724
static void
725
pdf_out_sc_pattern(fz_context *ctx, pdf_processor *proc_, const char *name, pdf_pattern *pat, int n, float *color)
726
0
{
727
0
  int i;
728
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
729
730
0
  if (proc->sep)
731
0
    fz_write_byte(ctx, proc->out, ' ');
732
0
  for (i = 0; i < n; ++i)
733
0
    fz_write_printf(ctx, proc->out, "%g ", color[i]);
734
0
  fz_write_printf(ctx, proc->out, "%n scn", name);
735
0
  post_op(ctx, proc);
736
0
}
737
738
static void
739
pdf_out_SC_shade(fz_context *ctx, pdf_processor *proc_, const char *name, fz_shade *shade)
740
0
{
741
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
742
743
0
  fz_write_printf(ctx, proc->out, "%n SCN", name);
744
0
  post_op(ctx, proc);
745
0
}
746
747
static void
748
pdf_out_sc_shade(fz_context *ctx, pdf_processor *proc_, const char *name, fz_shade *shade)
749
0
{
750
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
751
752
0
  fz_write_printf(ctx, proc->out, "%n scn", name);
753
0
  post_op(ctx, proc);
754
0
}
755
756
static void
757
pdf_out_SC_color(fz_context *ctx, pdf_processor *proc_, int n, float *color)
758
0
{
759
0
  int i;
760
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
761
762
0
  if (proc->sep)
763
0
    fz_write_byte(ctx, proc->out, ' ');
764
0
  for (i = 0; i < n; ++i)
765
0
    fz_write_printf(ctx, proc->out, "%g ", color[i]);
766
0
  fz_write_string(ctx, proc->out, "SCN");
767
0
  post_op(ctx, proc);
768
0
}
769
770
static void
771
pdf_out_sc_color(fz_context *ctx, pdf_processor *proc_, int n, float *color)
772
0
{
773
0
  int i;
774
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
775
776
0
  if (proc->sep)
777
0
    fz_write_byte(ctx, proc->out, ' ');
778
0
  for (i = 0; i < n; ++i)
779
0
    fz_write_printf(ctx, proc->out, "%g ", color[i]);
780
0
  fz_write_string(ctx, proc->out, "scn");
781
0
  post_op(ctx, proc);
782
0
}
783
784
static void
785
pdf_out_G(fz_context *ctx, pdf_processor *proc_, float g)
786
0
{
787
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
788
789
0
  if (proc->sep)
790
0
    fz_write_byte(ctx, proc->out, ' ');
791
0
  fz_write_printf(ctx, proc->out, "%g G", g);
792
0
  post_op(ctx, proc);
793
0
}
794
795
static void
796
pdf_out_g(fz_context *ctx, pdf_processor *proc_, float g)
797
0
{
798
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
799
800
0
  if (proc->sep)
801
0
    fz_write_byte(ctx, proc->out, ' ');
802
0
  fz_write_printf(ctx, proc->out, "%g g", g);
803
0
  post_op(ctx, proc);
804
0
}
805
806
static void
807
pdf_out_RG(fz_context *ctx, pdf_processor *proc_, float r, float g, float b)
808
0
{
809
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
810
811
0
  if (proc->sep)
812
0
    fz_write_byte(ctx, proc->out, ' ');
813
0
  fz_write_printf(ctx, proc->out, "%g %g %g RG", r, g, b);
814
0
  post_op(ctx, proc);
815
0
}
816
817
static void
818
pdf_out_rg(fz_context *ctx, pdf_processor *proc_, float r, float g, float b)
819
0
{
820
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
821
822
0
  if (proc->sep)
823
0
    fz_write_byte(ctx, proc->out, ' ');
824
0
  fz_write_printf(ctx, proc->out, "%g %g %g rg", r, g, b);
825
0
  post_op(ctx, proc);
826
0
}
827
828
static void
829
pdf_out_K(fz_context *ctx, pdf_processor *proc_, float c, float m, float y, float k)
830
0
{
831
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
832
833
0
  if (proc->sep)
834
0
    fz_write_byte(ctx, proc->out, ' ');
835
0
  fz_write_printf(ctx, proc->out, "%g %g %g %g K", c, m, y, k);
836
0
  post_op(ctx, proc);
837
0
}
838
839
static void
840
pdf_out_k(fz_context *ctx, pdf_processor *proc_, float c, float m, float y, float k)
841
0
{
842
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
843
844
0
  if (proc->sep)
845
0
    fz_write_byte(ctx, proc->out, ' ');
846
0
  fz_write_printf(ctx, proc->out, "%g %g %g %g k", c, m, y, k);
847
0
  post_op(ctx, proc);
848
0
}
849
850
/* shadings, images, xobjects */
851
852
static void
853
pdf_out_BI(fz_context *ctx, pdf_processor *proc_, fz_image *img, const char *colorspace)
854
0
{
855
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
856
0
  fz_output *out = proc->out;
857
0
  int ahx = proc->ahxencode;
858
0
  fz_compressed_buffer *cbuf;
859
0
  fz_buffer *buf = NULL;
860
0
  int i, w, h, bpc;
861
0
  unsigned char *data;
862
0
  size_t len;
863
0
  fz_pixmap *pix = NULL;
864
0
  fz_colorspace *cs;
865
0
  int type;
866
867
0
  if (img == NULL)
868
0
    return;
869
0
  cbuf = fz_compressed_image_buffer(ctx, img);
870
0
  if (cbuf == NULL)
871
0
  {
872
0
    pix = fz_get_pixmap_from_image(ctx, img, NULL, NULL, &w, &h);
873
0
    bpc = 8;
874
0
    cs = pix->colorspace;
875
0
    type = FZ_IMAGE_RAW;
876
0
  }
877
0
  else
878
0
  {
879
0
    buf = cbuf->buffer;
880
0
    if (buf == NULL)
881
0
      return;
882
0
    w = img->w;
883
0
    h = img->h;
884
0
    bpc = img->bpc;
885
0
    cs = img->colorspace;
886
0
    type = cbuf->params.type;
887
0
  }
888
889
0
  fz_try(ctx)
890
0
  {
891
0
    if (proc->sep)
892
0
      fz_write_byte(ctx, out, ' ');
893
0
    fz_write_string(ctx, out, "BI ");
894
0
    fz_write_printf(ctx, out, "/W %d", w);
895
0
    fz_write_printf(ctx, out, "/H %d", h);
896
0
    fz_write_printf(ctx, out, "/BPC %d", bpc);
897
0
    if (img->imagemask)
898
0
      fz_write_string(ctx, out, "/IM true");
899
0
    else if (cs == fz_device_gray(ctx))
900
0
      fz_write_string(ctx, out, "/CS/G");
901
0
    else if (cs == fz_device_rgb(ctx))
902
0
      fz_write_string(ctx, out, "/CS/RGB");
903
0
    else if (cs == fz_device_cmyk(ctx))
904
0
      fz_write_string(ctx, out, "/CS/CMYK");
905
0
    else if (cs)
906
0
      fz_write_printf(ctx, out, "/CS%n", colorspace);
907
0
    else
908
0
      fz_throw(ctx, FZ_ERROR_ARGUMENT, "BI operator can only show ImageMask, Gray, RGB, or CMYK images");
909
0
    if (img->interpolate)
910
0
      fz_write_string(ctx, out, "/I true");
911
0
    fz_write_string(ctx, out, "/D[");
912
0
    for (i = 0; i < img->n * 2; ++i)
913
0
    {
914
0
      if (i > 0)
915
0
        fz_write_byte(ctx, out, ' ');
916
0
      fz_write_printf(ctx, out, "%g", img->decode[i]);
917
0
    }
918
0
    fz_write_string(ctx, out, "]");
919
0
    proc->sep = 0;
920
921
0
    switch (type)
922
0
    {
923
0
    default:
924
0
      fz_throw(ctx, FZ_ERROR_ARGUMENT, "unknown compressed buffer type");
925
0
      break;
926
927
0
    case FZ_IMAGE_JPEG:
928
0
      fz_write_string(ctx, out, ahx ? "/F[/AHx/DCT]" : "/F/DCT");
929
0
      proc->sep = !ahx;
930
0
      if (cbuf->params.u.jpeg.color_transform >= 0)
931
0
      {
932
0
        fz_write_printf(ctx, out, "/DP<</ColorTransform %d>>", cbuf->params.u.jpeg.color_transform);
933
0
        proc->sep = 0;
934
0
      }
935
0
      if (cbuf->params.u.jpeg.invert_cmyk && img->n == 4)
936
0
      {
937
0
        fz_write_string(ctx, out, "/D[1 0 1 0 1 0 1 0]");
938
0
        proc->sep = 0;
939
0
      }
940
0
      break;
941
942
0
    case FZ_IMAGE_FAX:
943
0
      fz_write_string(ctx, out, ahx ? "/F[/AHx/CCF]/DP[null<<" : "/F/CCF/DP<<");
944
0
      fz_write_printf(ctx, out, "/K %d", cbuf->params.u.fax.k);
945
0
      if (cbuf->params.u.fax.columns != 1728)
946
0
        fz_write_printf(ctx, out, "/Columns %d", cbuf->params.u.fax.columns);
947
0
      if (cbuf->params.u.fax.rows > 0)
948
0
        fz_write_printf(ctx, out, "/Rows %d", cbuf->params.u.fax.rows);
949
0
      if (cbuf->params.u.fax.end_of_line)
950
0
        fz_write_string(ctx, out, "/EndOfLine true");
951
0
      if (cbuf->params.u.fax.encoded_byte_align)
952
0
        fz_write_string(ctx, out, "/EncodedByteAlign true");
953
0
      if (!cbuf->params.u.fax.end_of_block)
954
0
        fz_write_string(ctx, out, "/EndOfBlock false");
955
0
      if (cbuf->params.u.fax.black_is_1)
956
0
        fz_write_string(ctx, out, "/BlackIs1 true");
957
0
      if (cbuf->params.u.fax.damaged_rows_before_error > 0)
958
0
        fz_write_printf(ctx, out, "/DamagedRowsBeforeError %d",
959
0
          cbuf->params.u.fax.damaged_rows_before_error);
960
0
      fz_write_string(ctx, out, ahx ? ">>]" : ">>");
961
0
      proc->sep = 0;
962
0
      break;
963
964
0
    case FZ_IMAGE_RAW:
965
0
      if (ahx)
966
0
      {
967
0
        fz_write_string(ctx, out, "/F/AHx");
968
0
        proc->sep = 1;
969
0
      }
970
0
      break;
971
972
0
    case FZ_IMAGE_RLD:
973
0
      fz_write_string(ctx, out, ahx ? "/F[/AHx/RL]" : "/F/RL");
974
0
      proc->sep = !ahx;
975
0
      break;
976
977
0
    case FZ_IMAGE_FLATE:
978
0
      fz_write_string(ctx, out, ahx ? "/F[/AHx/Fl]" : "/F/Fl");
979
0
      proc->sep = !ahx;
980
0
      if (cbuf->params.u.flate.predictor > 1)
981
0
      {
982
0
        fz_write_string(ctx, out, ahx ? "/DP[null<<" : "/DP<<");
983
0
        fz_write_printf(ctx, out, "/Predictor %d", cbuf->params.u.flate.predictor);
984
0
        if (cbuf->params.u.flate.columns != 1)
985
0
          fz_write_printf(ctx, out, "/Columns %d", cbuf->params.u.flate.columns);
986
0
        if (cbuf->params.u.flate.colors != 1)
987
0
          fz_write_printf(ctx, out, "/Colors %d", cbuf->params.u.flate.colors);
988
0
        if (cbuf->params.u.flate.bpc != 8)
989
0
          fz_write_printf(ctx, out, "/BitsPerComponent %d", cbuf->params.u.flate.bpc);
990
0
        fz_write_string(ctx, out, ahx ? ">>]" : ">>");
991
0
        proc->sep = 0;
992
0
      }
993
0
      break;
994
995
0
    case FZ_IMAGE_LZW:
996
0
      fz_write_string(ctx, out, ahx ? "/F[/AHx/LZW]" : "/F/LZW");
997
0
      proc->sep = !ahx;
998
0
      if (cbuf->params.u.lzw.predictor > 1)
999
0
      {
1000
0
        fz_write_string(ctx, out, ahx ? "/DP[<<null" : "/DP<<");
1001
0
        fz_write_printf(ctx, out, "/Predictor %d", cbuf->params.u.lzw.predictor);
1002
0
        if (cbuf->params.u.lzw.columns != 1)
1003
0
          fz_write_printf(ctx, out, "/Columns %d", cbuf->params.u.lzw.columns);
1004
0
        if (cbuf->params.u.lzw.colors != 1)
1005
0
          fz_write_printf(ctx, out, "/Colors %d", cbuf->params.u.lzw.colors);
1006
0
        if (cbuf->params.u.lzw.bpc != 8)
1007
0
          fz_write_printf(ctx, out, "/BitsPerComponent %d", cbuf->params.u.lzw.bpc);
1008
0
        if (cbuf->params.u.lzw.early_change != 1)
1009
0
          fz_write_printf(ctx, out, "/EarlyChange %d", cbuf->params.u.lzw.early_change);
1010
0
        fz_write_string(ctx, out, ahx ? ">>]" : ">>");
1011
0
        proc->sep = 0;
1012
0
      }
1013
0
      break;
1014
0
    }
1015
1016
0
    if (proc->sep)
1017
0
      fz_write_byte(ctx, out, ' ');
1018
0
    fz_write_string(ctx, out, "ID ");
1019
0
    if (buf)
1020
0
      len = fz_buffer_storage(ctx, buf, &data);
1021
0
    else
1022
0
    {
1023
0
      data = pix->samples;
1024
0
      len = ((size_t)w) * h * pix->n;
1025
0
    }
1026
0
    if (ahx)
1027
0
    {
1028
0
      size_t z;
1029
0
      for (z = 0; z < len; ++z)
1030
0
      {
1031
0
        int c = data[z];
1032
0
        fz_write_byte(ctx, out, "0123456789abcdef"[(c >> 4) & 0xf]);
1033
0
        fz_write_byte(ctx, out, "0123456789abcdef"[c & 0xf]);
1034
0
        if ((z & 31) == 31)
1035
0
          fz_write_byte(ctx, out, '\n');
1036
0
      }
1037
0
      fz_write_byte(ctx, out, '>');
1038
0
    }
1039
0
    else
1040
0
    {
1041
0
      fz_write_data(ctx, out, data, len);
1042
0
    }
1043
0
    fz_write_string(ctx, out, " EI");
1044
0
    proc->sep = 1;
1045
0
  }
1046
0
  fz_always(ctx)
1047
0
    fz_drop_pixmap(ctx, pix);
1048
0
  fz_catch(ctx)
1049
0
    fz_rethrow(ctx);
1050
0
}
1051
1052
static void
1053
pdf_out_sh(fz_context *ctx, pdf_processor *proc_, const char *name, fz_shade *shade)
1054
0
{
1055
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
1056
1057
0
  fz_write_printf(ctx, proc->out, "%n sh", name);
1058
0
  post_op(ctx, proc);
1059
0
}
1060
1061
static void
1062
pdf_out_Do_image(fz_context *ctx, pdf_processor *proc_, const char *name, fz_image *image)
1063
0
{
1064
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
1065
1066
0
  fz_write_printf(ctx, proc->out, "%n Do", name);
1067
0
  post_op(ctx, proc);
1068
0
}
1069
1070
static void
1071
pdf_out_Do_form(fz_context *ctx, pdf_processor *proc_, const char *name, pdf_obj *xobj)
1072
0
{
1073
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
1074
1075
0
  fz_write_printf(ctx, proc->out, "%n Do", name);
1076
0
  post_op(ctx, proc);
1077
0
}
1078
1079
/* marked content */
1080
1081
static void
1082
pdf_out_MP(fz_context *ctx, pdf_processor *proc_, const char *tag)
1083
0
{
1084
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
1085
1086
0
  fz_write_printf(ctx, proc->out, "%n MP", tag);
1087
0
  post_op(ctx, proc);
1088
0
}
1089
1090
static void
1091
pdf_out_DP(fz_context *ctx, pdf_processor *proc_, const char *tag, pdf_obj *raw, pdf_obj *cooked)
1092
0
{
1093
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
1094
0
  int ahx = proc->ahxencode;
1095
1096
0
  fz_write_printf(ctx, proc->out, "%n", tag);
1097
0
  proc->sep = 1;
1098
0
  pdf_print_encrypted_obj(ctx, proc->out, raw, 1, ahx, NULL, 0, 0, &proc->sep);
1099
0
  if (proc->sep)
1100
0
    fz_write_byte(ctx, proc->out, ' ');
1101
0
  fz_write_string(ctx, proc->out, "DP");
1102
0
  post_op(ctx, proc);
1103
0
}
1104
1105
static void
1106
pdf_out_BMC(fz_context *ctx, pdf_processor *proc_, const char *tag)
1107
0
{
1108
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
1109
1110
0
  fz_write_printf(ctx, proc->out, "%n BMC", tag);
1111
0
  post_op(ctx, proc);
1112
0
}
1113
1114
static void
1115
pdf_out_BDC(fz_context *ctx, pdf_processor *proc_, const char *tag, pdf_obj *raw, pdf_obj *cooked)
1116
0
{
1117
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
1118
0
  int ahx = proc->ahxencode;
1119
1120
0
  fz_write_printf(ctx, proc->out, "%n", tag);
1121
0
  proc->sep = 1;
1122
0
  pdf_print_encrypted_obj(ctx, proc->out, raw, 1, ahx, NULL, 0, 0, &proc->sep);
1123
0
  if (proc->sep)
1124
0
    fz_write_byte(ctx, proc->out, ' ');
1125
0
  fz_write_string(ctx, proc->out, "BDC");
1126
0
  post_op(ctx, proc);
1127
0
}
1128
1129
static void
1130
pdf_out_EMC(fz_context *ctx, pdf_processor *proc_)
1131
0
{
1132
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
1133
1134
0
  if (proc->sep)
1135
0
    fz_write_byte(ctx, proc->out, ' ');
1136
0
  fz_write_string(ctx, proc->out, "EMC");
1137
0
  post_op(ctx, proc);
1138
0
}
1139
1140
/* compatibility */
1141
1142
static void
1143
pdf_out_BX(fz_context *ctx, pdf_processor *proc_)
1144
0
{
1145
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
1146
1147
0
  if (proc->sep)
1148
0
    fz_write_byte(ctx, proc->out, ' ');
1149
0
  fz_write_string(ctx, proc->out, "BX");
1150
0
  post_op(ctx, proc);
1151
0
}
1152
1153
static void
1154
pdf_out_EX(fz_context *ctx, pdf_processor *proc_)
1155
0
{
1156
0
  pdf_output_processor *proc = (pdf_output_processor *)proc_;
1157
1158
0
  if (proc->sep)
1159
0
    fz_write_byte(ctx, proc->out, ' ');
1160
0
  fz_write_string(ctx, proc->out, "EX");
1161
0
  post_op(ctx, proc);
1162
0
}
1163
1164
static void
1165
pdf_close_output_processor(fz_context *ctx, pdf_processor *proc_)
1166
0
{
1167
0
  pdf_output_processor *proc = (pdf_output_processor*)proc_;
1168
0
  fz_output *out = proc->out;
1169
1170
  /* Add missing 'Q' operators to get back to zero. */
1171
  /* We can't prepend missing 'q' operators to guarantee we don't underflow. */
1172
0
  while (proc->balance > 0)
1173
0
  {
1174
0
    proc->balance--;
1175
0
    if (proc->sep)
1176
0
      fz_write_byte(ctx, proc->out, ' ');
1177
0
    fz_write_byte(ctx, out, 'Q');
1178
0
    post_op(ctx, proc);
1179
0
  }
1180
1181
0
  fz_close_output(ctx, out);
1182
0
}
1183
1184
static void
1185
pdf_drop_output_processor(fz_context *ctx, pdf_processor *proc)
1186
0
{
1187
0
  pdf_output_processor *p = (pdf_output_processor *)proc;
1188
1189
0
  fz_drop_output(ctx, p->out);
1190
0
}
1191
1192
static void
1193
pdf_reset_output_processor(fz_context *ctx, pdf_processor *proc)
1194
0
{
1195
0
  pdf_output_processor *p = (pdf_output_processor *)proc;
1196
1197
0
  fz_reset_output(ctx, p->out);
1198
0
}
1199
1200
static void
1201
pdf_out_push_resources(fz_context *ctx, pdf_processor *proc, pdf_obj *res)
1202
0
{
1203
0
  pdf_output_processor *p = (pdf_output_processor *)proc;
1204
0
  resources_stack *stk = fz_malloc_struct(ctx, resources_stack);
1205
1206
0
  stk->next = p->rstack;
1207
0
  p->rstack = stk;
1208
0
  stk->res = pdf_keep_obj(ctx, res);
1209
0
}
1210
1211
static pdf_obj *
1212
pdf_out_pop_resources(fz_context *ctx, pdf_processor *proc)
1213
0
{
1214
0
  pdf_output_processor *p = (pdf_output_processor *)proc;
1215
0
  resources_stack *stk = p->rstack;
1216
0
  pdf_obj *res = stk->res;
1217
1218
0
  p->rstack = stk->next;
1219
0
  fz_free(ctx, stk);
1220
1221
0
  return res;
1222
0
}
1223
1224
pdf_processor *
1225
pdf_new_output_processor(fz_context *ctx, fz_output *out, int ahxencode, int newlines)
1226
0
{
1227
0
  pdf_output_processor *proc = pdf_new_processor(ctx, sizeof *proc);
1228
1229
0
  proc->super.close_processor = pdf_close_output_processor;
1230
0
  proc->super.drop_processor = pdf_drop_output_processor;
1231
0
  proc->super.reset_processor = pdf_reset_output_processor;
1232
1233
0
  proc->super.push_resources = pdf_out_push_resources;
1234
0
  proc->super.pop_resources = pdf_out_pop_resources;
1235
1236
  /* general graphics state */
1237
0
  proc->super.op_w = pdf_out_w;
1238
0
  proc->super.op_j = pdf_out_j;
1239
0
  proc->super.op_J = pdf_out_J;
1240
0
  proc->super.op_M = pdf_out_M;
1241
0
  proc->super.op_d = pdf_out_d;
1242
0
  proc->super.op_ri = pdf_out_ri;
1243
0
  proc->super.op_i = pdf_out_i;
1244
0
  proc->super.op_gs_begin = pdf_out_gs_begin;
1245
0
  proc->super.op_gs_end = pdf_out_gs_end;
1246
1247
  /* transparency graphics state */
1248
0
  proc->super.op_gs_BM = NULL;
1249
0
  proc->super.op_gs_CA = NULL;
1250
0
  proc->super.op_gs_ca = NULL;
1251
0
  proc->super.op_gs_SMask = NULL;
1252
1253
  /* special graphics state */
1254
0
  proc->super.op_q = pdf_out_q;
1255
0
  proc->super.op_Q = pdf_out_Q;
1256
0
  proc->super.op_cm = pdf_out_cm;
1257
1258
  /* path construction */
1259
0
  proc->super.op_m = pdf_out_m;
1260
0
  proc->super.op_l = pdf_out_l;
1261
0
  proc->super.op_c = pdf_out_c;
1262
0
  proc->super.op_v = pdf_out_v;
1263
0
  proc->super.op_y = pdf_out_y;
1264
0
  proc->super.op_h = pdf_out_h;
1265
0
  proc->super.op_re = pdf_out_re;
1266
1267
  /* path painting */
1268
0
  proc->super.op_S = pdf_out_S;
1269
0
  proc->super.op_s = pdf_out_s;
1270
0
  proc->super.op_F = pdf_out_F;
1271
0
  proc->super.op_f = pdf_out_f;
1272
0
  proc->super.op_fstar = pdf_out_fstar;
1273
0
  proc->super.op_B = pdf_out_B;
1274
0
  proc->super.op_Bstar = pdf_out_Bstar;
1275
0
  proc->super.op_b = pdf_out_b;
1276
0
  proc->super.op_bstar = pdf_out_bstar;
1277
0
  proc->super.op_n = pdf_out_n;
1278
1279
  /* clipping paths */
1280
0
  proc->super.op_W = pdf_out_W;
1281
0
  proc->super.op_Wstar = pdf_out_Wstar;
1282
1283
  /* text objects */
1284
0
  proc->super.op_BT = pdf_out_BT;
1285
0
  proc->super.op_ET = pdf_out_ET;
1286
1287
  /* text state */
1288
0
  proc->super.op_Tc = pdf_out_Tc;
1289
0
  proc->super.op_Tw = pdf_out_Tw;
1290
0
  proc->super.op_Tz = pdf_out_Tz;
1291
0
  proc->super.op_TL = pdf_out_TL;
1292
0
  proc->super.op_Tf = pdf_out_Tf;
1293
0
  proc->super.op_Tr = pdf_out_Tr;
1294
0
  proc->super.op_Ts = pdf_out_Ts;
1295
1296
  /* text positioning */
1297
0
  proc->super.op_Td = pdf_out_Td;
1298
0
  proc->super.op_TD = pdf_out_TD;
1299
0
  proc->super.op_Tm = pdf_out_Tm;
1300
0
  proc->super.op_Tstar = pdf_out_Tstar;
1301
1302
  /* text showing */
1303
0
  proc->super.op_TJ = pdf_out_TJ;
1304
0
  proc->super.op_Tj = pdf_out_Tj;
1305
0
  proc->super.op_squote = pdf_out_squote;
1306
0
  proc->super.op_dquote = pdf_out_dquote;
1307
1308
  /* type 3 fonts */
1309
0
  proc->super.op_d0 = pdf_out_d0;
1310
0
  proc->super.op_d1 = pdf_out_d1;
1311
1312
  /* color */
1313
0
  proc->super.op_CS = pdf_out_CS;
1314
0
  proc->super.op_cs = pdf_out_cs;
1315
0
  proc->super.op_SC_color = pdf_out_SC_color;
1316
0
  proc->super.op_sc_color = pdf_out_sc_color;
1317
0
  proc->super.op_SC_pattern = pdf_out_SC_pattern;
1318
0
  proc->super.op_sc_pattern = pdf_out_sc_pattern;
1319
0
  proc->super.op_SC_shade = pdf_out_SC_shade;
1320
0
  proc->super.op_sc_shade = pdf_out_sc_shade;
1321
1322
0
  proc->super.op_G = pdf_out_G;
1323
0
  proc->super.op_g = pdf_out_g;
1324
0
  proc->super.op_RG = pdf_out_RG;
1325
0
  proc->super.op_rg = pdf_out_rg;
1326
0
  proc->super.op_K = pdf_out_K;
1327
0
  proc->super.op_k = pdf_out_k;
1328
1329
  /* shadings, images, xobjects */
1330
0
  proc->super.op_BI = pdf_out_BI;
1331
0
  proc->super.op_sh = pdf_out_sh;
1332
0
  proc->super.op_Do_image = pdf_out_Do_image;
1333
0
  proc->super.op_Do_form = pdf_out_Do_form;
1334
1335
  /* marked content */
1336
0
  proc->super.op_MP = pdf_out_MP;
1337
0
  proc->super.op_DP = pdf_out_DP;
1338
0
  proc->super.op_BMC = pdf_out_BMC;
1339
0
  proc->super.op_BDC = pdf_out_BDC;
1340
0
  proc->super.op_EMC = pdf_out_EMC;
1341
1342
  /* compatibility */
1343
0
  proc->super.op_BX = pdf_out_BX;
1344
0
  proc->super.op_EX = pdf_out_EX;
1345
1346
  /* extgstate */
1347
0
  proc->super.op_gs_OP = NULL;
1348
0
  proc->super.op_gs_op = NULL;
1349
0
  proc->super.op_gs_OPM = NULL;
1350
0
  proc->super.op_gs_UseBlackPtComp = NULL;
1351
1352
0
  proc->out = out;
1353
0
  proc->ahxencode = ahxencode;
1354
0
  proc->newlines = newlines;
1355
1356
0
  proc->super.requirements = PDF_PROCESSOR_REQUIRES_DECODED_IMAGES;
1357
1358
0
  proc->balance = 0;
1359
1360
0
  return (pdf_processor*)proc;
1361
0
}
1362
1363
pdf_processor *
1364
pdf_new_buffer_processor(fz_context *ctx, fz_buffer *buffer, int ahxencode, int newlines)
1365
0
{
1366
0
  pdf_processor *proc = NULL;
1367
0
  fz_output *out = fz_new_output_with_buffer(ctx, buffer);
1368
0
  fz_try(ctx)
1369
0
  {
1370
0
    proc = pdf_new_output_processor(ctx, out, ahxencode, newlines);
1371
0
  }
1372
0
  fz_catch(ctx)
1373
0
  {
1374
0
    fz_drop_output(ctx, out);
1375
0
    fz_rethrow(ctx);
1376
0
  }
1377
0
  return proc;
1378
0
}
1379
1380
/* Simplified processor that only counts matching q/Q pairs. */
1381
1382
typedef struct
1383
{
1384
  pdf_processor super;
1385
  int *balance;
1386
  int *min_q;
1387
  int *min_op_q;
1388
  int first;
1389
} pdf_balance_processor;
1390
1391
static void
1392
pdf_balance_q(fz_context *ctx, pdf_processor *proc_)
1393
0
{
1394
0
  pdf_balance_processor *proc = (pdf_balance_processor*)proc_;
1395
0
  (*proc->balance)++;
1396
0
}
1397
1398
static void
1399
pdf_balance_Q(fz_context *ctx, pdf_processor *proc_)
1400
0
{
1401
0
  pdf_balance_processor *proc = (pdf_balance_processor*)proc_;
1402
0
  (*proc->balance)--;
1403
0
  if (*proc->balance < *proc->min_q)
1404
0
    *proc->min_q = *proc->balance;
1405
0
}
1406
1407
static void
1408
pdf_balance_void(fz_context *ctx, pdf_processor *proc_)
1409
0
{
1410
0
  pdf_balance_processor *proc = (pdf_balance_processor*)proc_;
1411
0
  if (*proc->balance < *proc->min_op_q)
1412
0
    *proc->min_op_q = *proc->balance;
1413
0
}
1414
1415
0
#define BALANCE { pdf_balance_void(ctx, p); }
Unexecuted instantiation: pdf-op-buffer.c:pdf_balance_float
Unexecuted instantiation: pdf-op-buffer.c:pdf_balance_int
Unexecuted instantiation: pdf-op-buffer.c:pdf_balance_d
Unexecuted instantiation: pdf-op-buffer.c:pdf_balance_string
Unexecuted instantiation: pdf-op-buffer.c:pdf_balance_gs_begin
Unexecuted instantiation: pdf-op-buffer.c:pdf_balance_float6
Unexecuted instantiation: pdf-op-buffer.c:pdf_balance_float2
Unexecuted instantiation: pdf-op-buffer.c:pdf_balance_float4
Unexecuted instantiation: pdf-op-buffer.c:pdf_balance_Tf
Unexecuted instantiation: pdf-op-buffer.c:pdf_balance_TJ
Unexecuted instantiation: pdf-op-buffer.c:pdf_balance_Tj
Unexecuted instantiation: pdf-op-buffer.c:pdf_balance_squote
Unexecuted instantiation: pdf-op-buffer.c:pdf_balance_dquote
Unexecuted instantiation: pdf-op-buffer.c:pdf_balance_cs
Unexecuted instantiation: pdf-op-buffer.c:pdf_balance_sc_color
Unexecuted instantiation: pdf-op-buffer.c:pdf_balance_sc_pattern
Unexecuted instantiation: pdf-op-buffer.c:pdf_balance_sc_shade
Unexecuted instantiation: pdf-op-buffer.c:pdf_balance_float3
Unexecuted instantiation: pdf-op-buffer.c:pdf_balance_BI
Unexecuted instantiation: pdf-op-buffer.c:pdf_balance_sh
Unexecuted instantiation: pdf-op-buffer.c:pdf_balance_Do_image
Unexecuted instantiation: pdf-op-buffer.c:pdf_balance_Do_form
Unexecuted instantiation: pdf-op-buffer.c:pdf_balance_BDC
1416
1417
static void pdf_balance_string(fz_context *ctx, pdf_processor *p, const char *x) BALANCE
1418
static void pdf_balance_int(fz_context *ctx, pdf_processor *p, int x) BALANCE
1419
static void pdf_balance_float(fz_context *ctx, pdf_processor *p, float x) BALANCE
1420
static void pdf_balance_float2(fz_context *ctx, pdf_processor *p, float x, float y) BALANCE
1421
static void pdf_balance_float3(fz_context *ctx, pdf_processor *p, float x, float y, float z) BALANCE
1422
static void pdf_balance_float4(fz_context *ctx, pdf_processor *p, float x, float y, float z, float w) BALANCE
1423
static void pdf_balance_float6(fz_context *ctx, pdf_processor *p, float a, float b, float c, float d, float e, float f) BALANCE
1424
1425
static void pdf_balance_d(fz_context *ctx, pdf_processor *p, pdf_obj *array, float phase) BALANCE
1426
static void pdf_balance_gs_begin(fz_context *ctx, pdf_processor *p, const char *name, pdf_obj *extgstate) BALANCE
1427
static void pdf_balance_Tf(fz_context *ctx, pdf_processor *p, const char *name, pdf_font_desc *font, float size) BALANCE
1428
static void pdf_balance_TJ(fz_context *ctx, pdf_processor *p, pdf_obj *array) BALANCE
1429
static void pdf_balance_Tj(fz_context *ctx, pdf_processor *p, char *str, size_t len) BALANCE
1430
static void pdf_balance_squote(fz_context *ctx, pdf_processor *p, char *str, size_t len) BALANCE
1431
static void pdf_balance_dquote(fz_context *ctx, pdf_processor *p, float aw, float ac, char *str, size_t len) BALANCE
1432
static void pdf_balance_cs(fz_context *ctx, pdf_processor *p, const char *name, fz_colorspace *cs) BALANCE
1433
static void pdf_balance_sc_pattern(fz_context *ctx, pdf_processor *p, const char *name, pdf_pattern *pat, int n, float *color) BALANCE
1434
static void pdf_balance_sc_shade(fz_context *ctx, pdf_processor *p, const char *name, fz_shade *shade) BALANCE
1435
static void pdf_balance_sc_color(fz_context *ctx, pdf_processor *p, int n, float *color) BALANCE
1436
static void pdf_balance_BDC(fz_context *ctx, pdf_processor *p, const char *tag, pdf_obj *raw, pdf_obj *cooked) BALANCE
1437
static void pdf_balance_BI(fz_context *ctx, pdf_processor *p, fz_image *img, const char *colorspace) BALANCE
1438
static void pdf_balance_sh(fz_context *ctx, pdf_processor *p, const char *name, fz_shade *shade) BALANCE
1439
static void pdf_balance_Do_image(fz_context *ctx, pdf_processor *p, const char *name, fz_image *image) BALANCE
1440
static void pdf_balance_Do_form(fz_context *ctx, pdf_processor *p, const char *name, pdf_obj *xobj) BALANCE
1441
1442
static pdf_processor *
1443
pdf_new_balance_processor(fz_context *ctx, int *balance, int *min_q, int *min_op_q)
1444
0
{
1445
0
  pdf_balance_processor *proc = pdf_new_processor(ctx, sizeof *proc);
1446
1447
0
  proc->super.op_q = pdf_balance_q;
1448
0
  proc->super.op_Q = pdf_balance_Q;
1449
1450
  /* general graphics state */
1451
0
  proc->super.op_w = pdf_balance_float;
1452
0
  proc->super.op_j = pdf_balance_int;
1453
0
  proc->super.op_J = pdf_balance_int;
1454
0
  proc->super.op_M = pdf_balance_float;
1455
0
  proc->super.op_d = pdf_balance_d;
1456
0
  proc->super.op_ri = pdf_balance_string;
1457
0
  proc->super.op_i = pdf_balance_float;
1458
0
  proc->super.op_gs_begin = pdf_balance_gs_begin;
1459
1460
  /* special graphics state */
1461
0
  proc->super.op_cm = pdf_balance_float6;
1462
1463
  /* path construction */
1464
0
  proc->super.op_m = pdf_balance_float2;
1465
0
  proc->super.op_l = pdf_balance_float2;
1466
0
  proc->super.op_c = pdf_balance_float6;
1467
0
  proc->super.op_v = pdf_balance_float4;
1468
0
  proc->super.op_y = pdf_balance_float4;
1469
0
  proc->super.op_h = pdf_balance_void;
1470
0
  proc->super.op_re = pdf_balance_float4;
1471
1472
  /* path painting */
1473
0
  proc->super.op_S = pdf_balance_void;
1474
0
  proc->super.op_s = pdf_balance_void;
1475
0
  proc->super.op_F = pdf_balance_void;
1476
0
  proc->super.op_f = pdf_balance_void;
1477
0
  proc->super.op_fstar = pdf_balance_void;
1478
0
  proc->super.op_B = pdf_balance_void;
1479
0
  proc->super.op_Bstar = pdf_balance_void;
1480
0
  proc->super.op_b = pdf_balance_void;
1481
0
  proc->super.op_bstar = pdf_balance_void;
1482
0
  proc->super.op_n = pdf_balance_void;
1483
1484
  /* clipping paths */
1485
0
  proc->super.op_W = pdf_balance_void;
1486
0
  proc->super.op_Wstar = pdf_balance_void;
1487
1488
  /* text objects */
1489
0
  proc->super.op_BT = pdf_balance_void;
1490
0
  proc->super.op_ET = pdf_balance_void;
1491
1492
  /* text state */
1493
0
  proc->super.op_Tc = pdf_balance_float;
1494
0
  proc->super.op_Tw = pdf_balance_float;
1495
0
  proc->super.op_Tz = pdf_balance_float;
1496
0
  proc->super.op_TL = pdf_balance_float;
1497
0
  proc->super.op_Tf = pdf_balance_Tf;
1498
0
  proc->super.op_Tr = pdf_balance_int;
1499
0
  proc->super.op_Ts = pdf_balance_float;
1500
1501
  /* text positioning */
1502
0
  proc->super.op_Td = pdf_balance_float2;
1503
0
  proc->super.op_TD = pdf_balance_float2;
1504
0
  proc->super.op_Tm = pdf_balance_float6;
1505
0
  proc->super.op_Tstar = pdf_balance_void;
1506
1507
  /* text showing */
1508
0
  proc->super.op_TJ = pdf_balance_TJ;
1509
0
  proc->super.op_Tj = pdf_balance_Tj;
1510
0
  proc->super.op_squote = pdf_balance_squote;
1511
0
  proc->super.op_dquote = pdf_balance_dquote;
1512
1513
  /* type 3 fonts */
1514
0
  proc->super.op_d0 = pdf_balance_float2;
1515
0
  proc->super.op_d1 = pdf_balance_float6;
1516
1517
  /* color */
1518
0
  proc->super.op_CS = pdf_balance_cs;
1519
0
  proc->super.op_cs = pdf_balance_cs;
1520
0
  proc->super.op_SC_color = pdf_balance_sc_color;
1521
0
  proc->super.op_sc_color = pdf_balance_sc_color;
1522
0
  proc->super.op_SC_pattern = pdf_balance_sc_pattern;
1523
0
  proc->super.op_sc_pattern = pdf_balance_sc_pattern;
1524
0
  proc->super.op_SC_shade = pdf_balance_sc_shade;
1525
0
  proc->super.op_sc_shade = pdf_balance_sc_shade;
1526
1527
0
  proc->super.op_G = pdf_balance_float;
1528
0
  proc->super.op_g = pdf_balance_float;
1529
0
  proc->super.op_RG = pdf_balance_float3;
1530
0
  proc->super.op_rg = pdf_balance_float3;
1531
0
  proc->super.op_K = pdf_balance_float4;
1532
0
  proc->super.op_k = pdf_balance_float4;
1533
1534
  /* shadings, images, xobjects */
1535
0
  proc->super.op_BI = pdf_balance_BI;
1536
0
  proc->super.op_sh = pdf_balance_sh;
1537
0
  proc->super.op_Do_image = pdf_balance_Do_image;
1538
0
  proc->super.op_Do_form = pdf_balance_Do_form;
1539
1540
  /* marked content */
1541
0
  proc->super.op_MP = pdf_balance_string;
1542
0
  proc->super.op_DP = pdf_balance_BDC;
1543
0
  proc->super.op_BMC = pdf_balance_string;
1544
0
  proc->super.op_BDC = pdf_balance_BDC;
1545
0
  proc->super.op_EMC = pdf_balance_void;
1546
1547
  /* compatibility */
1548
0
  proc->super.op_BX = pdf_balance_void;
1549
0
  proc->super.op_EX = pdf_balance_void;
1550
1551
0
  proc->balance = balance;
1552
0
  proc->min_q = min_q;
1553
0
  proc->min_op_q = min_op_q;
1554
1555
0
  return (pdf_processor*)proc;
1556
0
}
1557
1558
void
1559
pdf_count_q_balance(fz_context *ctx, pdf_document *doc, pdf_obj *res, pdf_obj *stm, int *prepend, int *append)
1560
0
{
1561
0
  pdf_processor *proc;
1562
1563
0
  int end_q = 0;
1564
0
  int min_q = 0;
1565
0
  int min_op_q = 1;
1566
1567
0
  proc = pdf_new_balance_processor(ctx, &end_q, &min_q, &min_op_q);
1568
0
  fz_try(ctx)
1569
0
  {
1570
0
    pdf_process_raw_contents(ctx, proc, doc, res, stm, NULL);
1571
0
    pdf_close_processor(ctx, proc);
1572
0
  }
1573
0
  fz_always(ctx)
1574
0
    pdf_drop_processor(ctx, proc);
1575
0
  fz_catch(ctx)
1576
0
    fz_rethrow(ctx);
1577
1578
  /* normally zero, but in bad files there could be more Q than q */
1579
0
  *prepend = -min_q;
1580
1581
  /* how many Q are missing at the end */
1582
0
  *append = end_q - min_q;
1583
1584
  /* if there are unguarded operators we must add one level of q/Q around everything */
1585
0
  if (min_op_q == min_q)
1586
0
  {
1587
0
    *prepend += 1;
1588
0
    *append += 1;
1589
0
  }
1590
0
}