static fz_error loadpostscriptfunc(pdf_function *func, pdf_xref *xref, fz_obj *dict, int oid, int gen) { fz_error error; fz_stream *stream; int codeptr; pdf_logrsrc("load postscript function (%d %d R)\n", oid, gen); error = pdf_openstream(&stream, xref, oid, gen); if (error) return fz_rethrow(error, "cannot open calculator function stream"); if (fz_readbyte(stream) != '{') { fz_dropstream(stream); return fz_throw("stream is not a calculator function"); } func->u.p.code = nil; func->u.p.cap = 0; codeptr = 0; error = parsecode(func, stream, &codeptr); if (error) { fz_dropstream(stream); return fz_rethrow(error, "cannot parse calculator function"); } fz_dropstream(stream); return fz_okay; }
static fz_error loadcharproc(fz_tree **treep, pdf_xref *xref, fz_obj *rdb, fz_obj *stmref) { fz_error error; pdf_csi *csi; fz_stream *stm; error = pdf_newcsi(&csi, 1); if (error) return fz_rethrow(error, "cannot create interpreter"); error = pdf_openstream(&stm, xref, fz_tonum(stmref), fz_togen(stmref)); if (error) { pdf_dropcsi(csi); return fz_rethrow(error, "cannot open glyph content stream"); } error = pdf_runcsi(csi, xref, rdb, stm); if (error) { fz_dropstream(stm); pdf_dropcsi(csi); return fz_rethrow(error, "cannot interpret glyph content stream (%d %d R)", fz_tonum(stmref), fz_togen(stmref)); } *treep = csi->tree; csi->tree = nil; fz_dropstream(stm); pdf_dropcsi(csi); return fz_okay; }
static void showstream(int num, int gen) { fz_error error; fz_stream *stm; unsigned char buf[2048]; int n; showcolumn = 0; if (showdecode) error = pdf_openstream(&stm, xref, num, gen); else error = pdf_openrawstream(&stm, xref, num, gen); if (error) die(error); while (1) { error = fz_read(&n, stm, buf, sizeof buf); if (error) die(error); if (n == 0) break; if (showbinary) fwrite(buf, 1, n, stdout); else showsafe(buf, n); } fz_dropstream(stm); }
void fz_dropstream(fz_stream *stm) { stm->refs --; if (stm->refs == 0) { if (stm->error) { fz_catch(stm->error, "dropped unhandled ioerror"); stm->error = fz_okay; } switch (stm->kind) { case FZ_SFILE: close(stm->file); break; case FZ_SFILTER: fz_dropfilter(stm->filter); fz_dropstream(stm->chain); break; case FZ_SBUFFER: break; } fz_dropbuffer(stm->buffer); fz_free(stm); } }
/* * Load predefined CMap from system. */ fz_error pdf_loadsystemcmap(pdf_cmap **cmapp, char *cmapname) { fz_error error; fz_stream *stream; pdf_cmap *usecmap; pdf_cmap *cmap; unsigned char *data; unsigned int len; int i; pdf_logfont("loading system cmap %s\n", cmapname); error = pdf_getcmapbuffer(cmapname, &data, &len); if(error) return fz_rethrow(error, "no builtin cmap file: %s", cmapname); stream = fz_openrmemory(data, len); error = pdf_parsecmap(&cmap, stream); fz_dropstream(stream); if(error) return fz_rethrow(error, "cannot parse cmap data"); if (cmap->usecmapname[0] && !cmap->usecmap) { pdf_logfont("charmap depends on other charmap (%s), loading it\n", cmap->usecmapname); error = pdf_loadsystemcmap(&usecmap, cmap->usecmapname); if (error) return fz_rethrow(error, "could not load usecmap: %s", cmap->usecmapname); pdf_setusecmap(cmap, usecmap); } *cmapp = cmap; return fz_okay; }
static fz_error * parseTTCs(char *path) { fz_error *err = nil; int byteread; fz_stream *file = nil; FONT_COLLECTION fontcollectioin; ULONG i; err = fz_openrfile(&file, path); if(err) goto cleanup; SAFE_FZ_READ(file, &fontcollectioin, sizeof(FONT_COLLECTION)); if(memcmp(fontcollectioin.Tag,"ttcf",sizeof(fontcollectioin.Tag)) == 0) { fontcollectioin.Version = SWAPLONG(fontcollectioin.Version); fontcollectioin.NumFonts = SWAPLONG(fontcollectioin.NumFonts); if( fontcollectioin.Version == TTC_VERSION1 || fontcollectioin.Version == TTC_VERSION2 ) { ULONG *offsettable = fz_malloc(sizeof(ULONG)*fontcollectioin.NumFonts); if(offsettable == nil) { err = fz_outofmem; goto cleanup; } SAFE_FZ_READ(file, offsettable, sizeof(ULONG)*fontcollectioin.NumFonts); for(i = 0; i < fontcollectioin.NumFonts; ++i) { offsettable[i] = SWAPLONG(offsettable[i]); parseTTF(file,offsettable[i],i,path); } fz_free(offsettable); } else { err = fz_throw("fonterror : invalid version"); goto cleanup; } } else { err = fz_throw("fonterror: wrong format"); goto cleanup; } cleanup: if(file) fz_dropstream(file); return err; }
/* * 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; error = pdf_openstream(&stm, xref, oid, gen); if (error) return fz_rethrow(error, "cannot open stream (%d)", oid); error = fz_readall(bufp, stm, 0); fz_dropstream(stm); if (error) return fz_rethrow(error, "cannot load stream into buffer (%d)", oid); return fz_okay; }
static fz_error * parseTTFs(char *path) { fz_error *err = nil; fz_stream *file = nil; err = fz_openrfile(&file, path); if(err) goto cleanup; err = parseTTF(file,0,0,path); if(err) goto cleanup; cleanup: if(file) fz_dropstream(file); return err; }
void fz_dropstream(fz_stream *stm) { stm->refs --; if (stm->refs == 0) { if (stm->error) { fflush(stdout); fz_printerror(stm->error); fz_droperror(stm->error); fflush(stderr); fz_warn("dropped unhandled ioerror"); } if (stm->mode == FZ_SWRITE) { stm->buffer->eof = 1; fz_flush(stm); } switch (stm->kind) { case FZ_SFILE: close(stm->file); break; case FZ_SFILTER: fz_dropfilter(stm->filter); fz_dropstream(stm->chain); break; case FZ_SBUFFER: break; } fz_dropbuffer(stm->buffer); fz_free(stm); } }
fz_error * pdf_loadinlineimage(pdf_image **imgp, pdf_xref *xref, fz_obj *rdb, fz_obj *dict, fz_stream *file) { fz_error *error; pdf_image *img; fz_filter *filter; fz_obj *f; fz_obj *cs; fz_obj *d; int ismask; int i; img = fz_malloc(sizeof(pdf_image)); if (!img) return fz_outofmem; pdf_logimage("load inline image %p {\n", img); img->super.loadtile = pdf_loadtile; img->super.drop = pdf_dropimage; img->super.n = 0; img->super.a = 0; img->super.refs = 0; img->indexed = nil; img->usecolorkey = 0; img->mask = nil; img->super.w = fz_toint(fz_dictgetsa(dict, "Width", "W")); img->super.h = fz_toint(fz_dictgetsa(dict, "Height", "H")); img->bpc = fz_toint(fz_dictgetsa(dict, "BitsPerComponent", "BPC")); ismask = fz_tobool(fz_dictgetsa(dict, "ImageMask", "IM")); d = fz_dictgetsa(dict, "Decode", "D"); cs = fz_dictgetsa(dict, "ColorSpace", "CS"); pdf_logimage("size %dx%d %d\n", img->super.w, img->super.h, img->bpc); if (ismask) { pdf_logimage("is mask\n"); img->super.cs = nil; img->super.n = 0; img->super.a = 1; img->bpc = 1; } if (cs) { img->super.cs = nil; if (fz_isname(cs)) { fz_obj *csd = fz_dictgets(rdb, "ColorSpace"); if (csd) { fz_obj *cso = fz_dictget(csd, cs); img->super.cs = pdf_finditem(xref->store, PDF_KCOLORSPACE, cso); if (img->super.cs) fz_keepcolorspace(img->super.cs); } } if (!img->super.cs) { /* XXX danger! danger! does this resolve? */ error = pdf_loadcolorspace(&img->super.cs, xref, cs); if (error) return error; } if (!strcmp(img->super.cs->name, "Indexed")) { pdf_logimage("indexed\n"); img->indexed = (pdf_indexed*)img->super.cs; img->super.cs = img->indexed->base; } pdf_logimage("colorspace %s\n", img->super.cs->name); img->super.n = img->super.cs->n; img->super.a = 0; } if (fz_isarray(d)) { pdf_logimage("decode array\n"); if (img->indexed) for (i = 0; i < 2; i++) img->decode[i] = fz_toreal(fz_arrayget(d, i)); else for (i = 0; i < (img->super.n + img->super.a) * 2; i++) img->decode[i] = fz_toreal(fz_arrayget(d, i)); } else { if (img->indexed) for (i = 0; i < 2; i++) img->decode[i] = i & 1 ? (1 << img->bpc) - 1 : 0; else for (i = 0; i < (img->super.n + img->super.a) * 2; i++) img->decode[i] = i & 1; } if (img->indexed) img->stride = (img->super.w * img->bpc + 7) / 8; else img->stride = (img->super.w * (img->super.n + img->super.a) * img->bpc + 7) / 8; /* load image data */ f = fz_dictgetsa(dict, "Filter", "F"); if (f) { fz_stream *tempfile; error = pdf_buildinlinefilter(&filter, dict); if (error) return error; error = fz_openrfilter(&tempfile, filter, file); if (error) return error; i = fz_readall(&img->samples, tempfile); if (i < 0) return fz_ioerror(tempfile); fz_dropfilter(filter); fz_dropstream(tempfile); } else { error = fz_newbuffer(&img->samples, img->super.h * img->stride); if (error) return error; i = fz_read(file, img->samples->bp, img->super.h * img->stride); if (i < 0) return fz_ioerror(file); img->samples->wp += img->super.h * img->stride; } /* 0 means opaque and 1 means transparent, so we invert to get alpha */ if (ismask) { unsigned char *p; for (p = img->samples->bp; p < img->samples->ep; p++) *p = ~*p; } pdf_logimage("}\n"); *imgp = img; return nil; }
/* * Load CMap stream in PDF file */ fz_error pdf_loadembeddedcmap(pdf_cmap **cmapp, pdf_xref *xref, fz_obj *stmref) { fz_error error = fz_okay; fz_obj *stmobj; fz_stream *file = nil; pdf_cmap *cmap = nil; pdf_cmap *usecmap; fz_obj *wmode; fz_obj *obj; if ((*cmapp = pdf_finditem(xref->store, PDF_KCMAP, stmref))) { pdf_keepcmap(*cmapp); return fz_okay; } pdf_logfont("load embedded cmap (%d %d R) {\n", fz_tonum(stmref), fz_togen(stmref)); stmobj = fz_resolveindirect(stmref); error = pdf_openstream(&file, xref, fz_tonum(stmref), fz_togen(stmref)); if (error) { error = fz_rethrow(error, "cannot open cmap stream"); goto cleanup; } error = pdf_parsecmap(&cmap, file); if (error) { error = fz_rethrow(error, "cannot parse cmap stream"); goto cleanup; } fz_dropstream(file); wmode = fz_dictgets(stmobj, "WMode"); if (fz_isint(wmode)) { pdf_logfont("wmode %d\n", wmode); pdf_setwmode(cmap, fz_toint(wmode)); } obj = fz_dictgets(stmobj, "UseCMap"); if (fz_isname(obj)) { pdf_logfont("usecmap /%s\n", fz_toname(obj)); error = pdf_loadsystemcmap(&usecmap, fz_toname(obj)); if (error) { error = fz_rethrow(error, "cannot load system usecmap '%s'", fz_toname(obj)); goto cleanup; } pdf_setusecmap(cmap, usecmap); pdf_dropcmap(usecmap); } else if (fz_isindirect(obj)) { pdf_logfont("usecmap (%d %d R)\n", fz_tonum(obj), fz_togen(obj)); error = pdf_loadembeddedcmap(&usecmap, xref, obj); if (error) { error = fz_rethrow(error, "cannot load embedded usecmap"); goto cleanup; } pdf_setusecmap(cmap, usecmap); pdf_dropcmap(usecmap); } pdf_logfont("}\n"); error = pdf_storeitem(xref->store, PDF_KCMAP, stmref, cmap); if (error) { error = fz_rethrow(error, "cannot store cmap resource"); goto cleanup; } *cmapp = cmap; return fz_okay; cleanup: if (file) fz_dropstream(file); if (cmap) pdf_dropcmap(cmap); return error; /* already rethrown */ }
fz_error * pdf_updatexref(pdf_xref *xref, char *path) { fz_error *error; fz_stream *out; int oid; int i, n; int startxref; fz_obj *obj; pdf_logxref("updatexref '%s' %p\n", path, xref); error = fz_openafile(&out, path); if (error) return error; fz_print(out, "\n"); for (oid = 0; oid < xref->len; oid++) { if (xref->table[oid].type == 'a') { xref->table[oid].ofs = fz_tell(out); error = writeobject(out, xref, xref->crypt, oid, xref->table[oid].gen); if (error) goto cleanup; } } /* always write out entry 0 in appended xref sections */ xref->table[0].type = 'd'; startxref = fz_tell(out); fz_print(out, "xref\n"); oid = 0; while (oid < xref->len) { n = countmodified(xref, oid); pdf_logxref(" section %d +%d\n", oid, n); fz_print(out, "%d %d\n", oid, n); for (i = 0; i < n; i++) { if (xref->table[oid + i].type == 'd') xref->table[oid + i].type = 'f'; if (xref->table[oid + i].type == 'a') xref->table[oid + i].type = 'n'; fz_print(out, "%010d %05d %c \n", xref->table[oid + i].ofs, xref->table[oid + i].gen, xref->table[oid + i].type); } oid += n; while (oid < xref->len && xref->table[oid].type != 'a' && xref->table[oid].type != 'd') oid ++; } fz_print(out, "\n"); fz_print(out, "trailer\n<<\n /Size %d\n /Prev %d", xref->len, xref->startxref); obj = fz_dictgets(xref->trailer, "Root"); fz_print(out,"\n /Root %d %d R", fz_tonum(obj), fz_togen(obj)); obj = fz_dictgets(xref->trailer, "Info"); if (obj) fz_print(out,"\n /Info %d %d R", fz_tonum(obj), fz_togen(obj)); obj = fz_dictgets(xref->trailer, "Encrypt"); if (obj) { fz_print(out,"\n /Encrypt "); fz_printobj(out, obj, TIGHT); } obj = fz_dictgets(xref->trailer, "ID"); if (obj) { fz_print(out,"\n /ID "); fz_printobj(out, obj, TIGHT); } fz_print(out, "\n>>\n\n"); fz_print(out, "startxref\n"); fz_print(out, "%d\n", startxref); fz_print(out, "%%%%EOF\n"); xref->startxref = startxref; fz_dropstream(out); return nil; cleanup: fz_dropstream(out); return error; }
fz_error pdf_loadxref(pdf_xref *xref, char *filename) { fz_error error; fz_obj *size; int i; char buf[65536]; /* yeowch! */ pdf_logxref("loadxref '%s' %p\n", filename, xref); error = fz_openrfile(&xref->file, filename); if (error) { return fz_rethrow(error, "cannot open file: '%s'", filename); } error = loadversion(xref); if (error) { error = fz_rethrow(error, "cannot read version marker"); goto cleanup; } error = readstartxref(xref); if (error) { error = fz_rethrow(error, "cannot read startxref"); goto cleanup; } error = readtrailer(xref, buf, sizeof buf); if (error) { error = fz_rethrow(error, "cannot read trailer"); goto cleanup; } size = fz_dictgets(xref->trailer, "Size"); if (!size) { error = fz_throw("trailer missing Size entry"); goto cleanup; } pdf_logxref(" size %d at 0x%x\n", fz_toint(size), xref->startxref); assert(xref->table == nil); xref->len = fz_toint(size); xref->cap = xref->len + 1; /* for hack to allow broken pdf generators with off-by-one errors */ xref->table = fz_malloc(xref->cap * sizeof(pdf_xrefentry)); for (i = 0; i < xref->cap; i++) { xref->table[i].ofs = 0; xref->table[i].gen = 0; xref->table[i].stmofs = 0; xref->table[i].obj = nil; xref->table[i].type = 0; } error = readxrefsections(xref, xref->startxref, buf, sizeof buf); if (error) { error = fz_rethrow(error, "cannot read xref"); goto cleanup; } /* broken pdfs where first object is not free */ if (xref->table[0].type != 'f') { fz_warn("first object in xref is not free"); xref->table[0].type = 'f'; } /* broken pdfs where freed objects have offset and gen set to 0 but still exits */ for (i = 0; i < xref->len; i++) if (xref->table[i].type == 'n' && xref->table[i].ofs == 0 && xref->table[i].gen == 0 && xref->table[i].obj == nil) { fz_warn("object (%d %d R) has invalid offset, assumed missing", i, xref->table[i].gen); xref->table[i].type = 'f'; } return fz_okay; cleanup: fz_dropstream(xref->file); xref->file = nil; free(xref->table); xref->table = nil; return error; }
int main(int argc, char **argv) { pdf_cmap *cmap; fz_error error; fz_stream *fi; FILE *fo; char name[256]; char *realname; int i, k; if (argc < 3) { fprintf(stderr, "usage: cmapdump output.c lots of cmap files\n"); return 1; } fo = fopen(argv[1], "wb"); if (!fo) { fprintf(stderr, "cmapdump: could not open output file\n"); return 1; } fprintf(fo, "#include \"fitz.h\"\n"); fprintf(fo, "#include \"mupdf.h\"\n"); fprintf(fo, "\n"); for (i = 2; i < argc; i++) { realname = strrchr(argv[i], '/'); if (!realname) realname = strrchr(argv[i], '\\'); if (realname) realname ++; else realname = argv[i]; if (strlen(realname) > (sizeof name - 1)) { fprintf(stderr, "cmapdump: file name too long\n"); return 1; } strcpy(name, realname); clean(name); error = fz_openrfile(&fi, argv[i]); if (error) { fz_catch(error, "cmapdump: could not open input file %s\n", argv[i]); return 1; } error = pdf_parsecmap(&cmap, fi); if (error) { fz_catch(error, "cmapdump: could not parse input cmap %s\n", argv[i]); return 1; } fprintf(fo, "/*\n * %s\n */\n\n", cmap->cmapname); fprintf(fo, "static const pdf_range pdf_cmap_%s_ranges[] =\n{\n", name); if (cmap->rlen == 0) { fprintf(fo, " /* dummy entry for non-c99 compilers */\n"); fprintf(fo, " { 0x0, 0x0, PDF_CMAP_RANGE, 0 }\n"); } for (k = 0; k < cmap->rlen; k++) { fprintf(fo, " { 0x%04x, 0x%04x, %s %d },\n", cmap->ranges[k].low, cmap->ranges[k].high, flagtoname(cmap->ranges[k].flag), cmap->ranges[k].offset); } fprintf(fo, "};\n\n"); if (cmap->tlen == 0) { fprintf(fo, "static const unsigned short pdf_cmap_%s_table[1] = { 0 };\n\n", name); } else { fprintf(fo, "static const unsigned short pdf_cmap_%s_table[%d] =\n{", name, cmap->tlen); for (k = 0; k < cmap->tlen; k++) { if (k % 8 == 0) fprintf(fo, "\n "); fprintf(fo, "%d, ", cmap->table[k]); } fprintf(fo, "\n};\n\n"); } fprintf(fo, "pdf_cmap pdf_cmap_%s =\n", name); fprintf(fo, "{\n"); fprintf(fo, " -1, "); fprintf(fo, "\"%s\", ", cmap->cmapname); fprintf(fo, "\"%s\", nil, ", cmap->usecmapname); fprintf(fo, "%d,\n", cmap->wmode); fprintf(fo, " %d, /* codespace table */\n", cmap->ncspace); fprintf(fo, " {\n"); if (cmap->ncspace == 0) { fprintf(fo, " /* dummy entry for non-c99 compilers */\n"); fprintf(fo, " { 0, 0x0, 0x0 },\n"); } for (k = 0; k < cmap->ncspace; k++) { fprintf(fo, "\t{ %d, 0x%04x, 0x%04x },\n", cmap->cspace[k].n, cmap->cspace[k].low, cmap->cspace[k].high); } fprintf(fo, " },\n"); fprintf(fo, " %d, %d, (pdf_range*) pdf_cmap_%s_ranges,\n", cmap->rlen, cmap->rlen, name); fprintf(fo, " %d, %d, (unsigned short*) pdf_cmap_%s_table,\n", cmap->tlen, cmap->tlen, name); fprintf(fo, "};\n\n"); fz_dropstream(fi); } return 0; }
fz_error pdf_loadobjstm(pdf_xref *xref, int oid, int gen, char *buf, int cap) { fz_error error; fz_stream *stm; fz_obj *objstm; int *oidbuf; int *ofsbuf; fz_obj *obj; int first; int count; int i, n; pdf_token_e tok; pdf_logxref("loadobjstm (%d %d R)\n", oid, gen); error = pdf_loadobject(&objstm, xref, oid, gen); if (error) return fz_rethrow(error, "cannot load object stream object"); count = fz_toint(fz_dictgets(objstm, "N")); first = fz_toint(fz_dictgets(objstm, "First")); pdf_logxref(" count %d\n", count); oidbuf = fz_malloc(count * sizeof(int)); ofsbuf = fz_malloc(count * sizeof(int)); error = pdf_openstream(&stm, xref, oid, gen); if (error) { error = fz_rethrow(error, "cannot open object stream"); goto cleanupbuf; } for (i = 0; i < count; i++) { error = pdf_lex(&tok, stm, buf, cap, &n); if (error || tok != PDF_TINT) { error = fz_rethrow(error, "corrupt object stream"); goto cleanupstm; } oidbuf[i] = atoi(buf); error = pdf_lex(&tok, stm, buf, cap, &n); if (error || tok != PDF_TINT) { error = fz_rethrow(error, "corrupt object stream"); goto cleanupstm; } ofsbuf[i] = atoi(buf); } error = fz_seek(stm, first, 0); if (error) { error = fz_rethrow(error, "cannot seek in object stream"); goto cleanupstm; } for (i = 0; i < count; i++) { /* FIXME: seek to first + ofsbuf[i] */ error = pdf_parsestmobj(&obj, xref, stm, buf, cap); if (error) { error = fz_rethrow(error, "cannot parse object %d in stream", i); goto cleanupstm; } if (oidbuf[i] < 1 || oidbuf[i] >= xref->len) { fz_dropobj(obj); error = fz_throw("object id (%d 0 R) out of range (0..%d)", oidbuf[i], xref->len - 1); goto cleanupstm; } if (xref->table[oidbuf[i]].obj) fz_dropobj(xref->table[oidbuf[i]].obj); xref->table[oidbuf[i]].obj = obj; } fz_dropstream(stm); fz_free(ofsbuf); fz_free(oidbuf); fz_dropobj(objstm); return fz_okay; cleanupstm: fz_dropstream(stm); cleanupbuf: fz_free(ofsbuf); fz_free(oidbuf); fz_dropobj(objstm); return error; /* already rethrown */ }
fz_error * pdf_loadtype7shade(fz_shade *shade, pdf_xref *xref, fz_obj *shading, fz_obj *ref) { fz_error *error; fz_stream *stream; fz_obj *obj; int bpcoord; int bpcomp; int bpflag; int ncomp; float x0, x1, y0, y1; float c0[FZ_MAXCOLORS]; float c1[FZ_MAXCOLORS]; int i, n, j; unsigned int t; int flag; fz_point p[16]; pdf_tensorpatch patch; error = nil; ncomp = shade->cs->n; bpcoord = fz_toint(fz_dictgets(shading, "BitsPerCoordinate")); bpcomp = fz_toint(fz_dictgets(shading, "BitsPerComponent")); bpflag = fz_toint(fz_dictgets(shading, "BitsPerFlag")); obj = fz_dictgets(shading, "Decode"); if (fz_isarray(obj)) { pdf_logshade("decode array\n"); x0 = fz_toreal(fz_arrayget(obj, 0)); x1 = fz_toreal(fz_arrayget(obj, 1)); y0 = fz_toreal(fz_arrayget(obj, 2)); y1 = fz_toreal(fz_arrayget(obj, 3)); for (i=0; i < fz_arraylen(obj) / 2; ++i) { c0[i] = fz_toreal(fz_arrayget(obj, i*2+4)); c1[i] = fz_toreal(fz_arrayget(obj, i*2+5)); } } else { error = fz_throw("syntaxerror: No Decode key in Type 6 Shade"); goto cleanup; } obj = fz_dictgets(shading, "Function"); if (obj) { ncomp = 1; pdf_loadshadefunction(shade, xref, shading, c0[0], c1[0]); shade->usefunction = 1; } else shade->usefunction = 0; shade->meshcap = 0; shade->mesh = nil; error = growshademesh(shade, 1024); if (error) goto cleanup; n = 2 + shade->cs->n; j = 0; error = pdf_openstream(&stream, xref, fz_tonum(ref), fz_togen(ref)); if (error) goto cleanup; while (fz_peekbyte(stream) != EOF) { flag = getdata(stream, bpflag); for (i = 0; i < 16; ++i) { t = getdata(stream, bpcoord); p[i].x = x0 + (t * (x1 - x0) / (pow(2, bpcoord) - 1.)); t = getdata(stream, bpcoord); p[i].y = y0 + (t * (y1 - y0) / (pow(2, bpcoord) - 1.)); } for (i = 0; i < 4; ++i) { int k; for (k=0; k < ncomp; ++k) { t = getdata(stream, bpcomp); patch.color[i][k] = c0[k] + (t * (c1[k] - c0[k]) / (pow(2, bpcomp) - 1.0f)); } } patch.pole[0][0] = p[0]; patch.pole[0][1] = p[1]; patch.pole[0][2] = p[2]; patch.pole[0][3] = p[3]; patch.pole[1][3] = p[4]; patch.pole[2][3] = p[5]; patch.pole[3][3] = p[6]; patch.pole[3][2] = p[7]; patch.pole[3][1] = p[8]; patch.pole[3][0] = p[9]; patch.pole[2][0] = p[10]; patch.pole[1][0] = p[11]; patch.pole[1][1] = p[12]; patch.pole[1][2] = p[13]; patch.pole[2][2] = p[14]; patch.pole[2][1] = p[15]; j = drawpatch(patch, shade, j, ncomp, 0); } fz_dropstream(stream); shade->meshlen = j / n / 3; cleanup: return nil; }
/* * 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; if (oid < 0 || oid >= xref->len) return fz_throw("object id out of range (%d)", oid); x = xref->table + oid; error = pdf_cacheobject(xref, oid, gen); if (error) return fz_rethrow(error, "cannot load stream object (%d)", oid); if (x->stmbuf) { error = pdf_buildfilter(&filter, xref, x->obj, oid, gen); if (error) return fz_rethrow(error, "cannot create filter"); error = fz_openrbuffer(&rawstm, x->stmbuf); if (error) { fz_dropfilter(filter); return fz_rethrow(error, "cannot open stream from buffer"); } error = fz_openrfilter(stmp, filter, rawstm); fz_dropfilter(filter); fz_dropstream(rawstm); if (error) return fz_rethrow(error, "cannot open filter stream"); return fz_okay; } if (x->stmofs) { error = pdf_buildfilter(&filter, xref, x->obj, oid, gen); if (error) return fz_rethrow(error, "cannot create filter"); error = fz_seek(xref->file, x->stmofs, 0); if (error) { fz_dropfilter(filter); return fz_rethrow(error, "cannot seek to stream"); } error = fz_openrfilter(stmp, filter, xref->file); fz_dropfilter(filter); if (error) return fz_rethrow(error, "cannot open filter stream"); return fz_okay; } return fz_throw("object is not a stream"); }
static fz_error * writestream(fz_stream *out, pdf_xref *xref, pdf_crypt *encrypt, int oid, int gen) { fz_error *error; fz_stream *dststm; fz_stream *srcstm; unsigned char buf[4096]; fz_filter *ef; int n; fz_print(out, "stream\n"); if (encrypt) { error = pdf_cryptstream(&ef, encrypt, oid, gen); if (error) return error; error = fz_openrfilter(&dststm, ef, out); fz_dropfilter(ef); if (error) return error; } else { dststm = fz_keepstream(out); } error = pdf_openrawstream(&srcstm, xref, oid, gen); if (error) goto cleanupdst; while (1) { n = fz_read(srcstm, buf, sizeof buf); if (n == 0) break; if (n < 0) { error = fz_ioerror(srcstm); goto cleanupsrc; } n = fz_write(dststm, buf, n); if (n < 0) { error = fz_ioerror(dststm); goto cleanupsrc; } } fz_dropstream(srcstm); fz_dropstream(dststm); fz_print(out, "endstream\n"); return nil; cleanupsrc: fz_dropstream(srcstm); cleanupdst: fz_dropstream(dststm); return error; }
fz_error * pdf_savexref(pdf_xref *xref, char *path, pdf_crypt *encrypt) { fz_error *error; fz_stream *out; int oid; int startxref; int *ofsbuf; fz_obj *obj; int eoid, egen; pdf_logxref("savexref '%s' %p\n", path, xref); /* need to add encryption object for acrobat < 6 */ if (encrypt) { pdf_logxref("make encryption dict\n"); error = pdf_allocobject(xref, &eoid, &egen); if (error) return error; pdf_cryptobj(encrypt, encrypt->encrypt, eoid, egen); error = pdf_updateobject(xref, eoid, egen, encrypt->encrypt); if (error) return error; } ofsbuf = fz_malloc(sizeof(int) * xref->len); if (!ofsbuf) return fz_outofmem; error = fz_openwfile(&out, path); if (error) { fz_free(ofsbuf); return error; } fz_print(out, "%%PDF-%1.1f\n", xref->version); fz_print(out, "%%\342\343\317\323\n\n"); for (oid = 0; oid < xref->len; oid++) { pdf_xrefentry *x = xref->table + oid; if (x->type == 'n' || x->type == 'o' || x->type == 'a') { ofsbuf[oid] = fz_tell(out); error = writeobject(out, xref, encrypt, oid, x->type == 'o' ? 0 : x->gen); if (error) goto cleanup; } else { ofsbuf[oid] = x->ofs; } } startxref = fz_tell(out); fz_print(out, "xref\n"); fz_print(out, "0 %d\n", xref->len); for (oid = 0; oid < xref->len; oid++) { int gen = xref->table[oid].gen; int type = xref->table[oid].type; if (type == 'o') gen = 0; if (type == 'a' || type == 'o') type = 'n'; if (type == 'd') type = 'f'; fz_print(out, "%010d %05d %c \n", ofsbuf[oid], gen, type); } fz_print(out, "\n"); fz_print(out, "trailer\n<<\n /Size %d", xref->len); obj = fz_dictgets(xref->trailer, "Root"); fz_print(out, "\n /Root %d %d R", fz_tonum(obj), fz_togen(obj)); obj = fz_dictgets(xref->trailer, "Info"); if (obj) fz_print(out, "\n /Info %d %d R", fz_tonum(obj), fz_togen(obj)); if (encrypt) { fz_print(out, "\n /Encrypt %d %d R", eoid, egen); fz_print(out, "\n /ID ["); fz_printobj(out, encrypt->id, 1); fz_printobj(out, encrypt->id, 1); fz_print(out, "]"); pdf_cryptobj(encrypt, encrypt->encrypt, eoid, egen); } fz_print(out, "\n>>\n\n"); fz_print(out, "startxref\n"); fz_print(out, "%d\n", startxref); fz_print(out, "%%%%EOF\n"); xref->startxref = startxref; if(ofsbuf) fz_free(ofsbuf); fz_dropstream(out); return nil; cleanup: if(ofsbuf) fz_free(ofsbuf); fz_dropstream(out); return error; }
static fz_error readnewxref(fz_obj **trailerp, pdf_xref *xref, char *buf, int cap) { fz_error error; fz_stream *stm; fz_obj *trailer; fz_obj *index; fz_obj *obj; int oid, gen, stmofs; int size, w0, w1, w2; int t; int i; pdf_logxref("load new xref format\n"); error = pdf_parseindobj(&trailer, xref, xref->file, buf, cap, &oid, &gen, &stmofs); if (error) return fz_rethrow(error, "cannot parse compressed xref stream object"); obj = fz_dictgets(trailer, "Size"); if (!obj) { fz_dropobj(trailer); return fz_throw("xref stream missing Size entry"); } size = fz_toint(obj); if (size >= xref->cap) { xref->cap = size + 1; /* for hack to allow broken pdf generators with off-by-one errors */ xref->table = fz_realloc(xref->table, xref->cap * sizeof(pdf_xrefentry)); } if (size > xref->len) { for (i = xref->len; i < xref->cap; i++) { xref->table[i].ofs = 0; xref->table[i].gen = 0; xref->table[i].stmofs = 0; xref->table[i].obj = nil; xref->table[i].type = 0; } xref->len = size; } if (oid < 0 || oid >= xref->len) { if (oid == xref->len && oid < xref->cap) { /* allow broken pdf files that have off-by-one errors in the xref */ fz_warn("object id (%d %d R) out of range (0..%d)", oid, gen, xref->len - 1); xref->len ++; } else { fz_dropobj(trailer); return fz_throw("object id (%d %d R) out of range (0..%d)", oid, gen, xref->len - 1); } } xref->table[oid].type = 'n'; xref->table[oid].gen = gen; xref->table[oid].obj = fz_keepobj(trailer); xref->table[oid].stmofs = stmofs; xref->table[oid].ofs = 0; obj = fz_dictgets(trailer, "W"); if (!obj) { fz_dropobj(trailer); return fz_throw("xref stream missing W entry"); } w0 = fz_toint(fz_arrayget(obj, 0)); w1 = fz_toint(fz_arrayget(obj, 1)); w2 = fz_toint(fz_arrayget(obj, 2)); index = fz_dictgets(trailer, "Index"); error = pdf_openstream(&stm, xref, oid, gen); if (error) { fz_dropobj(trailer); return fz_rethrow(error, "cannot open compressed xref stream"); } if (!index) { error = readnewxrefsection(xref, stm, 0, size, w0, w1, w2); if (error) { fz_dropstream(stm); fz_dropobj(trailer); return fz_rethrow(error, "cannot read xref stream"); } } else { for (t = 0; t < fz_arraylen(index); t += 2) { int i0 = fz_toint(fz_arrayget(index, t + 0)); int i1 = fz_toint(fz_arrayget(index, t + 1)); error = readnewxrefsection(xref, stm, i0, i1, w0, w1, w2); if (error) { fz_dropstream(stm); fz_dropobj(trailer); return fz_rethrow(error, "cannot read xref stream section"); } } } fz_dropstream(stm); *trailerp = trailer; return fz_okay; }
fz_error * pdf_loadtype5shade(fz_shade *shade, pdf_xref *xref, fz_obj *shading, fz_obj *ref) { fz_error *error; fz_stream *stream; fz_obj *obj; int bpcoord; int bpcomp; int vpr, vpc; int ncomp; float x0, x1, y0, y1; float c0[FZ_MAXCOLORS]; float c1[FZ_MAXCOLORS]; int i, n, j; int p, q; unsigned int t; float *x, *y, *c[FZ_MAXCOLORS]; error = nil; ncomp = shade->cs->n; bpcoord = fz_toint(fz_dictgets(shading, "BitsPerCoordinate")); bpcomp = fz_toint(fz_dictgets(shading, "BitsPerComponent")); vpr = fz_toint(fz_dictgets(shading, "VerticesPerRow")); if (vpr < 2) { error = fz_throw("VerticesPerRow must be greater than or equal to 2"); goto cleanup; } obj = fz_dictgets(shading, "Decode"); if (fz_isarray(obj)) { pdf_logshade("decode array\n"); x0 = fz_toreal(fz_arrayget(obj, 0)); x1 = fz_toreal(fz_arrayget(obj, 1)); y0 = fz_toreal(fz_arrayget(obj, 2)); y1 = fz_toreal(fz_arrayget(obj, 3)); for (i=0; i < fz_arraylen(obj) / 2; ++i) { c0[i] = fz_toreal(fz_arrayget(obj, i*2+4)); c1[i] = fz_toreal(fz_arrayget(obj, i*2+5)); } } else { error = fz_throw("syntaxerror: No Decode key in Type 4 Shade"); goto cleanup; } obj = fz_dictgets(shading, "Function"); if (obj) { ncomp = 1; pdf_loadshadefunction(shade, xref, shading, c0[0], c1[0]); shade->usefunction = 1; } else shade->usefunction = 0; n = 2 + shade->cs->n; j = 0; #define BIGNUM 1024 x = fz_malloc(sizeof(float) * vpr * BIGNUM); y = fz_malloc(sizeof(float) * vpr * BIGNUM); for (i = 0; i < ncomp; ++i) { c[i] = fz_malloc(sizeof(float) * vpr * BIGNUM); } q = 0; error = pdf_openstream(&stream, xref, fz_tonum(ref), fz_togen(ref)); if (error) goto cleanup; while (fz_peekbyte(stream) != EOF) { for (p = 0; p < vpr; ++p) { int idx; idx = q * vpr + p; t = getdata(stream, bpcoord); x[idx] = x0 + (t * (x1 - x0) / ((float)pow(2, bpcoord) - 1)); t = getdata(stream, bpcoord); y[idx] = y0 + (t * (y1 - y0) / ((float)pow(2, bpcoord) - 1)); for (i=0; i < ncomp; ++i) { t = getdata(stream, bpcomp); c[i][idx] = c0[i] + (t * (c1[i] - c0[i]) / (float)(pow(2, bpcomp) - 1)); } } q++; } fz_dropstream(stream); #define ADD_VERTEX(idx) \ {\ int z;\ shade->mesh[j++] = x[idx];\ shade->mesh[j++] = y[idx];\ for (z = 0; z < shade->cs->n; ++z) {\ shade->mesh[j++] = c[z][idx];\ }\ }\ vpc = q; shade->meshcap = 0; shade->mesh = fz_malloc(sizeof(float) * 1024); if (!shade) { error = fz_outofmem; goto cleanup; } j = 0; for (p = 0; p < vpr-1; ++p) { for (q = 0; q < vpc-1; ++q) { ADD_VERTEX(q * vpr + p); ADD_VERTEX(q * vpr + p + 1); ADD_VERTEX((q + 1) * vpr + p + 1); ADD_VERTEX(q * vpr + p); ADD_VERTEX((q + 1) * vpr + p + 1); ADD_VERTEX((q + 1) * vpr + p); } } shade->meshlen = j / n / 3; fz_free(x); fz_free(y); for (i = 0; i < ncomp; ++i) { fz_free(c[i]); } cleanup: return nil; }