comparison mupdf-source/source/tools/pdfaudit.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 // Copyright (C) 2023-2025 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 /*
24 * PDF auditing tool
25 */
26
27 #include "mupdf/fitz.h"
28 #include "mupdf/pdf.h"
29
30 #include <string.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33
34 #define SWITCH(x) switch ((intptr_t)(x))
35 #define CASE(x) case ((intptr_t)(x))
36
37 typedef enum
38 {
39 AUDIT_UNKNOWN = 0,
40 AUDIT_THUMBNAILS,
41 AUDIT_IMAGES,
42 AUDIT_BOOKMARKS,
43 AUDIT_PAGE_OBJECTS,
44 AUDIT_CONTENT_STREAMS,
45 AUDIT_FONTS,
46 AUDIT_STRUCTURE_INFO,
47 AUDIT_FORMS,
48 AUDIT_LINK_ANNOTATIONS,
49 AUDIT_COMMENTS,
50 AUDIT_3DCONTENT,
51 AUDIT_NAMED_DESTINATIONS,
52 //AUDIT_DOCUMENT_OVERHEAD, // FIXME
53 AUDIT_COLORSPACES,
54 AUDIT_FORM_XOBJ,
55 AUDIT_EXTGS,
56 AUDIT_PIECE_INFORMATION,
57 AUDIT_EMBEDDED_FILES,
58 AUDIT_TRAILER,
59 AUDIT_RESOURCES,
60 AUDIT_OBJSTM,
61 AUDIT_METADATA,
62 AUDIT__MAX
63 } audit_type_t;
64
65 const char *audit_type[] =
66 {
67 "UNKNOWN",
68 "THUMBNAILS",
69 "IMAGES",
70 "BOOKMARKS",
71 "PAGE OBJECTS",
72 "CONTENT_STREAMS",
73 "FONTS",
74 "STRUCTURE_INFO",
75 "FORMS",
76 "LINK_ANNOTATIONS",
77 "COMMENTS",
78 "3DCONTENT",
79 "NAMED_DESTINATIONS",
80 //"DOCUMENT_OVERHEAD",
81 "COLORSPACES",
82 "FORM_XOBJ",
83 "EXTGS",
84 "PIECE_INFORMATION",
85 "EMBEDDED_FILES",
86 "TRAILER",
87 "RESOURCES",
88 "OBJSTM",
89 "METADATA"
90 };
91
92 typedef struct
93 {
94 audit_type_t type;
95 int is_in_objstm;
96 /* The number of bytes this object will take in the file, not including any actual stream content. */
97 size_t textsize;
98 /* The number of bytes of overhead "1 0 R\nendobj\n" plus "stream\nendstream\n" */
99 size_t overhead;
100 /* Uncompressed stream size */
101 size_t len;
102 /* Compressed stream size (not including 'stream\nendstream\n) */
103 size_t stream_len;
104 } obj_info_t;
105
106 enum
107 {
108 OP_w = 0,
109 OP_j,
110 OP_J,
111 OP_M,
112 OP_d,
113 OP_ri,
114 OP_gs_OP,
115 OP_gs_op,
116 OP_gs_OPM,
117 OP_gs_UseBlackPtComp,
118 OP_i,
119 OP_gs_begin,
120 OP_gs_BM,
121 OP_gs_CA,
122 OP_gs_ca,
123 OP_gs_SMask,
124 OP_gs_end,
125 OP_q,
126 OP_cm,
127 OP_m,
128 OP_l,
129 OP_c,
130 OP_v,
131 OP_y,
132 OP_h,
133 OP_re,
134 OP_S,
135 OP_s,
136 OP_F,
137 OP_f,
138 OP_fstar,
139 OP_B,
140 OP_Bstar,
141 OP_b,
142 OP_bstar,
143 OP_n,
144 OP_W,
145 OP_Wstar,
146 OP_BT,
147 OP_ET,
148 OP_Q,
149 OP_Tc,
150 OP_Tw,
151 OP_Tz,
152 OP_TL,
153 OP_Tf,
154 OP_Tr,
155 OP_Ts,
156 OP_Td,
157 OP_TD,
158 OP_Tm,
159 OP_Tstar,
160 OP_TJ,
161 OP_Tj,
162 OP_squote,
163 OP_dquote,
164 OP_d0,
165 OP_d1,
166 OP_CS,
167 OP_cs,
168 OP_SC_pattern,
169 OP_sc_pattern,
170 OP_SC_shade,
171 OP_sc_shade,
172 OP_SC_color,
173 OP_sc_color,
174 OP_G,
175 OP_g,
176 OP_RG,
177 OP_rg,
178 OP_K,
179 OP_k,
180 OP_BI,
181 OP_sh,
182 OP_Do_image,
183 OP_Do_form,
184 OP_MP,
185 OP_DP,
186 OP_BMC,
187 OP_BDC,
188 OP_EMC,
189 OP_BX,
190 OP_EX,
191 OP_END
192 };
193
194 const char *op_names[] =
195 {
196 "w",
197 "j",
198 "J",
199 "M",
200 "d",
201 "ri",
202 "gs_OP",
203 "gs_op",
204 "gs_OPM",
205 "gs_UseBlackPtComp",
206 "i",
207 "gs_begin",
208 "gs_BM",
209 "gs_CA",
210 "gs_ca",
211 "gs_SMask",
212 "gs_end",
213 "q",
214 "cm",
215 "m",
216 "l",
217 "c",
218 "v",
219 "y",
220 "h",
221 "re",
222 "S",
223 "s",
224 "F",
225 "f",
226 "fstar",
227 "B",
228 "Bstar",
229 "b",
230 "bstar",
231 "n",
232 "W",
233 "Wstar",
234 "BT",
235 "ET",
236 "Q",
237 "Tc",
238 "Tw",
239 "Tz",
240 "TL",
241 "Tf",
242 "Tr",
243 "Ts",
244 "Td",
245 "TD",
246 "Tm",
247 "Tstar",
248 "TJ",
249 "Tj",
250 "squote",
251 "dquote",
252 "d0",
253 "d1",
254 "CS",
255 "cs",
256 "SC_pattern",
257 "sc_pattern",
258 "SC_shade",
259 "sc_shade",
260 "SC_color",
261 "sc_color",
262 "G",
263 "g",
264 "RG",
265 "rg",
266 "K",
267 "k",
268 "BI",
269 "sh",
270 "Do_image",
271 "Do_form",
272 "MP",
273 "DP",
274 "BMC",
275 "BDC",
276 "EMC",
277 "BX",
278 "EX",
279 };
280
281 typedef struct
282 {
283 size_t len[OP_END];
284 } op_usage_t;
285
286 typedef struct
287 {
288 pdf_processor super;
289 pdf_document *doc;
290 int structparents;
291 pdf_processor *mine;
292 pdf_processor *chain;
293 pdf_filter_options *global_options;
294 op_usage_t *op_usage;
295 fz_buffer *buffer;
296 } pdf_opcount_processor;
297
298 /* general graphics state */
299
300 static void
301 pdf_opcount_w(fz_context *ctx, pdf_processor *proc, float linewidth)
302 {
303 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
304 size_t z = p->buffer->len;
305
306 if (p->mine->op_w)
307 p->mine->op_w(ctx, p->mine, linewidth);
308
309 z = p->buffer->len - z;
310 p->op_usage->len[OP_w] += z;
311 }
312
313 static void
314 pdf_opcount_j(fz_context *ctx, pdf_processor *proc, int linejoin)
315 {
316 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
317 size_t z = p->buffer->len;
318
319 if (p->mine->op_j)
320 p->mine->op_j(ctx, p->mine, linejoin);
321
322 z = p->buffer->len - z;
323 p->op_usage->len[OP_j] += z;
324 }
325
326 static void
327 pdf_opcount_J(fz_context *ctx, pdf_processor *proc, int linecap)
328 {
329 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
330 size_t z = p->buffer->len;
331
332 if (p->mine->op_J)
333 p->mine->op_J(ctx, p->mine, linecap);
334
335 z = p->buffer->len - z;
336 p->op_usage->len[OP_J] += z;
337 }
338
339 static void
340 pdf_opcount_M(fz_context *ctx, pdf_processor *proc, float miterlimit)
341 {
342 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
343 size_t z = p->buffer->len;
344
345 if (p->mine->op_M)
346 p->mine->op_M(ctx, p->mine, miterlimit);
347
348 z = p->buffer->len - z;
349 p->op_usage->len[OP_M] += z;
350 }
351
352 static void
353 pdf_opcount_d(fz_context *ctx, pdf_processor *proc, pdf_obj *array, float phase)
354 {
355 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
356 size_t z = p->buffer->len;
357
358 if (p->mine->op_d)
359 p->mine->op_d(ctx, p->mine, array, phase);
360
361 z = p->buffer->len - z;
362 p->op_usage->len[OP_d] += z;
363 }
364
365 static void
366 pdf_opcount_ri(fz_context *ctx, pdf_processor *proc, const char *intent)
367 {
368 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
369 size_t z = p->buffer->len;
370
371 if (p->mine->op_ri)
372 p->mine->op_ri(ctx, p->mine, intent);
373
374 z = p->buffer->len - z;
375 p->op_usage->len[OP_ri] += z;
376 }
377
378 static void
379 pdf_opcount_gs_OP(fz_context *ctx, pdf_processor *proc, int b)
380 {
381 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
382 size_t z = p->buffer->len;
383
384 if (p->mine->op_gs_OP)
385 p->mine->op_gs_OP(ctx, p->mine, b);
386
387 z = p->buffer->len - z;
388 p->op_usage->len[OP_gs_OP] += z;
389 }
390
391 static void
392 pdf_opcount_gs_op(fz_context *ctx, pdf_processor *proc, int b)
393 {
394 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
395 size_t z = p->buffer->len;
396
397 if (p->mine->op_gs_op)
398 p->mine->op_gs_op(ctx, p->mine, b);
399
400 z = p->buffer->len - z;
401 p->op_usage->len[OP_gs_op] += z;
402 }
403
404 static void
405 pdf_opcount_gs_OPM(fz_context *ctx, pdf_processor *proc, int i)
406 {
407 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
408 size_t z = p->buffer->len;
409
410 if (p->mine->op_gs_OPM)
411 p->mine->op_gs_OPM(ctx, p->mine, i);
412
413 z = p->buffer->len - z;
414 p->op_usage->len[OP_gs_OPM] += z;
415 }
416
417 static void
418 pdf_opcount_gs_UseBlackPtComp(fz_context *ctx, pdf_processor *proc, pdf_obj *name)
419 {
420 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
421 size_t z = p->buffer->len;
422
423 if (p->mine->op_gs_UseBlackPtComp)
424 p->mine->op_gs_UseBlackPtComp(ctx, p->mine, name);
425
426 z = p->buffer->len - z;
427 p->op_usage->len[OP_gs_UseBlackPtComp] += z;
428 }
429
430 static void
431 pdf_opcount_i(fz_context *ctx, pdf_processor *proc, float flatness)
432 {
433 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
434 size_t z = p->buffer->len;
435
436 if (p->mine->op_i)
437 p->mine->op_i(ctx, p->mine, flatness);
438
439 z = p->buffer->len - z;
440 p->op_usage->len[OP_i] += z;
441 }
442
443 static void
444 pdf_opcount_gs_begin(fz_context *ctx, pdf_processor *proc, const char *name, pdf_obj *extgstate)
445 {
446 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
447 size_t z = p->buffer->len;
448
449 if (p->mine->op_gs_begin)
450 p->mine->op_gs_begin(ctx, p->mine, name, extgstate);
451
452 z = p->buffer->len - z;
453 p->op_usage->len[OP_gs_begin] += z;
454 }
455
456 static void
457 pdf_opcount_gs_BM(fz_context *ctx, pdf_processor *proc, const char *blendmode)
458 {
459 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
460 size_t z = p->buffer->len;
461
462 if (p->mine->op_gs_BM)
463 p->mine->op_gs_BM(ctx, p->mine, blendmode);
464
465 z = p->buffer->len - z;
466 p->op_usage->len[OP_gs_BM] += z;
467 }
468
469 static void
470 pdf_opcount_gs_CA(fz_context *ctx, pdf_processor *proc, float alpha)
471 {
472 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
473 size_t z = p->buffer->len;
474
475 if (p->mine->op_gs_CA)
476 p->mine->op_gs_CA(ctx, p->mine, alpha);
477
478 z = p->buffer->len - z;
479 p->op_usage->len[OP_gs_CA] += z;
480 }
481
482 static void
483 pdf_opcount_gs_ca(fz_context *ctx, pdf_processor *proc, float alpha)
484 {
485 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
486 size_t z = p->buffer->len;
487
488 if (p->mine->op_gs_ca)
489 p->mine->op_gs_ca(ctx, p->mine, alpha);
490
491 z = p->buffer->len - z;
492 p->op_usage->len[OP_gs_ca] += z;
493 }
494
495 static void
496 pdf_opcount_gs_SMask(fz_context *ctx, pdf_processor *proc, pdf_obj *smask, fz_colorspace *smask_cs, float *bc, int luminosity, pdf_obj *obj)
497 {
498 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
499 size_t z = p->buffer->len;
500
501 if (p->mine->op_gs_SMask)
502 p->mine->op_gs_SMask(ctx, p->mine, smask, smask_cs, bc, luminosity, obj);
503
504 z = p->buffer->len - z;
505 p->op_usage->len[OP_gs_SMask] += z;
506 }
507
508 static void
509 pdf_opcount_gs_end(fz_context *ctx, pdf_processor *proc)
510 {
511 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
512 size_t z = p->buffer->len;
513
514 if (p->mine->op_gs_end)
515 p->mine->op_gs_end(ctx, p->mine);
516
517 z = p->buffer->len - z;
518 p->op_usage->len[OP_gs_end] += z;
519 }
520
521 /* special graphics state */
522
523 static void
524 pdf_opcount_q(fz_context *ctx, pdf_processor *proc)
525 {
526 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
527 size_t z = p->buffer->len;
528
529 if (p->mine->op_q)
530 p->mine->op_q(ctx, p->mine);
531
532 z = p->buffer->len - z;
533 p->op_usage->len[OP_q] += z;
534 }
535
536 static void
537 pdf_opcount_cm(fz_context *ctx, pdf_processor *proc, float a, float b, float c, float d, float e, float f)
538 {
539 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
540 size_t z = p->buffer->len;
541
542 if (p->mine->op_cm)
543 p->mine->op_cm(ctx, p->mine, a, b, c, d, e, f);
544
545 z = p->buffer->len - z;
546 p->op_usage->len[OP_cm] += z;
547 }
548
549 /* path construction */
550
551 static void
552 pdf_opcount_m(fz_context *ctx, pdf_processor *proc, float x, float y)
553 {
554 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
555 size_t z = p->buffer->len;
556
557 if (p->mine->op_m)
558 p->mine->op_m(ctx, p->mine, x, y);
559
560 z = p->buffer->len - z;
561 p->op_usage->len[OP_m] += z;
562 }
563
564 static void
565 pdf_opcount_l(fz_context *ctx, pdf_processor *proc, float x, float y)
566 {
567 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
568 size_t z = p->buffer->len;
569
570 if (p->mine->op_l)
571 p->mine->op_l(ctx, p->mine, x, y);
572
573 z = p->buffer->len - z;
574 p->op_usage->len[OP_l] += z;
575 }
576
577 static void
578 pdf_opcount_c(fz_context *ctx, pdf_processor *proc, float x1, float y1, float x2, float y2, float x3, float y3)
579 {
580 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
581 size_t z = p->buffer->len;
582
583 if (p->mine->op_c)
584 p->mine->op_c(ctx, p->mine, x1, y1, x2, y2, x3, y3);
585
586 z = p->buffer->len - z;
587 p->op_usage->len[OP_c] += z;
588 }
589
590 static void
591 pdf_opcount_v(fz_context *ctx, pdf_processor *proc, float x2, float y2, float x3, float y3)
592 {
593 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
594 size_t z = p->buffer->len;
595
596 if (p->mine->op_v)
597 p->mine->op_v(ctx, p->mine, x2, y2, x3, y3);
598
599 z = p->buffer->len - z;
600 p->op_usage->len[OP_v] += z;
601 }
602
603 static void
604 pdf_opcount_y(fz_context *ctx, pdf_processor *proc, float x1, float y1, float x3, float y3)
605 {
606 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
607 size_t z = p->buffer->len;
608
609 if (p->mine->op_y)
610 p->mine->op_y(ctx, p->mine, x1, y1, x3, y3);
611
612 z = p->buffer->len - z;
613 p->op_usage->len[OP_y] += z;
614 }
615
616 static void
617 pdf_opcount_h(fz_context *ctx, pdf_processor *proc)
618 {
619 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
620 size_t z = p->buffer->len;
621
622 if (p->mine->op_h)
623 p->mine->op_h(ctx, p->mine);
624
625 z = p->buffer->len - z;
626 p->op_usage->len[OP_h] += z;
627 }
628
629 static void
630 pdf_opcount_re(fz_context *ctx, pdf_processor *proc, float x, float y, float w, float h)
631 {
632 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
633 size_t z = p->buffer->len;
634
635 if (p->mine->op_re)
636 p->mine->op_re(ctx, p->mine, x, y, w, h);
637
638 z = p->buffer->len - z;
639 p->op_usage->len[OP_re] += z;
640 }
641
642 /* path painting */
643
644 static void
645 pdf_opcount_S(fz_context *ctx, pdf_processor *proc)
646 {
647 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
648 size_t z = p->buffer->len;
649
650 if (p->mine->op_S)
651 p->mine->op_S(ctx, p->mine);
652
653 z = p->buffer->len - z;
654 p->op_usage->len[OP_S] += z;
655 }
656
657 static void
658 pdf_opcount_s(fz_context *ctx, pdf_processor *proc)
659 {
660 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
661 size_t z = p->buffer->len;
662
663 if (p->mine->op_s)
664 p->mine->op_s(ctx, p->mine);
665
666 z = p->buffer->len - z;
667 p->op_usage->len[OP_s] += z;
668 }
669
670 static void
671 pdf_opcount_F(fz_context *ctx, pdf_processor *proc)
672 {
673 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
674 size_t z = p->buffer->len;
675
676 if (p->mine->op_F)
677 p->mine->op_F(ctx, p->mine);
678
679 z = p->buffer->len - z;
680 p->op_usage->len[OP_F] += z;
681 }
682
683 static void
684 pdf_opcount_f(fz_context *ctx, pdf_processor *proc)
685 {
686 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
687 size_t z = p->buffer->len;
688
689 if (p->mine->op_f)
690 p->mine->op_f(ctx, p->mine);
691
692 z = p->buffer->len - z;
693 p->op_usage->len[OP_f] += z;
694 }
695
696 static void
697 pdf_opcount_fstar(fz_context *ctx, pdf_processor *proc)
698 {
699 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
700 size_t z = p->buffer->len;
701
702 if (p->mine->op_fstar)
703 p->mine->op_fstar(ctx, p->mine);
704
705 z = p->buffer->len - z;
706 p->op_usage->len[OP_fstar] += z;
707 }
708
709 static void
710 pdf_opcount_B(fz_context *ctx, pdf_processor *proc)
711 {
712 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
713 size_t z = p->buffer->len;
714
715 if (p->mine->op_B)
716 p->mine->op_B(ctx, p->mine);
717
718 z = p->buffer->len - z;
719 p->op_usage->len[OP_B] += z;
720 }
721
722 static void
723 pdf_opcount_Bstar(fz_context *ctx, pdf_processor *proc)
724 {
725 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
726 size_t z = p->buffer->len;
727
728 if (p->mine->op_Bstar)
729 p->mine->op_Bstar(ctx, p->mine);
730
731 z = p->buffer->len - z;
732 p->op_usage->len[OP_Bstar] += z;
733 }
734
735 static void
736 pdf_opcount_b(fz_context *ctx, pdf_processor *proc)
737 {
738 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
739 size_t z = p->buffer->len;
740
741 if (p->mine->op_b)
742 p->mine->op_b(ctx, p->mine);
743
744 z = p->buffer->len - z;
745 p->op_usage->len[OP_b] += z;
746 }
747
748 static void
749 pdf_opcount_bstar(fz_context *ctx, pdf_processor *proc)
750 {
751 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
752 size_t z = p->buffer->len;
753
754 if (p->mine->op_bstar)
755 p->mine->op_bstar(ctx, p->mine);
756
757 z = p->buffer->len - z;
758 p->op_usage->len[OP_bstar] += z;
759 }
760
761 static void
762 pdf_opcount_n(fz_context *ctx, pdf_processor *proc)
763 {
764 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
765 size_t z = p->buffer->len;
766
767 if (p->mine->op_n)
768 p->mine->op_n(ctx, p->mine);
769
770 z = p->buffer->len - z;
771 p->op_usage->len[OP_n] += z;
772 }
773
774 /* clipping paths */
775
776 static void
777 pdf_opcount_W(fz_context *ctx, pdf_processor *proc)
778 {
779 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
780 size_t z = p->buffer->len;
781
782 if (p->mine->op_W)
783 p->mine->op_W(ctx, p->mine);
784
785 z = p->buffer->len - z;
786 p->op_usage->len[OP_W] += z;
787 }
788
789 static void
790 pdf_opcount_Wstar(fz_context *ctx, pdf_processor *proc)
791 {
792 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
793 size_t z = p->buffer->len;
794
795 if (p->mine->op_Wstar)
796 p->mine->op_Wstar(ctx, p->mine);
797
798 z = p->buffer->len - z;
799 p->op_usage->len[OP_Wstar] += z;
800 }
801
802 /* text objects */
803
804 static void
805 pdf_opcount_BT(fz_context *ctx, pdf_processor *proc)
806 {
807 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
808 size_t z = p->buffer->len;
809
810 if (p->mine->op_BT)
811 p->mine->op_BT(ctx, p->mine);
812
813 z = p->buffer->len - z;
814 p->op_usage->len[OP_BT] += z;
815 }
816
817 static void
818 pdf_opcount_ET(fz_context *ctx, pdf_processor *proc)
819 {
820 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
821 size_t z = p->buffer->len;
822
823 if (p->mine->op_ET)
824 p->mine->op_ET(ctx, p->mine);
825
826 z = p->buffer->len - z;
827 p->op_usage->len[OP_ET] += z;
828 }
829
830 static void
831 pdf_opcount_Q(fz_context *ctx, pdf_processor *proc)
832 {
833 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
834 size_t z = p->buffer->len;
835
836 if (p->mine->op_Q)
837 p->mine->op_Q(ctx, p->mine);
838
839 z = p->buffer->len - z;
840 p->op_usage->len[OP_Q] += z;
841 }
842
843 /* text state */
844
845 static void
846 pdf_opcount_Tc(fz_context *ctx, pdf_processor *proc, float charspace)
847 {
848 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
849 size_t z = p->buffer->len;
850
851 if (p->mine->op_Tc)
852 p->mine->op_Tc(ctx, p->mine, charspace);
853
854 z = p->buffer->len - z;
855 p->op_usage->len[OP_Tc] += z;
856 }
857
858 static void
859 pdf_opcount_Tw(fz_context *ctx, pdf_processor *proc, float wordspace)
860 {
861 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
862 size_t z = p->buffer->len;
863
864 if (p->mine->op_Tw)
865 p->mine->op_Tw(ctx, p->mine, wordspace);
866
867 z = p->buffer->len - z;
868 p->op_usage->len[OP_Tw] += z;
869 }
870
871 static void
872 pdf_opcount_Tz(fz_context *ctx, pdf_processor *proc, float scale)
873 {
874 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
875 size_t z = p->buffer->len;
876
877 if (p->mine->op_Tz)
878 p->mine->op_Tz(ctx, p->mine, scale);
879
880 z = p->buffer->len - z;
881 p->op_usage->len[OP_Tz] += z;
882 }
883
884 static void
885 pdf_opcount_TL(fz_context *ctx, pdf_processor *proc, float leading)
886 {
887 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
888 size_t z = p->buffer->len;
889
890 if (p->mine->op_TL)
891 p->mine->op_TL(ctx, p->mine, leading);
892
893 z = p->buffer->len - z;
894 p->op_usage->len[OP_TL] += z;
895 }
896
897 static void
898 pdf_opcount_Tf(fz_context *ctx, pdf_processor *proc, const char *name, pdf_font_desc *font, float size)
899 {
900 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
901 size_t z = p->buffer->len;
902
903 if (p->mine->op_Tf)
904 p->mine->op_Tf(ctx, p->mine, name, font, size);
905
906 z = p->buffer->len - z;
907 p->op_usage->len[OP_Tf] += z;
908 }
909
910 static void
911 pdf_opcount_Tr(fz_context *ctx, pdf_processor *proc, int render)
912 {
913 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
914 size_t z = p->buffer->len;
915
916 if (p->mine->op_Tr)
917 p->mine->op_Tr(ctx, p->mine, render);
918
919 z = p->buffer->len - z;
920 p->op_usage->len[OP_Tr] += z;
921 }
922
923 static void
924 pdf_opcount_Ts(fz_context *ctx, pdf_processor *proc, float rise)
925 {
926 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
927 size_t z = p->buffer->len;
928
929 if (p->mine->op_Ts)
930 p->mine->op_Ts(ctx, p->mine, rise);
931
932 z = p->buffer->len - z;
933 p->op_usage->len[OP_Ts] += z;
934 }
935
936 /* text positioning */
937
938 static void
939 pdf_opcount_Td(fz_context *ctx, pdf_processor *proc, float tx, float ty)
940 {
941 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
942 size_t z = p->buffer->len;
943
944 if (p->mine->op_Td)
945 p->mine->op_Td(ctx, p->mine, tx, ty);
946
947 z = p->buffer->len - z;
948 p->op_usage->len[OP_Td] += z;
949 }
950
951 static void
952 pdf_opcount_TD(fz_context *ctx, pdf_processor *proc, float tx, float ty)
953 {
954 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
955 size_t z = p->buffer->len;
956
957 if (p->mine->op_TD)
958 p->mine->op_TD(ctx, p->mine, tx, ty);
959
960 z = p->buffer->len - z;
961 p->op_usage->len[OP_TD] += z;
962 }
963
964 static void
965 pdf_opcount_Tm(fz_context *ctx, pdf_processor *proc, float a, float b, float c, float d, float e, float f)
966 {
967 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
968 size_t z = p->buffer->len;
969
970 if (p->mine->op_Tm)
971 p->mine->op_Tm(ctx, p->mine, a, b, c, d, e, f);
972
973 z = p->buffer->len - z;
974 p->op_usage->len[OP_Tm] += z;
975 }
976
977 static void
978 pdf_opcount_Tstar(fz_context *ctx, pdf_processor *proc)
979 {
980 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
981 size_t z = p->buffer->len;
982
983 if (p->mine->op_Tstar)
984 p->mine->op_Tstar(ctx, p->mine);
985
986 z = p->buffer->len - z;
987 p->op_usage->len[OP_Tstar] += z;
988 }
989
990 /* text showing */
991
992 static void
993 pdf_opcount_TJ(fz_context *ctx, pdf_processor *proc, pdf_obj *array)
994 {
995 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
996 size_t z = p->buffer->len;
997
998 if (p->mine->op_TJ)
999 p->mine->op_TJ(ctx, p->mine, array);
1000
1001 z = p->buffer->len - z;
1002 p->op_usage->len[OP_TJ] += z;
1003 }
1004
1005 static void
1006 pdf_opcount_Tj(fz_context *ctx, pdf_processor *proc, char *str, size_t len)
1007 {
1008 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1009 size_t z = p->buffer->len;
1010
1011 if (p->mine->op_Tj)
1012 p->mine->op_Tj(ctx, p->mine, str, len);
1013
1014 z = p->buffer->len - z;
1015 p->op_usage->len[OP_Tj] += z;
1016 }
1017
1018 static void
1019 pdf_opcount_squote(fz_context *ctx, pdf_processor *proc, char *str, size_t len)
1020 {
1021 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1022 size_t z = p->buffer->len;
1023
1024 if (p->mine->op_squote)
1025 p->mine->op_squote(ctx, p->mine, str, len);
1026
1027 z = p->buffer->len - z;
1028 p->op_usage->len[OP_squote] += z;
1029 }
1030
1031 static void
1032 pdf_opcount_dquote(fz_context *ctx, pdf_processor *proc, float aw, float ac, char *str, size_t len)
1033 {
1034 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1035 size_t z = p->buffer->len;
1036
1037 if (p->mine->op_dquote)
1038 p->mine->op_dquote(ctx, p->mine, aw, ac, str, len);
1039
1040 z = p->buffer->len - z;
1041 p->op_usage->len[OP_dquote] += z;
1042 }
1043
1044 /* type 3 fonts */
1045
1046 static void
1047 pdf_opcount_d0(fz_context *ctx, pdf_processor *proc, float wx, float wy)
1048 {
1049 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1050 size_t z = p->buffer->len;
1051
1052 if (p->mine->op_d0)
1053 p->mine->op_d0(ctx, p->mine, wx, wy);
1054
1055 z = p->buffer->len - z;
1056 p->op_usage->len[OP_d0] += z;
1057 }
1058
1059 static void
1060 pdf_opcount_d1(fz_context *ctx, pdf_processor *proc, float wx, float wy, float llx, float lly, float urx, float ury)
1061 {
1062 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1063 size_t z = p->buffer->len;
1064
1065 if (p->mine->op_d1)
1066 p->mine->op_d1(ctx, p->mine, wx, wy, llx, lly, urx, ury);
1067
1068 z = p->buffer->len - z;
1069 p->op_usage->len[OP_d1] += z;
1070 }
1071
1072 /* color */
1073
1074 static void
1075 pdf_opcount_CS(fz_context *ctx, pdf_processor *proc, const char *name, fz_colorspace *cs)
1076 {
1077 pdf_opcount_processor *p = (pdf_opcount_processor *)proc;
1078 size_t z = p->buffer->len;
1079
1080 if (p->mine->op_CS)
1081 p->mine->op_CS(ctx, p->mine, name, cs);
1082
1083 z = p->buffer->len - z;
1084 p->op_usage->len[OP_CS] += z;
1085 }
1086
1087 static void
1088 pdf_opcount_cs(fz_context *ctx, pdf_processor *proc, const char *name, fz_colorspace *cs)
1089 {
1090 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1091 size_t z = p->buffer->len;
1092
1093 if (p->mine->op_cs)
1094 p->mine->op_cs(ctx, p->mine, name, cs);
1095
1096 z = p->buffer->len - z;
1097 p->op_usage->len[OP_cs] += z;
1098 }
1099
1100 static void
1101 pdf_opcount_SC_pattern(fz_context *ctx, pdf_processor *proc, const char *name, pdf_pattern *pat, int n, float *color)
1102 {
1103 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1104 size_t z = p->buffer->len;
1105
1106 if (p->mine->op_SC_pattern)
1107 p->mine->op_SC_pattern(ctx, p->mine, name, pat, n, color);
1108
1109 z = p->buffer->len - z;
1110 p->op_usage->len[OP_SC_pattern] += z;
1111 }
1112
1113 static void
1114 pdf_opcount_sc_pattern(fz_context *ctx, pdf_processor *proc, const char *name, pdf_pattern *pat, int n, float *color)
1115 {
1116 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1117 size_t z = p->buffer->len;
1118
1119 if (p->mine->op_sc_pattern)
1120 p->mine->op_sc_pattern(ctx, p->mine, name, pat, n, color);
1121
1122 z = p->buffer->len - z;
1123 p->op_usage->len[OP_sc_pattern] += z;
1124 }
1125
1126 static void
1127 pdf_opcount_SC_shade(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade)
1128 {
1129 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1130 size_t z = p->buffer->len;
1131
1132 if (p->mine->op_SC_shade)
1133 p->mine->op_SC_shade(ctx, p->mine, name, shade);
1134
1135 z = p->buffer->len - z;
1136 p->op_usage->len[OP_SC_shade] += z;
1137 }
1138
1139 static void
1140 pdf_opcount_sc_shade(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade)
1141 {
1142 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1143 size_t z = p->buffer->len;
1144
1145 if (p->mine->op_sc_shade)
1146 p->mine->op_sc_shade(ctx, p->mine, name, shade);
1147
1148 z = p->buffer->len - z;
1149 p->op_usage->len[OP_sc_shade] += z;
1150 }
1151
1152 static void
1153 pdf_opcount_SC_color(fz_context *ctx, pdf_processor *proc, int n, float *color)
1154 {
1155 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1156 size_t z = p->buffer->len;
1157
1158 if (p->mine->op_SC_color)
1159 p->mine->op_SC_color(ctx, p->mine, n, color);
1160
1161 z = p->buffer->len - z;
1162 p->op_usage->len[OP_SC_color] += z;
1163 }
1164
1165 static void
1166 pdf_opcount_sc_color(fz_context *ctx, pdf_processor *proc, int n, float *color)
1167 {
1168 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1169 size_t z = p->buffer->len;
1170
1171 if (p->mine->op_sc_color)
1172 p->mine->op_sc_color(ctx, p->mine, n, color);
1173
1174 z = p->buffer->len - z;
1175 p->op_usage->len[OP_sc_color] += z;
1176 }
1177
1178 static void
1179 pdf_opcount_G(fz_context *ctx, pdf_processor *proc, float g)
1180 {
1181 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1182 size_t z = p->buffer->len;
1183
1184 if (p->mine->op_G)
1185 p->mine->op_G(ctx, p->mine, g);
1186
1187 z = p->buffer->len - z;
1188 p->op_usage->len[OP_G] += z;
1189 }
1190
1191 static void
1192 pdf_opcount_g(fz_context *ctx, pdf_processor *proc, float g)
1193 {
1194 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1195 size_t z = p->buffer->len;
1196
1197 if (p->mine->op_g)
1198 p->mine->op_g(ctx, p->mine, g);
1199
1200 z = p->buffer->len - z;
1201 p->op_usage->len[OP_g] += z;
1202 }
1203
1204 static void
1205 pdf_opcount_RG(fz_context *ctx, pdf_processor *proc, float r, float g, float b)
1206 {
1207 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1208 size_t z = p->buffer->len;
1209
1210 if (p->mine->op_RG)
1211 p->mine->op_RG(ctx, p->mine, r, g, b);
1212
1213 z = p->buffer->len - z;
1214 p->op_usage->len[OP_RG] += z;
1215 }
1216
1217 static void
1218 pdf_opcount_rg(fz_context *ctx, pdf_processor *proc, float r, float g, float b)
1219 {
1220 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1221 size_t z = p->buffer->len;
1222
1223 if (p->mine->op_rg)
1224 p->mine->op_rg(ctx, p->mine, r, g, b);
1225
1226 z = p->buffer->len - z;
1227 p->op_usage->len[OP_rg] += z;
1228 }
1229
1230 static void
1231 pdf_opcount_K(fz_context *ctx, pdf_processor *proc, float c, float m, float y, float k)
1232 {
1233 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1234 size_t z = p->buffer->len;
1235
1236 if (p->mine->op_K)
1237 p->mine->op_K(ctx, p->mine, c, m, y, k);
1238
1239 z = p->buffer->len - z;
1240 p->op_usage->len[OP_K] += z;
1241 }
1242
1243 static void
1244 pdf_opcount_k(fz_context *ctx, pdf_processor *proc, float c, float m, float y, float k)
1245 {
1246 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1247 size_t z = p->buffer->len;
1248
1249 if (p->mine->op_k)
1250 p->mine->op_k(ctx, p->mine, c, m, y, k);
1251
1252 z = p->buffer->len - z;
1253 p->op_usage->len[OP_k] += z;
1254 }
1255
1256 /* shadings, images, xobjects */
1257
1258 static void
1259 pdf_opcount_BI(fz_context *ctx, pdf_processor *proc, fz_image *image, const char *colorspace)
1260 {
1261 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1262 size_t z = p->buffer->len;
1263
1264 if (p->mine->op_BI)
1265 p->mine->op_BI(ctx, p->mine, image, colorspace);
1266
1267 z = p->buffer->len - z;
1268 p->op_usage->len[OP_BI] += z;
1269 }
1270
1271 static void
1272 pdf_opcount_sh(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade)
1273 {
1274 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1275 size_t z = p->buffer->len;
1276
1277 if (p->mine->op_sh)
1278 p->mine->op_sh(ctx, p->mine, name, shade);
1279
1280 z = p->buffer->len - z;
1281 p->op_usage->len[OP_sh] += z;
1282 }
1283
1284 static void
1285 pdf_opcount_Do_image(fz_context *ctx, pdf_processor *proc, const char *name, fz_image *image)
1286 {
1287 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1288 size_t z = p->buffer->len;
1289
1290 if (p->mine->op_Do_image)
1291 p->mine->op_Do_image(ctx, p->mine, name, image);
1292
1293 z = p->buffer->len - z;
1294 p->op_usage->len[OP_Do_image] += z;
1295 }
1296
1297 static void
1298 pdf_opcount_Do_form(fz_context *ctx, pdf_processor *proc, const char *name, pdf_obj *xobj)
1299 {
1300 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1301 size_t z = p->buffer->len;
1302
1303 if (p->mine->op_Do_form)
1304 p->mine->op_Do_form(ctx, p->mine, name, xobj);
1305
1306 z = p->buffer->len - z;
1307 p->op_usage->len[OP_Do_form] += z;
1308 }
1309
1310 /* marked content */
1311
1312 static void
1313 pdf_opcount_MP(fz_context *ctx, pdf_processor *proc, const char *tag)
1314 {
1315 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1316 size_t z = p->buffer->len;
1317
1318 if (p->mine->op_MP)
1319 p->mine->op_MP(ctx, p->mine, tag);
1320
1321 z = p->buffer->len - z;
1322 p->op_usage->len[OP_MP] += z;
1323 }
1324
1325 static void
1326 pdf_opcount_DP(fz_context *ctx, pdf_processor *proc, const char *tag, pdf_obj *raw, pdf_obj *cooked)
1327 {
1328 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1329 size_t z = p->buffer->len;
1330
1331 if (p->mine->op_DP)
1332 p->mine->op_DP(ctx, p->mine, tag, raw, cooked);
1333
1334 z = p->buffer->len - z;
1335 p->op_usage->len[OP_DP] += z;
1336 }
1337
1338 static void
1339 pdf_opcount_BMC(fz_context *ctx, pdf_processor *proc, const char *tag)
1340 {
1341 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1342 size_t z = p->buffer->len;
1343
1344 if (p->mine->op_BMC)
1345 p->mine->op_BMC(ctx, p->mine, tag);
1346
1347 z = p->buffer->len - z;
1348 p->op_usage->len[OP_BMC] += z;
1349 }
1350
1351 static void
1352 pdf_opcount_BDC(fz_context *ctx, pdf_processor *proc, const char *tag, pdf_obj *raw, pdf_obj *cooked)
1353 {
1354 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1355 size_t z = p->buffer->len;
1356
1357 if (p->mine->op_BDC)
1358 p->mine->op_BDC(ctx, p->mine, tag, raw, cooked);
1359
1360 z = p->buffer->len - z;
1361 p->op_usage->len[OP_BDC] += z;
1362 }
1363
1364 static void
1365 pdf_opcount_EMC(fz_context *ctx, pdf_processor *proc)
1366 {
1367 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1368 size_t z = p->buffer->len;
1369
1370 if (p->mine->op_EMC)
1371 p->mine->op_EMC(ctx, p->mine);
1372
1373 z = p->buffer->len - z;
1374 p->op_usage->len[OP_EMC] += z;
1375 }
1376
1377 /* compatibility */
1378
1379 static void
1380 pdf_opcount_BX(fz_context *ctx, pdf_processor *proc)
1381 {
1382 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1383 size_t z = p->buffer->len;
1384
1385 if (p->mine->op_BX)
1386 p->mine->op_BX(ctx, p->mine);
1387
1388 z = p->buffer->len - z;
1389 p->op_usage->len[OP_BX] += z;
1390 }
1391
1392 static void
1393 pdf_opcount_EX(fz_context *ctx, pdf_processor *proc)
1394 {
1395 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1396 size_t z = p->buffer->len;
1397
1398 if (p->mine->op_EX)
1399 p->mine->op_EX(ctx, p->mine);
1400
1401 z = p->buffer->len - z;
1402 p->op_usage->len[OP_EX] += z;
1403 }
1404
1405 static void
1406 pdf_opcount_END(fz_context *ctx, pdf_processor *proc)
1407 {
1408 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1409
1410 if (p->mine->op_END)
1411 p->mine->op_END(ctx, p->mine);
1412 }
1413
1414 static void
1415 pdf_close_opcount_processor(fz_context *ctx, pdf_processor *proc)
1416 {
1417 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1418
1419 pdf_close_processor(ctx, p->mine);
1420 pdf_close_processor(ctx, p->chain);
1421 }
1422
1423 static void
1424 pdf_drop_opcount_processor(fz_context *ctx, pdf_processor *proc)
1425 {
1426 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1427
1428 fz_drop_buffer(ctx, p->buffer);
1429 pdf_drop_processor(ctx, p->mine);
1430 }
1431
1432 static void
1433 pdf_opcount_push_resources(fz_context *ctx, pdf_processor *proc, pdf_obj *res)
1434 {
1435 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1436
1437 pdf_processor_push_resources(ctx, p->mine, res);
1438 }
1439
1440 static pdf_obj *
1441 pdf_opcount_pop_resources(fz_context *ctx, pdf_processor *proc)
1442 {
1443 pdf_opcount_processor *p = (pdf_opcount_processor*)proc;
1444
1445 return pdf_processor_pop_resources(ctx, p->mine);
1446 }
1447
1448 pdf_processor *
1449 pdf_new_opcount_filter(
1450 fz_context *ctx,
1451 pdf_document *doc,
1452 pdf_processor *chain,
1453 int struct_parents,
1454 fz_matrix transform,
1455 pdf_filter_options *global_options,
1456 void *options_)
1457 {
1458 pdf_opcount_processor *proc = pdf_new_processor(ctx, sizeof * proc);
1459
1460 fz_try(ctx)
1461 {
1462 proc->buffer = fz_new_buffer(ctx, 1024);
1463 proc->mine = pdf_new_buffer_processor(ctx, proc->buffer, 0, 0);
1464 }
1465 fz_catch(ctx)
1466 fz_rethrow(ctx);
1467
1468 proc->op_usage = (op_usage_t *)options_;
1469
1470 proc->super.close_processor = pdf_close_opcount_processor;
1471 proc->super.drop_processor = pdf_drop_opcount_processor;
1472
1473 proc->super.push_resources = pdf_opcount_push_resources;
1474 proc->super.pop_resources = pdf_opcount_pop_resources;
1475
1476 /* general graphics state */
1477 proc->super.op_w = pdf_opcount_w;
1478 proc->super.op_j = pdf_opcount_j;
1479 proc->super.op_J = pdf_opcount_J;
1480 proc->super.op_M = pdf_opcount_M;
1481 proc->super.op_d = pdf_opcount_d;
1482 proc->super.op_ri = pdf_opcount_ri;
1483 proc->super.op_i = pdf_opcount_i;
1484 proc->super.op_gs_begin = pdf_opcount_gs_begin;
1485 proc->super.op_gs_end = pdf_opcount_gs_end;
1486
1487 /* transparency graphics state */
1488 proc->super.op_gs_BM = pdf_opcount_gs_BM;
1489 proc->super.op_gs_CA = pdf_opcount_gs_CA;
1490 proc->super.op_gs_ca = pdf_opcount_gs_ca;
1491 proc->super.op_gs_SMask = pdf_opcount_gs_SMask;
1492
1493 /* special graphics state */
1494 proc->super.op_q = pdf_opcount_q;
1495 proc->super.op_Q = pdf_opcount_Q;
1496 proc->super.op_cm = pdf_opcount_cm;
1497
1498 /* path construction */
1499 proc->super.op_m = pdf_opcount_m;
1500 proc->super.op_l = pdf_opcount_l;
1501 proc->super.op_c = pdf_opcount_c;
1502 proc->super.op_v = pdf_opcount_v;
1503 proc->super.op_y = pdf_opcount_y;
1504 proc->super.op_h = pdf_opcount_h;
1505 proc->super.op_re = pdf_opcount_re;
1506
1507 /* path painting */
1508 proc->super.op_S = pdf_opcount_S;
1509 proc->super.op_s = pdf_opcount_s;
1510 proc->super.op_F = pdf_opcount_F;
1511 proc->super.op_f = pdf_opcount_f;
1512 proc->super.op_fstar = pdf_opcount_fstar;
1513 proc->super.op_B = pdf_opcount_B;
1514 proc->super.op_Bstar = pdf_opcount_Bstar;
1515 proc->super.op_b = pdf_opcount_b;
1516 proc->super.op_bstar = pdf_opcount_bstar;
1517 proc->super.op_n = pdf_opcount_n;
1518
1519 /* clipping paths */
1520 proc->super.op_W = pdf_opcount_W;
1521 proc->super.op_Wstar = pdf_opcount_Wstar;
1522
1523 /* text objects */
1524 proc->super.op_BT = pdf_opcount_BT;
1525 proc->super.op_ET = pdf_opcount_ET;
1526
1527 /* text state */
1528 proc->super.op_Tc = pdf_opcount_Tc;
1529 proc->super.op_Tw = pdf_opcount_Tw;
1530 proc->super.op_Tz = pdf_opcount_Tz;
1531 proc->super.op_TL = pdf_opcount_TL;
1532 proc->super.op_Tf = pdf_opcount_Tf;
1533 proc->super.op_Tr = pdf_opcount_Tr;
1534 proc->super.op_Ts = pdf_opcount_Ts;
1535
1536 /* text positioning */
1537 proc->super.op_Td = pdf_opcount_Td;
1538 proc->super.op_TD = pdf_opcount_TD;
1539 proc->super.op_Tm = pdf_opcount_Tm;
1540 proc->super.op_Tstar = pdf_opcount_Tstar;
1541
1542 /* text showing */
1543 proc->super.op_TJ = pdf_opcount_TJ;
1544 proc->super.op_Tj = pdf_opcount_Tj;
1545 proc->super.op_squote = pdf_opcount_squote;
1546 proc->super.op_dquote = pdf_opcount_dquote;
1547
1548 /* type 3 fonts */
1549 proc->super.op_d0 = pdf_opcount_d0;
1550 proc->super.op_d1 = pdf_opcount_d1;
1551
1552 /* color */
1553 proc->super.op_CS = pdf_opcount_CS;
1554 proc->super.op_cs = pdf_opcount_cs;
1555 proc->super.op_SC_color = pdf_opcount_SC_color;
1556 proc->super.op_sc_color = pdf_opcount_sc_color;
1557 proc->super.op_SC_pattern = pdf_opcount_SC_pattern;
1558 proc->super.op_sc_pattern = pdf_opcount_sc_pattern;
1559 proc->super.op_SC_shade = pdf_opcount_SC_shade;
1560 proc->super.op_sc_shade = pdf_opcount_sc_shade;
1561
1562 proc->super.op_G = pdf_opcount_G;
1563 proc->super.op_g = pdf_opcount_g;
1564 proc->super.op_RG = pdf_opcount_RG;
1565 proc->super.op_rg = pdf_opcount_rg;
1566 proc->super.op_K = pdf_opcount_K;
1567 proc->super.op_k = pdf_opcount_k;
1568
1569 /* shadings, images, xobjects */
1570 proc->super.op_BI = pdf_opcount_BI;
1571 proc->super.op_sh = pdf_opcount_sh;
1572 proc->super.op_Do_image = pdf_opcount_Do_image;
1573 proc->super.op_Do_form = pdf_opcount_Do_form;
1574
1575 /* marked content */
1576 proc->super.op_MP = pdf_opcount_MP;
1577 proc->super.op_DP = pdf_opcount_DP;
1578 proc->super.op_BMC = pdf_opcount_BMC;
1579 proc->super.op_BDC = pdf_opcount_BDC;
1580 proc->super.op_EMC = pdf_opcount_EMC;
1581
1582 /* compatibility */
1583 proc->super.op_BX = pdf_opcount_BX;
1584 proc->super.op_EX = pdf_opcount_EX;
1585
1586 /* extgstate */
1587 proc->super.op_gs_OP = pdf_opcount_gs_OP;
1588 proc->super.op_gs_op = pdf_opcount_gs_op;
1589 proc->super.op_gs_OPM = pdf_opcount_gs_OPM;
1590 proc->super.op_gs_UseBlackPtComp = pdf_opcount_gs_UseBlackPtComp;
1591
1592 proc->super.op_END = pdf_opcount_END;
1593
1594 proc->global_options = global_options;
1595 proc->chain = chain;
1596
1597 return (pdf_processor*)proc;
1598 }
1599
1600 static void
1601 filter_page(fz_context *ctx, pdf_document *doc, op_usage_t *op_usage, int page_num)
1602 {
1603 pdf_page *page = pdf_load_page(ctx, doc, page_num);
1604 pdf_filter_options options = { 0 };
1605 pdf_filter_factory list[2] = { 0 };
1606 pdf_annot *annot;
1607
1608 options.filters = list;
1609 options.recurse = 1;
1610 options.no_update = 1;
1611 list[0].filter = pdf_new_opcount_filter;
1612 list[0].options = op_usage;
1613
1614 fz_try(ctx)
1615 {
1616 pdf_filter_page_contents(ctx, doc, page, &options);
1617
1618 for (annot = pdf_first_annot(ctx, page); annot != NULL; annot = pdf_next_annot(ctx, annot))
1619 pdf_filter_annot_contents(ctx, doc, annot, &options);
1620 }
1621 fz_always(ctx)
1622 fz_drop_page(ctx, &page->super);
1623 fz_catch(ctx)
1624 fz_rethrow(ctx);
1625 }
1626
1627 static void
1628 filter_page_streams(fz_context *ctx, pdf_document *pdf, op_usage_t *ou)
1629 {
1630 int i, n = pdf_count_pages(ctx, pdf);
1631
1632 for (i= 0; i < n; i++)
1633 {
1634 filter_page(ctx, pdf, ou, i);
1635 }
1636 }
1637
1638 static void
1639 filter_buffer(fz_context *ctx, obj_info_t *oi, fz_buffer *buf)
1640 {
1641 oi->len = buf->len;
1642 }
1643
1644 static void
1645 filter_stream(fz_context *ctx, pdf_document *pdf, int i, obj_info_t *oi)
1646 {
1647 fz_buffer *buf = pdf_load_stream_number(ctx, pdf, i);
1648
1649 fz_try(ctx)
1650 filter_buffer(ctx, oi, buf);
1651 fz_always(ctx)
1652 fz_drop_buffer(ctx, buf);
1653 fz_catch(ctx)
1654 fz_rethrow(ctx);
1655 }
1656
1657 static void
1658 filter_obj(fz_context *ctx, obj_info_t *oi, pdf_obj *obj)
1659 {
1660 fz_buffer *buf = fz_new_buffer(ctx, 1024);
1661 fz_output *out = NULL;
1662
1663 fz_var(out);
1664
1665 fz_try(ctx)
1666 {
1667 out = fz_new_output_with_buffer(ctx, buf);
1668 pdf_print_obj(ctx, out, obj, 1, 0);
1669 fz_close_output(ctx, out);
1670 }
1671 fz_always(ctx)
1672 {
1673 fz_drop_output(ctx, out);
1674 if (buf)
1675 oi->textsize = buf->len;
1676 fz_drop_buffer(ctx, buf);
1677 }
1678 fz_catch(ctx)
1679 fz_rethrow(ctx);
1680 }
1681
1682 typedef struct
1683 {
1684 int len;
1685 int max;
1686 struct {
1687 pdf_obj *obj;
1688 int pos;
1689 int state;
1690 } *stack;
1691 } walk_stack_t;
1692
1693 static void
1694 walk(fz_context *ctx, walk_stack_t *ws, int n, obj_info_t *oi, pdf_obj *obj, audit_type_t type)
1695 {
1696 int num = 0;
1697 do
1698 {
1699 if (pdf_is_indirect(ctx, obj))
1700 {
1701 num = pdf_to_num(ctx, obj);
1702 if (num < 0 || num >= n)
1703 fz_throw(ctx, FZ_ERROR_GENERIC, "object outside of xref range");
1704 if (oi[num].type != AUDIT_UNKNOWN)
1705 goto visited;
1706 if (pdf_mark_obj(ctx, obj))
1707 {
1708 /* We've already visited this one! */
1709 goto visited;
1710 }
1711 }
1712 /* Push the object onto the stack. */
1713 if (ws->len == ws->max)
1714 {
1715 int newmax = ws->max * 2;
1716 if (newmax == 0)
1717 newmax = 32;
1718 ws->stack = fz_realloc(ctx, ws->stack, sizeof(ws->stack[0]) * newmax);
1719 ws->max = newmax;
1720 }
1721
1722 /* If the object we are about to stack is a dict, then check to see if
1723 * we should be changing type because of it. */
1724 if (pdf_is_dict(ctx, obj))
1725 {
1726 pdf_obj *otype = pdf_dict_get(ctx, obj, PDF_NAME(Type));
1727 pdf_obj *subtype = pdf_dict_get(ctx, obj, PDF_NAME(Subtype));
1728
1729 if (pdf_name_eq(ctx, otype, PDF_NAME(Annot)))
1730 {
1731 if (pdf_name_eq(ctx, subtype, PDF_NAME(Link)))
1732 type = AUDIT_LINK_ANNOTATIONS;
1733 else if (pdf_name_eq(ctx, subtype, PDF_NAME(Text)))
1734 type = AUDIT_COMMENTS;
1735 else if (pdf_name_eq(ctx, subtype, PDF_NAME(FreeText)))
1736 type = AUDIT_COMMENTS;
1737 else if (pdf_name_eq(ctx, subtype, PDF_NAME(Popup)))
1738 type = AUDIT_COMMENTS;
1739 else if (pdf_name_eq(ctx, subtype, PDF_NAME(3D)))
1740 type = AUDIT_3DCONTENT;
1741 else if (pdf_name_eq(ctx, subtype, PDF_NAME(PieceInfo)))
1742 type = AUDIT_PIECE_INFORMATION;
1743 }
1744 else if (pdf_name_eq(ctx, otype, PDF_NAME(Font)))
1745 type = AUDIT_FONTS;
1746 else if (pdf_name_eq(ctx, otype, PDF_NAME(FontDescriptor)))
1747 type = AUDIT_FONTS;
1748 else if (pdf_name_eq(ctx, otype, PDF_NAME(XObject)))
1749 {
1750 if (pdf_name_eq(ctx, subtype, PDF_NAME(Image)))
1751 type = AUDIT_IMAGES;
1752 else if (pdf_name_eq(ctx, subtype, PDF_NAME(Form)))
1753 type = AUDIT_FORM_XOBJ;
1754 }
1755 else if (pdf_name_eq(ctx, otype, PDF_NAME(Page)))
1756 type = AUDIT_PAGE_OBJECTS;
1757 else if (pdf_name_eq(ctx, otype, PDF_NAME(Pages)))
1758 type = AUDIT_PAGE_OBJECTS;
1759 else if (pdf_name_eq(ctx, otype, PDF_NAME(Metadata)))
1760 type = AUDIT_METADATA;
1761 }
1762 ws->stack[ws->len].obj = obj;
1763 ws->stack[ws->len].pos = 0;
1764 ws->stack[ws->len].state = type;
1765 ws->len++;
1766
1767 /* So we have stepped successfully onto obj. */
1768 /* Record its type. */
1769 if (type != AUDIT_UNKNOWN)
1770 {
1771 num = pdf_obj_parent_num(ctx, obj);
1772 oi[num].type = type;
1773 }
1774
1775 /* Step onwards to any children. */
1776 if (pdf_is_dict(ctx, obj))
1777 {
1778 pdf_obj *key;
1779 /* We've just stepped onto a dict. */
1780 step_next_dict_child:
1781 if (ws->stack[ws->len-1].pos == pdf_dict_len(ctx, obj))
1782 goto pop;
1783 key = pdf_dict_get_key(ctx, ws->stack[ws->len-1].obj, ws->stack[ws->len-1].pos);
1784 ws->stack[ws->len-1].pos++;
1785
1786 if (pdf_name_eq(ctx, key, PDF_NAME(Parent)))
1787 goto step_next_dict_child;
1788
1789 if (pdf_name_eq(ctx, key, PDF_NAME(Thumb)))
1790 type = AUDIT_THUMBNAILS;
1791 else if (pdf_name_eq(ctx, key, PDF_NAME(Outlines)))
1792 type = AUDIT_BOOKMARKS;
1793 else if (pdf_name_eq(ctx, key, PDF_NAME(Contents)))
1794 type = AUDIT_CONTENT_STREAMS;
1795 else if (pdf_name_eq(ctx, key, PDF_NAME(StructTreeRoot)))
1796 type = AUDIT_STRUCTURE_INFO;
1797 else if (pdf_name_eq(ctx, key, PDF_NAME(AcroForm)))
1798 type = AUDIT_FORMS;
1799 else if (pdf_name_eq(ctx, key, PDF_NAME(ColorSpace)))
1800 type = AUDIT_COLORSPACES;
1801 else if (pdf_name_eq(ctx, key, PDF_NAME(CS)))
1802 type = AUDIT_COLORSPACES;
1803 else if (pdf_name_eq(ctx, key, PDF_NAME(Dests)))
1804 type = AUDIT_NAMED_DESTINATIONS;
1805 else if (pdf_name_eq(ctx, key, PDF_NAME(ExtGState)))
1806 type = AUDIT_EXTGS;
1807 else if (pdf_name_eq(ctx, key, PDF_NAME(Resources)))
1808 type = AUDIT_RESOURCES;
1809 else if (pdf_name_eq(ctx, key, PDF_NAME(EmbeddedFile)))
1810 type = AUDIT_EMBEDDED_FILES;
1811 else if (pdf_name_eq(ctx, key, PDF_NAME(Metadata)))
1812 type = AUDIT_METADATA;
1813
1814 /* OK. step onto the val. */
1815 obj = pdf_dict_get_val(ctx, ws->stack[ws->len-1].obj, ws->stack[ws->len-1].pos-1);
1816 continue;
1817 }
1818 else if (pdf_is_array(ctx, obj))
1819 {
1820 step_next_array_child:
1821 if (ws->stack[ws->len-1].pos == pdf_array_len(ctx, obj))
1822 goto pop;
1823
1824 obj = pdf_array_get(ctx, ws->stack[ws->len-1].obj, ws->stack[ws->len-1].pos);
1825 ws->stack[ws->len-1].pos++;
1826 continue;
1827 }
1828
1829 /* Nothing more to do with this object. Pop back up. */
1830 pop:
1831 if (pdf_is_indirect(ctx, obj))
1832 {
1833 pdf_unmark_obj(ctx, obj);
1834 }
1835 ws->len--;
1836 visited:
1837 if (ws->len > 0)
1838 {
1839 /* We should either have stepped up to a dict or an array. */
1840 obj = ws->stack[ws->len-1].obj;
1841 type = ws->stack[ws->len-1].state;
1842 num = pdf_obj_parent_num(ctx, obj);
1843 if (pdf_is_dict(ctx, obj))
1844 goto step_next_dict_child;
1845 else if (pdf_is_array(ctx, obj))
1846 goto step_next_array_child;
1847 else
1848 assert("Never happens" == NULL);
1849 }
1850 }
1851 while (ws->len > 0);
1852 }
1853
1854 static void
1855 classify_by_walking(fz_context *ctx, pdf_document *doc, int n, obj_info_t *oi)
1856 {
1857 walk_stack_t ws = { 0 };
1858
1859 fz_try(ctx)
1860 walk(ctx, &ws, n, oi, pdf_trailer(ctx, doc), AUDIT_TRAILER);
1861 fz_always(ctx)
1862 fz_free(ctx, ws.stack);
1863 fz_catch(ctx)
1864 fz_rethrow(ctx);
1865 }
1866
1867 static void
1868 output_size(fz_context *ctx, fz_output *out, uint64_t file_size, const char *str, uint64_t size, uint64_t size2)
1869 {
1870 fz_write_printf(ctx, out, "<tr align=right><td align=left>%s<td>%,ld<td>%.2f%%<td>%,ld<td>%.2f%%</tr>\n", str, size, 100.0f * size/file_size, size2, 100.0f * size2/file_size);
1871 }
1872
1873 static void
1874 filter_file(fz_context *ctx, fz_output *out, const char *filename)
1875 {
1876 pdf_document *pdf = NULL;
1877 int i, n;
1878 pdf_obj *obj = NULL;
1879 obj_info_t *oi = NULL;
1880 op_usage_t ou = { 0 };
1881
1882 fz_var(pdf);
1883 fz_var(obj);
1884 fz_var(i);
1885 fz_var(oi);
1886
1887 fz_try(ctx)
1888 {
1889 pdf = pdf_open_document(ctx, filename);
1890
1891 n = pdf_xref_len(ctx, pdf);
1892 oi = fz_malloc_array(ctx, n, obj_info_t);
1893 memset(oi, 0, n * sizeof(obj_info_t));
1894 for (i = 1; i < n; i++)
1895 {
1896 fz_try(ctx)
1897 {
1898 for (; i <n; i++)
1899 {
1900 pdf_xref_entry *entry = pdf_cache_object(ctx, pdf, i);
1901 int is_in_objstm = entry->type == 'o';
1902 pdf_obj *type, *subtype;
1903 char text[128];
1904
1905 if (entry->obj == NULL)
1906 continue;
1907 oi[i].is_in_objstm = is_in_objstm;
1908 if (!is_in_objstm)
1909 {
1910 sprintf(text, "%d 0 obj\nendobj\n", i);
1911 oi[i].overhead = strlen(text);
1912 }
1913 else
1914 {
1915 sprintf(text, "%d %zd ", i, (size_t)entry->ofs);
1916 oi[i].overhead = strlen(text);
1917 }
1918 type = pdf_dict_get(ctx, entry->obj, PDF_NAME(Type));
1919 SWITCH (type)
1920 {
1921 CASE(PDF_NAME(ObjStm)):
1922 oi[i].type = AUDIT_OBJSTM;
1923 break;
1924
1925 }
1926 subtype = pdf_dict_get(ctx, entry->obj, PDF_NAME(Subtype));
1927 SWITCH (subtype)
1928 {
1929 CASE(PDF_NAME(Image)):
1930 oi[i].type = AUDIT_IMAGES;
1931 break;
1932 }
1933
1934 filter_obj(ctx, &oi[i], entry->obj);
1935 if (pdf_obj_num_is_stream(ctx, pdf, i))
1936 {
1937 filter_stream(ctx, pdf, i, &oi[i]);
1938 oi[i].stream_len = pdf_dict_get_int64(ctx, entry->obj, PDF_NAME(Length));
1939 }
1940 pdf_drop_obj(ctx, obj);
1941 obj = NULL;
1942 }
1943 }
1944 fz_catch(ctx)
1945 {
1946 i++;
1947 /* Swallow error */
1948 }
1949 }
1950
1951 /* Walk the doc structure. */
1952 classify_by_walking(ctx, pdf, n, oi);
1953
1954 /* Filter the content streams to establish operator usage */
1955 filter_page_streams(ctx, pdf, &ou);
1956
1957 fz_write_printf(ctx, out, "<html><title>PDF Audit: %s</title><body>\n", filename);
1958 fz_write_printf(ctx, out, "<H1>Input file: %s</H1>\n", filename);
1959 fz_write_printf(ctx, out, "<p>Total file size: %,zd bytes</p>", pdf->file_size);
1960
1961 fz_write_printf(ctx, out, "<H3>Total file usage</H3>\n");
1962 /* Sum the results */
1963 {
1964 struct {
1965 size_t obj;
1966 size_t objstm;
1967 } counts[AUDIT__MAX] = { 0 };
1968 size_t total_obj = 0;
1969 size_t total_objstm = 0;
1970 size_t overhead = 0;
1971 size_t objstm_overhead = 0;
1972 size_t total_stream_uncomp = 0;
1973 size_t total_stream_comp = 0;
1974 for (i = 1; i < n; i++)
1975 {
1976 size_t z = oi[i].textsize + oi[i].overhead + oi[i].stream_len;
1977 total_stream_uncomp += oi[i].len;
1978 total_stream_comp += oi[i].stream_len;
1979 if (oi[i].is_in_objstm)
1980 {
1981 objstm_overhead += oi[i].overhead;
1982 total_objstm += oi[i].textsize;
1983 counts[oi[i].type].objstm += z;
1984 }
1985 else
1986 {
1987 overhead += oi[i].overhead;
1988 total_obj += oi[i].textsize;
1989 counts[oi[i].type].obj += z;
1990 }
1991 }
1992 fz_write_printf(ctx, out, "<table border=1><thead><th><th colspan=2>not in objstms<th colspan=2>in objstms</thead>\n");
1993 output_size(ctx, out, pdf->file_size, "object text", total_obj, total_objstm);
1994 output_size(ctx, out, pdf->file_size, "object overhead", overhead, objstm_overhead);
1995 fz_write_printf(ctx, out, "<thead><th><th colspan=2>uncompressed<th colspan=2>compressed</thead>\n");
1996 output_size(ctx, out, pdf->file_size, "streams", total_stream_uncomp, total_stream_comp);
1997 fz_write_printf(ctx, out, "</table>\n");
1998 fz_write_printf(ctx, out, "<p>NOTE: The uncompressed streams percentage figure is misleading,"
1999 " as it is the percentage of the complete file which typically includes compression.</p>\n");
2000 fz_write_printf(ctx, out, "<table border=1><thead><th><th colspan=2>not in objstms<th colspan=2>in objstms</thead>\n");
2001 fz_write_printf(ctx, out, "<H3>Classified file usage</H3>\n");
2002 for (i = 0; i < AUDIT__MAX; i++)
2003 {
2004 output_size(ctx, out, pdf->file_size, audit_type[i], counts[i].obj, counts[i].objstm);
2005 }
2006 fz_write_printf(ctx, out, "</table>\n");
2007 fz_write_printf(ctx, out, "<p>NOTE: The percentages are as percentages of the complete file. This again means that"
2008 " the percentages in the &quot;in objstms&quot; column are misleading as the objstms are"
2009 " typically compressed!</p>\n");
2010 }
2011
2012 /* List some unknown objects. */
2013 {
2014 int count = 0;
2015
2016 for (i = 1; i < n; i++)
2017 {
2018 if (oi[i].type != AUDIT_UNKNOWN || oi[i].textsize == 0)
2019 continue;
2020
2021 if (count == 0)
2022 fz_write_printf(ctx, out, "<p>Some objects still unknown: e.g. ");
2023 fz_write_printf(ctx, out, "%d ", i);
2024 count++;
2025 if (count == 10)
2026 break;
2027 }
2028 if (count > 0)
2029 fz_write_printf(ctx, out, "</p>\n");
2030 }
2031
2032 /* Write out the operator usage */
2033 fz_write_printf(ctx, out, "<H3>Operator usage within streams</H3>\n");
2034 {
2035 size_t total = 0;
2036 for (i = 0; i < OP_END; i++)
2037 total += ou.len[i];
2038 fz_write_printf(ctx, out, "<table border=1><thead><th>Op<th>bytes<th></thead>\n");
2039 for (i = 0; i < OP_END; i++)
2040 {
2041 fz_write_printf(ctx, out, "<tr align=right><td align=left>%s<td>%,zd<td>%.2f%%</tr>\n", op_names[i], ou.len[i], 100.f * ou.len[i] / total);
2042 }
2043 fz_write_printf(ctx, out, "</table>\n");
2044 fz_write_printf(ctx, out, "<p>NOTE: The percentages are of the operator stream content found.</p>\n");
2045 }
2046
2047 }
2048 fz_always(ctx)
2049 {
2050 pdf_drop_obj(ctx, obj);
2051 pdf_drop_document(ctx, pdf);
2052 fz_free(ctx, oi);
2053 }
2054 fz_catch(ctx)
2055 fz_rethrow(ctx);
2056 }
2057
2058 static int usage(void)
2059 {
2060 fprintf(stderr,
2061 "usage: mutool audit [options] input.pdf+\n"
2062 "\t-o -\toutput file\n"
2063 );
2064 return 1;
2065 }
2066
2067 int pdfaudit_main(int argc, char **argv)
2068 {
2069 char *outfile = "-";
2070 int c;
2071 int errors = 0;
2072 int append = 0;
2073 fz_context *ctx;
2074 fz_output *out = NULL;
2075 const fz_getopt_long_options longopts[] =
2076 {
2077 { NULL, NULL, NULL }
2078 };
2079
2080 while ((c = fz_getopt_long(argc, argv, "o:", longopts)) != -1)
2081 {
2082 switch (c)
2083 {
2084 case 'o': outfile = fz_optpath(fz_optarg); break;
2085 case 0:
2086 {
2087 SWITCH(fz_optlong->opaque)
2088 {
2089 // Any future long options go here.
2090 default:
2091 case 0:
2092 assert(!"Never happens");
2093 break;
2094 break;
2095 }
2096 }
2097 default: return usage();
2098 }
2099 }
2100
2101 if (argc - fz_optind < 1)
2102 return usage();
2103
2104 ctx = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED);
2105 if (!ctx)
2106 {
2107 fprintf(stderr, "cannot initialise context\n");
2108 exit(1);
2109 }
2110
2111 #ifdef _WIN32
2112 fz_set_stddbg(ctx, fz_stdods(ctx));
2113 #endif
2114
2115 fz_var(out);
2116
2117 fz_try(ctx)
2118 {
2119 out = fz_new_output_with_path(ctx, outfile, append);
2120 while (fz_optind < argc)
2121 filter_file(ctx, out, argv[fz_optind++]);
2122 fz_close_output(ctx, out);
2123 }
2124 fz_always(ctx)
2125 fz_drop_output(ctx, out);
2126 fz_catch(ctx)
2127 {
2128 fz_report_error(ctx);
2129 errors++;
2130 }
2131 fz_drop_context(ctx);
2132
2133 return errors != 0;
2134 }