diff options
author | Robin Watts <robin.watts@artifex.com> | 2011-11-25 19:42:34 +0000 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2011-11-25 19:42:34 +0000 |
commit | bdf5c8848a2de071c8380fab86a1a49215ed5ee7 (patch) | |
tree | 8ff2e40bca4f337e5db112284992e6be67cea820 /pdf | |
parent | 5f6c8d94faecc0bd87113a138befe554ab2172b2 (diff) | |
parent | 6e14149d3e915f559f99276a525862e28d6f0478 (diff) | |
download | mupdf-bdf5c8848a2de071c8380fab86a1a49215ed5ee7.tar.xz |
Merge branch 'master' into context
Diffstat (limited to 'pdf')
-rw-r--r-- | pdf/mupdf.h | 19 | ||||
-rw-r--r-- | pdf/pdf_crypt.c | 6 | ||||
-rw-r--r-- | pdf/pdf_image.c | 12 | ||||
-rw-r--r-- | pdf/pdf_interpret.c | 283 | ||||
-rw-r--r-- | pdf/pdf_repair.c | 21 | ||||
-rw-r--r-- | pdf/pdf_xref.c | 171 |
6 files changed, 474 insertions, 38 deletions
diff --git a/pdf/mupdf.h b/pdf/mupdf.h index d3eb72e6..79560dab 100644 --- a/pdf/mupdf.h +++ b/pdf/mupdf.h @@ -45,6 +45,8 @@ char *pdf_from_ucs2(fz_context *ctx, unsigned short *str); typedef struct pdf_xref_entry_s pdf_xref_entry; typedef struct pdf_crypt_s pdf_crypt; +typedef struct pdf_ocg_descriptor_s pdf_ocg_descriptor; +typedef struct pdf_ocg_entry_s pdf_ocg_entry; struct pdf_xref_entry_s { @@ -55,6 +57,20 @@ struct pdf_xref_entry_s int type; /* 0=unset (f)ree i(n)use (o)bjstm */ }; +struct pdf_ocg_entry_s +{ + int num; + int gen; + int state; +}; + +struct pdf_ocg_descriptor_s +{ + int len; + pdf_ocg_entry *ocgs; + fz_obj *intent; +}; + struct pdf_xref_s { fz_context *ctx; @@ -64,6 +80,7 @@ struct pdf_xref_s int file_size; pdf_crypt *crypt; fz_obj *trailer; + pdf_ocg_descriptor *ocg; int len; pdf_xref_entry *table; @@ -478,7 +495,7 @@ void pdf_free_page(fz_context *ctx, pdf_page *page); * Content stream parsing */ -void pdf_run_page_with_usage(pdf_xref *xref, pdf_page *page, fz_device *dev, fz_matrix ctm, char *target); +void pdf_run_page_with_usage(pdf_xref *xref, pdf_page *page, fz_device *dev, fz_matrix ctm, char *event); void pdf_run_page(pdf_xref *xref, pdf_page *page, fz_device *dev, fz_matrix ctm); void pdf_run_glyph(pdf_xref *xref, fz_obj *resources, fz_buffer *contents, fz_device *dev, fz_matrix ctm); diff --git a/pdf/pdf_crypt.c b/pdf/pdf_crypt.c index 1ae16b37..98ad0159 100644 --- a/pdf/pdf_crypt.c +++ b/pdf/pdf_crypt.c @@ -722,7 +722,11 @@ pdf_crypt_obj_imp(fz_context *ctx, pdf_crypt *crypt, fz_obj *obj, unsigned char if (crypt->strf.method == PDF_CRYPT_AESV2 || crypt->strf.method == PDF_CRYPT_AESV3) { - if (n & 15 || n < 32) + if (n == 0) + { + /* Empty strings are permissible */ + } + else if (n & 15 || n < 32) fz_warn(ctx, "invalid string length for aes encryption"); else { diff --git a/pdf/pdf_image.c b/pdf/pdf_image.c index 438f4cef..849f703e 100644 --- a/pdf/pdf_image.c +++ b/pdf/pdf_image.c @@ -309,6 +309,18 @@ pdf_load_jpx_image(pdf_xref *xref, fz_obj *dict) img->mask = pdf_load_image_imp(xref, NULL, obj, NULL, 1); /* RJW: "cannot load image mask/softmask" */ } + + obj = fz_dict_getsa(dict, "Decode", "D"); + if (obj) + { + float decode[FZ_MAX_COLORS * 2]; + int i; + + for (i = 0; i < img->n * 2; i++) + decode[i] = fz_to_real(fz_array_get(obj, i)); + + fz_decode_tile(img, decode); + } } fz_catch(ctx) { diff --git a/pdf/pdf_interpret.c b/pdf/pdf_interpret.c index 85901539..0720f782 100644 --- a/pdf/pdf_interpret.c +++ b/pdf/pdf_interpret.c @@ -67,7 +67,7 @@ struct pdf_csi_s pdf_xref *xref; /* usage mode for optional content groups */ - char *target; /* "View", "Print", "Export" */ + char *event; /* "View", "Print", "Export" */ /* interpreter stack */ fz_obj *obj; @@ -79,6 +79,7 @@ struct pdf_csi_s int xbalance; int in_text; + int in_hidden_ocg; /* path object state */ fz_path *path; @@ -102,24 +103,194 @@ static void pdf_run_buffer(pdf_csi *csi, fz_obj *rdb, fz_buffer *contents); static void pdf_run_xobject(pdf_csi *csi, fz_obj *resources, pdf_xobject *xobj, fz_matrix transform); static void pdf_show_pattern(pdf_csi *csi, pdf_pattern *pat, fz_rect area, int what); +static int +ocg_intents_include(pdf_ocg_descriptor *desc, char *name) +{ + int i, len; + + if (strcmp(name, "All") == 0) + return 1; + + /* In the absence of a specified intent, it's 'View' */ + if (desc->intent == NULL) + return (strcmp(name, "View") == 0); + + if (fz_is_name(desc->intent)) + { + char *intent = fz_to_name(desc->intent); + if (strcmp(intent, "All") == 0) + return 1; + return (strcmp(intent, name) == 0); + } + if (!fz_is_array(desc->intent)) + return 0; + + len = fz_array_len(desc->intent); + for (i=0; i < len; i++) + { + char *intent = fz_to_name(fz_array_get(desc->intent, i)); + if (strcmp(intent, "All") == 0) + return 1; + if (strcmp(intent, name) == 0) + return 1; + } + return 0; +} static int -pdf_is_hidden_ocg(fz_context *ctx, fz_obj *xobj, char *target) +pdf_is_hidden_ocg(fz_obj *ocg, pdf_csi *csi, fz_obj *rdb) { - char target_state[16]; - fz_obj *obj; + char event_state[16]; + fz_obj *obj, *obj2; + char *type; + pdf_ocg_descriptor *desc = csi->xref->ocg; + + /* If no ocg descriptor, everything is visible */ + if (desc == NULL) + return 0; + + /* If we've been handed a name, look it up in the properties. */ + if (fz_is_name(ocg)) + { + ocg = fz_dict_gets(fz_dict_gets(rdb, "Properties"), fz_to_name(ocg)); + } + /* If we haven't been given an ocg at all, then we're visible */ + if (ocg == NULL) + return 0; + + fz_strlcpy(event_state, csi->event, sizeof event_state); + fz_strlcat(event_state, "State", sizeof event_state); + + type = fz_to_name(fz_dict_gets(ocg, "Type")); + + if (strcmp(type, "OCG") == 0) + { + /* An Optional Content Group */ + int num = fz_to_num(ocg); + int gen = fz_to_gen(ocg); + int len = desc->len; + int i; + + for (i = 0; i < len; i++) + { + if (desc->ocgs[i].num == num && desc->ocgs[i].gen == gen) + { + if (desc->ocgs[i].state == 0) + return 1; /* If off, hidden */ + break; + } + } - fz_strlcpy(target_state, target, sizeof target_state); - fz_strlcat(target_state, "State", sizeof target_state); + /* Check Intents; if our intent is not part of the set given + * by the current config, we should ignore it. */ + obj = fz_dict_gets(ocg, "Intent"); + if (fz_is_name(obj)) + { + /* If it doesn't match, it's hidden */ + if (ocg_intents_include(desc, fz_to_name(obj)) == 0) + return 1; + } + else if (fz_is_array(obj)) + { + int match = 0; + len = fz_array_len(obj); + for (i=0; i<len; i++) { + match |= ocg_intents_include(desc, fz_to_name(fz_array_get(obj, i))); + if (match) + break; + } + /* If we don't match any, it's hidden */ + if (match == 0) + return 1; + } + else + { + /* If it doesn't match, it's hidden */ + if (ocg_intents_include(desc, "View") == 0) + return 1; + } + + /* FIXME: Currently we do a very simple check whereby we look + * at the Usage object (an Optional Content Usage Dictionary) + * and check to see if the corresponding 'event' key is on + * or off. + * + * Really we should only look at Usage dictionaries that + * correspond to entries in the AS list in the OCG config. + * Given that we don't handle Zoom or User, or Language + * dicts, this is not really a problem. */ + obj = fz_dict_gets(ocg, "Usage"); + if (!fz_is_dict(obj)) + return 0; + /* FIXME: Should look at Zoom (and return hidden if out of + * max/min range) */ + /* FIXME: Could provide hooks to the caller to check if + * User is appropriate - if not return hidden. */ + obj2 = fz_dict_gets(obj, csi->event); + if (strcmp(fz_to_name(fz_dict_gets(obj2, event_state)), "OFF") == 0) + { + return 1; + } + return 0; + } + else if (strcmp(type, "OCMD") == 0) + { + /* An Optional Content Membership Dictionary */ + char *name; + int combine, on; + + obj = fz_dict_gets(ocg, "VE"); + if (fz_is_array(obj)) { + /* FIXME: Calculate visibility from array */ + return 0; + } + name = fz_to_name(fz_dict_gets(ocg, "P")); + /* Set combine; Bit 0 set => AND, Bit 1 set => true means + * Off, otherwise true means On */ + if (strcmp(name, "AllOn") == 0) + { + combine = 1; + } + else if (strcmp(name, "AnyOff") == 0) + { + combine = 2; + } + else if (strcmp(name, "AllOff") == 0) + { + combine = 3; + } + else /* Assume it's the default (AnyOn) */ + { + combine = 0; + } - obj = fz_dict_gets(xobj, "OC"); - obj = fz_dict_gets(obj, "OCGs"); - if (fz_is_array(obj)) - obj = fz_array_get(obj, 0); - obj = fz_dict_gets(obj, "Usage"); - obj = fz_dict_gets(obj, target); - obj = fz_dict_gets(obj, target_state); - return !strcmp(fz_to_name(obj), "OFF"); + obj = fz_dict_gets(ocg, "OCGs"); + on = combine & 1; + if (fz_is_array(obj)) { + int i, len; + len = fz_array_len(obj); + for (i = 0; i < len; i++) + { + int hidden; + hidden = pdf_is_hidden_ocg(fz_array_get(obj, i), csi, rdb); + if ((combine & 1) == 0) + hidden = !hidden; + if (combine & 2) + on &= hidden; + else + on |= hidden; + } + } + else + { + on = pdf_is_hidden_ocg(obj, csi, rdb); + if ((combine & 1) == 0) + on = !on; + } + return !on; + } + /* No idea what sort of object this is - be visible */ + return 0; } /* @@ -172,6 +343,9 @@ pdf_show_shade(pdf_csi *csi, fz_shade *shd) pdf_gstate *gstate = csi->gstate + csi->gtop; fz_rect bbox; + if (csi->in_hidden_ocg > 0) + return; + bbox = fz_bound_shade(shd, gstate->ctm); pdf_begin_group(csi, bbox); @@ -187,6 +361,9 @@ pdf_show_image(pdf_csi *csi, fz_pixmap *image) pdf_gstate *gstate = csi->gstate + csi->gtop; fz_rect bbox; + if (csi->in_hidden_ocg > 0) + return; + bbox = fz_transform_rect(gstate->ctm, fz_unit_rect); if (image->mask) @@ -266,8 +443,12 @@ pdf_show_path(pdf_csi *csi, int doclose, int dofill, int dostroke, int even_odd) { gstate->clip_depth++; fz_clip_path(csi->dev, path, NULL, csi->clip_even_odd, gstate->ctm); + csi->clip = 0; } + if (csi->in_hidden_ocg > 0) + dostroke = dofill = 0; + if (dofill || dostroke) pdf_begin_group(csi, bbox); @@ -369,6 +550,9 @@ pdf_flush_text(pdf_csi *csi) case 7: doclip = 1; break; } + if (csi->in_hidden_ocg > 0) + dostroke = dofill = 0; + bbox = fz_bound_text(text, gstate->ctm); pdf_begin_group(csi, bbox); @@ -656,14 +840,14 @@ pdf_init_gstate(pdf_gstate *gs, fz_matrix ctm) } static pdf_csi * -pdf_new_csi(pdf_xref *xref, fz_device *dev, fz_matrix ctm, char *target) +pdf_new_csi(pdf_xref *xref, fz_device *dev, fz_matrix ctm, char *event) { pdf_csi *csi; csi = fz_malloc(dev->ctx, sizeof(pdf_csi)); csi->xref = xref; csi->dev = dev; - csi->target = target; + csi->event = event; csi->top = 0; csi->obj = NULL; @@ -673,6 +857,7 @@ pdf_new_csi(pdf_xref *xref, fz_device *dev, fz_matrix ctm, char *target) csi->xbalance = 0; csi->in_text = 0; + csi->in_hidden_ocg = 0; csi->path = fz_new_path(xref->ctx); csi->clip = 0; @@ -1265,8 +1450,33 @@ pdf_run_extgstate(pdf_csi *csi, fz_obj *rdb, fz_obj *extgstate) * Operators */ -static void pdf_run_BDC(pdf_csi *csi) +static void pdf_run_BDC(pdf_csi *csi, fz_obj *rdb) { + fz_obj *ocg; + + /* If we are already in a hidden OCG, then we'll still be hidden - + * just increment the depth so we pop back to visibility when we've + * seen enough EDCs. */ + if (csi->in_hidden_ocg > 0) + { + csi->in_hidden_ocg++; + return; + } + + ocg = fz_dict_gets(fz_dict_gets(rdb, "Properties"), csi->name); + if (ocg == NULL) + { + /* No Properties array, or name not found in the properties + * means visible. */ + return; + } + if (strcmp(fz_to_name(fz_dict_gets(ocg, "Type")), "OCG") != 0) + { + /* Wrong type of property */ + return; + } + if (pdf_is_hidden_ocg(ocg, csi, rdb)) + csi->in_hidden_ocg++; } static void pdf_run_BI(pdf_csi *csi, fz_obj *rdb, fz_stream *file) @@ -1311,6 +1521,13 @@ static void pdf_run_B(pdf_csi *csi) static void pdf_run_BMC(pdf_csi *csi) { + /* If we are already in a hidden OCG, then we'll still be hidden - + * just increment the depth so we pop back to visibility when we've + * seen enough EDCs. */ + if (csi->in_hidden_ocg > 0) + { + csi->in_hidden_ocg++; + } } static void pdf_run_BT(pdf_csi *csi) @@ -1401,7 +1618,7 @@ static void pdf_run_Do(pdf_csi *csi, fz_obj *rdb) if (!fz_is_name(subtype)) fz_throw(ctx, "no XObject subtype specified"); - if (pdf_is_hidden_ocg(ctx, obj, csi->target)) + if (pdf_is_hidden_ocg(fz_dict_gets(obj, "OC"), csi, rdb)) return; if (!strcmp(fz_to_name(subtype), "Form") && fz_dict_gets(obj, "Subtype2")) @@ -1449,6 +1666,8 @@ static void pdf_run_Do(pdf_csi *csi, fz_obj *rdb) static void pdf_run_EMC(pdf_csi *csi) { + if (csi->in_hidden_ocg > 0) + csi->in_hidden_ocg--; } static void pdf_run_ET(pdf_csi *csi) @@ -1999,7 +2218,7 @@ pdf_run_keyword(pdf_csi *csi, fz_obj *rdb, fz_stream *file, char *buf) case A('\''): pdf_run_squote(csi); break; case A('B'): pdf_run_B(csi); break; case B('B','*'): pdf_run_Bstar(csi); break; - case C('B','D','C'): pdf_run_BDC(csi); break; + case C('B','D','C'): pdf_run_BDC(csi, rdb); break; case B('B','I'): pdf_run_BI(csi, rdb, file); /* RJW: "cannot draw inline image" */ @@ -2252,7 +2471,7 @@ pdf_run_buffer(pdf_csi *csi, fz_obj *rdb, fz_buffer *contents) } void -pdf_run_page_with_usage(pdf_xref *xref, pdf_page *page, fz_device *dev, fz_matrix ctm, char *target) +pdf_run_page_with_usage(pdf_xref *xref, pdf_page *page, fz_device *dev, fz_matrix ctm, char *event) { pdf_csi *csi; pdf_annot *annot; @@ -2262,7 +2481,7 @@ pdf_run_page_with_usage(pdf_xref *xref, pdf_page *page, fz_device *dev, fz_matri if (page->transparency) fz_begin_group(dev, fz_transform_rect(ctm, page->mediabox), 1, 0, 0, 1); - csi = pdf_new_csi(xref, dev, ctm, target); + csi = pdf_new_csi(xref, dev, ctm, event); fz_try(ctx) { pdf_run_buffer(csi, page->resources, page->contents); @@ -2286,18 +2505,18 @@ pdf_run_page_with_usage(pdf_xref *xref, pdf_page *page, fz_device *dev, fz_matri if (flags & (1 << 5)) /* NoView */ continue; - if (pdf_is_hidden_ocg(ctx, annot->obj, target)) - continue; - - csi = pdf_new_csi(xref, dev, ctm, target); - fz_try(ctx) - { - pdf_run_xobject(csi, page->resources, annot->ap, annot->matrix); - } - fz_catch(ctx) + csi = pdf_new_csi(xref, dev, ctm, event); + if (!pdf_is_hidden_ocg(fz_dict_gets(annot->obj, "OC"), csi, page->resources)) { - pdf_free_csi(csi); - fz_throw(ctx, "cannot parse annotation appearance stream"); + fz_try(ctx) + { + pdf_run_xobject(csi, page->resources, annot->ap, annot->matrix); + } + fz_catch(ctx) + { + pdf_free_csi(csi); + fz_throw(ctx, "cannot parse annotation appearance stream"); + } } pdf_free_csi(csi); } diff --git a/pdf/pdf_repair.c b/pdf/pdf_repair.c index 0a30f83b..abc443cc 100644 --- a/pdf/pdf_repair.c +++ b/pdf/pdf_repair.c @@ -33,8 +33,15 @@ pdf_repair_obj(fz_stream *file, char *buf, int cap, int *stmofsp, int *stmlenp, fz_obj *dict, *obj; /* Send NULL xref so we don't try to resolve references */ - dict = pdf_parse_dict(NULL, file, buf, cap); - /* RJW: "cannot parse object" */ + fz_try(ctx) + { + dict = pdf_parse_dict(NULL, file, buf, cap); + } + fz_catch(ctx) + { + /* Silently swallow the error */ + dict = fz_new_dict(ctx, 2); + } obj = fz_dict_gets(dict, "Type"); if (fz_is_name(obj) && !strcmp(fz_to_name(obj), "XRef")) @@ -66,13 +73,19 @@ pdf_repair_obj(fz_stream *file, char *buf, int cap, int *stmofsp, int *stmlenp, while ( tok != PDF_TOK_STREAM && tok != PDF_TOK_ENDOBJ && tok != PDF_TOK_ERROR && - tok != PDF_TOK_EOF ) + tok != PDF_TOK_EOF && + tok != PDF_TOK_INT ) { tok = pdf_lex(file, buf, cap, &len); /* RJW: "cannot scan for endobj or stream token" */ } - if (tok == PDF_TOK_STREAM) + if (tok == PDF_TOK_INT) + { + while (len-- > 0) + fz_unread_byte(file); + } + else if (tok == PDF_TOK_STREAM) { int c = fz_read_byte(file); if (c == '\r') { diff --git a/pdf/pdf_xref.c b/pdf/pdf_xref.c index cb538ae3..501db660 100644 --- a/pdf/pdf_xref.c +++ b/pdf/pdf_xref.c @@ -469,6 +469,165 @@ pdf_load_xref(pdf_xref *xref, char *buf, int bufsize) } } +void +pdf_ocg_set_config(pdf_xref *xref, int config) +{ + int i, j, len, len2; + pdf_ocg_descriptor *desc = xref->ocg; + fz_obj *obj, *cobj; + char *name; + + obj = fz_dict_gets(fz_dict_gets(xref->trailer, "Root"), "OCProperties"); + if (obj == NULL) + { + if (config == 0) + return; + else + fz_throw(xref->ctx, "Unknown OCG config (None known!)"); + } + if (config == 0) + { + cobj = fz_dict_gets(obj, "D"); + if (cobj == NULL) + fz_throw(xref->ctx, "No default OCG config"); + } + else + { + cobj = fz_array_get(fz_dict_gets(obj, "Configs"), config); + if (cobj == NULL) + fz_throw(xref->ctx, "Illegal OCG config"); + } + + if (desc->intent != NULL) + fz_drop_obj(desc->intent); + desc->intent = fz_dict_gets(cobj, "Intent"); + if (desc->intent != NULL) + fz_keep_obj(desc->intent); + + len = desc->len; + name = fz_to_name(fz_dict_gets(cobj, "BaseState")); + if (strcmp(name, "Unchanged") == 0) + { + /* Do nothing */ + } + else if (strcmp(name, "OFF") == 0) + { + for (i = 0; i < len; i++) + { + desc->ocgs[i].state = 0; + } + } + else /* Default to ON */ + { + for (i = 0; i < len; i++) + { + desc->ocgs[i].state = 1; + } + } + + obj = fz_dict_gets(cobj, "ON"); + len2 = fz_array_len(obj); + for (i = 0; i < len2; i++) + { + fz_obj *o = fz_array_get(obj, i); + int n = fz_to_num(o); + int g = fz_to_gen(o); + for (j=0; j < len; j++) + { + if (desc->ocgs[j].num == n && desc->ocgs[j].gen == g) + { + desc->ocgs[j].state = 1; + break; + } + } + } + + obj = fz_dict_gets(cobj, "OFF"); + len2 = fz_array_len(obj); + for (i = 0; i < len2; i++) + { + fz_obj *o = fz_array_get(obj, i); + int n = fz_to_num(o); + int g = fz_to_gen(o); + for (j=0; j < len; j++) + { + if (desc->ocgs[j].num == n && desc->ocgs[j].gen == g) + { + desc->ocgs[j].state = 0; + break; + } + } + } + + /* FIXME: Should make 'num configs' available in the descriptor. */ + /* FIXME: Should copy out 'Intent' here into the descriptor, and remove + * csi->intent in favour of that. */ + /* FIXME: Should copy 'AS' into the descriptor, and visibility + * decisions should respect it. */ + /* FIXME: Make 'Order' available via the descriptor (when we have an + * app that needs it) */ + /* FIXME: Make 'ListMode' available via the descriptor (when we have + * an app that needs it) */ + /* FIXME: Make 'RBGroups' available via the descriptor (when we have + * an app that needs it) */ + /* FIXME: Make 'Locked' available via the descriptor (when we have + * an app that needs it) */ +} + +static void +pdf_read_ocg(pdf_xref *xref) +{ + fz_obj *obj, *ocg; + int len, i; + pdf_ocg_descriptor * volatile desc; + fz_context *ctx = xref->ctx; + + obj = fz_dict_gets(fz_dict_gets(xref->trailer, "Root"), "OCProperties"); + if (obj == NULL) + return; + ocg = fz_dict_gets(obj, "OCGs"); + if (ocg == NULL || !fz_is_array(ocg)) + /* Not ever supposed to happen, but live with it. */ + return; + len = fz_array_len(ocg); + fz_try(ctx) + { + desc = fz_calloc(ctx, 1, sizeof(*desc)); + desc->len = len; + desc->ocgs = fz_calloc(ctx, len, sizeof(*desc->ocgs)); + desc->intent = NULL; + for (i=0; i < len; i++) + { + fz_obj *o = fz_array_get(ocg, i); + desc->ocgs[i].num = fz_to_num(o); + desc->ocgs[i].gen = fz_to_gen(o); + desc->ocgs[i].state = 0; + } + xref->ocg = desc; + } + fz_catch(ctx) + { + if (desc != NULL) + fz_free(ctx, desc->ocgs); + fz_free(ctx, desc); + fz_rethrow(ctx); + } + + pdf_ocg_set_config(xref, 0); +} + +static void +pdf_free_ocg(fz_context *ctx, pdf_ocg_descriptor *desc) +{ + if (desc == NULL) + return; + + if (desc->intent) + fz_drop_obj(desc->intent); + fz_free(ctx, desc->ocgs); + fz_free(ctx, desc); +} + /* * Initialize and load xref tables. * If password is not null, try to decrypt. @@ -591,6 +750,16 @@ pdf_open_xref_with_stream(fz_stream *file, char *password) fz_throw(ctx, "cannot open document"); } + fz_try(ctx) + { + pdf_read_ocg(xref); + } + fz_catch(ctx) + { + pdf_free_xref(xref); + fz_throw(ctx, "Broken Optional Content"); + } + return xref; } @@ -637,6 +806,8 @@ pdf_free_xref(pdf_xref *xref) if (xref->crypt) pdf_free_crypt(ctx, xref->crypt); + pdf_free_ocg(ctx, xref->ocg); + fz_free(ctx, xref); } |