diff options
-rw-r--r-- | apps/pdfapp.c | 2 | ||||
-rw-r--r-- | apps/pdfapp.h | 2 | ||||
-rw-r--r-- | apps/pdfdraw.c | 50 | ||||
-rw-r--r-- | apps/xpsdraw.c | 31 | ||||
-rw-r--r-- | fitz/doc_outline.c | 49 | ||||
-rw-r--r-- | fitz/fitz.h | 18 | ||||
-rw-r--r-- | ios/document.c | 11 | ||||
-rw-r--r-- | ios/document.h | 1 | ||||
-rw-r--r-- | ios/main.m | 66 | ||||
-rw-r--r-- | pdf/mupdf.h | 14 | ||||
-rw-r--r-- | pdf/pdf_outline.c | 66 | ||||
-rw-r--r-- | win32/libmupdf.vcproj | 7 | ||||
-rw-r--r-- | xps/muxps.h | 19 | ||||
-rw-r--r-- | xps/xps_doc.c | 113 | ||||
-rw-r--r-- | xps/xps_outline.c | 124 | ||||
-rw-r--r-- | xps/xps_xml.c | 2 |
16 files changed, 393 insertions, 182 deletions
diff --git a/apps/pdfapp.c b/apps/pdfapp.c index 3050145f..ab29fcb9 100644 --- a/apps/pdfapp.c +++ b/apps/pdfapp.c @@ -235,7 +235,7 @@ void pdfapp_close(pdfapp_t *app) app->image = NULL; if (app->outline) - pdf_free_outline(app->outline); + fz_free_outline(app->outline); app->outline = NULL; if (app->xref) diff --git a/apps/pdfapp.h b/apps/pdfapp.h index a3829b3e..270c450a 100644 --- a/apps/pdfapp.h +++ b/apps/pdfapp.h @@ -31,7 +31,7 @@ struct pdfapp_s /* current document params */ char *doctitle; pdf_xref *xref; - pdf_outline *outline; + fz_outline *outline; xps_context *xps; int pagecount; diff --git a/apps/pdfdraw.c b/apps/pdfdraw.c index 90db4c1b..d79cd75c 100644 --- a/apps/pdfdraw.c +++ b/apps/pdfdraw.c @@ -297,54 +297,14 @@ static void drawrange(pdf_xref *xref, char *range) } } -static int get_page_number(pdf_xref *xref, pdf_link *link) -{ - if (link->kind == PDF_LINK_GOTO) - return pdf_find_page_number(xref, fz_array_get(link->dest, 0)); - return 0; -} - -static void print_outline_xml(pdf_xref *xref, pdf_outline *outline, int level) -{ - int page; - printf("<outline>\n"); - while (outline) - { - page = get_page_number(xref, outline->link); - printf("<link title=\"%s\" page=\"%d\" />\n", - outline->title ? outline->title : "<null>", page); - if (outline->child) - print_outline_xml(xref, outline->child, level + 1); - outline = outline->next; - } - printf("</outline>\n"); -} - -static void print_outline_plain(pdf_xref *xref, pdf_outline *outline, int level) -{ - int i, page; - while (outline) - { - page = get_page_number(xref, outline->link); - for (i = 0; i < level; i++) - putchar('\t'); - printf("%s %d\n", outline->title ? outline->title : "<null>", page); - if (outline->child) - print_outline_plain(xref, outline->child, level + 1); - outline = outline->next; - } -} - static void drawoutline(pdf_xref *xref) { - pdf_outline *outline = pdf_load_outline(xref); - if (showoutline > 2) - pdf_debug_outline(outline, 0); - else if (showoutline > 1) - print_outline_xml(xref, outline, 0); + fz_outline *outline = pdf_load_outline(xref); + if (showoutline > 1) + fz_debug_outline_xml(outline, 0); else - print_outline_plain(xref, outline, 0); - pdf_free_outline(outline); + fz_debug_outline(outline, 0); + fz_free_outline(outline); } int main(int argc, char **argv) diff --git a/apps/xpsdraw.c b/apps/xpsdraw.c index 29738e6b..1d2992bc 100644 --- a/apps/xpsdraw.c +++ b/apps/xpsdraw.c @@ -14,6 +14,7 @@ int showxml = 0; int showtext = 0; int showtime = 0; int showmd5 = 0; +int showoutline = 0; int savealpha = 0; int uselist = 1; @@ -47,6 +48,7 @@ static void usage(void) "\t-x\tshow display list\n" "\t-d\tdisable use of display list\n" "\t-5\tshow md5 checksums\n" + "\t-l\tprint outline\n" "\tpages\tcomma separated list of ranges\n"); exit(1); } @@ -272,6 +274,16 @@ static void drawrange(xps_context *ctx, char *range) } } +static void drawoutline(xps_context *ctx) +{ + fz_outline *outline = xps_load_outline(ctx); + if (showoutline > 1) + fz_debug_outline_xml(outline, 0); + else + fz_debug_outline(outline, 0); + fz_free_outline(outline); +} + int main(int argc, char **argv) { int grayscale = 0; @@ -280,7 +292,7 @@ int main(int argc, char **argv) int code; int c; - while ((c = fz_getopt(argc, argv, "o:p:r:Aadgmtx5")) != -1) + while ((c = fz_getopt(argc, argv, "o:p:r:Aadglmtx5")) != -1) { switch (c) { @@ -288,6 +300,7 @@ int main(int argc, char **argv) case 'r': resolution = atof(fz_optarg); break; case 'A': accelerate = 0; break; case 'a': savealpha = 1; break; + case 'l': showoutline++; break; case 'm': showtime++; break; case 't': showtext++; break; case 'x': showxml++; break; @@ -301,7 +314,7 @@ int main(int argc, char **argv) if (fz_optind == argc) usage(); - if (!showtext && !showxml && !showtime && !showmd5 && !output) + if (!showtext && !showxml && !showtime && !showmd5 && !showoutline && !output) { printf("nothing to do\n"); exit(0); @@ -341,10 +354,16 @@ int main(int argc, char **argv) if (showxml) printf("<document name=\"%s\">\n", filename); - if (fz_optind == argc || !isrange(argv[fz_optind])) - drawrange(ctx, "1-"); - if (fz_optind < argc && isrange(argv[fz_optind])) - drawrange(ctx, argv[fz_optind++]); + if (showoutline) + drawoutline(ctx); + + if (showtext || showxml || showtime || showmd5 || output) + { + if (fz_optind == argc || !isrange(argv[fz_optind])) + drawrange(ctx, "1-"); + if (fz_optind < argc && isrange(argv[fz_optind])) + drawrange(ctx, argv[fz_optind++]); + } if (showxml) printf("</document>\n"); diff --git a/fitz/doc_outline.c b/fitz/doc_outline.c new file mode 100644 index 00000000..ea3906ac --- /dev/null +++ b/fitz/doc_outline.c @@ -0,0 +1,49 @@ +#include "fitz.h" + +void +fz_free_outline(fz_outline *outline) +{ + while (outline) + { + fz_outline *next = outline->next; + fz_free_outline(outline->down); + fz_free(outline->title); + fz_free(outline); + outline = next; + } +} + +void +fz_debug_outline_xml(fz_outline *outline, int level) +{ + while (outline) + { + printf("<outline title=\"%s\" page=\"%d\"", outline->title, outline->page); + if (outline->down) + { + printf(">\n"); + fz_debug_outline_xml(outline->down, level + 1); + printf("</outline>\n"); + } + else + { + printf(" />\n"); + } + outline = outline->next; + } +} + +void +fz_debug_outline(fz_outline *outline, int level) +{ + int i; + while (outline) + { + for (i = 0; i < level; i++) + putchar('\t'); + printf("%s\t%d\n", outline->title, outline->page); + if (outline->down) + fz_debug_outline(outline->down, level + 1); + outline = outline->next; + } +} diff --git a/fitz/fitz.h b/fitz/fitz.h index dff6b8d4..5529384d 100644 --- a/fitz/fitz.h +++ b/fitz/fitz.h @@ -1064,6 +1064,24 @@ fz_device *fz_new_list_device(fz_display_list *list); void fz_execute_display_list(fz_display_list *list, fz_device *dev, fz_matrix ctm, fz_bbox area); /* + * Document interface. + */ + +typedef struct fz_outline_s fz_outline; + +struct fz_outline_s +{ + char *title; + int page; + fz_outline *next; + fz_outline *down; +}; + +void fz_debug_outline_xml(fz_outline *outline, int level); +void fz_debug_outline(fz_outline *outline, int level); +void fz_free_outline(fz_outline *outline); + +/* * Plotting functions. */ diff --git a/ios/document.c b/ios/document.c index 85f8e381..6d30a0bc 100644 --- a/ios/document.c +++ b/ios/document.c @@ -43,6 +43,17 @@ open_document(char *filename) } } +fz_outline * +load_outline(struct document *doc) +{ + if (doc->pdf) + return pdf_load_outline(doc->pdf); + else if (doc->xps) + return xps_load_outline(doc->xps); + else + return NULL; +} + int count_pages(struct document *doc) { diff --git a/ios/document.h b/ios/document.h index a16de309..1f59ccdd 100644 --- a/ios/document.h +++ b/ios/document.h @@ -23,6 +23,7 @@ struct document }; struct document *open_document(char *filename); +fz_outline *load_outline(struct document *doc); int count_pages(struct document *doc); void measure_page(struct document *doc, int number, float *w, float *h); void draw_page(struct document *doc, int number, fz_device *dev, fz_matrix ctm); @@ -1,7 +1,5 @@ #import <UIKit/UIKit.h> -// TODO: [[UIScreen mainScreen] scale]; -- for retina iphone 4 displays we want double resolution! - #undef ABS #undef MIN #undef MAX @@ -118,37 +116,27 @@ static void showAlert(NSString *msg) [alert release]; } -static int pageNumberFromLink(pdf_xref *xref, pdf_link *link) +static void flattenOutline(NSMutableArray *titles, NSMutableArray *pages, fz_outline *outline, int level) { - if (link->kind == PDF_LINK_GOTO) - return pdf_find_page_number(xref, fz_array_get(link->dest, 0)); - return -1; -} - -static void loadOutlineImp(NSMutableArray *titles, NSMutableArray *pages, pdf_xref *xref, pdf_outline *outline, int level) -{ - char buf[512]; - memset(buf, 0, sizeof buf); - memset(buf, ' ', level * 4); + char indent[8*4+1]; + if (level > 8) + level = 8; + memset(indent, ' ', level * 4); + indent[level * 4] = 0; while (outline) { - int number = pageNumberFromLink(xref, outline->link); - if (number >= 0) { - [titles addObject: [NSString stringWithFormat: @"%s%s", buf, outline->title]]; - [pages addObject: [NSNumber numberWithInt: number]]; + if (outline->page >= 0 && outline->title) { + NSString *title = [NSString stringWithUTF8String: outline->title]; + [titles addObject: [NSString stringWithFormat: @"%s%@", indent, title]]; + [pages addObject: [NSNumber numberWithInt: outline->page]]; } - loadOutlineImp(titles, pages, xref, outline->child, level + 1); + flattenOutline(titles, pages, outline->down, level + 1); outline = outline->next; } } -static void loadOutline(NSMutableArray *titles, NSMutableArray *pages, pdf_xref *xref) +static void loadOutline(NSMutableArray *titles, NSMutableArray *pages, struct document *doc) { - pdf_outline *outline = pdf_load_outline(xref); - if (outline) { - loadOutlineImp(titles, pages, xref, outline, 0); - pdf_free_outline(outline); - } } static void releasePixmap(void *info, const void *data, size_t size) @@ -686,9 +674,7 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize, - (id) initWithFile: (NSString*)nsfilename { - fz_error error; char filename[PATH_MAX]; - char *password = ""; self = [super init]; if (!self) @@ -711,20 +697,22 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize, return nil; } - if (doc->pdf) { - NSMutableArray *titles = [[NSMutableArray alloc] init]; - NSMutableArray *pages = [[NSMutableArray alloc] init]; - loadOutline(titles, pages, doc->pdf); - if ([titles count]) { - outline = [[MuOutlineController alloc] initWithTarget: self titles: titles pages: pages]; - [[self navigationItem] setRightBarButtonItem: - [[UIBarButtonItem alloc] - initWithBarButtonSystemItem: UIBarButtonSystemItemBookmarks - target:self action:@selector(onShowOutline:)]]; - } - [titles release]; - [pages release]; + NSMutableArray *titles = [[NSMutableArray alloc] init]; + NSMutableArray *pages = [[NSMutableArray alloc] init]; + fz_outline *root = load_outline(doc); + if (root) { + flattenOutline(titles, pages, root, 0); + fz_free_outline(root); + } + if ([titles count]) { + outline = [[MuOutlineController alloc] initWithTarget: self titles: titles pages: pages]; + [[self navigationItem] setRightBarButtonItem: + [[UIBarButtonItem alloc] + initWithBarButtonSystemItem: UIBarButtonSystemItemBookmarks + target:self action:@selector(onShowOutline:)]]; } + [titles release]; + [pages release]; return self; } diff --git a/pdf/mupdf.h b/pdf/mupdf.h index 6870edfc..22e087f9 100644 --- a/pdf/mupdf.h +++ b/pdf/mupdf.h @@ -406,7 +406,6 @@ void pdf_debug_font(pdf_font_desc *fontdesc); typedef struct pdf_link_s pdf_link; typedef struct pdf_annot_s pdf_annot; -typedef struct pdf_outline_s pdf_outline; typedef enum pdf_link_kind_e { @@ -434,22 +433,11 @@ struct pdf_annot_s pdf_annot *next; }; -struct pdf_outline_s -{ - char *title; - pdf_link *link; - int count; - pdf_outline *child; - pdf_outline *next; -}; - fz_obj *pdf_lookup_dest(pdf_xref *xref, fz_obj *needle); fz_obj *pdf_lookup_name(pdf_xref *xref, char *which, fz_obj *needle); fz_obj *pdf_load_name_tree(pdf_xref *xref, char *which); -pdf_outline *pdf_load_outline(pdf_xref *xref); -void pdf_debug_outline(pdf_outline *outline, int level); -void pdf_free_outline(pdf_outline *outline); +fz_outline *pdf_load_outline(pdf_xref *xref); pdf_link *pdf_load_link(pdf_xref *xref, fz_obj *dict); void pdf_load_links(pdf_link **, pdf_xref *, fz_obj *annots); diff --git a/pdf/pdf_outline.c b/pdf/pdf_outline.c index 4f81bb9b..d1f5f575 100644 --- a/pdf/pdf_outline.c +++ b/pdf/pdf_outline.c @@ -1,36 +1,37 @@ #include "fitz.h" #include "mupdf.h" -static pdf_outline * +static fz_outline * pdf_load_outline_imp(pdf_xref *xref, fz_obj *dict) { - pdf_outline *node; + pdf_link *link; + fz_outline *node; fz_obj *obj; if (fz_is_null(dict)) return NULL; - node = fz_malloc(sizeof(pdf_outline)); + node = fz_malloc(sizeof(fz_outline)); node->title = NULL; - node->link = NULL; - node->child = NULL; + node->page = 0; + node->down = NULL; node->next = NULL; - node->count = 0; obj = fz_dict_gets(dict, "Title"); if (obj) node->title = pdf_to_utf8(obj); - obj = fz_dict_gets(dict, "Count"); - if (obj) - node->count = fz_to_int(obj); - if (fz_dict_gets(dict, "Dest") || fz_dict_gets(dict, "A")) - node->link = pdf_load_link(xref, dict); + { + link = pdf_load_link(xref, dict); + if (link->kind == PDF_LINK_GOTO) + node->page = pdf_find_page_number(xref, fz_array_get(link->dest, 0)); + pdf_free_link(link); + } obj = fz_dict_gets(dict, "First"); if (obj) - node->child = pdf_load_outline_imp(xref, obj); + node->down = pdf_load_outline_imp(xref, obj); obj = fz_dict_gets(dict, "Next"); if (obj) @@ -39,7 +40,7 @@ pdf_load_outline_imp(pdf_xref *xref, fz_obj *dict) return node; } -pdf_outline * +fz_outline * pdf_load_outline(pdf_xref *xref) { fz_obj *root, *obj, *first; @@ -52,42 +53,3 @@ pdf_load_outline(pdf_xref *xref) return NULL; } - -void -pdf_free_outline(pdf_outline *outline) -{ - if (outline->child) - pdf_free_outline(outline->child); - if (outline->next) - pdf_free_outline(outline->next); - if (outline->link) - pdf_free_link(outline->link); - fz_free(outline->title); - fz_free(outline); -} - -void -pdf_debug_outline(pdf_outline *outline, int level) -{ - int i; - while (outline) - { - for (i = 0; i < level; i++) - putchar(' '); - - if (outline->title) - printf("%s ", outline->title); - else - printf("<NULL> "); - - if (outline->link) - fz_debug_obj(outline->link->dest); - else - printf("<NULL>\n"); - - if (outline->child) - pdf_debug_outline(outline->child, level + 2); - - outline = outline->next; - } -} diff --git a/win32/libmupdf.vcproj b/win32/libmupdf.vcproj index 88af36ef..cadad09c 100644 --- a/win32/libmupdf.vcproj +++ b/win32/libmupdf.vcproj @@ -323,6 +323,9 @@ > </File> <File + RelativePath="..\fitz\doc_outline.c" + > + <File RelativePath="..\fitz\dev_bbox.c" > </File> @@ -503,6 +506,10 @@ > </File> <File + RelativePath="..\xps\xps_outline.c" + > + </File> + <File RelativePath="..\xps\xps_path.c" > </File> diff --git a/xps/muxps.h b/xps/muxps.h index 28603aea..172a8535 100644 --- a/xps/muxps.h +++ b/xps/muxps.h @@ -15,6 +15,8 @@ typedef struct xps_context_s xps_context; #define REL_START_PART \ "http://schemas.microsoft.com/xps/2005/06/fixedrepresentation" +#define REL_DOC_STRUCTURE \ + "http://schemas.microsoft.com/xps/2005/06/documentstructure" #define REL_REQUIRED_RESOURCE \ "http://schemas.microsoft.com/xps/2005/06/required-resource" #define REL_REQUIRED_RESOURCE_RECURSIVE \ @@ -70,22 +72,32 @@ void xps_free_part(xps_context *ctx, xps_part *part); typedef struct xps_document_s xps_document; typedef struct xps_page_s xps_page; +typedef struct xps_target_s xps_target; struct xps_document_s { char *name; + char *outline; xps_document *next; }; struct xps_page_s { char *name; + int number; int width; int height; xml_element *root; xps_page *next; }; +struct xps_target_s +{ + char *name; + int page; + xps_target *next; +}; + int xps_read_page_list(xps_context *ctx); void xps_debug_page_list(xps_context *ctx); void xps_free_page_list(xps_context *ctx); @@ -94,6 +106,10 @@ int xps_count_pages(xps_context *ctx); int xps_load_page(xps_page **page, xps_context *ctx, int number); void xps_free_page(xps_context *ctx, xps_page *page); +fz_outline *xps_load_outline(xps_context *ctx); + +int xps_find_link_target(xps_context *ctx, char *target_uri); + /* * Images, fonts, and colorspaces. */ @@ -206,6 +222,9 @@ struct xps_context_s xps_document *last_fixdoc; /* last fixed document */ xps_page *first_page; /* first page of document */ xps_page *last_page; /* last page of document */ + int page_count; + + xps_target *target; /* link targets */ char *base_uri; /* base uri for parsing XML and resolving relative paths */ char *part_uri; /* part uri for parsing metadata relations */ diff --git a/xps/xps_doc.c b/xps/xps_doc.c index 5719e7f8..e0ab7d61 100644 --- a/xps/xps_doc.c +++ b/xps/xps_doc.c @@ -1,6 +1,20 @@ #include "fitz.h" #include "muxps.h" +static void +xps_rels_for_part(char *buf, char *name, int buflen) +{ + char *p, *basename; + p = strrchr(name, '/'); + basename = p ? p + 1 : name; + fz_strlcpy(buf, name, buflen); + p = strrchr(buf, '/'); + if (p) *p = 0; + fz_strlcat(buf, "/_rels/", buflen); + fz_strlcat(buf, basename, buflen); + fz_strlcat(buf, ".rels", buflen); +} + /* * The FixedDocumentSequence and FixedDocument parts determine * which parts correspond to actual pages, and the page order. @@ -23,7 +37,7 @@ xps_debug_page_list(xps_context *ctx) while (page) { - printf("page %s w=%d h=%d\n", page->name, page->width, page->height); + printf("page[%d] %s w=%d h=%d\n", page->number, page->name, page->width, page->height); page = page->next; } } @@ -40,6 +54,7 @@ xps_add_fixed_document(xps_context *ctx, char *name) fixdoc = fz_malloc(sizeof(xps_document)); fixdoc->name = fz_strdup(name); + fixdoc->outline = NULL; fixdoc->next = NULL; if (!ctx->first_fixdoc) @@ -66,6 +81,7 @@ xps_add_fixed_page(xps_context *ctx, char *name, int width, int height) page = fz_malloc(sizeof(xps_page)); page->name = fz_strdup(name); + page->number = ctx->page_count++; page->width = width; page->height = height; page->root = NULL; @@ -84,6 +100,42 @@ xps_add_fixed_page(xps_context *ctx, char *name, int width, int height) } static void +xps_add_link_target(xps_context *ctx, char *name) +{ + xps_page *page = ctx->last_page; + xps_target *target = fz_malloc(sizeof *target); + target->name = fz_strdup(name); + target->page = page->number; + target->next = ctx->target; + ctx->target = target; +} + +int +xps_find_link_target(xps_context *ctx, char *target_uri) +{ + xps_target *target; + char *needle = strrchr(target_uri, '#'); + needle = needle ? needle + 1 : target_uri; + for (target = ctx->target; target; target = target->next) + if (!strcmp(target->name, needle)) + return target->page; + return 0; +} + +static void +xps_free_link_targets(xps_context *ctx) +{ + xps_target *target = ctx->target, *next; + while (target) + { + next = target->next; + fz_free(target->name); + fz_free(target); + target = next; + } +} + +static void xps_free_fixed_pages(xps_context *ctx) { xps_page *page = ctx->first_page; @@ -102,13 +154,13 @@ xps_free_fixed_pages(xps_context *ctx) static void xps_free_fixed_documents(xps_context *ctx) { - xps_document *doc = ctx->first_fixdoc; - while (doc) + xps_document *fixdoc = ctx->first_fixdoc; + while (fixdoc) { - xps_document *next = doc->next; - fz_free(doc->name); - fz_free(doc); - doc = next; + xps_document *next = fixdoc->next; + fz_free(fixdoc->name); + fz_free(fixdoc); + fixdoc = next; } ctx->first_fixdoc = NULL; ctx->last_fixdoc = NULL; @@ -119,6 +171,7 @@ xps_free_page_list(xps_context *ctx) { xps_free_fixed_documents(ctx); xps_free_fixed_pages(ctx); + xps_free_link_targets(ctx); } /* @@ -126,12 +179,10 @@ xps_free_page_list(xps_context *ctx) */ static void -xps_parse_metadata_imp(xps_context *ctx, xml_element *item) +xps_parse_metadata_imp(xps_context *ctx, xml_element *item, xps_document *fixdoc) { while (item) { - xps_parse_metadata_imp(ctx, xml_down(item)); - if (!strcmp(xml_tag(item), "Relationship")) { char *target = xml_att(item, "Target"); @@ -142,6 +193,8 @@ xps_parse_metadata_imp(xps_context *ctx, xml_element *item) xps_absolute_path(tgtbuf, ctx->base_uri, target, sizeof tgtbuf); if (!strcmp(type, REL_START_PART)) ctx->start_part = fz_strdup(tgtbuf); + if (!strcmp(type, REL_DOC_STRUCTURE) && fixdoc) + fixdoc->outline = fz_strdup(tgtbuf); } } @@ -171,12 +224,21 @@ xps_parse_metadata_imp(xps_context *ctx, xml_element *item) } } + if (!strcmp(xml_tag(item), "LinkTarget")) + { + char *name = xml_att(item, "Name"); + if (name) + xps_add_link_target(ctx, name); + } + + xps_parse_metadata_imp(ctx, xml_down(item), fixdoc); + item = xml_next(item); } } static int -xps_parse_metadata(xps_context *ctx, xps_part *part) +xps_parse_metadata(xps_context *ctx, xps_part *part, xps_document *fixdoc) { xml_element *root; char buf[1024]; @@ -203,7 +265,7 @@ xps_parse_metadata(xps_context *ctx, xps_part *part) if (!root) return fz_rethrow(-1, "cannot parse metadata part '%s'", part->name); - xps_parse_metadata_imp(ctx, root); + xps_parse_metadata_imp(ctx, root, fixdoc); xml_free_element(root); @@ -214,7 +276,7 @@ xps_parse_metadata(xps_context *ctx, xps_part *part) } static int -xps_read_and_process_metadata_part(xps_context *ctx, char *name) +xps_read_and_process_metadata_part(xps_context *ctx, char *name, xps_document *fixdoc) { xps_part *part; int code; @@ -223,7 +285,7 @@ xps_read_and_process_metadata_part(xps_context *ctx, char *name) if (!part) return fz_rethrow(-1, "cannot read zip part '%s'", name); - code = xps_parse_metadata(ctx, part); + code = xps_parse_metadata(ctx, part, fixdoc); if (code) return fz_rethrow(code, "cannot process metadata part '%s'", name); @@ -235,23 +297,30 @@ xps_read_and_process_metadata_part(xps_context *ctx, char *name) int xps_read_page_list(xps_context *ctx) { - xps_document *doc; + xps_document *fixdoc; int code; - code = xps_read_and_process_metadata_part(ctx, "/_rels/.rels"); + code = xps_read_and_process_metadata_part(ctx, "/_rels/.rels", NULL); if (code) return fz_rethrow(code, "cannot process root relationship part"); if (!ctx->start_part) return fz_throw("cannot find fixed document sequence start part"); - code = xps_read_and_process_metadata_part(ctx, ctx->start_part); + code = xps_read_and_process_metadata_part(ctx, ctx->start_part, NULL); if (code) return fz_rethrow(code, "cannot process FixedDocumentSequence part"); - for (doc = ctx->first_fixdoc; doc; doc = doc->next) + for (fixdoc = ctx->first_fixdoc; fixdoc; fixdoc = fixdoc->next) { - code = xps_read_and_process_metadata_part(ctx, doc->name); + char relbuf[1024]; + xps_rels_for_part(relbuf, fixdoc->name, sizeof relbuf); + + code = xps_read_and_process_metadata_part(ctx, relbuf, fixdoc); + if (code) + fz_catch(code, "cannot process FixedDocument rels part"); + + code = xps_read_and_process_metadata_part(ctx, fixdoc->name, fixdoc); if (code) return fz_rethrow(code, "cannot process FixedDocument part"); } @@ -262,11 +331,7 @@ xps_read_page_list(xps_context *ctx) int xps_count_pages(xps_context *ctx) { - xps_page *page; - int n = 0; - for (page = ctx->first_page; page; page = page->next) - n ++; - return n; + return ctx->page_count; } static int diff --git a/xps/xps_outline.c b/xps/xps_outline.c new file mode 100644 index 00000000..a4ab6c19 --- /dev/null +++ b/xps/xps_outline.c @@ -0,0 +1,124 @@ +#include "fitz.h" +#include "muxps.h" + +/* + * Parse the document structure / outline parts referenced from fixdoc relationships. + */ + +static fz_outline * +xps_find_last_outline_at_level(fz_outline *node, int level, int target_level) +{ + while (node->next) + node = node->next; + if (level == target_level || !node->down) + return node; + return xps_find_last_outline_at_level(node->down, level + 1, target_level); +} + +static fz_outline * +xps_parse_document_outline(xps_context *ctx, xml_element *root) +{ + xml_element *node; + fz_outline *head = NULL, *entry, *tail; + int last_level = 1, this_level; + for (node = xml_down(root); node; node = xml_next(node)) + { + if (!strcmp(xml_tag(node), "OutlineEntry")) + { + char *level = xml_att(node, "OutlineLevel"); + char *target = xml_att(node, "OutlineTarget"); + char *description = xml_att(node, "Description"); + if (!target || !description) + continue; + + entry = fz_malloc(sizeof *entry); + entry->title = fz_strdup(description); + entry->page = xps_find_link_target(ctx, target); + entry->down = NULL; + entry->next = NULL; + + this_level = level ? atoi(level) : 1; + + if (!head) + { + head = entry; + } + else + { + tail = xps_find_last_outline_at_level(head, 1, this_level); + if (this_level > last_level) + tail->down = entry; + else + tail->next = entry; + } + + last_level = this_level; + } + } + return head; +} + +static fz_outline * +xps_parse_document_structure(xps_context *ctx, xml_element *root) +{ + xml_element *node; + if (!strcmp(xml_tag(root), "DocumentStructure")) + { + node = xml_down(root); + if (!strcmp(xml_tag(node), "DocumentStructure.Outline")) + { + node = xml_down(node); + if (!strcmp(xml_tag(node), "DocumentOutline")) + return xps_parse_document_outline(ctx, node); + } + } + return NULL; +} + +static fz_outline * +xps_load_document_structure(xps_context *ctx, xps_document *fixdoc) +{ + xps_part *part; + xml_element *root; + fz_outline *outline; + + part = xps_read_part(ctx, fixdoc->outline); + if (!part) + return NULL; + + root = xml_parse_document(part->data, part->size); + if (!root) { + fz_catch(-1, "cannot parse document structure part '%s'", part->name); + xps_free_part(ctx, part); + return NULL; + } + + outline = xps_parse_document_structure(ctx, root); + + xml_free_element(root); + xps_free_part(ctx, part); + + return outline; + +} + +fz_outline * +xps_load_outline(xps_context *ctx) +{ + xps_document *fixdoc; + fz_outline *head = NULL, *tail, *outline; + + for (fixdoc = ctx->first_fixdoc; fixdoc; fixdoc = fixdoc->next) { + if (fixdoc->outline) { + outline = xps_load_document_structure(ctx, fixdoc); + if (outline) { + if (!head) + head = outline; + else + tail->next = outline; + tail = outline; + } + } + } + return head; +} diff --git a/xps/xps_xml.c b/xps/xps_xml.c index 8448ecef..aacabd5a 100644 --- a/xps/xps_xml.c +++ b/xps/xps_xml.c @@ -376,7 +376,7 @@ xml_parse_document(unsigned char *s, int n) error = xml_parse_document_imp(&parser, p); if (error) { - fz_throw(error); + fz_throw("%s", error); return NULL; } |