reactos/rosapps/smartpdf/fitz/mupdf/pdf_stream.c
Daniel Reimer a7fddf9c07 Delete all Trailing spaces in code.
svn path=/trunk/; revision=29689
2007-10-19 23:05:02 +00:00

493 lines
8.7 KiB
C

#include "fitz.h"
#include "mupdf.h"
/*
* Check if an object is a stream or not.
*/
int
pdf_isstream(pdf_xref *xref, int oid, int gen)
{
fz_error *error;
if (oid < 0 || oid >= xref->len)
return 0;
error = pdf_cacheobject(xref, oid, gen);
if (error) {
fz_warn("%s", error->msg);
fz_droperror(error);
return 0;
}
return xref->table[oid].stmbuf || xref->table[oid].stmofs;
}
/*
* Create a filter given a name and param dictionary.
*/
static fz_error *
buildonefilter(fz_filter **fp, fz_obj *f, fz_obj *p)
{
fz_filter *decompress;
fz_filter *predict;
fz_error *error;
char *s;
s = fz_toname(f);
if (!strcmp(s, "ASCIIHexDecode") || !strcmp(s, "AHx"))
return fz_newahxd(fp, p);
if (!strcmp(s, "ASCII85Decode") || !strcmp(s, "A85"))
return fz_newa85d(fp, p);
if (!strcmp(s, "CCITTFaxDecode") || !strcmp(s, "CCF"))
return fz_newfaxd(fp, p);
if (!strcmp(s, "DCTDecode") || !strcmp(s, "DCT"))
return fz_newdctd(fp, p);
if (!strcmp(s, "RunLengthDecode") || !strcmp(s, "RL"))
return fz_newrld(fp, p);
if (!strcmp(s, "FlateDecode") || !strcmp(s, "Fl"))
{
if (fz_isdict(p))
{
fz_obj *obj = fz_dictgets(p, "Predictor");
if (obj)
{
error = fz_newflated(&decompress, p);
if (error)
return error;
error = fz_newpredictd(&predict, p);
if (error)
{
fz_dropfilter(decompress);
return error;
}
error = fz_newpipeline(fp, decompress, predict);
fz_dropfilter(decompress);
fz_dropfilter(predict);
return error;
}
}
return fz_newflated(fp, p);
}
if (!strcmp(s, "LZWDecode") || !strcmp(s, "LZW"))
{
if (fz_isdict(p))
{
fz_obj *obj = fz_dictgets(p, "Predictor");
if (obj)
{
error = fz_newlzwd(&decompress, p);
if (error)
return error;
error = fz_newpredictd(&predict, p);
if (error)
{
fz_dropfilter(decompress);
return error;
}
error = fz_newpipeline(fp, decompress, predict);
fz_dropfilter(decompress);
fz_dropfilter(predict);
return error;
}
}
return fz_newlzwd(fp, p);
}
#ifdef HAVE_JBIG2DEC
if (!strcmp(s, "JBIG2Decode"))
{
/* TODO: extract and feed JBIG2Global */
return fz_newjbig2d(fp, p);
}
#endif
#ifdef HAVE_JASPER
if (!strcmp(s, "JPXDecode"))
return fz_newjpxd(fp, p);
#endif
return fz_throw("syntaxerror: unknown filter: %s", s);
}
/*
* Build a chain of filters given filter names and param dicts.
* If head is given, start filter chain with it.
* Assume ownership of head.
*/
static fz_error *
buildfilterchain(fz_filter **filterp, fz_filter *head, fz_obj *fs, fz_obj *ps)
{
fz_error *error;
fz_filter *newhead;
fz_filter *tail;
fz_obj *f;
fz_obj *p;
int i;
for (i = 0; i < fz_arraylen(fs); i++)
{
f = fz_arrayget(fs, i);
if (fz_isarray(ps))
p = fz_arrayget(ps, i);
else
p = nil;
error = buildonefilter(&tail, f, p);
if (error)
return error;
if (head)
{
error = fz_newpipeline(&newhead, head, tail);
fz_dropfilter(head);
fz_dropfilter(tail);
if (error)
{
fz_dropfilter(newhead);
return error;
}
head = newhead;
}
else
head = tail;
}
*filterp = head;
return nil;
}
/*
* Build a filter for reading raw stream data.
* This is a null filter to constrain reading to the
* stream length, followed by a decryption filter.
*/
static fz_error *
buildrawfilter(fz_filter **filterp, pdf_xref *xref, fz_obj *stmobj, int oid, int gen)
{
fz_error *error;
fz_filter *base;
fz_obj *stmlen;
int len;
stmlen = fz_dictgets(stmobj, "Length");
error = pdf_resolve(&stmlen, xref);
if (error)
return error;
len = fz_toint(stmlen);
fz_dropobj(stmlen);
error = fz_newnullfilter(&base, len);
if (error)
return error;
if (xref->crypt)
{
fz_filter *crypt;
fz_filter *pipe;
error = pdf_cryptstream(&crypt, xref->crypt, oid, gen);
if (error)
{
fz_dropfilter(base);
return error;
}
error = fz_newpipeline(&pipe, base, crypt);
fz_dropfilter(base);
fz_dropfilter(crypt);
if (error)
return error;
*filterp = pipe;
}
else
{
*filterp = base;
}
return nil;
}
/*
* Construct a filter to decode a stream, without
* constraining to stream length, and without decryption.
*/
fz_error *
pdf_buildinlinefilter(fz_filter **filterp, fz_obj *stmobj)
{
fz_obj *filters;
fz_obj *params;
filters = fz_dictgetsa(stmobj, "Filter", "F");
params = fz_dictgetsa(stmobj, "DecodeParms", "DP");
*filterp = nil;
if (filters)
{
if (fz_isname(filters))
return buildonefilter(filterp, filters, params);
else if (fz_arraylen(filters) > 0)
return buildfilterchain(filterp, nil, filters, params);
}
/* uh oh, no filter */
return nil;
}
/*
* Construct a filter to decode a stream, constraining
* to stream length and decrypting.
*/
static fz_error *
pdf_buildfilter(fz_filter **filterp, pdf_xref *xref, fz_obj *stmobj, int oid, 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 error;
filters = fz_dictgetsa(stmobj, "Filter", "F");
params = fz_dictgetsa(stmobj, "DecodeParms", "DP");
if (filters)
{
error = pdf_resolve(&filters, xref);
if (error)
goto cleanup0;
if (params)
{
error = pdf_resolve(&params, xref);
if (error)
goto cleanup1;
}
if (fz_isname(filters))
{
error = buildonefilter(&tmp, filters, params);
if (error)
goto cleanup2;
error = fz_newpipeline(&pipe, base, tmp);
fz_dropfilter(base);
fz_dropfilter(tmp);
if (error)
goto cleanup2;
}
else
{
error = buildfilterchain(&pipe, base, filters, params);
if (error)
goto cleanup2;
}
if (params)
fz_dropobj(params);
fz_dropobj(filters);
*filterp = pipe;
}
else
{
*filterp = base;
}
return nil;
cleanup2:
if (params)
fz_dropobj(params);
cleanup1:
fz_dropobj(filters);
cleanup0:
fz_dropfilter(base);
return error;
}
/*
* Open a stream for reading the raw (compressed but decrypted) data.
* 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_xrefentry *x;
fz_error *error;
fz_filter *filter;
int n;
if (oid < 0 || oid >= xref->len)
return fz_throw("rangecheck: object id out of range");
x = xref->table + oid;
error = pdf_cacheobject(xref, oid, gen);
if (error)
return error;
if (x->stmbuf)
{
return fz_openrbuffer(stmp, x->stmbuf);
}
if (x->stmofs)
{
error = buildrawfilter(&filter, xref, x->obj, oid, gen);
if (error)
return error;
n = fz_seek(xref->file, x->stmofs, 0);
if (n == -1)
{
fz_dropfilter(filter);
return fz_ioerror(xref->file);
}
error = fz_openrfilter(stmp, filter, xref->file);
fz_dropfilter(filter);
if (error)
return error;
return nil;
}
return fz_throw("syntaxerror: object is not a stream");
}
/*
* Open a stream for reading uncompressed data.
* Put the opened file in xref->stream.
* 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_xrefentry *x;
fz_error *error;
fz_stream *rawstm;
fz_filter *filter;
int n;
if (oid < 0 || oid >= xref->len)
return fz_throw("rangecheck: object id out of range");
x = xref->table + oid;
error = pdf_cacheobject(xref, oid, gen);
if (error)
return error;
if (x->stmbuf)
{
error = pdf_buildfilter(&filter, xref, x->obj, oid, gen);
if (error)
return error;
error = fz_openrbuffer(&rawstm, x->stmbuf);
if (error)
{
fz_dropfilter(filter);
return error;
}
error = fz_openrfilter(stmp, filter, rawstm);
fz_dropfilter(filter);
fz_dropstream(rawstm);
return error;
}
if (x->stmofs)
{
error = pdf_buildfilter(&filter, xref, x->obj, oid, gen);
if (error)
return error;
n = fz_seek(xref->file, x->stmofs, 0);
if (n == -1)
{
fz_dropfilter(filter);
return fz_ioerror(xref->file);
}
error = fz_openrfilter(stmp, filter, xref->file);
fz_dropfilter(filter);
if (error)
return error;
return nil;
}
return fz_throw("syntaxerror: object is not a stream");
}
/*
* 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)
{
fz_error *error;
fz_stream *stm;
int n;
error = pdf_openrawstream(&stm, xref, oid, gen);
if (error)
return error;
n = fz_readall(bufp, stm);
if (n < 0)
error = fz_ioerror(stm);
else
error = nil;
fz_dropstream(stm);
return error;
}
/*
* Load uncompressed contents of a stream into buf.
*/
fz_error *
pdf_loadstream(fz_buffer **bufp, pdf_xref *xref, int oid, int gen)
{
fz_error *error;
fz_stream *stm;
int n;
error = pdf_openstream(&stm, xref, oid, gen);
if (error)
return error;
n = fz_readall(bufp, stm);
if (n < 0)
error = fz_ioerror(stm);
else
error = nil;
fz_dropstream(stm);
return error;
}