mirror of
https://github.com/reactos/reactos.git
synced 2025-01-03 21:09:19 +00:00
435a566751
* sumatrapdf - vendor import * everything compiles (libjpeg, poppler, fitz, sumatrapdf) * does NOT link (remove the comment tags in the parent directory.rbuild file (rosapps dir) to build it) svn path=/trunk/; revision=29295
455 lines
7.8 KiB
C
455 lines
7.8 KiB
C
#include <fitz.h>
|
|
#include <mupdf.h>
|
|
|
|
/*
|
|
* create xref structure.
|
|
* needs to be initialized by initxref, openxref or repairxref.
|
|
*/
|
|
|
|
fz_error *
|
|
pdf_newxref(pdf_xref **xrefp)
|
|
{
|
|
pdf_xref *xref;
|
|
|
|
xref = fz_malloc(sizeof(pdf_xref));
|
|
if (!xref)
|
|
return fz_outofmem;
|
|
memset(xref, 0, sizeof(pdf_xref));
|
|
|
|
pdf_logxref("newxref %p\n", xref);
|
|
|
|
xref->file = nil;
|
|
xref->version = 1.3f;
|
|
xref->startxref = 0;
|
|
xref->crypt = nil;
|
|
|
|
xref->trailer = nil;
|
|
xref->root = nil;
|
|
xref->info = nil;
|
|
xref->dests = nil;
|
|
xref->store = nil;
|
|
|
|
xref->cap = 0;
|
|
xref->len = 0;
|
|
xref->table = nil;
|
|
|
|
xref->store = nil; /* you need to create this if you want to render */
|
|
|
|
*xrefp = xref;
|
|
return nil;
|
|
}
|
|
|
|
void
|
|
pdf_closexref(pdf_xref *xref)
|
|
{
|
|
pdf_logxref("closexref %p\n", xref);
|
|
|
|
if (xref->store)
|
|
fz_warn("someone forgot to empty the store before freeing xref!");
|
|
|
|
if (xref->table)
|
|
{
|
|
pdf_flushxref(xref, 1);
|
|
fz_free(xref->table);
|
|
}
|
|
|
|
if (xref->file)
|
|
fz_dropstream(xref->file);
|
|
|
|
if (xref->crypt)
|
|
pdf_dropcrypt(xref->crypt);
|
|
if (xref->trailer)
|
|
fz_dropobj(xref->trailer);
|
|
if (xref->root)
|
|
fz_dropobj(xref->root);
|
|
if (xref->info)
|
|
fz_dropobj(xref->info);
|
|
if (xref->dests)
|
|
fz_dropobj(xref->dests);
|
|
|
|
fz_free(xref);
|
|
}
|
|
|
|
fz_error *
|
|
pdf_initxref(pdf_xref *xref)
|
|
{
|
|
xref->table = fz_malloc(sizeof(pdf_xrefentry) * 128);
|
|
if (!xref->table)
|
|
return fz_outofmem;
|
|
|
|
xref->cap = 128;
|
|
xref->len = 1;
|
|
|
|
xref->table[0].type = 'f';
|
|
xref->table[0].mark = 0;
|
|
xref->table[0].ofs = 0;
|
|
xref->table[0].gen = 65535;
|
|
xref->table[0].stmbuf = nil;
|
|
xref->table[0].stmofs = 0;
|
|
xref->table[0].obj = nil;
|
|
|
|
return nil;
|
|
}
|
|
|
|
void
|
|
pdf_flushxref(pdf_xref *xref, int force)
|
|
{
|
|
int i;
|
|
|
|
pdf_logxref("flushxref %p (%d)\n", xref, force);
|
|
|
|
for (i = 0; i < xref->len; i++)
|
|
{
|
|
if (force)
|
|
{
|
|
if (xref->table[i].stmbuf)
|
|
{
|
|
fz_dropbuffer(xref->table[i].stmbuf);
|
|
xref->table[i].stmbuf = nil;
|
|
}
|
|
if (xref->table[i].obj)
|
|
{
|
|
fz_dropobj(xref->table[i].obj);
|
|
xref->table[i].obj = nil;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (xref->table[i].stmbuf && xref->table[i].stmbuf->refs == 1)
|
|
{
|
|
fz_dropbuffer(xref->table[i].stmbuf);
|
|
xref->table[i].stmbuf = nil;
|
|
}
|
|
if (xref->table[i].obj && xref->table[i].obj->refs == 1)
|
|
{
|
|
fz_dropobj(xref->table[i].obj);
|
|
xref->table[i].obj = nil;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
pdf_debugxref(pdf_xref *xref)
|
|
{
|
|
int i;
|
|
printf("xref\n0 %d\n", xref->len);
|
|
for (i = 0; i < xref->len; i++)
|
|
{
|
|
printf("%010d %05d %c | %d %c%c\n",
|
|
xref->table[i].ofs,
|
|
xref->table[i].gen,
|
|
xref->table[i].type,
|
|
xref->table[i].obj ? xref->table[i].obj->refs : 0,
|
|
xref->table[i].stmofs ? 'f' : '-',
|
|
xref->table[i].stmbuf ? 'b' : '-');
|
|
}
|
|
}
|
|
|
|
/* ICKY! */
|
|
fz_error *
|
|
pdf_decryptxref(pdf_xref *xref)
|
|
{
|
|
fz_error *error;
|
|
fz_obj *encrypt;
|
|
fz_obj *id;
|
|
|
|
encrypt = fz_dictgets(xref->trailer, "Encrypt");
|
|
id = fz_dictgets(xref->trailer, "ID");
|
|
|
|
if (encrypt && id)
|
|
{
|
|
error = pdf_resolve(&encrypt, xref);
|
|
if (error)
|
|
return error;
|
|
|
|
if (fz_isnull(encrypt))
|
|
{
|
|
fz_dropobj(encrypt);
|
|
return nil;
|
|
}
|
|
|
|
error = pdf_resolve(&id, xref);
|
|
if (error)
|
|
{
|
|
fz_dropobj(encrypt);
|
|
return error;
|
|
}
|
|
|
|
error = pdf_newdecrypt(&xref->crypt, encrypt, id);
|
|
fz_dropobj(encrypt);
|
|
fz_dropobj(id);
|
|
return error;
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|
|
/*
|
|
* mutate objects
|
|
*/
|
|
|
|
static int findprev(pdf_xref *xref, int oid)
|
|
{
|
|
int prev;
|
|
for (prev = oid - 1; prev >= 0; prev--)
|
|
if (xref->table[prev].type == 'f' || xref->table[prev].type == 'd')
|
|
return prev;
|
|
return 0;
|
|
}
|
|
|
|
static int findnext(pdf_xref *xref, int oid)
|
|
{
|
|
int next;
|
|
for (next = oid + 1; next < xref->len; next++)
|
|
if (xref->table[next].type == 'f' || xref->table[next].type == 'd')
|
|
return next;
|
|
return 0;
|
|
}
|
|
|
|
fz_error *
|
|
pdf_allocobject(pdf_xref *xref, int *oidp, int *genp)
|
|
{
|
|
pdf_xrefentry *x;
|
|
int prev, next;
|
|
int oid = 0;
|
|
|
|
pdf_logxref("allocobj");
|
|
|
|
while (1)
|
|
{
|
|
x = xref->table + oid;
|
|
|
|
if (x->type == 'f' || x->type == 'd')
|
|
{
|
|
if (x->gen < 65535)
|
|
{
|
|
*oidp = oid;
|
|
*genp = x->gen;
|
|
|
|
pdf_logxref(" reuse %d %d\n", *oidp, *genp);
|
|
|
|
x->type = 'a';
|
|
x->ofs = 0;
|
|
|
|
prev = findprev(xref, oid);
|
|
next = findnext(xref, oid);
|
|
xref->table[prev].type = 'd';
|
|
xref->table[prev].ofs = next;
|
|
|
|
return nil;
|
|
}
|
|
}
|
|
|
|
oid = x->ofs;
|
|
|
|
if (oid == 0)
|
|
break;
|
|
}
|
|
|
|
if (xref->len + 1 >= xref->cap)
|
|
{
|
|
int newcap = xref->cap + 256;
|
|
pdf_xrefentry *newtable;
|
|
|
|
newtable = fz_realloc(xref->table, sizeof(pdf_xrefentry) * newcap);
|
|
if (!newtable)
|
|
return fz_outofmem;
|
|
|
|
xref->table = newtable;
|
|
xref->cap = newcap;
|
|
}
|
|
|
|
oid = xref->len ++;
|
|
|
|
xref->table[oid].type = 'a';
|
|
xref->table[oid].mark = 0;
|
|
xref->table[oid].ofs = 0;
|
|
xref->table[oid].gen = 0;
|
|
xref->table[oid].stmbuf = nil;
|
|
xref->table[oid].stmofs = 0;
|
|
xref->table[oid].obj = nil;
|
|
|
|
*oidp = oid;
|
|
*genp = 0;
|
|
|
|
pdf_logxref(" %d %d\n", *oidp, *genp);
|
|
|
|
prev = findprev(xref, oid);
|
|
next = findnext(xref, oid);
|
|
xref->table[prev].type = 'd';
|
|
xref->table[prev].ofs = next;
|
|
|
|
return nil;
|
|
}
|
|
|
|
fz_error *
|
|
pdf_deleteobject(pdf_xref *xref, int oid, int gen)
|
|
{
|
|
pdf_xrefentry *x;
|
|
int prev;
|
|
|
|
if (oid < 0 || oid >= xref->len)
|
|
return fz_throw("rangecheck: object number out of range: %d", oid);
|
|
|
|
pdf_logxref("deleteobj %d %d\n", oid, gen);
|
|
|
|
x = xref->table + oid;
|
|
|
|
x->type = 'd';
|
|
x->ofs = findnext(xref, oid);
|
|
x->gen ++;
|
|
|
|
if (x->stmbuf)
|
|
fz_dropbuffer(x->stmbuf);
|
|
x->stmbuf = nil;
|
|
|
|
if (x->obj)
|
|
fz_dropobj(x->obj);
|
|
x->obj = nil;
|
|
|
|
prev = findprev(xref, oid);
|
|
xref->table[prev].type = 'd';
|
|
xref->table[prev].ofs = oid;
|
|
|
|
return nil;
|
|
}
|
|
|
|
fz_error *
|
|
pdf_updateobject(pdf_xref *xref, int oid, int gen, fz_obj *obj)
|
|
{
|
|
pdf_xrefentry *x;
|
|
|
|
if (oid < 0 || oid >= xref->len)
|
|
return fz_throw("rangecheck: object number out of range: %d", oid);
|
|
|
|
pdf_logxref("updateobj %d %d (%p)\n", oid, gen, obj);
|
|
|
|
x = xref->table + oid;
|
|
|
|
if (x->obj)
|
|
fz_dropobj(x->obj);
|
|
x->obj = fz_keepobj(obj);
|
|
|
|
if (x->type == 'f' || x->type == 'd')
|
|
{
|
|
int prev = findprev(xref, oid);
|
|
int next = findnext(xref, oid);
|
|
xref->table[prev].type = 'd';
|
|
xref->table[prev].ofs = next;
|
|
}
|
|
|
|
x->type = 'a';
|
|
|
|
return nil;
|
|
}
|
|
|
|
fz_error *
|
|
pdf_updatestream(pdf_xref *xref, int oid, int gen, fz_buffer *stm)
|
|
{
|
|
pdf_xrefentry *x;
|
|
|
|
if (oid < 0 || oid >= xref->len)
|
|
return fz_throw("rangecheck: object number out of range: %d", oid);
|
|
|
|
pdf_logxref("updatestm %d %d (%p)\n", oid, gen, stm);
|
|
|
|
x = xref->table + oid;
|
|
|
|
if (x->stmbuf)
|
|
fz_dropbuffer(x->stmbuf);
|
|
x->stmbuf = fz_keepbuffer(stm);
|
|
|
|
return nil;
|
|
}
|
|
|
|
/*
|
|
* object loading
|
|
*/
|
|
|
|
fz_error *
|
|
pdf_cacheobject(pdf_xref *xref, int oid, int gen)
|
|
{
|
|
char buf[65536]; /* yeowch! */
|
|
|
|
fz_error *error;
|
|
pdf_xrefentry *x;
|
|
int roid, rgen;
|
|
int n;
|
|
|
|
if (oid < 0 || oid >= xref->len)
|
|
return fz_throw("rangecheck: object number out of range: %d", oid);
|
|
|
|
x = &xref->table[oid];
|
|
|
|
if (x->obj)
|
|
return nil;
|
|
|
|
if (x->type == 'f' || x->type == 'd')
|
|
{
|
|
error = fz_newnull(&x->obj);
|
|
if (error)
|
|
return error;
|
|
return nil;
|
|
}
|
|
|
|
if (x->type == 'n')
|
|
{
|
|
n = fz_seek(xref->file, x->ofs, 0);
|
|
if (n < 0)
|
|
return fz_ioerror(xref->file);
|
|
|
|
error = pdf_parseindobj(&x->obj, xref->file, buf, sizeof buf, &roid, &rgen, &x->stmofs);
|
|
if (error)
|
|
return error;
|
|
|
|
if (roid != oid || rgen != gen)
|
|
return fz_throw("syntaxerror: found wrong object");
|
|
|
|
if (xref->crypt)
|
|
pdf_cryptobj(xref->crypt, x->obj, oid, gen);
|
|
}
|
|
|
|
else if (x->type == 'o')
|
|
{
|
|
if (!x->obj)
|
|
{
|
|
error = pdf_loadobjstm(xref, x->ofs, 0, buf, sizeof buf);
|
|
if (error)
|
|
return error;
|
|
}
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|
|
fz_error *
|
|
pdf_loadobject(fz_obj **objp, pdf_xref *xref, int oid, int gen)
|
|
{
|
|
fz_error *error;
|
|
|
|
error = pdf_cacheobject(xref, oid, gen);
|
|
if (error)
|
|
return error;
|
|
|
|
*objp = fz_keepobj(xref->table[oid].obj);
|
|
|
|
return nil;
|
|
}
|
|
|
|
fz_error *
|
|
pdf_loadindirect(fz_obj **objp, pdf_xref *xref, fz_obj *ref)
|
|
{
|
|
assert(ref != nil);
|
|
return pdf_loadobject(objp, xref, fz_tonum(ref), fz_togen(ref));
|
|
}
|
|
|
|
fz_error *
|
|
pdf_resolve(fz_obj **objp, pdf_xref *xref)
|
|
{
|
|
if (fz_isindirect(*objp))
|
|
return pdf_loadindirect(objp, xref, *objp);
|
|
fz_keepobj(*objp);
|
|
return nil;
|
|
}
|
|
|