From 767c59e8bde7feae04c4eab04a3a38bbc9ce71e9 Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Thu, 10 Nov 2011 14:38:36 +0100 Subject: [PATCH] tpdftoc: Added a simple tool to display a PDF's TOC. For now, a simple ASCII output is supported only. --- .gitignore | 1 + src/Makefile.am | 9 +- src/tpdftoc.c | 220 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 228 insertions(+), 2 deletions(-) create mode 100644 src/tpdftoc.c diff --git a/.gitignore b/.gitignore index 423f122..8daf649 100644 --- a/.gitignore +++ b/.gitignore @@ -23,5 +23,6 @@ ltmain.sh *.lo *.o tpdfview +tpdftoc tpdfv_features.h diff --git a/src/Makefile.am b/src/Makefile.am index 6dda19a..3615d5d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -16,14 +16,19 @@ libtpdfv_la_LDFLAGS = -version-info 0:0:0 \ @GTK2_LIBS@ \ @POPPLER_GLIB_LIBS@ -bin_PROGRAMS = tpdfview +bin_PROGRAMS = tpdfview tpdftoc -tpdfview_SOURCES = tpdfview.c tpdfv.h +tpdfview_SOURCES = tpdfview.c tpdfv.h tpdfv_features.h tpdfview_CFLAGS = $(AM_CFLAGS) -DBUILD_DATE="\"$$( date --utc '+%F %T' ) (UTC)\"" \ @GTK2_CFLAGS@ tpdfview_LDFLAGS = @GTK2_LIBS@ tpdfview_LDADD = libtpdfv.la +tpdftoc_SOURCES = tpdftoc.c tpdfv.h tpdfv_features.h +tpdftoc_CFLAGS = $(AM_CFLAGS) -DBUILD_DATE="\"$$( date --utc '+%F %T' ) (UTC)\"" \ + @POPPLER_GLIB_CFLAGS@ +tpdftoc_LDFLAGS = @POPPLER_GLIB_LIBS@ + ../version: FORCE @# As a side-effect, this updates ../version. @echo Building $(PACKAGE_NAME) version $$( cd .. && ./version-gen.sh ) diff --git a/src/tpdftoc.c b/src/tpdftoc.c new file mode 100644 index 0000000..5d7d092 --- /dev/null +++ b/src/tpdftoc.c @@ -0,0 +1,220 @@ +/* + * tpdfview - src/tpdftoc.c + * Copyright (C) 2011 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * A tiny tool to display the TOC of PDF documents. + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include "tpdfv.h" +#include "tpdfv_features.h" + +#if HAVE_LIBGEN_H +# include +#else /* HAVE_LIBGEN_H */ +# define basename(path) (path) +#endif /* ! HAVE_LIBGEN_H */ + +#include + +#include + +#include +#include + +#include + +#include + +#include + +static void +exit_usage(char *name, int status) +{ + printf( +"Usage: %s [] \n" + +"\nA tiny PDF viewer - display the TOC of a PDF document.\n" + +"\nOptions:\n" +" -h display this help and exit\n" +" -V display the version number and copyright\n" + +"\ntpdfview "TPDFV_VERSION_STRING TPDFV_VERSION_EXTRA", "PACKAGE_URL"\n" +"Copyright (C) 2011 "PACKAGE_MAINTAINER"\n", +basename(name)); + exit(status); +} /* exit_usage */ + +static void +exit_version(void) +{ + printf("tpdfview version "TPDFV_VERSION_STRING TPDFV_VERSION_EXTRA", " + "built "BUILD_DATE"\n" + "Copyright (C) 2011 "PACKAGE_MAINTAINER"\n" + + "\nThis is free software under the terms of the BSD license, see " + "the source for\ncopying conditions. There is NO WARRANTY; not " + "even for MERCHANTABILITY or\nFITNESS FOR A PARTICULAR " + "PURPOSE.\n"); + exit(0); +} /* exit_version */ + +static void +walk_pdf_toc(PopplerDocument *doc, PopplerIndexIter *iter, int depth) +{ + if (! iter) + return; + + do { + PopplerAction *action; + PopplerDest *dest; + + char *entry_title; + int entry_pagenum; + + PopplerIndexIter *child; + + int i; + + action = poppler_index_iter_get_action(iter); + + if (action->type != POPPLER_ACTION_GOTO_DEST) { + poppler_action_free(action); + return; + } + + dest = ((PopplerActionGotoDest *)action)->dest; + entry_title = ((PopplerActionGotoDest *)action)->title; + entry_pagenum = dest->page_num; + + if (dest->type == POPPLER_DEST_NAMED) { + dest = poppler_document_find_dest(doc, dest->named_dest); + if (dest) { + entry_pagenum = dest->page_num; + poppler_dest_free(dest); + dest = NULL; + } + } + + for (i = 0; i < depth - 1; ++i) + printf(" "); + if (i < depth) + printf(" |- "); + printf("%s %i\n", entry_title, entry_pagenum); + + poppler_action_free(action); + action = NULL; + + child = poppler_index_iter_get_child(iter); + if (! child) + continue; + + walk_pdf_toc(doc, child, depth + 1); + poppler_index_iter_free(child); + } while (poppler_index_iter_next(iter)); +} /* walk_pdf_index */ + +int +main(int argc, char **argv) +{ + PopplerDocument *doc; + PopplerIndexIter *iter; + GError *err = NULL; + + char *filename; + + g_type_init(); + + while (42) { + int opt = getopt(argc, argv, "hV"); + + if (-1 == opt) + break; + + switch (opt) { + case 'h': + exit_usage(argv[0], 0); + break; + case 'V': + exit_version(); + break; + default: + exit_usage(argv[0], 1); + } + } + + if (argc - optind != 1) { + fprintf(stderr, "%s: missing filename\n", argv[0]); + exit_usage(argv[0], 1); + } + + /* XXX: move this into libtpdfv as well. */ + if (strstr(argv[optind], "://")) + filename = strdup(argv[optind]); + else { + size_t len = strlen("file://") + strlen(argv[optind]); + filename = (char *)malloc(len + 1); + if (filename) { + *filename = '\0'; + strncat(filename, "file://", len); + strncat(filename, argv[optind], len - strlen("file://")); + } + } + + if (! filename) { + char errbuf[1024]; + strerror_r(errno, errbuf, sizeof(errbuf)); + fprintf(stderr, "Failed to allocate string: %s.\n", errbuf); + return 1; + } + + doc = poppler_document_new_from_file(filename, + /* password = */ NULL, &err); + if (! doc) { + fprintf(stderr, "Failed to open PDF: %s.\n", err->message); + return 1; + } + + iter = poppler_index_iter_new(doc); + if (! iter) { + /* no index */ + return 0; + } + + walk_pdf_toc(doc, iter, 0); + + poppler_index_iter_free(iter); + free(filename); + return 0; +} /* main */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + -- 2.30.2