pdfaudit.c 48 KB

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