summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2012-06-11 15:50:30 +0100
committerRobin Watts <robin.watts@artifex.com>2012-06-11 19:55:53 +0100
commit120dabdf30be66b5d17f4c59862907bb5d176e27 (patch)
tree509ac66222e21248e98fd55eaf0408e098222878
parentb42125b79edc28af6508145a24308674403a8460 (diff)
downloadmupdf-120dabdf30be66b5d17f4c59862907bb5d176e27.tar.xz
Fix Bug 693099: Render failure due to corrupt jpeg data.
The file supplied with the bug contains corrupt jpeg data on page 61. This causes an error to be thrown which results in mudraw exiting. Previously, when image decode was done at loading time, the error would have been thrown under the pdf interpreter rather than under the display list renderer. This error would have been caught, a warning given, and the program would have continued. This is not ideal behaviour, as there is no way for a caller to know that there was a problem, and that the image is potentially incomplete. The solution adopted here, solves both these problems. The fz_cookie structure is expanded to include a 'errors' count. Whenever we meet an error during rendering, we increment the 'errors' count, and continue. This enables applications to spot the errors count being non-zero on exit and to display a warning. mupdf is updated here to pass a cookie in and to check the error count at the end; if it is found to be non zero, then a warning is given (just once per visit to each page) to say that the page may have errors on it.
-rw-r--r--apps/pdfapp.c21
-rw-r--r--apps/pdfapp.h1
-rw-r--r--fitz/dev_list.c179
-rw-r--r--fitz/fitz.h3
-rw-r--r--pdf/pdf_interpret.c190
5 files changed, 222 insertions, 172 deletions
diff --git a/apps/pdfapp.c b/apps/pdfapp.c
index b4ec4fbf..2a8ae3b5 100644
--- a/apps/pdfapp.c
+++ b/apps/pdfapp.c
@@ -229,6 +229,7 @@ static void pdfapp_loadpage(pdfapp_t *app)
{
fz_device *mdev = NULL;
int errored = 0;
+ fz_cookie cookie = { 0 };
fz_var(mdev);
@@ -270,7 +271,12 @@ static void pdfapp_loadpage(pdfapp_t *app)
/* Create display list */
app->page_list = fz_new_display_list(app->ctx);
mdev = fz_new_list_device(app->ctx, app->page_list);
- fz_run_page(app->doc, app->page, mdev, fz_identity, NULL);
+ fz_run_page(app->doc, app->page, mdev, fz_identity, &cookie);
+ if (cookie.errors)
+ {
+ pdfapp_warn(app, "Errors found on page");
+ errored = 1;
+ }
}
fz_always(app->ctx)
{
@@ -291,6 +297,8 @@ static void pdfapp_loadpage(pdfapp_t *app)
if (!errored)
pdfapp_warn(app, "Cannot load page");
}
+
+ app->errored = errored;
}
#define MAX_TITLE 256
@@ -303,6 +311,7 @@ static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repai
fz_colorspace *colorspace;
fz_matrix ctm;
fz_bbox bbox;
+ fz_cookie cookie = { 0 };
wincursor(app, WAIT);
@@ -318,7 +327,7 @@ static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repai
app->page_sheet = fz_new_text_sheet(app->ctx);
app->page_text = fz_new_text_page(app->ctx, app->page_bbox);
tdev = fz_new_text_device(app->ctx, app->page_sheet, app->page_text);
- fz_run_display_list(app->page_list, tdev, fz_identity, fz_infinite_bbox, NULL);
+ fz_run_display_list(app->page_list, tdev, fz_identity, fz_infinite_bbox, &cookie);
fz_free_device(tdev);
}
@@ -357,7 +366,7 @@ static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repai
app->image = fz_new_pixmap_with_bbox(app->ctx, colorspace, bbox);
fz_clear_pixmap_with_value(app->ctx, app->image, 255);
idev = fz_new_draw_device(app->ctx, app->image);
- fz_run_display_list(app->page_list, idev, ctm, bbox, NULL);
+ fz_run_display_list(app->page_list, idev, ctm, bbox, &cookie);
fz_free_device(idev);
if (app->invert)
fz_invert_pixmap(app->ctx, app->image);
@@ -388,6 +397,12 @@ static void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage, int repai
wincursor(app, ARROW);
}
+ if (cookie.errors && app->errored == 0)
+ {
+ app->errored = 1;
+ pdfapp_warn(app, "Errors found on page. Page rendering may be incomplete.");
+ }
+
fz_flush_warnings(app->ctx);
}
diff --git a/apps/pdfapp.h b/apps/pdfapp.h
index f93b816a..31ad18e1 100644
--- a/apps/pdfapp.h
+++ b/apps/pdfapp.h
@@ -56,6 +56,7 @@ struct pdfapp_s
fz_text_page *page_text;
fz_text_sheet *page_sheet;
fz_link *page_links;
+ int errored;
/* snapback history */
int hist[256];
diff --git a/fitz/dev_list.c b/fitz/dev_list.c
index 1ca8bf98..d84fb15b 100644
--- a/fitz/dev_list.c
+++ b/fitz/dev_list.c
@@ -593,6 +593,7 @@ fz_run_display_list(fz_display_list *list, fz_device *dev, fz_matrix top_ctm, fz
int tiled = 0;
int empty;
int progress = 0;
+ fz_context *ctx = dev->ctx;
if (cookie)
{
@@ -658,93 +659,103 @@ fz_run_display_list(fz_display_list *list, fz_device *dev, fz_matrix top_ctm, fz
visible:
ctm = fz_concat(node->ctm, top_ctm);
- switch (node->cmd)
- {
- case FZ_CMD_FILL_PATH:
- fz_fill_path(dev, node->item.path, node->flag, ctm,
- node->colorspace, node->color, node->alpha);
- break;
- case FZ_CMD_STROKE_PATH:
- fz_stroke_path(dev, node->item.path, node->stroke, ctm,
- node->colorspace, node->color, node->alpha);
- break;
- case FZ_CMD_CLIP_PATH:
- {
- fz_rect trect = fz_transform_rect(top_ctm, node->rect);
- fz_clip_path(dev, node->item.path, &trect, node->flag, ctm);
- break;
- }
- case FZ_CMD_CLIP_STROKE_PATH:
+ fz_try(ctx)
{
- fz_rect trect = fz_transform_rect(top_ctm, node->rect);
- fz_clip_stroke_path(dev, node->item.path, &trect, node->stroke, ctm);
- break;
+ switch (node->cmd)
+ {
+ case FZ_CMD_FILL_PATH:
+ fz_fill_path(dev, node->item.path, node->flag, ctm,
+ node->colorspace, node->color, node->alpha);
+ break;
+ case FZ_CMD_STROKE_PATH:
+ fz_stroke_path(dev, node->item.path, node->stroke, ctm,
+ node->colorspace, node->color, node->alpha);
+ break;
+ case FZ_CMD_CLIP_PATH:
+ {
+ fz_rect trect = fz_transform_rect(top_ctm, node->rect);
+ fz_clip_path(dev, node->item.path, &trect, node->flag, ctm);
+ break;
+ }
+ case FZ_CMD_CLIP_STROKE_PATH:
+ {
+ fz_rect trect = fz_transform_rect(top_ctm, node->rect);
+ fz_clip_stroke_path(dev, node->item.path, &trect, node->stroke, ctm);
+ break;
+ }
+ case FZ_CMD_FILL_TEXT:
+ fz_fill_text(dev, node->item.text, ctm,
+ node->colorspace, node->color, node->alpha);
+ break;
+ case FZ_CMD_STROKE_TEXT:
+ fz_stroke_text(dev, node->item.text, node->stroke, ctm,
+ node->colorspace, node->color, node->alpha);
+ break;
+ case FZ_CMD_CLIP_TEXT:
+ fz_clip_text(dev, node->item.text, ctm, node->flag);
+ break;
+ case FZ_CMD_CLIP_STROKE_TEXT:
+ fz_clip_stroke_text(dev, node->item.text, node->stroke, ctm);
+ break;
+ case FZ_CMD_IGNORE_TEXT:
+ fz_ignore_text(dev, node->item.text, ctm);
+ break;
+ case FZ_CMD_FILL_SHADE:
+ fz_fill_shade(dev, node->item.shade, ctm, node->alpha);
+ break;
+ case FZ_CMD_FILL_IMAGE:
+ fz_fill_image(dev, node->item.image, ctm, node->alpha);
+ break;
+ case FZ_CMD_FILL_IMAGE_MASK:
+ fz_fill_image_mask(dev, node->item.image, ctm,
+ node->colorspace, node->color, node->alpha);
+ break;
+ case FZ_CMD_CLIP_IMAGE_MASK:
+ {
+ fz_rect trect = fz_transform_rect(top_ctm, node->rect);
+ fz_clip_image_mask(dev, node->item.image, &trect, ctm);
+ break;
+ }
+ case FZ_CMD_POP_CLIP:
+ fz_pop_clip(dev);
+ break;
+ case FZ_CMD_BEGIN_MASK:
+ rect = fz_transform_rect(top_ctm, node->rect);
+ fz_begin_mask(dev, rect, node->flag, node->colorspace, node->color);
+ break;
+ case FZ_CMD_END_MASK:
+ fz_end_mask(dev);
+ break;
+ case FZ_CMD_BEGIN_GROUP:
+ rect = fz_transform_rect(top_ctm, node->rect);
+ fz_begin_group(dev, rect,
+ (node->flag & ISOLATED) != 0, (node->flag & KNOCKOUT) != 0,
+ node->item.blendmode, node->alpha);
+ break;
+ case FZ_CMD_END_GROUP:
+ fz_end_group(dev);
+ break;
+ case FZ_CMD_BEGIN_TILE:
+ tiled++;
+ rect.x0 = node->color[2];
+ rect.y0 = node->color[3];
+ rect.x1 = node->color[4];
+ rect.y1 = node->color[5];
+ fz_begin_tile(dev, node->rect, rect,
+ node->color[0], node->color[1], ctm);
+ break;
+ case FZ_CMD_END_TILE:
+ tiled--;
+ fz_end_tile(dev);
+ break;
+ }
}
- case FZ_CMD_FILL_TEXT:
- fz_fill_text(dev, node->item.text, ctm,
- node->colorspace, node->color, node->alpha);
- break;
- case FZ_CMD_STROKE_TEXT:
- fz_stroke_text(dev, node->item.text, node->stroke, ctm,
- node->colorspace, node->color, node->alpha);
- break;
- case FZ_CMD_CLIP_TEXT:
- fz_clip_text(dev, node->item.text, ctm, node->flag);
- break;
- case FZ_CMD_CLIP_STROKE_TEXT:
- fz_clip_stroke_text(dev, node->item.text, node->stroke, ctm);
- break;
- case FZ_CMD_IGNORE_TEXT:
- fz_ignore_text(dev, node->item.text, ctm);
- break;
- case FZ_CMD_FILL_SHADE:
- fz_fill_shade(dev, node->item.shade, ctm, node->alpha);
- break;
- case FZ_CMD_FILL_IMAGE:
- fz_fill_image(dev, node->item.image, ctm, node->alpha);
- break;
- case FZ_CMD_FILL_IMAGE_MASK:
- fz_fill_image_mask(dev, node->item.image, ctm,
- node->colorspace, node->color, node->alpha);
- break;
- case FZ_CMD_CLIP_IMAGE_MASK:
+ fz_catch(ctx)
{
- fz_rect trect = fz_transform_rect(top_ctm, node->rect);
- fz_clip_image_mask(dev, node->item.image, &trect, ctm);
- break;
- }
- case FZ_CMD_POP_CLIP:
- fz_pop_clip(dev);
- break;
- case FZ_CMD_BEGIN_MASK:
- rect = fz_transform_rect(top_ctm, node->rect);
- fz_begin_mask(dev, rect, node->flag, node->colorspace, node->color);
- break;
- case FZ_CMD_END_MASK:
- fz_end_mask(dev);
- break;
- case FZ_CMD_BEGIN_GROUP:
- rect = fz_transform_rect(top_ctm, node->rect);
- fz_begin_group(dev, rect,
- (node->flag & ISOLATED) != 0, (node->flag & KNOCKOUT) != 0,
- node->item.blendmode, node->alpha);
- break;
- case FZ_CMD_END_GROUP:
- fz_end_group(dev);
- break;
- case FZ_CMD_BEGIN_TILE:
- tiled++;
- rect.x0 = node->color[2];
- rect.y0 = node->color[3];
- rect.x1 = node->color[4];
- rect.y1 = node->color[5];
- fz_begin_tile(dev, node->rect, rect,
- node->color[0], node->color[1], ctm);
- break;
- case FZ_CMD_END_TILE:
- tiled--;
- fz_end_tile(dev);
- break;
+ /* Swallow the error */
+ if (cookie)
+ cookie->errors++;
+ fz_warn(ctx, "Ignoring error during interpretation");
}
}
}
diff --git a/fitz/fitz.h b/fitz/fitz.h
index a10fd4dc..1892bc5e 100644
--- a/fitz/fitz.h
+++ b/fitz/fitz.h
@@ -1750,12 +1750,15 @@ typedef struct fz_cookie_s fz_cookie;
may change from -1 to a positive value once an upper bound is
known, so take this into consideration when comparing the
value of progress to that of progress_max.
+
+ errors: count of errors during current rendering.
*/
struct fz_cookie_s
{
int abort;
int progress;
int progress_max; /* -1 for unknown */
+ int errors;
};
/*
diff --git a/pdf/pdf_interpret.c b/pdf/pdf_interpret.c
index 8851be6e..870050df 100644
--- a/pdf/pdf_interpret.c
+++ b/pdf/pdf_interpret.c
@@ -2434,7 +2434,7 @@ pdf_run_keyword(pdf_csi *csi, pdf_obj *rdb, fz_stream *file, char *buf)
}
fz_catch(ctx)
{
- fz_warn(ctx, "cannot draw xobject/image");
+ fz_throw(ctx, "cannot draw xobject/image");
}
break;
case C('E','M','C'): pdf_run_EMC(csi); break;
@@ -2464,7 +2464,7 @@ pdf_run_keyword(pdf_csi *csi, pdf_obj *rdb, fz_stream *file, char *buf)
}
fz_catch(ctx)
{
- fz_warn(ctx, "cannot set font");
+ fz_throw(ctx, "cannot set font");
}
break;
case B('T','j'): pdf_run_Tj(csi); break;
@@ -2493,7 +2493,7 @@ pdf_run_keyword(pdf_csi *csi, pdf_obj *rdb, fz_stream *file, char *buf)
}
fz_catch(ctx)
{
- fz_warn(ctx, "cannot set graphics state");
+ fz_throw(ctx, "cannot set graphics state");
}
break;
case A('h'): pdf_run_h(csi); break;
@@ -2517,7 +2517,7 @@ pdf_run_keyword(pdf_csi *csi, pdf_obj *rdb, fz_stream *file, char *buf)
}
fz_catch(ctx)
{
- fz_warn(ctx, "cannot draw shading");
+ fz_throw(ctx, "cannot draw shading");
}
break;
case A('v'): pdf_run_v(csi); break;
@@ -2525,7 +2525,7 @@ pdf_run_keyword(pdf_csi *csi, pdf_obj *rdb, fz_stream *file, char *buf)
case A('y'): pdf_run_y(csi); break;
default:
if (!csi->xbalance)
- fz_warn(ctx, "unknown keyword: '%s'", buf);
+ fz_throw(ctx, "unknown keyword: '%s'", buf);
break;
}
}
@@ -2540,13 +2540,15 @@ pdf_run_stream(pdf_csi *csi, pdf_obj *rdb, fz_stream *file, pdf_lexbuf *buf)
pdf_clear_stack(csi);
in_array = 0;
+ fz_var(in_array);
+
if (csi->cookie)
{
csi->cookie->progress_max = -1;
csi->cookie->progress = 0;
}
- while (1)
+ do
{
if (csi->top == nelem(csi->stack) - 1)
fz_throw(ctx, "stack overflow");
@@ -2555,105 +2557,123 @@ pdf_run_stream(pdf_csi *csi, pdf_obj *rdb, fz_stream *file, pdf_lexbuf *buf)
if (csi->cookie)
{
if (csi->cookie->abort)
+ {
+ tok = PDF_TOK_EOF;
break;
+ }
csi->cookie->progress++;
}
- tok = pdf_lex(file, buf);
- /* RJW: "lexical error in content stream" */
-
- if (in_array)
+ fz_try(ctx)
{
- if (tok == PDF_TOK_CLOSE_ARRAY)
- {
- in_array = 0;
- }
- else if (tok == PDF_TOK_REAL)
- {
- pdf_gstate *gstate = csi->gstate + csi->gtop;
- pdf_show_space(csi, -buf->f * gstate->size * 0.001f);
- }
- else if (tok == PDF_TOK_INT)
- {
- pdf_gstate *gstate = csi->gstate + csi->gtop;
- pdf_show_space(csi, -buf->i * gstate->size * 0.001f);
- }
- else if (tok == PDF_TOK_STRING)
- {
- pdf_show_string(csi, (unsigned char *)buf->scratch, buf->len);
- }
- else if (tok == PDF_TOK_KEYWORD)
+ tok = pdf_lex(file, buf);
+ /* RJW: "lexical error in content stream" */
+
+ if (in_array)
{
- if (!strcmp(buf->scratch, "Tw") || !strcmp(buf->scratch, "Tc"))
- fz_warn(ctx, "ignoring keyword '%s' inside array", buf->scratch);
+ if (tok == PDF_TOK_CLOSE_ARRAY)
+ {
+ in_array = 0;
+ }
+ else if (tok == PDF_TOK_REAL)
+ {
+ pdf_gstate *gstate = csi->gstate + csi->gtop;
+ pdf_show_space(csi, -buf->f * gstate->size * 0.001f);
+ }
+ else if (tok == PDF_TOK_INT)
+ {
+ pdf_gstate *gstate = csi->gstate + csi->gtop;
+ pdf_show_space(csi, -buf->i * gstate->size * 0.001f);
+ }
+ else if (tok == PDF_TOK_STRING)
+ {
+ pdf_show_string(csi, (unsigned char *)buf->scratch, buf->len);
+ }
+ else if (tok == PDF_TOK_KEYWORD)
+ {
+ if (!strcmp(buf->scratch, "Tw") || !strcmp(buf->scratch, "Tc"))
+ fz_warn(ctx, "ignoring keyword '%s' inside array", buf->scratch);
+ else
+ fz_throw(ctx, "syntax error in array");
+ }
+ else if (tok == PDF_TOK_EOF)
+ break;
else
fz_throw(ctx, "syntax error in array");
}
- else if (tok == PDF_TOK_EOF)
- return;
- else
- fz_throw(ctx, "syntax error in array");
- }
-
- else switch (tok)
- {
- case PDF_TOK_ENDSTREAM:
- case PDF_TOK_EOF:
- return;
- case PDF_TOK_OPEN_ARRAY:
- if (!csi->in_text)
- {
- csi->obj = pdf_parse_array(csi->xref, file, buf);
- /* RJW: "cannot parse array" */
- }
- else
+ else switch (tok)
{
- in_array = 1;
- }
- break;
+ case PDF_TOK_ENDSTREAM:
+ case PDF_TOK_EOF:
+ tok = PDF_TOK_EOF;
+ break;
- case PDF_TOK_OPEN_DICT:
- csi->obj = pdf_parse_dict(csi->xref, file, buf);
- /* RJW: "cannot parse dictionary" */
- break;
+ case PDF_TOK_OPEN_ARRAY:
+ if (!csi->in_text)
+ {
+ csi->obj = pdf_parse_array(csi->xref, file, buf);
+ /* RJW: "cannot parse array" */
+ }
+ else
+ {
+ in_array = 1;
+ }
+ break;
- case PDF_TOK_NAME:
- fz_strlcpy(csi->name, buf->scratch, sizeof(csi->name));
- break;
+ case PDF_TOK_OPEN_DICT:
+ csi->obj = pdf_parse_dict(csi->xref, file, buf);
+ /* RJW: "cannot parse dictionary" */
+ break;
- case PDF_TOK_INT:
- csi->stack[csi->top] = buf->i;
- csi->top ++;
- break;
+ case PDF_TOK_NAME:
+ fz_strlcpy(csi->name, buf->scratch, sizeof(csi->name));
+ break;
- case PDF_TOK_REAL:
- csi->stack[csi->top] = buf->f;
- csi->top ++;
- break;
+ case PDF_TOK_INT:
+ csi->stack[csi->top] = buf->i;
+ csi->top ++;
+ break;
- case PDF_TOK_STRING:
- if (buf->len <= sizeof(csi->string))
- {
- memcpy(csi->string, buf->scratch, buf->len);
- csi->string_len = buf->len;
- }
- else
- {
- csi->obj = pdf_new_string(ctx, buf->scratch, buf->len);
- }
- break;
+ case PDF_TOK_REAL:
+ csi->stack[csi->top] = buf->f;
+ csi->top ++;
+ break;
- case PDF_TOK_KEYWORD:
- pdf_run_keyword(csi, rdb, file, buf->scratch);
- /* RJW: "cannot run keyword" */
- pdf_clear_stack(csi);
- break;
+ case PDF_TOK_STRING:
+ if (buf->len <= sizeof(csi->string))
+ {
+ memcpy(csi->string, buf->scratch, buf->len);
+ csi->string_len = buf->len;
+ }
+ else
+ {
+ csi->obj = pdf_new_string(ctx, buf->scratch, buf->len);
+ }
+ break;
+
+ case PDF_TOK_KEYWORD:
+ pdf_run_keyword(csi, rdb, file, buf->scratch);
+ /* RJW: "cannot run keyword" */
+ pdf_clear_stack(csi);
+ break;
- default:
- fz_throw(ctx, "syntax error in content stream");
+ default:
+ fz_throw(ctx, "syntax error in content stream");
+ }
+ }
+ fz_catch(ctx)
+ {
+ /* Swallow the error */
+ if (csi->cookie)
+ csi->cookie->errors++;
+ fz_warn(ctx, "Ignoring error during rendering");
+ /* If we do catch an error, then reset ourselves to a
+ * base lexing state */
+ in_array = 0;
}
}
+ while (tok != PDF_TOK_EOF);
}
/*