diff options
author | Robin Watts <robin.watts@artifex.com> | 2012-05-09 19:13:14 +0100 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2012-05-10 13:38:26 +0100 |
commit | 90a289b18e2936bd2e585265964474df31c0dd5f (patch) | |
tree | ae9678288dd715bdf7c052f6c0ad4dc10a683507 /pdf/pdf_write.c | |
parent | b0beab3eecdb1681f5fb8a163278803aad852b81 (diff) | |
download | mupdf-90a289b18e2936bd2e585265964474df31c0dd5f.tar.xz |
mupdfclean - update to allow renumbering of encrypted objects
mupdfclean (or more correctly, the pdf_write function) currently has
a limitation, in that we cannot renumber objects when encryption is
being used. This is because the object/generation number is pickled
into the stream, and renumbering the object causes it to become
unreadable.
The solution used here is to provide extended functions that take both
the object/generation number and the original object/generation
number. The original object numbers are only used for setting up the
encryption.
pdf_write now keeps track of the original object/generation number
for each object.
This fix is important, if we ever want to output linearized pdf as
this requires us to be able to renumber objects to a very specific
order.
We also make a fix in removeduplicateobjects that should only
matter in the case where we fail to read an object correctly.
Diffstat (limited to 'pdf/pdf_write.c')
-rw-r--r-- | pdf/pdf_write.c | 56 |
1 files changed, 42 insertions, 14 deletions
diff --git a/pdf/pdf_write.c b/pdf/pdf_write.c index e14cfa28..e2086e5c 100644 --- a/pdf/pdf_write.c +++ b/pdf/pdf_write.c @@ -13,6 +13,8 @@ struct pdf_write_options_s int *ofslist; int *genlist; int *renumbermap; + int *revrenumbermap; + int *revgenlist; }; /* @@ -91,7 +93,7 @@ static void removeduplicateobjs(pdf_document *xref, pdf_write_options *opts) for (other = 1; other < num; other++) { pdf_obj *a, *b; - int match; + int differ, newnum; if (num == other || !opts->uselist[num] || !opts->uselist[other]) continue; @@ -104,14 +106,14 @@ static void removeduplicateobjs(pdf_document *xref, pdf_write_options *opts) */ fz_try(ctx) { - match = (pdf_is_stream(xref, num, 0) || pdf_is_stream(xref, other, 0)); + differ = (pdf_is_stream(xref, num, 0) || pdf_is_stream(xref, other, 0)); } fz_catch(ctx) { /* Assume different */ - match = 0; + differ = 1; } - if (match) + if (differ) continue; a = xref->table[num].obj; @@ -124,8 +126,10 @@ static void removeduplicateobjs(pdf_document *xref, pdf_write_options *opts) continue; /* Keep the lowest numbered object */ - opts->renumbermap[num] = MIN(num, other); - opts->renumbermap[other] = MIN(num, other); + newnum = MIN(num, other); + opts->renumbermap[num] = newnum; + opts->renumbermap[other] = newnum; + opts->revrenumbermap[newnum] = num; /* Either will do */ opts->uselist[MAX(num, other)] = 0; /* One duplicate was found, do not look for another */ @@ -136,6 +140,8 @@ static void removeduplicateobjs(pdf_document *xref, pdf_write_options *opts) /* * Renumber objects sequentially so the xref is more compact + * + * This code assumes that any opts->renumbermap[n] <= n for all n. */ static void compactxref(pdf_document *xref, pdf_write_options *opts) @@ -152,10 +158,25 @@ static void compactxref(pdf_document *xref, pdf_write_options *opts) newnum = 1; for (num = 1; num < xref->len; num++) { - if (opts->uselist[num] && opts->renumbermap[num] == num) + /* If it's not used, map it to zero */ + if (!opts->uselist[num]) + { + opts->renumbermap[num] = 0; + } + /* If it's not moved, compact it. */ + else if (opts->renumbermap[num] == num) + { + opts->revrenumbermap[newnum] = opts->revrenumbermap[num]; + opts->revgenlist[newnum] = opts->revgenlist[num]; opts->renumbermap[num] = newnum++; - else if (opts->renumbermap[num] != num) + } + /* Otherwise it's used, and moved. We know that it must have + * moved down, so the place it's moved to will be in the right + * place already. */ + else + { opts->renumbermap[num] = opts->renumbermap[opts->renumbermap[num]]; + } } } @@ -384,8 +405,10 @@ static void copystream(pdf_document *xref, pdf_write_options *opts, pdf_obj *obj fz_buffer *buf, *tmp; pdf_obj *newlen; fz_context *ctx = xref->ctx; + int orig_num = opts->revrenumbermap[num]; + int orig_gen = opts->revgenlist[num]; - buf = pdf_load_raw_stream(xref, num, gen); + buf = pdf_load_raw_renumbered_stream(xref, num, gen, orig_num, orig_gen); if (opts->doascii && isbinarystream(buf)) { @@ -414,8 +437,10 @@ static void expandstream(pdf_document *xref, pdf_write_options *opts, pdf_obj *o fz_buffer *buf, *tmp; pdf_obj *newlen; fz_context *ctx = xref->ctx; + int orig_num = opts->revrenumbermap[num]; + int orig_gen = opts->revgenlist[num]; - buf = pdf_load_stream(xref, num, gen); + buf = pdf_load_renumbered_stream(xref, num, gen, orig_num, orig_gen); pdf_dict_dels(obj, "Filter"); pdf_dict_dels(obj, "DecodeParms"); @@ -580,6 +605,8 @@ void pdf_write(pdf_document *xref, char *filename, fz_write_options *fz_opts) opts.ofslist = fz_malloc_array(ctx, xref->len + 1, sizeof(int)); opts.genlist = fz_malloc_array(ctx, xref->len + 1, sizeof(int)); opts.renumbermap = fz_malloc_array(ctx, xref->len + 1, sizeof(int)); + opts.revrenumbermap = fz_malloc_array(ctx, xref->len + 1, sizeof(int)); + opts.revgenlist = fz_malloc_array(ctx, xref->len + 1, sizeof(int)); fprintf(opts.out, "%%PDF-%d.%d\n", xref->version / 10, xref->version % 10); fprintf(opts.out, "%%\316\274\341\277\246\n\n"); @@ -589,6 +616,8 @@ void pdf_write(pdf_document *xref, char *filename, fz_write_options *fz_opts) opts.uselist[num] = 0; opts.ofslist[num] = 0; opts.renumbermap[num] = num; + opts.revrenumbermap[num] = num; + opts.revgenlist[num] = xref->table[num].gen; } /* Make sure any objects hidden in compressed streams have been loaded */ @@ -607,10 +636,7 @@ void pdf_write(pdf_document *xref, char *filename, fz_write_options *fz_opts) compactxref(xref, &opts); /* Make renumbering affect all indirect references and update xref */ - /* Do not renumber objects if encryption is in use, as the object - * numbers are baked into the streams/strings, and we can't currently - * cope with moving them. See bug 692627. */ - if (opts.dogarbage >= 2 && !xref->crypt) + if (opts.dogarbage >= 2) renumberobjs(xref, &opts); for (num = 0; num < xref->len; num++) @@ -653,6 +679,8 @@ void pdf_write(pdf_document *xref, char *filename, fz_write_options *fz_opts) fz_free(ctx, opts.ofslist); fz_free(ctx, opts.genlist); fz_free(ctx, opts.renumbermap); + fz_free(ctx, opts.revrenumbermap); + fz_free(ctx, opts.revgenlist); fclose(opts.out); } fz_catch(ctx) |