static void xps_load_links_in_path(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, char *base_uri, xps_resource *dict, fz_xml *root, fz_link **link) { char *navigate_uri_att = fz_xml_att(root, "FixedPage.NavigateUri"); if (navigate_uri_att) { char *transform_att = fz_xml_att(root, "RenderTransform"); fz_xml *transform_tag = fz_xml_down(fz_xml_find_down(root, "Path.RenderTransform")); char *data_att = fz_xml_att(root, "Data"); fz_xml *data_tag = fz_xml_down(fz_xml_find_down(root, "Path.Data")); fz_path *path = NULL; int fill_rule; fz_matrix local_ctm; fz_rect area; xps_resolve_resource_reference(ctx, doc, dict, &data_att, &data_tag, NULL); xps_resolve_resource_reference(ctx, doc, dict, &transform_att, &transform_tag, NULL); xps_parse_transform(ctx, doc, transform_att, transform_tag, &local_ctm, ctm); if (data_att) path = xps_parse_abbreviated_geometry(ctx, doc, data_att, &fill_rule); else if (data_tag) path = xps_parse_path_geometry(ctx, doc, dict, data_tag, 0, &fill_rule); if (path) { fz_bound_path(ctx, path, NULL, &local_ctm, &area); fz_drop_path(ctx, path); xps_add_link(ctx, doc, &area, base_uri, navigate_uri_att, link); } } }
static fz_outline * epub_parse_ncx_imp(fz_context *ctx, epub_document *doc, fz_xml *node, char *base_uri) { char path[2048]; fz_outline *outline, *head, **tailp; head = NULL; tailp = &head; node = fz_xml_find_down(node, "navPoint"); while (node) { char *text = fz_xml_text(fz_xml_down(fz_xml_find_down(fz_xml_find_down(node, "navLabel"), "text"))); char *content = fz_xml_att(fz_xml_find_down(node, "content"), "src"); if (text && content) { fz_strlcpy(path, base_uri, sizeof path); fz_strlcat(path, "/", sizeof path); fz_strlcat(path, content, sizeof path); fz_urldecode(path); fz_cleanname(path); *tailp = outline = fz_new_outline(ctx); tailp = &(*tailp)->next; outline->title = fz_strdup(ctx, text); outline->uri = fz_strdup(ctx, path); outline->page = -1; outline->down = epub_parse_ncx_imp(ctx, doc, node, base_uri); } node = fz_xml_find_next(node, "navPoint"); } return head; }
static void xps_load_links_in_fixed_page(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, xps_page *page, fz_link **link) { fz_xml *node, *resource_tag; xps_resource *dict = NULL; char base_uri[1024]; char *s; if (!page->root) return; fz_strlcpy(base_uri, page->fix->name, sizeof base_uri); s = strrchr(base_uri, '/'); if (s) s[1] = 0; resource_tag = fz_xml_down(fz_xml_find_down(page->root, "FixedPage.Resources")); if (resource_tag) dict = xps_parse_resource_dictionary(ctx, doc, base_uri, resource_tag); for (node = fz_xml_down(page->root); node; node = fz_xml_next(node)) xps_load_links_in_element(ctx, doc, ctm, base_uri, dict, node, link); if (dict) xps_drop_resource_dictionary(ctx, doc, dict); }
static char * find_metadata(fz_context *ctx, fz_xml *metadata, char *key) { char *text = fz_xml_text(fz_xml_down(fz_xml_find_down(metadata, key))); if (text) return fz_strdup(ctx, text); return NULL; }
static void xps_load_links_in_canvas(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, char *base_uri, xps_resource *dict, fz_xml *root, fz_link **link) { xps_resource *new_dict = NULL; fz_matrix local_ctm; fz_xml *node; char *navigate_uri_att = fz_xml_att(root, "FixedPage.NavigateUri"); char *transform_att = fz_xml_att(root, "RenderTransform"); fz_xml *transform_tag = fz_xml_down(fz_xml_find_down(root, "Canvas.RenderTransform")); fz_xml *resource_tag = fz_xml_down(fz_xml_find_down(root, "Canvas.Resources")); if (resource_tag) { new_dict = xps_parse_resource_dictionary(ctx, doc, base_uri, resource_tag); if (new_dict) { new_dict->parent = dict; dict = new_dict; } } xps_resolve_resource_reference(ctx, doc, dict, &transform_att, &transform_tag, NULL); xps_parse_transform(ctx, doc, transform_att, transform_tag, &local_ctm, ctm); if (navigate_uri_att) fz_warn(ctx, "FixedPage.NavigateUri attribute on Canvas element"); for (node = fz_xml_down(root); node; node = fz_xml_next(node)) xps_load_links_in_element(ctx, doc, &local_ctm, base_uri, dict, node, link); if (new_dict) xps_drop_resource_dictionary(ctx, doc, new_dict); }
static const char * rel_path_from_idref(fz_xml *manifest, const char *idref) { fz_xml *item; if (!idref) return NULL; item = fz_xml_find_down(manifest, "item"); while (item) { const char *id = fz_xml_att(item, "id"); if (id && !strcmp(id, idref)) return fz_xml_att(item, "href"); item = fz_xml_find_next(item, "item"); } return NULL; }
static void xps_load_links_in_glyphs(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, char *base_uri, xps_resource *dict, fz_xml *root, fz_link **link) { char *navigate_uri_att = fz_xml_att(root, "FixedPage.NavigateUri"); if (navigate_uri_att) { char *transform_att = fz_xml_att(root, "RenderTransform"); fz_xml *transform_tag = fz_xml_down(fz_xml_find_down(root, "Path.RenderTransform")); char *bidi_level_att = fz_xml_att(root, "BidiLevel"); char *font_size_att = fz_xml_att(root, "FontRenderingEmSize"); char *font_uri_att = fz_xml_att(root, "FontUri"); char *origin_x_att = fz_xml_att(root, "OriginX"); char *origin_y_att = fz_xml_att(root, "OriginY"); char *is_sideways_att = fz_xml_att(root, "IsSideways"); char *indices_att = fz_xml_att(root, "Indices"); char *unicode_att = fz_xml_att(root, "UnicodeString"); char *style_att = fz_xml_att(root, "StyleSimulations"); int is_sideways = 0; int bidi_level = 0; fz_matrix local_ctm; fz_font *font; fz_text *text; fz_rect area; xps_resolve_resource_reference(ctx, doc, dict, &transform_att, &transform_tag, NULL); xps_parse_transform(ctx, doc, transform_att, transform_tag, &local_ctm, ctm); if (is_sideways_att) is_sideways = !strcmp(is_sideways_att, "true"); if (bidi_level_att) bidi_level = atoi(bidi_level_att); font = xps_lookup_font(ctx, doc, base_uri, font_uri_att, style_att); text = xps_parse_glyphs_imp(ctx, doc, &local_ctm, font, fz_atof(font_size_att), fz_atof(origin_x_att), fz_atof(origin_y_att), is_sideways, bidi_level, indices_att, unicode_att); fz_bound_text(ctx, text, NULL, &local_ctm, &area); fz_drop_text(ctx, text); fz_drop_font(ctx, font); xps_add_link(ctx, doc, &area, base_uri, navigate_uri_att, link); } }
static fz_css_rule * html_load_css(fz_context *ctx, fz_archive *zip, const char *base_uri, fz_css_rule *css, fz_xml *root) { fz_xml *html, *head, *node; fz_buffer *buf; char path[2048]; fz_var(buf); html = fz_xml_find(root, "html"); head = fz_xml_find_down(html, "head"); for (node = fz_xml_down(head); node; node = fz_xml_next(node)) { if (fz_xml_is_tag(node, "link")) { char *rel = fz_xml_att(node, "rel"); if (rel && !fz_strcasecmp(rel, "stylesheet")) { char *type = fz_xml_att(node, "type"); if ((type && !strcmp(type, "text/css")) || !type) { char *href = fz_xml_att(node, "href"); if (href) { fz_strlcpy(path, base_uri, sizeof path); fz_strlcat(path, "/", sizeof path); fz_strlcat(path, href, sizeof path); fz_urldecode(path); fz_cleanname(path); buf = NULL; fz_try(ctx) { buf = fz_read_archive_entry(ctx, zip, path); fz_write_buffer_byte(ctx, buf, 0); css = fz_parse_css(ctx, css, (char*)buf->data, path); } fz_always(ctx) fz_drop_buffer(ctx, buf); fz_catch(ctx) fz_warn(ctx, "ignoring stylesheet %s", path); } } }
static void epub_parse_ncx(fz_context *ctx, epub_document *doc, const char *path) { fz_archive *zip = doc->zip; fz_buffer *buf; fz_xml *ncx; char base_uri[2048]; unsigned char *data; size_t len; fz_dirname(base_uri, path, sizeof base_uri); buf = fz_read_archive_entry(ctx, zip, path); fz_write_buffer_byte(ctx, buf, 0); len = fz_buffer_storage(ctx, buf, &data); ncx = fz_parse_xml(ctx, data, len, 0); fz_drop_buffer(ctx, buf); doc->outline = epub_parse_ncx_imp(ctx, doc, fz_xml_find_down(ncx, "navMap"), base_uri); fz_drop_xml(ctx, ncx); }
static void epub_parse_header(fz_context *ctx, epub_document *doc) { fz_archive *zip = doc->zip; fz_buffer *buf; fz_xml *container_xml, *content_opf; fz_xml *container, *rootfiles, *rootfile; fz_xml *package, *manifest, *spine, *itemref, *metadata; char base_uri[2048]; const char *full_path; const char *version; char ncx[2048], s[2048]; epub_chapter **tailp; size_t len; unsigned char *data; if (fz_has_archive_entry(ctx, zip, "META-INF/rights.xml")) fz_throw(ctx, FZ_ERROR_GENERIC, "EPUB is locked by DRM"); if (fz_has_archive_entry(ctx, zip, "META-INF/encryption.xml")) fz_throw(ctx, FZ_ERROR_GENERIC, "EPUB is locked by DRM"); /* parse META-INF/container.xml to find OPF */ buf = fz_read_archive_entry(ctx, zip, "META-INF/container.xml"); fz_write_buffer_byte(ctx, buf, 0); len = fz_buffer_storage(ctx, buf, &data); container_xml = fz_parse_xml(ctx, data, len, 0); fz_drop_buffer(ctx, buf); container = fz_xml_find(container_xml, "container"); rootfiles = fz_xml_find_down(container, "rootfiles"); rootfile = fz_xml_find_down(rootfiles, "rootfile"); full_path = fz_xml_att(rootfile, "full-path"); if (!full_path) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find root file in EPUB"); fz_dirname(base_uri, full_path, sizeof base_uri); /* parse OPF to find NCX and spine */ buf = fz_read_archive_entry(ctx, zip, full_path); fz_write_buffer_byte(ctx, buf, 0); len = fz_buffer_storage(ctx, buf, &data); content_opf = fz_parse_xml(ctx, data, len, 0); fz_drop_buffer(ctx, buf); package = fz_xml_find(content_opf, "package"); version = fz_xml_att(package, "version"); if (!version || strcmp(version, "2.0")) fz_warn(ctx, "unknown epub version: %s", version ? version : "<none>"); metadata = fz_xml_find_down(package, "metadata"); if (metadata) { doc->dc_title = find_metadata(ctx, metadata, "title"); doc->dc_creator = find_metadata(ctx, metadata, "creator"); } manifest = fz_xml_find_down(package, "manifest"); spine = fz_xml_find_down(package, "spine"); if (path_from_idref(ncx, manifest, base_uri, fz_xml_att(spine, "toc"), sizeof ncx)) { epub_parse_ncx(ctx, doc, ncx); } doc->spine = NULL; tailp = &doc->spine; itemref = fz_xml_find_down(spine, "itemref"); while (itemref) { if (path_from_idref(s, manifest, base_uri, fz_xml_att(itemref, "idref"), sizeof s)) { *tailp = epub_parse_chapter(ctx, doc, s); tailp = &(*tailp)->next; } itemref = fz_xml_find_next(itemref, "itemref"); } fz_drop_xml(ctx, container_xml); fz_drop_xml(ctx, content_opf); }
static void epub_parse_header(fz_context *ctx, epub_document *doc) { fz_archive *zip = doc->zip; fz_buffer *buf; fz_xml *container_xml, *content_opf; fz_xml *container, *rootfiles, *rootfile; fz_xml *package, *manifest, *spine, *itemref; char base_uri[2048]; const char *full_path; const char *version; char ncx[2048], s[2048]; epub_chapter *head, *tail; if (fz_has_archive_entry(ctx, zip, "META-INF/rights.xml")) fz_throw(ctx, FZ_ERROR_GENERIC, "EPUB is locked by DRM"); if (fz_has_archive_entry(ctx, zip, "META-INF/encryption.xml")) fz_throw(ctx, FZ_ERROR_GENERIC, "EPUB is locked by DRM"); /* parse META-INF/container.xml to find OPF */ buf = fz_read_archive_entry(ctx, zip, "META-INF/container.xml"); fz_write_buffer_byte(ctx, buf, 0); container_xml = fz_parse_xml(ctx, buf->data, buf->len, 0); fz_drop_buffer(ctx, buf); container = fz_xml_find(container_xml, "container"); rootfiles = fz_xml_find_down(container, "rootfiles"); rootfile = fz_xml_find_down(rootfiles, "rootfile"); full_path = fz_xml_att(rootfile, "full-path"); if (!full_path) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find root file in EPUB"); printf("epub: found root: %s\n", full_path); fz_dirname(base_uri, full_path, sizeof base_uri); /* parse OPF to find NCX and spine */ buf = fz_read_archive_entry(ctx, zip, full_path); fz_write_buffer_byte(ctx, buf, 0); content_opf = fz_parse_xml(ctx, buf->data, buf->len, 0); fz_drop_buffer(ctx, buf); package = fz_xml_find(content_opf, "package"); version = fz_xml_att(package, "version"); if (!version || strcmp(version, "2.0")) fz_warn(ctx, "unknown epub version: %s", version ? version : "<none>"); manifest = fz_xml_find_down(package, "manifest"); spine = fz_xml_find_down(package, "spine"); if (path_from_idref(ncx, manifest, base_uri, fz_xml_att(spine, "toc"), sizeof ncx)) { /* TODO: parse NCX to create fz_outline */ printf("epub: found outline: %s\n", ncx); } head = tail = NULL; itemref = fz_xml_find_down(spine, "itemref"); while (itemref) { if (path_from_idref(s, manifest, base_uri, fz_xml_att(itemref, "idref"), sizeof s)) { printf("epub: found spine %s\n", s); if (!head) head = tail = epub_parse_chapter(ctx, doc, s); else tail = tail->next = epub_parse_chapter(ctx, doc, s); } itemref = fz_xml_find_next(itemref, "itemref"); } doc->spine = head; printf("epub: done.\n"); fz_drop_xml(ctx, container_xml); fz_drop_xml(ctx, content_opf); }