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(ctx->ctx, part->data, part->size); if (!root) { fz_error_handle(ctx->ctx, -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(ctx->ctx, root); xps_free_part(ctx, part); return outline; }
static xps_resource * xps_parse_remote_resource_dictionary(xps_document *doc, char *base_uri, char *source_att) { char part_name[1024]; char part_uri[1024]; xps_resource *dict; xps_part *part; xml_element *xml; char *s; /* External resource dictionaries MUST NOT reference other resource dictionaries */ xps_resolve_url(part_name, base_uri, source_att, sizeof part_name); part = xps_read_part(doc, part_name); xml = xml_parse_document(doc->ctx, part->data, part->size); xps_free_part(doc, part); if (strcmp(xml_tag(xml), "ResourceDictionary")) { xml_free_element(doc->ctx, xml); fz_throw(doc->ctx, "expected ResourceDictionary element (found %s)", xml_tag(xml)); } fz_strlcpy(part_uri, part_name, sizeof part_uri); s = strrchr(part_uri, '/'); if (s) s[1] = 0; dict = xps_parse_resource_dictionary(doc, part_uri, xml); if (dict) dict->base_xml = xml; /* pass on ownership */ return dict; }
static int xps_load_fixed_page(xps_context *ctx, xps_page *page) { xps_part *part; xml_element *root; char *width_att; char *height_att; part = xps_read_part(ctx, page->name); if (!part) return fz_rethrow(-1, "cannot read zip part '%s'", page->name); root = xml_parse_document(part->data, part->size); if (!root) return fz_rethrow(-1, "cannot parse xml part '%s'", page->name); xps_free_part(ctx, part); if (strcmp(xml_tag(root), "FixedPage")) return fz_throw("expected FixedPage element (found %s)", xml_tag(root)); width_att = xml_att(root, "Width"); if (!width_att) return fz_throw("FixedPage missing required attribute: Width"); height_att = xml_att(root, "Height"); if (!height_att) return fz_throw("FixedPage missing required attribute: Height"); page->width = atoi(width_att); page->height = atoi(height_att); page->root = root; return 0; }
fz_obj *xps_extract_doc_props(xps_context *ctx) { char path[1024]; xps_part *part; fz_obj *dict; if (xps_find_doc_props_path(ctx, path) != fz_okay) fz_error_handle(ctx->ctx, -1, "ignore broken part '/_rels/.rels'"); if (!*path) return NULL; part = xps_read_part(ctx, path); if (!part) { fz_error_handle(ctx->ctx, -1, "cannot read zip part '%s'", path); return NULL; } dict = fz_new_dict(ctx->ctx, 8); xps_hacky_get_prop(ctx->ctx, part->data, dict, "Title", "dc:title"); xps_hacky_get_prop(ctx->ctx, part->data, dict, "Subject", "dc:subject"); xps_hacky_get_prop(ctx->ctx, part->data, dict, "Author", "dc:creator"); xps_hacky_get_prop(ctx->ctx, part->data, dict, "CreationDate", "dcterms:created"); xps_hacky_get_prop(ctx->ctx, part->data, dict, "ModDate", "dcterms:modified"); xps_free_part(ctx, part); return dict; }
fz_obj *xps_extract_doc_props(xps_context *ctx) { char path[1024]; xps_part *part; fz_obj *dict; if (xps_find_doc_props_path(ctx, path) != fz_okay) { fz_catch(-1, "couldn't find the exact part name for /docProps/core.xml"); fz_strlcpy(path, "/docProps/core.xml", sizeof(path)); } if (!*path) return NULL; part = xps_read_part(ctx, path); if (!part) { fz_catch(-1, "cannot read zip part '%s'", path); return NULL; } dict = fz_new_dict(8); xps_hacky_get_prop(part->data, dict, "Title", "dc:title"); xps_hacky_get_prop(part->data, dict, "Subject", "dc:subject"); xps_hacky_get_prop(part->data, dict, "Author", "dc:creator"); xps_hacky_get_prop(part->data, dict, "CreationDate", "dcterms:created"); xps_hacky_get_prop(part->data, dict, "ModDate", "dcterms:modified"); xps_free_part(ctx, part); return dict; }
static int xps_parse_remote_resource_dictionary(xps_context *ctx, xps_resource **dictp, char *base_uri, char *source_att) { char part_name[1024]; char part_uri[1024]; xps_resource *dict; xps_part *part; xml_element *xml; char *s; int code; /* External resource dictionaries MUST NOT reference other resource dictionaries */ xps_absolute_path(part_name, base_uri, source_att, sizeof part_name); part = xps_read_part(ctx, part_name); if (!part) { return fz_throw("cannot find remote resource part '%s'", part_name); } xml = xml_parse_document(part->data, part->size); if (!xml) { xps_free_part(ctx, part); return fz_rethrow(-1, "cannot parse xml"); } if (strcmp(xml_tag(xml), "ResourceDictionary")) { xml_free_element(xml); xps_free_part(ctx, part); return fz_throw("expected ResourceDictionary element (found %s)", xml_tag(xml)); } fz_strlcpy(part_uri, part_name, sizeof part_uri); s = strrchr(part_uri, '/'); if (s) s[1] = 0; code = xps_parse_resource_dictionary(ctx, &dict, part_uri, xml); if (code) { xml_free_element(xml); xps_free_part(ctx, part); return fz_rethrow(code, "cannot parse remote resource dictionary: %s", part_uri); } dict->base_xml = xml; /* pass on ownership */ xps_free_part(ctx, part); *dictp = dict; return fz_okay; }
static int xps_open_and_parse(xps_context *ctx, char *path, xml_element **rootp) { xps_part *part = xps_read_part(ctx, path); if (!part) return fz_error_note(ctx->ctx, -1, "cannot read part '%s'", path); *rootp = xml_parse_document(ctx->ctx, part->data, part->size); xps_free_part(ctx, part); if (!*rootp) return fz_error_note(ctx->ctx, -1, "cannot parse part '%s'", path); return fz_okay; }
static int xps_open_and_parse(xps_context *ctx, char *path, xml_element **rootp) { xps_part *part = xps_read_part(ctx, path); if (!part) return fz_rethrow(-1, "cannot read zip part '%s'", path); *rootp = xml_parse_document(part->data, part->size); xps_free_part(ctx, part); if (!*rootp) return fz_rethrow(-1, "cannot parse metadata for part '%s'", path); return fz_okay; }
static xps_resource * xps_parse_remote_resource_dictionary(fz_context *ctx, xps_document *doc, char *base_uri, char *source_att) { char part_name[1024]; char part_uri[1024]; xps_part *part; xps_resource *dict = NULL; fz_xml_doc *xml = NULL; char *s; fz_var(xml); /* External resource dictionaries MUST NOT reference other resource dictionaries */ xps_resolve_url(ctx, doc, part_name, base_uri, source_att, sizeof part_name); part = xps_read_part(ctx, doc, part_name); fz_try(ctx) { xml = fz_parse_xml(ctx, part->data, 0); if (!fz_xml_is_tag(fz_xml_root(xml), "ResourceDictionary")) fz_throw(ctx, FZ_ERROR_GENERIC, "expected ResourceDictionary element"); fz_strlcpy(part_uri, part_name, sizeof part_uri); s = strrchr(part_uri, '/'); if (s) s[1] = 0; dict = xps_parse_resource_dictionary(ctx, doc, part_uri, fz_xml_root(xml)); if (dict) { dict->base_xml = xml; /* pass on ownership */ xml = NULL; } } fz_always(ctx) { xps_drop_part(ctx, doc, part); fz_drop_xml(ctx, xml); } fz_catch(ctx) { fz_rethrow(ctx); } return dict; }
static int xps_read_and_process_metadata_part(xps_context *ctx, char *name) { xps_part *part; int code; part = xps_read_part(ctx, name); if (!part) return fz_rethrow(-1, "cannot read zip part '%s'", name); code = xps_parse_metadata(ctx, part); if (code) return fz_rethrow(code, "cannot process metadata part '%s'", name); xps_free_part(ctx, part); return fz_okay; }
static void xps_read_and_process_metadata_part(fz_context *ctx, xps_document *doc, char *name, xps_fixdoc *fixdoc) { xps_part *part; if (!xps_has_part(ctx, doc, name)) return; part = xps_read_part(ctx, doc, name); fz_try(ctx) { xps_parse_metadata(ctx, doc, part, fixdoc); } fz_always(ctx) { xps_drop_part(ctx, doc, part); } fz_catch(ctx) { fz_rethrow(ctx); } }
fz_font * xps_lookup_font(fz_context *ctx, xps_document *doc, char *base_uri, char *font_uri, char *style_att) { char partname[1024]; char fakename[1024]; char *subfont; int subfontid = 0; xps_part *part; fz_font *font; xps_resolve_url(ctx, doc, partname, base_uri, font_uri, sizeof partname); subfont = strrchr(partname, '#'); if (subfont) { subfontid = atoi(subfont + 1); *subfont = 0; } /* Make a new part name for font with style simulation applied */ fz_strlcpy(fakename, partname, sizeof fakename); if (style_att) { if (!strcmp(style_att, "BoldSimulation")) fz_strlcat(fakename, "#Bold", sizeof fakename); else if (!strcmp(style_att, "ItalicSimulation")) fz_strlcat(fakename, "#Italic", sizeof fakename); else if (!strcmp(style_att, "BoldItalicSimulation")) fz_strlcat(fakename, "#BoldItalic", sizeof fakename); } font = xps_lookup_font_imp(ctx, doc, fakename); if (!font) { fz_buffer *buf = NULL; fz_var(buf); fz_try(ctx) { part = xps_read_part(ctx, doc, partname); } fz_catch(ctx) { fz_rethrow_if(ctx, FZ_ERROR_TRYLATER); fz_warn(ctx, "cannot find font resource part '%s'", partname); return NULL; } /* deobfuscate if necessary */ if (strstr(part->name, ".odttf")) xps_deobfuscate_font_resource(ctx, doc, part); if (strstr(part->name, ".ODTTF")) xps_deobfuscate_font_resource(ctx, doc, part); fz_try(ctx) { buf = fz_new_buffer_from_data(ctx, part->data, part->size); /* part->data is now owned by buf */ part->data = NULL; font = fz_new_font_from_buffer(ctx, NULL, buf, subfontid, 1); } fz_always(ctx) { fz_drop_buffer(ctx, buf); xps_drop_part(ctx, doc, part); } fz_catch(ctx) { fz_rethrow_if(ctx, FZ_ERROR_TRYLATER); fz_warn(ctx, "cannot load font resource '%s'", partname); return NULL; } if (style_att) { font->ft_bold = !!strstr(style_att, "Bold"); font->ft_italic = !!strstr(style_att, "Italic"); } xps_select_best_font_encoding(ctx, doc, font); xps_insert_font(ctx, doc, fakename, font); }
void xps_parse_glyphs(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, char *base_uri, xps_resource *dict, fz_xml *root) { fz_device *dev = doc->dev; fz_xml *node; char *fill_uri; char *opacity_mask_uri; char *bidi_level_att; char *fill_att; char *font_size_att; char *font_uri_att; char *origin_x_att; char *origin_y_att; char *is_sideways_att; char *indices_att; char *unicode_att; char *style_att; char *transform_att; char *clip_att; char *opacity_att; char *opacity_mask_att; char *navigate_uri_att; fz_xml *transform_tag = NULL; fz_xml *clip_tag = NULL; fz_xml *fill_tag = NULL; fz_xml *opacity_mask_tag = NULL; char *fill_opacity_att = NULL; xps_part *part; fz_font *font; char partname[1024]; char fakename[1024]; char *subfont; float font_size = 10; int subfontid = 0; int is_sideways = 0; int bidi_level = 0; fz_text *text; fz_rect area; fz_matrix local_ctm = *ctm; /* * Extract attributes and extended attributes. */ bidi_level_att = fz_xml_att(root, "BidiLevel"); fill_att = fz_xml_att(root, "Fill"); font_size_att = fz_xml_att(root, "FontRenderingEmSize"); font_uri_att = fz_xml_att(root, "FontUri"); origin_x_att = fz_xml_att(root, "OriginX"); origin_y_att = fz_xml_att(root, "OriginY"); is_sideways_att = fz_xml_att(root, "IsSideways"); indices_att = fz_xml_att(root, "Indices"); unicode_att = fz_xml_att(root, "UnicodeString"); style_att = fz_xml_att(root, "StyleSimulations"); transform_att = fz_xml_att(root, "RenderTransform"); clip_att = fz_xml_att(root, "Clip"); opacity_att = fz_xml_att(root, "Opacity"); opacity_mask_att = fz_xml_att(root, "OpacityMask"); navigate_uri_att = fz_xml_att(root, "FixedPage.NavigateUri"); for (node = fz_xml_down(root); node; node = fz_xml_next(node)) { if (fz_xml_is_tag(node, "Glyphs.RenderTransform")) transform_tag = fz_xml_down(node); if (fz_xml_is_tag(node, "Glyphs.OpacityMask")) opacity_mask_tag = fz_xml_down(node); if (fz_xml_is_tag(node, "Glyphs.Clip")) clip_tag = fz_xml_down(node); if (fz_xml_is_tag(node, "Glyphs.Fill")) fill_tag = fz_xml_down(node); } fill_uri = base_uri; opacity_mask_uri = base_uri; xps_resolve_resource_reference(ctx, doc, dict, &transform_att, &transform_tag, NULL); xps_resolve_resource_reference(ctx, doc, dict, &clip_att, &clip_tag, NULL); xps_resolve_resource_reference(ctx, doc, dict, &fill_att, &fill_tag, &fill_uri); xps_resolve_resource_reference(ctx, doc, dict, &opacity_mask_att, &opacity_mask_tag, &opacity_mask_uri); /* * Check that we have all the necessary information. */ if (!font_size_att || !font_uri_att || !origin_x_att || !origin_y_att) { fz_warn(ctx, "missing attributes in glyphs element"); return; } if (!indices_att && !unicode_att) return; /* nothing to draw */ if (is_sideways_att) is_sideways = !strcmp(is_sideways_att, "true"); if (bidi_level_att) bidi_level = atoi(bidi_level_att); /* * Find and load the font resource */ xps_resolve_url(ctx, doc, partname, base_uri, font_uri_att, sizeof partname); subfont = strrchr(partname, '#'); if (subfont) { subfontid = atoi(subfont + 1); *subfont = 0; } /* Make a new part name for font with style simulation applied */ fz_strlcpy(fakename, partname, sizeof fakename); if (style_att) { if (!strcmp(style_att, "BoldSimulation")) fz_strlcat(fakename, "#Bold", sizeof fakename); else if (!strcmp(style_att, "ItalicSimulation")) fz_strlcat(fakename, "#Italic", sizeof fakename); else if (!strcmp(style_att, "BoldItalicSimulation")) fz_strlcat(fakename, "#BoldItalic", sizeof fakename); } font = xps_lookup_font(ctx, doc, fakename); if (!font) { fz_buffer *buf = NULL; fz_var(buf); fz_try(ctx) { part = xps_read_part(ctx, doc, partname); } fz_catch(ctx) { fz_rethrow_if(ctx, FZ_ERROR_TRYLATER); fz_warn(ctx, "cannot find font resource part '%s'", partname); return; } /* deobfuscate if necessary */ if (strstr(part->name, ".odttf")) xps_deobfuscate_font_resource(ctx, doc, part); if (strstr(part->name, ".ODTTF")) xps_deobfuscate_font_resource(ctx, doc, part); fz_try(ctx) { buf = fz_new_buffer_from_data(ctx, part->data, part->size); /* part->data is now owned by buf */ part->data = NULL; font = fz_new_font_from_buffer(ctx, NULL, buf, subfontid, 1); } fz_always(ctx) { fz_drop_buffer(ctx, buf); xps_drop_part(ctx, doc, part); } fz_catch(ctx) { fz_rethrow_if(ctx, FZ_ERROR_TRYLATER); fz_warn(ctx, "cannot load font resource '%s'", partname); return; } if (style_att) { font->ft_bold = !!strstr(style_att, "Bold"); font->ft_italic = !!strstr(style_att, "Italic"); } xps_select_best_font_encoding(ctx, doc, font); xps_insert_font(ctx, doc, fakename, font); }
static fz_xml * xps_load_fixed_page(fz_context *ctx, xps_document *doc, xps_fixpage *page) { xps_part *part; fz_xml *root; char *width_att; char *height_att; part = xps_read_part(ctx, doc, page->name); fz_try(ctx) { root = fz_parse_xml(ctx, part->data, part->size, 0); } fz_always(ctx) { xps_drop_part(ctx, doc, part); } fz_catch(ctx) { fz_rethrow_if(ctx, FZ_ERROR_TRYLATER); root = NULL; } if (!root) fz_throw(ctx, FZ_ERROR_GENERIC, "FixedPage missing root element"); if (fz_xml_is_tag(root, "AlternateContent")) { fz_xml *node = xps_lookup_alternate_content(ctx, doc, root); if (!node) { fz_drop_xml(ctx, root); fz_throw(ctx, FZ_ERROR_GENERIC, "FixedPage missing alternate root element"); } fz_detach_xml(node); fz_drop_xml(ctx, root); root = node; } if (!fz_xml_is_tag(root, "FixedPage")) { fz_drop_xml(ctx, root); fz_throw(ctx, FZ_ERROR_GENERIC, "expected FixedPage element"); } width_att = fz_xml_att(root, "Width"); if (!width_att) { fz_drop_xml(ctx, root); fz_throw(ctx, FZ_ERROR_GENERIC, "FixedPage missing required attribute: Width"); } height_att = fz_xml_att(root, "Height"); if (!height_att) { fz_drop_xml(ctx, root); fz_throw(ctx, FZ_ERROR_GENERIC, "FixedPage missing required attribute: Height"); } page->width = atoi(width_att); page->height = atoi(height_att); return root; }