summaryrefslogtreecommitdiff
path: root/pdf/pdf_write.c
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2012-05-09 19:13:14 +0100
committerRobin Watts <robin.watts@artifex.com>2012-05-10 13:38:26 +0100
commit90a289b18e2936bd2e585265964474df31c0dd5f (patch)
treeae9678288dd715bdf7c052f6c0ad4dc10a683507 /pdf/pdf_write.c
parentb0beab3eecdb1681f5fb8a163278803aad852b81 (diff)
downloadmupdf-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.c56
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)