summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/pdfapp.c2
-rw-r--r--apps/pdfapp.h2
-rw-r--r--apps/pdfdraw.c50
-rw-r--r--apps/xpsdraw.c31
-rw-r--r--fitz/doc_outline.c49
-rw-r--r--fitz/fitz.h18
-rw-r--r--ios/document.c11
-rw-r--r--ios/document.h1
-rw-r--r--ios/main.m66
-rw-r--r--pdf/mupdf.h14
-rw-r--r--pdf/pdf_outline.c66
-rw-r--r--win32/libmupdf.vcproj7
-rw-r--r--xps/muxps.h19
-rw-r--r--xps/xps_doc.c113
-rw-r--r--xps/xps_outline.c124
-rw-r--r--xps/xps_xml.c2
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);
diff --git a/ios/main.m b/ios/main.m
index 4b1c5f1c..3a6a45f3 100644
--- a/ios/main.m
+++ b/ios/main.m
@@ -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;
}