summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mupdf/mupdf.h2
-rw-r--r--mupdf/pdf_crypt.c10
-rw-r--r--mupdf/pdf_stream.c147
3 files changed, 112 insertions, 47 deletions
diff --git a/mupdf/mupdf.h b/mupdf/mupdf.h
index dab5b211..e4c8eef6 100644
--- a/mupdf/mupdf.h
+++ b/mupdf/mupdf.h
@@ -103,7 +103,7 @@ fz_error pdf_newcrypt(pdf_crypt **cp, fz_obj *enc, fz_obj *id);
void pdf_freecrypt(pdf_crypt *crypt);
fz_error pdf_parsecryptfilter(pdf_cryptfilter *cf, fz_obj *dict, int defaultlength);
-fz_error pdf_cryptstream(fz_filter **fp, pdf_crypt *crypt, int num, int gen);
+fz_error pdf_cryptstream(fz_filter **fp, pdf_crypt *crypt, pdf_cryptfilter *cf, int num, int gen);
void pdf_cryptobj(pdf_crypt *crypt, fz_obj *obj, int num, int gen);
int pdf_needspassword(pdf_xref *xref);
diff --git a/mupdf/pdf_crypt.c b/mupdf/pdf_crypt.c
index 48ea1b39..d06c0c32 100644
--- a/mupdf/pdf_crypt.c
+++ b/mupdf/pdf_crypt.c
@@ -603,15 +603,15 @@ pdf_cryptobj(pdf_crypt *crypt, fz_obj *obj, int num, int gen)
* Create filter suitable for de/encrypting a stream.
*/
fz_error
-pdf_cryptstream(fz_filter **fp, pdf_crypt *crypt, int num, int gen)
+pdf_cryptstream(fz_filter **fp, pdf_crypt *crypt, pdf_cryptfilter *stmf, int num, int gen)
{
fz_error error;
unsigned char key[16];
int len;
- len = pdf_computeobjectkey(crypt, &crypt->stmf, num, gen, key);
+ len = pdf_computeobjectkey(crypt, stmf, num, gen, key);
- if (crypt->stmf.method == PDF_CRYPT_NONE)
+ if (stmf->method == PDF_CRYPT_NONE)
{
error = fz_newcopyfilter(fp);
if (error)
@@ -619,7 +619,7 @@ pdf_cryptstream(fz_filter **fp, pdf_crypt *crypt, int num, int gen)
return fz_okay;
}
- if (crypt->stmf.method == PDF_CRYPT_RC4)
+ if (stmf->method == PDF_CRYPT_RC4)
{
error = fz_newarc4filter(fp, key, len);
if (error)
@@ -627,7 +627,7 @@ pdf_cryptstream(fz_filter **fp, pdf_crypt *crypt, int num, int gen)
return fz_okay;
}
- if (crypt->stmf.method == PDF_CRYPT_AESV2)
+ if (stmf->method == PDF_CRYPT_AESV2)
{
error = fz_newaesdfilter(fp, key, len);
if (error)
diff --git a/mupdf/pdf_stream.c b/mupdf/pdf_stream.c
index 86094bb8..4a5c8120 100644
--- a/mupdf/pdf_stream.c
+++ b/mupdf/pdf_stream.c
@@ -5,28 +5,58 @@
* Check if an object is a stream or not.
*/
int
-pdf_isstream(pdf_xref *xref, int oid, int gen)
+pdf_isstream(pdf_xref *xref, int num, int gen)
{
fz_error error;
- if (oid < 0 || oid >= xref->len)
+ if (num < 0 || num >= xref->len)
return 0;
- error = pdf_cacheobject(xref, oid, gen);
+ error = pdf_cacheobject(xref, num, gen);
if (error)
{
fz_catch(error, "could not load object, ignoring error");
return 0;
}
- return xref->table[oid].stmofs > 0;
+ return xref->table[num].stmofs > 0;
+}
+
+/*
+ * Scan stream dictionary for an explicit /Crypt filter
+ */
+static int
+pdf_streamhascrypt(fz_obj *stm)
+{
+ fz_obj *filters;
+ fz_obj *obj;
+ int i;
+
+ filters = fz_dictgetsa(stm, "Filter", "F");
+ if (filters)
+ {
+ if (fz_isname(filters))
+ if (!strcmp(fz_toname(filters), "Crypt"))
+ return 1;
+ if (fz_isarray(filters))
+ {
+ for (i = 0; i < fz_arraylen(filters); i++)
+ {
+ obj = fz_arrayget(filters, i);
+ if (fz_isname(obj))
+ if (!strcmp(fz_toname(obj), "Crypt"))
+ return 1;
+ }
+ }
+ }
+ return 0;
}
/*
* Create a filter given a name and param dictionary.
*/
static fz_error
-buildonefilter(fz_filter **fp, pdf_xref *xref, fz_obj *f, fz_obj *p)
+buildonefilter(fz_filter **fp, pdf_xref *xref, fz_obj *f, fz_obj *p, int num, int gen)
{
fz_filter *decompress;
fz_filter *predict;
@@ -149,6 +179,37 @@ buildonefilter(fz_filter **fp, pdf_xref *xref, fz_obj *f, fz_obj *p)
error = fz_newjpxd(fp, p);
#endif
+ else if (!strcmp(s, "Crypt"))
+ {
+ pdf_cryptfilter cf;
+ fz_obj *name;
+
+ if (!xref->crypt)
+ return fz_throw("crypt filter in unencrypted document");
+
+ name = fz_dictgets(p, "Name");
+ if (fz_isname(name) && strcmp(fz_toname(name), "Identity") != 0)
+ {
+ fz_obj *obj = fz_dictget(xref->crypt->cf, name);
+ if (fz_isdict(obj))
+ {
+ error = pdf_parsecryptfilter(&cf, obj, xref->crypt->length);
+ if (error)
+ return fz_rethrow(error, "cannot parse crypt filter");
+
+ error = pdf_cryptstream(fp, xref->crypt, &cf, num, gen);
+ if (error)
+ return fz_rethrow(error, "cannot create crypt filter");
+ return fz_okay;
+ }
+ }
+
+ error = fz_newcopyfilter(fp);
+ if (error)
+ return fz_rethrow(error, "cannot create identity crypt filter");
+ return fz_okay;
+ }
+
else
{
return fz_throw("unknown filter name (%s)", s);
@@ -165,7 +226,8 @@ buildonefilter(fz_filter **fp, pdf_xref *xref, fz_obj *f, fz_obj *p)
* Assume ownership of head.
*/
static fz_error
-buildfilterchain(fz_filter **filterp, pdf_xref *xref, fz_filter *head, fz_obj *fs, fz_obj *ps)
+buildfilterchain(fz_filter **filterp, pdf_xref *xref, fz_filter *head,
+ fz_obj *fs, fz_obj *ps, int num, int gen)
{
fz_error error;
fz_filter *newhead;
@@ -182,7 +244,7 @@ buildfilterchain(fz_filter **filterp, pdf_xref *xref, fz_filter *head, fz_obj *f
else
p = nil;
- error = buildonefilter(&tail, xref, f, p);
+ error = buildonefilter(&tail, xref, f, p, num, gen);
if (error)
return fz_rethrow(error, "cannot create filter");
@@ -212,12 +274,15 @@ buildfilterchain(fz_filter **filterp, pdf_xref *xref, fz_filter *head, fz_obj *f
* stream length, followed by a decryption filter.
*/
static fz_error
-buildrawfilter(fz_filter **filterp, pdf_xref *xref, fz_obj *stmobj, int oid, int gen)
+buildrawfilter(fz_filter **filterp, pdf_xref *xref, fz_obj *stmobj, int num, int gen)
{
fz_error error;
fz_filter *base;
fz_obj *stmlen;
int len;
+ int hascrypt;
+
+ hascrypt = pdf_streamhascrypt(stmobj);
stmlen = fz_dictgets(stmobj, "Length");
if (!fz_isint(stmlen))
@@ -228,12 +293,12 @@ buildrawfilter(fz_filter **filterp, pdf_xref *xref, fz_obj *stmobj, int oid, int
if (error)
return fz_rethrow(error, "cannot create null filter");
- if (xref->crypt)
+ if (xref->crypt && !hascrypt)
{
fz_filter *crypt;
fz_filter *pipe;
- error = pdf_cryptstream(&crypt, xref->crypt, oid, gen);
+ error = pdf_cryptstream(&crypt, xref->crypt, &xref->crypt->stmf, num, gen);
if (error)
{
fz_dropfilter(base);
@@ -273,9 +338,9 @@ pdf_buildinlinefilter(fz_filter **filterp, pdf_xref *xref, fz_obj *stmobj)
if (filters)
{
if (fz_isname(filters))
- error = buildonefilter(filterp, xref, filters, params);
+ error = buildonefilter(filterp, xref, filters, params, 0, 0);
else
- error = buildfilterchain(filterp, xref, nil, filters, params);
+ error = buildfilterchain(filterp, xref, nil, filters, params, 0, 0);
}
else
error = fz_newnullfilter(filterp, -1);
@@ -290,25 +355,25 @@ pdf_buildinlinefilter(fz_filter **filterp, pdf_xref *xref, fz_obj *stmobj)
* to stream length and decrypting.
*/
static fz_error
-pdf_buildfilter(fz_filter **filterp, pdf_xref *xref, fz_obj *stmobj, int oid, int gen)
+pdf_buildfilter(fz_filter **filterp, pdf_xref *xref, fz_obj *stmobj, int num, int gen)
{
fz_error error;
fz_filter *base, *pipe, *tmp;
fz_obj *filters;
fz_obj *params;
- error = buildrawfilter(&base, xref, stmobj, oid, gen);
- if (error)
- return fz_rethrow(error, "cannot create raw filter chain");
-
filters = fz_dictgetsa(stmobj, "Filter", "F");
params = fz_dictgetsa(stmobj, "DecodeParms", "DP");
+ error = buildrawfilter(&base, xref, stmobj, num, gen);
+ if (error)
+ return fz_rethrow(error, "cannot create raw filter chain");
+
if (filters)
{
if (fz_isname(filters))
{
- error = buildonefilter(&tmp, xref, filters, params);
+ error = buildonefilter(&tmp, xref, filters, params, num, gen);
if (error)
{
fz_dropfilter(base);
@@ -329,7 +394,7 @@ pdf_buildfilter(fz_filter **filterp, pdf_xref *xref, fz_obj *stmobj, int oid, in
else
{
/* The pipeline chain takes ownership of base */
- error = buildfilterchain(&pipe, xref, base, filters, params);
+ error = buildfilterchain(&pipe, xref, base, filters, params, num, gen);
if (error)
return fz_rethrow(error, "cannot create filter chain");
}
@@ -349,24 +414,24 @@ pdf_buildfilter(fz_filter **filterp, pdf_xref *xref, fz_obj *stmobj, int oid, in
* Using xref->file while this is open is a bad idea.
*/
fz_error
-pdf_openrawstream(fz_stream **stmp, pdf_xref *xref, int oid, int gen)
+pdf_openrawstream(fz_stream **stmp, pdf_xref *xref, int num, int gen)
{
pdf_xrefentry *x;
fz_error error;
fz_filter *filter;
- if (oid < 0 || oid >= xref->len)
- return fz_throw("object id out of range (%d %d R)", oid, gen);
+ if (num < 0 || num >= xref->len)
+ return fz_throw("object id out of range (%d %d R)", num, gen);
- x = xref->table + oid;
+ x = xref->table + num;
- error = pdf_cacheobject(xref, oid, gen);
+ error = pdf_cacheobject(xref, num, gen);
if (error)
- return fz_rethrow(error, "cannot load stream object (%d %d R)", oid, gen);
+ return fz_rethrow(error, "cannot load stream object (%d %d R)", num, gen);
if (x->stmofs)
{
- error = buildrawfilter(&filter, xref, x->obj, oid, gen);
+ error = buildrawfilter(&filter, xref, x->obj, num, gen);
if (error)
return fz_rethrow(error, "cannot create raw filter");
@@ -396,24 +461,24 @@ pdf_openrawstream(fz_stream **stmp, pdf_xref *xref, int oid, int gen)
* Using xref->file while a stream is open is a Bad idea.
*/
fz_error
-pdf_openstream(fz_stream **stmp, pdf_xref *xref, int oid, int gen)
+pdf_openstream(fz_stream **stmp, pdf_xref *xref, int num, int gen)
{
pdf_xrefentry *x;
fz_error error;
fz_filter *filter;
- if (oid < 0 || oid >= xref->len)
- return fz_throw("object id out of range (%d %d R)", oid, gen);
+ if (num < 0 || num >= xref->len)
+ return fz_throw("object id out of range (%d %d R)", num, gen);
- x = xref->table + oid;
+ x = xref->table + num;
- error = pdf_cacheobject(xref, oid, gen);
+ error = pdf_cacheobject(xref, num, gen);
if (error)
- return fz_rethrow(error, "cannot load stream object (%d %d R)", oid, gen);
+ return fz_rethrow(error, "cannot load stream object (%d %d R)", num, gen);
if (x->stmofs)
{
- error = pdf_buildfilter(&filter, xref, x->obj, oid, gen);
+ error = pdf_buildfilter(&filter, xref, x->obj, num, gen);
if (error)
return fz_rethrow(error, "cannot create filter");
@@ -439,19 +504,19 @@ pdf_openstream(fz_stream **stmp, pdf_xref *xref, int oid, int gen)
* Load raw (compressed but decrypted) contents of a stream into buf.
*/
fz_error
-pdf_loadrawstream(fz_buffer **bufp, pdf_xref *xref, int oid, int gen)
+pdf_loadrawstream(fz_buffer **bufp, pdf_xref *xref, int num, int gen)
{
fz_error error;
fz_stream *stm;
- error = pdf_openrawstream(&stm, xref, oid, gen);
+ error = pdf_openrawstream(&stm, xref, num, gen);
if (error)
- return fz_rethrow(error, "cannot open raw stream (%d %d R)", oid, gen);
+ return fz_rethrow(error, "cannot open raw stream (%d %d R)", num, gen);
error = fz_readall(bufp, stm, 0);
fz_dropstream(stm);
if (error)
- return fz_rethrow(error, "cannot load stream into buffer (%d %d R)", oid, gen);
+ return fz_rethrow(error, "cannot load stream into buffer (%d %d R)", num, gen);
return fz_okay;
}
@@ -459,19 +524,19 @@ pdf_loadrawstream(fz_buffer **bufp, pdf_xref *xref, int oid, int gen)
* Load uncompressed contents of a stream into buf.
*/
fz_error
-pdf_loadstream(fz_buffer **bufp, pdf_xref *xref, int oid, int gen)
+pdf_loadstream(fz_buffer **bufp, pdf_xref *xref, int num, int gen)
{
fz_error error;
fz_stream *stm;
- error = pdf_openstream(&stm, xref, oid, gen);
+ error = pdf_openstream(&stm, xref, num, gen);
if (error)
- return fz_rethrow(error, "cannot open stream (%d %d R)", oid, gen);
+ return fz_rethrow(error, "cannot open stream (%d %d R)", num, gen);
error = fz_readall(bufp, stm, 0);
fz_dropstream(stm);
if (error)
- return fz_rethrow(error, "cannot load stream into buffer (%d %d R)", oid, gen);
+ return fz_rethrow(error, "cannot load stream into buffer (%d %d R)", num, gen);
return fz_okay;
}