pdfshow.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  1. // Copyright (C) 2004-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. * pdfshow -- the ultimate pdf debugging tool
  24. */
  25. #include "mupdf/fitz.h"
  26. #include "mupdf/pdf.h"
  27. #include <stdlib.h>
  28. #include <stdio.h>
  29. #include <string.h>
  30. static pdf_document *doc = NULL;
  31. static fz_output *out = NULL;
  32. static pdf_object_labels *labels = NULL;
  33. static int showbinary = 0;
  34. static int showdecode = 1;
  35. static int do_tight = 0;
  36. static int do_repair = 0;
  37. static int do_label = 0;
  38. static int showcolumn;
  39. static int usage(void)
  40. {
  41. fprintf(stderr,
  42. "usage: mutool show [options] file.pdf ( trailer | xref | pages | grep | outline | js | form | <path> ) *\n"
  43. "\t-p -\tpassword\n"
  44. "\t-o -\toutput file\n"
  45. "\t-e\tleave stream contents in their original form\n"
  46. "\t-b\tprint only stream contents, as raw binary data\n"
  47. "\t-g\tprint only object, one line per object, suitable for grep\n"
  48. "\t-r\tforce repair before showing any objects\n"
  49. "\t-L\tshow object labels\n"
  50. "\tpath: path to an object, starting with either an object number,\n"
  51. "\t\t'pages', 'trailer', or a property in the trailer;\n"
  52. "\t\tpath elements separated by '.' or '/'. Path elements must be\n"
  53. "\t\tarray index numbers, dictionary property names, or '*'.\n"
  54. );
  55. return 1;
  56. }
  57. static void showtrailer(fz_context *ctx)
  58. {
  59. if (do_tight)
  60. fz_write_printf(ctx, out, "trailer ");
  61. else
  62. fz_write_printf(ctx, out, "trailer\n");
  63. pdf_print_obj(ctx, out, pdf_trailer(ctx, doc), do_tight, 1);
  64. fz_write_printf(ctx, out, "\n");
  65. }
  66. static void showxref(fz_context *ctx)
  67. {
  68. int i;
  69. int xref_len = pdf_xref_len(ctx, doc);
  70. fz_write_printf(ctx, out, "xref\n0 %d\n", xref_len);
  71. for (i = 0; i < xref_len; i++)
  72. {
  73. pdf_xref_entry *entry = pdf_get_xref_entry_no_null(ctx, doc, i);
  74. fz_write_printf(ctx, out, "%05d: %010d %05d %c \n",
  75. i,
  76. (int)entry->ofs,
  77. entry->gen,
  78. entry->type ? entry->type : '-');
  79. }
  80. }
  81. static void showpages(fz_context *ctx)
  82. {
  83. pdf_obj *ref;
  84. int i, n = pdf_count_pages(ctx, doc);
  85. for (i = 0; i < n; ++i)
  86. {
  87. ref = pdf_lookup_page_obj(ctx, doc, i);
  88. fz_write_printf(ctx, out, "page %d = %d 0 R\n", i + 1, pdf_to_num(ctx, ref));
  89. }
  90. }
  91. static void showsafe(unsigned char *buf, size_t n)
  92. {
  93. size_t i;
  94. for (i = 0; i < n; i++) {
  95. if (buf[i] == '\r' || buf[i] == '\n') {
  96. putchar('\n');
  97. showcolumn = 0;
  98. }
  99. else if (buf[i] < 32 || buf[i] > 126) {
  100. putchar('.');
  101. showcolumn ++;
  102. }
  103. else {
  104. putchar(buf[i]);
  105. showcolumn ++;
  106. }
  107. if (showcolumn == 79) {
  108. putchar('\n');
  109. showcolumn = 0;
  110. }
  111. }
  112. }
  113. static void showstream(fz_context *ctx, int num)
  114. {
  115. fz_stream *stm;
  116. unsigned char buf[2048];
  117. size_t n;
  118. showcolumn = 0;
  119. if (showdecode)
  120. stm = pdf_open_stream_number(ctx, doc, num);
  121. else
  122. stm = pdf_open_raw_stream_number(ctx, doc, num);
  123. while (1)
  124. {
  125. n = fz_read(ctx, stm, buf, sizeof buf);
  126. if (n == 0)
  127. break;
  128. if (showbinary)
  129. fz_write_data(ctx, out, buf, n);
  130. else
  131. showsafe(buf, n);
  132. }
  133. fz_drop_stream(ctx, stm);
  134. }
  135. static void showlabel(fz_context *ctx, void *arg, const char *label)
  136. {
  137. fz_write_printf(ctx, arg, "%% %s\n", label);
  138. }
  139. static void showobject(fz_context *ctx, pdf_obj *ref)
  140. {
  141. pdf_obj *obj = pdf_resolve_indirect(ctx, ref);
  142. int num = pdf_to_num(ctx, ref);
  143. if (pdf_is_stream(ctx, ref))
  144. {
  145. if (showbinary)
  146. {
  147. showstream(ctx, num);
  148. }
  149. else
  150. {
  151. if (do_label)
  152. pdf_label_object(ctx, labels, num, showlabel, out);
  153. if (do_tight)
  154. {
  155. fz_write_printf(ctx, out, "%d 0 obj ", num);
  156. pdf_print_obj(ctx, out, obj, 1, 1);
  157. fz_write_printf(ctx, out, " stream\n");
  158. }
  159. else
  160. {
  161. fz_write_printf(ctx, out, "%d 0 obj\n", num);
  162. pdf_print_obj(ctx, out, obj, 0, 1);
  163. fz_write_printf(ctx, out, "\nstream\n");
  164. showstream(ctx, num);
  165. fz_write_printf(ctx, out, "endstream\n");
  166. fz_write_printf(ctx, out, "endobj\n");
  167. }
  168. }
  169. }
  170. else
  171. {
  172. if (do_label)
  173. pdf_label_object(ctx, labels, num, showlabel, out);
  174. if (do_tight)
  175. {
  176. fz_write_printf(ctx, out, "%d 0 obj ", num);
  177. pdf_print_obj(ctx, out, obj, 1, 1);
  178. fz_write_printf(ctx, out, "\n");
  179. }
  180. else
  181. {
  182. fz_write_printf(ctx, out, "%d 0 obj\n", num);
  183. pdf_print_obj(ctx, out, obj, 0, 1);
  184. fz_write_printf(ctx, out, "\nendobj\n");
  185. }
  186. }
  187. }
  188. static void showgrep(fz_context *ctx)
  189. {
  190. pdf_obj *ref, *obj;
  191. int i, len;
  192. len = pdf_count_objects(ctx, doc);
  193. for (i = 0; i < len; i++)
  194. {
  195. pdf_xref_entry *entry = pdf_get_xref_entry_no_null(ctx, doc, i);
  196. if (entry->type == 'n' || entry->type == 'o')
  197. {
  198. fz_try(ctx)
  199. {
  200. ref = pdf_new_indirect(ctx, doc, i, 0);
  201. obj = pdf_resolve_indirect(ctx, ref);
  202. }
  203. fz_catch(ctx)
  204. {
  205. pdf_drop_obj(ctx, ref);
  206. fz_warn(ctx, "skipping object (%d 0 R)", i);
  207. continue;
  208. }
  209. pdf_sort_dict(ctx, obj);
  210. fz_write_printf(ctx, out, "%d 0 obj ", i);
  211. pdf_print_obj(ctx, out, obj, 1, 1);
  212. if (pdf_is_stream(ctx, ref))
  213. fz_write_printf(ctx, out, " stream");
  214. fz_write_printf(ctx, out, "\n");
  215. pdf_drop_obj(ctx, ref);
  216. }
  217. }
  218. fz_write_printf(ctx, out, "trailer ");
  219. pdf_print_obj(ctx, out, pdf_trailer(ctx, doc), 1, 1);
  220. fz_write_printf(ctx, out, "\n");
  221. }
  222. static void
  223. print_outline(fz_context *ctx, fz_outline *outline, int level)
  224. {
  225. int i;
  226. while (outline)
  227. {
  228. if (outline->down)
  229. fz_write_byte(ctx, out, outline->is_open ? '-' : '+');
  230. else
  231. fz_write_byte(ctx, out, '|');
  232. for (i = 0; i < level; i++)
  233. fz_write_byte(ctx, out, '\t');
  234. fz_write_printf(ctx, out, "%Q\t%s\n", outline->title, outline->uri);
  235. if (outline->down)
  236. print_outline(ctx, outline->down, level + 1);
  237. outline = outline->next;
  238. }
  239. }
  240. static void showoutline(fz_context *ctx)
  241. {
  242. fz_outline *outline = fz_load_outline(ctx, (fz_document*)doc);
  243. fz_try(ctx)
  244. print_outline(ctx, outline, 1);
  245. fz_always(ctx)
  246. fz_drop_outline(ctx, outline);
  247. fz_catch(ctx)
  248. fz_rethrow(ctx);
  249. }
  250. static void showtext(fz_context *ctx, char *buf, int indent)
  251. {
  252. int bol = 1;
  253. int c = *buf;
  254. while (*buf)
  255. {
  256. c = *buf++;
  257. if (c == '\r')
  258. {
  259. if (*buf == '\n')
  260. ++buf;
  261. c = '\n';
  262. }
  263. if (indent && bol)
  264. fz_write_byte(ctx, out, '\t');
  265. fz_write_byte(ctx, out, c);
  266. bol = (c == '\n');
  267. }
  268. if (!bol)
  269. fz_write_byte(ctx, out, '\n');
  270. }
  271. static void showjs(fz_context *ctx)
  272. {
  273. pdf_obj *tree;
  274. int i;
  275. tree = pdf_load_name_tree(ctx, doc, PDF_NAME(JavaScript));
  276. for (i = 0; i < pdf_dict_len(ctx, tree); ++i)
  277. {
  278. pdf_obj *name = pdf_dict_get_key(ctx, tree, i);
  279. pdf_obj *action = pdf_dict_get_val(ctx, tree, i);
  280. pdf_obj *js = pdf_dict_get(ctx, action, PDF_NAME(JS));
  281. char *src = pdf_load_stream_or_string_as_utf8(ctx, js);
  282. fz_write_printf(ctx, out, "// %s\n", pdf_to_name(ctx, name));
  283. showtext(ctx, src, 0);
  284. fz_free(ctx, src);
  285. }
  286. }
  287. static void showaction(fz_context *ctx, pdf_obj *action, const char *name)
  288. {
  289. if (action)
  290. {
  291. pdf_obj *js = pdf_dict_get(ctx, action, PDF_NAME(JS));
  292. if (js)
  293. {
  294. char *src = pdf_load_stream_or_string_as_utf8(ctx, js);
  295. fz_write_printf(ctx, out, " %s: {\n", name);
  296. showtext(ctx, src, 1);
  297. fz_write_printf(ctx, out, " }\n", name);
  298. fz_free(ctx, src);
  299. }
  300. else
  301. {
  302. fz_write_printf(ctx, out, " %s: ", name);
  303. if (pdf_is_indirect(ctx, action))
  304. action = pdf_resolve_indirect(ctx, action);
  305. pdf_print_obj(ctx, out, action, 1, 1);
  306. fz_write_printf(ctx, out, "\n");
  307. }
  308. }
  309. }
  310. static void showfield(fz_context *ctx, pdf_obj *field)
  311. {
  312. pdf_obj *kids, *ft, *parent;
  313. const char *tu;
  314. char *t;
  315. int ff;
  316. int i, n;
  317. t = pdf_load_field_name(ctx, field);
  318. tu = pdf_dict_get_text_string(ctx, field, PDF_NAME(TU));
  319. ft = pdf_dict_get_inheritable(ctx, field, PDF_NAME(FT));
  320. ff = pdf_field_flags(ctx, field);
  321. parent = pdf_dict_get(ctx, field, PDF_NAME(Parent));
  322. fz_write_printf(ctx, out, "field %d\n", pdf_to_num(ctx, field));
  323. fz_write_printf(ctx, out, " Type: %s\n", pdf_to_name(ctx, ft));
  324. if (ff)
  325. {
  326. fz_write_printf(ctx, out, " Flags:");
  327. if (ff & PDF_FIELD_IS_READ_ONLY) fz_write_string(ctx, out, " readonly");
  328. if (ff & PDF_FIELD_IS_REQUIRED) fz_write_string(ctx, out, " required");
  329. if (ff & PDF_FIELD_IS_NO_EXPORT) fz_write_string(ctx, out, " noExport");
  330. if (ft == PDF_NAME(Btn))
  331. {
  332. if (ff & PDF_BTN_FIELD_IS_NO_TOGGLE_TO_OFF) fz_write_string(ctx, out, " noToggleToOff");
  333. if (ff & PDF_BTN_FIELD_IS_RADIO) fz_write_string(ctx, out, " radio");
  334. if (ff & PDF_BTN_FIELD_IS_PUSHBUTTON) fz_write_string(ctx, out, " pushButton");
  335. if (ff & PDF_BTN_FIELD_IS_RADIOS_IN_UNISON) fz_write_string(ctx, out, " radiosInUnison");
  336. }
  337. if (ft == PDF_NAME(Tx))
  338. {
  339. if (ff & PDF_TX_FIELD_IS_MULTILINE) fz_write_string(ctx, out, " multiline");
  340. if (ff & PDF_TX_FIELD_IS_PASSWORD) fz_write_string(ctx, out, " password");
  341. if (ff & PDF_TX_FIELD_IS_FILE_SELECT) fz_write_string(ctx, out, " fileSelect");
  342. if (ff & PDF_TX_FIELD_IS_DO_NOT_SPELL_CHECK) fz_write_string(ctx, out, " dontSpellCheck");
  343. if (ff & PDF_TX_FIELD_IS_DO_NOT_SCROLL) fz_write_string(ctx, out, " dontScroll");
  344. if (ff & PDF_TX_FIELD_IS_COMB) fz_write_string(ctx, out, " comb");
  345. if (ff & PDF_TX_FIELD_IS_RICH_TEXT) fz_write_string(ctx, out, " richText");
  346. }
  347. if (ft == PDF_NAME(Ch))
  348. {
  349. if (ff & PDF_CH_FIELD_IS_COMBO) fz_write_string(ctx, out, " combo");
  350. if (ff & PDF_CH_FIELD_IS_EDIT) fz_write_string(ctx, out, " edit");
  351. if (ff & PDF_CH_FIELD_IS_SORT) fz_write_string(ctx, out, " sort");
  352. if (ff & PDF_CH_FIELD_IS_MULTI_SELECT) fz_write_string(ctx, out, " multiSelect");
  353. if (ff & PDF_CH_FIELD_IS_DO_NOT_SPELL_CHECK) fz_write_string(ctx, out, " dontSpellCheck");
  354. if (ff & PDF_CH_FIELD_IS_COMMIT_ON_SEL_CHANGE) fz_write_string(ctx, out, " commitOnSelChange");
  355. }
  356. fz_write_string(ctx, out, "\n");
  357. }
  358. fz_write_printf(ctx, out, " Name: %(\n", t);
  359. fz_free(ctx, t);
  360. if (*tu)
  361. fz_write_printf(ctx, out, " Label: %q\n", tu);
  362. if (parent)
  363. fz_write_printf(ctx, out, " Parent: %d\n", pdf_to_num(ctx, parent));
  364. showaction(ctx, pdf_dict_getp(ctx, field, "A"), "Action");
  365. showaction(ctx, pdf_dict_getp_inheritable(ctx, field, "AA/K"), "Keystroke");
  366. showaction(ctx, pdf_dict_getp_inheritable(ctx, field, "AA/V"), "Validate");
  367. showaction(ctx, pdf_dict_getp_inheritable(ctx, field, "AA/F"), "Format");
  368. showaction(ctx, pdf_dict_getp_inheritable(ctx, field, "AA/C"), "Calculate");
  369. showaction(ctx, pdf_dict_getp_inheritable(ctx, field, "AA/E"), "Enter");
  370. showaction(ctx, pdf_dict_getp_inheritable(ctx, field, "AA/X"), "Exit");
  371. showaction(ctx, pdf_dict_getp_inheritable(ctx, field, "AA/D"), "Down");
  372. showaction(ctx, pdf_dict_getp_inheritable(ctx, field, "AA/U"), "Up");
  373. showaction(ctx, pdf_dict_getp_inheritable(ctx, field, "AA/Fo"), "Focus");
  374. showaction(ctx, pdf_dict_getp_inheritable(ctx, field, "AA/Bl"), "Blur");
  375. fz_write_string(ctx, out, "\n");
  376. kids = pdf_dict_get(ctx, field, PDF_NAME(Kids));
  377. n = pdf_array_len(ctx, kids);
  378. for (i = 0; i < n; ++i)
  379. showfield(ctx, pdf_array_get(ctx, kids, i));
  380. }
  381. static void showform(fz_context *ctx)
  382. {
  383. pdf_obj *fields;
  384. int i, n;
  385. fields = pdf_dict_getp(ctx, pdf_trailer(ctx, doc), "Root/AcroForm/Fields");
  386. n = pdf_array_len(ctx, fields);
  387. for (i = 0; i < n; ++i)
  388. showfield(ctx, pdf_array_get(ctx, fields, i));
  389. }
  390. #define SEP ".[]/"
  391. static int isnumber(char *s)
  392. {
  393. if (*s == '-')
  394. s++;
  395. while (*s)
  396. {
  397. if (*s < '0' || *s > '9')
  398. return 0;
  399. ++s;
  400. }
  401. return 1;
  402. }
  403. static void showpath(fz_context *ctx, char *path, pdf_obj *obj)
  404. {
  405. if (path && path[0])
  406. {
  407. char *part = fz_strsep(&path, SEP);
  408. if (part && part[0])
  409. {
  410. if (!strcmp(part, "*"))
  411. {
  412. int i, n;
  413. char buf[1000];
  414. if (pdf_is_array(ctx, obj))
  415. {
  416. n = pdf_array_len(ctx, obj);
  417. for (i = 0; i < n; ++i)
  418. {
  419. if (path)
  420. {
  421. fz_strlcpy(buf, path, sizeof buf);
  422. showpath(ctx, buf, pdf_array_get(ctx, obj, i));
  423. }
  424. else
  425. showpath(ctx, NULL, pdf_array_get(ctx, obj, i));
  426. }
  427. }
  428. else if (pdf_is_dict(ctx, obj))
  429. {
  430. n = pdf_dict_len(ctx, obj);
  431. for (i = 0; i < n; ++i)
  432. {
  433. if (path)
  434. {
  435. fz_strlcpy(buf, path, sizeof buf);
  436. showpath(ctx, buf, pdf_dict_get_val(ctx, obj, i));
  437. }
  438. else
  439. showpath(ctx, NULL, pdf_dict_get_val(ctx, obj, i));
  440. }
  441. }
  442. else
  443. {
  444. fz_write_string(ctx, out, "null\n");
  445. }
  446. }
  447. else if (isnumber(part) && pdf_is_array(ctx, obj))
  448. {
  449. int num = atoi(part);
  450. num = num < 0 ? pdf_array_len(ctx, obj) + num : num - 1;
  451. showpath(ctx, path, pdf_array_get(ctx, obj, num));
  452. }
  453. else
  454. showpath(ctx, path, pdf_dict_gets(ctx, obj, part));
  455. }
  456. else
  457. fz_write_string(ctx, out, "null\n");
  458. }
  459. else
  460. {
  461. if (pdf_is_indirect(ctx, obj))
  462. showobject(ctx, obj);
  463. else
  464. {
  465. pdf_print_obj(ctx, out, obj, do_tight, 0);
  466. fz_write_string(ctx, out, "\n");
  467. }
  468. }
  469. }
  470. static void showpathpage(fz_context *ctx, char *path)
  471. {
  472. if (path)
  473. {
  474. char *part = fz_strsep(&path, SEP);
  475. if (part && part[0])
  476. {
  477. if (!strcmp(part, "*"))
  478. {
  479. int i, n;
  480. char buf[1000];
  481. n = pdf_count_pages(ctx, doc);
  482. for (i = 0; i < n; ++i)
  483. {
  484. if (path)
  485. {
  486. fz_strlcpy(buf, path, sizeof buf);
  487. showpath(ctx, buf, pdf_lookup_page_obj(ctx, doc, i));
  488. }
  489. else
  490. showpath(ctx, NULL, pdf_lookup_page_obj(ctx, doc, i));
  491. }
  492. }
  493. else if (isnumber(part))
  494. {
  495. int num = atoi(part);
  496. num = num < 0 ? pdf_count_pages(ctx, doc) + num : num - 1;
  497. showpath(ctx, path, pdf_lookup_page_obj(ctx, doc, num));
  498. }
  499. else
  500. fz_write_string(ctx, out, "null\n");
  501. }
  502. else
  503. fz_write_string(ctx, out, "null\n");
  504. }
  505. else
  506. {
  507. showpages(ctx);
  508. }
  509. }
  510. static void showpathroot(fz_context *ctx, char *path)
  511. {
  512. char buf[2000], *list = buf, *part;
  513. fz_strlcpy(buf, path, sizeof buf);
  514. part = fz_strsep(&list, SEP);
  515. if (part && part[0])
  516. {
  517. if (!strcmp(part, "trailer"))
  518. showpath(ctx, list, pdf_trailer(ctx, doc));
  519. else if (!strcmp(part, "pages"))
  520. showpathpage(ctx, list);
  521. else if (isnumber(part))
  522. {
  523. pdf_obj *obj;
  524. int num = atoi(part);
  525. num = num < 0 ? pdf_xref_len(ctx, doc) + num : num;
  526. obj = pdf_new_indirect(ctx, doc, num, 0);
  527. fz_try(ctx)
  528. showpath(ctx, list, obj);
  529. fz_always(ctx)
  530. pdf_drop_obj(ctx, obj);
  531. fz_catch(ctx)
  532. ;
  533. }
  534. else
  535. showpath(ctx, list, pdf_dict_gets(ctx, pdf_trailer(ctx, doc), part));
  536. }
  537. else
  538. fz_write_string(ctx, out, "null\n");
  539. }
  540. static void show(fz_context *ctx, char *sel)
  541. {
  542. if (!strcmp(sel, "trailer"))
  543. showtrailer(ctx);
  544. else if (!strcmp(sel, "xref"))
  545. showxref(ctx);
  546. else if (!strcmp(sel, "pages"))
  547. showpages(ctx);
  548. else if (!strcmp(sel, "grep"))
  549. showgrep(ctx);
  550. else if (!strcmp(sel, "outline"))
  551. showoutline(ctx);
  552. else if (!strcmp(sel, "js"))
  553. showjs(ctx);
  554. else if (!strcmp(sel, "form"))
  555. showform(ctx);
  556. else
  557. showpathroot(ctx, sel);
  558. }
  559. int pdfshow_main(int argc, char **argv)
  560. {
  561. char *password = NULL; /* don't throw errors if encrypted */
  562. char *filename = NULL;
  563. char *output = NULL;
  564. int c;
  565. int errored = 0;
  566. fz_context *ctx = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED);
  567. if (!ctx)
  568. {
  569. fprintf(stderr, "cannot initialise context\n");
  570. exit(1);
  571. }
  572. while ((c = fz_getopt(argc, argv, "p:o:begrL")) != -1)
  573. {
  574. switch (c)
  575. {
  576. case 'p': password = fz_optarg; break;
  577. case 'o': output = fz_optarg; break;
  578. case 'b': showbinary = 1; break;
  579. case 'e': showdecode = 0; break;
  580. case 'g': do_tight = 1; break;
  581. case 'r': do_repair = 1; break;
  582. case 'L': do_label = 1; break;
  583. default: return usage();
  584. }
  585. }
  586. if (fz_optind == argc)
  587. return usage();
  588. filename = argv[fz_optind++];
  589. if (output)
  590. out = fz_new_output_with_path(ctx, output, 0);
  591. else
  592. out = fz_stdout(ctx);
  593. fz_var(doc);
  594. fz_var(labels);
  595. fz_try(ctx)
  596. {
  597. doc = pdf_open_document(ctx, filename);
  598. if (pdf_needs_password(ctx, doc))
  599. if (!pdf_authenticate_password(ctx, doc, password))
  600. fz_warn(ctx, "cannot authenticate password: %s", filename);
  601. if (do_repair)
  602. {
  603. fz_try(ctx)
  604. {
  605. pdf_repair_xref(ctx, doc);
  606. }
  607. fz_catch(ctx)
  608. {
  609. fz_rethrow_if(ctx, FZ_ERROR_TRYLATER);
  610. fz_rethrow_if(ctx, FZ_ERROR_SYSTEM);
  611. fz_rethrow_if(ctx, FZ_ERROR_REPAIRED);
  612. fz_report_error(ctx);
  613. }
  614. }
  615. if (do_label)
  616. labels = pdf_load_object_labels(ctx, doc);
  617. if (fz_optind == argc)
  618. showtrailer(ctx);
  619. while (fz_optind < argc)
  620. show(ctx, argv[fz_optind++]);
  621. }
  622. fz_always(ctx)
  623. {
  624. fz_close_output(ctx, out);
  625. fz_drop_output(ctx, out);
  626. pdf_drop_object_labels(ctx, labels);
  627. pdf_drop_document(ctx, doc);
  628. }
  629. fz_catch(ctx)
  630. {
  631. fz_report_error(ctx);
  632. errored = 1;
  633. }
  634. fz_drop_context(ctx);
  635. return errored;
  636. }